diff options
author | Android (Google) Code Review <android-gerrit@google.com> | 2009-06-19 17:38:13 -0700 |
---|---|---|
committer | Android (Google) Code Review <android-gerrit@google.com> | 2009-06-19 17:38:13 -0700 |
commit | deb47eadf0a66364e234e8e8031fec564ab49e41 (patch) | |
tree | 8d159a5dfc1d7dd0aaf2247bfbf42c7afc12f71f /V8Binding/binding | |
parent | 25b3eb1cdb4b57a15a24a30384d296f5791c75e8 (diff) | |
parent | 7ea7249b96d1fe31dd4c4ebe3672124b9f975351 (diff) | |
download | external_webkit-deb47eadf0a66364e234e8e8031fec564ab49e41.zip external_webkit-deb47eadf0a66364e234e8e8031fec564ab49e41.tar.gz external_webkit-deb47eadf0a66364e234e8e8031fec564ab49e41.tar.bz2 |
Merge change 4868
* changes:
Renaming bindings to binding.
Diffstat (limited to 'V8Binding/binding')
41 files changed, 11599 insertions, 0 deletions
diff --git a/V8Binding/binding/DOMObjectsInclude.h b/V8Binding/binding/DOMObjectsInclude.h new file mode 100644 index 0000000..a79f03d --- /dev/null +++ b/V8Binding/binding/DOMObjectsInclude.h @@ -0,0 +1,193 @@ +// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef DOMObjectsInclude_h +#define DOMObjectsInclude_h + +#include "BarInfo.h" +#include "CanvasGradient.h" +#include "CanvasPattern.h" +#include "CanvasPixelArray.h" +#include "CanvasRenderingContext2D.h" +#include "CanvasStyle.h" +#include "CharacterData.h" +#include "ClientRect.h" +#include "ClientRectList.h" +#include "Clipboard.h" +#include "Console.h" +#include "Counter.h" +#include "CSSCharsetRule.h" +#include "CSSFontFaceRule.h" +#include "CSSImportRule.h" +#include "CSSMediaRule.h" +#include "CSSPageRule.h" +#include "CSSRule.h" +#include "CSSRuleList.h" +#include "CSSStyleDeclaration.h" +#include "CSSStyleRule.h" +#include "CSSStyleSheet.h" +#include "CSSValueList.h" +#include "CSSVariablesDeclaration.h" +#include "CSSVariablesRule.h" +#include "Database.h" +#include "DocumentType.h" +#include "DocumentFragment.h" +#include "DOMApplicationCache.h" +#include "DOMCoreException.h" +#include "DOMImplementation.h" +#include "DOMParser.h" +#include "DOMSelection.h" +#include "DOMStringList.h" +#include "DOMWindow.h" +#include "Entity.h" +#include "EventListener.h" +#include "EventTarget.h" +#include "Event.h" +#include "EventException.h" +#include "ExceptionCode.h" +#include "File.h" +#include "FileList.h" +#include "Frame.h" +#include "FrameLoader.h" +#include "FrameTree.h" +#include "History.h" +#include "HTMLNames.h" +#include "HTMLDocument.h" +#include "HTMLElement.h" +#include "HTMLImageElement.h" +#include "HTMLInputElement.h" +#include "HTMLSelectElement.h" +#include "HTMLOptionsCollection.h" +#include "ImageData.h" +#include "InspectorController.h" +#include "KeyboardEvent.h" +#include "Location.h" +#include "MediaError.h" +#include "MediaList.h" +#include "MediaPlayer.h" +#include "MessageChannel.h" +#include "MessageEvent.h" +#include "MessagePort.h" +#include "MimeTypeArray.h" +#include "MouseEvent.h" +#include "MutationEvent.h" +#include "Navigator.h" // for MimeTypeArray +#include "NodeFilter.h" +#include "Notation.h" +#include "NodeList.h" +#include "NodeIterator.h" +#include "OverflowEvent.h" +#include "Page.h" +#include "Plugin.h" +#include "PluginArray.h" +#include "ProcessingInstruction.h" +#include "ProgressEvent.h" +#include "Range.h" +#include "RangeException.h" +#include "Rect.h" +#include "RGBColor.h" +#include "Screen.h" +#include "ScriptExecutionContext.h" +#include "SecurityOrigin.h" +#include "Settings.h" +#include "SQLTransaction.h" +#include "SQLResultSet.h" +#include "SQLResultSetRowList.h" +#include "StyleSheet.h" +#include "StyleSheetList.h" +#include "TextEvent.h" +#include "TextMetrics.h" +#include "TimeRanges.h" +#include "TreeWalker.h" +#include "XSLTProcessor.h" +#include "V8AbstractEventListener.h" +#include "V8CustomEventListener.h" +#include "V8DOMWindow.h" +#include "V8HTMLElement.h" +#include "V8LazyEventListener.h" +#include "V8NodeFilterCondition.h" +#include "V8ObjectEventListener.h" +#include "WebKitAnimationEvent.h" +#include "WebKitCSSKeyframeRule.h" +#include "WebKitCSSKeyframesRule.h" +#include "WebKitCSSMatrix.h" +#include "WebKitCSSTransformValue.h" +#include "WebKitPoint.h" +#include "WebKitTransitionEvent.h" +#include "WheelEvent.h" +#include "XMLHttpRequest.h" +#include "XMLHttpRequestException.h" +#include "XMLHttpRequestProgressEvent.h" +#include "XMLHttpRequestUpload.h" +#include "XMLSerializer.h" +#include "XPathEvaluator.h" +#include "XPathException.h" +#include "XPathExpression.h" +#include "XPathNSResolver.h" +#include "XPathResult.h" + +#if ENABLE(SVG) +#include "SVGAngle.h" +#include "SVGAnimatedPoints.h" +#include "SVGColor.h" +#include "SVGElement.h" +#include "SVGElementInstance.h" +#include "SVGElementInstanceList.h" +#include "SVGException.h" +#include "SVGLength.h" +#include "SVGLengthList.h" +#include "SVGNumberList.h" +#include "SVGPaint.h" +#include "SVGPathSeg.h" +#include "SVGPathSegArc.h" +#include "SVGPathSegClosePath.h" +#include "SVGPathSegCurvetoCubic.h" +#include "SVGPathSegCurvetoCubicSmooth.h" +#include "SVGPathSegCurvetoQuadratic.h" +#include "SVGPathSegCurvetoQuadraticSmooth.h" +#include "SVGPathSegLineto.h" +#include "SVGPathSegLinetoHorizontal.h" +#include "SVGPathSegLinetoVertical.h" +#include "SVGPathSegList.h" +#include "SVGPathSegMoveto.h" +#include "SVGPointList.h" +#include "SVGPreserveAspectRatio.h" +#include "SVGRenderingIntent.h" +#include "SVGStringList.h" +#include "SVGTransform.h" +#include "SVGTransformList.h" +#include "SVGUnitTypes.h" +#include "SVGURIReference.h" +#include "SVGZoomEvent.h" +#include "V8SVGPODTypeWrapper.h" +#endif // SVG + +#if ENABLE(WORKERS) +#include "Worker.h" +#include "WorkerContext.h" +#include "WorkerLocation.h" +#include "WorkerNavigator.h" +#endif // WORKERS + +#if PLATFORM(ANDROID) +#include "Coordinates.h" +#include "Geolocation.h" +#include "Geoposition.h" +#include "PositionError.h" +#include "PositionErrorCallback.h" +#include "Touch.h" +#include "TouchList.h" +#include "TouchEvent.h" +#include "VoidCallback.h" +#endif + +namespace WebCore { + +// A helper class for undetectable document.all +class UndetectableHTMLCollection : public HTMLCollection { +}; + +} // namespace WebCore + +#endif // DOMObjectsInclude_h diff --git a/V8Binding/binding/JSDOMBinding.cpp b/V8Binding/binding/JSDOMBinding.cpp new file mode 100644 index 0000000..c72a92b --- /dev/null +++ b/V8Binding/binding/JSDOMBinding.cpp @@ -0,0 +1,52 @@ +// Copyright (c) 2008, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#include "config.h" +#include "JSDOMBinding.h" + +#include "Document.h" +#include "Node.h" + +namespace WebCore { + +void updateDOMNodeDocument(Node* node, Document* oldDocument, + Document* newDocument) +{ + // We don't do anything here in V8 bindings +} + +ScriptState* scriptStateFromNode(Node* node) +{ + // This should be never reached with V8 bindings (WebKit only uses it + // for non-JS bindings) + ASSERT_NOT_REACHED(); + return 0; +} + +} // namespace WebCore diff --git a/V8Binding/binding/JSDOMBinding.h b/V8Binding/binding/JSDOMBinding.h new file mode 100644 index 0000000..8ed5602 --- /dev/null +++ b/V8Binding/binding/JSDOMBinding.h @@ -0,0 +1,50 @@ +// Copyright (c) 2008, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Masquerade to pretend that we support JSC namespace and avoid unforking +// This is not a reimplementation of the JSC namespace. It's just enough code +// to avoid #ifdefs in WebKit code. + +#ifndef JSDOMBinding_h +#define JSDOMBinding_h + +namespace WebCore { + class Node; + class Document; + class ScriptState; + + void updateDOMNodeDocument(Node*, Document* oldDocument, + Document* newDocument); + + ScriptState* scriptStateFromNode(Node*); + +} + + +#endif // JSDOMBinding_h diff --git a/V8Binding/binding/JSXPathNSResolver.cpp b/V8Binding/binding/JSXPathNSResolver.cpp new file mode 100644 index 0000000..2fb2849 --- /dev/null +++ b/V8Binding/binding/JSXPathNSResolver.cpp @@ -0,0 +1,90 @@ +// Copyright (c) 2008, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#include "config.h" +#include "JSXPathNSResolver.h" + +#if ENABLE(XPATH) + +#include "v8_proxy.h" +#include "v8_binding.h" +#include "PlatformString.h" + +namespace WebCore { + +JSXPathNSResolver::JSXPathNSResolver(v8::Handle<v8::Object> resolver) +: m_resolver(resolver) { +} + +JSXPathNSResolver::~JSXPathNSResolver() { +} + +String JSXPathNSResolver::lookupNamespaceURI(const String& prefix) { + v8::Handle<v8::Function> lookupNamespaceURIFunc; + v8::Handle<v8::String> lookupNamespaceURIName = v8::String::New("lookupNamespaceURI"); + + // Check if the resolver has a function property named lookupNamespaceURI. + if (m_resolver->Has(lookupNamespaceURIName)) { + v8::Handle<v8::Value> lookupNamespaceURI = m_resolver->Get(lookupNamespaceURIName); + if (lookupNamespaceURI->IsFunction()) { + lookupNamespaceURIFunc = v8::Handle<v8::Function>::Cast(lookupNamespaceURI); + } + } + + if (lookupNamespaceURIFunc.IsEmpty() && !m_resolver->IsFunction()) { + Frame* frame = V8Proxy::retrieveActiveFrame(); + log_info(frame, "XPathNSResolver does not have a lookupNamespaceURI method.", String()); + return String(); + } + + // Catch exceptions from calling the namespace resolver. + v8::TryCatch try_catch; + try_catch.SetVerbose(true); // Print exceptions to console. + + const int argc = 1; + v8::Handle<v8::Value> argv[argc] = { v8String(prefix) }; + v8::Handle<v8::Function> function = lookupNamespaceURIFunc.IsEmpty() + ? v8::Handle<v8::Function>::Cast(m_resolver) + : lookupNamespaceURIFunc; + + V8Proxy* proxy = V8Proxy::retrieve(); + v8::Handle<v8::Value> retval = proxy->CallFunction(function, m_resolver, argc, argv); + + // Eat exceptions from namespace resolver and return an empty string. This + // will most likely cause NAMESPACE_ERR. + if (try_catch.HasCaught()) { + return String(); + } + + return ToWebCoreString(retval); +} + +} + +#endif // ENABLE(XPATH) diff --git a/V8Binding/binding/JSXPathNSResolver.h b/V8Binding/binding/JSXPathNSResolver.h new file mode 100644 index 0000000..f0c340c --- /dev/null +++ b/V8Binding/binding/JSXPathNSResolver.h @@ -0,0 +1,33 @@ +// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef JSXPATHNSRESOLVER_H__ +#define JSXPATHNSRESOLVER_H__ + +#if ENABLE(XPATH) + +#include <v8.h> +#include <wtf/RefCounted.h> +#include "XPathNSResolver.h" + +namespace WebCore { + + class String; + + class JSXPathNSResolver : public XPathNSResolver { + public: + + JSXPathNSResolver(v8::Handle<v8::Object> resolver); + virtual ~JSXPathNSResolver(); + + virtual String lookupNamespaceURI(const String& prefix); + + private: + v8::Handle<v8::Object> m_resolver; // Handle to resolver object. + }; +} + +#endif // ENABLE(XPATH) + +#endif // JSXPATHNSRESOLVER_H__ diff --git a/V8Binding/binding/NPV8Object.cpp b/V8Binding/binding/NPV8Object.cpp new file mode 100644 index 0000000..defe6bf --- /dev/null +++ b/V8Binding/binding/NPV8Object.cpp @@ -0,0 +1,504 @@ +/* + * Copyright (C) 2004, 2006 Apple Computer, Inc. All rights reserved. + * Copyright (C) 2007-2009 Google, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" + +#include <stdio.h> + +#define max max +#define min min +#include <v8.h> +#include "NPV8Object.h" +#if PLATFORM(CHROMIUM) +#include "ChromiumBridge.h" +#endif +#include "Frame.h" +#include "npruntime_priv.h" +#include "PlatformString.h" +#include "ScriptController.h" +#include "v8_custom.h" +#include "v8_helpers.h" +#include "V8NPUtils.h" +#include "v8_proxy.h" +#include "DOMWindow.h" + +using WebCore::V8ClassIndex; +using WebCore::V8Custom; +using WebCore::V8Proxy; + +// FIXME(mbelshe): comments on why use malloc and free. +static NPObject* AllocV8NPObject(NPP, NPClass*) +{ + return static_cast<NPObject*>(malloc(sizeof(V8NPObject))); +} + +static void FreeV8NPObject(NPObject* npobj) +{ + V8NPObject *object = reinterpret_cast<V8NPObject*>(npobj); +#ifndef NDEBUG + V8Proxy::UnregisterGlobalHandle(object, object->v8Object); +#endif + object->v8Object.Dispose(); + free(object); +} + +static v8::Handle<v8::Value>* listFromVariantArgs(const NPVariant* args, + uint32_t argCount, + NPObject *owner) +{ + v8::Handle<v8::Value>* argv = new v8::Handle<v8::Value>[argCount]; + for (uint32_t index = 0; index < argCount; index++) { + const NPVariant *arg = &args[index]; + argv[index] = convertNPVariantToV8Object(arg, owner); + } + return argv; +} + +// Create an identifier (null terminated utf8 char*) from the NPIdentifier. +static v8::Local<v8::String> NPIdentifierToV8Identifier(NPIdentifier name) +{ + PrivateIdentifier* identifier = static_cast<PrivateIdentifier*>(name); + if (identifier->isString) + return v8::String::New(static_cast<const char *>(identifier->value.string)); + + char buf[32]; + sprintf(buf, "%d", identifier->value.number); + return v8::String::New(buf); +} + +static NPClass V8NPObjectClass = { NP_CLASS_STRUCT_VERSION, + AllocV8NPObject, + FreeV8NPObject, + 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + +// NPAPI's npruntime functions +NPClass* npScriptObjectClass = &V8NPObjectClass; + +NPObject* npCreateV8ScriptObject(NPP npp, v8::Handle<v8::Object> object, WebCore::DOMWindow* root) +{ + // Check to see if this object is already wrapped. + if (object->InternalFieldCount() == V8Custom::kNPObjectInternalFieldCount && + object->GetInternalField(V8Custom::kDOMWrapperTypeIndex)->IsNumber() && + object->GetInternalField(V8Custom::kDOMWrapperTypeIndex)->Uint32Value() == V8ClassIndex::NPOBJECT) { + + NPObject* rv = V8Proxy::ToNativeObject<NPObject>(V8ClassIndex::NPOBJECT, object); + NPN_RetainObject(rv); + return rv; + } + + V8NPObject* obj = reinterpret_cast<V8NPObject*>(NPN_CreateObject(npp, &V8NPObjectClass)); + obj->v8Object = v8::Persistent<v8::Object>::New(object); +#ifndef NDEBUG + V8Proxy::RegisterGlobalHandle(WebCore::NPOBJECT, obj, obj->v8Object); +#endif + obj->rootObject = root; + return reinterpret_cast<NPObject*>(obj); +} + +bool NPN_Invoke(NPP npp, NPObject *npobj, NPIdentifier methodName, + const NPVariant *args, uint32_t argCount, NPVariant *result) +{ + if (!npobj) + return false; + + if (npobj->_class == npScriptObjectClass) { + V8NPObject *object = reinterpret_cast<V8NPObject*>(npobj); + + PrivateIdentifier *identifier = static_cast<PrivateIdentifier*>(methodName); + if (!identifier->isString) + return false; + + v8::HandleScope handleScope; + // FIXME: should use the plugin's owner frame as the security context + v8::Handle<v8::Context> context = getV8Context(npp, npobj); + if (context.IsEmpty()) + return false; + + v8::Context::Scope scope(context); + + // Special case the "eval" method. + if (methodName == NPN_GetStringIdentifier("eval")) { + if (argCount != 1) + return false; + if (args[0].type != NPVariantType_String) + return false; + return NPN_Evaluate(npp, npobj, const_cast<NPString*>(&args[0].value.stringValue), result); + } + + v8::Handle<v8::Value> funcObj = object->v8Object->Get(v8::String::New(identifier->value.string)); + if (funcObj.IsEmpty() || funcObj->IsNull()) { + NULL_TO_NPVARIANT(*result); + return false; + } + if (funcObj->IsUndefined()) { + VOID_TO_NPVARIANT(*result); + return false; + } + + WebCore::V8Proxy* proxy = GetV8Proxy(npobj); + ASSERT(proxy); // must not be null + + // FIXME: fix variable naming + // Call the function object + v8::Handle<v8::Function> func = v8::Handle<v8::Function>::Cast(funcObj); + // Create list of args to pass to v8 + v8::Handle<v8::Value>* argv = listFromVariantArgs(args, argCount, npobj); + v8::Local<v8::Value> resultObj = proxy->CallFunction(func, object->v8Object, argCount, argv); + delete[] argv; + + // If we had an error, return false. The spec is a little unclear here, but + // says "Returns true if the method was successfully invoked". If we get an + // error return value, was that successfully invoked? + if (resultObj.IsEmpty()) + return false; + + // Convert the result back to an NPVariant + convertV8ObjectToNPVariant(resultObj, npobj, result); + return true; + } + + if (npobj->_class->invoke) + return npobj->_class->invoke(npobj, methodName, args, argCount, result); + + VOID_TO_NPVARIANT(*result); + return true; +} + +// FIXME: Fix it same as NPN_Invoke (HandleScope and such) +bool NPN_InvokeDefault(NPP npp, NPObject *npobj, const NPVariant *args, + uint32_t argCount, NPVariant *result) +{ + if (!npobj) + return false; + + if (npobj->_class == npScriptObjectClass) { + V8NPObject *object = reinterpret_cast<V8NPObject*>(npobj); + + VOID_TO_NPVARIANT(*result); + + v8::HandleScope handleScope; + v8::Handle<v8::Context> context = getV8Context(npp, npobj); + if (context.IsEmpty()) + return false; + + v8::Context::Scope scope(context); + + // Lookup the function object + v8::Handle<v8::Object> funcObj(object->v8Object); + if (!funcObj->IsFunction()) + return false; + + // Call the function object + v8::Local<v8::Value> resultObj; + v8::Handle<v8::Function> func(v8::Function::Cast(*funcObj)); + if (!func->IsNull()) { + WebCore::V8Proxy* proxy = GetV8Proxy(npobj); + ASSERT(proxy); + + // Create list of args to pass to v8 + v8::Handle<v8::Value>* argv = listFromVariantArgs(args, argCount, npobj); + resultObj = proxy->CallFunction(func, funcObj, argCount, argv); + delete[] argv; + } + + // If we had an error, return false. The spec is a little unclear here, but + // says "Returns true if the method was successfully invoked". If we get an + // error return value, was that successfully invoked? + if (resultObj.IsEmpty()) + return false; + + // Convert the result back to an NPVariant. + convertV8ObjectToNPVariant(resultObj, npobj, result); + return true; + } + + if (npobj->_class->invokeDefault) + return npobj->_class->invokeDefault(npobj, args, argCount, result); + + VOID_TO_NPVARIANT(*result); + return true; +} + +#if PLATFORM(ANDROID) +static +#endif +bool NPN_EvaluateHelper(NPP npp, bool popupsAllowed, NPObject* npobj, NPString* npscript, NPVariant *result) +{ + VOID_TO_NPVARIANT(*result); + if (!npobj) + return false; + + if (npobj->_class != npScriptObjectClass) + return false; + + v8::HandleScope handleScope; + v8::Handle<v8::Context> context = getV8Context(npp, npobj); + if (context.IsEmpty()) + return false; + + WebCore::V8Proxy* proxy = GetV8Proxy(npobj); + ASSERT(proxy); + + v8::Context::Scope scope(context); + + WebCore::String filename; + if (!popupsAllowed) + filename = "npscript"; + + // Convert UTF-8 stream to WebCore::String. + WebCore::String script = WebCore::String::fromUTF8(npscript->UTF8Characters, npscript->UTF8Length); + v8::Local<v8::Value> v8result = proxy->evaluate(WebCore::ScriptSourceCode(script, WebCore::KURL(filename)), 0); + + // If we had an error, return false. + if (v8result.IsEmpty()) + return false; + + convertV8ObjectToNPVariant(v8result, npobj, result); + return true; +} + +bool NPN_Evaluate(NPP npp, NPObject *npobj, NPString *npscript, NPVariant *result) +{ +#if PLATFORM(CHROMIUM) + bool popupsAllowed = WebCore::ChromiumBridge::popupsAllowed(npp); +#else + // TODO(fqian): create an Android bridge + bool popupsAllowed = false; +#endif + return NPN_EvaluateHelper(npp, popupsAllowed, npobj, npscript, result); +} + +bool NPN_GetProperty(NPP npp, NPObject *npobj, NPIdentifier propertyName, NPVariant *result) +{ + if (!npobj) + return false; + + if (npobj->_class == npScriptObjectClass) { + V8NPObject *object = reinterpret_cast<V8NPObject*>(npobj); + + v8::HandleScope handleScope; + v8::Handle<v8::Context> context = getV8Context(npp, npobj); + if (context.IsEmpty()) + return false; + + v8::Context::Scope scope(context); + + v8::Handle<v8::Object> obj(object->v8Object); + v8::Local<v8::Value> v8result = obj->Get(NPIdentifierToV8Identifier(propertyName)); + + convertV8ObjectToNPVariant(v8result, npobj, result); + return true; + } + + if (npobj->_class->hasProperty && npobj->_class->getProperty) { + if (npobj->_class->hasProperty(npobj, propertyName)) + return npobj->_class->getProperty(npobj, propertyName, result); + } + + VOID_TO_NPVARIANT(*result); + return false; +} + +bool NPN_SetProperty(NPP npp, NPObject *npobj, NPIdentifier propertyName, const NPVariant *value) +{ + if (!npobj) + return false; + + if (npobj->_class == npScriptObjectClass) { + V8NPObject *object = reinterpret_cast<V8NPObject*>(npobj); + + v8::HandleScope handleScope; + v8::Handle<v8::Context> context = getV8Context(npp, npobj); + if (context.IsEmpty()) + return false; + + v8::Context::Scope scope(context); + + v8::Handle<v8::Object> obj(object->v8Object); + obj->Set(NPIdentifierToV8Identifier(propertyName), + convertNPVariantToV8Object(value, object->rootObject->frame()->script()->windowScriptNPObject())); + return true; + } + + if (npobj->_class->setProperty) + return npobj->_class->setProperty(npobj, propertyName, value); + + return false; +} + +bool NPN_RemoveProperty(NPP npp, NPObject *npobj, NPIdentifier propertyName) +{ + if (!npobj) + return false; + if (npobj->_class != npScriptObjectClass) + return false; + + V8NPObject *object = reinterpret_cast<V8NPObject*>(npobj); + + v8::HandleScope handleScope; + v8::Handle<v8::Context> context = getV8Context(npp, npobj); + if (context.IsEmpty()) + return false; + v8::Context::Scope scope(context); + + v8::Handle<v8::Object> obj(object->v8Object); + // FIXME(mbelshe) - verify that setting to undefined is right. + obj->Set(NPIdentifierToV8Identifier(propertyName), v8::Undefined()); + return true; +} + +bool NPN_HasProperty(NPP npp, NPObject *npobj, NPIdentifier propertyName) +{ + if (!npobj) + return false; + + if (npobj->_class == npScriptObjectClass) { + V8NPObject *object = reinterpret_cast<V8NPObject*>(npobj); + + v8::HandleScope handleScope; + v8::Handle<v8::Context> context = getV8Context(npp, npobj); + if (context.IsEmpty()) + return false; + v8::Context::Scope scope(context); + + v8::Handle<v8::Object> obj(object->v8Object); + return obj->Has(NPIdentifierToV8Identifier(propertyName)); + } + + if (npobj->_class->hasProperty) + return npobj->_class->hasProperty(npobj, propertyName); + return false; +} + +bool NPN_HasMethod(NPP npp, NPObject *npobj, NPIdentifier methodName) +{ + if (!npobj) + return false; + + if (npobj->_class == npScriptObjectClass) { + V8NPObject *object = reinterpret_cast<V8NPObject*>(npobj); + + v8::HandleScope handleScope; + v8::Handle<v8::Context> context = getV8Context(npp, npobj); + if (context.IsEmpty()) + return false; + v8::Context::Scope scope(context); + + v8::Handle<v8::Object> obj(object->v8Object); + v8::Handle<v8::Value> prop = obj->Get(NPIdentifierToV8Identifier(methodName)); + return prop->IsFunction(); + } + + if (npobj->_class->hasMethod) + return npobj->_class->hasMethod(npobj, methodName); + return false; +} + +void NPN_SetException(NPObject *npobj, const NPUTF8 *message) +{ + if (npobj->_class != npScriptObjectClass) + return; + v8::HandleScope handleScope; + v8::Handle<v8::Context> context = getV8Context(0, npobj); + if (context.IsEmpty()) + return; + + v8::Context::Scope scope(context); + V8Proxy::ThrowError(V8Proxy::GENERAL_ERROR, message); +} + +bool NPN_Enumerate(NPP npp, NPObject *npobj, NPIdentifier **identifier, uint32_t *count) +{ + if (!npobj) + return false; + + if (npobj->_class == npScriptObjectClass) { + V8NPObject *object = reinterpret_cast<V8NPObject*>(npobj); + + v8::HandleScope handleScope; + v8::Handle<v8::Context> context = getV8Context(npp, npobj); + if (context.IsEmpty()) + return false; + v8::Context::Scope scope(context); + + v8::Handle<v8::Object> obj(object->v8Object); + + // FIXME(fqian): http://b/issue?id=1210340: Use a v8::Object::Keys() method + // when it exists, instead of evaluating javascript. + + // FIXME(mpcomplete): figure out how to cache this helper function. + // Run a helper function that collects the properties on the object into + // an array. + const char enumeratorCode[] = + "(function (obj) {" + " var props = [];" + " for (var prop in obj) {" + " props[props.length] = prop;" + " }" + " return props;" + "});"; + v8::Handle<v8::String> source = v8::String::New(enumeratorCode); + v8::Handle<v8::Script> script = v8::Script::Compile(source, 0); + v8::Handle<v8::Value> enumeratorObj = script->Run(); + v8::Handle<v8::Function> enumerator = v8::Handle<v8::Function>::Cast(enumeratorObj); + v8::Handle<v8::Value> argv[] = { obj }; + v8::Local<v8::Value> propsObj = enumerator->Call(v8::Handle<v8::Object>::Cast(enumeratorObj), 1, argv); + if (propsObj.IsEmpty()) + return false; + + // Convert the results into an array of NPIdentifiers. + v8::Handle<v8::Array> props = v8::Handle<v8::Array>::Cast(propsObj); + *count = props->Length(); + *identifier = static_cast<NPIdentifier*>(malloc(sizeof(NPIdentifier*) * *count)); + for (uint32_t i = 0; i < *count; ++i) { + v8::Local<v8::Value> name = props->Get(v8::Integer::New(i)); + (*identifier)[i] = getStringIdentifier(v8::Local<v8::String>::Cast(name)); + } + return true; + } + + if (NP_CLASS_STRUCT_VERSION_HAS_ENUM(npobj->_class) && npobj->_class->enumerate) + return npobj->_class->enumerate(npobj, identifier, count); + + return false; +} + +bool NPN_Construct(NPP npp, NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result) +{ + if (!npobj) + return false; + + // FIXME(estade): implement this case. + if (npobj->_class == npScriptObjectClass) { + VOID_TO_NPVARIANT(*result); + return false; + } + + if (NP_CLASS_STRUCT_VERSION_HAS_CTOR(npobj->_class) && npobj->_class->construct) + return npobj->_class->construct(npobj, args, argCount, result); + + return false; +} diff --git a/V8Binding/binding/NPV8Object.h b/V8Binding/binding/NPV8Object.h new file mode 100644 index 0000000..1b9713e --- /dev/null +++ b/V8Binding/binding/NPV8Object.h @@ -0,0 +1,41 @@ +// Copyright (c) 2006-2009 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef np_v8object_h +#define np_v8object_h + +#if PLATFORM(CHROMIUM) +#include "bindings/npruntime.h" +#else +#include "bridge/npruntime.h" // use WebCore version +#endif + +#include <v8.h> + +namespace WebCore { + class DOMWindow; +} + +extern NPClass* npScriptObjectClass; + +// A V8NPObject is a NPObject which carries additional V8-specific +// information. It is allocated and deallocated by AllocV8NPObject() +// and FreeV8NPObject() methods. +struct V8NPObject { + NPObject object; + v8::Persistent<v8::Object> v8Object; + WebCore::DOMWindow* rootObject; +}; + +struct PrivateIdentifier { + union { + const NPUTF8* string; + int32_t number; + } value; + bool isString; +}; + +NPObject* npCreateV8ScriptObject(NPP npp, v8::Handle<v8::Object>, WebCore::DOMWindow*); + +#endif // np_v8object_h diff --git a/V8Binding/binding/RGBColor.cpp b/V8Binding/binding/RGBColor.cpp new file mode 100644 index 0000000..4a37ea6 --- /dev/null +++ b/V8Binding/binding/RGBColor.cpp @@ -0,0 +1,50 @@ +// Copyright (c) 2008, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#include "RGBColor.h" + +namespace WebCore { + +PassRefPtr<CSSPrimitiveValue> RGBColor::red() { + unsigned int value = (m_rgbcolor >> 16) & 0xFF; + return CSSPrimitiveValue::create(value, CSSPrimitiveValue::CSS_NUMBER); +} + +PassRefPtr<CSSPrimitiveValue> RGBColor::green() { + unsigned int value = (m_rgbcolor >> 8) & 0xFF; + return CSSPrimitiveValue::create(value, CSSPrimitiveValue::CSS_NUMBER); +} + +PassRefPtr<CSSPrimitiveValue> RGBColor::blue() { + unsigned int value = m_rgbcolor & 0xFF; + return CSSPrimitiveValue::create(value, CSSPrimitiveValue::CSS_NUMBER); +} + +} // namespace WebCore + diff --git a/V8Binding/binding/RGBColor.h b/V8Binding/binding/RGBColor.h new file mode 100644 index 0000000..afc0500 --- /dev/null +++ b/V8Binding/binding/RGBColor.h @@ -0,0 +1,28 @@ +// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef RGBColor_h +#define RGBColor_h + +#include "config.h" +#include "CSSPrimitiveValue.h" +#include <wtf/RefCounted.h> + +namespace WebCore { + +class RGBColor : public RefCounted<RGBColor> { + public: + RGBColor(unsigned rgbcolor) : m_rgbcolor(rgbcolor) { } + + PassRefPtr<CSSPrimitiveValue> red(); + PassRefPtr<CSSPrimitiveValue> green(); + PassRefPtr<CSSPrimitiveValue> blue(); + + private: + unsigned m_rgbcolor; +}; + +} // namespace WebCore + +#endif // RGBColor_h diff --git a/V8Binding/binding/ScriptController.cpp b/V8Binding/binding/ScriptController.cpp new file mode 100644 index 0000000..e53606e --- /dev/null +++ b/V8Binding/binding/ScriptController.cpp @@ -0,0 +1,451 @@ +// Copyright (c) 2008, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#include "config.h" +#include "ScriptController.h" + +#if PLATFORM(CHROMIUM) +#include "ChromiumBridge.h" +#endif + +#include "CString.h" +#include "Document.h" +#include "DOMWindow.h" +#include "Event.h" +#include "EventListener.h" +#include "EventNames.h" +#include "Frame.h" +#include "Node.h" +#include "NotImplemented.h" +#include "npruntime_priv.h" +#include "NPV8Object.h" +#include "ScriptSourceCode.h" +#include "PluginView.h" +#include "Widget.h" + +#include "v8_proxy.h" +#include "v8_binding.h" +#include "V8NPObject.h" + +NPRuntimeFunctions npruntime_functions = { + NPN_GetStringIdentifier, + NPN_GetStringIdentifiers, + NPN_GetIntIdentifier, + NPN_IdentifierIsString, + NPN_UTF8FromIdentifier, + NPN_IntFromIdentifier, + NPN_CreateObject, + NPN_RetainObject, + NPN_ReleaseObject, + NPN_Invoke, + NPN_InvokeDefault, + NPN_Evaluate, + NPN_GetProperty, + NPN_SetProperty, + NPN_RemoveProperty, + NPN_HasProperty, + NPN_HasMethod, + NPN_ReleaseVariantValue, + NPN_SetException +}; + + +namespace WebCore { + +void ScriptController::setFlags(const char* str, int length) +{ + v8::V8::SetFlagsFromString(str, length); +} + +Frame* ScriptController::retrieveActiveFrame() +{ + return V8Proxy::retrieveActiveFrame(); +} + +bool ScriptController::isSafeScript(Frame* target) +{ + return V8Proxy::CanAccessFrame(target, true); +} + +void ScriptController::gcProtectJSWrapper(void* dom_object) +{ + V8Proxy::GCProtect(dom_object); +} + +void ScriptController::gcUnprotectJSWrapper(void* dom_object) +{ + V8Proxy::GCUnprotect(dom_object); +} + +ScriptController::ScriptController(Frame* frame) + : m_frame(frame) + , m_sourceURL(0) + , m_processingTimerCallback(false) + , m_paused(false) + , m_proxy(new V8Proxy(frame)) +#if ENABLE(NETSCAPE_PLUGIN_API) + , m_windowScriptNPObject(0) +#endif +{ +} + +ScriptController::~ScriptController() +{ +} + +void ScriptController::clearScriptObjects() +{ + PluginObjectMap::iterator it = m_pluginObjects.begin(); + for (; it != m_pluginObjects.end(); ++it) { + _NPN_UnregisterObject(it->second); + NPN_ReleaseObject(it->second); + } + m_pluginObjects.clear(); + +#if ENABLE(NETSCAPE_PLUGIN_API) + if (m_windowScriptNPObject) { + // Call _NPN_DeallocateObject() instead of _NPN_ReleaseObject() so that we don't leak if a plugin fails to release the window + // script object properly. + // This shouldn't cause any problems for plugins since they should have already been stopped and destroyed at this point. + _NPN_DeallocateObject(m_windowScriptNPObject); + m_windowScriptNPObject = 0; + } +#endif +} + +void ScriptController::updateSecurityOrigin() +{ + m_proxy->updateSecurityOrigin(); +} + +void ScriptController::updatePlatformScriptObjects() +{ + notImplemented(); +} + +// Disconnect the proxy from its owner frame; +void ScriptController::disconnectFrame() +{ + m_proxy->disconnectFrame(); +} + +bool ScriptController::processingUserGesture() const +{ + Frame* active_frame = V8Proxy::retrieveActiveFrame(); + // No script is running, must be run by users. + if (!active_frame) + return true; + + V8Proxy* active_proxy = active_frame->script()->proxy(); + + v8::HandleScope handle_scope; + v8::Handle<v8::Context> context = V8Proxy::GetContext(active_frame); + // TODO(fqian): find all cases context can be empty: + // 1) JS is disabled; + // 2) page is NULL; + if (context.IsEmpty()) + return true; + + v8::Context::Scope scope(context); + + v8::Handle<v8::Object> global = context->Global(); + v8::Handle<v8::Value> jsevent = global->Get(v8::String::NewSymbol("event")); + Event* event = V8Proxy::ToNativeEvent(jsevent); + + // Based on code from kjs_bindings.cpp. + // Note: This is more liberal than Firefox's implementation. + if (event) { + const AtomicString& type = event->type(); + bool event_ok = + // mouse events + type == eventNames().clickEvent || + type == eventNames().mousedownEvent || + type == eventNames().mouseupEvent || + type == eventNames().dblclickEvent || + // keyboard events + type == eventNames().keydownEvent || + type == eventNames().keypressEvent || + type == eventNames().keyupEvent || + // other accepted events + type == eventNames().selectEvent || + type == eventNames().changeEvent || + type == eventNames().focusEvent || + type == eventNames().blurEvent || + type == eventNames().submitEvent; + + if (event_ok) + return true; + } else if (active_proxy->inlineCode() && !active_proxy->timerCallback()) + // This is the <a href="javascript:window.open('...')> case -> we let it + // through + return true; + + // This is the <script>window.open(...)</script> case or a timer callback -> + // block it + return false; +} + +void ScriptController::evaluateInNewContext( + const Vector<ScriptSourceCode>& sources) { + m_proxy->evaluateInNewContext(sources); +} + +// Evaluate a script file in the environment of this proxy. +ScriptValue ScriptController::evaluate(const ScriptSourceCode& sourceCode) +{ + v8::HandleScope hs; + v8::Handle<v8::Context> context = V8Proxy::GetContext(m_proxy->frame()); + if (context.IsEmpty()) + return ScriptValue(); + + v8::Context::Scope scope(context); + v8::Local<v8::Value> obj = m_proxy->evaluate(sourceCode, NULL); + + if (obj.IsEmpty() || obj->IsUndefined()) + return ScriptValue(); + + return ScriptValue(obj); +} + +void ScriptController::disposeJSResult(v8::Persistent<v8::Value> result) +{ + result.Dispose(); + result.Clear(); +} + +PassRefPtr<EventListener> ScriptController::createInlineEventListener( + const String& functionName, const String& code, Node* node) +{ + return m_proxy->createInlineEventListener(functionName, code, node); +} + +#if ENABLE(SVG) +PassRefPtr<EventListener> ScriptController::createSVGEventHandler( + const String& functionName, const String& code, Node* node) +{ + return m_proxy->createSVGEventHandler(functionName, code, node); +} +#endif + +void ScriptController::setEventHandlerLineno(int lineno) +{ + m_proxy->setEventHandlerLineno(lineno); +} + +void ScriptController::finishedWithEvent(Event* evt) +{ + m_proxy->finishedWithEvent(evt); +} + +// Create a V8 object with an interceptor of NPObjectPropertyGetter +void ScriptController::BindToWindowObject(Frame* frame, const String& key, NPObject* object) +{ + v8::HandleScope handle_scope; + + v8::Handle<v8::Context> context = V8Proxy::GetContext(frame); + if (context.IsEmpty()) + return; + + v8::Context::Scope scope(context); + + v8::Handle<v8::Object> value = CreateV8ObjectForNPObject(object, NULL); + + // Attach to the global object + v8::Handle<v8::Object> global = context->Global(); + global->Set(v8String(key), value); +} + +void ScriptController::collectGarbage() +{ + v8::HandleScope hs; + v8::Handle<v8::Context> context = V8Proxy::GetContext(m_proxy->frame()); + if (context.IsEmpty()) + return; + + v8::Context::Scope scope(context); + + m_proxy->evaluate(ScriptSourceCode("if (window.gc) void(gc());"), NULL); +} + +NPRuntimeFunctions* ScriptController::functions() +{ + return &npruntime_functions; +} + + +bool ScriptController::haveInterpreter() const +{ + return m_proxy->ContextInitialized(); +} + +bool ScriptController::isEnabled() const +{ + return m_proxy->isEnabled(); +} + +PassScriptInstance ScriptController::createScriptInstanceForWidget(Widget* widget) +{ + ASSERT(widget != 0); + +#if PLATFORM(CHROMIUM) + if (widget->isFrameView()) + return 0; + + NPObject* npObject = ChromiumBridge::pluginScriptableObject(widget); +#elif PLATFORM(ANDROID) + if (!widget->isPluginView()) + return 0; + + PluginView* pluginView = static_cast<PluginView*>(widget); + NPObject* npObject = pluginView->getNPObject(); +#endif + if (!npObject) + return 0; + // Frame Memory Management for NPObjects + // ------------------------------------- + // NPObjects are treated differently than other objects wrapped by JS. + // NPObjects can be created either by the browser (e.g. the main + // window object) or by the plugin (the main plugin object + // for a HTMLEmbedElement). Further, + // unlike most DOM Objects, the frame is especially careful to ensure + // NPObjects terminate at frame teardown because if a plugin leaks a + // reference, it could leak its objects (or the browser's objects). + // + // The Frame maintains a list of plugin objects (m_pluginObjects) + // which it can use to quickly find the wrapped embed object. + // + // Inside the NPRuntime, we've added a few methods for registering + // wrapped NPObjects. The purpose of the registration is because + // javascript garbage collection is non-deterministic, yet we need to + // be able to tear down the plugin objects immediately. When an object + // is registered, javascript can use it. When the object is destroyed, + // or when the object's "owning" object is destroyed, the object will + // be un-registered, and the javascript engine must not use it. + // + // Inside the javascript engine, the engine can keep a reference to the + // NPObject as part of its wrapper. However, before accessing the object + // it must consult the NPN_Registry. + + v8::Local<v8::Object> wrapper = CreateV8ObjectForNPObject(npObject, NULL); + + // Track the plugin object. We've been given a reference to the object. + m_pluginObjects.set(widget, npObject); + + return V8ScriptInstance::create(wrapper); +} + +void ScriptController::cleanupScriptObjectsForPlugin(void* nativeHandle) +{ + PluginObjectMap::iterator it = m_pluginObjects.find(nativeHandle); + if (it == m_pluginObjects.end()) + return; + _NPN_UnregisterObject(it->second); + NPN_ReleaseObject(it->second); + m_pluginObjects.remove(it); +} + +static NPObject* createNoScriptObject() +{ + notImplemented(); + return 0; +} + +static NPObject* createScriptObject(Frame* frame) +{ + v8::HandleScope handleScope; + v8::Handle<v8::Context> context = V8Proxy::GetContext(frame); + if (context.IsEmpty()) + return createNoScriptObject(); + + v8::Context::Scope scope(context); + DOMWindow* window = frame->domWindow(); + v8::Handle<v8::Value> global = V8Proxy::ToV8Object(V8ClassIndex::DOMWINDOW, window); + ASSERT(global->IsObject()); + return npCreateV8ScriptObject(0, v8::Handle<v8::Object>::Cast(global), window); +} + +NPObject* ScriptController::windowScriptNPObject() +{ + if (m_windowScriptNPObject) + return m_windowScriptNPObject; + + if (isEnabled()) { + // JavaScript is enabled, so there is a JavaScript window object. + // Return an NPObject bound to the window object. + m_windowScriptNPObject = createScriptObject(m_frame); + _NPN_RegisterObject(m_windowScriptNPObject, NULL); + } else { + // JavaScript is not enabled, so we cannot bind the NPObject to the + // JavaScript window object. Instead, we create an NPObject of a + // different class, one which is not bound to a JavaScript object. + m_windowScriptNPObject = createNoScriptObject(); + } + return m_windowScriptNPObject; +} + +NPObject* ScriptController::createScriptObjectForPluginElement(HTMLPlugInElement* plugin) +{ + // Can't create NPObjects when JavaScript is disabled + if (!isEnabled()) + return createNoScriptObject(); + + v8::HandleScope handleScope; + v8::Handle<v8::Context> context = V8Proxy::GetContext(m_frame); + if (context.IsEmpty()) + return createNoScriptObject(); + v8::Context::Scope scope(context); + + DOMWindow* window = m_frame->domWindow(); + v8::Handle<v8::Value> v8plugin = V8Proxy::ToV8Object(V8ClassIndex::HTMLEMBEDELEMENT, plugin); + if (!v8plugin->IsObject()) + return createNoScriptObject(); + + return npCreateV8ScriptObject(0, v8::Handle<v8::Object>::Cast(v8plugin), window); +} + + +void ScriptController::clearWindowShell() +{ + // V8 binding expects ScriptController::clearWindowShell only be called + // when a frame is loading a new page. V8Proxy::clearForNavigation + // creates a new context for the new page. + m_proxy->clearForNavigation(); +} + +void ScriptController::attachDebugger(void*) +{ + notImplemented(); +} + +void ScriptController::updateDocument() +{ + m_proxy->updateDocument(); +} + +} // namespace WebCpre diff --git a/V8Binding/binding/ScriptController.h b/V8Binding/binding/ScriptController.h new file mode 100644 index 0000000..40534fb --- /dev/null +++ b/V8Binding/binding/ScriptController.h @@ -0,0 +1,271 @@ +// Copyright 2008, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// An interface to abstract implementation differences +// for various Javascript engines. + +#ifndef ScriptController_h +#define ScriptController_h + +#include "HashMap.h" +#include "MessagePort.h" +#include "ScriptInstance.h" +#include "ScriptValue.h" +#include "SecurityOrigin.h" + +#if PLATFORM(CHROMIUM) +#include "bindings/npruntime.h" +#else +#include "bridge/npruntime.h" // use WebCore version +#endif + +#include <wtf/HashMap.h> +#include <wtf/Vector.h> + +#include "v8.h" +#include "v8_proxy.h" + +// JavaScript implementations which expose NPObject will need to implement +// these methods. +typedef void (*NPN_ReleaseVariantValueProcPtr) (NPVariant *variant); + +typedef NPIdentifier(*NPN_GetStringIdentifierProcPtr) (const NPUTF8 *name); +typedef void (*NPN_GetStringIdentifiersProcPtr) (const NPUTF8 **names, + int32_t nameCount, + NPIdentifier *identifiers); +typedef NPIdentifier(*NPN_GetIntIdentifierProcPtr) (int32_t intid); +typedef int32_t (*NPN_IntFromIdentifierProcPtr) (NPIdentifier identifier); +typedef bool (*NPN_IdentifierIsStringProcPtr) (NPIdentifier identifier); +typedef NPUTF8 * (*NPN_UTF8FromIdentifierProcPtr) (NPIdentifier identifier); + +typedef NPObject* (*NPN_CreateObjectProcPtr) (NPP, + NPClass *aClass); +typedef NPObject* (*NPN_RetainObjectProcPtr) (NPObject *obj); +typedef void (*NPN_ReleaseObjectProcPtr) (NPObject *obj); +typedef bool (*NPN_InvokeProcPtr) (NPP npp, + NPObject *obj, + NPIdentifier methodName, + const NPVariant *args, + unsigned argCount, + NPVariant *result); +typedef bool (*NPN_InvokeDefaultProcPtr) (NPP npp, + NPObject *obj, + const NPVariant *args, + unsigned argCount, + NPVariant *result); +typedef bool (*NPN_EvaluateProcPtr) (NPP npp, + NPObject *obj, + NPString *script, + NPVariant *result); +typedef bool (*NPN_GetPropertyProcPtr) (NPP npp, + NPObject *obj, + NPIdentifier propertyName, + NPVariant *result); +typedef bool (*NPN_SetPropertyProcPtr) (NPP npp, + NPObject *obj, + NPIdentifier propertyName, + const NPVariant *value); +typedef bool (*NPN_HasPropertyProcPtr) (NPP, + NPObject *npobj, + NPIdentifier propertyName); +typedef bool (*NPN_HasMethodProcPtr) (NPP npp, + NPObject *npobj, + NPIdentifier methodName); +typedef bool (*NPN_RemovePropertyProcPtr) (NPP npp, + NPObject *obj, + NPIdentifier propertyName); +typedef void (*NPN_SetExceptionProcPtr) (NPObject *obj, + const NPUTF8 *message); + +typedef struct _NPRuntimeFunctions { + NPN_GetStringIdentifierProcPtr getStringIdentifier; + NPN_GetStringIdentifiersProcPtr getStringIdentifiers; + NPN_GetIntIdentifierProcPtr getIntIdentifier; + NPN_IdentifierIsStringProcPtr identifierIsString; + NPN_UTF8FromIdentifierProcPtr utf8FromIdentifier; + NPN_IntFromIdentifierProcPtr intFromIdentifier; + NPN_CreateObjectProcPtr createObject; + NPN_RetainObjectProcPtr retainObject; + NPN_ReleaseObjectProcPtr releaseObject; + NPN_InvokeProcPtr invoke; + NPN_InvokeDefaultProcPtr invokeDefault; + NPN_EvaluateProcPtr evaluate; + NPN_GetPropertyProcPtr getProperty; + NPN_SetPropertyProcPtr setProperty; + NPN_RemovePropertyProcPtr removeProperty; + NPN_HasPropertyProcPtr hasProperty; + NPN_HasMethodProcPtr hasMethod; + NPN_ReleaseVariantValueProcPtr releaseVariantValue; + NPN_SetExceptionProcPtr setException; +} NPRuntimeFunctions; + +namespace WebCore { +class Document; +class EventListener; +class Event; +class Frame; +class HTMLPlugInElement; +class Node; +class ScriptSourceCode; +class String; +class Widget; + +typedef v8::Local<v8::Object> JSInstance; +typedef v8::Local<v8::Object> JSInstanceHandle; +typedef v8::Persistent<v8::Object> JSPersistentInstance; +typedef v8::Local<v8::Value> JSException; +typedef v8::Persistent<v8::Value> JSResult; + +class ScriptController { +public: + ScriptController(Frame*); + ~ScriptController(); + + // TODO(eseidel): V8Proxy should either be folded into ScriptController + // or this accessor should be made JSProxy* + V8Proxy* proxy() { return m_proxy.get(); } + + // Evaluate a script file in the environment of this proxy. + // If succeeded, 'succ' is set to true and result is returned + // as a string. + ScriptValue evaluate(const ScriptSourceCode&); + + // Executes JavaScript in a new context associated with the web frame. The + // script gets its own global scope and its own prototypes for intrinsic + // JavaScript objects (String, Array, and so-on). It shares the wrappers for + // all DOM nodes and DOM constructors. + void evaluateInNewContext(const Vector<ScriptSourceCode>& sources); + + // JSC has a WindowShell object, but for V8, the ScriptController + // is the WindowShell. + bool haveWindowShell() const { return m_proxy->ContextInitialized(); } + + // Masquerade 'this' as the windowShell. + // This is a bit of a hack, but provides reasonable compatibility + // with what JSC does as well. + ScriptController* windowShell() { return this; } + + void disposeJSResult(JSResult result); + void collectGarbage(); + + PassRefPtr<EventListener> createInlineEventListener(const String& functionName, const String& code, Node*); +#if ENABLE(SVG) + PassRefPtr<EventListener> createSVGEventHandler(const String& functionName, const String& code, Node*); +#endif + + // Creates a property of the global object of a frame. + void BindToWindowObject(Frame*, const String& key, NPObject*); + + NPRuntimeFunctions* functions(); + + PassScriptInstance createScriptInstanceForWidget(Widget*); + + void disconnectFrame(); + + // Check if the javascript engine has been initialized. + bool haveInterpreter() const; + + bool isEnabled() const; + + // TODO(eseidel): void* is a compile hack + void attachDebugger(void*); + + // Create a NPObject wrapper for a JSObject + // NPObject *WrapScriptObject(NPP pluginId, JSObject* objectToWrap, + // JSRootObject* originRootObject, + // JSRootObject* rootObject); + + // --- Static methods assume we are running VM in single thread, --- + // --- and there is only one VM instance. --- + + // Returns the frame of the calling code is in. + // Not necessary the frame of this proxy. + // For example, JS code in frame A calls windowB.open(...). + // Window::open method has the frame pointer of B, but + // the execution context is in frame A, so it needs + // frame A's loader to complete URL. + static Frame* retrieveActiveFrame(); + + // Check whether it is safe to access a frame in another domain. + static bool isSafeScript(Frame* target); + + // Pass command-line flags to the JS engine + static void setFlags(const char* str, int length); + + // Protect and unprotect the JS wrapper from garbage collected. + static void gcProtectJSWrapper(void* object); + static void gcUnprotectJSWrapper(void* object); + + void finishedWithEvent(Event*); + void setEventHandlerLineno(int lineno); + + void setProcessingTimerCallback(bool b) { m_processingTimerCallback = b; } + bool processingUserGesture() const; + + void setPaused(bool b) { m_paused = b; } + bool isPaused() const { return m_paused; } + + const String* sourceURL() const { return m_sourceURL; } // 0 if we are not evaluating any script + + void clearWindowShell(); + void updateDocument(); + + void updateSecurityOrigin(); + void clearScriptObjects(); + void updatePlatformScriptObjects(); + void cleanupScriptObjectsForPlugin(void*); + +#if ENABLE(NETSCAPE_PLUGIN_API) + NPObject* createScriptObjectForPluginElement(HTMLPlugInElement*); + NPObject* windowScriptNPObject(); +#endif + +private: + Frame* m_frame; + const String* m_sourceURL; + + bool m_processingTimerCallback; + bool m_paused; + + OwnPtr<V8Proxy> m_proxy; + typedef HashMap<void*, NPObject*> PluginObjectMap; + + // A mapping between Widgets and their corresponding script object. + // This list is used so that when the plugin dies, we can immediately + // invalidate all sub-objects which are associated with that plugin. + // The frame keeps a NPObject reference for each item on the list. + PluginObjectMap m_pluginObjects; +#if ENABLE(NETSCAPE_PLUGIN_API) + NPObject* m_windowScriptNPObject; +#endif +}; + +} // namespace WebCore + +#endif // ScriptController_h diff --git a/V8Binding/binding/UndetectableHTMLCollection.idl b/V8Binding/binding/UndetectableHTMLCollection.idl new file mode 100644 index 0000000..bcb2aee --- /dev/null +++ b/V8Binding/binding/UndetectableHTMLCollection.idl @@ -0,0 +1,14 @@ +// Copyright (c) 2008 The Chromium Authors. All rights reserved. Use of this +// source code is governed by a BSD-style license that can be found in the +// LICENSE file. + +module html { + + // This interface is used for undetectable HTMLCollections. + // An undetectable HTMLCollection behaves like an HTMLCollection + // when used, but the 'typeof' operator returns undefined and + // ToBoolean returns false. + interface UndetectableHTMLCollection : HTMLCollection { + }; + +} diff --git a/V8Binding/binding/V8CanvasPixelArrayCustom.cpp b/V8Binding/binding/V8CanvasPixelArrayCustom.cpp new file mode 100644 index 0000000..d5441a1 --- /dev/null +++ b/V8Binding/binding/V8CanvasPixelArrayCustom.cpp @@ -0,0 +1,77 @@ +// Copyright (c) 2009, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#include "config.h" + +#include "v8_binding.h" +#include "v8_custom.h" +#include "v8_proxy.h" + +#include "CanvasPixelArray.h" + +namespace WebCore { + +// Get the specified value from the pixel buffer and return it wrapped as a +// JavaScript Number object to V8. Accesses outside the valid pixel buffer +// range return "undefined". +INDEXED_PROPERTY_GETTER(CanvasPixelArray) { + INC_STATS("DOM.CanvasPixelArray.IndexedPropertyGetter"); + CanvasPixelArray* pixelBuffer = + V8Proxy::ToNativeObject<CanvasPixelArray>( + V8ClassIndex::CANVASPIXELARRAY, + info.Holder()); + + if ((index < 0) || (index >= pixelBuffer->length())) { + return v8::Undefined(); + } + unsigned char result; + if (!pixelBuffer->get(index, result)) { + return v8::Undefined(); + } + return v8::Number::New(result); +} + + +// Set the specified value in the pixel buffer. Accesses outside the valid pixel +// buffer range are silently ignored. +INDEXED_PROPERTY_SETTER(CanvasPixelArray) { + INC_STATS("DOM.CanvasPixelArray.IndexedPropertySetter"); + CanvasPixelArray* pixelBuffer = + V8Proxy::ToNativeObject<CanvasPixelArray>( + V8ClassIndex::CANVASPIXELARRAY, + info.Holder()); + + if ((index >= 0) && (index < pixelBuffer->length())) { + pixelBuffer->set(index, value->NumberValue()); + } + return value; +} + + +} // namespace WebCore diff --git a/V8Binding/binding/V8InitializeThreading.cpp b/V8Binding/binding/V8InitializeThreading.cpp new file mode 100644 index 0000000..869e374 --- /dev/null +++ b/V8Binding/binding/V8InitializeThreading.cpp @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2008 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "V8InitializeThreading.h" +#include <wtf/Threading.h> + +namespace V8 { + +void initializeThreading() { + static bool initializedThreading = false; + if (!initializedThreading) { + WTF::initializeThreading(); + initializedThreading = true; + } +} + +} // namespace JSC + diff --git a/V8Binding/binding/V8InitializeThreading.h b/V8Binding/binding/V8InitializeThreading.h new file mode 100644 index 0000000..e548441 --- /dev/null +++ b/V8Binding/binding/V8InitializeThreading.h @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2008 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef InitializeThreading_h +#define InitializeThreading_h + +namespace V8 { + + // This function must be called from the main thread. It is safe to call it repeatedly. + // Darwin is an exception to this rule: it is OK to call this function from any thread, even reentrantly. + void initializeThreading(); +} + +#endif // InitializeThreading_h diff --git a/V8Binding/binding/V8MessagePortCustom.cpp b/V8Binding/binding/V8MessagePortCustom.cpp new file mode 100644 index 0000000..6405b67 --- /dev/null +++ b/V8Binding/binding/V8MessagePortCustom.cpp @@ -0,0 +1,239 @@ +/* +* Copyright (C) 2009 Google Inc. All rights reserved. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions are +* met: +* +* * Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* * Redistributions in binary form must reproduce the above +* copyright notice, this list of conditions and the following disclaimer +* in the documentation and/or other materials provided with the +* distribution. +* * Neither the name of Google Inc. nor the names of its +* contributors may be used to endorse or promote products derived from +* this software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include "config.h" + +#include "v8_binding.h" +#include "v8_custom.h" +#include "v8_proxy.h" + +#include "V8Document.h" +#include "V8HTMLDocument.h" +#include "V8ObjectEventListener.h" + +#include "ExceptionCode.h" +#include "MessagePort.h" + +namespace WebCore { + +// FIXME: merge these with XHR's CreateHiddenXHRDependency + +// Use an array to hold dependents. It works like a ref-counted scheme. +// A value can be added more than once to the xhr object. +static void CreateHiddenDependency(v8::Local<v8::Object> object, + v8::Local<v8::Value> value) +{ + ASSERT(V8Proxy::GetDOMWrapperType(object) == V8ClassIndex::MESSAGEPORT); + v8::Local<v8::Value> cache = object->GetInternalField(V8Custom::kMessagePortRequestCacheIndex); + if (cache->IsNull() || cache->IsUndefined()) { + cache = v8::Array::New(); + object->SetInternalField(V8Custom::kMessagePortRequestCacheIndex, cache); + } + + v8::Local<v8::Array> cacheArray = v8::Local<v8::Array>::Cast(cache); + cacheArray->Set(v8::Integer::New(cacheArray->Length()), value); +} + +static void RemoveHiddenDependency(v8::Local<v8::Object> object, + v8::Local<v8::Value> value) +{ + ASSERT(V8Proxy::GetDOMWrapperType(object) == V8ClassIndex::MESSAGEPORT); + v8::Local<v8::Value> cache = object->GetInternalField(V8Custom::kMessagePortRequestCacheIndex); + ASSERT(cache->IsArray()); + v8::Local<v8::Array> cacheArray = v8::Local<v8::Array>::Cast(cache); + for (int i = cacheArray->Length() - 1; i >= 0; i--) { + v8::Local<v8::Value> cached = cacheArray->Get(v8::Integer::New(i)); + if (cached->StrictEquals(value)) { + cacheArray->Delete(i); + return; + } + } + + // We should only get here if we try to remove an event listener that was + // never added. +} + +ACCESSOR_GETTER(MessagePortOnmessage) +{ + INC_STATS("DOM.MessagePort.onmessage._get"); + MessagePort* messagePort = V8Proxy::ToNativeObject<MessagePort>( + V8ClassIndex::MESSAGEPORT, info.Holder()); + if (messagePort->onmessage()) { + V8ObjectEventListener* listener = + static_cast<V8ObjectEventListener*>(messagePort->onmessage()); + v8::Local<v8::Object> v8Listener = listener->getListenerObject(); + return v8Listener; + } + return v8::Undefined(); +} + +ACCESSOR_SETTER(MessagePortOnmessage) +{ + INC_STATS("DOM.MessagePort.onmessage._set"); + MessagePort* messagePort = V8Proxy::ToNativeObject<MessagePort>( + V8ClassIndex::MESSAGEPORT, info.Holder()); + if (value->IsNull()) { + if (messagePort->onmessage()) { + V8ObjectEventListener* listener = + static_cast<V8ObjectEventListener*>(messagePort->onmessage()); + v8::Local<v8::Object> v8Listener = listener->getListenerObject(); + RemoveHiddenDependency(info.Holder(), v8Listener); + } + + // Clear the listener + messagePort->setOnmessage(0); + + } else { + V8Proxy* proxy = V8Proxy::retrieve(messagePort->scriptExecutionContext()); + if (!proxy) + return; + + RefPtr<EventListener> listener = + proxy->FindOrCreateObjectEventListener(value, false); + if (listener) { + messagePort->setOnmessage(listener); + CreateHiddenDependency(info.Holder(), value); + } + } +} + +ACCESSOR_GETTER(MessagePortOnclose) +{ + INC_STATS("DOM.MessagePort.onclose._get"); + MessagePort* messagePort = V8Proxy::ToNativeObject<MessagePort>( + V8ClassIndex::MESSAGEPORT, info.Holder()); + if (messagePort->onclose()) { + V8ObjectEventListener* listener = + static_cast<V8ObjectEventListener*>(messagePort->onclose()); + v8::Local<v8::Object> v8Listener = listener->getListenerObject(); + return v8Listener; + } + return v8::Undefined(); +} + +ACCESSOR_SETTER(MessagePortOnclose) +{ + INC_STATS("DOM.MessagePort.onclose._set"); + MessagePort* messagePort = V8Proxy::ToNativeObject<MessagePort>( + V8ClassIndex::MESSAGEPORT, info.Holder()); + if (value->IsNull()) { + if (messagePort->onclose()) { + V8ObjectEventListener* listener = + static_cast<V8ObjectEventListener*>(messagePort->onclose()); + v8::Local<v8::Object> v8Listener = listener->getListenerObject(); + RemoveHiddenDependency(info.Holder(), v8Listener); + } + + // Clear the listener + messagePort->setOnclose(0); + } else { + V8Proxy* proxy = V8Proxy::retrieve(messagePort->scriptExecutionContext()); + if (!proxy) + return; + + RefPtr<EventListener> listener = + proxy->FindOrCreateObjectEventListener(value, false); + if (listener) { + messagePort->setOnclose(listener); + CreateHiddenDependency(info.Holder(), value); + } + } +} + +CALLBACK_FUNC_DECL(MessagePortStartConversation) +{ + INC_STATS("DOM.MessagePort.StartConversation()"); + if (args.Length() < 1) { + V8Proxy::ThrowError(V8Proxy::SYNTAX_ERROR, "Not enough arguments"); + return v8::Undefined(); + } + + MessagePort* messagePort = V8Proxy::ToNativeObject<MessagePort>( + V8ClassIndex::MESSAGEPORT, args.Holder()); + + V8Proxy* proxy = V8Proxy::retrieve(messagePort->scriptExecutionContext()); + if (!proxy) + return v8::Undefined(); + + RefPtr<MessagePort> port = + messagePort->startConversation(messagePort->scriptExecutionContext(), + ToWebCoreString(args[0])); + v8::Handle<v8::Value> wrapper = + V8Proxy::ToV8Object(V8ClassIndex::MESSAGEPORT, port.get()); + return wrapper; +} + +CALLBACK_FUNC_DECL(MessagePortAddEventListener) +{ + INC_STATS("DOM.MessagePort.AddEventListener()"); + MessagePort* messagePort = V8Proxy::ToNativeObject<MessagePort>( + V8ClassIndex::MESSAGEPORT, args.Holder()); + + V8Proxy* proxy = V8Proxy::retrieve(messagePort->scriptExecutionContext()); + if (!proxy) + return v8::Undefined(); + + RefPtr<EventListener> listener = + proxy->FindOrCreateObjectEventListener(args[1], false); + if (listener) { + String type = ToWebCoreString(args[0]); + bool useCapture = args[2]->BooleanValue(); + messagePort->addEventListener(type, listener, useCapture); + + CreateHiddenDependency(args.Holder(), args[1]); + } + return v8::Undefined(); +} + +CALLBACK_FUNC_DECL(MessagePortRemoveEventListener) +{ + INC_STATS("DOM.MessagePort.RemoveEventListener()"); + MessagePort* messagePort = V8Proxy::ToNativeObject<MessagePort>( + V8ClassIndex::MESSAGEPORT, args.Holder()); + + V8Proxy* proxy = V8Proxy::retrieve(messagePort->scriptExecutionContext()); + if (!proxy) + return v8::Undefined(); // probably leaked + + RefPtr<EventListener> listener = + proxy->FindObjectEventListener(args[1], false); + + if (listener) { + String type = ToWebCoreString(args[0]); + bool useCapture = args[2]->BooleanValue(); + messagePort->removeEventListener(type, listener.get(), useCapture); + + RemoveHiddenDependency(args.Holder(), args[1]); + } + + return v8::Undefined(); +} + +} // namespace WebCore diff --git a/V8Binding/binding/V8NPObject.cpp b/V8Binding/binding/V8NPObject.cpp new file mode 100644 index 0000000..60e66a9 --- /dev/null +++ b/V8Binding/binding/V8NPObject.cpp @@ -0,0 +1,369 @@ +// Copyright (c) 2008, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#include "config.h" + +#include "v8_custom.h" +#include "v8_helpers.h" +#include "V8NPObject.h" +#include "V8NPUtils.h" +#include "NPV8Object.h" +#include "npruntime_priv.h" +#include "v8_proxy.h" +#include "dom_wrapper_map.h" +#include "HTMLPlugInElement.h" +#include "V8HTMLAppletElement.h" +#include "V8HTMLEmbedElement.h" +#include "V8HTMLObjectElement.h" + +using namespace WebCore; + +enum InvokeFunctionType { + INVOKE_METHOD = 1, + INVOKE_DEFAULT = 2 +}; + +// TODO(mbelshe): need comments. +// Params: holder could be HTMLEmbedElement or NPObject +static v8::Handle<v8::Value> NPObjectInvokeImpl(const v8::Arguments& args, InvokeFunctionType funcId) +{ + NPObject* npobject; + + // These three types are subtypes of HTMLPlugInElement. + if (V8HTMLAppletElement::HasInstance(args.Holder()) || + V8HTMLEmbedElement::HasInstance(args.Holder()) || + V8HTMLObjectElement::HasInstance(args.Holder())) { + // The holder object is a subtype of HTMLPlugInElement. + HTMLPlugInElement* imp = V8Proxy::DOMWrapperToNode<HTMLPlugInElement>(args.Holder()); + ScriptInstance scriptInstance = imp->getInstance(); + if (scriptInstance) + npobject = V8Proxy::ToNativeObject<NPObject>(V8ClassIndex::NPOBJECT, scriptInstance->instance()); + else + npobject = NULL; + } else { + // The holder object is not a subtype of HTMLPlugInElement, it + // must be an NPObject which has three internal fields. + if (args.Holder()->InternalFieldCount() != V8Custom::kNPObjectInternalFieldCount) { + V8Proxy::ThrowError(V8Proxy::REFERENCE_ERROR, "NPMethod called on non-NPObject"); + return v8::Undefined(); + } + npobject = V8Proxy::ToNativeObject<NPObject>(V8ClassIndex::NPOBJECT, args.Holder()); + } + + // Verify that our wrapper wasn't using a NPObject which + // has already been deleted. + if (!npobject || !_NPN_IsAlive(npobject)) { + V8Proxy::ThrowError(V8Proxy::REFERENCE_ERROR, "NPObject deleted"); + return v8::Undefined(); + } + + // wrap up parameters + int argc = args.Length(); + NPVariant* npArgs = new NPVariant[argc]; + + for (int i = 0; i < argc; i++) + convertV8ObjectToNPVariant(args[i], npobject, &npArgs[i]); + + NPVariant result; + VOID_TO_NPVARIANT(result); + + switch (funcId) { + case INVOKE_METHOD: + if (npobject->_class->invoke) { + v8::Handle<v8::String> function_name(v8::String::Cast(*args.Data())); + NPIdentifier ident = getStringIdentifier(function_name); + npobject->_class->invoke(npobject, ident, npArgs, argc, &result); + } + break; + case INVOKE_DEFAULT: + if (npobject->_class->invokeDefault) + npobject->_class->invokeDefault(npobject, npArgs, argc, &result); + break; + default: + break; + } + + for (int i=0; i < argc; i++) + NPN_ReleaseVariantValue(&npArgs[i]); + delete[] npArgs; + + // unwrap return values + v8::Handle<v8::Value> rv = convertNPVariantToV8Object(&result, npobject); + NPN_ReleaseVariantValue(&result); + + return rv; +} + + +v8::Handle<v8::Value> NPObjectMethodHandler(const v8::Arguments& args) +{ + return NPObjectInvokeImpl(args, INVOKE_METHOD); +} + + +v8::Handle<v8::Value> NPObjectInvokeDefaultHandler(const v8::Arguments& args) +{ + return NPObjectInvokeImpl(args, INVOKE_DEFAULT); +} + + +static void WeakTemplateCallback(v8::Persistent<v8::Value> obj, void* param); + +// NPIdentifier is PrivateIdentifier*. +static WeakReferenceMap<PrivateIdentifier, v8::FunctionTemplate> \ + static_template_map(&WeakTemplateCallback); + +static void WeakTemplateCallback(v8::Persistent<v8::Value> obj, void* param) +{ + PrivateIdentifier* iden = static_cast<PrivateIdentifier*>(param); + ASSERT(iden != NULL); + ASSERT(static_template_map.contains(iden)); + + static_template_map.forget(iden); +} + + +static v8::Handle<v8::Value> NPObjectGetProperty(v8::Local<v8::Object> self, + NPIdentifier ident, + v8::Local<v8::Value> key) +{ + NPObject* npobject = V8Proxy::ToNativeObject<NPObject>(V8ClassIndex::NPOBJECT, self); + + // Verify that our wrapper wasn't using a NPObject which + // has already been deleted. + if (!npobject || !_NPN_IsAlive(npobject)) { + V8Proxy::ThrowError(V8Proxy::REFERENCE_ERROR, "NPObject deleted"); + return v8::Handle<v8::Value>(); + } + + if (npobject->_class->hasProperty && + npobject->_class->hasProperty(npobject, ident) && + npobject->_class->getProperty) { + + NPVariant result; + VOID_TO_NPVARIANT(result); + if (!npobject->_class->getProperty(npobject, ident, &result)) + return v8::Handle<v8::Value>(); + + v8::Handle<v8::Value> rv = convertNPVariantToV8Object(&result, npobject); + NPN_ReleaseVariantValue(&result); + return rv; + } else if (key->IsString() && npobject->_class->hasMethod && npobject->_class->hasMethod(npobject, ident)) { + PrivateIdentifier* id = static_cast<PrivateIdentifier*>(ident); + v8::Persistent<v8::FunctionTemplate> desc = static_template_map.get(id); + // Cache templates using identifier as the key. + if (desc.IsEmpty()) { + // Create a new template + v8::Local<v8::FunctionTemplate> temp = v8::FunctionTemplate::New(); + temp->SetCallHandler(NPObjectMethodHandler, key); + desc = v8::Persistent<v8::FunctionTemplate>::New(temp); + static_template_map.set(id, desc); + } + + // FunctionTemplate caches function for each context. + v8::Local<v8::Function> func = desc->GetFunction(); + func->SetName(v8::Handle<v8::String>::Cast(key)); + return func; + } + + return v8::Handle<v8::Value>(); +} + +v8::Handle<v8::Value> NPObjectNamedPropertyGetter(v8::Local<v8::String> name, + const v8::AccessorInfo& info) +{ + NPIdentifier ident = getStringIdentifier(name); + return NPObjectGetProperty(info.Holder(), ident, name); +} + +v8::Handle<v8::Value> NPObjectIndexedPropertyGetter(uint32_t index, + const v8::AccessorInfo& info) +{ + NPIdentifier ident = NPN_GetIntIdentifier(index); + return NPObjectGetProperty(info.Holder(), ident, v8::Number::New(index)); +} + +v8::Handle<v8::Value> NPObjectGetNamedProperty(v8::Local<v8::Object> self, + v8::Local<v8::String> name) +{ + NPIdentifier ident = getStringIdentifier(name); + return NPObjectGetProperty(self, ident, name); +} + +v8::Handle<v8::Value> NPObjectGetIndexedProperty(v8::Local<v8::Object> self, + uint32_t index) +{ + NPIdentifier ident = NPN_GetIntIdentifier(index); + return NPObjectGetProperty(self, ident, v8::Number::New(index)); +} + +static v8::Handle<v8::Value> NPObjectSetProperty(v8::Local<v8::Object> self, + NPIdentifier ident, + v8::Local<v8::Value> value) +{ + NPObject* npobject = V8Proxy::ToNativeObject<NPObject>(V8ClassIndex::NPOBJECT, self); + + // Verify that our wrapper wasn't using a NPObject which + // has already been deleted. + if (!npobject || !_NPN_IsAlive(npobject)) { + V8Proxy::ThrowError(V8Proxy::REFERENCE_ERROR, "NPObject deleted"); + return value; // intercepted, but an exception was thrown + } + + if (npobject->_class->hasProperty && + npobject->_class->hasProperty(npobject, ident) && + npobject->_class->setProperty) { + + NPVariant npvalue; + VOID_TO_NPVARIANT(npvalue); + convertV8ObjectToNPVariant(value, npobject, &npvalue); + bool succ = npobject->_class->setProperty(npobject, ident, &npvalue); + NPN_ReleaseVariantValue(&npvalue); + if (succ) + return value; // intercept the call + } + return v8::Local<v8::Value>(); // do not intercept the call +} + + +v8::Handle<v8::Value> NPObjectNamedPropertySetter(v8::Local<v8::String> name, + v8::Local<v8::Value> value, + const v8::AccessorInfo& info) +{ + NPIdentifier ident = getStringIdentifier(name); + return NPObjectSetProperty(info.Holder(), ident, value); +} + + +v8::Handle<v8::Value> NPObjectIndexedPropertySetter(uint32_t index, + v8::Local<v8::Value> value, + const v8::AccessorInfo& info) +{ + NPIdentifier ident = NPN_GetIntIdentifier(index); + return NPObjectSetProperty(info.Holder(), ident, value); +} + +v8::Handle<v8::Value> NPObjectSetNamedProperty(v8::Local<v8::Object> self, + v8::Local<v8::String> name, + v8::Local<v8::Value> value) +{ + NPIdentifier ident = getStringIdentifier(name); + return NPObjectSetProperty(self, ident, value); +} + +v8::Handle<v8::Value> NPObjectSetIndexedProperty(v8::Local<v8::Object> self, + uint32_t index, + v8::Local<v8::Value> value) +{ + NPIdentifier ident = NPN_GetIntIdentifier(index); + return NPObjectSetProperty(self, ident, value); +} + + +static void WeakNPObjectCallback(v8::Persistent<v8::Value> obj, void* param); + +static DOMWrapperMap<NPObject> staticNpobjectMap(&WeakNPObjectCallback); + +static void WeakNPObjectCallback(v8::Persistent<v8::Value> obj, void* param) +{ + NPObject* npobject = static_cast<NPObject*>(param); + ASSERT(staticNpobjectMap.contains(npobject)); + ASSERT(npobject != NULL); + + // Must remove from our map before calling NPN_ReleaseObject(). + // NPN_ReleaseObject can call ForgetV8ObjectForNPObject, which + // uses the table as well. + staticNpobjectMap.forget(npobject); + + if (_NPN_IsAlive(npobject)) + NPN_ReleaseObject(npobject); +} + + +v8::Local<v8::Object> CreateV8ObjectForNPObject(NPObject* object, NPObject* root) +{ + static v8::Persistent<v8::FunctionTemplate> npObjectDesc; + + ASSERT(v8::Context::InContext()); + + // If this is a v8 object, just return it. + if (object->_class == npScriptObjectClass) { + V8NPObject* v8npobject = reinterpret_cast<V8NPObject*>(object); + return v8::Local<v8::Object>::New(v8npobject->v8Object); + } + + // If we've already wrapped this object, just return it. + if (staticNpobjectMap.contains(object)) + return v8::Local<v8::Object>::New(staticNpobjectMap.get(object)); + + // TODO: we should create a Wrapper type as a subclass of JSObject. + // It has two internal fields, field 0 is the wrapped pointer, + // and field 1 is the type. There should be an api function that + // returns unused type id. + // The same Wrapper type can be used by DOM bindings. + if (npObjectDesc.IsEmpty()) { + npObjectDesc = v8::Persistent<v8::FunctionTemplate>::New(v8::FunctionTemplate::New()); + npObjectDesc->InstanceTemplate()->SetInternalFieldCount(V8Custom::kNPObjectInternalFieldCount); + npObjectDesc->InstanceTemplate()->SetNamedPropertyHandler(NPObjectNamedPropertyGetter, NPObjectNamedPropertySetter); + npObjectDesc->InstanceTemplate()->SetIndexedPropertyHandler(NPObjectIndexedPropertyGetter, NPObjectIndexedPropertySetter); + npObjectDesc->InstanceTemplate()->SetCallAsFunctionHandler(NPObjectInvokeDefaultHandler); + } + + v8::Handle<v8::Function> func = npObjectDesc->GetFunction(); + v8::Local<v8::Object> value = SafeAllocation::NewInstance(func); + + // If we were unable to allocate the instance we avoid wrapping + // and registering the NP object. + if (value.IsEmpty()) + return value; + + WrapNPObject(value, object); + + // KJS retains the object as part of its wrapper (see Bindings::CInstance) + NPN_RetainObject(object); + + _NPN_RegisterObject(object, root); + + // Maintain a weak pointer for v8 so we can cleanup the object. + v8::Persistent<v8::Object> weakRef = v8::Persistent<v8::Object>::New(value); + staticNpobjectMap.set(object, weakRef); + + return value; +} + +void ForgetV8ObjectForNPObject(NPObject* object) +{ + if (staticNpobjectMap.contains(object)) { + v8::HandleScope scope; + v8::Persistent<v8::Object> handle(staticNpobjectMap.get(object)); + WebCore::V8Proxy::SetDOMWrapper(handle, WebCore::V8ClassIndex::NPOBJECT, NULL); + staticNpobjectMap.forget(object); + NPN_ReleaseObject(object); + } +} diff --git a/V8Binding/binding/V8NPObject.h b/V8Binding/binding/V8NPObject.h new file mode 100644 index 0000000..04cbff1 --- /dev/null +++ b/V8Binding/binding/V8NPObject.h @@ -0,0 +1,57 @@ +// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef v8_npobject_h +#define v8_npobject_h + +#include <v8.h> +#if PLATFORM(CHROMIUM) +#include "third_party/npapi/bindings/npruntime.h" +#else +#include "bridge/npruntime.h" // use WebCore version +#endif + +// These functions can be replaced by normal JS operation. +// Getters +v8::Handle<v8::Value> NPObjectNamedPropertyGetter(v8::Local<v8::String> name, + const v8::AccessorInfo& info); +v8::Handle<v8::Value> NPObjectIndexedPropertyGetter(uint32_t index, + const v8::AccessorInfo& info); +v8::Handle<v8::Value> NPObjectGetNamedProperty(v8::Local<v8::Object> self, + v8::Local<v8::String> name); +v8::Handle<v8::Value> NPObjectGetIndexedProperty(v8::Local<v8::Object> self, + uint32_t index); + +// Setters +v8::Handle<v8::Value> NPObjectNamedPropertySetter(v8::Local<v8::String> name, + v8::Local<v8::Value> value, + const v8::AccessorInfo& info); +v8::Handle<v8::Value> NPObjectIndexedPropertySetter(uint32_t index, + const v8::AccessorInfo& info); +v8::Handle<v8::Value> NPObjectSetNamedProperty(v8::Local<v8::Object> self, + v8::Local<v8::String> name, + v8::Local<v8::Value> value); +v8::Handle<v8::Value> NPObjectSetIndexedProperty(v8::Local<v8::Object> self, + uint32_t index, + v8::Local<v8::Value> value); + +v8::Handle<v8::Value> NPObjectInvokeDefaultHandler(const v8::Arguments& args); + +// Get a wrapper for a NPObject. +// If the object is already wrapped, the pre-existing wrapper +// will be returned. +// If the object is not wrapped, wrap it, and give V8 a weak +// reference to the wrapper which will cleanup when there are +// no more JS references to the object. +v8::Local<v8::Object> CreateV8ObjectForNPObject(NPObject* object, NPObject *root); + +// Tell V8 to forcibly remove an object. +// This is used at plugin teardown so that the caller can +// aggressively unload the plugin library. After calling this +// function, the persistent handle to the wrapper will be +// gone, and the wrapped NPObject will be removed so that +// it cannot be referred to. +void ForgetV8ObjectForNPObject(NPObject*object); + +#endif // v8_npobject_h diff --git a/V8Binding/binding/V8NPUtils.cpp b/V8Binding/binding/V8NPUtils.cpp new file mode 100644 index 0000000..04e6ede --- /dev/null +++ b/V8Binding/binding/V8NPUtils.cpp @@ -0,0 +1,124 @@ +// Copyright (c) 2008, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#include "config.h" + +#include "V8NPUtils.h" + +#include "DOMWindow.h" +#include "Frame.h" +#include "PlatformString.h" +#undef LOG + +#include "npruntime_priv.h" +#include "NPV8Object.h" +#include "V8NPObject.h" +#include "v8_proxy.h" + +void convertV8ObjectToNPVariant(v8::Local<v8::Value> object, NPObject *owner, NPVariant* result) +{ + VOID_TO_NPVARIANT(*result); + + // It is really the caller's responsibility to deal with the empty handle + // case because there could be different actions to take in different + // contexts. + ASSERT(!object.IsEmpty()); + + if (object.IsEmpty()) + return; + + if (object->IsInt32()) + INT32_TO_NPVARIANT(object->NumberValue(), *result); + else if (object->IsNumber()) + DOUBLE_TO_NPVARIANT(object->NumberValue(), *result); + else if (object->IsBoolean()) + BOOLEAN_TO_NPVARIANT(object->BooleanValue(), *result); + else if (object->IsNull()) + NULL_TO_NPVARIANT(*result); + else if (object->IsUndefined()) + VOID_TO_NPVARIANT(*result); + else if (object->IsString()) { + v8::String::Utf8Value utf8(object); + char* utf8_chars = strdup(*utf8); + STRINGN_TO_NPVARIANT(utf8_chars, utf8.length(), *result); + } else if (object->IsObject()) { + WebCore::DOMWindow* window = WebCore::V8Proxy::retrieveWindow(); + NPObject* npobject = npCreateV8ScriptObject(0, v8::Handle<v8::Object>::Cast(object), window); + if (npobject) + _NPN_RegisterObject(npobject, owner); + OBJECT_TO_NPVARIANT(npobject, *result); + } +} + + +v8::Handle<v8::Value> convertNPVariantToV8Object(const NPVariant* variant, NPObject* npobject) +{ + NPVariantType type = variant->type; + + if (type == NPVariantType_Int32) + return v8::Integer::New(NPVARIANT_TO_INT32(*variant)); + if (type == NPVariantType_Double) + return v8::Number::New(NPVARIANT_TO_DOUBLE(*variant)); + if (type == NPVariantType_Bool) + return NPVARIANT_TO_BOOLEAN(*variant) ? v8::True() : v8::False(); + if (type == NPVariantType_Null) + return v8::Null(); + if (type == NPVariantType_Void) + return v8::Undefined(); + if (type == NPVariantType_String) { + NPString src = NPVARIANT_TO_STRING(*variant); + return v8::String::New(src.UTF8Characters, src.UTF8Length); + } + if (type == NPVariantType_Object) { + NPObject* obj = NPVARIANT_TO_OBJECT(*variant); + if (obj->_class == npScriptObjectClass) + return reinterpret_cast<V8NPObject*>(obj)->v8Object; + return CreateV8ObjectForNPObject(obj, npobject); + } + return v8::Undefined(); +} + +// Helper function to create an NPN String Identifier from a v8 string. +NPIdentifier getStringIdentifier(v8::Handle<v8::String> str) +{ + const int kStackBufSize = 100; + + int bufLen = str->Length() + 1; + if (bufLen <= kStackBufSize) { + // Use local stack buffer to avoid heap allocations for small strings. + // Here we should only use the stack space for stack_buf when it's used, + // not when we use the heap. + char stackBuf[kStackBufSize]; + str->WriteAscii(stackBuf); + return NPN_GetStringIdentifier(stackBuf); + } + + v8::String::AsciiValue ascii(str); + return NPN_GetStringIdentifier(*ascii); +} diff --git a/V8Binding/binding/V8NPUtils.h b/V8Binding/binding/V8NPUtils.h new file mode 100644 index 0000000..2e07e66 --- /dev/null +++ b/V8Binding/binding/V8NPUtils.h @@ -0,0 +1,31 @@ +// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef v8_np_utils_h +#define v8_np_utils_h + +#include <v8.h> +#if PLATFORM(CHROMIUM) +#include "third_party/npapi/bindings/npruntime.h" +#else +#include "bridge/npruntime.h" // use WebCore version +#endif + +namespace WebCore { + class Frame; +} + +// Convert a V8 Value of any type (string, bool, object, etc) to a NPVariant. +void convertV8ObjectToNPVariant(v8::Local<v8::Value> object, NPObject *owner, NPVariant* result); + +// Convert a NPVariant (string, bool, object, etc) back to a V8 Value. +// The owner object is the NPObject which relates to the object, if the object +// is an Object. The created NPObject will be tied to the lifetime of the +// owner. +v8::Handle<v8::Value> convertNPVariantToV8Object(const NPVariant* value, NPObject* owner); + +// Helper function to create an NPN String Identifier from a v8 string. +NPIdentifier getStringIdentifier(v8::Handle<v8::String> str); + +#endif // v8_np_utils_h diff --git a/V8Binding/binding/V8SVGPODTypeWrapper.h b/V8Binding/binding/V8SVGPODTypeWrapper.h new file mode 100644 index 0000000..79553c2 --- /dev/null +++ b/V8Binding/binding/V8SVGPODTypeWrapper.h @@ -0,0 +1,363 @@ +/* + * Copyright (C) 2006, 2008 Nikolas Zimmermann <zimmermann@kde.org> + * Copyright (C) 2008 Apple Inc. All rights reserved. + * Copyright (C) 2008 The Chromium Authors. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef V8SVGPODTypeWrapper_h +#define V8SVGPODTypeWrapper_h + +#if ENABLE(SVG) + +#include "config.h" +#include "SVGElement.h" +#include "SVGList.h" +#include <wtf/Assertions.h> +#include <wtf/RefCounted.h> +#include <wtf/HashMap.h> + +namespace WebCore { + +template<typename PODType> +class V8SVGPODTypeWrapper : public RefCounted<V8SVGPODTypeWrapper<PODType> > { +public: + V8SVGPODTypeWrapper() { } + virtual ~V8SVGPODTypeWrapper() { } + virtual operator PODType() = 0; + virtual void commitChange(PODType, SVGElement*) = 0; +}; + +template<typename PODType> +class V8SVGPODTypeWrapperCreatorForList : public V8SVGPODTypeWrapper<PODType> +{ +public: + typedef PODType (SVGPODListItem<PODType>::*GetterMethod)() const; + typedef void (SVGPODListItem<PODType>::*SetterMethod)(PODType); + + V8SVGPODTypeWrapperCreatorForList(SVGPODListItem<PODType>* creator, const QualifiedName& attributeName) + : m_creator(creator) + , m_getter(&SVGPODListItem<PODType>::value) + , m_setter(&SVGPODListItem<PODType>::setValue) + , m_associatedAttributeName(attributeName) + { + ASSERT(m_creator); + ASSERT(m_getter); + ASSERT(m_setter); + } + + virtual ~V8SVGPODTypeWrapperCreatorForList() { } + + // Getter wrapper + virtual operator PODType() { return (m_creator.get()->*m_getter)(); } + + // Setter wrapper + virtual void commitChange(PODType type, SVGElement* context) + { + if (!m_setter) + return; + + (m_creator.get()->*m_setter)(type); + + if (context) + context->svgAttributeChanged(m_associatedAttributeName); + } + +private: + // Update callbacks + RefPtr<SVGPODListItem<PODType> > m_creator; + GetterMethod m_getter; + SetterMethod m_setter; + const QualifiedName& m_associatedAttributeName; +}; + +template<typename PODType> +class V8SVGStaticPODTypeWrapper : public V8SVGPODTypeWrapper<PODType> +{ +public: + V8SVGStaticPODTypeWrapper(PODType type) + : m_podType(type) + { } + + virtual ~V8SVGStaticPODTypeWrapper() { } + + // Getter wrapper + virtual operator PODType() { return m_podType; } + + // Setter wrapper + virtual void commitChange(PODType type, SVGElement*) + { + m_podType = type; + } + +private: + PODType m_podType; +}; + +template<typename PODType, typename ParentTypeArg> +class V8SVGStaticPODTypeWrapperWithPODTypeParent : public V8SVGStaticPODTypeWrapper<PODType> { +public: + typedef V8SVGPODTypeWrapper<ParentTypeArg> ParentType; + + V8SVGStaticPODTypeWrapperWithPODTypeParent(PODType type, ParentType* parent) + : V8SVGStaticPODTypeWrapper<PODType>(type) + , m_parentType(parent) + { + } + + virtual void commitChange(PODType type, SVGElement* context) + { + V8SVGStaticPODTypeWrapper<PODType>::commitChange(type, context); + m_parentType->commitChange(ParentTypeArg(type), context); + } + +private: + RefPtr<ParentType> m_parentType; +}; + +template<typename PODType, typename ParentType> +class V8SVGStaticPODTypeWrapperWithParent : public V8SVGPODTypeWrapper<PODType> { +public: + typedef PODType (ParentType::*GetterMethod)() const; + typedef void (ParentType::*SetterMethod)(const PODType&); + + V8SVGStaticPODTypeWrapperWithParent(ParentType* parent, GetterMethod getter, SetterMethod setter) + : m_parent(parent) + , m_getter(getter) + , m_setter(setter) + { + ASSERT(m_parent); + ASSERT(m_getter); + ASSERT(m_setter); + } + + virtual operator PODType() + { + return (m_parent.get()->*m_getter)(); + } + + virtual void commitChange(PODType type, SVGElement* context) + { + (m_parent.get()->*m_setter)(type); + } + +private: + // Update callbacks + RefPtr<ParentType> m_parent; + GetterMethod m_getter; + SetterMethod m_setter; +}; + +template<typename PODType, typename PODTypeCreator> +class V8SVGDynamicPODTypeWrapper : public V8SVGPODTypeWrapper<PODType> +{ +public: + typedef PODType (PODTypeCreator::*GetterMethod)() const; + typedef void (PODTypeCreator::*SetterMethod)(PODType); + typedef void (*CacheRemovalCallback)(V8SVGPODTypeWrapper<PODType>*); + + V8SVGDynamicPODTypeWrapper(PODTypeCreator* creator, GetterMethod getter, SetterMethod setter, CacheRemovalCallback cacheRemovalCallback) + : m_creator(creator) + , m_getter(getter) + , m_setter(setter) + , m_cacheRemovalCallback(cacheRemovalCallback) + { + ASSERT(creator); + ASSERT(getter); + ASSERT(setter); + ASSERT(cacheRemovalCallback); + } + + virtual ~V8SVGDynamicPODTypeWrapper() { + ASSERT(m_cacheRemovalCallback); + + (*m_cacheRemovalCallback)(this); + } + + // Getter wrapper + virtual operator PODType() { return (m_creator.get()->*m_getter)(); } + + // Setter wrapper + virtual void commitChange(PODType type, SVGElement* context) + { + (m_creator.get()->*m_setter)(type); + + if (context) + context->svgAttributeChanged(m_creator->associatedAttributeName()); + } + +private: + // Update callbacks + RefPtr<PODTypeCreator> m_creator; + GetterMethod m_getter; + SetterMethod m_setter; + CacheRemovalCallback m_cacheRemovalCallback; +}; + +// Caching facilities +template<typename PODType, typename PODTypeCreator> +struct PODTypeWrapperCacheInfo { + typedef PODType (PODTypeCreator::*GetterMethod)() const; + typedef void (PODTypeCreator::*SetterMethod)(PODType); + + // Empty value + PODTypeWrapperCacheInfo() + : creator(0) + , getter(0) + , setter(0) + { } + + // Deleted value + explicit PODTypeWrapperCacheInfo(WTF::HashTableDeletedValueType) + : creator(reinterpret_cast<PODTypeCreator*>(-1)) + , getter(0) + , setter(0) + { + } + bool isHashTableDeletedValue() const + { + return creator == reinterpret_cast<PODTypeCreator*>(-1); + } + + PODTypeWrapperCacheInfo(PODTypeCreator* _creator, GetterMethod _getter, SetterMethod _setter) + : creator(_creator) + , getter(_getter) + , setter(_setter) + { + ASSERT(creator); + ASSERT(getter); + } + + bool operator==(const PODTypeWrapperCacheInfo& other) const + { + return creator == other.creator && getter == other.getter && setter == other.setter; + } + + PODTypeCreator* creator; + GetterMethod getter; + SetterMethod setter; +}; + +template<typename PODType, typename PODTypeCreator> +struct PODTypeWrapperCacheInfoHash { + static unsigned hash(const PODTypeWrapperCacheInfo<PODType, PODTypeCreator>& info) + { + unsigned creator = reinterpret_cast<unsigned>(info.creator); + unsigned getter = reinterpret_cast<unsigned>(*(void**)&info.getter); + unsigned setter = reinterpret_cast<unsigned>(*(void**)&info.setter); + return (creator * 13) + getter ^ (setter >> 2); + } + + static bool equal(const PODTypeWrapperCacheInfo<PODType, PODTypeCreator>& a, const PODTypeWrapperCacheInfo<PODType, PODTypeCreator>& b) + { + return a == b; + } + + static const bool safeToCompareToEmptyOrDeleted = true; +}; + +template<typename PODType, typename PODTypeCreator> +struct PODTypeWrapperCacheInfoTraits : WTF::GenericHashTraits<PODTypeWrapperCacheInfo<PODType, PODTypeCreator> > { + typedef PODTypeWrapperCacheInfo<PODType, PODTypeCreator> CacheInfo; + + static const bool emptyValueIsZero = true; + static const bool needsDestruction = false; + + static const CacheInfo& emptyValue() + { + static CacheInfo key; + return key; + } + + static void constructDeletedValue(CacheInfo& slot) + { + new (&slot) CacheInfo(WTF::HashTableDeletedValue); + } + + static bool isDeletedValue(const CacheInfo& value) + { + return value.isHashTableDeletedValue(); + } +}; + +template<typename PODType, typename PODTypeCreator> +class V8SVGDynamicPODTypeWrapperCache +{ +public: + typedef PODType (PODTypeCreator::*GetterMethod)() const; + typedef void (PODTypeCreator::*SetterMethod)(PODType); + + typedef PODTypeWrapperCacheInfo<PODType, PODTypeCreator> CacheInfo; + typedef PODTypeWrapperCacheInfoHash<PODType, PODTypeCreator> CacheInfoHash; + typedef PODTypeWrapperCacheInfoTraits<PODType, PODTypeCreator> CacheInfoTraits; + + typedef V8SVGPODTypeWrapper<PODType> WrapperBase; + typedef V8SVGDynamicPODTypeWrapper<PODType, PODTypeCreator> DynamicWrapper; + + typedef HashMap<CacheInfo, DynamicWrapper*, CacheInfoHash, CacheInfoTraits> DynamicWrapperHashMap; + typedef typename DynamicWrapperHashMap::const_iterator DynamicWrapperHashMapIterator; + + static DynamicWrapperHashMap& dynamicWrapperHashMap() + { + static DynamicWrapperHashMap _dynamicWrapperHashMap; + return _dynamicWrapperHashMap; + } + + // Used for readwrite attributes only + static WrapperBase* lookupOrCreateWrapper(PODTypeCreator* creator, GetterMethod getter, SetterMethod setter) + { + DynamicWrapperHashMap& map(dynamicWrapperHashMap()); + CacheInfo info(creator, getter, setter); + + if (map.contains(info)) + return map.get(info); + + DynamicWrapper* wrapper = new V8SVGDynamicPODTypeWrapper<PODType, PODTypeCreator>( + creator, getter, setter, forgetWrapper); + map.set(info, wrapper); + return wrapper; + } + + static void forgetWrapper(V8SVGPODTypeWrapper<PODType>* wrapper) + { + DynamicWrapperHashMap& map(dynamicWrapperHashMap()); + + DynamicWrapperHashMapIterator it = map.begin(); + DynamicWrapperHashMapIterator end = map.end(); + + for (; it != end; ++it) { + if (it->second != wrapper) + continue; + + // It's guaranteed that there's just one object we need to take care of. + map.remove(it->first); + break; + } + } +}; + + +} // namespace WebCore + +#endif // ENABLE(SVG) +#endif // V8SVGPODTypeWrapper_h diff --git a/V8Binding/binding/V8Utilities.cpp b/V8Binding/binding/V8Utilities.cpp new file mode 100644 index 0000000..8853506 --- /dev/null +++ b/V8Binding/binding/V8Utilities.cpp @@ -0,0 +1,110 @@ +/* + * Copyright (C) 2008, 2009 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "V8Utilities.h" + +#include <v8.h> + +#include "V8CustomBinding.h" +#include "V8Proxy.h" + +#include <wtf/Assertions.h> +#include "Frame.h" + +namespace WebCore { + +// Use an array to hold dependents. It works like a ref-counted scheme. +// A value can be added more than once to the DOM object. +void createHiddenDependency(v8::Local<v8::Object> object, v8::Local<v8::Value> value, int cacheIndex) +{ + v8::Local<v8::Value> cache = object->GetInternalField(cacheIndex); + if (cache->IsNull() || cache->IsUndefined()) { + cache = v8::Array::New(); + object->SetInternalField(cacheIndex, cache); + } + + v8::Local<v8::Array> cacheArray = v8::Local<v8::Array>::Cast(cache); + cacheArray->Set(v8::Integer::New(cacheArray->Length()), value); +} + +void removeHiddenDependency(v8::Local<v8::Object> object, v8::Local<v8::Value> value, int cacheIndex) +{ + v8::Local<v8::Value> cache = object->GetInternalField(cacheIndex); + ASSERT(cache->IsArray()); + v8::Local<v8::Array> cacheArray = v8::Local<v8::Array>::Cast(cache); + for (int i = cacheArray->Length() - 1; i >= 0; --i) { + v8::Local<v8::Value> cached = cacheArray->Get(v8::Integer::New(i)); + if (cached->StrictEquals(value)) { + cacheArray->Delete(i); + return; + } + } + + // We should only get here if we try to remove an event listener that was never added. + ASSERT_NOT_REACHED(); +} + +#if PLATFORM(ANDROID) + // The functions below are not needed on Android. +#else +bool processingUserGesture() +{ + Frame* frame = V8Proxy::retrieveFrameForEnteredContext(); + return frame && frame->script()->processingUserGesture(); +} + +bool shouldAllowNavigation(Frame* frame) +{ + Frame* callingFrame = V8Proxy::retrieveFrameForCallingContext(); + return callingFrame && callingFrame->loader()->shouldAllowNavigation(frame); +} + +KURL completeURL(const String& relativeURL) +{ + // For histoical reasons, we need to complete the URL using the dynamic frame. + Frame* frame = V8Proxy::retrieveFrameForEnteredContext(); + if (!frame) + return KURL(); + return frame->loader()->completeURL(relativeURL); +} + +void navigateIfAllowed(Frame* frame, const KURL& url, bool lockHistory, bool lockBackForwardList) +{ + Frame* callingFrame = V8Proxy::retrieveFrameForCallingContext(); + if (!callingFrame) + return; + + if (!protocolIsJavaScript(url) || ScriptController::isSafeScript(frame)) + frame->loader()->scheduleLocationChange(url.string(), callingFrame->loader()->outgoingReferrer(), lockHistory, lockBackForwardList, processingUserGesture()); +} +#endif // PLATFORM(ANDROID) + +} // namespace WebCore diff --git a/V8Binding/binding/V8Utilities.h b/V8Binding/binding/V8Utilities.h new file mode 100644 index 0000000..f4346f6 --- /dev/null +++ b/V8Binding/binding/V8Utilities.h @@ -0,0 +1,131 @@ +/* + * Copyright (C) 2006, 2007, 2008, 2009 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef V8Utilities_h +#define V8Utilities_h + +// FIXME: Remove once chromium dependencies on v8_utility.h are removed. +#define V8UTILITIES_DEFINED 1 + +#include <v8.h> + +namespace WebCore { + + class Frame; + class KURL; + class String; + + // Use an array to hold dependents. It works like a ref-counted scheme. A value can be added more than once to the DOM object. + void createHiddenDependency(v8::Local<v8::Object>, v8::Local<v8::Value>, int cacheIndex); + void removeHiddenDependency(v8::Local<v8::Object>, v8::Local<v8::Value>, int cacheIndex); + +#if PLATFORM(ANDROID) + // The functions below are not needed (yet) on Android. +#else + bool processingUserGesture(); + bool shouldAllowNavigation(Frame*); + KURL completeURL(const String& relativeURL); + void navigateIfAllowed(Frame*, const KURL&, bool lockHistory, bool lockBackForwardList); +#endif // PLATFORM(ANDROID) + + class AllowAllocation { + public: + inline AllowAllocation() + { + m_previous = m_current; + m_current = true; + } + + inline ~AllowAllocation() + { + m_current = m_previous; + } + + static bool m_current; + + private: + bool m_previous; + }; + + class SafeAllocation { + public: + static inline v8::Local<v8::Object> newInstance(v8::Handle<v8::Function>); + static inline v8::Local<v8::Object> newInstance(v8::Handle<v8::ObjectTemplate>); + static inline v8::Local<v8::Object> newInstance(v8::Handle<v8::Function>, int argc, v8::Handle<v8::Value> argv[]); + + // FIXME: These NewInstance functions are here to ease upstreaming. Remove along with V8UTILITIES_DEFINED once chromium dependencies on v8_utility.h are removed. + static inline v8::Local<v8::Object> NewInstance(v8::Handle<v8::Function>); + static inline v8::Local<v8::Object> NewInstance(v8::Handle<v8::ObjectTemplate>); + static inline v8::Local<v8::Object> NewInstance(v8::Handle<v8::Function>, int argc, v8::Handle<v8::Value> argv[]); + }; + + v8::Local<v8::Object> SafeAllocation::newInstance(v8::Handle<v8::Function> function) + { + if (function.IsEmpty()) + return v8::Local<v8::Object>(); + AllowAllocation allow; + return function->NewInstance(); + } + + v8::Local<v8::Object> SafeAllocation::newInstance(v8::Handle<v8::ObjectTemplate> objectTemplate) + { + if (objectTemplate.IsEmpty()) + return v8::Local<v8::Object>(); + AllowAllocation allow; + return objectTemplate->NewInstance(); + } + + v8::Local<v8::Object> SafeAllocation::newInstance(v8::Handle<v8::Function> function, int argc, v8::Handle<v8::Value> argv[]) + { + if (function.IsEmpty()) + return v8::Local<v8::Object>(); + AllowAllocation allow; + return function->NewInstance(argc, argv); + } + + // FIXME: These NewInstance functions are here to ease upstreaming. Remove along with V8UTILITIES_DEFINED once chromium dependencies on v8_utility.h are removed. + v8::Local<v8::Object> SafeAllocation::NewInstance(v8::Handle<v8::Function> function) + { + return newInstance(function); + } + + v8::Local<v8::Object> SafeAllocation::NewInstance(v8::Handle<v8::ObjectTemplate> objectTemplate) + { + return newInstance(objectTemplate); + } + + v8::Local<v8::Object> SafeAllocation::NewInstance(v8::Handle<v8::Function> function, int argc, v8::Handle<v8::Value> argv[]) + { + return newInstance(function, argc, argv); + } + +} // namespace WebCore + +#endif // V8Utilities_h diff --git a/V8Binding/binding/V8WorkerContextCustom.cpp b/V8Binding/binding/V8WorkerContextCustom.cpp new file mode 100644 index 0000000..e646bb5 --- /dev/null +++ b/V8Binding/binding/V8WorkerContextCustom.cpp @@ -0,0 +1,230 @@ +// Copyright (c) 2009, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#include "config.h" + +#if ENABLE(WORKERS) + +#include "v8_binding.h" +#include "v8_custom.h" +#include "v8_proxy.h" +#include "WorkerContextExecutionProxy.h" + +#include "ExceptionCode.h" +#include "MessagePort.h" +#include "NotImplemented.h" +#include "V8Document.h" +#include "V8HTMLDocument.h" +#include "V8WorkerContextEventListener.h" +#include "WorkerContext.h" + +namespace WebCore { + +// TODO(mbelshe) - merge these with XHR's CreateHiddenXHRDependency + +// Use an array to hold dependents. It works like a ref-counted scheme. +// A value can be added more than once to the xhr object. +static void CreateHiddenDependency(v8::Local<v8::Object> object, + v8::Local<v8::Value> value) { + ASSERT(V8Proxy::GetDOMWrapperType(object) == V8ClassIndex::WORKERCONTEXT); + v8::Local<v8::Value> cache = + object->GetInternalField(V8Custom::kWorkerContextRequestCacheIndex); + if (cache->IsNull() || cache->IsUndefined()) { + cache = v8::Array::New(); + object->SetInternalField(V8Custom::kWorkerContextRequestCacheIndex, cache); + } + + v8::Local<v8::Array> cache_array = v8::Local<v8::Array>::Cast(cache); + cache_array->Set(v8::Integer::New(cache_array->Length()), value); +} + +static void RemoveHiddenDependency(v8::Local<v8::Object> object, + v8::Local<v8::Value> value) { + ASSERT(V8Proxy::GetDOMWrapperType(object) == V8ClassIndex::WORKERCONTEXT); + v8::Local<v8::Value> cache = + object->GetInternalField(V8Custom::kWorkerContextRequestCacheIndex); + ASSERT(cache->IsArray()); + v8::Local<v8::Array> cache_array = v8::Local<v8::Array>::Cast(cache); + for (int i = cache_array->Length() - 1; i >= 0; i--) { + v8::Local<v8::Value> cached = cache_array->Get(v8::Integer::New(i)); + if (cached->StrictEquals(value)) { + cache_array->Delete(i); + return; + } + } + + // We should only get here if we try to remove an event listener that was + // never added. +} + +ACCESSOR_GETTER(WorkerContextSelf) { + INC_STATS(L"DOM.WorkerContext.self._get"); + WorkerContext* imp = V8Proxy::ToNativeObject<WorkerContext>( + V8ClassIndex::WORKERCONTEXT, info.Holder()); + return WorkerContextExecutionProxy::WorkerContextToV8Object(imp); +} + +ACCESSOR_GETTER(WorkerContextOnmessage) { + INC_STATS(L"DOM.WorkerContext.onmessage._get"); + WorkerContext* imp = V8Proxy::ToNativeObject<WorkerContext>( + V8ClassIndex::WORKERCONTEXT, info.Holder()); + if (imp->onmessage()) { + V8WorkerContextEventListener* listener = + static_cast<V8WorkerContextEventListener*>(imp->onmessage()); + v8::Local<v8::Object> v8_listener = listener->getListenerObject(); + return v8_listener; + } + return v8::Undefined(); +} + +ACCESSOR_SETTER(WorkerContextOnmessage) { + INC_STATS(L"DOM.WorkerContext.onmessage._set"); + WorkerContext* imp = V8Proxy::ToNativeObject<WorkerContext>( + V8ClassIndex::WORKERCONTEXT, info.Holder()); + V8WorkerContextEventListener* old_listener = + static_cast<V8WorkerContextEventListener*>(imp->onmessage()); + if (value->IsNull()) { + if (imp->onmessage()) { + v8::Local<v8::Object> old_v8_listener = old_listener->getListenerObject(); + RemoveHiddenDependency(info.Holder(), old_v8_listener); + } + + // Clear the listener + imp->setOnmessage(0); + + } else { + RefPtr<V8EventListener> listener = + imp->script()->proxy()->FindOrCreateEventListener( + v8::Local<v8::Object>::Cast(value), false, false); + if (listener) { + if (old_listener) { + v8::Local<v8::Object> old_v8_listener = + old_listener->getListenerObject(); + RemoveHiddenDependency(info.Holder(), old_v8_listener); + } + + imp->setOnmessage(listener); + CreateHiddenDependency(info.Holder(), value); + } + } +} + +v8::Handle<v8::Value> SetTimeoutOrInterval(const v8::Arguments& args, + bool singleShot) { + WorkerContext* imp = V8Proxy::ToNativeObject<WorkerContext>( + V8ClassIndex::WORKERCONTEXT, args.Holder()); + + int delay = ToInt32(args[1]); + + notImplemented(); + + return v8::Undefined(); +} + +v8::Handle<v8::Value> ClearTimeoutOrInterval(const v8::Arguments& args) { + WorkerContext* imp = V8Proxy::ToNativeObject<WorkerContext>( + V8ClassIndex::WORKERCONTEXT, args.Holder()); + + bool ok = false; + int tid = ToInt32(args[0], ok); + if (ok) { + imp->removeTimeout(tid); + } + + return v8::Undefined(); +} + +CALLBACK_FUNC_DECL(WorkerContextImportScripts) { + INC_STATS(L"DOM.WorkerContext.importScripts()"); + notImplemented(); + return v8::Undefined(); +} + +CALLBACK_FUNC_DECL(WorkerContextSetTimeout) { + INC_STATS(L"DOM.WorkerContext.setTimeout()"); + return SetTimeoutOrInterval(args, true); +} + +CALLBACK_FUNC_DECL(WorkerContextClearTimeout) { + INC_STATS(L"DOM.WorkerContext.clearTimeout()"); + return ClearTimeoutOrInterval(args); +} + +CALLBACK_FUNC_DECL(WorkerContextSetInterval) { + INC_STATS(L"DOM.WorkerContext.setInterval()"); + return SetTimeoutOrInterval(args, false); +} + +CALLBACK_FUNC_DECL(WorkerContextClearInterval) { + INC_STATS(L"DOM.WorkerContext.clearInterval()"); + return ClearTimeoutOrInterval(args); +} + +CALLBACK_FUNC_DECL(WorkerContextAddEventListener) { + INC_STATS(L"DOM.WorkerContext.addEventListener()"); + WorkerContext* imp = V8Proxy::ToNativeObject<WorkerContext>( + V8ClassIndex::WORKERCONTEXT, args.Holder()); + + RefPtr<V8EventListener> listener = + imp->script()->proxy()->FindOrCreateEventListener( + v8::Local<v8::Object>::Cast(args[1]), false, false); + + if (listener) { + String type = ToWebCoreString(args[0]); + bool useCapture = args[2]->BooleanValue(); + imp->addEventListener(type, listener, useCapture); + + CreateHiddenDependency(args.Holder(), args[1]); + } + return v8::Undefined(); +} + +CALLBACK_FUNC_DECL(WorkerContextRemoveEventListener) { + INC_STATS(L"DOM.WorkerContext.removeEventListener()"); + WorkerContext* imp = V8Proxy::ToNativeObject<WorkerContext>( + V8ClassIndex::WORKERCONTEXT, args.Holder()); + WorkerContextExecutionProxy* proxy = imp->script()->proxy(); + + RefPtr<V8EventListener> listener = proxy->FindOrCreateEventListener( + v8::Local<v8::Object>::Cast(args[1]), false, true); + + if (listener) { + String type = ToWebCoreString(args[0]); + bool useCapture = args[2]->BooleanValue(); + imp->removeEventListener(type, listener.get(), useCapture); + + RemoveHiddenDependency(args.Holder(), args[1]); + } + + return v8::Undefined(); +} + +} // namespace WebCore + +#endif // ENABLE(WORKERS) diff --git a/V8Binding/binding/V8WorkerCustom.cpp b/V8Binding/binding/V8WorkerCustom.cpp new file mode 100644 index 0000000..1f7e5fe --- /dev/null +++ b/V8Binding/binding/V8WorkerCustom.cpp @@ -0,0 +1,282 @@ +// Copyright (c) 2008, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#include "config.h" + +#if ENABLE(WORKERS) + +#include "v8_binding.h" +#include "v8_custom.h" +#include "v8_proxy.h" + +#include "ExceptionCode.h" +#include "Frame.h" +#include "MessagePort.h" +#include "V8Document.h" +#include "V8HTMLDocument.h" +#include "V8ObjectEventListener.h" +#include "Worker.h" +#include "WorkerContextExecutionProxy.h" + +namespace WebCore { + +CALLBACK_FUNC_DECL(WorkerConstructor) { + INC_STATS(L"DOM.Worker.Constructor"); + + if (!WorkerContextExecutionProxy::isWebWorkersEnabled()) { + V8Proxy::ThrowError(V8Proxy::SYNTAX_ERROR, "Worker is not enabled."); + return v8::Undefined(); + } + + if (!args.IsConstructCall()) { + V8Proxy::ThrowError(V8Proxy::TYPE_ERROR, + "DOM object constructor cannot be called as a function."); + return v8::Undefined(); + } + + if (args.Length() == 0) { + V8Proxy::ThrowError(V8Proxy::SYNTAX_ERROR, "Not enough arguments"); + return v8::Undefined(); + } + + v8::TryCatch try_catch; + v8::Handle<v8::String> script_url = args[0]->ToString(); + if (try_catch.HasCaught()) { + v8::ThrowException(try_catch.Exception()); + return v8::Undefined(); + } + if (script_url.IsEmpty()) { + return v8::Undefined(); + } + + // Get the document. + Frame* frame = V8Proxy::retrieveFrame(); + if (!frame) + return v8::Undefined(); + Document* document = frame->document(); + + // Create the worker object. + // Note: it's OK to let this RefPtr go out of scope because we also call + // SetDOMWrapper(), which effectively holds a reference to obj. + ExceptionCode ec = 0; + RefPtr<Worker> obj = Worker::create( + ToWebCoreString(script_url), document, ec); + + // Setup the standard wrapper object internal fields. + v8::Handle<v8::Object> wrapper_object = args.Holder(); + V8Proxy::SetDOMWrapper( + wrapper_object, V8ClassIndex::WORKER, obj.get()); + + obj->ref(); + V8Proxy::SetJSWrapperForActiveDOMObject( + obj.get(), v8::Persistent<v8::Object>::New(wrapper_object)); + + return wrapper_object; +} + +// TODO(mbelshe) - merge these with XHR's CreateHiddenXHRDependency + +// Use an array to hold dependents. It works like a ref-counted scheme. +// A value can be added more than once to the xhr object. +static void CreateHiddenDependency(v8::Local<v8::Object> object, + v8::Local<v8::Value> value) { + ASSERT(V8Proxy::GetDOMWrapperType(object) == + V8ClassIndex::WORKER); + v8::Local<v8::Value> cache = + object->GetInternalField(V8Custom::kWorkerRequestCacheIndex); + if (cache->IsNull() || cache->IsUndefined()) { + cache = v8::Array::New(); + object->SetInternalField(V8Custom::kWorkerRequestCacheIndex, cache); + } + + v8::Local<v8::Array> cache_array = v8::Local<v8::Array>::Cast(cache); + cache_array->Set(v8::Integer::New(cache_array->Length()), value); +} + +static void RemoveHiddenDependency(v8::Local<v8::Object> object, + v8::Local<v8::Value> value) { + ASSERT(V8Proxy::GetDOMWrapperType(object) == V8ClassIndex::WORKER); + v8::Local<v8::Value> cache = + object->GetInternalField(V8Custom::kWorkerRequestCacheIndex); + ASSERT(cache->IsArray()); + v8::Local<v8::Array> cache_array = v8::Local<v8::Array>::Cast(cache); + for (int i = cache_array->Length() - 1; i >= 0; i--) { + v8::Local<v8::Value> cached = cache_array->Get(v8::Integer::New(i)); + if (cached->StrictEquals(value)) { + cache_array->Delete(i); + return; + } + } + + // We should only get here if we try to remove an event listener that was + // never added. +} + +ACCESSOR_GETTER(WorkerOnmessage) { + INC_STATS(L"DOM.Worker.onmessage._get"); + Worker* imp = V8Proxy::ToNativeObject<Worker>( + V8ClassIndex::WORKER, info.Holder()); + if (imp->onmessage()) { + V8ObjectEventListener* listener = + static_cast<V8ObjectEventListener*>(imp->onmessage()); + v8::Local<v8::Object> v8_listener = listener->getListenerObject(); + return v8_listener; + } + return v8::Undefined(); +} + +ACCESSOR_SETTER(WorkerOnmessage) { + INC_STATS(L"DOM.Worker.onmessage._set"); + Worker* imp = V8Proxy::ToNativeObject<Worker>( + V8ClassIndex::WORKER, info.Holder()); + V8ObjectEventListener* old_listener = + static_cast<V8ObjectEventListener*>(imp->onmessage()); + if (value->IsNull()) { + if (old_listener) { + v8::Local<v8::Object> old_v8_listener = old_listener->getListenerObject(); + RemoveHiddenDependency(info.Holder(), old_v8_listener); + } + + // Clear the listener + imp->setOnmessage(0); + + } else { + V8Proxy* proxy = V8Proxy::retrieve(imp->scriptExecutionContext()); + if (!proxy) + return; + + RefPtr<EventListener> listener = + proxy->FindOrCreateObjectEventListener(value, false); + if (listener) { + if (old_listener) { + v8::Local<v8::Object> old_v8_listener = + old_listener->getListenerObject(); + RemoveHiddenDependency(info.Holder(), old_v8_listener); + } + + imp->setOnmessage(listener); + CreateHiddenDependency(info.Holder(), value); + } + } +} + +ACCESSOR_GETTER(WorkerOnerror) { + INC_STATS(L"DOM.Worker.onerror._get"); + Worker* imp = V8Proxy::ToNativeObject<Worker>( + V8ClassIndex::WORKER, info.Holder()); + if (imp->onerror()) { + V8ObjectEventListener* listener = + static_cast<V8ObjectEventListener*>(imp->onerror()); + v8::Local<v8::Object> v8_listener = listener->getListenerObject(); + return v8_listener; + } + return v8::Undefined(); +} + +ACCESSOR_SETTER(WorkerOnerror) { + INC_STATS(L"DOM.Worker.onerror._set"); + Worker* imp = V8Proxy::ToNativeObject<Worker>( + V8ClassIndex::WORKER, info.Holder()); + V8ObjectEventListener* old_listener = + static_cast<V8ObjectEventListener*>(imp->onerror()); + if (value->IsNull()) { + if (old_listener) { + v8::Local<v8::Object> old_v8_listener = + old_listener->getListenerObject(); + RemoveHiddenDependency(info.Holder(), old_v8_listener); + } + + // Clear the listener + imp->setOnerror(0); + } else { + V8Proxy* proxy = V8Proxy::retrieve(imp->scriptExecutionContext()); + if (!proxy) + return; + + RefPtr<EventListener> listener = + proxy->FindOrCreateObjectEventListener(value, false); + if (listener) { + if (old_listener) { + v8::Local<v8::Object> old_v8_listener = old_listener->getListenerObject(); + RemoveHiddenDependency(info.Holder(), old_v8_listener); + } + + imp->setOnerror(listener); + CreateHiddenDependency(info.Holder(), value); + } + } +} + +CALLBACK_FUNC_DECL(WorkerAddEventListener) { + INC_STATS(L"DOM.Worker.addEventListener()"); + Worker* imp = V8Proxy::ToNativeObject<Worker>( + V8ClassIndex::WORKER, args.Holder()); + + V8Proxy* proxy = V8Proxy::retrieve(imp->scriptExecutionContext()); + if (!proxy) + return v8::Undefined(); + + RefPtr<EventListener> listener = + proxy->FindOrCreateObjectEventListener(args[1], false); + if (listener) { + String type = ToWebCoreString(args[0]); + bool useCapture = args[2]->BooleanValue(); + imp->addEventListener(type, listener, useCapture); + + CreateHiddenDependency(args.Holder(), args[1]); + } + return v8::Undefined(); +} + +CALLBACK_FUNC_DECL(WorkerRemoveEventListener) { + INC_STATS(L"DOM.Worker.removeEventListener()"); + Worker* imp = V8Proxy::ToNativeObject<Worker>( + V8ClassIndex::WORKER, args.Holder()); + + V8Proxy* proxy = V8Proxy::retrieve(imp->scriptExecutionContext()); + if (!proxy) + return v8::Undefined(); // probably leaked + + RefPtr<EventListener> listener = + proxy->FindObjectEventListener(args[1], false); + + if (listener) { + String type = ToWebCoreString(args[0]); + bool useCapture = args[2]->BooleanValue(); + imp->removeEventListener(type, listener.get(), useCapture); + + RemoveHiddenDependency(args.Holder(), args[1]); + } + + return v8::Undefined(); +} + +} // namespace WebCore + +#endif // ENABLE(WORKERS) diff --git a/V8Binding/binding/dom_wrapper_map.h b/V8Binding/binding/dom_wrapper_map.h new file mode 100644 index 0000000..e95ff88 --- /dev/null +++ b/V8Binding/binding/dom_wrapper_map.h @@ -0,0 +1,72 @@ +// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef BINDINGS_V8_DOM_WRAPPER_MAP +#define BINDINGS_V8_DOM_WRAPPER_MAP + +#include <v8.h> +#include <wtf/HashMap.h> + +// A table of wrappers with weak pointers. +// This table allows us to avoid track wrapped objects for debugging +// and for ensuring that we don't double wrap the same object. +template<class KeyType, class ValueType> +class WeakReferenceMap { + public: + WeakReferenceMap(v8::WeakReferenceCallback callback) : + weak_reference_callback_(callback) { } +#ifndef NDEBUG + virtual ~WeakReferenceMap() { + if (map_.size() > 0) { + fprintf(stderr, "Leak %d JS wrappers.\n", map_.size()); + // Print out details. + } + } +#endif + + // Get the JS wrapper object of an object. + virtual v8::Persistent<ValueType> get(KeyType* obj) { + ValueType* wrapper = map_.get(obj); + return wrapper ? v8::Persistent<ValueType>(wrapper) + : v8::Persistent<ValueType>(); + } + + virtual void set(KeyType* obj, v8::Persistent<ValueType> wrapper) { + ASSERT(!map_.contains(obj)); + wrapper.MakeWeak(obj, weak_reference_callback_); + map_.set(obj, *wrapper); + } + + virtual void forget(KeyType* obj) { + ASSERT(obj); + ValueType* wrapper = map_.take(obj); + if (wrapper) { + v8::Persistent<ValueType> handle(wrapper); + handle.Dispose(); + handle.Clear(); + } + } + + bool contains(KeyType* obj) { + return map_.contains(obj); + } + + HashMap<KeyType*, ValueType*>& impl() { + return map_; + } + + protected: + HashMap<KeyType*, ValueType*> map_; + v8::WeakReferenceCallback weak_reference_callback_; +}; + + +template <class KeyType> +class DOMWrapperMap : public WeakReferenceMap<KeyType, v8::Object> { + public: + DOMWrapperMap(v8::WeakReferenceCallback callback) : + WeakReferenceMap<KeyType, v8::Object>(callback) { } +}; + +#endif // BINDINGS_V8_DOM_WRAPPER_MAP diff --git a/V8Binding/binding/npruntime.cpp b/V8Binding/binding/npruntime.cpp new file mode 100644 index 0000000..f32c63d --- /dev/null +++ b/V8Binding/binding/npruntime.cpp @@ -0,0 +1,436 @@ +/* + * Copyright (C) 2004, 2006 Apple Computer, Inc. All rights reserved. + * Copyright (C) 2007-2009 Google, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" + +#include "NPV8Object.h" +#include "npruntime_priv.h" +#include "V8NPObject.h" + +#include <wtf/HashMap.h> +#include <wtf/HashSet.h> +#include <wtf/Assertions.h> + +// FIXME: Consider removing locks if we're singlethreaded already. +// The static initializer here should work okay, but we want to avoid +// static initialization in general. +// +// Commenting out the locks to avoid dependencies on chrome for now. +// Need a platform abstraction which we can use. +// static Lock StringIdentifierMapLock; + +namespace { + +// We use StringKey here as the key-type to avoid a string copy to +// construct the map key and for faster comparisons than strcmp. +class StringKey { + public: + explicit StringKey(const char* str) + : m_string(str), m_length(strlen(str)) {} + StringKey() : m_string(0), m_length(0) {} + explicit StringKey(WTF::HashTableDeletedValueType) + : m_string(hashTableDeletedValue()), m_length(0) { } + + StringKey& operator=(const StringKey& other) { + this->m_string = other.m_string; + this->m_length = other.m_length; + return *this; + } + + bool isHashTableDeletedValue() const { + return m_string == hashTableDeletedValue(); + } + + const char* m_string; + size_t m_length; + private: + const char* hashTableDeletedValue() const { + return reinterpret_cast<const char*>(-1); + } +}; + +inline bool operator==(const StringKey& x, const StringKey& y) { + if (x.m_length != y.m_length) { + return false; + } else if (x.m_string == y.m_string) { + return true; + } else { + ASSERT(!x.isHashTableDeletedValue() && !y.isHashTableDeletedValue()); + return memcmp(x.m_string, y.m_string, y.m_length) == 0; + } +} + +// Implement WTF::DefaultHash<StringKey>::Hash interface. +struct StringKeyHash { + static unsigned hash(const StringKey& key) { + // Compute string hash. + unsigned hash = 0; + size_t len = key.m_length; + const char* str = key.m_string; + for (size_t i = 0; i < len; i++) { + char c = str[i]; + hash += c; + hash += (hash << 10); + hash ^= (hash >> 6); + } + hash += (hash << 3); + hash ^= (hash >> 11); + hash += (hash << 15); + if (hash == 0) { + hash = 27; + } + return hash; + } + + static bool equal(const StringKey& x, const StringKey& y) { + return x == y; + } + + static const bool safeToCompareToEmptyOrDeleted = true; +}; + +} // namespace + +// Implement HashTraits<StringKey> +struct StringKeyHashTraits : WTF::GenericHashTraits<StringKey> { + static void constructDeletedValue(StringKey& slot) { + new (&slot) StringKey(WTF::HashTableDeletedValue); + } + static bool isDeletedValue(const StringKey& value) { + return value.isHashTableDeletedValue(); + } +}; + +typedef WTF::HashMap<StringKey, PrivateIdentifier*, \ + StringKeyHash, StringKeyHashTraits> StringIdentifierMap; + +static StringIdentifierMap* getStringIdentifierMap() { + static StringIdentifierMap* stringIdentifierMap = 0; + if (!stringIdentifierMap) + stringIdentifierMap = new StringIdentifierMap(); + return stringIdentifierMap; +} + +// FIXME: Consider removing locks if we're singlethreaded already. +// static Lock IntIdentifierMapLock; + +typedef WTF::HashMap<int, PrivateIdentifier*> IntIdentifierMap; + +static IntIdentifierMap* getIntIdentifierMap() { + static IntIdentifierMap* intIdentifierMap = 0; + if (!intIdentifierMap) + intIdentifierMap = new IntIdentifierMap(); + return intIdentifierMap; +} + +extern "C" { + +NPIdentifier NPN_GetStringIdentifier(const NPUTF8* name) { + ASSERT(name); + + if (name) { + // AutoLock safeLock(StringIdentifierMapLock); + + StringKey key(name); + StringIdentifierMap* identMap = getStringIdentifierMap(); + StringIdentifierMap::iterator iter = identMap->find(key); + if (iter != identMap->end()) + return static_cast<NPIdentifier>(iter->second); + + size_t nameLen = key.m_length; + + // We never release identifiers, so this dictionary will grow. + PrivateIdentifier* identifier = static_cast<PrivateIdentifier*>( + malloc(sizeof(PrivateIdentifier) + nameLen + 1)); + char* nameStorage = reinterpret_cast<char*>(identifier + 1); + memcpy(nameStorage, name, nameLen + 1); + identifier->isString = true; + identifier->value.string = reinterpret_cast<NPUTF8*>(nameStorage); + key.m_string = nameStorage; + identMap->set(key, identifier); + return (NPIdentifier)identifier; + } + + return 0; +} + +void NPN_GetStringIdentifiers(const NPUTF8** names, int32_t nameCount, + NPIdentifier* identifiers) { + ASSERT(names); + ASSERT(identifiers); + + if (names && identifiers) + for (int i = 0; i < nameCount; i++) + identifiers[i] = NPN_GetStringIdentifier(names[i]); +} + +NPIdentifier NPN_GetIntIdentifier(int32_t intid) { + // AutoLock safeLock(IntIdentifierMapLock); + // Special case for -1 and 0, both cannot be used as key in HashMap. + if (intid == 0 || intid == -1) { + static PrivateIdentifier* minusOneOrZeroIds[2]; + PrivateIdentifier* id = minusOneOrZeroIds[intid + 1]; + if (!id) { + id = reinterpret_cast<PrivateIdentifier*>( + malloc(sizeof(PrivateIdentifier))); + id->isString = false; + id->value.number = intid; + minusOneOrZeroIds[intid + 1] = id; + } + return (NPIdentifier)id; + } + + IntIdentifierMap* identMap = getIntIdentifierMap(); + IntIdentifierMap::iterator iter = identMap->find(intid); + if (iter != identMap->end()) + return static_cast<NPIdentifier>(iter->second); + + // We never release identifiers, so this dictionary will grow. + PrivateIdentifier* identifier = reinterpret_cast<PrivateIdentifier*>( + malloc(sizeof(PrivateIdentifier))); + identifier->isString = false; + identifier->value.number = intid; + identMap->set(intid, identifier); + return (NPIdentifier)identifier; +} + +bool NPN_IdentifierIsString(NPIdentifier identifier) { + PrivateIdentifier* i = reinterpret_cast<PrivateIdentifier*>(identifier); + return i->isString; +} + +NPUTF8 *NPN_UTF8FromIdentifier(NPIdentifier identifier) { + PrivateIdentifier* i = reinterpret_cast<PrivateIdentifier*>(identifier); + if (!i->isString || !i->value.string) + return NULL; + + return (NPUTF8 *)strdup(i->value.string); +} + +int32_t NPN_IntFromIdentifier(NPIdentifier identifier) { + PrivateIdentifier* i = reinterpret_cast<PrivateIdentifier*>(identifier); + if (i->isString) + return 0; + return i->value.number; +} + +void NPN_ReleaseVariantValue(NPVariant* variant) { + ASSERT(variant); + + if (variant->type == NPVariantType_Object) { + NPN_ReleaseObject(variant->value.objectValue); + variant->value.objectValue = 0; + } else if (variant->type == NPVariantType_String) { + free((void*)variant->value.stringValue.UTF8Characters); + variant->value.stringValue.UTF8Characters = 0; + variant->value.stringValue.UTF8Length = 0; + } + + variant->type = NPVariantType_Void; +} + +NPObject *NPN_CreateObject(NPP npp, NPClass* aClass) { + ASSERT(aClass); + + if (aClass) { + NPObject* obj; + if (aClass->allocate != NULL) + obj = aClass->allocate(npp, aClass); + else + obj = reinterpret_cast<NPObject*>(malloc(sizeof(NPObject))); + + obj->_class = aClass; + obj->referenceCount = 1; + return obj; + } + + return 0; +} + +NPObject* NPN_RetainObject(NPObject* obj) { + ASSERT(obj); + ASSERT(obj->referenceCount > 0); + + if (obj) + obj->referenceCount++; + + return obj; +} + +// _NPN_DeallocateObject actually deletes the object. Technically, +// callers should use NPN_ReleaseObject. Webkit exposes this function +// to kill objects which plugins may not have properly released. +void _NPN_DeallocateObject(NPObject *obj) { + ASSERT(obj); + ASSERT(obj->referenceCount >= 0); + + if (obj) { + // NPObjects that remain in pure C++ may never have wrappers. + // Hence, if it's not already alive, don't unregister it. + // If it is alive, unregister it as the *last* thing we do + // so that it can do as much cleanup as possible on its own. + if (_NPN_IsAlive(obj)) + _NPN_UnregisterObject(obj); + + obj->referenceCount = -1; + if (obj->_class->deallocate) + obj->_class->deallocate(obj); + else + free(obj); + } +} + +void NPN_ReleaseObject(NPObject* obj) { + ASSERT(obj); + ASSERT(obj->referenceCount >= 1); + + if (obj && obj->referenceCount >= 1) { + if (--obj->referenceCount == 0) + _NPN_DeallocateObject(obj); + } +} + +void _NPN_InitializeVariantWithStringCopy(NPVariant* variant, + const NPString* value) { + variant->type = NPVariantType_String; + variant->value.stringValue.UTF8Length = value->UTF8Length; + variant->value.stringValue.UTF8Characters = + reinterpret_cast<NPUTF8*>(malloc(sizeof(NPUTF8) * value->UTF8Length)); + memcpy((void*)variant->value.stringValue.UTF8Characters, + value->UTF8Characters, + sizeof(NPUTF8) * value->UTF8Length); +} + + +// NPN_Registry +// +// The registry is designed for quick lookup of NPObjects. +// JS needs to be able to quickly lookup a given NPObject to determine +// if it is alive or not. +// The browser needs to be able to quickly lookup all NPObjects which are +// "owned" by an object. +// +// The g_live_objects is a hash table of all live objects to their owner +// objects. Presence in this table is used primarily to determine if +// objects are live or not. +// +// The g_root_objects is a hash table of root objects to a set of +// objects that should be deactivated in sync with the root. A +// root is defined as a top-level owner object. This is used on +// Frame teardown to deactivate all objects associated +// with a particular plugin. + +typedef WTF::HashSet<NPObject*> NPObjectSet; +typedef WTF::HashMap<NPObject*, NPObject*> NPObjectMap; +typedef WTF::HashMap<NPObject*, NPObjectSet*> NPRootObjectMap; + +// A map of live NPObjects with pointers to their Roots. +NPObjectMap g_live_objects; + +// A map of the root objects and the list of NPObjects +// associated with that object. +NPRootObjectMap g_root_objects; + +void _NPN_RegisterObject(NPObject* obj, NPObject* owner) { + ASSERT(obj); + + // Check if already registered. + if (g_live_objects.find(obj) != g_live_objects.end()) { + return; + } + + if (!owner) { + // Registering a new owner object. + ASSERT(g_root_objects.find(obj) == g_root_objects.end()); + g_root_objects.set(obj, new NPObjectSet()); + } else { + // Always associate this object with it's top-most parent. + // Since we always flatten, we only have to look up one level. + NPObjectMap::iterator owner_entry = g_live_objects.find(owner); + NPObject* parent = NULL; + if (g_live_objects.end() != owner_entry) + parent = owner_entry->second; + + if (parent) { + owner = parent; + } + ASSERT(g_root_objects.find(obj) == g_root_objects.end()); + if (g_root_objects.find(owner) != g_root_objects.end()) + g_root_objects.get(owner)->add(obj); + } + + ASSERT(g_live_objects.find(obj) == g_live_objects.end()); + g_live_objects.set(obj, owner); +} + +void _NPN_UnregisterObject(NPObject* obj) { + ASSERT(obj); + ASSERT(g_live_objects.find(obj) != g_live_objects.end()); + + NPObject* owner = NULL; + if (g_live_objects.find(obj) != g_live_objects.end()) + owner = g_live_objects.find(obj)->second; + + if (owner == NULL) { + // Unregistering a owner object; also unregister it's descendants. + ASSERT(g_root_objects.find(obj) != g_root_objects.end()); + NPObjectSet* set = g_root_objects.get(obj); + while (set->size() > 0) { +#ifndef NDEBUG + int size = set->size(); +#endif + NPObject* sub_object = *(set->begin()); + // The sub-object should not be a owner! + ASSERT(g_root_objects.find(sub_object) == g_root_objects.end()); + + // First, unregister the object. + set->remove(sub_object); + g_live_objects.remove(sub_object); + + // Remove the JS references to the object. + ForgetV8ObjectForNPObject(sub_object); + + ASSERT(set->size() < size); + } + delete set; + g_root_objects.remove(obj); + } else { + NPRootObjectMap::iterator owner_entry = g_root_objects.find(owner); + if (owner_entry != g_root_objects.end()) { + NPObjectSet* list = owner_entry->second; + ASSERT(list->find(obj) != list->end()); + list->remove(obj); + } + } + g_live_objects.remove(obj); + ForgetV8ObjectForNPObject(obj); +} + +bool _NPN_IsAlive(NPObject* obj) { + return g_live_objects.find(obj) != g_live_objects.end(); +} + +} // extern "C" diff --git a/V8Binding/binding/npruntime_impl.h b/V8Binding/binding/npruntime_impl.h new file mode 100644 index 0000000..31db922 --- /dev/null +++ b/V8Binding/binding/npruntime_impl.h @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2008, 2009, Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef npruntime_impl_h +#define npruntime_impl_h + +#if PLATFORM(CHROMIUM) +#include "bindings/npruntime.h" +#else +#include "npruntime.h" // use V8Binding/npapi version +#endif + +// This file exists to support WebCore, which expects to be able to call upon +// portions of the NPRuntime implementation. + +// A simple mapping for now. FIXME We should probably just adopt the +// underscore prefix as our naming convention too. + +#define _NPN_ReleaseVariantValue NPN_ReleaseVariantValue +#define _NPN_GetStringIdentifier NPN_GetStringIdentifier +#define _NPN_GetStringIdentifiers NPN_GetStringIdentifiers +#define _NPN_GetIntIdentifier NPN_GetIntIdentifier +#define _NPN_IdentifierIsString NPN_IdentifierIsString +#define _NPN_UTF8FromIdentifier NPN_UTF8FromIdentifier +#define _NPN_IntFromIdentifier NPN_IntFromIdentifier +#define _NPN_CreateObject NPN_CreateObject +#define _NPN_RetainObject NPN_RetainObject +#define _NPN_ReleaseObject NPN_ReleaseObject +#define _NPN_DeallocateObject NPN_DeallocateObject +#define _NPN_Invoke NPN_Invoke +#define _NPN_InvokeDefault NPN_InvokeDefault +#define _NPN_Evaluate NPN_Evaluate +#define _NPN_GetProperty NPN_GetProperty +#define _NPN_SetProperty NPN_SetProperty +#define _NPN_RemoveProperty NPN_RemoveProperty +#define _NPN_HasProperty NPN_HasProperty +#define _NPN_HasMethod NPN_HasMethod +#define _NPN_SetException NPN_SetException +#define _NPN_Enumerate NPN_Enumerate +#define _NPN_Construct NPN_Construct + +#endif diff --git a/V8Binding/binding/npruntime_internal.h b/V8Binding/binding/npruntime_internal.h new file mode 100644 index 0000000..75bf2b0 --- /dev/null +++ b/V8Binding/binding/npruntime_internal.h @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2007 Collabora, Ltd. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * + * This is a internal include header for npapi.h + * + * Some of the #defines which are in X11 headers conflict with type and enum + * names in JavaScriptCore and WebCore + * This header #undefs those defines to fix the conflicts + * If you need to include npapi.h or npruntime.h when building on X11, + * include this file instead of the actual npapi.h or npruntime.h + */ + +#include "npapi.h" +#include "npruntime.h" +#include "npfunctions.h" + +#ifdef XP_UNIX + #include <X11/Xresource.h> + + #undef None + #undef Above + #undef Below + #undef Auto + #undef Complex + #undef Status +#endif diff --git a/V8Binding/binding/npruntime_priv.h b/V8Binding/binding/npruntime_priv.h new file mode 100644 index 0000000..8b1ddec --- /dev/null +++ b/V8Binding/binding/npruntime_priv.h @@ -0,0 +1,95 @@ +/* + * Copyright (C) 2003, 2006 Apple Computer, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef NP_RUNTIME_PRIV_H_ +#define NP_RUNTIME_PRIV_H_ + +#if PLATFORM(CHROMIUM) +#include "third_party/npapi/bindings/npruntime.h" +#else +#include "bridge/npruntime.h" +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/* + _NPN_InitializeVariantWithStringCopy() will copy string data. The string data + will be deallocated by calls to NPReleaseVariantValue(). +*/ +void _NPN_InitializeVariantWithStringCopy(NPVariant*, const NPString*); +void _NPN_DeallocateObject(NPObject *obj); + +// The following routines allow the browser to aggressively cleanup NPObjects +// on a per plugin basis. All NPObjects used through the NPRuntime API should +// be "registered" while they are alive. After an object has been +// deleted, it is possible for Javascript to have a reference to that object +// which has not yet been garbage collected. Javascript access to NPObjects +// will reference this registry to determine if the object is accessible or +// not. + +// Windows introduces an additional complication for objects created by the +// plugin. Plugins load inside of a DLL. Each DLL has it's own heap. If +// the browser unloads the plugin DLL, all objects created within the DLL's +// heap instantly become invalid. Normally, when WebKit drops the reference +// on the top-level plugin object, it tells the plugin manager that the +// plugin can be destroyed, which can unload the DLL. So, we must eliminate +// all pointers to any object ever created by the plugin. + +// We generally associate NPObjects with an owner. The owner of an NPObject +// is an NPObject which, when destroyed, also destroys all objects it owns. +// For example, if an NPAPI plugin creates 10 sub-NPObjects, all 11 objects +// (the NPAPI plugin + its 10 sub-objects) should become inaccessible +// simultaneously. + +// The ownership hierarchy is flat, and not a tree. Imagine the following +// object creation: +// PluginObject +// | +// +-- Creates -----> Object1 +// | +// +-- Creates -----> Object2 +// +// PluginObject will be the "owner" for both Object1 and Object2. + +// Register an NPObject with the runtime. If the owner is NULL, the +// object is treated as an owning object. If owner is not NULL, +// this object will be registered as owned by owner's top-level owner. +void _NPN_RegisterObject(NPObject* obj, NPObject* owner); + +// Unregister an NPObject with the runtime. If obj is an owning +// object, this call will also unregister all of the owned objects. +void _NPN_UnregisterObject(NPObject* obj); + +// Check to see if an object is registered with the runtime. +// Return true if registered, false otherwise. +bool _NPN_IsAlive(NPObject* obj); + +#ifdef __cplusplus +} /* end extern "C" */ +#endif + +#endif diff --git a/V8Binding/binding/v8_binding.cpp b/V8Binding/binding/v8_binding.cpp new file mode 100644 index 0000000..3a36fc5 --- /dev/null +++ b/V8Binding/binding/v8_binding.cpp @@ -0,0 +1,120 @@ +// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "v8_binding.h" + +#include "AtomicString.h" +#include "CString.h" +#include "MathExtras.h" +#include "PlatformString.h" +#include "StringBuffer.h" + +#include <v8.h> + +namespace WebCore { + +// WebCoreStringResource is a helper class for v8ExternalString. It is used +// to manage the life-cycle of the underlying buffer of the external string. +class WebCoreStringResource: public v8::String::ExternalStringResource { + public: + explicit WebCoreStringResource(const String& str) + : impl_(str.impl()) { } + + virtual ~WebCoreStringResource() {} + + const uint16_t* data() const { + return reinterpret_cast<const uint16_t*>(impl_.characters()); + } + + size_t length() const { return impl_.length(); } + + String webcore_string() { return impl_; } + + private: + // A shallow copy of the string. + // Keeps the string buffer alive until the V8 engine garbage collects it. + String impl_; +}; + +String v8StringToWebCoreString(v8::Handle<v8::String> v8_str) { + if (v8_str->IsExternal()) { + WebCoreStringResource* str_resource = static_cast<WebCoreStringResource*>( + v8_str->GetExternalStringResource()); + return str_resource->webcore_string(); + } + + int length = v8_str->Length(); + if (length == 0) { + // Avoid trying to morph empty strings, as they do not have enough room to + // contain the external reference. + return ""; + } + + // Copy the characters from the v8::String into a WebCore::String and allocate + // an external resource which will be attached to the v8::String. + String result; + const int kStringSizeToCopy = 256; + if (length < kStringSizeToCopy) { + uint16_t buffer[kStringSizeToCopy]; + v8_str->Write(buffer, 0, length); + result = StringImpl::create(reinterpret_cast<UChar*>(buffer), length); + } else { + StringBuffer buf(length); + v8_str->Write(reinterpret_cast<uint16_t*>(buf.characters()), 0, length); + result = String::adopt(buf); + } + +// +// TODO(mbelshe): Disable string morphing because it causes mystery +// perf regressions on intl1 and intl2 page cyclers. It works fine +// on machines other than the buildbots. +// +// WebCoreStringResource* resource = new WebCoreStringResource(result); +// if (!v8_str->MakeExternal(resource)) { +// // In case of a failure delete the external resource as it was not used. +// delete resource; +// } + return result; +} + + +String v8ValueToWebCoreString(v8::Handle<v8::Value> obj) { + v8::Handle<v8::String> v8_str; + if (obj->IsString()) { + v8_str = v8::Handle<v8::String>::Cast(obj); + } else { + v8::TryCatch block; + v8_str = obj->ToString(); + if (v8_str.IsEmpty()) + return ""; + } + return v8StringToWebCoreString(v8_str); +} + + +AtomicString v8StringToAtomicWebCoreString(v8::Handle<v8::String> v8_str) { + String str = v8StringToWebCoreString(v8_str); + return AtomicString(str); +} + + +AtomicString v8ValueToAtomicWebCoreString(v8::Handle<v8::Value> v8_str) { + String str = v8ValueToWebCoreString(v8_str); + return AtomicString(str); +} + + +v8::Handle<v8::String> v8String(const String& str) { + if (!str.length()) + return v8::String::Empty(); + return v8::String::NewExternal(new WebCoreStringResource(str)); +} + +v8::Local<v8::String> v8ExternalString(const String& str) { + if (!str.length()) + return v8::String::Empty(); + return v8::String::NewExternal(new WebCoreStringResource(str)); +} + +} // namespace WebCore diff --git a/V8Binding/binding/v8_binding.h b/V8Binding/binding/v8_binding.h new file mode 100644 index 0000000..8300dd7 --- /dev/null +++ b/V8Binding/binding/v8_binding.h @@ -0,0 +1,130 @@ +// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef V8_BINDING_H__ +#define V8_BINDING_H__ + +#include "config.h" + +#include "MathExtras.h" +#include "PlatformString.h" + +#include <v8.h> + +namespace WebCore { + +// The string returned by this function is still owned by the argument +// and will be deallocated when the argument is deallocated. +inline const uint16_t* FromWebCoreString(const String& str) { + return reinterpret_cast<const uint16_t*>(str.characters()); +} + +// Convert v8 types to a WebCore::String. If the V8 string is not already +// an external string then it is transformed into an external string at this +// point to avoid repeated conversions. +String v8StringToWebCoreString(v8::Handle<v8::String> obj); +String v8ValueToWebCoreString(v8::Handle<v8::Value> obj); + +// TODO(mbelshe): drop this in favor of the type specific +// v8ValueToWebCoreString when we rework the code generation. +inline String ToWebCoreString(v8::Handle<v8::Value> obj) { + return v8ValueToWebCoreString(obj); +} + +// Convert v8 types to a WebCore::AtomicString. +AtomicString v8StringToAtomicWebCoreString(v8::Handle<v8::String> obj); +AtomicString v8ValueToAtomicWebCoreString(v8::Handle<v8::Value> obj); + +inline String valueToStringWithNullCheck(v8::Handle<v8::Value> value) { + if (value->IsNull()) return String(); + return ToWebCoreString(value); +} + +inline String valueToStringWithNullOrUndefinedCheck( + v8::Handle<v8::Value> value) { + if (value->IsNull() || value->IsUndefined()) return String(); + return ToWebCoreString(value); +} + +// Convert a value to a 32-bit integer. The conversion fails if the +// value cannot be converted to an integer or converts to nan or to an +// infinity. +// FIXME: Rename to toInt32() once V8 bindings migration is complete. +inline int ToInt32(v8::Handle<v8::Value> value, bool& ok) { + ok = true; + + // Fast case. The value is already a 32-bit integer. + if (value->IsInt32()) { + return value->Int32Value(); + } + + // Can the value be converted to a number? + v8::Local<v8::Number> number_object = value->ToNumber(); + if (number_object.IsEmpty()) { + ok = false; + return 0; + } + + // Does the value convert to nan or to an infinity? + double number_value = number_object->Value(); + if (isnan(number_value) || isinf(number_value)) { + ok = false; + return 0; + } + + // Can the value be converted to a 32-bit integer? + v8::Local<v8::Int32> int_value = value->ToInt32(); + if (int_value.IsEmpty()) { + ok = false; + return 0; + } + + // Return the result of the int32 conversion. + return int_value->Value(); +} + +// Convert a value to a 32-bit integer assuming the conversion cannot fail. +// FIXME: Rename to toInt32() once V8 bindings migration is complete. +inline int ToInt32(v8::Handle<v8::Value> value) { + bool ok; + return ToInt32(value, ok); +} + +inline String ToString(const String& string) { + return string; +} + +// Convert a string to a V8 string. +v8::Handle<v8::String> v8String(const String& str); + +inline v8::Handle<v8::String> v8UndetectableString(const String& str) { + return v8::String::NewUndetectable(FromWebCoreString(str), str.length()); +} + +// Return a V8 external string that shares the underlying buffer with the given +// WebCore string. The reference counting mechanism is used to keep the +// underlying buffer alive while the string is still live in the V8 engine. +v8::Local<v8::String> v8ExternalString(const String& str); + +inline v8::Handle<v8::Value> v8StringOrNull(const String& str) { + return str.isNull() + ? v8::Handle<v8::Value>(v8::Null()) + : v8::Handle<v8::Value>(v8String(str)); +} + +inline v8::Handle<v8::Value> v8StringOrUndefined(const String& str) { + return str.isNull() + ? v8::Handle<v8::Value>(v8::Undefined()) + : v8::Handle<v8::Value>(v8String(str)); +} + +inline v8::Handle<v8::Value> v8StringOrFalse(const String& str) { + return str.isNull() + ? v8::Handle<v8::Value>(v8::False()) + : v8::Handle<v8::Value>(v8String(str)); +} + +} // namespace WebCore + +#endif // V8_BINDING_H__ diff --git a/V8Binding/binding/v8_custom.cpp b/V8Binding/binding/v8_custom.cpp new file mode 100644 index 0000000..855e192 --- /dev/null +++ b/V8Binding/binding/v8_custom.cpp @@ -0,0 +1,1102 @@ +/* + * Copyright (C) 2000 Harri Porten (porten@kde.org) + * Copyright (C) 2001 Peter Kelly (pmk@post.com) + * Copyright (C) 2004-2006 Apple Computer, Inc. + * Copyright (C) 2006 James G. Speth (speth@end.com) + * Copyright (C) 2006 Samuel Weinig (sam@webkit.org) + * Copyright 2007, 2008 Google Inc. All Rights Reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "config.h" + +#include <Assertions.h> +#include <wtf/ASCIICType.h> + +#include "v8_proxy.h" +#include "v8_binding.h" +#include "V8NPObject.h" +#include "v8_custom.h" + +#include "V8Attr.h" +#include "V8CanvasGradient.h" +#include "V8CanvasPattern.h" +#include "V8CustomEventListener.h" +#include "V8Document.h" +#include "V8DOMWindow.h" +#include "V8HTMLCanvasElement.h" +#include "V8HTMLDocument.h" +#include "V8HTMLImageElement.h" +#include "V8HTMLOptionElement.h" +#include "V8Node.h" + +#if ENABLE(XPATH) +#include "V8XPathNSResolver.h" +#include "V8XPathResult.h" +#endif + +#include "Base64.h" +#include "CanvasGradient.h" +#include "CanvasPattern.h" +#include "CanvasRenderingContext2D.h" +#include "CanvasStyle.h" +#include "Clipboard.h" +#include "ClipboardEvent.h" +#include "Console.h" +#include "DOMParser.h" +#include "DOMStringList.h" +#include "DOMTimer.h" +#include "DOMWindow.h" +#include "Document.h" +#include "DocumentFragment.h" +#include "Event.h" +#include "EventListener.h" +#include "EventTarget.h" +#include "ExceptionCode.h" +#include "FloatRect.h" +#include "Frame.h" +#include "FrameLoader.h" +#include "FrameTree.h" +#include "HTMLBodyElement.h" +#include "HTMLCanvasElement.h" +#include "HTMLDocument.h" +#include "HTMLEmbedElement.h" +#include "HTMLFormElement.h" +#include "HTMLFrameElement.h" +#include "HTMLFrameElementBase.h" +#include "HTMLFrameSetElement.h" +#include "HTMLIFrameElement.h" +#include "HTMLImageElement.h" +#include "HTMLInputElement.h" +#include "HTMLNames.h" +#include "HTMLOptionElement.h" +#include "HTMLOptionsCollection.h" +#include "HTMLSelectElement.h" +#include "History.h" +#include "JSXPathNSResolver.h" +#include "JSDOMBinding.h" +#include "KURL.h" +#include "Location.h" +#include "MessageChannel.h" +#include "MessagePort.h" +#include "MouseEvent.h" +#include "NodeIterator.h" +#include "NodeList.h" +#include "RGBColor.h" +#include "RenderPartObject.h" +#include "RenderWidget.h" +#include "ScheduledAction.h" +#include "ScriptState.h" +#include "ScriptController.h" +#include "ScriptSourceCode.h" +#include "SecurityOrigin.h" +#include "StyleSheetList.h" +#include "TreeWalker.h" +#include "WebKitCSSMatrix.h" +#include "WebKitPoint.h" +#include "XMLSerializer.h" +#include "XPathEvaluator.h" +#include "XPathResult.h" +#include "XSLTProcessor.h" + +#if ENABLE(SVG) +#include "V8SVGPODTypeWrapper.h" +#include "SVGElementInstance.h" +#include "SVGException.h" +#include "SVGPathSeg.h" +#endif + +#include "Navigator.h" + +namespace WebCore { + +CALLBACK_FUNC_DECL(WebKitPointConstructor) { + INC_STATS("DOM.WebKitPoint.Constructor"); + return V8Proxy::ConstructDOMObject<V8ClassIndex::WEBKITPOINT, + WebKitPoint>(args); +} + +// DOMImplementation is a singleton in WebCore. If we use our normal +// mapping from DOM objects to V8 wrappers, the same wrapper will be +// shared for all frames in the same process. This is a major +// security problem. Therefore, we generate a DOMImplementation +// wrapper per document and store it in an internal field of the +// document. Since the DOMImplementation object is a singleton, we do +// not have to do anything to keep the DOMImplementation object alive +// for the lifetime of the wrapper. +ACCESSOR_GETTER(DocumentImplementation) { + ASSERT(info.Holder()->InternalFieldCount() >= + kDocumentMinimumInternalFieldCount); + // Check if the internal field already contains a wrapper. + v8::Local<v8::Value> implementation = + info.Holder()->GetInternalField(kDocumentImplementationIndex); + if (!implementation->IsUndefined()) { + return implementation; + } + // Generate a wrapper. + Document* doc = V8Proxy::DOMWrapperToNative<Document>(info.Holder()); + v8::Handle<v8::Value> wrapper = + V8Proxy::DOMImplementationToV8Object(doc->implementation()); + // Store the wrapper in the internal field. + info.Holder()->SetInternalField(kDocumentImplementationIndex, wrapper); + + return wrapper; +} + + +ACCESSOR_GETTER(DocumentLocation) { + Document* imp = V8Proxy::DOMWrapperToNative<Document>(info.Holder()); + if (!imp->frame()) + return v8::Null(); + + DOMWindow* window = imp->frame()->domWindow(); + return V8Proxy::ToV8Object(V8ClassIndex::LOCATION, window->location()); +} + + +ACCESSOR_SETTER(DocumentLocation) { + Document* imp = V8Proxy::DOMWrapperToNative<Document>(info.Holder()); + if (!imp->frame()) + return; + + DOMWindow* window = imp->frame()->domWindow(); + // WindowSetLocation does security checks. // XXXMB- verify! + WindowSetLocation(window, ToWebCoreString(value)); +} + + +INDEXED_PROPERTY_GETTER(HTMLFormElement) { + INC_STATS("DOM.HTMLFormElement.IndexedPropertyGetter"); + HTMLFormElement* form = + V8Proxy::DOMWrapperToNode<HTMLFormElement>(info.Holder()); + + RefPtr<Node> result = form->elements()->item(index); + if (!result) return v8::Handle<v8::Value>(); + return V8Proxy::NodeToV8Object(result.get()); +} + + +INDEXED_PROPERTY_GETTER(HTMLOptionsCollection) { + INC_STATS("DOM.HTMLOptionsCollection.IndexedPropertyGetter"); + HTMLOptionsCollection* collection = + V8Proxy::ToNativeObject<HTMLOptionsCollection>( + V8ClassIndex::HTMLOPTIONSCOLLECTION, info.Holder()); + + RefPtr<Node> result = collection->item(index); + if (!result) return v8::Handle<v8::Value>(); + + return V8Proxy::NodeToV8Object(result.get()); +} + +static v8::Handle<v8::Value> OptionsCollectionSetter(uint32_t index, + v8::Handle<v8::Value> value, HTMLSelectElement* base) { + if (value->IsNull() || value->IsUndefined()) { + base->remove(index); + return value; + } + + ExceptionCode ec = 0; + + // Check that the value is an HTMLOptionElement. If not, throw a + // TYPE_MISMATCH_ERR DOMException. + if (!V8HTMLOptionElement::HasInstance(value)) { + V8Proxy::SetDOMException(TYPE_MISMATCH_ERR); + return value; + } + + HTMLOptionElement* element = + V8Proxy::DOMWrapperToNode<HTMLOptionElement>( + v8::Handle<v8::Object>::Cast(value)); + base->setOption(index, element, ec); + + V8Proxy::SetDOMException(ec); + return value; +} + + +INDEXED_PROPERTY_SETTER(HTMLOptionsCollection) { + INC_STATS("DOM.HTMLOptionsCollection.IndexedPropertySetter"); + HTMLOptionsCollection* collection = + V8Proxy::ToNativeObject<HTMLOptionsCollection>( + V8ClassIndex::HTMLOPTIONSCOLLECTION, info.Holder()); + HTMLSelectElement* base = static_cast<HTMLSelectElement*>(collection->base()); + return OptionsCollectionSetter(index, value, base); +} + + +INDEXED_PROPERTY_SETTER(HTMLSelectElementCollection) { + INC_STATS("DOM.HTMLSelectElementCollection.IndexedPropertySetter"); + HTMLSelectElement* select = + V8Proxy::DOMWrapperToNode<HTMLSelectElement>(info.Holder()); + return OptionsCollectionSetter(index, value, select); +} + +// CanvasRenderingContext2D ---------------------------------------------------- + +// Helper macro for converting v8 values into floats (expected by many of the +// canvas functions). +#define TO_FLOAT(a) static_cast<float>((a)->NumberValue()) + +// TODO: SetStrokeColor and SetFillColor are similar except function names, +// consolidate them into one. +CALLBACK_FUNC_DECL(CanvasRenderingContext2DSetStrokeColor) { + INC_STATS("DOM.CanvasRenderingContext2D.setStrokeColor()"); + CanvasRenderingContext2D* context = + V8Proxy::ToNativeObject<CanvasRenderingContext2D>( + V8ClassIndex::CANVASRENDERINGCONTEXT2D, args.Holder()); + switch (args.Length()) { + case 1: + if (args[0]->IsString()) { + context->setStrokeColor(ToWebCoreString(args[0])); + } else { + context->setStrokeColor(TO_FLOAT(args[0])); + } + break; + case 2: + if (args[0]->IsString()) { + context->setStrokeColor(ToWebCoreString(args[0]), + TO_FLOAT(args[1])); + } else { + context->setStrokeColor(TO_FLOAT(args[0]), + TO_FLOAT(args[1])); + } + break; + case 4: + context->setStrokeColor(TO_FLOAT(args[0]), + TO_FLOAT(args[1]), + TO_FLOAT(args[2]), + TO_FLOAT(args[3])); + break; + case 5: + context->setStrokeColor(TO_FLOAT(args[0]), + TO_FLOAT(args[1]), + TO_FLOAT(args[2]), + TO_FLOAT(args[3]), + TO_FLOAT(args[4])); + break; + default: + V8Proxy::ThrowError(V8Proxy::SYNTAX_ERROR, + "setStrokeColor: Invalid number of arguments"); + break; + } + return v8::Undefined(); +} + +CALLBACK_FUNC_DECL(CanvasRenderingContext2DSetFillColor) { + INC_STATS("DOM.CanvasRenderingContext2D.setFillColor()"); + CanvasRenderingContext2D* context = + V8Proxy::ToNativeObject<CanvasRenderingContext2D>( + V8ClassIndex::CANVASRENDERINGCONTEXT2D, args.Holder()); + switch (args.Length()) { + case 1: + if (args[0]->IsString()) { + context->setFillColor(ToWebCoreString(args[0])); + } else { + context->setFillColor(TO_FLOAT(args[0])); + } + break; + case 2: + if (args[0]->IsString()) { + context->setFillColor(ToWebCoreString(args[0]), TO_FLOAT(args[1])); + } else { + context->setFillColor(TO_FLOAT(args[0]), TO_FLOAT(args[1])); + } + break; + case 4: + context->setFillColor(TO_FLOAT(args[0]), + TO_FLOAT(args[1]), + TO_FLOAT(args[2]), + TO_FLOAT(args[3])); + break; + case 5: + context->setFillColor(TO_FLOAT(args[0]), + TO_FLOAT(args[1]), + TO_FLOAT(args[2]), + TO_FLOAT(args[3]), + TO_FLOAT(args[4])); + break; + default: + V8Proxy::ThrowError(V8Proxy::SYNTAX_ERROR, + "setFillColor: Invalid number of arguments"); + break; + } + return v8::Undefined(); +} + +CALLBACK_FUNC_DECL(CanvasRenderingContext2DStrokeRect) { + INC_STATS("DOM.CanvasRenderingContext2D.strokeRect()"); + CanvasRenderingContext2D* context = + V8Proxy::ToNativeObject<CanvasRenderingContext2D>( + V8ClassIndex::CANVASRENDERINGCONTEXT2D, args.Holder()); + if (args.Length() == 5) { + context->strokeRect(TO_FLOAT(args[0]), + TO_FLOAT(args[1]), + TO_FLOAT(args[2]), + TO_FLOAT(args[3]), + TO_FLOAT(args[4])); + } else if (args.Length() == 4) { + context->strokeRect(TO_FLOAT(args[0]), + TO_FLOAT(args[1]), + TO_FLOAT(args[2]), + TO_FLOAT(args[3])); + } else { + V8Proxy::SetDOMException(INDEX_SIZE_ERR); + return v8::Handle<v8::Value>(); + } + + return v8::Undefined(); +} + +CALLBACK_FUNC_DECL(CanvasRenderingContext2DSetShadow) { + INC_STATS("DOM.CanvasRenderingContext2D.setShadow()"); + CanvasRenderingContext2D* context = + V8Proxy::ToNativeObject<CanvasRenderingContext2D>( + V8ClassIndex::CANVASRENDERINGCONTEXT2D, args.Holder()); + + switch (args.Length()) { + case 3: + context->setShadow(TO_FLOAT(args[0]), TO_FLOAT(args[1]), + TO_FLOAT(args[2])); + break; + case 4: + if (args[3]->IsString()) + context->setShadow(TO_FLOAT(args[0]), TO_FLOAT(args[1]), + TO_FLOAT(args[2]), ToWebCoreString(args[3])); + else + context->setShadow(TO_FLOAT(args[0]), TO_FLOAT(args[1]), + TO_FLOAT(args[2]), TO_FLOAT(args[3])); + break; + case 5: + if (args[3]->IsString()) + context->setShadow(TO_FLOAT(args[0]), TO_FLOAT(args[1]), + TO_FLOAT(args[2]), ToWebCoreString(args[3]), + TO_FLOAT(args[4])); + else + context->setShadow(TO_FLOAT(args[0]), TO_FLOAT(args[1]), + TO_FLOAT(args[2]), TO_FLOAT(args[3]), + TO_FLOAT(args[4])); + break; + case 7: + context->setShadow(TO_FLOAT(args[0]), TO_FLOAT(args[1]), + TO_FLOAT(args[2]), TO_FLOAT(args[3]), + TO_FLOAT(args[4]), TO_FLOAT(args[5]), + TO_FLOAT(args[6])); + break; + case 8: + context->setShadow(TO_FLOAT(args[0]), TO_FLOAT(args[1]), + TO_FLOAT(args[2]), TO_FLOAT(args[3]), + TO_FLOAT(args[4]), TO_FLOAT(args[5]), + TO_FLOAT(args[6]), TO_FLOAT(args[7])); + break; + default: + V8Proxy::ThrowError(V8Proxy::SYNTAX_ERROR, + "setShadow: Invalid number of arguments"); + break; + } + + return v8::Undefined(); +} + +CALLBACK_FUNC_DECL(CanvasRenderingContext2DDrawImage) { + INC_STATS("DOM.CanvasRenderingContext2D.drawImage()"); + CanvasRenderingContext2D* context = + V8Proxy::ToNativeObject<CanvasRenderingContext2D>( + V8ClassIndex::CANVASRENDERINGCONTEXT2D, args.Holder()); + + v8::Handle<v8::Value> arg = args[0]; + + if (V8HTMLImageElement::HasInstance(arg)) { + ExceptionCode ec = 0; + HTMLImageElement* image_element = + V8Proxy::DOMWrapperToNode<HTMLImageElement>(arg); + switch (args.Length()) { + case 3: + context->drawImage(image_element, TO_FLOAT(args[1]), TO_FLOAT(args[2])); + break; + case 5: + context->drawImage(image_element, TO_FLOAT(args[1]), TO_FLOAT(args[2]), + TO_FLOAT(args[3]), TO_FLOAT(args[4]), ec); + if (ec != 0) { + V8Proxy::SetDOMException(ec); + return v8::Handle<v8::Value>(); + } + break; + case 9: + context->drawImage(image_element, + FloatRect(TO_FLOAT(args[1]), TO_FLOAT(args[2]), + TO_FLOAT(args[3]), TO_FLOAT(args[4])), + FloatRect(TO_FLOAT(args[5]), TO_FLOAT(args[6]), + TO_FLOAT(args[7]), TO_FLOAT(args[8])), + ec); + if (ec != 0) { + V8Proxy::SetDOMException(ec); + return v8::Handle<v8::Value>(); + } + break; + default: + V8Proxy::ThrowError(V8Proxy::SYNTAX_ERROR, + "drawImage: Invalid number of arguments"); + return v8::Undefined(); + } + return v8::Undefined(); + } + + // HTMLCanvasElement + if (V8HTMLCanvasElement::HasInstance(arg)) { + ExceptionCode ec = 0; + HTMLCanvasElement* canvas_element = + V8Proxy::DOMWrapperToNode<HTMLCanvasElement>(arg); + switch (args.Length()) { + case 3: + context->drawImage(canvas_element, TO_FLOAT(args[1]), TO_FLOAT(args[2])); + break; + case 5: + context->drawImage(canvas_element, TO_FLOAT(args[1]), TO_FLOAT(args[2]), + TO_FLOAT(args[3]), TO_FLOAT(args[4]), ec); + if (ec != 0) { + V8Proxy::SetDOMException(ec); + return v8::Handle<v8::Value>(); + } + break; + case 9: + context->drawImage(canvas_element, + FloatRect(TO_FLOAT(args[1]), TO_FLOAT(args[2]), + TO_FLOAT(args[3]), TO_FLOAT(args[4])), + FloatRect(TO_FLOAT(args[5]), TO_FLOAT(args[6]), + TO_FLOAT(args[7]), TO_FLOAT(args[8])), + ec); + if (ec != 0) { + V8Proxy::SetDOMException(ec); + return v8::Handle<v8::Value>(); + } + break; + default: + V8Proxy::ThrowError(V8Proxy::SYNTAX_ERROR, + "drawImage: Invalid number of arguments"); + return v8::Undefined(); + } + return v8::Undefined(); + } + + V8Proxy::SetDOMException(TYPE_MISMATCH_ERR); + return v8::Handle<v8::Value>(); +} + +CALLBACK_FUNC_DECL(CanvasRenderingContext2DDrawImageFromRect) { + INC_STATS("DOM.CanvasRenderingContext2D.drawImageFromRect()"); + CanvasRenderingContext2D* context = + V8Proxy::ToNativeObject<CanvasRenderingContext2D>( + V8ClassIndex::CANVASRENDERINGCONTEXT2D, args.Holder()); + + v8::Handle<v8::Value> arg = args[0]; + + if (V8HTMLImageElement::HasInstance(arg)) { + HTMLImageElement* image_element = + V8Proxy::DOMWrapperToNode<HTMLImageElement>(arg); + context->drawImageFromRect(image_element, + TO_FLOAT(args[1]), TO_FLOAT(args[2]), + TO_FLOAT(args[3]), TO_FLOAT(args[4]), + TO_FLOAT(args[5]), TO_FLOAT(args[6]), + TO_FLOAT(args[7]), TO_FLOAT(args[8]), + ToWebCoreString(args[9])); + } else { + V8Proxy::ThrowError(V8Proxy::TYPE_ERROR, + "drawImageFromRect: Invalid type of arguments"); + } + + return v8::Undefined(); +} + +CALLBACK_FUNC_DECL(CanvasRenderingContext2DCreatePattern) { + INC_STATS("DOM.CanvasRenderingContext2D.createPattern()"); + CanvasRenderingContext2D* context = + V8Proxy::ToNativeObject<CanvasRenderingContext2D>( + V8ClassIndex::CANVASRENDERINGCONTEXT2D, args.Holder()); + + v8::Handle<v8::Value> arg = args[0]; + + if (V8HTMLImageElement::HasInstance(arg)) { + HTMLImageElement* image_element = + V8Proxy::DOMWrapperToNode<HTMLImageElement>(arg); + ExceptionCode ec = 0; + RefPtr<CanvasPattern> pattern = + context->createPattern(image_element, valueToStringWithNullCheck(args[1]), ec); + if (ec != 0) { + V8Proxy::SetDOMException(ec); + return v8::Handle<v8::Value>(); + } + return V8Proxy::ToV8Object(V8ClassIndex::CANVASPATTERN, pattern.get()); + } + + if (V8HTMLCanvasElement::HasInstance(arg)) { + HTMLCanvasElement* canvas_element = + V8Proxy::DOMWrapperToNode<HTMLCanvasElement>(arg); + ExceptionCode ec = 0; + RefPtr<CanvasPattern> pattern = + context->createPattern(canvas_element, valueToStringWithNullCheck(args[1]), ec); + if (ec != 0) { + V8Proxy::SetDOMException(ec); + return v8::Handle<v8::Value>(); + } + return V8Proxy::ToV8Object(V8ClassIndex::CANVASPATTERN, pattern.get()); + } + + V8Proxy::SetDOMException(TYPE_MISMATCH_ERR); + return v8::Handle<v8::Value>(); +} + +CALLBACK_FUNC_DECL(CanvasRenderingContext2DFillText) { + INC_STATS("DOM.CanvasRenderingContext2D.fillText()"); + + CanvasRenderingContext2D* context = + V8Proxy::ToNativeObject<CanvasRenderingContext2D>( + V8ClassIndex::CANVASRENDERINGCONTEXT2D, args.Holder()); + + // Two forms: + // * fillText(text, x, y) + // * fillText(text, x, y, maxWidth) + if (args.Length() < 3 || args.Length() > 4) { + V8Proxy::SetDOMException(SYNTAX_ERR); + return v8::Handle<v8::Value>(); + } + + String text = ToWebCoreString(args[0]); + float x = TO_FLOAT(args[1]); + float y = TO_FLOAT(args[2]); + + if (args.Length() == 4) { + float maxWidth = TO_FLOAT(args[3]); + context->fillText(text, x, y, maxWidth); + } else { + context->fillText(text, x, y); + } + + return v8::Undefined(); +} + +CALLBACK_FUNC_DECL(CanvasRenderingContext2DStrokeText) { + INC_STATS("DOM.CanvasRenderingContext2D.strokeText()"); + + CanvasRenderingContext2D* context = + V8Proxy::ToNativeObject<CanvasRenderingContext2D>( + V8ClassIndex::CANVASRENDERINGCONTEXT2D, args.Holder()); + + // Two forms: + // * strokeText(text, x, y) + // * strokeText(text, x, y, maxWidth) + if (args.Length() < 3 || args.Length() > 4) { + V8Proxy::SetDOMException(SYNTAX_ERR); + return v8::Handle<v8::Value>(); + } + + String text = ToWebCoreString(args[0]); + float x = TO_FLOAT(args[1]); + float y = TO_FLOAT(args[2]); + + if (args.Length() == 4) { + float maxWidth = TO_FLOAT(args[3]); + context->strokeText(text, x, y, maxWidth); + } else { + context->strokeText(text, x, y); + } + + return v8::Undefined(); +} + +CALLBACK_FUNC_DECL(CanvasRenderingContext2DPutImageData) { + INC_STATS("DOM.CanvasRenderingContext2D.putImageData()"); + + // Two froms: + // * putImageData(ImageData, x, y) + // * putImageData(ImageData, x, y, dirtyX, dirtyY, dirtyWidth, dirtyHeight) + if (args.Length() != 3 && args.Length() != 7) { + V8Proxy::SetDOMException(SYNTAX_ERR); + return v8::Handle<v8::Value>(); + } + + CanvasRenderingContext2D* context = + V8Proxy::ToNativeObject<CanvasRenderingContext2D>( + V8ClassIndex::CANVASRENDERINGCONTEXT2D, args.Holder()); + + ImageData* imageData = 0; + + // Need to check that the argument is of the correct type, since + // ToNativeObject() expects it to be correct. If the argument was incorrect + // we leave it null, and putImageData() will throw the correct exception + // (TYPE_MISMATCH_ERR). + if (V8Proxy::IsWrapperOfType(args[0], V8ClassIndex::IMAGEDATA)) { + imageData = V8Proxy::ToNativeObject<ImageData>( + V8ClassIndex::IMAGEDATA, args[0]); + } + + ExceptionCode ec = 0; + + if (args.Length() == 7) { + context->putImageData(imageData, + TO_FLOAT(args[1]), TO_FLOAT(args[2]), TO_FLOAT(args[3]), + TO_FLOAT(args[4]), TO_FLOAT(args[5]), TO_FLOAT(args[6]), ec); + } else { + context->putImageData(imageData, TO_FLOAT(args[1]), TO_FLOAT(args[2]), ec); + } + + if (ec != 0) { + V8Proxy::SetDOMException(ec); + return v8::Handle<v8::Value>(); + } + + return v8::Undefined(); +} + +static bool AllowSettingSrcToJavascriptURL(Element* element, String name, + String value) { + // Need to parse value as URL first in order to check its protocol. + // " javascript:", "java\0script:", "javascript\t:", "javascript\1:" + // are all parsed as "javascript:" url. + // When changing location in HTMLFrameElement, value is parsed as url. + // We must match the behavior there. + // See issue 804099. + // + // parseURL is defined in CSSHelper.cpp. + if ((element->hasTagName(HTMLNames::iframeTag) || + element->hasTagName(HTMLNames::frameTag)) && + equalIgnoringCase(name, "src") && + parseURL(value).startsWith("javascript:", false)) { + HTMLFrameElementBase* frame = static_cast<HTMLFrameElementBase*>(element); + Node* contentDoc = frame->contentDocument(); + if (contentDoc && !V8Proxy::CheckNodeSecurity(contentDoc)) + return false; + } + return true; +} + + +static bool AllowSettingFrameSrcToJavascriptUrl(HTMLFrameElementBase* frame, + String value) { + // See same issue in AllowSettingSrcToJavascriptURL. + if (parseURL(value).startsWith("javascript:", false)) { + Node* contentDoc = frame->contentDocument(); + if (contentDoc && !V8Proxy::CheckNodeSecurity(contentDoc)) + return false; + } + return true; +} + + +// HTMLIFrameElement ----------------------------------------------------------- + +// TODO(mbelshe): This should move into V8DOMWindowCustom.cpp +// Can't move it right now because it depends on V8ScheduledAction, +// which is private to this file (v8_custom.cpp). +v8::Handle<v8::Value> V8Custom::WindowSetTimeoutImpl(const v8::Arguments& args, + bool single_shot) { + int num_arguments = args.Length(); + + if (num_arguments < 1) return v8::Undefined(); + + DOMWindow* imp = V8Proxy::ToNativeObject<DOMWindow>( + V8ClassIndex::DOMWINDOW, args.Holder()); + + if (!imp->frame()) + return v8::Undefined(); + + if (!V8Proxy::CanAccessFrame(imp->frame(), true)) + return v8::Undefined(); + + ScriptExecutionContext* script_context = + static_cast<ScriptExecutionContext*>(imp->frame()->document()); + + v8::Handle<v8::Value> function = args[0]; + + int32_t timeout = 0; + if (num_arguments >= 2) timeout = args[1]->Int32Value(); + + int id; + if (function->IsString()) { + // Don't allow setting timeouts to run empty functions! + // (Bug 1009597) + WebCore::String string_function = ToWebCoreString(function); + if (string_function.length() == 0) + return v8::Undefined(); + + id = DOMTimer::install(script_context, + new ScheduledAction(string_function), timeout, + single_shot); + } else if (function->IsFunction()) { + int param_count = num_arguments >= 2 ? num_arguments - 2 : 0; + v8::Local<v8::Value>* params = 0; + if (param_count > 0) { + params = new v8::Local<v8::Value>[param_count]; + for (int i = 0; i < param_count; i++) + // parameters must be globalized + params[i] = args[i+2]; + } + + // params is passed to action, and released in action's destructor + ScheduledAction* action = new ScheduledAction( + v8::Handle<v8::Function>::Cast(function), param_count, params); + + delete[] params; + + id = DOMTimer::install(script_context, action, timeout, single_shot); + } else { + // TODO(fqian): what's the right return value if failed. + return v8::Undefined(); + } + return v8::Integer::New(id); +} + + +// DOMWindow ------------------------------------------------------------------- + +static bool IsAscii(const String& str) { + for (size_t i = 0; i < str.length(); i++) { + if (str[i] > 0xFF) + return false; + } + return true; +} + +static v8::Handle<v8::Value> Base64Convert(const String& str, bool encode) { + if (!IsAscii(str)) { + V8Proxy::SetDOMException(INVALID_CHARACTER_ERR); + return v8::Handle<v8::Value>(); + } + + Vector<char> in(str.length()); + for (size_t i = 0; i < str.length(); i++) { + in[i] = static_cast<char>(str[i]); + } + Vector<char> out; + + if (encode) { + base64Encode(in, out); + } else { + if (!base64Decode(in, out)) { + V8Proxy::ThrowError(V8Proxy::GENERAL_ERROR, "Cannot decode base64"); + return v8::Undefined(); + } + } + + return v8String(String(out.data(), out.size())); +} + +CALLBACK_FUNC_DECL(DOMWindowAtob) { + INC_STATS("DOM.DOMWindow.atob()"); + DOMWindow* imp = V8Proxy::ToNativeObject<DOMWindow>( + V8ClassIndex::DOMWINDOW, args.Holder()); + + if (!V8Proxy::CanAccessFrame(imp->frame(), true)) + return v8::Undefined(); + + if (args.Length() < 1) { + V8Proxy::ThrowError(V8Proxy::SYNTAX_ERROR, "Not enough arguments"); + return v8::Undefined(); + } + + if (args[0]->IsNull()) return v8String(""); + + String str = ToWebCoreString(args[0]); + return Base64Convert(str, false); +} + +CALLBACK_FUNC_DECL(DOMWindowBtoa) { + INC_STATS("DOM.DOMWindow.btoa()"); + DOMWindow* imp = V8Proxy::ToNativeObject<DOMWindow>( + V8ClassIndex::DOMWINDOW, args.Holder()); + + if (!V8Proxy::CanAccessFrame(imp->frame(), true)) + return v8::Undefined(); + + if (args.Length() < 1) { + V8Proxy::ThrowError(V8Proxy::SYNTAX_ERROR, "Not enough arguments"); + return v8::Undefined(); + } + + if (args[0]->IsNull()) return v8String(""); + + String str = ToWebCoreString(args[0]); + return Base64Convert(str, true); +} + +// TODO(fqian): returning string is cheating, and we should +// fix this by calling toString function on the receiver. +// However, V8 implements toString in JavaScript, which requires +// switching context of receiver. I consider it is dangerous. +CALLBACK_FUNC_DECL(DOMWindowToString) +{ + INC_STATS("DOM.DOMWindow.toString()"); + return args.This()->ObjectProtoToString(); +} + +CALLBACK_FUNC_DECL(DOMWindowNOP) +{ + INC_STATS("DOM.DOMWindow.nop()"); + return v8::Undefined(); +} + + +CALLBACK_FUNC_DECL(HTMLFormElementSubmit) { + INC_STATS("DOM.HTMLFormElement.submit()"); + + HTMLFormElement* form = + V8Proxy::DOMWrapperToNative<HTMLFormElement>(args.Holder()); + + form->submit(0, false, false); + return v8::Undefined(); +} + +static String EventNameFromAttributeName(const String& name) { + ASSERT(name.startsWith("on")); + String event_type = name.substring(2); + + if (event_type.startsWith("w")) { + switch(event_type[event_type.length() - 1]) { + case 't': + event_type = "webkitAnimationStart"; + break; + case 'n': + event_type = "webkitAnimationIteration"; + break; + case 'd': + ASSERT(event_type.length() > 7); + if (event_type[7] == 'a') + event_type = "webkitAnimationEnd"; + else + event_type = "webkitTransitionEnd"; + break; + } + } + + return event_type; +} + + +ACCESSOR_SETTER(DOMWindowEventHandler) { + v8::Handle<v8::Object> holder = V8Proxy::LookupDOMWrapper( + V8ClassIndex::DOMWINDOW, info.This()); + if (holder.IsEmpty()) + return; + + DOMWindow* imp = V8Proxy::ToNativeObject<DOMWindow>( + V8ClassIndex::DOMWINDOW, holder); + if (!imp->frame()) + return; + + Document* doc = imp->frame()->document(); + if (!doc) + return; + + String key = ToWebCoreString(name); + String event_type = EventNameFromAttributeName(key); + + if (value->IsNull()) { + // Clear the event listener + doc->removeWindowInlineEventListenerForType(event_type); + } else { + V8Proxy* proxy = V8Proxy::retrieve(imp->frame()); + if (!proxy) + return; + + RefPtr<EventListener> listener = + proxy->FindOrCreateV8EventListener(value, true); + if (listener) { + doc->setWindowInlineEventListenerForType(event_type, listener); + } + } +} + + +ACCESSOR_GETTER(DOMWindowEventHandler) { + v8::Handle<v8::Object> holder = V8Proxy::LookupDOMWrapper( + V8ClassIndex::DOMWINDOW, info.This()); + if (holder.IsEmpty()) + return v8::Undefined(); + + DOMWindow* imp = V8Proxy::ToNativeObject<DOMWindow>( + V8ClassIndex::DOMWINDOW, holder); + if (!imp->frame()) + return v8::Undefined(); + + Document* doc = imp->frame()->document(); + if (!doc) + return v8::Undefined(); + + String key = ToWebCoreString(name); + String event_type = EventNameFromAttributeName(key); + + EventListener* listener = doc->windowInlineEventListenerForType(event_type); + return V8Proxy::EventListenerToV8Object(listener); +} + + +// --------------- Security Checks ------------------------- +NAMED_ACCESS_CHECK(DOMWindow) { + ASSERT(V8ClassIndex::FromInt(data->Int32Value()) == V8ClassIndex::DOMWINDOW); + v8::Handle<v8::Value> window = + V8Proxy::LookupDOMWrapper(V8ClassIndex::DOMWINDOW, host); + if (window.IsEmpty()) + return false; // the frame is gone. + + DOMWindow* target_win = + V8Proxy::ToNativeObject<DOMWindow>(V8ClassIndex::DOMWINDOW, window); + + ASSERT(target_win); + + Frame* target = target_win->frame(); + if (!target) + return false; + + if (key->IsString()) { + String name = ToWebCoreString(key); + + // Allow access of GET and HAS if index is a subframe. + if ((type == v8::ACCESS_GET || type == v8::ACCESS_HAS) && + target->tree()->child(name)) { + return true; + } + } + + return V8Proxy::CanAccessFrame(target, false); +} + + +INDEXED_ACCESS_CHECK(DOMWindow) { + ASSERT(V8ClassIndex::FromInt(data->Int32Value()) == V8ClassIndex::DOMWINDOW); + v8::Handle<v8::Value> window = + V8Proxy::LookupDOMWrapper(V8ClassIndex::DOMWINDOW, host); + if (window.IsEmpty()) + return false; + + DOMWindow* target_win = + V8Proxy::ToNativeObject<DOMWindow>(V8ClassIndex::DOMWINDOW, window); + + ASSERT(target_win); + + Frame* target = target_win->frame(); + if (!target) + return false; + + // Allow access of GET and HAS if index is a subframe. + if ((type == v8::ACCESS_GET || type == v8::ACCESS_HAS) && + target->tree()->child(index)) { + return true; + } + + return V8Proxy::CanAccessFrame(target, false); +} + + +INDEXED_ACCESS_CHECK(History) { + ASSERT(V8ClassIndex::FromInt(data->Int32Value()) == V8ClassIndex::HISTORY); + // Only allow same origin access + History* imp = + V8Proxy::ToNativeObject<History>(V8ClassIndex::HISTORY, host); + return V8Proxy::CanAccessFrame(imp->frame(), false); +} + + +NAMED_ACCESS_CHECK(History) { + ASSERT(V8ClassIndex::FromInt(data->Int32Value()) == V8ClassIndex::HISTORY); + // Only allow same origin access + History* imp = + V8Proxy::ToNativeObject<History>(V8ClassIndex::HISTORY, host); + return V8Proxy::CanAccessFrame(imp->frame(), false); +} + + + +#undef INDEXED_ACCESS_CHECK +#undef NAMED_ACCESS_CHECK +#undef NAMED_PROPERTY_GETTER +#undef NAMED_PROPERTY_SETTER + + +// static +Frame* V8Custom::GetTargetFrame(v8::Local<v8::Object> host, + v8::Local<v8::Value> data) { + Frame* target = 0; + switch (V8ClassIndex::FromInt(data->Int32Value())) { + case V8ClassIndex::DOMWINDOW: { + v8::Handle<v8::Value> window = + V8Proxy::LookupDOMWrapper(V8ClassIndex::DOMWINDOW, host); + if (window.IsEmpty()) + return target; + + DOMWindow* target_win = + V8Proxy::ToNativeObject<DOMWindow>(V8ClassIndex::DOMWINDOW, window); + target = target_win->frame(); + break; + } + case V8ClassIndex::LOCATION: { + History* imp = + V8Proxy::ToNativeObject<History>(V8ClassIndex::HISTORY, host); + target = imp->frame(); + break; + } + case V8ClassIndex::HISTORY: { + Location* imp = + V8Proxy::ToNativeObject<Location>(V8ClassIndex::LOCATION, host); + target = imp->frame(); + break; + } + default: + break; + } + return target; +} + +#if ENABLE(SVG) +V8ClassIndex::V8WrapperType V8Custom::DowncastSVGPathSeg(void* path_seg) { + WebCore::SVGPathSeg *real_path_seg = + reinterpret_cast<WebCore::SVGPathSeg*>(path_seg); + + switch (real_path_seg->pathSegType()) { +#define MAKE_CASE(svg_val, v8_val) \ + case WebCore::SVGPathSeg::svg_val: \ + return V8ClassIndex::v8_val; + +MAKE_CASE(PATHSEG_CLOSEPATH, SVGPATHSEGCLOSEPATH) +MAKE_CASE(PATHSEG_MOVETO_ABS, SVGPATHSEGMOVETOABS) +MAKE_CASE(PATHSEG_MOVETO_REL, SVGPATHSEGMOVETOREL) +MAKE_CASE(PATHSEG_LINETO_ABS, SVGPATHSEGLINETOABS) +MAKE_CASE(PATHSEG_LINETO_REL, SVGPATHSEGLINETOREL) +MAKE_CASE(PATHSEG_CURVETO_CUBIC_ABS, SVGPATHSEGCURVETOCUBICABS) +MAKE_CASE(PATHSEG_CURVETO_CUBIC_REL, SVGPATHSEGCURVETOCUBICREL) +MAKE_CASE(PATHSEG_CURVETO_QUADRATIC_ABS, SVGPATHSEGCURVETOQUADRATICABS) +MAKE_CASE(PATHSEG_CURVETO_QUADRATIC_REL, SVGPATHSEGCURVETOQUADRATICREL) +MAKE_CASE(PATHSEG_ARC_ABS, SVGPATHSEGARCABS) +MAKE_CASE(PATHSEG_ARC_REL, SVGPATHSEGARCREL) +MAKE_CASE(PATHSEG_LINETO_HORIZONTAL_ABS, SVGPATHSEGLINETOHORIZONTALABS) +MAKE_CASE(PATHSEG_LINETO_HORIZONTAL_REL, SVGPATHSEGLINETOHORIZONTALREL) +MAKE_CASE(PATHSEG_LINETO_VERTICAL_ABS, SVGPATHSEGLINETOVERTICALABS) +MAKE_CASE(PATHSEG_LINETO_VERTICAL_REL, SVGPATHSEGLINETOVERTICALREL) +MAKE_CASE(PATHSEG_CURVETO_CUBIC_SMOOTH_ABS, SVGPATHSEGCURVETOCUBICSMOOTHABS) +MAKE_CASE(PATHSEG_CURVETO_CUBIC_SMOOTH_REL, SVGPATHSEGCURVETOCUBICSMOOTHREL) +MAKE_CASE(PATHSEG_CURVETO_QUADRATIC_SMOOTH_ABS, \ + SVGPATHSEGCURVETOQUADRATICSMOOTHABS) +MAKE_CASE(PATHSEG_CURVETO_QUADRATIC_SMOOTH_REL, \ + SVGPATHSEGCURVETOQUADRATICSMOOTHREL) + +#undef MAKE_CASE + + default: + return V8ClassIndex::INVALID_CLASS_INDEX; + } +} + +#endif // ENABLE(SVG) + +} // namespace WebCore diff --git a/V8Binding/binding/v8_custom.h b/V8Binding/binding/v8_custom.h new file mode 100644 index 0000000..caeac41 --- /dev/null +++ b/V8Binding/binding/v8_custom.h @@ -0,0 +1,559 @@ +// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef V8_CUSTOM_H__ +#define V8_CUSTOM_H__ + +#include <v8.h> +#include "v8_index.h" + +struct NPObject; + +#define CALLBACK_FUNC_DECL(NAME) \ +v8::Handle<v8::Value> V8Custom::v8##NAME##Callback(const v8::Arguments& args) + +#define ACCESSOR_GETTER(NAME) \ +v8::Handle<v8::Value> V8Custom::v8##NAME##AccessorGetter(\ + v8::Local<v8::String> name, const v8::AccessorInfo& info) + +#define ACCESSOR_SETTER(NAME) \ +void V8Custom::v8##NAME##AccessorSetter(v8::Local<v8::String> name, \ + v8::Local<v8::Value> value, \ + const v8::AccessorInfo& info) + +#define INDEXED_PROPERTY_GETTER(NAME) \ +v8::Handle<v8::Value> V8Custom::v8##NAME##IndexedPropertyGetter(\ + uint32_t index, const v8::AccessorInfo& info) + +#define INDEXED_PROPERTY_SETTER(NAME) \ +v8::Handle<v8::Value> V8Custom::v8##NAME##IndexedPropertySetter(\ + uint32_t index, v8::Local<v8::Value> value, const v8::AccessorInfo& info) + +#define INDEXED_PROPERTY_DELETER(NAME) \ +v8::Handle<v8::Boolean> V8Custom::v8##NAME##IndexedPropertyDeleter(\ + uint32_t index, const v8::AccessorInfo& info) + +#define NAMED_PROPERTY_GETTER(NAME) \ + v8::Handle<v8::Value> V8Custom::v8##NAME##NamedPropertyGetter(\ + v8::Local<v8::String> name, const v8::AccessorInfo& info) + +#define NAMED_PROPERTY_SETTER(NAME) \ + v8::Handle<v8::Value> V8Custom::v8##NAME##NamedPropertySetter(\ + v8::Local<v8::String> name, v8::Local<v8::Value> value, \ + const v8::AccessorInfo& info) + +#define NAMED_PROPERTY_DELETER(NAME) \ + v8::Handle<v8::Boolean> V8Custom::v8##NAME##NamedPropertyDeleter(\ + v8::Local<v8::String> name, const v8::AccessorInfo& info) + +#define NAMED_ACCESS_CHECK(NAME) \ + bool V8Custom::v8##NAME##NamedSecurityCheck(v8::Local<v8::Object> host, \ + v8::Local<v8::Value> key, \ + v8::AccessType type, \ + v8::Local<v8::Value> data) + +#define INDEXED_ACCESS_CHECK(NAME) \ + bool V8Custom::v8##NAME##IndexedSecurityCheck(v8::Local<v8::Object> host, \ + uint32_t index, \ + v8::AccessType type, \ + v8::Local<v8::Value> data) + +namespace WebCore { + +class Frame; +class V8Proxy; +class String; +class HTMLCollection; +class DOMWindow; + +class V8Custom { + public: + + // Constants. + static const int kDOMWrapperTypeIndex = 0; + static const int kDOMWrapperObjectIndex = 1; + static const int kDefaultWrapperInternalFieldCount = 2; + + static const int kNPObjectInternalFieldCount = + kDefaultWrapperInternalFieldCount + 0; + + static const int kDocumentImplementationIndex = + kDefaultWrapperInternalFieldCount + 0; + static const int kDocumentMinimumInternalFieldCount = + kDefaultWrapperInternalFieldCount + 1; + + static const int kHTMLDocumentMarkerIndex = + kDocumentMinimumInternalFieldCount + 0; + static const int kHTMLDocumentShadowIndex = + kDocumentMinimumInternalFieldCount + 1; + static const int kHTMLDocumentInternalFieldCount = + kDocumentMinimumInternalFieldCount + 2; + + static const int kXMLHttpRequestCacheIndex = + kDefaultWrapperInternalFieldCount + 0; + static const int kXMLHttpRequestInternalFieldCount = + kDefaultWrapperInternalFieldCount + 1; + + static const int kMessageChannelPort1Index = + kDefaultWrapperInternalFieldCount + 0; + static const int kMessageChannelPort2Index = + kDefaultWrapperInternalFieldCount + 1; + static const int kMessageChannelInternalFieldCount = + kDefaultWrapperInternalFieldCount + 2; + + static const int kMessagePortRequestCacheIndex = + kDefaultWrapperInternalFieldCount + 0; + static const int kMessagePortEntangledPortIndex = + kDefaultWrapperInternalFieldCount + 1; + static const int kMessagePortInternalFieldCount = + kDefaultWrapperInternalFieldCount + 2; + +#if ENABLE(WORKERS) + static const int kWorkerRequestCacheIndex = + kDefaultWrapperInternalFieldCount + 0; + static const int kWorkerInternalFieldCount = + kDefaultWrapperInternalFieldCount + 1; + + static const int kWorkerContextRequestCacheIndex = + kDefaultWrapperInternalFieldCount + 0; + static const int kWorkerContextInternalFieldCount = + kDefaultWrapperInternalFieldCount + 1; +#endif + + static const int kDOMWindowHistoryIndex = + kDefaultWrapperInternalFieldCount + 0; + static const int kDOMWindowNavigatorIndex = + kDefaultWrapperInternalFieldCount + 1; + static const int kDOMWindowLocationIndex = + kDefaultWrapperInternalFieldCount + 2; + static const int kDOMWindowInternalFieldCount = + kDefaultWrapperInternalFieldCount + 3; + + static const int kStyleSheetOwnerNodeIndex = + kDefaultWrapperInternalFieldCount + 0; + static const int kStyleSheetInternalFieldCount = + kDefaultWrapperInternalFieldCount + 1; + +#if ENABLE(OFFLINE_WEB_APPLICATIONS) + static const int kDOMApplicationCacheCacheIndex = + kDefaultWrapperInternalFieldCount + 0; + static const int kDOMApplicationCacheFieldCount = + kDefaultWrapperInternalFieldCount + 1; +#endif + +#define DECLARE_PROPERTY_ACCESSOR_GETTER(NAME) \ +static v8::Handle<v8::Value> v8##NAME##AccessorGetter(\ + v8::Local<v8::String> name, const v8::AccessorInfo& info); + +#define DECLARE_PROPERTY_ACCESSOR_SETTER(NAME) \ +static void v8##NAME##AccessorSetter(v8::Local<v8::String> name, \ + v8::Local<v8::Value> value, \ + const v8::AccessorInfo& info); + +#define DECLARE_PROPERTY_ACCESSOR(NAME) \ + DECLARE_PROPERTY_ACCESSOR_GETTER(NAME) \ + DECLARE_PROPERTY_ACCESSOR_SETTER(NAME) + + +#define DECLARE_NAMED_PROPERTY_GETTER(NAME) \ +static v8::Handle<v8::Value> v8##NAME##NamedPropertyGetter(\ + v8::Local<v8::String> name, const v8::AccessorInfo& info); + +#define DECLARE_NAMED_PROPERTY_SETTER(NAME) \ +static v8::Handle<v8::Value> v8##NAME##NamedPropertySetter(\ + v8::Local<v8::String> name, \ + v8::Local<v8::Value> value, \ + const v8::AccessorInfo& info); + +#define DECLARE_NAMED_PROPERTY_DELETER(NAME) \ +static v8::Handle<v8::Boolean> v8##NAME##NamedPropertyDeleter(\ + v8::Local<v8::String> name, const v8::AccessorInfo& info); + +#define USE_NAMED_PROPERTY_GETTER(NAME) \ + V8Custom::v8##NAME##NamedPropertyGetter + +#define USE_NAMED_PROPERTY_SETTER(NAME) \ + V8Custom::v8##NAME##NamedPropertySetter + +#define USE_NAMED_PROPERTY_DELETER(NAME) \ + V8Custom::v8##NAME##NamedPropertyDeleter + +#define DECLARE_INDEXED_PROPERTY_GETTER(NAME) \ +static v8::Handle<v8::Value> v8##NAME##IndexedPropertyGetter(\ + uint32_t index, const v8::AccessorInfo& info); + +#define DECLARE_INDEXED_PROPERTY_SETTER(NAME) \ +static v8::Handle<v8::Value> v8##NAME##IndexedPropertySetter(\ + uint32_t index, v8::Local<v8::Value> value, const v8::AccessorInfo& info); + +#define DECLARE_INDEXED_PROPERTY_DELETER(NAME) \ +static v8::Handle<v8::Boolean> v8##NAME##IndexedPropertyDeleter(\ + uint32_t index, const v8::AccessorInfo& info); + +#define USE_INDEXED_PROPERTY_GETTER(NAME) \ + V8Custom::v8##NAME##IndexedPropertyGetter + +#define USE_INDEXED_PROPERTY_SETTER(NAME) \ + V8Custom::v8##NAME##IndexedPropertySetter + +#define USE_INDEXED_PROPERTY_DELETER(NAME) \ + V8Custom::v8##NAME##IndexedPropertyDeleter + +#define DECLARE_CALLBACK(NAME) \ +static v8::Handle<v8::Value> v8##NAME##Callback(const v8::Arguments& args); + +#define USE_CALLBACK(NAME) \ + V8Custom::v8##NAME##Callback + +#define DECLARE_NAMED_ACCESS_CHECK(NAME) \ +static bool v8##NAME##NamedSecurityCheck(v8::Local<v8::Object> host, \ + v8::Local<v8::Value> key, \ + v8::AccessType type, \ + v8::Local<v8::Value> data); + +#define DECLARE_INDEXED_ACCESS_CHECK(NAME) \ +static bool v8##NAME##IndexedSecurityCheck(v8::Local<v8::Object> host, \ + uint32_t index, \ + v8::AccessType type, \ + v8::Local<v8::Value> data); + +DECLARE_PROPERTY_ACCESSOR(CanvasRenderingContext2DStrokeStyle) +DECLARE_PROPERTY_ACCESSOR(CanvasRenderingContext2DFillStyle) +// Customized getter&setter of DOMWindow.location +DECLARE_PROPERTY_ACCESSOR_SETTER(DOMWindowLocation) +// Customized setter of DOMWindow.opener +DECLARE_PROPERTY_ACCESSOR_SETTER(DOMWindowOpener) + +DECLARE_PROPERTY_ACCESSOR(DocumentLocation) +DECLARE_PROPERTY_ACCESSOR(DocumentImplementation) +DECLARE_PROPERTY_ACCESSOR_GETTER(EventSrcElement) +DECLARE_PROPERTY_ACCESSOR(EventReturnValue) +DECLARE_PROPERTY_ACCESSOR_GETTER(EventDataTransfer) +DECLARE_PROPERTY_ACCESSOR_GETTER(EventClipboardData) + +// Getter/Setter for window event handlers +DECLARE_PROPERTY_ACCESSOR(DOMWindowEventHandler) +// Getter/Setter for Element event handlers +DECLARE_PROPERTY_ACCESSOR(ElementEventHandler) + +// HTMLCanvasElement +DECLARE_CALLBACK(HTMLCanvasElementGetContext) + +// Customized setter of src and location on HTMLFrameElement +DECLARE_PROPERTY_ACCESSOR_SETTER(HTMLFrameElementSrc) +DECLARE_PROPERTY_ACCESSOR_SETTER(HTMLFrameElementLocation) +// Customized setter of src on HTMLIFrameElement +DECLARE_PROPERTY_ACCESSOR_SETTER(HTMLIFrameElementSrc) +// Customized setter of Attr.value +DECLARE_PROPERTY_ACCESSOR_SETTER(AttrValue) + +// Customized setter of HTMLOptionsCollection length +DECLARE_PROPERTY_ACCESSOR(HTMLOptionsCollectionLength) + +DECLARE_CALLBACK(HTMLInputElementSetSelectionRange) + +// Customized accessors for HTMLInputElement +DECLARE_PROPERTY_ACCESSOR(HTMLInputElementSelectionStart) +DECLARE_PROPERTY_ACCESSOR(HTMLInputElementSelectionEnd) + +DECLARE_NAMED_ACCESS_CHECK(Location) +DECLARE_INDEXED_ACCESS_CHECK(History) + +DECLARE_NAMED_ACCESS_CHECK(History) +DECLARE_INDEXED_ACCESS_CHECK(Location) + +// HTMLCollection customized functions. +DECLARE_CALLBACK(HTMLCollectionItem) +DECLARE_CALLBACK(HTMLCollectionNamedItem) +// HTMLCollections are callable as functions. +DECLARE_CALLBACK(HTMLCollectionCallAsFunction) + +// HTMLSelectElement customized functions. +DECLARE_CALLBACK(HTMLSelectElementRemove) + +// HTMLOptionsCollection customized functions. +DECLARE_CALLBACK(HTMLOptionsCollectionRemove) +DECLARE_CALLBACK(HTMLOptionsCollectionAdd) + +// HTMLDocument customized functions +DECLARE_CALLBACK(HTMLDocumentWrite) +DECLARE_CALLBACK(HTMLDocumentWriteln) +DECLARE_CALLBACK(HTMLDocumentOpen) +DECLARE_PROPERTY_ACCESSOR(HTMLDocumentAll) +DECLARE_NAMED_PROPERTY_GETTER(HTMLDocument) +DECLARE_NAMED_PROPERTY_DELETER(HTMLDocument) + +// Document customized functions +DECLARE_CALLBACK(DocumentEvaluate) +DECLARE_CALLBACK(DocumentGetCSSCanvasContext) + +// Window customized functions +DECLARE_CALLBACK(DOMWindowAddEventListener) +DECLARE_CALLBACK(DOMWindowRemoveEventListener) +DECLARE_CALLBACK(DOMWindowPostMessage) +DECLARE_CALLBACK(DOMWindowSetTimeout) +DECLARE_CALLBACK(DOMWindowSetInterval) +DECLARE_CALLBACK(DOMWindowAtob) +DECLARE_CALLBACK(DOMWindowBtoa) +DECLARE_CALLBACK(DOMWindowNOP) +DECLARE_CALLBACK(DOMWindowToString) +DECLARE_CALLBACK(DOMWindowShowModalDialog) +DECLARE_CALLBACK(DOMWindowOpen) +DECLARE_CALLBACK(DOMWindowClearTimeout) +DECLARE_CALLBACK(DOMWindowClearInterval) + +DECLARE_CALLBACK(DOMParserConstructor) +DECLARE_CALLBACK(MessageChannelConstructor) +DECLARE_CALLBACK(WebKitCSSMatrixConstructor) +DECLARE_CALLBACK(WebKitPointConstructor) +DECLARE_CALLBACK(XMLHttpRequestConstructor) +DECLARE_CALLBACK(XMLSerializerConstructor) +DECLARE_CALLBACK(XPathEvaluatorConstructor) +DECLARE_CALLBACK(XSLTProcessorConstructor) + +// Implementation of custom XSLTProcessor methods. +DECLARE_CALLBACK(XSLTProcessorImportStylesheet) +DECLARE_CALLBACK(XSLTProcessorTransformToFragment) +DECLARE_CALLBACK(XSLTProcessorTransformToDocument) +DECLARE_CALLBACK(XSLTProcessorSetParameter) +DECLARE_CALLBACK(XSLTProcessorGetParameter) +DECLARE_CALLBACK(XSLTProcessorRemoveParameter) + +// CSSPrimitiveValue customized functions +DECLARE_CALLBACK(CSSPrimitiveValueGetRGBColorValue) + +// Canvas 2D customized functions +DECLARE_CALLBACK(CanvasRenderingContext2DSetStrokeColor) +DECLARE_CALLBACK(CanvasRenderingContext2DSetFillColor) +DECLARE_CALLBACK(CanvasRenderingContext2DStrokeRect) +DECLARE_CALLBACK(CanvasRenderingContext2DSetShadow) +DECLARE_CALLBACK(CanvasRenderingContext2DDrawImage) +DECLARE_CALLBACK(CanvasRenderingContext2DDrawImageFromRect) +DECLARE_CALLBACK(CanvasRenderingContext2DCreatePattern) +DECLARE_CALLBACK(CanvasRenderingContext2DFillText) +DECLARE_CALLBACK(CanvasRenderingContext2DStrokeText) +DECLARE_CALLBACK(CanvasRenderingContext2DPutImageData) + +// Implementation of Clipboard attributes and methods. +DECLARE_PROPERTY_ACCESSOR_GETTER(ClipboardTypes) +DECLARE_CALLBACK(ClipboardClearData) +DECLARE_CALLBACK(ClipboardGetData) +DECLARE_CALLBACK(ClipboardSetData) +DECLARE_CALLBACK(ClipboardSetDragImage); + +// Implementation of Element methods. +DECLARE_CALLBACK(ElementQuerySelector) +DECLARE_CALLBACK(ElementQuerySelectorAll) +DECLARE_CALLBACK(ElementSetAttribute) +DECLARE_CALLBACK(ElementSetAttributeNode) +DECLARE_CALLBACK(ElementSetAttributeNS) +DECLARE_CALLBACK(ElementSetAttributeNodeNS) + +// Implementation of custom Location methods. +DECLARE_PROPERTY_ACCESSOR_SETTER(LocationProtocol) +DECLARE_PROPERTY_ACCESSOR_SETTER(LocationHost) +DECLARE_PROPERTY_ACCESSOR_SETTER(LocationHostname) +DECLARE_PROPERTY_ACCESSOR_SETTER(LocationPort) +DECLARE_PROPERTY_ACCESSOR_SETTER(LocationPathname) +DECLARE_PROPERTY_ACCESSOR_SETTER(LocationSearch) +DECLARE_PROPERTY_ACCESSOR_SETTER(LocationHash) +DECLARE_PROPERTY_ACCESSOR_SETTER(LocationHref) +DECLARE_PROPERTY_ACCESSOR_GETTER(LocationAssign) +DECLARE_PROPERTY_ACCESSOR_GETTER(LocationReplace) +DECLARE_PROPERTY_ACCESSOR_GETTER(LocationReload) +DECLARE_CALLBACK(LocationAssign) +DECLARE_CALLBACK(LocationReplace) +DECLARE_CALLBACK(LocationReload) +DECLARE_CALLBACK(LocationToString) +DECLARE_CALLBACK(LocationValueOf) + +// Implementation of EventTarget::addEventListener +// and EventTarget::removeEventListener +DECLARE_CALLBACK(NodeAddEventListener) +DECLARE_CALLBACK(NodeRemoveEventListener) + +// Custom implementation is Navigator properties. +// We actually only need this because WebKit has +// navigator.appVersion as custom. Our version just +// passes through. +DECLARE_PROPERTY_ACCESSOR(NavigatorAppVersion) + +// Custom implementation of XMLHttpRequest properties +DECLARE_PROPERTY_ACCESSOR(XMLHttpRequestOnabort) +DECLARE_PROPERTY_ACCESSOR(XMLHttpRequestOnerror) +DECLARE_PROPERTY_ACCESSOR(XMLHttpRequestOnload) +DECLARE_PROPERTY_ACCESSOR(XMLHttpRequestOnloadstart) +DECLARE_PROPERTY_ACCESSOR(XMLHttpRequestOnprogress) +DECLARE_PROPERTY_ACCESSOR(XMLHttpRequestOnreadystatechange) +DECLARE_PROPERTY_ACCESSOR(XMLHttpRequestResponseText) +DECLARE_CALLBACK(XMLHttpRequestAddEventListener) +DECLARE_CALLBACK(XMLHttpRequestRemoveEventListener) +DECLARE_CALLBACK(XMLHttpRequestOpen) +DECLARE_CALLBACK(XMLHttpRequestSend) +DECLARE_CALLBACK(XMLHttpRequestSetRequestHeader) +DECLARE_CALLBACK(XMLHttpRequestGetResponseHeader) +DECLARE_CALLBACK(XMLHttpRequestOverrideMimeType) +DECLARE_CALLBACK(XMLHttpRequestDispatchEvent) + +// Custom implementation of XMLHttpRequestUpload properties +DECLARE_PROPERTY_ACCESSOR(XMLHttpRequestUploadOnabort) +DECLARE_PROPERTY_ACCESSOR(XMLHttpRequestUploadOnerror) +DECLARE_PROPERTY_ACCESSOR(XMLHttpRequestUploadOnload) +DECLARE_PROPERTY_ACCESSOR(XMLHttpRequestUploadOnloadstart) +DECLARE_PROPERTY_ACCESSOR(XMLHttpRequestUploadOnprogress) +DECLARE_CALLBACK(XMLHttpRequestUploadAddEventListener) +DECLARE_CALLBACK(XMLHttpRequestUploadRemoveEventListener) +DECLARE_CALLBACK(XMLHttpRequestUploadDispatchEvent) + +// Custom implementation of TreeWalker functions +DECLARE_CALLBACK(TreeWalkerParentNode) +DECLARE_CALLBACK(TreeWalkerFirstChild) +DECLARE_CALLBACK(TreeWalkerLastChild) +DECLARE_CALLBACK(TreeWalkerNextNode) +DECLARE_CALLBACK(TreeWalkerPreviousNode) +DECLARE_CALLBACK(TreeWalkerNextSibling) +DECLARE_CALLBACK(TreeWalkerPreviousSibling) + +// Custom implementation of InspectorController functions +DECLARE_CALLBACK(InspectorControllerDebuggerEnabled) +DECLARE_CALLBACK(InspectorControllerPauseOnExceptions) +DECLARE_CALLBACK(InspectorControllerProfilerEnabled) +#if ENABLE(DATABASE) +DECLARE_CALLBACK(InspectorControllerDatabaseTableNames) +#endif +DECLARE_CALLBACK(InspectorControllerWrapCallback) + +// Custom implementation of NodeIterator functions +DECLARE_CALLBACK(NodeIteratorNextNode) +DECLARE_CALLBACK(NodeIteratorPreviousNode) + +// Custom implementation of NodeFilter function +DECLARE_CALLBACK(NodeFilterAcceptNode) + +// Custom implementation of HTMLFormElement +DECLARE_CALLBACK(HTMLFormElementSubmit) + +DECLARE_INDEXED_PROPERTY_GETTER(DOMStringList) +DECLARE_CALLBACK(DOMStringListItem) + +DECLARE_NAMED_PROPERTY_GETTER(DOMWindow) +DECLARE_INDEXED_PROPERTY_GETTER(DOMWindow) +DECLARE_NAMED_ACCESS_CHECK(DOMWindow) +DECLARE_INDEXED_ACCESS_CHECK(DOMWindow) + +DECLARE_NAMED_PROPERTY_GETTER(HTMLFrameSetElement) +DECLARE_NAMED_PROPERTY_GETTER(HTMLFormElement) +DECLARE_NAMED_PROPERTY_GETTER(NodeList) +DECLARE_NAMED_PROPERTY_GETTER(NamedNodeMap) +DECLARE_NAMED_PROPERTY_GETTER(CSSStyleDeclaration) +DECLARE_NAMED_PROPERTY_SETTER(CSSStyleDeclaration) +DECLARE_NAMED_PROPERTY_GETTER(HTMLPlugInElement) +DECLARE_NAMED_PROPERTY_SETTER(HTMLPlugInElement) +DECLARE_INDEXED_PROPERTY_GETTER(HTMLPlugInElement) +DECLARE_INDEXED_PROPERTY_SETTER(HTMLPlugInElement) + +// Plugin object can be called as function. +DECLARE_CALLBACK(HTMLPlugInElement) + +DECLARE_NAMED_PROPERTY_GETTER(StyleSheetList) +DECLARE_INDEXED_PROPERTY_GETTER(NamedNodeMap) +DECLARE_INDEXED_PROPERTY_GETTER(HTMLFormElement) +DECLARE_INDEXED_PROPERTY_GETTER(HTMLOptionsCollection) +DECLARE_INDEXED_PROPERTY_SETTER(HTMLOptionsCollection) +DECLARE_INDEXED_PROPERTY_SETTER(HTMLSelectElementCollection) +DECLARE_NAMED_PROPERTY_GETTER(HTMLCollection) + +// Canvas and supporting classes +DECLARE_INDEXED_PROPERTY_GETTER(CanvasPixelArray) +DECLARE_INDEXED_PROPERTY_SETTER(CanvasPixelArray) + +// MessagePort +DECLARE_PROPERTY_ACCESSOR(MessagePortOnmessage) +DECLARE_PROPERTY_ACCESSOR(MessagePortOnclose) +DECLARE_CALLBACK(MessagePortStartConversation) +DECLARE_CALLBACK(MessagePortAddEventListener) +DECLARE_CALLBACK(MessagePortRemoveEventListener) + +// Database +DECLARE_CALLBACK(DatabaseChangeVersion) +DECLARE_CALLBACK(DatabaseTransaction) +DECLARE_CALLBACK(SQLTransactionExecuteSql) +DECLARE_CALLBACK(SQLResultSetRowListItem) + +// SVG custom properties and callbacks +#if ENABLE(SVG) +DECLARE_PROPERTY_ACCESSOR_GETTER(SVGLengthValue) +DECLARE_CALLBACK(SVGLengthConvertToSpecifiedUnits) +DECLARE_CALLBACK(SVGMatrixInverse) +DECLARE_CALLBACK(SVGMatrixRotateFromVector) +DECLARE_CALLBACK(SVGElementInstanceAddEventListener) +DECLARE_CALLBACK(SVGElementInstanceRemoveEventListener) +#endif + +// Worker +#if ENABLE(WORKERS) +DECLARE_PROPERTY_ACCESSOR(WorkerOnmessage) +DECLARE_PROPERTY_ACCESSOR(WorkerOnerror) +DECLARE_CALLBACK(WorkerConstructor) +DECLARE_CALLBACK(WorkerAddEventListener) +DECLARE_CALLBACK(WorkerRemoveEventListener) + +DECLARE_PROPERTY_ACCESSOR_GETTER(WorkerContextSelf) +DECLARE_PROPERTY_ACCESSOR(WorkerContextOnmessage) +DECLARE_CALLBACK(WorkerContextImportScripts) +DECLARE_CALLBACK(WorkerContextSetTimeout) +DECLARE_CALLBACK(WorkerContextClearTimeout) +DECLARE_CALLBACK(WorkerContextSetInterval) +DECLARE_CALLBACK(WorkerContextClearInterval) +DECLARE_CALLBACK(WorkerContextAddEventListener) +DECLARE_CALLBACK(WorkerContextRemoveEventListener) +#endif + +// AppCache +#if ENABLE(OFFLINE_WEB_APPLICATIONS) +DECLARE_PROPERTY_ACCESSOR(DOMApplicationCacheEventHandler) +DECLARE_CALLBACK(DOMApplicationCacheAddEventListener) +DECLARE_CALLBACK(DOMApplicationCacheRemoveEventListener) +#endif + +#undef DECLARE_INDEXED_ACCESS_CHECK +#undef DECLARE_NAMED_ACCESS_CHECK + +#undef DECLARE_PROPERTY_ACCESSOR_SETTER +#undef DECLARE_PROPERTY_ACCESSOR_GETTER +#undef DECLARE_PROPERTY_ACCESSOR + +#undef DECLARE_NAMED_PROPERTY_GETTER +#undef DECLARE_NAMED_PROPERTY_SETTER +#undef DECLARE_NAMED_PROPERTY_DELETER + +#undef DECLARE_INDEXED_PROPERTY_GETTER +#undef DECLARE_INDEXED_PROPERTY_SETTER +#undef DECLARE_INDEXED_PROPERTY_DELETER + +#undef DECLARE_CALLBACK + + // Returns the NPObject corresponding to an HTMLElement object. + static NPObject* GetHTMLPlugInElementNPObject(v8::Handle<v8::Object> object); + + // Returns the owner frame pointer of a DOM wrapper object. It only works for + // these DOM objects requiring cross-domain access check. + static Frame* GetTargetFrame(v8::Local<v8::Object> host, + v8::Local<v8::Value> data); + + // Special case for downcasting SVG path segments +#if ENABLE(SVG) + static V8ClassIndex::V8WrapperType DowncastSVGPathSeg(void* path_seg); +#endif + + private: + static v8::Handle<v8::Value> WindowSetTimeoutImpl(const v8::Arguments& args, + bool single_shot); + static void ClearTimeoutImpl(const v8::Arguments& args); + static void WindowSetLocation(DOMWindow*, const String&); +}; + +} // namespace WebCore + +#endif // V8_CUSTOM_H__ diff --git a/V8Binding/binding/v8_helpers.cpp b/V8Binding/binding/v8_helpers.cpp new file mode 100644 index 0000000..7a72ab5 --- /dev/null +++ b/V8Binding/binding/v8_helpers.cpp @@ -0,0 +1,59 @@ +// Copyright (c) 2008, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#include "config.h" + +#define max max +#define min min +#include "v8_helpers.h" +#include "v8_proxy.h" +#include "v8_index.h" +#include "NPV8Object.h" + +#include "DOMWindow.h" + +using WebCore::V8Custom; + +void WrapNPObject(v8::Handle<v8::Object> obj, NPObject* npobj) +{ + WebCore::V8Proxy::SetDOMWrapper(obj, WebCore::V8ClassIndex::NPOBJECT, npobj); +} + +v8::Local<v8::Context> getV8Context(NPP npp, NPObject* npobj) +{ + V8NPObject* object = reinterpret_cast<V8NPObject*>(npobj); + return WebCore::V8Proxy::GetContext(object->rootObject->frame()); +} + +WebCore::V8Proxy* GetV8Proxy(NPObject* npobj) +{ + V8NPObject* object = reinterpret_cast<V8NPObject*>(npobj); + WebCore::Frame* frame = object->rootObject->frame(); + return WebCore::V8Proxy::retrieve(frame); +} diff --git a/V8Binding/binding/v8_helpers.h b/V8Binding/binding/v8_helpers.h new file mode 100644 index 0000000..b7f15aa --- /dev/null +++ b/V8Binding/binding/v8_helpers.h @@ -0,0 +1,29 @@ +// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef V8_HELPERS_H__ +#define V8_HELPERS_H__ + +#if PLATFORM(CHROMIUM) +#include "third_party/npapi/bindings/npruntime.h" +#else +#include "bridge/npruntime.h" // use WebCore version +#endif + +#include <v8.h> + +namespace WebCore { + class V8Proxy; +} + +// Associates an NPObject with a V8 object. +void WrapNPObject(v8::Handle<v8::Object> obj, NPObject *npobj); + +// Retrieves the V8 Context from the NP context pr obj (at most 1 may be NULL). +v8::Local<v8::Context> getV8Context(NPP npp, NPObject* npobj); + +// Get V8Proxy object from an NPObject. +WebCore::V8Proxy* GetV8Proxy(NPObject* npobj); + +#endif // V8_HELPERS_H__ diff --git a/V8Binding/binding/v8_index.cpp b/V8Binding/binding/v8_index.cpp new file mode 100644 index 0000000..df138dc --- /dev/null +++ b/V8Binding/binding/v8_index.cpp @@ -0,0 +1,431 @@ +// Copyright (c) 2008, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#include "config.h" + +#include "v8_index.h" + +// TODO: Can we use a macro to include necessary headers by using +// WRAPPER_TYPES? +#include "V8Attr.h" +#include "V8BarInfo.h" +#include "V8CanvasRenderingContext2D.h" +#include "V8CanvasGradient.h" +#include "V8CanvasPattern.h" +#include "V8CanvasPixelArray.h" +#include "V8CDATASection.h" +#include "V8CharacterData.h" +#include "V8ClientRect.h" +#include "V8ClientRectList.h" +#include "V8Clipboard.h" +#include "V8Comment.h" +#include "V8Console.h" +#include "V8Counter.h" +#include "V8CSSStyleDeclaration.h" +#include "V8CSSRule.h" +#include "V8CSSStyleRule.h" +#include "V8CSSCharsetRule.h" +#include "V8CSSImportRule.h" +#include "V8CSSMediaRule.h" +#include "V8CSSFontFaceRule.h" +#include "V8CSSPageRule.h" +#include "V8CSSRuleList.h" +#include "V8CSSPrimitiveValue.h" +#include "V8CSSValue.h" +#include "V8CSSValueList.h" +#include "V8CSSStyleSheet.h" +#include "V8CSSVariablesDeclaration.h" +#include "V8CSSVariablesRule.h" +#include "V8Document.h" +#include "V8DocumentFragment.h" +#include "V8DocumentType.h" +#include "V8Element.h" +#include "V8Entity.h" +#include "V8EntityReference.h" +#include "V8File.h" +#include "V8FileList.h" +#include "V8History.h" +#include "V8HTMLCanvasElement.h" +#include "V8UndetectableHTMLCollection.h" +#include "V8HTMLCollection.h" +#include "V8HTMLDocument.h" +#include "V8HTMLElement.h" +#include "V8HTMLOptionsCollection.h" +#include "V8HTMLAnchorElement.h" +#include "V8HTMLAppletElement.h" +#include "V8HTMLAreaElement.h" +#include "V8HTMLBaseElement.h" +#include "V8HTMLBaseFontElement.h" +#include "V8HTMLBlockquoteElement.h" +#include "V8HTMLBodyElement.h" +#include "V8HTMLBRElement.h" +#include "V8HTMLButtonElement.h" +#include "V8HTMLCanvasElement.h" +#include "V8HTMLModElement.h" +#include "V8HTMLDirectoryElement.h" +#include "V8HTMLDivElement.h" +#include "V8HTMLDListElement.h" +#include "V8HTMLEmbedElement.h" +#include "V8HTMLFieldSetElement.h" +#include "V8HTMLFormElement.h" +#include "V8HTMLFontElement.h" +#include "V8HTMLFrameElement.h" +#include "V8HTMLFrameSetElement.h" +#include "V8HTMLHeadingElement.h" +#include "V8HTMLHeadElement.h" +#include "V8HTMLHRElement.h" +#include "V8HTMLHtmlElement.h" +#include "V8HTMLIFrameElement.h" +#include "V8HTMLImageElement.h" +#include "V8HTMLInputElement.h" +#include "V8HTMLIsIndexElement.h" +#include "V8HTMLLabelElement.h" +#include "V8HTMLLegendElement.h" +#include "V8HTMLLIElement.h" +#include "V8HTMLLinkElement.h" +#include "V8HTMLMapElement.h" +#include "V8HTMLMarqueeElement.h" +#include "V8HTMLMenuElement.h" +#include "V8HTMLMetaElement.h" +#include "V8HTMLObjectElement.h" +#include "V8HTMLOListElement.h" +#include "V8HTMLOptGroupElement.h" +#include "V8HTMLOptionElement.h" +#include "V8HTMLParagraphElement.h" +#include "V8HTMLParamElement.h" +#include "V8HTMLPreElement.h" +#include "V8HTMLQuoteElement.h" +#include "V8HTMLScriptElement.h" +#include "V8HTMLSelectElement.h" +#include "V8HTMLStyleElement.h" +#include "V8HTMLTableCaptionElement.h" +#include "V8HTMLTableColElement.h" +#include "V8HTMLTableElement.h" +#include "V8HTMLTableSectionElement.h" +#include "V8HTMLTableCellElement.h" +#include "V8HTMLTableRowElement.h" +#include "V8HTMLTextAreaElement.h" +#include "V8HTMLTitleElement.h" +#include "V8HTMLUListElement.h" +#include "V8ImageData.h" +#include "V8MediaList.h" +#include "V8MessageChannel.h" +#include "V8MessageEvent.h" +#include "V8MessagePort.h" +#include "V8NamedNodeMap.h" +#include "V8Node.h" +#include "V8NodeList.h" +#include "V8NodeFilter.h" +#include "V8Notation.h" +#include "V8ProcessingInstruction.h" +#include "V8ProgressEvent.h" +#include "V8StyleSheet.h" +#include "V8Text.h" +#include "V8TextEvent.h" +#include "V8DOMCoreException.h" +#include "V8DOMParser.h" +#include "V8DOMStringList.h" +#include "V8DOMWindow.h" +#include "V8Event.h" +#include "V8EventException.h" +#include "V8KeyboardEvent.h" +#include "V8MouseEvent.h" +#include "V8WebKitAnimationEvent.h" +#include "V8WebKitCSSKeyframeRule.h" +#include "V8WebKitCSSKeyframesRule.h" +#include "V8WebKitCSSMatrix.h" +#include "V8WebKitCSSTransformValue.h" +#include "V8WebKitPoint.h" +#include "V8WebKitTransitionEvent.h" +#include "V8WheelEvent.h" +#include "V8UIEvent.h" +#include "V8MutationEvent.h" +#include "V8OverflowEvent.h" +#include "V8Location.h" +#include "V8Screen.h" +#include "V8DOMSelection.h" +#include "V8Navigator.h" +#include "V8MimeType.h" +#include "V8MimeTypeArray.h" +#include "V8Plugin.h" +#include "V8PluginArray.h" +#include "V8Range.h" +#include "V8RangeException.h" +#include "V8Rect.h" +#include "V8NodeIterator.h" +#include "V8TextMetrics.h" +#include "V8TreeWalker.h" +#include "V8StyleSheetList.h" +#include "V8DOMImplementation.h" + +#if ENABLE(XPATH) +#include "V8XPathResult.h" +#include "V8XPathException.h" +#include "V8XPathExpression.h" +#include "V8XPathNSResolver.h" +#include "V8XPathEvaluator.h" +#endif +#if ENABLE(XSLT) +#include "V8XSLTProcessor.h" +#endif + +#include "V8XMLHttpRequest.h" +#include "V8XMLHttpRequestException.h" +#include "V8XMLHttpRequestProgressEvent.h" +#include "V8XMLHttpRequestUpload.h" +#include "V8XMLSerializer.h" +#include "V8RGBColor.h" + +#if PLATFORM(CHROMIUM) +#include "V8InspectorController.h" +#endif + +#if PLATFORM(CHROMIUM) || ENABLE(DATABASE) +#include "V8Database.h" +#include "V8SQLError.h" +#include "V8SQLResultSet.h" +#include "V8SQLResultSetRowList.h" +#include "V8SQLTransaction.h" +#endif + +#if ENABLE(SVG_ANIMATION) +#include "V8SVGAnimateColorElement.h" +#include "V8SVGAnimateElement.h" +#include "V8SVGAnimateTransformElement.h" +#include "V8SVGAnimationElement.h" +#include "V8SVGSetElement.h" +#endif + +#if ENABLE(SVG_FILTERS) +#include "V8SVGComponentTransferFunctionElement.h" +#include "V8SVGFEBlendElement.h" +#include "V8SVGFEColorMatrixElement.h" +#include "V8SVGFEComponentTransferElement.h" +#include "V8SVGFECompositeElement.h" +#include "V8SVGFEDiffuseLightingElement.h" +#include "V8SVGFEDisplacementMapElement.h" +#include "V8SVGFEDistantLightElement.h" +#include "V8SVGFEFloodElement.h" +#include "V8SVGFEFuncAElement.h" +#include "V8SVGFEFuncBElement.h" +#include "V8SVGFEFuncGElement.h" +#include "V8SVGFEFuncRElement.h" +#include "V8SVGFEGaussianBlurElement.h" +#include "V8SVGFEImageElement.h" +#include "V8SVGFEMergeElement.h" +#include "V8SVGFEMergeNodeElement.h" +#include "V8SVGFEOffsetElement.h" +#include "V8SVGFEPointLightElement.h" +#include "V8SVGFESpecularLightingElement.h" +#include "V8SVGFESpotLightElement.h" +#include "V8SVGFETileElement.h" +#include "V8SVGFETurbulenceElement.h" +#include "V8SVGFilterElement.h" +#endif + +#if ENABLE(SVG_FONTS) +#include "V8SVGDefinitionSrcElement.h" +#include "V8SVGFontFaceElement.h" +#include "V8SVGFontFaceFormatElement.h" +#include "V8SVGFontFaceNameElement.h" +#include "V8SVGFontFaceSrcElement.h" +#include "V8SVGFontFaceUriElement.h" +#endif + +#if ENABLE(SVG_FOREIGN_OBJECT) +#include "V8SVGForeignObjectElement.h" +#endif + +#if ENABLE(SVG_USE) +#include "V8SVGUseElement.h" +#endif + +#if ENABLE(SVG) +#include "V8SVGAElement.h" +#include "V8SVGAltGlyphElement.h" +#include "V8SVGCircleElement.h" +#include "V8SVGClipPathElement.h" +#include "V8SVGCursorElement.h" +#include "V8SVGDefsElement.h" +#include "V8SVGDescElement.h" +#include "V8SVGElement.h" +#include "V8SVGEllipseElement.h" +#include "V8SVGException.h" +#include "V8SVGGElement.h" +#include "V8SVGGlyphElement.h" +#include "V8SVGGradientElement.h" +#include "V8SVGImageElement.h" +#include "V8SVGLinearGradientElement.h" +#include "V8SVGLineElement.h" +#include "V8SVGMarkerElement.h" +#include "V8SVGMaskElement.h" +#include "V8SVGMetadataElement.h" +#include "V8SVGPathElement.h" +#include "V8SVGPatternElement.h" +#include "V8SVGPolygonElement.h" +#include "V8SVGPolylineElement.h" +#include "V8SVGRadialGradientElement.h" +#include "V8SVGRectElement.h" +#include "V8SVGScriptElement.h" +#include "V8SVGStopElement.h" +#include "V8SVGStyleElement.h" +#include "V8SVGSVGElement.h" +#include "V8SVGSwitchElement.h" +#include "V8SVGSymbolElement.h" +#include "V8SVGTextContentElement.h" +#include "V8SVGTextElement.h" +#include "V8SVGTextPathElement.h" +#include "V8SVGTextPositioningElement.h" +#include "V8SVGTitleElement.h" +#include "V8SVGTRefElement.h" +#include "V8SVGTSpanElement.h" +#include "V8SVGViewElement.h" +#include "V8SVGAngle.h" +#include "V8SVGAnimatedAngle.h" +#include "V8SVGAnimatedBoolean.h" +#include "V8SVGAnimatedEnumeration.h" +#include "V8SVGAnimatedInteger.h" +#include "V8SVGAnimatedLength.h" +#include "V8SVGAnimatedLengthList.h" +#include "V8SVGAnimatedNumber.h" +#include "V8SVGAnimatedNumberList.h" +#include "V8SVGAnimatedPoints.h" +#include "V8SVGAnimatedPreserveAspectRatio.h" +#include "V8SVGAnimatedRect.h" +#include "V8SVGAnimatedString.h" +#include "V8SVGAnimatedTransformList.h" +#include "V8SVGColor.h" +#include "V8SVGDocument.h" +#include "V8SVGElementInstance.h" +#include "V8SVGElementInstanceList.h" +#include "V8SVGLength.h" +#include "V8SVGLengthList.h" +#include "V8SVGMatrix.h" +#include "V8SVGNumber.h" +#include "V8SVGNumberList.h" +#include "V8SVGPaint.h" +#include "V8SVGPathSeg.h" +#include "V8SVGPathSegArcAbs.h" +#include "V8SVGPathSegArcRel.h" +#include "V8SVGPathSegClosePath.h" +#include "V8SVGPathSegCurvetoCubicAbs.h" +#include "V8SVGPathSegCurvetoCubicRel.h" +#include "V8SVGPathSegCurvetoCubicSmoothAbs.h" +#include "V8SVGPathSegCurvetoCubicSmoothRel.h" +#include "V8SVGPathSegCurvetoQuadraticAbs.h" +#include "V8SVGPathSegCurvetoQuadraticRel.h" +#include "V8SVGPathSegCurvetoQuadraticSmoothAbs.h" +#include "V8SVGPathSegCurvetoQuadraticSmoothRel.h" +#include "V8SVGPathSegLinetoAbs.h" +#include "V8SVGPathSegLinetoHorizontalAbs.h" +#include "V8SVGPathSegLinetoHorizontalRel.h" +#include "V8SVGPathSegLinetoRel.h" +#include "V8SVGPathSegLinetoVerticalAbs.h" +#include "V8SVGPathSegLinetoVerticalRel.h" +#include "V8SVGPathSegList.h" +#include "V8SVGPathSegMovetoAbs.h" +#include "V8SVGPathSegMovetoRel.h" +#include "V8SVGPoint.h" +#include "V8SVGPointList.h" +#include "V8SVGPreserveAspectRatio.h" +#include "V8SVGRect.h" +#include "V8SVGRenderingIntent.h" +#include "V8SVGStringList.h" +#include "V8SVGTransform.h" +#include "V8SVGTransformList.h" +#include "V8SVGUnitTypes.h" +#include "V8SVGURIReference.h" +#include "V8SVGZoomEvent.h" +#endif + +#if ENABLE(VIDEO) +#include "V8HTMLAudioElement.h" +#include "V8HTMLMediaElement.h" +#include "V8HTMLSourceElement.h" +#include "V8HTMLVideoElement.h" +#include "V8MediaError.h" +#include "V8TimeRanges.h" +#endif + +#if ENABLE(WORKERS) +#include "V8Worker.h" +#include "V8WorkerContext.h" +#include "V8WorkerLocation.h" +#include "V8WorkerNavigator.h" +#endif + +#if PLATFORM(ANDROID) +#include "V8Coordinates.h" +#include "V8Geolocation.h" +#include "V8Geoposition.h" +#include "V8PositionError.h" +#include "V8PositionErrorCallback.h" +#include "V8Touch.h" +#include "V8TouchList.h" +#include "V8TouchEvent.h" +#include "V8VoidCallback.h" +#endif + +#if ENABLE(OFFLINE_WEB_APPLICATIONS) +#include "V8DOMApplicationCache.h" +#endif + +namespace WebCore { + +FunctionTemplateFactory V8ClassIndex::GetFactory(V8WrapperType type) { + switch (type) { +#define MAKE_CASE(type, name)\ + case V8ClassIndex::type: return V8##name::GetTemplate; + WRAPPER_TYPES(MAKE_CASE) +#undef MAKE_CASE + default: return NULL; + } +} + + +#define MAKE_CACHE(type, name)\ + static v8::Persistent<v8::FunctionTemplate> name##_cache_; + ALL_WRAPPER_TYPES(MAKE_CACHE) +#undef MAKE_CACHE + + +v8::Persistent<v8::FunctionTemplate>* V8ClassIndex::GetCache( + V8WrapperType type) { + switch (type) { +#define MAKE_CASE(type, name)\ + case V8ClassIndex::type: return &name##_cache_; + ALL_WRAPPER_TYPES(MAKE_CASE) +#undef MAKE_CASE + default: + ASSERT(false); + return NULL; + } +} + +} // namespace WebCore diff --git a/V8Binding/binding/v8_index.h b/V8Binding/binding/v8_index.h new file mode 100644 index 0000000..71453c3 --- /dev/null +++ b/V8Binding/binding/v8_index.h @@ -0,0 +1,523 @@ +// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef V8_INDEX_H__ +#define V8_INDEX_H__ + +#include <v8.h> +#include "PlatformString.h" // for WebCore::String + +namespace WebCore { + +typedef v8::Persistent<v8::FunctionTemplate> (*FunctionTemplateFactory)(); + +#if ENABLE(VIDEO) +#define VIDEO_HTMLELEMENT_TYPES(V) \ + V(HTMLAUDIOELEMENT, HTMLAudioElement) \ + V(HTMLMEDIAELEMENT, HTMLMediaElement) \ + V(HTMLSOURCEELEMENT, HTMLSourceElement) \ + V(HTMLVIDEOELEMENT, HTMLVideoElement) +#define VIDEO_NONNODE_TYPES(V) \ + V(MEDIAERROR, MediaError) \ + V(TIMERANGES, TimeRanges) +#else +#define VIDEO_HTMLELEMENT_TYPES(V) +#define VIDEO_NONNODE_TYPES(V) +#endif + +#if ENABLE(WORKERS) +#define WORKER_ACTIVE_OBJECT_WRAPPER_TYPES(V) \ + V(WORKER, Worker) + +#define WORKER_NONNODE_WRAPPER_TYPES(V) \ + V(WORKERCONTEXT, WorkerContext) \ + V(WORKERLOCATION, WorkerLocation) \ + V(WORKERNAVIGATOR, WorkerNavigator) +#else +#define WORKER_ACTIVE_OBJECT_WRAPPER_TYPES(V) +#define WORKER_NONNODE_WRAPPER_TYPES(V) +#endif + +#if ENABLE(OFFLINE_WEB_APPLICATIONS) +#define APPLICATIONCACHE_NONNODE_WRAPPER_TYPES(V) \ + V(DOMAPPLICATIONCACHE, DOMApplicationCache) +#else +#define APPLICATIONCACHE_NONNODE_WRAPPER_TYPES(V) +#endif + +#define DOM_NODE_TYPES(V) \ + V(ATTR, Attr) \ + V(CHARACTERDATA, CharacterData) \ + V(CDATASECTION, CDATASection) \ + V(COMMENT, Comment) \ + V(DOCUMENT, Document) \ + V(DOCUMENTFRAGMENT, DocumentFragment) \ + V(DOCUMENTTYPE, DocumentType) \ + V(ELEMENT, Element) \ + V(ENTITY, Entity) \ + V(ENTITYREFERENCE, EntityReference) \ + V(HTMLDOCUMENT, HTMLDocument) \ + V(NODE, Node) \ + V(NOTATION, Notation) \ + V(PROCESSINGINSTRUCTION, ProcessingInstruction) \ + V(TEXT, Text) \ + \ + V(HTMLANCHORELEMENT, HTMLAnchorElement) \ + V(HTMLAPPLETELEMENT, HTMLAppletElement) \ + V(HTMLAREAELEMENT, HTMLAreaElement) \ + V(HTMLBASEELEMENT, HTMLBaseElement) \ + V(HTMLBASEFONTELEMENT, HTMLBaseFontElement) \ + V(HTMLBLOCKQUOTEELEMENT, HTMLBlockquoteElement) \ + V(HTMLBODYELEMENT, HTMLBodyElement) \ + V(HTMLBRELEMENT, HTMLBRElement) \ + V(HTMLBUTTONELEMENT, HTMLButtonElement) \ + V(HTMLCANVASELEMENT, HTMLCanvasElement) \ + V(HTMLDIRECTORYELEMENT, HTMLDirectoryElement) \ + V(HTMLDIVELEMENT, HTMLDivElement) \ + V(HTMLDLISTELEMENT, HTMLDListElement) \ + V(HTMLEMBEDELEMENT, HTMLEmbedElement) \ + V(HTMLFIELDSETELEMENT, HTMLFieldSetElement) \ + V(HTMLFONTELEMENT, HTMLFontElement) \ + V(HTMLFORMELEMENT, HTMLFormElement) \ + V(HTMLFRAMEELEMENT, HTMLFrameElement) \ + V(HTMLFRAMESETELEMENT, HTMLFrameSetElement) \ + V(HTMLHEADINGELEMENT, HTMLHeadingElement) \ + V(HTMLHEADELEMENT, HTMLHeadElement) \ + V(HTMLHRELEMENT, HTMLHRElement) \ + V(HTMLHTMLELEMENT, HTMLHtmlElement) \ + V(HTMLIFRAMEELEMENT, HTMLIFrameElement) \ + V(HTMLIMAGEELEMENT, HTMLImageElement) \ + V(HTMLINPUTELEMENT, HTMLInputElement) \ + V(HTMLISINDEXELEMENT, HTMLIsIndexElement) \ + V(HTMLLABELELEMENT, HTMLLabelElement) \ + V(HTMLLEGENDELEMENT, HTMLLegendElement) \ + V(HTMLLIELEMENT, HTMLLIElement) \ + V(HTMLLINKELEMENT, HTMLLinkElement) \ + V(HTMLMAPELEMENT, HTMLMapElement) \ + V(HTMLMARQUEEELEMENT, HTMLMarqueeElement) \ + V(HTMLMENUELEMENT, HTMLMenuElement) \ + V(HTMLMETAELEMENT, HTMLMetaElement) \ + V(HTMLMODELEMENT, HTMLModElement) \ + V(HTMLOBJECTELEMENT, HTMLObjectElement) \ + V(HTMLOLISTELEMENT, HTMLOListElement) \ + V(HTMLOPTGROUPELEMENT, HTMLOptGroupElement) \ + V(HTMLOPTIONELEMENT, HTMLOptionElement) \ + V(HTMLPARAGRAPHELEMENT, HTMLParagraphElement) \ + V(HTMLPARAMELEMENT, HTMLParamElement) \ + V(HTMLPREELEMENT, HTMLPreElement) \ + V(HTMLQUOTEELEMENT, HTMLQuoteElement) \ + V(HTMLSCRIPTELEMENT, HTMLScriptElement) \ + V(HTMLSELECTELEMENT, HTMLSelectElement) \ + V(HTMLSTYLEELEMENT, HTMLStyleElement) \ + V(HTMLTABLECAPTIONELEMENT, HTMLTableCaptionElement) \ + V(HTMLTABLECOLELEMENT, HTMLTableColElement) \ + V(HTMLTABLEELEMENT, HTMLTableElement) \ + V(HTMLTABLESECTIONELEMENT, HTMLTableSectionElement) \ + V(HTMLTABLECELLELEMENT, HTMLTableCellElement) \ + V(HTMLTABLEROWELEMENT, HTMLTableRowElement) \ + V(HTMLTEXTAREAELEMENT, HTMLTextAreaElement) \ + V(HTMLTITLEELEMENT, HTMLTitleElement) \ + V(HTMLULISTELEMENT, HTMLUListElement) \ + V(HTMLELEMENT, HTMLElement) \ + VIDEO_HTMLELEMENT_TYPES(V) + +#if ENABLE(SVG_ANIMATION) +#define SVG_ANIMATION_ELEMENT_TYPES(V) \ + V(SVGANIMATECOLORELEMENT, SVGAnimateColorElement) \ + V(SVGANIMATEELEMENT, SVGAnimateElement) \ + V(SVGANIMATETRANSFORMELEMENT, SVGAnimateTransformElement) \ + V(SVGANIMATIONELEMENT, SVGAnimationElement) \ + V(SVGSETELEMENT, SVGSetElement) +#else +#define SVG_ANIMATION_ELEMENT_TYPES(V) +#endif + +#if ENABLE(SVG_FILTERS) +#define SVG_FILTERS_ELEMENT_TYPES(V) \ + V(SVGCOMPONENTTRANSFERFUNCTIONELEMENT, SVGComponentTransferFunctionElement)\ + V(SVGFEBLENDELEMENT, SVGFEBlendElement) \ + V(SVGFECOLORMATRIXELEMENT, SVGFEColorMatrixElement) \ + V(SVGFECOMPONENTTRANSFERELEMENT, SVGFEComponentTransferElement) \ + V(SVGFECOMPOSITEELEMENT, SVGFECompositeElement) \ + V(SVGFEDIFFUSELIGHTINGELEMENT, SVGFEDiffuseLightingElement) \ + V(SVGFEDISPLACEMENTMAPELEMENT, SVGFEDisplacementMapElement) \ + V(SVGFEDISTANTLIGHTELEMENT, SVGFEDistantLightElement) \ + V(SVGFEFLOODELEMENT, SVGFEFloodElement) \ + V(SVGFEFUNCAELEMENT, SVGFEFuncAElement) \ + V(SVGFEFUNCBELEMENT, SVGFEFuncBElement) \ + V(SVGFEFUNCGELEMENT, SVGFEFuncGElement) \ + V(SVGFEFUNCRELEMENT, SVGFEFuncRElement) \ + V(SVGFEGAUSSIANBLURELEMENT, SVGFEGaussianBlurElement) \ + V(SVGFEIMAGEELEMENT, SVGFEImageElement) \ + V(SVGFEMERGEELEMENT, SVGFEMergeElement) \ + V(SVGFEMERGENODEELEMENT, SVGFEMergeNodeElement) \ + V(SVGFEOFFSETELEMENT, SVGFEOffsetElement) \ + V(SVGFEPOINTLIGHTELEMENT, SVGFEPointLightElement) \ + V(SVGFESPECULARLIGHTINGELEMENT, SVGFESpecularLightingElement) \ + V(SVGFESPOTLIGHTELEMENT, SVGFESpotLightElement) \ + V(SVGFETILEELEMENT, SVGFETileElement) \ + V(SVGFETURBULENCEELEMENT, SVGFETurbulenceElement) \ + V(SVGFILTERELEMENT, SVGFilterElement) +#else +#define SVG_FILTERS_ELEMENT_TYPES(V) +#endif + +#if ENABLE(SVG_FONTS) +#define SVG_FONTS_ELEMENT_TYPES(V) \ + V(SVGDEFINITIONSRCELEMENT, SVGDefinitionSrcElement) \ + V(SVGFONTFACEELEMENT, SVGFontFaceElement) \ + V(SVGFONTFACEFORMATELEMENT, SVGFontFaceFormatElement) \ + V(SVGFONTFACENAMEELEMENT, SVGFontFaceNameElement) \ + V(SVGFONTFACESRCELEMENT, SVGFontFaceSrcElement) \ + V(SVGFONTFACEURIELEMENT, SVGFontFaceUriElement) +#else +#define SVG_FONTS_ELEMENT_TYPES(V) +#endif + +#if ENABLE(SVG_FOREIGN_OBJECT) +#define SVG_FOREIGN_OBJECT_ELEMENT_TYPES(V) \ + V(SVGFOREIGNOBJECTELEMENT, SVGForeignObjectElement) +#else +#define SVG_FOREIGN_OBJECT_ELEMENT_TYPES(V) +#endif + +#if ENABLE(SVG_USE) +#define SVG_USE_ELEMENT_TYPES(V) \ + V(SVGUSEELEMENT, SVGUseElement) +#else +#define SVG_USE_ELEMENT_TYPES(V) +#endif + +#if ENABLE(SVG) +#define SVG_NODE_TYPES(V) \ + SVG_ANIMATION_ELEMENT_TYPES(V) \ + SVG_FILTERS_ELEMENT_TYPES(V) \ + SVG_FONTS_ELEMENT_TYPES(V) \ + SVG_FOREIGN_OBJECT_ELEMENT_TYPES(V) \ + SVG_USE_ELEMENT_TYPES(V) \ + V(SVGAELEMENT, SVGAElement) \ + V(SVGALTGLYPHELEMENT, SVGAltGlyphElement) \ + V(SVGCIRCLEELEMENT, SVGCircleElement) \ + V(SVGCLIPPATHELEMENT, SVGClipPathElement) \ + V(SVGCURSORELEMENT, SVGCursorElement) \ + V(SVGDEFSELEMENT, SVGDefsElement) \ + V(SVGDESCELEMENT, SVGDescElement) \ + V(SVGELLIPSEELEMENT, SVGEllipseElement) \ + V(SVGGELEMENT, SVGGElement) \ + V(SVGGLYPHELEMENT, SVGGlyphElement) \ + V(SVGGRADIENTELEMENT, SVGGradientElement) \ + V(SVGIMAGEELEMENT, SVGImageElement) \ + V(SVGLINEARGRADIENTELEMENT, SVGLinearGradientElement) \ + V(SVGLINEELEMENT, SVGLineElement) \ + V(SVGMARKERELEMENT, SVGMarkerElement) \ + V(SVGMASKELEMENT, SVGMaskElement) \ + V(SVGMETADATAELEMENT, SVGMetadataElement) \ + V(SVGPATHELEMENT, SVGPathElement) \ + V(SVGPATTERNELEMENT, SVGPatternElement) \ + V(SVGPOLYGONELEMENT, SVGPolygonElement) \ + V(SVGPOLYLINEELEMENT, SVGPolylineElement) \ + V(SVGRADIALGRADIENTELEMENT, SVGRadialGradientElement) \ + V(SVGRECTELEMENT, SVGRectElement) \ + V(SVGSCRIPTELEMENT, SVGScriptElement) \ + V(SVGSTOPELEMENT, SVGStopElement) \ + V(SVGSTYLEELEMENT, SVGStyleElement) \ + V(SVGSVGELEMENT, SVGSVGElement) \ + V(SVGSWITCHELEMENT, SVGSwitchElement) \ + V(SVGSYMBOLELEMENT, SVGSymbolElement) \ + V(SVGTEXTCONTENTELEMENT, SVGTextContentElement) \ + V(SVGTEXTELEMENT, SVGTextElement) \ + V(SVGTEXTPATHELEMENT, SVGTextPathElement) \ + V(SVGTEXTPOSITIONINGELEMENT, SVGTextPositioningElement) \ + V(SVGTITLEELEMENT, SVGTitleElement) \ + V(SVGTREFELEMENT, SVGTRefElement) \ + V(SVGTSPANELEMENT, SVGTSpanElement) \ + V(SVGVIEWELEMENT, SVGViewElement) \ + V(SVGELEMENT, SVGElement) \ + \ + V(SVGDOCUMENT, SVGDocument) +#endif // SVG + + +// ACTIVE_DOM_OBJECT_TYPES are DOM_OBJECT_TYPES that need special treatement +// during GC. +#define ACTIVE_DOM_OBJECT_TYPES(V) \ + V(MESSAGEPORT, MessagePort) \ + V(XMLHTTPREQUEST, XMLHttpRequest) \ + WORKER_ACTIVE_OBJECT_WRAPPER_TYPES(V) + +// NOTE: DOM_OBJECT_TYPES is split into two halves because +// Visual Studio's Intellinonsense crashes when macros get +// too large. 10-29-08 +// DOM_OBJECT_TYPES are non-node DOM types. +#define DOM_OBJECT_TYPES_1(V) \ + V(BARINFO, BarInfo) \ + V(CANVASGRADIENT, CanvasGradient) \ + V(CANVASPATTERN, CanvasPattern) \ + V(CANVASRENDERINGCONTEXT2D, CanvasRenderingContext2D) \ + V(CLIENTRECT, ClientRect) \ + V(CLIENTRECTLIST, ClientRectList) \ + V(CLIPBOARD, Clipboard) \ + V(CONSOLE, Console) \ + V(COUNTER, Counter) \ + V(CSSCHARSETRULE, CSSCharsetRule) \ + V(CSSFONTFACERULE, CSSFontFaceRule) \ + V(CSSIMPORTRULE, CSSImportRule) \ + V(CSSMEDIARULE, CSSMediaRule) \ + V(CSSPAGERULE, CSSPageRule) \ + V(CSSPRIMITIVEVALUE, CSSPrimitiveValue) \ + V(CSSRULE, CSSRule) \ + V(CSSRULELIST, CSSRuleList) \ + V(CSSSTYLEDECLARATION, CSSStyleDeclaration) \ + V(CSSSTYLERULE, CSSStyleRule) \ + V(CSSSTYLESHEET, CSSStyleSheet) \ + V(CSSVALUE, CSSValue) \ + V(CSSVALUELIST, CSSValueList) \ + V(CSSVARIABLESDECLARATION, CSSVariablesDeclaration) \ + V(CSSVARIABLESRULE, CSSVariablesRule) \ + V(DOMCOREEXCEPTION, DOMCoreException) \ + V(DOMIMPLEMENTATION, DOMImplementation) \ + V(DOMPARSER, DOMParser) \ + V(DOMSELECTION, DOMSelection) \ + V(DOMSTRINGLIST, DOMStringList) \ + V(DOMWINDOW, DOMWindow) \ + V(EVENT, Event) \ + V(EVENTEXCEPTION, EventException) \ + V(FILE, File) \ + V(FILELIST, FileList) \ + V(HISTORY, History) \ + V(UNDETECTABLEHTMLCOLLECTION, UndetectableHTMLCollection) \ + V(HTMLCOLLECTION, HTMLCollection) \ + V(HTMLOPTIONSCOLLECTION, HTMLOptionsCollection) \ + V(IMAGEDATA, ImageData) \ + V(CANVASPIXELARRAY, CanvasPixelArray) \ + V(KEYBOARDEVENT, KeyboardEvent) \ + V(LOCATION, Location) \ + V(MEDIALIST, MediaList) + +#define DOM_OBJECT_TYPES_2(V) \ + V(MESSAGECHANNEL, MessageChannel) \ + V(MESSAGEEVENT, MessageEvent) \ + V(MIMETYPE, MimeType) \ + V(MIMETYPEARRAY, MimeTypeArray) \ + V(MOUSEEVENT, MouseEvent) \ + V(MUTATIONEVENT, MutationEvent) \ + V(NAMEDNODEMAP, NamedNodeMap) \ + V(NAVIGATOR, Navigator) \ + V(NODEFILTER, NodeFilter) \ + V(NODEITERATOR, NodeIterator) \ + V(NODELIST, NodeList) \ + V(OVERFLOWEVENT, OverflowEvent) \ + V(PLUGIN, Plugin) \ + V(PLUGINARRAY, PluginArray) \ + V(PROGRESSEVENT, ProgressEvent) \ + V(RANGE, Range) \ + V(RANGEEXCEPTION, RangeException) \ + V(RECT, Rect) \ + V(RGBCOLOR, RGBColor) \ + V(SCREEN, Screen) \ + V(STYLESHEET, StyleSheet) \ + V(STYLESHEETLIST, StyleSheetList) \ + V(TEXTEVENT, TextEvent) \ + V(TEXTMETRICS, TextMetrics) \ + V(TREEWALKER, TreeWalker) \ + V(UIEVENT, UIEvent) \ + V(WEBKITANIMATIONEVENT, WebKitAnimationEvent) \ + V(WEBKITCSSKEYFRAMERULE, WebKitCSSKeyframeRule) \ + V(WEBKITCSSKEYFRAMESRULE, WebKitCSSKeyframesRule) \ + V(WEBKITCSSMATRIX, WebKitCSSMatrix) \ + V(WEBKITPOINT, WebKitPoint) \ + V(WEBKITCSSTRANSFORMVALUE, WebKitCSSTransformValue) \ + V(WEBKITTRANSITIONEVENT, WebKitTransitionEvent) \ + V(WHEELEVENT, WheelEvent) \ + V(XMLHTTPREQUESTUPLOAD, XMLHttpRequestUpload) \ + V(XMLHTTPREQUESTEXCEPTION, XMLHttpRequestException) \ + V(XMLHTTPREQUESTPROGRESSEVENT, XMLHttpRequestProgressEvent) \ + V(XMLSERIALIZER, XMLSerializer) \ + ACTIVE_DOM_OBJECT_TYPES(V) \ + APPLICATIONCACHE_NONNODE_WRAPPER_TYPES(V) \ + VIDEO_NONNODE_TYPES(V) \ + WORKER_NONNODE_WRAPPER_TYPES(V) + +#define DOM_OBJECT_XPATH_TYPES(V) \ + V(XPATHEVALUATOR, XPathEvaluator) \ + V(XPATHEXCEPTION, XPathException) \ + V(XPATHEXPRESSION, XPathExpression) \ + V(XPATHNSRESOLVER, XPathNSResolver) \ + V(XPATHRESULT, XPathResult) + +#if ENABLE(DATABASE) +#define DOM_OBJECT_DATABASE_TYPES(V) \ + V(DATABASE, Database) \ + V(SQLERROR, SQLError) \ + V(SQLRESULTSET, SQLResultSet) \ + V(SQLRESULTSETROWLIST, SQLResultSetRowList) \ + V(SQLTRANSACTION, SQLTransaction) +#else +#define DOM_OBJECT_DATABASE_TYPES(V) +#endif + +#if PLATFORM(CHROMIUM) +#define DOM_OBJECT_TYPES(V) \ + DOM_OBJECT_TYPES_1(V) \ + DOM_OBJECT_TYPES_2(V) \ + DOM_OBJECT_DATABASE_TYPES(V) \ + DOM_OBJECT_XPATH_TYPES(V) \ + V(XSLTPROCESSOR, XSLTProcessor) \ + V(INSPECTORCONTROLLER, InspectorController) +#endif + +#if PLATFORM(ANDROID) +#define DOM_OBJECT_TYPES(V) \ + DOM_OBJECT_TYPES_1(V) \ + DOM_OBJECT_TYPES_2(V) \ + DOM_OBJECT_DATABASE_TYPES(V) \ + V(COORDINATES, Coordinates) \ + V(GEOLOCATION, Geolocation) \ + V(GEOPOSITION, Geoposition) \ + V(POSITIONERROR, PositionError) \ + V(POSITIONERRORCALLBACK, PositionErrorCallback) \ + V(TOUCHLIST, TouchList) \ + V(TOUCHEVENT, TouchEvent) \ + V(TOUCH, Touch) \ + V(VOIDCALLBACK, VoidCallback) +#endif + +// Other platform must define DOM_OBJECT_TYPES + +#if ENABLE(SVG) +// SVG_OBJECT_TYPES are svg non-node, non-pod types. +#define SVG_OBJECT_TYPES(V) \ + V(SVGANGLE, SVGAngle) \ + V(SVGANIMATEDANGLE, SVGAnimatedAngle) \ + V(SVGANIMATEDBOOLEAN, SVGAnimatedBoolean) \ + V(SVGANIMATEDENUMERATION, SVGAnimatedEnumeration) \ + V(SVGANIMATEDINTEGER, SVGAnimatedInteger) \ + V(SVGANIMATEDLENGTH, SVGAnimatedLength) \ + V(SVGANIMATEDLENGTHLIST, SVGAnimatedLengthList) \ + V(SVGANIMATEDNUMBER, SVGAnimatedNumber) \ + V(SVGANIMATEDNUMBERLIST, SVGAnimatedNumberList) \ + V(SVGANIMATEDPRESERVEASPECTRATIO, SVGAnimatedPreserveAspectRatio) \ + V(SVGANIMATEDRECT, SVGAnimatedRect) \ + V(SVGANIMATEDSTRING, SVGAnimatedString) \ + V(SVGANIMATEDTRANSFORMLIST, SVGAnimatedTransformList) \ + V(SVGCOLOR, SVGColor) \ + V(SVGELEMENTINSTANCE, SVGElementInstance) \ + V(SVGELEMENTINSTANCELIST, SVGElementInstanceList) \ + V(SVGEXCEPTION, SVGException) \ + V(SVGLENGTHLIST, SVGLengthList) \ + V(SVGNUMBERLIST, SVGNumberList) \ + V(SVGPAINT, SVGPaint) \ + V(SVGPATHSEG, SVGPathSeg) \ + V(SVGPATHSEGARCABS, SVGPathSegArcAbs) \ + V(SVGPATHSEGARCREL, SVGPathSegArcRel) \ + V(SVGPATHSEGCLOSEPATH, SVGPathSegClosePath) \ + V(SVGPATHSEGCURVETOCUBICABS, SVGPathSegCurvetoCubicAbs) \ + V(SVGPATHSEGCURVETOCUBICREL, SVGPathSegCurvetoCubicRel) \ + V(SVGPATHSEGCURVETOCUBICSMOOTHABS, SVGPathSegCurvetoCubicSmoothAbs) \ + V(SVGPATHSEGCURVETOCUBICSMOOTHREL, SVGPathSegCurvetoCubicSmoothRel) \ + V(SVGPATHSEGCURVETOQUADRATICABS, SVGPathSegCurvetoQuadraticAbs) \ + V(SVGPATHSEGCURVETOQUADRATICREL, SVGPathSegCurvetoQuadraticRel) \ + V(SVGPATHSEGCURVETOQUADRATICSMOOTHABS, SVGPathSegCurvetoQuadraticSmoothAbs)\ + V(SVGPATHSEGCURVETOQUADRATICSMOOTHREL, SVGPathSegCurvetoQuadraticSmoothRel)\ + V(SVGPATHSEGLINETOABS, SVGPathSegLinetoAbs) \ + V(SVGPATHSEGLINETOHORIZONTALABS, SVGPathSegLinetoHorizontalAbs) \ + V(SVGPATHSEGLINETOHORIZONTALREL, SVGPathSegLinetoHorizontalRel) \ + V(SVGPATHSEGLINETOREL, SVGPathSegLinetoRel) \ + V(SVGPATHSEGLINETOVERTICALABS, SVGPathSegLinetoVerticalAbs) \ + V(SVGPATHSEGLINETOVERTICALREL, SVGPathSegLinetoVerticalRel) \ + V(SVGPATHSEGLIST, SVGPathSegList) \ + V(SVGPATHSEGMOVETOABS, SVGPathSegMovetoAbs) \ + V(SVGPATHSEGMOVETOREL, SVGPathSegMovetoRel) \ + V(SVGPOINTLIST, SVGPointList) \ + V(SVGPRESERVEASPECTRATIO, SVGPreserveAspectRatio) \ + V(SVGRENDERINGINTENT, SVGRenderingIntent) \ + V(SVGSTRINGLIST, SVGStringList) \ + V(SVGTRANSFORMLIST, SVGTransformList) \ + V(SVGUNITTYPES, SVGUnitTypes) \ + V(SVGZOOMEVENT, SVGZoomEvent) + +// SVG POD types should list all types whose IDL has PODType declaration. +#define SVG_POD_TYPES(V) \ + V(SVGLENGTH, SVGLength) \ + V(SVGTRANSFORM, SVGTransform) \ + V(SVGMATRIX, SVGMatrix) \ + V(SVGNUMBER, SVGNumber) \ + V(SVGPOINT, SVGPoint) \ + V(SVGRECT, SVGRect) + +// POD types can have different implementation names, see CodeGenerateV8.pm. +#define SVG_POD_NATIVE_TYPES(V) \ + V(SVGLENGTH, SVGLength) \ + V(SVGTRANSFORM, SVGTransform) \ + V(SVGMATRIX, TransformationMatrix) \ + V(SVGNUMBER, float) \ + V(SVGPOINT, FloatPoint) \ + V(SVGRECT, FloatRect) + +// Shouldn't generate code for these two types. +#define SVG_NO_WRAPPER_TYPES(V) \ + V(SVGURIREFERENCE, SVGURIReference) \ + V(SVGANIMATEDPOINTS, SVGAnimatedPoints) + +// SVG_NONNODE_TYPES are SVG non-node object types, pod typs and +// numerical types. +#define SVG_NONNODE_TYPES(V) \ + SVG_OBJECT_TYPES(V) \ + SVG_POD_TYPES(V) +#endif // SVG + +// EVENTTARGET, EVENTLISTENER, and NPOBJECT do not have V8 wrappers. +#define DOM_NO_WRAPPER_TYPES(V) \ + V(EVENTTARGET, EventTarget) \ + V(EVENTLISTENER, EventListener) \ + V(NPOBJECT, NPObject) + +#if ENABLE(SVG) +#define WRAPPER_TYPES(V) \ + DOM_NODE_TYPES(V) \ + DOM_OBJECT_TYPES(V) \ + SVG_NODE_TYPES(V) \ + SVG_NONNODE_TYPES(V) +#define NO_WRAPPER_TYPES(V) \ + DOM_NO_WRAPPER_TYPES(V) \ + SVG_NO_WRAPPER_TYPES(V) +#else // SVG +#define WRAPPER_TYPES(V) \ + DOM_NODE_TYPES(V) \ + DOM_OBJECT_TYPES(V) +#define NO_WRAPPER_TYPES(V) \ + DOM_NO_WRAPPER_TYPES(V) +#endif // SVG + +#define ALL_WRAPPER_TYPES(V) \ + WRAPPER_TYPES(V) \ + NO_WRAPPER_TYPES(V) + +class V8ClassIndex { + public: + // Type must start at non-negative numbers. See ToInt, FromInt. + enum V8WrapperType { + INVALID_CLASS_INDEX = 0, +#define DEFINE_ENUM(name, type) name, + ALL_WRAPPER_TYPES(DEFINE_ENUM) +#undef DEFINE_ENUM + CLASSINDEX_END, + WRAPPER_TYPE_COUNT = CLASSINDEX_END + }; + + static int ToInt(V8WrapperType type) { return static_cast<int>(type); } + + static V8WrapperType FromInt(int v) { + ASSERT(INVALID_CLASS_INDEX <= v && v < CLASSINDEX_END); + return static_cast<V8WrapperType>(v); + } + + static FunctionTemplateFactory GetFactory(V8WrapperType type); + // Returns a field to be used as cache for the template for the given type + static v8::Persistent<v8::FunctionTemplate>* GetCache(V8WrapperType type); +}; + +} + +#endif // V8_INDEX_H__ diff --git a/V8Binding/binding/v8_npobject.h b/V8Binding/binding/v8_npobject.h new file mode 100644 index 0000000..c2d8550 --- /dev/null +++ b/V8Binding/binding/v8_npobject.h @@ -0,0 +1,7 @@ +// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// This is a temporary file until V8HTMLPlugInElementCustom.cpp in WebKit +// includes the new name of this file. +#include "V8NPObject.h" diff --git a/V8Binding/binding/v8_proxy.cpp b/V8Binding/binding/v8_proxy.cpp new file mode 100644 index 0000000..45b56d7 --- /dev/null +++ b/V8Binding/binding/v8_proxy.cpp @@ -0,0 +1,3408 @@ +// Copyright (c) 2008, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#include "config.h" + +#include <algorithm> +#include <utility> + +#include <v8.h> + +#ifdef ENABLE_DEBUGGER_SUPPORT +#include <v8-debug.h> +#endif + +#include "v8_proxy.h" +#include "v8_index.h" +#include "v8_binding.h" +#include "v8_custom.h" +#include "V8Collection.h" +#include "V8DOMWindow.h" + +#if PLATFORM(CHROMIUM) +#include "ChromiumBridge.h" +#endif + +#include "DOMObjectsInclude.h" + +#include "ScriptController.h" +#include "V8DOMMap.h" + +#include "CString.h" + +namespace WebCore { + +V8EventListenerList::V8EventListenerList(const char* name) +{ + ASSERT(strlen(name) <= kMaxKeyNameLength); + v8::HandleScope handleScope; + + // Write the name into a temporary buffer, leaving 1 space at the beginning + // for a prefix we'll vary between the inline and non-inline keys. + char keyBuffer[kMaxKeyNameLength + 2] = { 0 }; + strncpy(keyBuffer + 1, name, kMaxKeyNameLength); + keyBuffer[0] = '1'; + m_inlineKey = v8::Persistent<v8::String>::New(v8::String::New(keyBuffer)); + keyBuffer[0] = '2'; + m_nonInlineKey = v8::Persistent<v8::String>::New(v8::String::New(keyBuffer)); +} + +V8EventListenerList::~V8EventListenerList() +{ + m_inlineKey.Dispose(); + m_nonInlineKey.Dispose(); +} + +V8EventListenerList::iterator V8EventListenerList::begin() +{ + return m_list.begin(); +} + +V8EventListenerList::iterator V8EventListenerList::end() +{ + return m_list.end(); +} + +v8::Handle<v8::String> V8EventListenerList::getKey(bool isInline) +{ + if (isInline) + return m_inlineKey; + else + return m_nonInlineKey; +} + +// See comment in .h file for this function, and update accordingly if +// implementation details change here. +void V8EventListenerList::add(V8EventListener* listener) +{ + m_list.append(listener); + + v8::HandleScope handleScope; + v8::Local<v8::Object> object = listener->getListenerObject(); + v8::Local<v8::Value> value = v8::External::Wrap(listener); + object->SetHiddenValue(getKey(listener->isInline()), value); +} + +void V8EventListenerList::remove(V8EventListener* listener) +{ + v8::HandleScope handleScope; + for (size_t i = 0; i < m_list.size(); i++) { + V8EventListener* element = m_list.at(i); + if (element->isInline() == listener->isInline() && element == listener) { + v8::Local<v8::Object> object = listener->getListenerObject(); + object->DeleteHiddenValue(getKey(listener->isInline())); + m_list.remove(i); + break; + } + } +} + +void V8EventListenerList::clear() +{ + v8::HandleScope handleScope; + for (size_t i = 0; i < m_list.size(); i++) { + V8EventListener* element = m_list.at(i); + v8::Local<v8::Object> object = element->getListenerObject(); + object->DeleteHiddenValue(getKey(element->isInline())); + } + m_list.clear(); +} + +V8EventListener* V8EventListenerList::find(v8::Local<v8::Object> object, bool isInline) +{ + v8::Local<v8::Value> value = object->GetHiddenValue(getKey(isInline)); + if (value.IsEmpty()) + return 0; + return reinterpret_cast<V8EventListener*>(v8::External::Unwrap(value)); +} + + +// Static utility context. +v8::Persistent<v8::Context> V8Proxy::m_utilityContext; + +// Static list of registered extensions +V8ExtensionList V8Proxy::m_extensions; + + +#ifndef NDEBUG +// Keeps track of global handles created (not JS wrappers +// of DOM objects). Often these global handles are source +// of leaks. +// +// If you want to let a C++ object hold a persistent handle +// to a JS object, you should register the handle here to +// keep track of leaks. +// +// When creating a persistent handle, call: +// +// #ifndef NDEBUG +// V8Proxy::RegisterGlobalHandle(type, host, handle); +// #endif +// +// When releasing the handle, call: +// +// #ifndef NDEBUG +// V8Proxy::UnregisterGlobalHandle(type, host, handle); +// #endif +// +typedef HashMap<v8::Value*, GlobalHandleInfo*> GlobalHandleMap; + +static GlobalHandleMap& global_handle_map() +{ + static GlobalHandleMap static_global_handle_map; + return static_global_handle_map; +} + + +// The USE_VAR(x) template is used to silence C++ compiler warnings +// issued for unused variables (typically parameters or values that +// we want to watch in the debugger). +template <typename T> +static inline void USE_VAR(T) { } + +// The function is the place to set the break point to inspect +// live global handles. Leaks are often come from leaked global handles. +static void EnumerateGlobalHandles() +{ + for (GlobalHandleMap::iterator it = global_handle_map().begin(), + end = global_handle_map().end(); it != end; ++it) { + GlobalHandleInfo* info = it->second; + USE_VAR(info); + v8::Value* handle = it->first; + USE_VAR(handle); + } +} + +void V8Proxy::RegisterGlobalHandle(GlobalHandleType type, void* host, + v8::Persistent<v8::Value> handle) +{ + ASSERT(!global_handle_map().contains(*handle)); + global_handle_map().set(*handle, new GlobalHandleInfo(host, type)); +} + + +void V8Proxy::UnregisterGlobalHandle(void* host, v8::Persistent<v8::Value> handle) +{ + ASSERT(global_handle_map().contains(*handle)); + GlobalHandleInfo* info = global_handle_map().take(*handle); + ASSERT(info->host_ == host); + delete info; +} +#endif // ifndef NDEBUG + +void BatchConfigureAttributes(v8::Handle<v8::ObjectTemplate> inst, + v8::Handle<v8::ObjectTemplate> proto, + const BatchedAttribute* attrs, + size_t num_attrs) +{ + for (size_t i = 0; i < num_attrs; ++i) { + const BatchedAttribute* a = &attrs[i]; + (a->on_proto ? proto : inst)->SetAccessor( + v8::String::New(a->name), + a->getter, + a->setter, + a->data == V8ClassIndex::INVALID_CLASS_INDEX + ? v8::Handle<v8::Value>() + : v8::Integer::New(V8ClassIndex::ToInt(a->data)), + a->settings, + a->attribute); + } +} + +void BatchConfigureConstants(v8::Handle<v8::FunctionTemplate> desc, + v8::Handle<v8::ObjectTemplate> proto, + const BatchedConstant* consts, + size_t num_consts) +{ + for (size_t i = 0; i < num_consts; ++i) { + const BatchedConstant* c = &consts[i]; + desc->Set(v8::String::New(c->name), + v8::Integer::New(c->value), + v8::ReadOnly); + proto->Set(v8::String::New(c->name), + v8::Integer::New(c->value), + v8::ReadOnly); + } +} + +typedef HashMap<Node*, v8::Object*> DOMNodeMap; +typedef HashMap<void*, v8::Object*> DOMObjectMap; + +#ifndef NDEBUG +static void EnumerateDOMObjectMap(DOMObjectMap& wrapper_map) +{ + for (DOMObjectMap::iterator it = wrapper_map.begin(), end = wrapper_map.end(); + it != end; ++it) { + v8::Persistent<v8::Object> wrapper(it->second); + V8ClassIndex::V8WrapperType type = V8Proxy::GetDOMWrapperType(wrapper); + void* obj = it->first; + USE_VAR(type); + USE_VAR(obj); + } +} + + +static void EnumerateDOMNodeMap(DOMNodeMap& node_map) +{ + for (DOMNodeMap::iterator it = node_map.begin(), end = node_map.end(); + it != end; ++it) { + Node* node = it->first; + USE_VAR(node); + ASSERT(v8::Persistent<v8::Object>(it->second).IsWeak()); + } +} +#endif // NDEBUG + +#if ENABLE(SVG) +v8::Handle<v8::Value> V8Proxy::SVGElementInstanceToV8Object( + SVGElementInstance* instance) +{ + if (!instance) + return v8::Null(); + + v8::Handle<v8::Object> existing_instance = getDOMSVGElementInstanceMap().get(instance); + if (!existing_instance.IsEmpty()) + return existing_instance; + + instance->ref(); + + // Instantiate the V8 object and remember it + v8::Handle<v8::Object> result = + InstantiateV8Object(V8ClassIndex::SVGELEMENTINSTANCE, + V8ClassIndex::SVGELEMENTINSTANCE, + instance); + if (!result.IsEmpty()) { + // Only update the DOM SVG element map if the result is non-empty. + getDOMSVGElementInstanceMap().set(instance, + v8::Persistent<v8::Object>::New(result)); + } + return result; +} + +// Map of SVG objects with contexts to their contexts +static HashMap<void*, SVGElement*>& svg_object_to_context_map() +{ + static HashMap<void*, SVGElement*> static_svg_object_to_context_map; + return static_svg_object_to_context_map; +} + +v8::Handle<v8::Value> V8Proxy::SVGObjectWithContextToV8Object( + V8ClassIndex::V8WrapperType type, void* object) +{ + if (!object) + return v8::Null(); + + v8::Persistent<v8::Object> result = + getDOMSVGObjectWithContextMap().get(object); + if (!result.IsEmpty()) return result; + + // Special case: SVGPathSegs need to be downcast to their real type + if (type == V8ClassIndex::SVGPATHSEG) + type = V8Custom::DowncastSVGPathSeg(object); + + v8::Local<v8::Object> v8obj = InstantiateV8Object(type, type, object); + if (!v8obj.IsEmpty()) { + result = v8::Persistent<v8::Object>::New(v8obj); + switch (type) { +#define MAKE_CASE(TYPE, NAME) \ + case V8ClassIndex::TYPE: static_cast<NAME*>(object)->ref(); break; +SVG_OBJECT_TYPES(MAKE_CASE) +#undef MAKE_CASE +#define MAKE_CASE(TYPE, NAME) \ + case V8ClassIndex::TYPE: \ + static_cast<V8SVGPODTypeWrapper<NAME>*>(object)->ref(); break; +SVG_POD_NATIVE_TYPES(MAKE_CASE) +#undef MAKE_CASE + default: + ASSERT(false); + } + getDOMSVGObjectWithContextMap().set(object, result); + } + + return result; +} + +void V8Proxy::SetSVGContext(void* obj, SVGElement* context) +{ + SVGElement* old_context = svg_object_to_context_map().get(obj); + + if (old_context == context) + return; + + if (old_context) + old_context->deref(); + + if (context) + context->ref(); + + svg_object_to_context_map().set(obj, context); +} + +SVGElement* V8Proxy::GetSVGContext(void* obj) +{ + return svg_object_to_context_map().get(obj); +} + +#endif + +// A map from a DOM node to its JS wrapper, the wrapper +// is kept as a strong reference to survive GCs. +static DOMObjectMap& gc_protected_map() { + static DOMObjectMap static_gc_protected_map; + return static_gc_protected_map; +} + +// static +void V8Proxy::GCProtect(void* dom_object) +{ + if (!dom_object) + return; + if (gc_protected_map().contains(dom_object)) + return; + if (!getDOMObjectMap().contains(dom_object)) + return; + + // Create a new (strong) persistent handle for the object. + v8::Persistent<v8::Object> wrapper = getDOMObjectMap().get(dom_object); + if (wrapper.IsEmpty()) return; + + gc_protected_map().set(dom_object, *v8::Persistent<v8::Object>::New(wrapper)); +} + + +// static +void V8Proxy::GCUnprotect(void* dom_object) +{ + if (!dom_object) + return; + if (!gc_protected_map().contains(dom_object)) + return; + + // Dispose the strong reference. + v8::Persistent<v8::Object> wrapper(gc_protected_map().take(dom_object)); + wrapper.Dispose(); +} + + +typedef std::pair<uintptr_t, Node*> GrouperPair; +typedef Vector<GrouperPair> GrouperList; + +#if PLATFORM(ANDROID) +// Sort GrouperPair by the group id. Node* is only involved to sort within +// a group id, so it will be fine. +static bool ComparePair(const GrouperPair& p1, const GrouperPair& p2) { + return p1.first < p2.first; +} +#endif + +// Create object groups for DOM tree nodes. +static void GCPrologue() +{ + v8::HandleScope scope; + +#ifndef NDEBUG + EnumerateDOMObjectMap(getDOMObjectMap().impl()); +#endif + + // Run through all objects with possible pending activity making their + // wrappers non weak if there is pending activity. + DOMObjectMap active_map = getActiveDOMObjectMap().impl(); + for (DOMObjectMap::iterator it = active_map.begin(), end = active_map.end(); + it != end; ++it) { + void* obj = it->first; + v8::Persistent<v8::Object> wrapper = v8::Persistent<v8::Object>(it->second); + ASSERT(wrapper.IsWeak()); + V8ClassIndex::V8WrapperType type = V8Proxy::GetDOMWrapperType(wrapper); + switch (type) { +#define MAKE_CASE(TYPE, NAME) \ + case V8ClassIndex::TYPE: { \ + NAME* impl = static_cast<NAME*>(obj); \ + if (impl->hasPendingActivity()) \ + wrapper.ClearWeak(); \ + break; \ + } +ACTIVE_DOM_OBJECT_TYPES(MAKE_CASE) + default: + ASSERT(false); +#undef MAKE_CASE + } + + // Additional handling of message port ensuring that entangled ports also + // have their wrappers entangled. This should ideally be handled when the + // ports are actually entangled in MessagePort::entangle, but to avoid + // forking MessagePort.* this is postponed to GC time. Having this postponed + // has the drawback that the wrappers are "entangled/unentangled" for each + // GC even though their entnaglement most likely is still the same. + if (type == V8ClassIndex::MESSAGEPORT) { + // Get the port and its entangled port. + MessagePort* port1 = static_cast<MessagePort*>(obj); + MessagePort* port2 = port1->entangledPort(); + if (port2 != NULL) { + // As ports are always entangled in pairs only perform the entanglement + // once for each pair (see ASSERT in MessagePort::unentangle()). + if (port1 < port2) { + v8::Handle<v8::Value> port1_wrapper = + V8Proxy::ToV8Object(V8ClassIndex::MESSAGEPORT, port1); + v8::Handle<v8::Value> port2_wrapper = + V8Proxy::ToV8Object(V8ClassIndex::MESSAGEPORT, port2); + ASSERT(port1_wrapper->IsObject()); + v8::Handle<v8::Object>::Cast(port1_wrapper)->SetInternalField( + V8Custom::kMessagePortEntangledPortIndex, port2_wrapper); + ASSERT(port2_wrapper->IsObject()); + v8::Handle<v8::Object>::Cast(port2_wrapper)->SetInternalField( + V8Custom::kMessagePortEntangledPortIndex, port1_wrapper); + } + } else { + // Remove the wrapper entanglement when a port is not entangled. + if (V8Proxy::DOMObjectHasJSWrapper(port1)) { + v8::Handle<v8::Value> wrapper = + V8Proxy::ToV8Object(V8ClassIndex::MESSAGEPORT, port1); + ASSERT(wrapper->IsObject()); + v8::Handle<v8::Object>::Cast(wrapper)->SetInternalField( + V8Custom::kMessagePortEntangledPortIndex, v8::Undefined()); + } + } + } + } + + // Create object groups. + DOMNodeMap node_map = getDOMNodeMap().impl(); + GrouperList grouper; + grouper.reserveCapacity(node_map.size()); + + for (DOMNodeMap::iterator it = node_map.begin(), end = node_map.end(); + it != end; ++it) { + Node* node = it->first; + + // If the node is in document, put it in the ownerDocument's object group. + // + // If an image element was created by JavaScript "new Image", + // it is not in a document. However, if the load event has not + // been fired (still onloading), it is treated as in the document. + // + // Otherwise, the node is put in an object group identified by the root + // elment of the tree to which it belongs. + uintptr_t group_id; + if (node->inDocument() || + (node->hasTagName(HTMLNames::imgTag) && + !static_cast<HTMLImageElement*>(node)->haveFiredLoadEvent())) { + group_id = reinterpret_cast<uintptr_t>(node->document()); + } else { + Node* root = node; + while (root->parent()) + root = root->parent(); + + // If the node is alone in its DOM tree (doesn't have a parent or any + // children) then the group will be filtered out later anyway. + if (root == node && !node->hasChildNodes()) + continue; + + group_id = reinterpret_cast<uintptr_t>(root); + } + grouper.append(GrouperPair(group_id, node)); + } + +#if PLATFORM(ANDROID) + std::stable_sort<GrouperPair>(grouper.begin(), grouper.end(), ComparePair); +#else + // Group by sorting by the group id. This will use the std::pair operator<, + // which will really sort by both the group id and the Node*. However the + // Node* is only involved to sort within a group id, so it will be fine. + std::sort(grouper.begin(), grouper.end()); +#endif + + // TODO(deanm): Should probably work in iterators here, but indexes were + // easier for my simple mind. + for (size_t i = 0; i < grouper.size(); ) { + // Seek to the next key (or the end of the list). + size_t next_key_index = grouper.size(); + for (size_t j = i; j < grouper.size(); ++j) { + if (grouper[i].first != grouper[j].first) { + next_key_index = j; + break; + } + } + + ASSERT(next_key_index > i); + + // We only care about a group if it has more than one object. If it only + // has one object, it has nothing else that needs to be kept alive. + if (next_key_index - i <= 1) { + i = next_key_index; + continue; + } + + Vector<v8::Persistent<v8::Value> > group; + group.reserveCapacity(next_key_index - i); + for (; i < next_key_index; ++i) { + v8::Persistent<v8::Value> wrapper = + getDOMNodeMap().get(grouper[i].second); + if (!wrapper.IsEmpty()) + group.append(wrapper); + } + + if (group.size() > 1) + v8::V8::AddObjectGroup(&group[0], group.size()); + + ASSERT(i == next_key_index); + } +} + + +static void GCEpilogue() +{ + v8::HandleScope scope; + + // Run through all objects with pending activity making their wrappers weak + // again. + DOMObjectMap active_map = getActiveDOMObjectMap().impl(); + for (DOMObjectMap::iterator it = active_map.begin(), end = active_map.end(); + it != end; ++it) { + void* obj = it->first; + v8::Persistent<v8::Object> wrapper = v8::Persistent<v8::Object>(it->second); + V8ClassIndex::V8WrapperType type = V8Proxy::GetDOMWrapperType(wrapper); + switch (type) { +#define MAKE_CASE(TYPE, NAME) \ + case V8ClassIndex::TYPE: { \ + NAME* impl = static_cast<NAME*>(obj); \ + if (impl->hasPendingActivity()) { \ + ASSERT(!wrapper.IsWeak()); \ + wrapper.MakeWeak(impl, &weakActiveDOMObjectCallback); \ + } \ + break; \ + } +ACTIVE_DOM_OBJECT_TYPES(MAKE_CASE) + default: + ASSERT(false); +#undef MAKE_CASE + } + } + +#ifndef NDEBUG + // Check all survivals are weak. + EnumerateDOMObjectMap(getDOMObjectMap().impl()); + EnumerateDOMNodeMap(getDOMNodeMap().impl()); + EnumerateDOMObjectMap(gc_protected_map()); + EnumerateGlobalHandles(); +#undef USE_VAR +#endif +} + + +typedef HashMap<int, v8::FunctionTemplate*> FunctionTemplateMap; + +bool AllowAllocation::m_current = false; + + +// JavaScriptConsoleMessages encapsulate everything needed to +// log messages originating from JavaScript to the Chrome console. +class JavaScriptConsoleMessage { + public: + JavaScriptConsoleMessage(const String& str, + const String& sourceID, + unsigned lineNumber) + : m_string(str) + , m_sourceID(sourceID) + , m_lineNumber(lineNumber) { } + + void AddToPage(Page* page) const; + + private: + const String m_string; + const String m_sourceID; + const unsigned m_lineNumber; +}; + +void JavaScriptConsoleMessage::AddToPage(Page* page) const +{ + ASSERT(page); + Console* console = page->mainFrame()->domWindow()->console(); + console->addMessage(JSMessageSource, ErrorMessageLevel, m_string, m_lineNumber, m_sourceID); +} + +// The ConsoleMessageManager handles all console messages that stem +// from JavaScript. It keeps a list of messages that have been delayed but +// it makes sure to add all messages to the console in the right order. +class ConsoleMessageManager { + public: + // Add a message to the console. May end up calling JavaScript code + // indirectly through the inspector so only call this function when + // it is safe to do allocations. + static void AddMessage(Page* page, const JavaScriptConsoleMessage& message); + + // Add a message to the console but delay the reporting until it + // is safe to do so: Either when we leave JavaScript execution or + // when adding other console messages. The primary purpose of this + // method is to avoid calling into V8 to handle console messages + // when the VM is in a state that does not support GCs or allocations. + // Delayed messages are always reported in the page corresponding + // to the active context. + static void AddDelayedMessage(const JavaScriptConsoleMessage& message); + + // Process any delayed messages. May end up calling JavaScript code + // indirectly through the inspector so only call this function when + // it is safe to do allocations. + static void ProcessDelayedMessages(); + + private: + // All delayed messages are stored in this vector. If the vector + // is NULL, there are no delayed messages. + static Vector<JavaScriptConsoleMessage>* m_delayed; +}; + + +Vector<JavaScriptConsoleMessage>* ConsoleMessageManager::m_delayed = NULL; + + +void ConsoleMessageManager::AddMessage( + Page* page, + const JavaScriptConsoleMessage& message) +{ + // Process any delayed messages to make sure that messages + // appear in the right order in the console. + ProcessDelayedMessages(); + message.AddToPage(page); +} + + +void ConsoleMessageManager::AddDelayedMessage(const JavaScriptConsoleMessage& message) +{ + if (!m_delayed) + // Allocate a vector for the delayed messages. Will be + // deallocated when the delayed messages are processed + // in ProcessDelayedMessages(). + m_delayed = new Vector<JavaScriptConsoleMessage>(); + m_delayed->append(message); +} + + +void ConsoleMessageManager::ProcessDelayedMessages() +{ + // If we have a delayed vector it cannot be empty. + if (!m_delayed) + return; + ASSERT(!m_delayed->isEmpty()); + + // Add the delayed messages to the page of the active + // context. If that for some bizarre reason does not + // exist, we clear the list of delayed messages to avoid + // posting messages. We still deallocate the vector. + Frame* frame = V8Proxy::retrieveActiveFrame(); + Page* page = NULL; + if (frame) + page = frame->page(); + if (!page) + m_delayed->clear(); + + // Iterate through all the delayed messages and add them + // to the console. + const int size = m_delayed->size(); + for (int i = 0; i < size; i++) { + m_delayed->at(i).AddToPage(page); + } + + // Deallocate the delayed vector. + delete m_delayed; + m_delayed = NULL; +} + + +// Convenience class for ensuring that delayed messages in the +// ConsoleMessageManager are processed quickly. +class ConsoleMessageScope { + public: + ConsoleMessageScope() { ConsoleMessageManager::ProcessDelayedMessages(); } + ~ConsoleMessageScope() { ConsoleMessageManager::ProcessDelayedMessages(); } +}; + +void log_info(Frame* frame, const String& msg, const String& url) +{ + Page* page = frame->page(); + if (!page) + return; + JavaScriptConsoleMessage message(msg, url, 0); + ConsoleMessageManager::AddMessage(page, message); +} + +static void HandleConsoleMessage(v8::Handle<v8::Message> message, + v8::Handle<v8::Value> data) +{ + // Use the frame where JavaScript is called from. + Frame* frame = V8Proxy::retrieveActiveFrame(); + if (!frame) + return; + + Page* page = frame->page(); + if (!page) + return; + + v8::Handle<v8::String> errorMessageString = message->Get(); + ASSERT(!errorMessageString.IsEmpty()); + String errorMessage = ToWebCoreString(errorMessageString); + + v8::Handle<v8::Value> resourceName = message->GetScriptResourceName(); + bool useURL = (resourceName.IsEmpty() || !resourceName->IsString()); + String resourceNameString = (useURL) + ? frame->document()->url() + : ToWebCoreString(resourceName); + JavaScriptConsoleMessage consoleMessage(errorMessage, + resourceNameString, + message->GetLineNumber()); + ConsoleMessageManager::AddMessage(page, consoleMessage); +} + + +enum DelayReporting { + REPORT_LATER, + REPORT_NOW +}; + + +static void ReportUnsafeAccessTo(Frame* target, DelayReporting delay) +{ + ASSERT(target); + Document* targetDocument = target->document(); + if (!targetDocument) + return; + + Frame* source = V8Proxy::retrieveActiveFrame(); + if (!source || !source->document()) + return; // Ignore error if the source document is gone. + + Document* sourceDocument = source->document(); + + // FIXME: This error message should contain more specifics of why the same + // origin check has failed. + String str = String::format("Unsafe JavaScript attempt to access frame " + "with URL %s from frame with URL %s. " + "Domains, protocols and ports must match.\n", + targetDocument->url().string().utf8().data(), + sourceDocument->url().string().utf8().data()); + + // Build a console message with fake source ID and line number. + const String kSourceID = ""; + const int kLineNumber = 1; + JavaScriptConsoleMessage message(str, kSourceID, kLineNumber); + + if (delay == REPORT_NOW) { + // NOTE(tc): Apple prints the message in the target page, but it seems like + // it should be in the source page. Even for delayed messages, we put it in + // the source page; see ConsoleMessageManager::ProcessDelayedMessages(). + ConsoleMessageManager::AddMessage(source->page(), message); + + } else { + ASSERT(delay == REPORT_LATER); + // We cannot safely report the message eagerly, because this may cause + // allocations and GCs internally in V8 and we cannot handle that at this + // point. Therefore we delay the reporting. + ConsoleMessageManager::AddDelayedMessage(message); + } +} + +static void ReportUnsafeJavaScriptAccess(v8::Local<v8::Object> host, + v8::AccessType type, + v8::Local<v8::Value> data) +{ + Frame* target = V8Custom::GetTargetFrame(host, data); + if (target) + ReportUnsafeAccessTo(target, REPORT_LATER); +} + +static void HandleFatalErrorInV8() +{ + // TODO: We temporarily deal with V8 internal error situations + // such as out-of-memory by crashing the renderer. + CRASH(); +} + +static void ReportFatalErrorInV8(const char* location, const char* message) +{ + // V8 is shutdown, we cannot use V8 api. + // The only thing we can do is to disable JavaScript. + // TODO: clean up V8Proxy and disable JavaScript. + printf("V8 error: %s (%s)\n", message, location); + HandleFatalErrorInV8(); +} + +V8Proxy::~V8Proxy() +{ + clearForClose(); + DestroyGlobal(); +} + +void V8Proxy::DestroyGlobal() +{ + if (!m_global.IsEmpty()) { +#ifndef NDEBUG + UnregisterGlobalHandle(this, m_global); +#endif + m_global.Dispose(); + m_global.Clear(); + } +} + + +bool V8Proxy::DOMObjectHasJSWrapper(void* obj) { + return getDOMObjectMap().contains(obj) || + getActiveDOMObjectMap().contains(obj); +} + + +// The caller must have increased obj's ref count. +void V8Proxy::SetJSWrapperForDOMObject(void* obj, v8::Persistent<v8::Object> wrapper) +{ + ASSERT(MaybeDOMWrapper(wrapper)); +#ifndef NDEBUG + V8ClassIndex::V8WrapperType type = V8Proxy::GetDOMWrapperType(wrapper); + switch (type) { +#define MAKE_CASE(TYPE, NAME) case V8ClassIndex::TYPE: +ACTIVE_DOM_OBJECT_TYPES(MAKE_CASE) + ASSERT(false); +#undef MAKE_CASE + default: break; + } +#endif + getDOMObjectMap().set(obj, wrapper); +} + +// The caller must have increased obj's ref count. +void V8Proxy::SetJSWrapperForActiveDOMObject(void* obj, v8::Persistent<v8::Object> wrapper) +{ + ASSERT(MaybeDOMWrapper(wrapper)); +#ifndef NDEBUG + V8ClassIndex::V8WrapperType type = V8Proxy::GetDOMWrapperType(wrapper); + switch (type) { +#define MAKE_CASE(TYPE, NAME) case V8ClassIndex::TYPE: break; +ACTIVE_DOM_OBJECT_TYPES(MAKE_CASE) + default: ASSERT(false); +#undef MAKE_CASE + } +#endif + getActiveDOMObjectMap().set(obj, wrapper); +} + +// The caller must have increased node's ref count. +void V8Proxy::SetJSWrapperForDOMNode(Node* node, v8::Persistent<v8::Object> wrapper) +{ + ASSERT(MaybeDOMWrapper(wrapper)); + getDOMNodeMap().set(node, wrapper); +} + +PassRefPtr<EventListener> V8Proxy::createInlineEventListener( + const String& functionName, + const String& code, Node* node) +{ + return V8LazyEventListener::create(m_frame, code, functionName); +} + +#if ENABLE(SVG) +PassRefPtr<EventListener> V8Proxy::createSVGEventHandler(const String& functionName, + const String& code, Node* node) +{ + return V8LazyEventListener::create(m_frame, code, functionName); +} +#endif + + +// Event listeners + +static V8EventListener* FindEventListenerInList(V8EventListenerList& list, + v8::Local<v8::Value> listener, + bool isInline) +{ + ASSERT(v8::Context::InContext()); + + if (!listener->IsObject()) + return 0; + + return list.find(listener->ToObject(), isInline); +} + +// Find an existing wrapper for a JS event listener in the map. +PassRefPtr<V8EventListener> V8Proxy::FindV8EventListener(v8::Local<v8::Value> listener, + bool isInline) +{ + return FindEventListenerInList(m_event_listeners, listener, isInline); +} + +PassRefPtr<V8EventListener> V8Proxy::FindOrCreateV8EventListener(v8::Local<v8::Value> obj, bool isInline) +{ + ASSERT(v8::Context::InContext()); + + if (!obj->IsObject()) + return 0; + + V8EventListener* wrapper = + FindEventListenerInList(m_event_listeners, obj, isInline); + if (wrapper) + return wrapper; + + // Create a new one, and add to cache. + RefPtr<V8EventListener> new_listener = + V8EventListener::create(m_frame, v8::Local<v8::Object>::Cast(obj), isInline); + m_event_listeners.add(new_listener.get()); + + return new_listener; +} + + +// Object event listeners (such as XmlHttpRequest and MessagePort) are +// different from listeners on DOM nodes. An object event listener wrapper +// only holds a weak reference to the JS function. A strong reference can +// create a cycle. +// +// The lifetime of these objects is bounded by the life time of its JS +// wrapper. So we can create a hidden reference from the JS wrapper to +// to its JS function. +// +// (map) +// XHR <---------- JS_wrapper +// | (hidden) : ^ +// V V : (may reachable by closure) +// V8_listener --------> JS_function +// (weak) <-- may create a cycle if it is strong +// +// The persistent reference is made weak in the constructor +// of V8ObjectEventListener. + +PassRefPtr<V8EventListener> V8Proxy::FindObjectEventListener( + v8::Local<v8::Value> listener, bool isInline) +{ + return FindEventListenerInList(m_xhr_listeners, listener, isInline); +} + + +PassRefPtr<V8EventListener> V8Proxy::FindOrCreateObjectEventListener( + v8::Local<v8::Value> obj, bool isInline) +{ + ASSERT(v8::Context::InContext()); + + if (!obj->IsObject()) + return 0; + + V8EventListener* wrapper = + FindEventListenerInList(m_xhr_listeners, obj, isInline); + if (wrapper) + return wrapper; + + // Create a new one, and add to cache. + RefPtr<V8EventListener> new_listener = + V8ObjectEventListener::create(m_frame, v8::Local<v8::Object>::Cast(obj), isInline); + m_xhr_listeners.add(new_listener.get()); + + return new_listener.release(); +} + + +static void RemoveEventListenerFromList(V8EventListenerList& list, + V8EventListener* listener) +{ + list.remove(listener); +} + + +void V8Proxy::RemoveV8EventListener(V8EventListener* listener) +{ + RemoveEventListenerFromList(m_event_listeners, listener); +} + + +void V8Proxy::RemoveObjectEventListener(V8ObjectEventListener* listener) +{ + RemoveEventListenerFromList(m_xhr_listeners, listener); +} + + +static void DisconnectEventListenersInList(V8EventListenerList& list) +{ + V8EventListenerList::iterator p = list.begin(); + while (p != list.end()) { + (*p)->disconnectFrame(); + ++p; + } + list.clear(); +} + + +void V8Proxy::DisconnectEventListeners() +{ + DisconnectEventListenersInList(m_event_listeners); + DisconnectEventListenersInList(m_xhr_listeners); +} + + +v8::Handle<v8::Script> V8Proxy::CompileScript(v8::Handle<v8::String> code, + const String& fileName, + int baseLine) +{ + const uint16_t* fileNameString = FromWebCoreString(fileName); + v8::Handle<v8::String> name = + v8::String::New(fileNameString, fileName.length()); + v8::Handle<v8::Integer> line = v8::Integer::New(baseLine); + v8::ScriptOrigin origin(name, line); + v8::Handle<v8::Script> script = v8::Script::Compile(code, &origin); + return script; +} + +bool V8Proxy::HandleOutOfMemory() +{ + v8::Local<v8::Context> context = v8::Context::GetCurrent(); + + if (!context->HasOutOfMemoryException()) + return false; + + // Warning, error, disable JS for this frame? + Frame* frame = V8Proxy::retrieveFrame(context); + + V8Proxy* proxy = V8Proxy::retrieve(frame); + // Clean m_context, and event handlers. + proxy->clearForClose(); + // Destroy the global object. + proxy->DestroyGlobal(); + +#if PLATFORM(CHROMIUM) + ChromiumBridge::notifyJSOutOfMemory(frame); +#endif + // Disable JS. + Settings* settings = frame->settings(); + ASSERT(settings); + settings->setJavaScriptEnabled(false); + + return true; +} + +void V8Proxy::evaluateInNewContext(const Vector<ScriptSourceCode>& sources) +{ + InitContextIfNeeded(); + + v8::HandleScope handleScope; + + // Set up the DOM window as the prototype of the new global object. + v8::Handle<v8::Context> windowContext = m_context; + v8::Handle<v8::Object> windowGlobal = windowContext->Global(); + v8::Handle<v8::Value> windowWrapper = + V8Proxy::LookupDOMWrapper(V8ClassIndex::DOMWINDOW, windowGlobal); + + ASSERT(V8Proxy::DOMWrapperToNative<DOMWindow>(windowWrapper) == + m_frame->domWindow()); + + v8::Persistent<v8::Context> context = + createNewContext(v8::Handle<v8::Object>()); + v8::Context::Scope context_scope(context); + v8::Handle<v8::Object> global = context->Global(); + + v8::Handle<v8::String> implicitProtoString = v8::String::New("__proto__"); + global->Set(implicitProtoString, windowWrapper); + + // Give the code running in the new context a way to get access to the + // original context. + global->Set(v8::String::New("contentWindow"), windowGlobal); + + // Run code in the new context. + for (size_t i = 0; i < sources.size(); ++i) + evaluate(sources[i], 0); + + // Using the default security token means that the canAccess is always + // called, which is slow. + // TODO(aa): Use tokens where possible. This will mean keeping track of all + // created contexts so that they can all be updated when the document domain + // changes. + context->UseDefaultSecurityToken(); + context.Dispose(); +} + +v8::Local<v8::Value> V8Proxy::evaluate(const ScriptSourceCode& source, Node* n) +{ + ASSERT(v8::Context::InContext()); + + // Compile the script. + v8::Local<v8::String> code = v8ExternalString(source.source()); +#if PLATFORM(CHROMIUM) + ChromiumBridge::traceEventBegin("v8.compile", n, ""); +#endif + + // NOTE: For compatibility with WebCore, ScriptSourceCode's line starts at + // 1, whereas v8 starts at 0. + v8::Handle<v8::Script> script = CompileScript(code, source.url(), + source.startLine() - 1); +#if PLATFORM(CHROMIUM) + ChromiumBridge::traceEventEnd("v8.compile", n, ""); + ChromiumBridge::traceEventBegin("v8.run", n, ""); +#endif + + v8::Local<v8::Value> result; + { + // Isolate exceptions that occur when executing the code. These + // exceptions should not interfere with javascript code we might + // evaluate from C++ when returning from here + v8::TryCatch try_catch; + try_catch.SetVerbose(true); + + // Set inlineCode to true for <a href="javascript:doSomething()"> + // and false for <script>doSomething</script>. We make a rough guess at + // this based on whether the script source has a URL. + result = RunScript(script, source.url().string().isNull()); + } +#if PLATFORM(CHROMIUM) + ChromiumBridge::traceEventEnd("v8.run", n, ""); +#endif + return result; +} + +v8::Local<v8::Value> V8Proxy::RunScript(v8::Handle<v8::Script> script, + bool inline_code) +{ + if (script.IsEmpty()) + return v8::Local<v8::Value>(); + + // Compute the source string and prevent against infinite recursion. + if (m_recursion >= kMaxRecursionDepth) { + v8::Local<v8::String> code = + v8ExternalString("throw RangeError('Recursion too deep')"); + // TODO(kasperl): Ideally, we should be able to re-use the origin of the + // script passed to us as the argument instead of using an empty string + // and 0 baseLine. + script = CompileScript(code, "", 0); + } + + if (HandleOutOfMemory()) + ASSERT(script.IsEmpty()); + + if (script.IsEmpty()) + return v8::Local<v8::Value>(); + + // Save the previous value of the inlineCode flag and update the flag for + // the duration of the script invocation. + bool previous_inline_code = inlineCode(); + setInlineCode(inline_code); + + // Run the script and keep track of the current recursion depth. + v8::Local<v8::Value> result; + { ConsoleMessageScope scope; + m_recursion++; + + // Evaluating the JavaScript could cause the frame to be deallocated, + // so we start the keep alive timer here. + // Frame::keepAlive method adds the ref count of the frame and sets a + // timer to decrease the ref count. It assumes that the current JavaScript + // execution finishs before firing the timer. + // See issue 1218756 and 914430. + m_frame->keepAlive(); + + result = script->Run(); + m_recursion--; + } + + if (HandleOutOfMemory()) + ASSERT(result.IsEmpty()); + + // Handle V8 internal error situation (Out-of-memory). + if (result.IsEmpty()) + return v8::Local<v8::Value>(); + + // Restore inlineCode flag. + setInlineCode(previous_inline_code); + + if (v8::V8::IsDead()) + HandleFatalErrorInV8(); + + return result; +} + + +v8::Local<v8::Value> V8Proxy::CallFunction(v8::Handle<v8::Function> function, + v8::Handle<v8::Object> receiver, + int argc, + v8::Handle<v8::Value> args[]) +{ + // For now, we don't put any artificial limitations on the depth + // of recursion that stems from calling functions. This is in + // contrast to the script evaluations. + v8::Local<v8::Value> result; + { + ConsoleMessageScope scope; + + // Evaluating the JavaScript could cause the frame to be deallocated, + // so we start the keep alive timer here. + // Frame::keepAlive method adds the ref count of the frame and sets a + // timer to decrease the ref count. It assumes that the current JavaScript + // execution finishs before firing the timer. + // See issue 1218756 and 914430. + m_frame->keepAlive(); + + result = function->Call(receiver, argc, args); + } + + if (v8::V8::IsDead()) + HandleFatalErrorInV8(); + + return result; +} + + +v8::Local<v8::Function> V8Proxy::GetConstructor(V8ClassIndex::V8WrapperType t){ + // A DOM constructor is a function instance created from a DOM constructor + // template. There is one instance per context. A DOM constructor is + // different from a normal function in two ways: + // 1) it cannot be called as constructor (aka, used to create a DOM object) + // 2) its __proto__ points to Object.prototype rather than + // Function.prototype. + // The reason for 2) is that, in Safari, a DOM constructor is a normal JS + // object, but not a function. Hotmail relies on the fact that, in Safari, + // HTMLElement.__proto__ == Object.prototype. + // + // m_object_prototype is a cache of the original Object.prototype. + + ASSERT(ContextInitialized()); + // Enter the context of the proxy to make sure that the + // function is constructed in the context corresponding to + // this proxy. + v8::Context::Scope scope(m_context); + v8::Handle<v8::FunctionTemplate> templ = GetTemplate(t); + // Getting the function might fail if we're running out of + // stack or memory. + v8::TryCatch try_catch; + v8::Local<v8::Function> value = templ->GetFunction(); + if (value.IsEmpty()) + return v8::Local<v8::Function>(); + // Hotmail fix, see comments above. + value->Set(v8::String::New("__proto__"), m_object_prototype); + return value; +} + + +v8::Local<v8::Object> V8Proxy::CreateWrapperFromCache(V8ClassIndex::V8WrapperType type) { + int class_index = V8ClassIndex::ToInt(type); + v8::Local<v8::Value> cached_object = + m_wrapper_boilerplates->Get(v8::Integer::New(class_index)); + if (cached_object->IsObject()) { + v8::Local<v8::Object> object = v8::Local<v8::Object>::Cast(cached_object); + return object->Clone(); + } + + // Not in cache. + InitContextIfNeeded(); + v8::Context::Scope scope(m_context); + v8::Local<v8::Function> function = GetConstructor(type); + v8::Local<v8::Object> instance = SafeAllocation::NewInstance(function); + if (!instance.IsEmpty()) { + m_wrapper_boilerplates->Set(v8::Integer::New(class_index), instance); + return instance->Clone(); + } + return v8::Local<v8::Object>(); +} + + +// Get the string 'toString'. +static v8::Persistent<v8::String> GetToStringName() { + static v8::Persistent<v8::String> value; + if (value.IsEmpty()) + value = v8::Persistent<v8::String>::New(v8::String::New("toString")); + return value; +} + + +static v8::Handle<v8::Value> ConstructorToString(const v8::Arguments& args) { + // The DOM constructors' toString functions grab the current toString + // for Functions by taking the toString function of itself and then + // calling it with the constructor as its receiver. This means that + // changes to the Function prototype chain or toString function are + // reflected when printing DOM constructors. The only wart is that + // changes to a DOM constructor's toString's toString will cause the + // toString of the DOM constructor itself to change. This is extremely + // obscure and unlikely to be a problem. + v8::Handle<v8::Value> val = args.Callee()->Get(GetToStringName()); + if (!val->IsFunction()) return v8::String::New(""); + return v8::Handle<v8::Function>::Cast(val)->Call(args.This(), 0, NULL); +} + + +v8::Persistent<v8::FunctionTemplate> V8Proxy::GetTemplate( + V8ClassIndex::V8WrapperType type) +{ + v8::Persistent<v8::FunctionTemplate>* cache_cell = + V8ClassIndex::GetCache(type); + if (!(*cache_cell).IsEmpty()) + return *cache_cell; + + // not found + FunctionTemplateFactory factory = V8ClassIndex::GetFactory(type); + v8::Persistent<v8::FunctionTemplate> desc = factory(); + // DOM constructors are functions and should print themselves as such. + // However, we will later replace their prototypes with Object + // prototypes so we need to explicitly override toString on the + // instance itself. If we later make DOM constructors full objects + // we can give them class names instead and Object.prototype.toString + // will work so we can remove this code. + static v8::Persistent<v8::FunctionTemplate> to_string_template; + if (to_string_template.IsEmpty()) { + to_string_template = v8::Persistent<v8::FunctionTemplate>::New( + v8::FunctionTemplate::New(ConstructorToString)); + } + desc->Set(GetToStringName(), to_string_template); + switch (type) { + case V8ClassIndex::CSSSTYLEDECLARATION: + // The named property handler for style declarations has a + // setter. Therefore, the interceptor has to be on the object + // itself and not on the prototype object. + desc->InstanceTemplate()->SetNamedPropertyHandler( + USE_NAMED_PROPERTY_GETTER(CSSStyleDeclaration), + USE_NAMED_PROPERTY_SETTER(CSSStyleDeclaration)); + setCollectionStringOrNullIndexedGetter<CSSStyleDeclaration>(desc); + break; + case V8ClassIndex::CSSRULELIST: + setCollectionIndexedGetter<CSSRuleList, CSSRule>(desc, + V8ClassIndex::CSSRULE); + break; + case V8ClassIndex::CSSVALUELIST: + setCollectionIndexedGetter<CSSValueList, CSSValue>( + desc, + V8ClassIndex::CSSVALUE); + break; + case V8ClassIndex::CSSVARIABLESDECLARATION: + setCollectionStringOrNullIndexedGetter<CSSVariablesDeclaration>(desc); + break; + case V8ClassIndex::WEBKITCSSTRANSFORMVALUE: + setCollectionIndexedGetter<WebKitCSSTransformValue, CSSValue>( + desc, + V8ClassIndex::CSSVALUE); + break; + case V8ClassIndex::UNDETECTABLEHTMLCOLLECTION: + desc->InstanceTemplate()->MarkAsUndetectable(); // fall through + case V8ClassIndex::HTMLCOLLECTION: + desc->InstanceTemplate()->SetNamedPropertyHandler( + USE_NAMED_PROPERTY_GETTER(HTMLCollection)); + desc->InstanceTemplate()->SetCallAsFunctionHandler( + USE_CALLBACK(HTMLCollectionCallAsFunction)); + setCollectionIndexedGetter<HTMLCollection, Node>(desc, + V8ClassIndex::NODE); + break; + case V8ClassIndex::HTMLOPTIONSCOLLECTION: + setCollectionNamedGetter<HTMLOptionsCollection, Node>( + desc, + V8ClassIndex::NODE); + desc->InstanceTemplate()->SetIndexedPropertyHandler( + USE_INDEXED_PROPERTY_GETTER(HTMLOptionsCollection), + USE_INDEXED_PROPERTY_SETTER(HTMLOptionsCollection)); + desc->InstanceTemplate()->SetCallAsFunctionHandler( + USE_CALLBACK(HTMLCollectionCallAsFunction)); + break; + case V8ClassIndex::HTMLSELECTELEMENT: + desc->InstanceTemplate()->SetNamedPropertyHandler( + nodeCollectionNamedPropertyGetter<HTMLSelectElement>, + 0, + 0, + 0, + 0, + v8::Integer::New(V8ClassIndex::NODE)); + desc->InstanceTemplate()->SetIndexedPropertyHandler( + nodeCollectionIndexedPropertyGetter<HTMLSelectElement>, + USE_INDEXED_PROPERTY_SETTER(HTMLSelectElementCollection), + 0, + 0, + nodeCollectionIndexedPropertyEnumerator<HTMLSelectElement>, + v8::Integer::New(V8ClassIndex::NODE)); + break; + case V8ClassIndex::HTMLDOCUMENT: { + desc->InstanceTemplate()->SetNamedPropertyHandler( + USE_NAMED_PROPERTY_GETTER(HTMLDocument), + 0, + 0, + USE_NAMED_PROPERTY_DELETER(HTMLDocument)); + + // We add an extra internal field to all Document wrappers for + // storing a per document DOMImplementation wrapper. + // + // Additionally, we add two extra internal fields for + // HTMLDocuments to implement temporary shadowing of + // document.all. One field holds an object that is used as a + // marker. The other field holds the marker object if + // document.all is not shadowed and some other value if + // document.all is shadowed. + v8::Local<v8::ObjectTemplate> instance_template = + desc->InstanceTemplate(); + ASSERT(instance_template->InternalFieldCount() == + V8Custom::kDefaultWrapperInternalFieldCount); + instance_template->SetInternalFieldCount( + V8Custom::kHTMLDocumentInternalFieldCount); + break; + } +#if ENABLE(SVG) + case V8ClassIndex::SVGDOCUMENT: // fall through +#endif + case V8ClassIndex::DOCUMENT: { + // We add an extra internal field to all Document wrappers for + // storing a per document DOMImplementation wrapper. + v8::Local<v8::ObjectTemplate> instance_template = + desc->InstanceTemplate(); + ASSERT(instance_template->InternalFieldCount() == + V8Custom::kDefaultWrapperInternalFieldCount); + instance_template->SetInternalFieldCount( + V8Custom::kDocumentMinimumInternalFieldCount); + break; + } + case V8ClassIndex::HTMLAPPLETELEMENT: // fall through + case V8ClassIndex::HTMLEMBEDELEMENT: // fall through + case V8ClassIndex::HTMLOBJECTELEMENT: + // HTMLAppletElement, HTMLEmbedElement and HTMLObjectElement are + // inherited from HTMLPlugInElement, and they share the same property + // handling code. + desc->InstanceTemplate()->SetNamedPropertyHandler( + USE_NAMED_PROPERTY_GETTER(HTMLPlugInElement), + USE_NAMED_PROPERTY_SETTER(HTMLPlugInElement)); + desc->InstanceTemplate()->SetIndexedPropertyHandler( + USE_INDEXED_PROPERTY_GETTER(HTMLPlugInElement), + USE_INDEXED_PROPERTY_SETTER(HTMLPlugInElement)); + desc->InstanceTemplate()->SetCallAsFunctionHandler( + USE_CALLBACK(HTMLPlugInElement)); + break; + case V8ClassIndex::HTMLFRAMESETELEMENT: + desc->InstanceTemplate()->SetNamedPropertyHandler( + USE_NAMED_PROPERTY_GETTER(HTMLFrameSetElement)); + break; + case V8ClassIndex::HTMLFORMELEMENT: + desc->InstanceTemplate()->SetNamedPropertyHandler( + USE_NAMED_PROPERTY_GETTER(HTMLFormElement)); + desc->InstanceTemplate()->SetIndexedPropertyHandler( + USE_INDEXED_PROPERTY_GETTER(HTMLFormElement), + 0, + 0, + 0, + nodeCollectionIndexedPropertyEnumerator<HTMLFormElement>, + v8::Integer::New(V8ClassIndex::NODE)); + break; + case V8ClassIndex::CANVASPIXELARRAY: + desc->InstanceTemplate()->SetIndexedPropertyHandler( + USE_INDEXED_PROPERTY_GETTER(CanvasPixelArray), + USE_INDEXED_PROPERTY_SETTER(CanvasPixelArray)); + break; + case V8ClassIndex::STYLESHEET: // fall through + case V8ClassIndex::CSSSTYLESHEET: { + // We add an extra internal field to hold a reference to + // the owner node. + v8::Local<v8::ObjectTemplate> instance_template = + desc->InstanceTemplate(); + ASSERT(instance_template->InternalFieldCount() == + V8Custom::kDefaultWrapperInternalFieldCount); + instance_template->SetInternalFieldCount( + V8Custom::kStyleSheetInternalFieldCount); + break; + } + case V8ClassIndex::MEDIALIST: + setCollectionStringOrNullIndexedGetter<MediaList>(desc); + break; + case V8ClassIndex::MIMETYPEARRAY: + setCollectionIndexedAndNamedGetters<MimeTypeArray, MimeType>( + desc, + V8ClassIndex::MIMETYPE); + break; + case V8ClassIndex::NAMEDNODEMAP: + desc->InstanceTemplate()->SetNamedPropertyHandler( + USE_NAMED_PROPERTY_GETTER(NamedNodeMap)); + desc->InstanceTemplate()->SetIndexedPropertyHandler( + USE_INDEXED_PROPERTY_GETTER(NamedNodeMap), + 0, + 0, + 0, + collectionIndexedPropertyEnumerator<NamedNodeMap>, + v8::Integer::New(V8ClassIndex::NODE)); + break; + case V8ClassIndex::NODELIST: + setCollectionIndexedGetter<NodeList, Node>(desc, V8ClassIndex::NODE); + desc->InstanceTemplate()->SetNamedPropertyHandler( + USE_NAMED_PROPERTY_GETTER(NodeList)); + break; + case V8ClassIndex::PLUGIN: + setCollectionIndexedAndNamedGetters<Plugin, MimeType>( + desc, + V8ClassIndex::MIMETYPE); + break; + case V8ClassIndex::PLUGINARRAY: + setCollectionIndexedAndNamedGetters<PluginArray, Plugin>( + desc, + V8ClassIndex::PLUGIN); + break; + case V8ClassIndex::STYLESHEETLIST: + desc->InstanceTemplate()->SetNamedPropertyHandler( + USE_NAMED_PROPERTY_GETTER(StyleSheetList)); + setCollectionIndexedGetter<StyleSheetList, StyleSheet>( + desc, + V8ClassIndex::STYLESHEET); + break; + case V8ClassIndex::DOMWINDOW: { + v8::Local<v8::Signature> default_signature = v8::Signature::New(desc); + + desc->PrototypeTemplate()->SetNamedPropertyHandler( + USE_NAMED_PROPERTY_GETTER(DOMWindow)); + desc->PrototypeTemplate()->SetIndexedPropertyHandler( + USE_INDEXED_PROPERTY_GETTER(DOMWindow)); + + desc->SetHiddenPrototype(true); + + // Reserve spaces for references to location, history and + // navigator objects. + v8::Local<v8::ObjectTemplate> instance_template = + desc->InstanceTemplate(); + instance_template->SetInternalFieldCount( + V8Custom::kDOMWindowInternalFieldCount); + + // Set access check callbacks, but turned off initially. + // When a context is detached from a frame, turn on the access check. + // Turning on checks also invalidates inline caches of the object. + instance_template->SetAccessCheckCallbacks( + V8Custom::v8DOMWindowNamedSecurityCheck, + V8Custom::v8DOMWindowIndexedSecurityCheck, + v8::Integer::New(V8ClassIndex::DOMWINDOW), + false); + break; + } + case V8ClassIndex::LOCATION: { + // For security reasons, these functions are on the instance + // instead of on the prototype object to insure that they cannot + // be overwritten. + v8::Local<v8::ObjectTemplate> instance = desc->InstanceTemplate(); + instance->SetAccessor( + v8::String::New("reload"), + V8Custom::v8LocationReloadAccessorGetter, + 0, + v8::Handle<v8::Value>(), + v8::ALL_CAN_READ, + static_cast<v8::PropertyAttribute>(v8::DontDelete|v8::ReadOnly)); + + instance->SetAccessor( + v8::String::New("replace"), + V8Custom::v8LocationReplaceAccessorGetter, + 0, + v8::Handle<v8::Value>(), + v8::ALL_CAN_READ, + static_cast<v8::PropertyAttribute>(v8::DontDelete|v8::ReadOnly)); + + instance->SetAccessor( + v8::String::New("assign"), + V8Custom::v8LocationAssignAccessorGetter, + 0, + v8::Handle<v8::Value>(), + v8::ALL_CAN_READ, + static_cast<v8::PropertyAttribute>(v8::DontDelete|v8::ReadOnly)); + break; + } + case V8ClassIndex::HISTORY: { + break; + } + + case V8ClassIndex::MESSAGECHANNEL: { + // Reserve two more internal fields for referencing the port1 + // and port2 wrappers. This ensures that the port wrappers are + // kept alive when the channel wrapper is. + desc->SetCallHandler(USE_CALLBACK(MessageChannelConstructor)); + v8::Local<v8::ObjectTemplate> instance_template = + desc->InstanceTemplate(); + instance_template->SetInternalFieldCount( + V8Custom::kMessageChannelInternalFieldCount); + break; + } + + case V8ClassIndex::MESSAGEPORT: { + // Reserve one more internal field for keeping event listeners. + v8::Local<v8::ObjectTemplate> instance_template = + desc->InstanceTemplate(); + instance_template->SetInternalFieldCount( + V8Custom::kMessagePortInternalFieldCount); + break; + } + +#if ENABLE(WORKERS) + case V8ClassIndex::WORKER: { + // Reserve one more internal field for keeping event listeners. + v8::Local<v8::ObjectTemplate> instance_template = + desc->InstanceTemplate(); + instance_template->SetInternalFieldCount( + V8Custom::kWorkerInternalFieldCount); + desc->SetCallHandler(USE_CALLBACK(WorkerConstructor)); + break; + } + + case V8ClassIndex::WORKERCONTEXT: { + // Reserve one more internal field for keeping event listeners. + v8::Local<v8::ObjectTemplate> instance_template = + desc->InstanceTemplate(); + instance_template->SetInternalFieldCount( + V8Custom::kWorkerContextInternalFieldCount); + break; + } +#endif // WORKERS + +#if ENABLE(OFFLINE_WEB_APPLICATIONS) + case V8ClassIndex::DOMAPPLICATIONCACHE: { + // Reserve one more internal field for keeping event listeners. + v8::Local<v8::ObjectTemplate> instance_template = + desc->InstanceTemplate(); + instance_template->SetInternalFieldCount( + V8Custom::kDOMApplicationCacheFieldCount); + break; + } +#endif + + // The following objects are created from JavaScript. + case V8ClassIndex::DOMPARSER: + desc->SetCallHandler(USE_CALLBACK(DOMParserConstructor)); + break; + case V8ClassIndex::WEBKITCSSMATRIX: + desc->SetCallHandler(USE_CALLBACK(WebKitCSSMatrixConstructor)); + break; + case V8ClassIndex::WEBKITPOINT: + desc->SetCallHandler(USE_CALLBACK(WebKitPointConstructor)); + break; + case V8ClassIndex::XMLSERIALIZER: + desc->SetCallHandler(USE_CALLBACK(XMLSerializerConstructor)); + break; + case V8ClassIndex::XMLHTTPREQUEST: { + // Reserve one more internal field for keeping event listeners. + v8::Local<v8::ObjectTemplate> instance_template = + desc->InstanceTemplate(); + instance_template->SetInternalFieldCount( + V8Custom::kXMLHttpRequestInternalFieldCount); + desc->SetCallHandler(USE_CALLBACK(XMLHttpRequestConstructor)); + break; + } + case V8ClassIndex::XMLHTTPREQUESTUPLOAD: { + // Reserve one more internal field for keeping event listeners. + v8::Local<v8::ObjectTemplate> instance_template = + desc->InstanceTemplate(); + instance_template->SetInternalFieldCount( + V8Custom::kXMLHttpRequestInternalFieldCount); + break; + } +#if ENABLE(XPATH) + case V8ClassIndex::XPATHEVALUATOR: + desc->SetCallHandler(USE_CALLBACK(XPathEvaluatorConstructor)); + break; +#endif +#if ENABLE(XSLT) + case V8ClassIndex::XSLTPROCESSOR: + desc->SetCallHandler(USE_CALLBACK(XSLTProcessorConstructor)); + break; +#endif + default: + break; + } + + *cache_cell = desc; + return desc; +} + + +bool V8Proxy::ContextInitialized() +{ + // m_context, m_global, m_object_prototype and m_wrapper_boilerplates should + // all be non-empty if if m_context is non-empty. + ASSERT(m_context.IsEmpty() || !m_global.IsEmpty()); + ASSERT(m_context.IsEmpty() || !m_object_prototype.IsEmpty()); + ASSERT(m_context.IsEmpty() || !m_wrapper_boilerplates.IsEmpty()); + return !m_context.IsEmpty(); +} + + +DOMWindow* V8Proxy::retrieveWindow() +{ + // TODO: This seems very fragile. How do we know that the global object + // from the current context is something sensible? Do we need to use the + // last entered here? Who calls this? + return retrieveWindow(v8::Context::GetCurrent()); +} + + +DOMWindow* V8Proxy::retrieveWindow(v8::Handle<v8::Context> context) +{ + v8::Handle<v8::Object> global = context->Global(); + ASSERT(!global.IsEmpty()); + global = LookupDOMWrapper(V8ClassIndex::DOMWINDOW, global); + ASSERT(!global.IsEmpty()); + return ToNativeObject<DOMWindow>(V8ClassIndex::DOMWINDOW, global); +} + + +Frame* V8Proxy::retrieveFrame(v8::Handle<v8::Context> context) +{ + return retrieveWindow(context)->frame(); +} + + +Frame* V8Proxy::retrieveActiveFrame() +{ + v8::Handle<v8::Context> context = v8::Context::GetEntered(); + if (context.IsEmpty()) + return 0; + return retrieveFrame(context); +} + + +Frame* V8Proxy::retrieveFrame() +{ + DOMWindow* window = retrieveWindow(); + return window ? window->frame() : 0; +} + + +V8Proxy* V8Proxy::retrieve() +{ + DOMWindow* window = retrieveWindow(); + ASSERT(window); + return retrieve(window->frame()); +} + +V8Proxy* V8Proxy::retrieve(Frame* frame) +{ + if (!frame) + return 0; + return frame->script()->isEnabled() ? frame->script()->proxy() : 0; +} + + +V8Proxy* V8Proxy::retrieve(ScriptExecutionContext* context) +{ + if (!context->isDocument()) + return 0; + return retrieve(static_cast<Document*>(context)->frame()); +} + + +void V8Proxy::disconnectFrame() +{ + // disconnect all event listeners + DisconnectEventListeners(); +} + + +bool V8Proxy::isEnabled() +{ + Settings* settings = m_frame->settings(); + if (!settings) + return false; + + // In the common case, JavaScript is enabled and we're done. + if (settings->isJavaScriptEnabled()) + return true; + + // If JavaScript has been disabled, we need to look at the frame to tell + // whether this script came from the web or the embedder. Scripts from the + // embedder are safe to run, but scripts from the other sources are + // disallowed. + Document* document = m_frame->document(); + if (!document) + return false; + + SecurityOrigin* origin = document->securityOrigin(); + if (origin->protocol().isEmpty()) + return false; // Uninitialized document + + if (origin->protocol() == "http" || origin->protocol() == "https") + return false; // Web site + + // TODO(darin): the following are application decisions, and they should + // not be made at this layer. instead, we should bridge out to the + // embedder to allow them to override policy here. + +#if PLATFORM(CHROMIUM) + if (origin->protocol() == ChromiumBridge::uiResourceProtocol()) + return true; // Embedder's scripts are ok to run +#endif + + // If the scheme is ftp: or file:, an empty file name indicates a directory + // listing, which requires JavaScript to function properly. + const char* kDirProtocols[] = { "ftp", "file" }; +#if PLATFORM(ANDROID) + // TODO(fqian): port arraysize function to Android. + for (size_t i = 0; i < 2; ++i) { +#else + for (size_t i = 0; i < arraysize(kDirProtocols); ++i) { +#endif + if (origin->protocol() == kDirProtocols[i]) { + const KURL& url = document->url(); + return url.pathAfterLastSlash() == url.pathEnd(); + } + } + + return false; // Other protocols fall through to here +} + + +void V8Proxy::UpdateDocumentWrapper(v8::Handle<v8::Value> wrapper) { + ClearDocumentWrapper(); + + ASSERT(m_document.IsEmpty()); + m_document = v8::Persistent<v8::Value>::New(wrapper); +#ifndef NDEBUG + RegisterGlobalHandle(PROXY, this, m_document); +#endif +} + + +void V8Proxy::ClearDocumentWrapper() +{ + if (!m_document.IsEmpty()) { +#ifndef NDEBUG + UnregisterGlobalHandle(this, m_document); +#endif + m_document.Dispose(); + m_document.Clear(); + } +} + + +void V8Proxy::DisposeContextHandles() { + if (!m_context.IsEmpty()) { + m_context.Dispose(); + m_context.Clear(); + } + + if (!m_wrapper_boilerplates.IsEmpty()) { +#ifndef NDEBUG + UnregisterGlobalHandle(this, m_wrapper_boilerplates); +#endif + m_wrapper_boilerplates.Dispose(); + m_wrapper_boilerplates.Clear(); + } + + if (!m_object_prototype.IsEmpty()) { +#ifndef NDEBUG + UnregisterGlobalHandle(this, m_object_prototype); +#endif + m_object_prototype.Dispose(); + m_object_prototype.Clear(); + } +} + +void V8Proxy::clearForClose() +{ + if (!m_context.IsEmpty()) { + v8::HandleScope handle_scope; + + ClearDocumentWrapper(); + DisposeContextHandles(); + } +} + + +void V8Proxy::clearForNavigation() +{ + if (!m_context.IsEmpty()) { + v8::HandleScope handle; + ClearDocumentWrapper(); + + v8::Context::Scope context_scope(m_context); + + // Turn on access check on the old DOMWindow wrapper. + v8::Handle<v8::Object> wrapper = + LookupDOMWrapper(V8ClassIndex::DOMWINDOW, m_global); + ASSERT(!wrapper.IsEmpty()); + wrapper->TurnOnAccessCheck(); + + // disconnect all event listeners + DisconnectEventListeners(); + + // Separate the context from its global object. + m_context->DetachGlobal(); + + DisposeContextHandles(); + + // Reinitialize the context so the global object points to + // the new DOM window. + InitContextIfNeeded(); + } +} + + +void V8Proxy::SetSecurityToken() { + Document* document = m_frame->document(); + // Setup security origin and security token + if (!document) { + m_context->UseDefaultSecurityToken(); + return; + } + + // Ask the document's SecurityOrigin to generate a security token. + // If two tokens are equal, then the SecurityOrigins canAccess each other. + // If two tokens are not equal, then we have to call canAccess. + // Note: we can't use the HTTPOrigin if it was set from the DOM. + SecurityOrigin* origin = document->securityOrigin(); + String token; + if (!origin->domainWasSetInDOM()) + token = document->securityOrigin()->toString(); + + // An empty or "null" token means we always have to call + // canAccess. The toString method on securityOrigins returns the + // string "null" for empty security origins and for security + // origins that should only allow access to themselves. In this + // case, we use the global object as the security token to avoid + // calling canAccess when a script accesses its own objects. + if (token.isEmpty() || token == "null") { + m_context->UseDefaultSecurityToken(); + return; + } + + CString utf8_token = token.utf8(); + // NOTE: V8 does identity comparison in fast path, must use a symbol + // as the security token. + m_context->SetSecurityToken( + v8::String::NewSymbol(utf8_token.data(), utf8_token.length())); +} + + +void V8Proxy::updateDocument() +{ + if (!m_frame->document()) + return; + + if (m_global.IsEmpty()) { + ASSERT(m_context.IsEmpty()); + return; + } + + { + v8::HandleScope scope; + SetSecurityToken(); + } +} + +void V8Proxy::updateSecurityOrigin() +{ + v8::HandleScope scope; + SetSecurityToken(); +} + +// Same origin policy implementation: +// +// Same origin policy prevents JS code from domain A access JS & DOM objects +// in a different domain B. There are exceptions and several objects are +// accessible by cross-domain code. For example, the window.frames object is +// accessible by code from a different domain, but window.document is not. +// +// The binding code sets security check callbacks on a function template, +// and accessing instances of the template calls the callback function. +// The callback function checks same origin policy. +// +// Callback functions are expensive. V8 uses a security token string to do +// fast access checks for the common case where source and target are in the +// same domain. A security token is a string object that represents +// the protocol/url/port of a domain. +// +// There are special cases where a security token matching is not enough. +// For example, JavaScript can set its domain to a super domain by calling +// document.setDomain(...). In these cases, the binding code can reset +// a context's security token to its global object so that the fast access +// check will always fail. + +// Check if the current execution context can access a target frame. +// First it checks same domain policy using the lexical context +// +// This is equivalent to KJS::Window::allowsAccessFrom(ExecState*, String&). +bool V8Proxy::CanAccessPrivate(DOMWindow* target_window) +{ + ASSERT(target_window); + + String message; + + DOMWindow* origin_window = retrieveWindow(); + if (origin_window == target_window) + return true; + + if (!origin_window) + return false; + + // JS may be attempting to access the "window" object, which should be + // valid, even if the document hasn't been constructed yet. + // If the document doesn't exist yet allow JS to access the window object. + if (!origin_window->document()) + return true; + + const SecurityOrigin* active_security_origin = origin_window->securityOrigin(); + const SecurityOrigin* target_security_origin = target_window->securityOrigin(); + + // We have seen crashes were the security origin of the target has not been + // initialized. Defend against that. + ASSERT(target_security_origin); + if (!target_security_origin) + return false; + + if (active_security_origin->canAccess(target_security_origin)) + return true; + + // Allow access to a "about:blank" page if the dynamic context is a + // detached context of the same frame as the blank page. + if (target_security_origin->isEmpty() && + origin_window->frame() == target_window->frame()) + return true; + + return false; +} + + +bool V8Proxy::CanAccessFrame(Frame* target, bool report_error) +{ + // The subject is detached from a frame, deny accesses. + if (!target) + return false; + + if (!CanAccessPrivate(target->domWindow())) { + if (report_error) + ReportUnsafeAccessTo(target, REPORT_NOW); + return false; + } + return true; +} + + +bool V8Proxy::CheckNodeSecurity(Node* node) +{ + if (!node) + return false; + + Frame* target = node->document()->frame(); + + if (!target) + return false; + + return CanAccessFrame(target, true); +} + +v8::Persistent<v8::Context> V8Proxy::createNewContext( + v8::Handle<v8::Object> global) +{ + v8::Persistent<v8::Context> result; + + // Create a new environment using an empty template for the shadow + // object. Reuse the global object if one has been created earlier. + v8::Persistent<v8::ObjectTemplate> globalTemplate = + V8DOMWindow::GetShadowObjectTemplate(); + if (globalTemplate.IsEmpty()) + return result; + + // Install a security handler with V8. + globalTemplate->SetAccessCheckCallbacks( + V8Custom::v8DOMWindowNamedSecurityCheck, + V8Custom::v8DOMWindowIndexedSecurityCheck, + v8::Integer::New(V8ClassIndex::DOMWINDOW)); + + // Dynamically tell v8 about our extensions now. + const char** extensionNames = new const char*[m_extensions.size()]; + int index = 0; + for (V8ExtensionList::iterator it = m_extensions.begin(); + it != m_extensions.end(); ++it) { + if (it->scheme.length() > 0 && + it->scheme != m_frame->document()->url().protocol()) + continue; + + extensionNames[index++] = it->extension->name(); + } + v8::ExtensionConfiguration extensions(index, extensionNames); + result = v8::Context::New(&extensions, globalTemplate, global); + delete [] extensionNames; + extensionNames = 0; + + return result; +} + +// Create a new environment and setup the global object. +// +// The global object corresponds to a DOMWindow instance. However, to +// allow properties of the JS DOMWindow instance to be shadowed, we +// use a shadow object as the global object and use the JS DOMWindow +// instance as the prototype for that shadow object. The JS DOMWindow +// instance is undetectable from javascript code because the __proto__ +// accessors skip that object. +// +// The shadow object and the DOMWindow instance are seen as one object +// from javascript. The javascript object that corresponds to a +// DOMWindow instance is the shadow object. When mapping a DOMWindow +// instance to a V8 object, we return the shadow object. +// +// To implement split-window, see +// 1) https://bugs.webkit.org/show_bug.cgi?id=17249 +// 2) https://wiki.mozilla.org/Gecko:SplitWindow +// 3) https://bugzilla.mozilla.org/show_bug.cgi?id=296639 +// we need to split the shadow object further into two objects: +// an outer window and an inner window. The inner window is the hidden +// prototype of the outer window. The inner window is the default +// global object of the context. A variable declared in the global +// scope is a property of the inner window. +// +// The outer window sticks to a Frame, it is exposed to JavaScript +// via window.window, window.self, window.parent, etc. The outer window +// has a security token which is the domain. The outer window cannot +// have its own properties. window.foo = 'x' is delegated to the +// inner window. +// +// When a frame navigates to a new page, the inner window is cut off +// the outer window, and the outer window identify is preserved for +// the frame. However, a new inner window is created for the new page. +// If there are JS code holds a closure to the old inner window, +// it won't be able to reach the outer window via its global object. +void V8Proxy::InitContextIfNeeded() +{ + // Bail out if the context has already been initialized. + if (!m_context.IsEmpty()) + return; + + // Create a handle scope for all local handles. + v8::HandleScope handle_scope; + + // Setup the security handlers and message listener. This only has + // to be done once. + static bool v8_initialized = false; + if (!v8_initialized) { + // Tells V8 not to call the default OOM handler, binding code + // will handle it. + v8::V8::IgnoreOutOfMemoryException(); + v8::V8::SetFatalErrorHandler(ReportFatalErrorInV8); + + v8::V8::SetGlobalGCPrologueCallback(&GCPrologue); + v8::V8::SetGlobalGCEpilogueCallback(&GCEpilogue); + + v8::V8::AddMessageListener(HandleConsoleMessage); + + v8::V8::SetFailedAccessCheckCallbackFunction(ReportUnsafeJavaScriptAccess); + + v8_initialized = true; + } + + m_context = createNewContext(m_global); + if (m_context.IsEmpty()) + return; + + // Starting from now, use local context only. + v8::Local<v8::Context> context = GetContext(); + v8::Context::Scope context_scope(context); + + // Store the first global object created so we can reuse it. + if (m_global.IsEmpty()) { + m_global = v8::Persistent<v8::Object>::New(context->Global()); + // Bail out if allocation of the first global objects fails. + if (m_global.IsEmpty()) { + DisposeContextHandles(); + return; + } +#ifndef NDEBUG + RegisterGlobalHandle(PROXY, this, m_global); +#endif + } + + // Allocate strings used during initialization. + v8::Handle<v8::String> object_string = v8::String::New("Object"); + v8::Handle<v8::String> prototype_string = v8::String::New("prototype"); + v8::Handle<v8::String> implicit_proto_string = v8::String::New("__proto__"); + // Bail out if allocation failed. + if (object_string.IsEmpty() || + prototype_string.IsEmpty() || + implicit_proto_string.IsEmpty()) { + DisposeContextHandles(); + return; + } + + // Allocate clone cache and pre-allocated objects + v8::Handle<v8::Object> object = v8::Handle<v8::Object>::Cast( + m_global->Get(object_string)); + m_object_prototype = v8::Persistent<v8::Value>::New( + object->Get(prototype_string)); + m_wrapper_boilerplates = v8::Persistent<v8::Array>::New( + v8::Array::New(V8ClassIndex::WRAPPER_TYPE_COUNT)); + // Bail out if allocation failed. + if (m_object_prototype.IsEmpty()) { + DisposeContextHandles(); + return; + } +#ifndef NDEBUG + RegisterGlobalHandle(PROXY, this, m_object_prototype); + RegisterGlobalHandle(PROXY, this, m_wrapper_boilerplates); +#endif + + // Create a new JS window object and use it as the prototype for the + // shadow global object. + v8::Handle<v8::Function> window_constructor = + GetConstructor(V8ClassIndex::DOMWINDOW); + v8::Local<v8::Object> js_window = + SafeAllocation::NewInstance(window_constructor); + // Bail out if allocation failed. + if (js_window.IsEmpty()) { + DisposeContextHandles(); + return; + } + + DOMWindow* window = m_frame->domWindow(); + + // Wrap the window. + SetDOMWrapper(js_window, + V8ClassIndex::ToInt(V8ClassIndex::DOMWINDOW), + window); + + window->ref(); + V8Proxy::SetJSWrapperForDOMObject(window, + v8::Persistent<v8::Object>::New(js_window)); + + // Insert the window instance as the prototype of the shadow object. + v8::Handle<v8::Object> v8_global = context->Global(); + v8_global->Set(implicit_proto_string, js_window); + + SetSecurityToken(); + + m_frame->loader()->dispatchWindowObjectAvailable(); +} + + +void V8Proxy::SetDOMException(int exception_code) +{ + if (exception_code <= 0) + return; + + ExceptionCodeDescription description; + getExceptionCodeDescription(exception_code, description); + + v8::Handle<v8::Value> exception; + switch (description.type) { + case DOMExceptionType: + exception = ToV8Object(V8ClassIndex::DOMCOREEXCEPTION, + DOMCoreException::create(description)); + break; + case RangeExceptionType: + exception = ToV8Object(V8ClassIndex::RANGEEXCEPTION, + RangeException::create(description)); + break; + case EventExceptionType: + exception = ToV8Object(V8ClassIndex::EVENTEXCEPTION, + EventException::create(description)); + break; + case XMLHttpRequestExceptionType: + exception = ToV8Object(V8ClassIndex::XMLHTTPREQUESTEXCEPTION, + XMLHttpRequestException::create(description)); + break; +#if ENABLE(SVG) + case SVGExceptionType: + exception = ToV8Object(V8ClassIndex::SVGEXCEPTION, + SVGException::create(description)); + break; +#endif +#if ENABLE(XPATH) + case XPathExceptionType: + exception = ToV8Object(V8ClassIndex::XPATHEXCEPTION, + XPathException::create(description)); + break; +#endif + } + + ASSERT(!exception.IsEmpty()); + v8::ThrowException(exception); +} + +v8::Handle<v8::Value> V8Proxy::ThrowError(ErrorType type, const char* message) +{ + switch (type) { + case RANGE_ERROR: + return v8::ThrowException(v8::Exception::RangeError(v8String(message))); + case REFERENCE_ERROR: + return v8::ThrowException( + v8::Exception::ReferenceError(v8String(message))); + case SYNTAX_ERROR: + return v8::ThrowException(v8::Exception::SyntaxError(v8String(message))); + case TYPE_ERROR: + return v8::ThrowException(v8::Exception::TypeError(v8String(message))); + case GENERAL_ERROR: + return v8::ThrowException(v8::Exception::Error(v8String(message))); + default: + ASSERT(false); + return v8::Handle<v8::Value>(); + } +} + +v8::Local<v8::Context> V8Proxy::GetContext(Frame* frame) +{ + V8Proxy* proxy = retrieve(frame); + if (!proxy) + return v8::Local<v8::Context>(); + + proxy->InitContextIfNeeded(); + return proxy->GetContext(); +} + +v8::Local<v8::Context> V8Proxy::GetCurrentContext() +{ + return v8::Context::GetCurrent(); +} + +v8::Handle<v8::Value> V8Proxy::ToV8Object(V8ClassIndex::V8WrapperType type, void* imp) +{ + ASSERT(type != V8ClassIndex::EVENTLISTENER); + ASSERT(type != V8ClassIndex::EVENTTARGET); + ASSERT(type != V8ClassIndex::EVENT); + + bool is_active_dom_object = false; + switch (type) { +#define MAKE_CASE(TYPE, NAME) case V8ClassIndex::TYPE: + DOM_NODE_TYPES(MAKE_CASE) +#if ENABLE(SVG) + SVG_NODE_TYPES(MAKE_CASE) +#endif + return NodeToV8Object(static_cast<Node*>(imp)); + case V8ClassIndex::CSSVALUE: + return CSSValueToV8Object(static_cast<CSSValue*>(imp)); + case V8ClassIndex::CSSRULE: + return CSSRuleToV8Object(static_cast<CSSRule*>(imp)); + case V8ClassIndex::STYLESHEET: + return StyleSheetToV8Object(static_cast<StyleSheet*>(imp)); + case V8ClassIndex::DOMWINDOW: + return WindowToV8Object(static_cast<DOMWindow*>(imp)); +#if ENABLE(SVG) + SVG_NONNODE_TYPES(MAKE_CASE) + if (type == V8ClassIndex::SVGELEMENTINSTANCE) + return SVGElementInstanceToV8Object(static_cast<SVGElementInstance*>(imp)); + return SVGObjectWithContextToV8Object(type, imp); +#endif + + ACTIVE_DOM_OBJECT_TYPES(MAKE_CASE) + is_active_dom_object = true; + break; + default: + break; + } + +#undef MAKE_CASE + + if (!imp) return v8::Null(); + + // Non DOM node + v8::Persistent<v8::Object> result = is_active_dom_object ? + getActiveDOMObjectMap().get(imp) : + getDOMObjectMap().get(imp); + if (result.IsEmpty()) { + v8::Local<v8::Object> v8obj = InstantiateV8Object(type, type, imp); + if (!v8obj.IsEmpty()) { + // Go through big switch statement, it has some duplications + // that were handled by code above (such as CSSVALUE, CSSRULE, etc). + switch (type) { +#define MAKE_CASE(TYPE, NAME) \ + case V8ClassIndex::TYPE: static_cast<NAME*>(imp)->ref(); break; + DOM_OBJECT_TYPES(MAKE_CASE) +#undef MAKE_CASE + default: + ASSERT(false); + } + result = v8::Persistent<v8::Object>::New(v8obj); + if (is_active_dom_object) + SetJSWrapperForActiveDOMObject(imp, result); + else + SetJSWrapperForDOMObject(imp, result); + + // Special case for non-node objects History, Location and + // Navigator. Both Safari and FF let Location and Navigator JS + // wrappers survive GC. To mimic their behaviors, V8 creates + // hidden references from the DOMWindow to these wrapper + // objects. These references get cleared when the DOMWindow is + // reused by a new page. + switch (type) { + case V8ClassIndex::HISTORY: + SetHiddenWindowReference(static_cast<History*>(imp)->frame(), + V8Custom::kDOMWindowHistoryIndex, result); + break; + case V8ClassIndex::NAVIGATOR: + SetHiddenWindowReference(static_cast<Navigator*>(imp)->frame(), + V8Custom::kDOMWindowNavigatorIndex, result); + break; + case V8ClassIndex::LOCATION: + SetHiddenWindowReference(static_cast<Location*>(imp)->frame(), + V8Custom::kDOMWindowLocationIndex, result); + break; + default: + break; + } + } + } + return result; +} + + +void V8Proxy::SetHiddenWindowReference(Frame* frame, + const int internal_index, + v8::Handle<v8::Object> jsobj) +{ + // Get DOMWindow + if (!frame) return; // Object might be detached from window + v8::Handle<v8::Context> context = GetContext(frame); + if (context.IsEmpty()) return; + + ASSERT(internal_index < V8Custom::kDOMWindowInternalFieldCount); + + v8::Handle<v8::Object> global = context->Global(); + // Look for real DOM wrapper. + global = LookupDOMWrapper(V8ClassIndex::DOMWINDOW, global); + ASSERT(!global.IsEmpty()); + ASSERT(global->GetInternalField(internal_index)->IsUndefined()); + global->SetInternalField(internal_index, jsobj); +} + + +V8ClassIndex::V8WrapperType V8Proxy::GetDOMWrapperType(v8::Handle<v8::Object> object) +{ + ASSERT(MaybeDOMWrapper(object)); + v8::Handle<v8::Value> type = + object->GetInternalField(V8Custom::kDOMWrapperTypeIndex); + return V8ClassIndex::FromInt(type->Int32Value()); +} + + +void* V8Proxy::ToNativeObjectImpl(V8ClassIndex::V8WrapperType type, + v8::Handle<v8::Value> object) +{ + // Native event listener is per frame, it cannot be handled + // by this generic function. + ASSERT(type != V8ClassIndex::EVENTLISTENER); + ASSERT(type != V8ClassIndex::EVENTTARGET); + + ASSERT(MaybeDOMWrapper(object)); + + switch (type) { +#define MAKE_CASE(TYPE, NAME) case V8ClassIndex::TYPE: + DOM_NODE_TYPES(MAKE_CASE) +#if ENABLE(SVG) + SVG_NODE_TYPES(MAKE_CASE) +#endif + ASSERT(false); + return NULL; + case V8ClassIndex::XMLHTTPREQUEST: + return DOMWrapperToNative<XMLHttpRequest>(object); + case V8ClassIndex::EVENT: + return DOMWrapperToNative<Event>(object); + case V8ClassIndex::CSSRULE: + return DOMWrapperToNative<CSSRule>(object); + default: + break; + } +#undef MAKE_CASE + + return DOMWrapperToNative<void>(object); +} + +v8::Handle<v8::Object> V8Proxy::LookupDOMWrapper( + V8ClassIndex::V8WrapperType type, v8::Handle<v8::Value> value) +{ + if (value.IsEmpty()) + return v8::Handle<v8::Object>(); + + v8::Handle<v8::FunctionTemplate> desc = V8Proxy::GetTemplate(type); + while (value->IsObject()) { + v8::Handle<v8::Object> object = v8::Handle<v8::Object>::Cast(value); + if (desc->HasInstance(object)) + return object; + + value = object->GetPrototype(); + } + return v8::Handle<v8::Object>(); +} + + +PassRefPtr<NodeFilter> V8Proxy::ToNativeNodeFilter(v8::Handle<v8::Value> filter) +{ + // A NodeFilter is used when walking through a DOM tree or iterating tree + // nodes. + // TODO: we may want to cache NodeFilterCondition and NodeFilter + // object, but it is minor. + // NodeFilter is passed to NodeIterator that has a ref counted pointer + // to NodeFilter. NodeFilter has a ref counted pointer to NodeFilterCondition. + // In NodeFilterCondition, filter object is persisted in its constructor, + // and disposed in its destructor. + if (!filter->IsFunction()) + return 0; + + NodeFilterCondition* cond = new V8NodeFilterCondition(filter); + return NodeFilter::create(cond); +} + + +v8::Local<v8::Object> V8Proxy::InstantiateV8Object( + V8ClassIndex::V8WrapperType desc_type, + V8ClassIndex::V8WrapperType cptr_type, + void* imp) +{ + // Make a special case for document.all + if (desc_type == V8ClassIndex::HTMLCOLLECTION && + static_cast<HTMLCollection*>(imp)->type() == HTMLCollection::DocAll) { + desc_type = V8ClassIndex::UNDETECTABLEHTMLCOLLECTION; + } + + V8Proxy* proxy = V8Proxy::retrieve(); + v8::Local<v8::Object> instance; + if (proxy) { + instance = proxy->CreateWrapperFromCache(desc_type); + } else { + v8::Local<v8::Function> function = GetTemplate(desc_type)->GetFunction(); + instance = SafeAllocation::NewInstance(function); + } + if (!instance.IsEmpty()) { + // Avoid setting the DOM wrapper for failed allocations. + SetDOMWrapper(instance, V8ClassIndex::ToInt(cptr_type), imp); + } + return instance; +} + +v8::Handle<v8::Value> V8Proxy::CheckNewLegal(const v8::Arguments& args) +{ + if (!AllowAllocation::m_current) + return ThrowError(TYPE_ERROR, "Illegal constructor"); + + return args.This(); +} + +void V8Proxy::SetDOMWrapper(v8::Handle<v8::Object> obj, int type, void* cptr) +{ + ASSERT(obj->InternalFieldCount() >= 2); + obj->SetInternalField(V8Custom::kDOMWrapperObjectIndex, WrapCPointer(cptr)); + obj->SetInternalField(V8Custom::kDOMWrapperTypeIndex, v8::Integer::New(type)); +} + + +#ifndef NDEBUG +bool V8Proxy::MaybeDOMWrapper(v8::Handle<v8::Value> value) +{ + if (value.IsEmpty() || !value->IsObject()) return false; + + v8::Handle<v8::Object> obj = v8::Handle<v8::Object>::Cast(value); + if (obj->InternalFieldCount() == 0) return false; + + ASSERT(obj->InternalFieldCount() >= + V8Custom::kDefaultWrapperInternalFieldCount); + + v8::Handle<v8::Value> type = + obj->GetInternalField(V8Custom::kDOMWrapperTypeIndex); + ASSERT(type->IsInt32()); + ASSERT(V8ClassIndex::INVALID_CLASS_INDEX < type->Int32Value() && + type->Int32Value() < V8ClassIndex::CLASSINDEX_END); + + v8::Handle<v8::Value> wrapper = + obj->GetInternalField(V8Custom::kDOMWrapperObjectIndex); + ASSERT(wrapper->IsNumber() || wrapper->IsExternal()); + + return true; +} +#endif + + +bool V8Proxy::IsDOMEventWrapper(v8::Handle<v8::Value> value) +{ + // All kinds of events use EVENT as dom type in JS wrappers. + // See EventToV8Object + return IsWrapperOfType(value, V8ClassIndex::EVENT); +} + +bool V8Proxy::IsWrapperOfType(v8::Handle<v8::Value> value, + V8ClassIndex::V8WrapperType classType) +{ + if (value.IsEmpty() || !value->IsObject()) return false; + + v8::Handle<v8::Object> obj = v8::Handle<v8::Object>::Cast(value); + if (obj->InternalFieldCount() == 0) return false; + + ASSERT(obj->InternalFieldCount() >= + V8Custom::kDefaultWrapperInternalFieldCount); + + v8::Handle<v8::Value> wrapper = + obj->GetInternalField(V8Custom::kDOMWrapperObjectIndex); + ASSERT(wrapper->IsNumber() || wrapper->IsExternal()); + + v8::Handle<v8::Value> type = + obj->GetInternalField(V8Custom::kDOMWrapperTypeIndex); + ASSERT(type->IsInt32()); + ASSERT(V8ClassIndex::INVALID_CLASS_INDEX < type->Int32Value() && + type->Int32Value() < V8ClassIndex::CLASSINDEX_END); + + return V8ClassIndex::FromInt(type->Int32Value()) == classType; +} + +#if ENABLE(VIDEO) +#define FOR_EACH_VIDEO_TAG(macro) \ + macro(audio, AUDIO) \ + macro(source, SOURCE) \ + macro(video, VIDEO) +#else +#define FOR_EACH_VIDEO_TAG(macro) +#endif + +#define FOR_EACH_TAG(macro) \ + macro(a, ANCHOR) \ + macro(applet, APPLET) \ + macro(area, AREA) \ + macro(base, BASE) \ + macro(basefont, BASEFONT) \ + macro(blockquote, BLOCKQUOTE) \ + macro(body, BODY) \ + macro(br, BR) \ + macro(button, BUTTON) \ + macro(caption, TABLECAPTION) \ + macro(col, TABLECOL) \ + macro(colgroup, TABLECOL) \ + macro(del, MOD) \ + macro(canvas, CANVAS) \ + macro(dir, DIRECTORY) \ + macro(div, DIV) \ + macro(dl, DLIST) \ + macro(embed, EMBED) \ + macro(fieldset, FIELDSET) \ + macro(font, FONT) \ + macro(form, FORM) \ + macro(frame, FRAME) \ + macro(frameset, FRAMESET) \ + macro(h1, HEADING) \ + macro(h2, HEADING) \ + macro(h3, HEADING) \ + macro(h4, HEADING) \ + macro(h5, HEADING) \ + macro(h6, HEADING) \ + macro(head, HEAD) \ + macro(hr, HR) \ + macro(html, HTML) \ + macro(img, IMAGE) \ + macro(iframe, IFRAME) \ + macro(image, IMAGE) \ + macro(input, INPUT) \ + macro(ins, MOD) \ + macro(isindex, ISINDEX) \ + macro(keygen, SELECT) \ + macro(label, LABEL) \ + macro(legend, LEGEND) \ + macro(li, LI) \ + macro(link, LINK) \ + macro(listing, PRE) \ + macro(map, MAP) \ + macro(marquee, MARQUEE) \ + macro(menu, MENU) \ + macro(meta, META) \ + macro(object, OBJECT) \ + macro(ol, OLIST) \ + macro(optgroup, OPTGROUP) \ + macro(option, OPTION) \ + macro(p, PARAGRAPH) \ + macro(param, PARAM) \ + macro(pre, PRE) \ + macro(q, QUOTE) \ + macro(script, SCRIPT) \ + macro(select, SELECT) \ + macro(style, STYLE) \ + macro(table, TABLE) \ + macro(thead, TABLESECTION) \ + macro(tbody, TABLESECTION) \ + macro(tfoot, TABLESECTION) \ + macro(td, TABLECELL) \ + macro(th, TABLECELL) \ + macro(tr, TABLEROW) \ + macro(textarea, TEXTAREA) \ + macro(title, TITLE) \ + macro(ul, ULIST) \ + macro(xmp, PRE) + +V8ClassIndex::V8WrapperType V8Proxy::GetHTMLElementType(HTMLElement* element) +{ + static HashMap<String, V8ClassIndex::V8WrapperType> map; + if (map.isEmpty()) { +#define ADD_TO_HASH_MAP(tag, name) \ + map.set(#tag, V8ClassIndex::HTML##name##ELEMENT); +FOR_EACH_TAG(ADD_TO_HASH_MAP) +#if ENABLE(VIDEO) + if (MediaPlayer::isAvailable()) { +FOR_EACH_VIDEO_TAG(ADD_TO_HASH_MAP) + } +#endif +#undef ADD_TO_HASH_MAP + } + + V8ClassIndex::V8WrapperType t = map.get(element->localName().impl()); + if (t == 0) + return V8ClassIndex::HTMLELEMENT; + return t; +} +#undef FOR_EACH_TAG + +#if ENABLE(SVG) + +#if ENABLE(SVG_ANIMATION) +#define FOR_EACH_ANIMATION_TAG(macro) \ + macro(animateColor, ANIMATECOLOR) \ + macro(animate, ANIMATE) \ + macro(animateTransform, ANIMATETRANSFORM) \ + macro(set, SET) +#else +#define FOR_EACH_ANIMATION_TAG(macro) +#endif + +#if ENABLE(SVG_FILTERS) +#define FOR_EACH_FILTERS_TAG(macro) \ + macro(feBlend, FEBLEND) \ + macro(feColorMatrix, FECOLORMATRIX) \ + macro(feComponentTransfer, FECOMPONENTTRANSFER) \ + macro(feComposite, FECOMPOSITE) \ + macro(feDiffuseLighting, FEDIFFUSELIGHTING) \ + macro(feDisplacementMap, FEDISPLACEMENTMAP) \ + macro(feDistantLight, FEDISTANTLIGHT) \ + macro(feFlood, FEFLOOD) \ + macro(feFuncA, FEFUNCA) \ + macro(feFuncB, FEFUNCB) \ + macro(feFuncG, FEFUNCG) \ + macro(feFuncR, FEFUNCR) \ + macro(feGaussianBlur, FEGAUSSIANBLUR) \ + macro(feImage, FEIMAGE) \ + macro(feMerge, FEMERGE) \ + macro(feMergeNode, FEMERGENODE) \ + macro(feOffset, FEOFFSET) \ + macro(fePointLight, FEPOINTLIGHT) \ + macro(feSpecularLighting, FESPECULARLIGHTING) \ + macro(feSpotLight, FESPOTLIGHT) \ + macro(feTile, FETILE) \ + macro(feTurbulence, FETURBULENCE) \ + macro(filter, FILTER) +#else +#define FOR_EACH_FILTERS_TAG(macro) +#endif + +#if ENABLE(SVG_FONTS) +#define FOR_EACH_FONTS_TAG(macro) \ + macro(definition-src, DEFINITIONSRC) \ + macro(font-face, FONTFACE) \ + macro(font-face-format, FONTFACEFORMAT) \ + macro(font-face-name, FONTFACENAME) \ + macro(font-face-src, FONTFACESRC) \ + macro(font-face-uri, FONTFACEURI) +#else +#define FOR_EACH_FONTS_TAG(marco) +#endif + +#if ENABLE(SVG_FOREIGN_OBJECT) +#define FOR_EACH_FOREIGN_OBJECT_TAG(macro) \ + macro(foreignObject, FOREIGNOBJECT) +#else +#define FOR_EACH_FOREIGN_OBJECT_TAG(macro) +#endif + +#if ENABLE(SVG_USE) +#define FOR_EACH_USE_TAG(macro) \ + macro(use, USE) +#else +#define FOR_EACH_USE_TAG(macro) +#endif + +#define FOR_EACH_TAG(macro) \ + FOR_EACH_ANIMATION_TAG(macro) \ + FOR_EACH_FILTERS_TAG(macro) \ + FOR_EACH_FONTS_TAG(macro) \ + FOR_EACH_FOREIGN_OBJECT_TAG(macro) \ + FOR_EACH_USE_TAG(macro) \ + macro(a, A) \ + macro(altGlyph, ALTGLYPH) \ + macro(circle, CIRCLE) \ + macro(clipPath, CLIPPATH) \ + macro(cursor, CURSOR) \ + macro(defs, DEFS) \ + macro(desc, DESC) \ + macro(ellipse, ELLIPSE) \ + macro(g, G) \ + macro(glyph, GLYPH) \ + macro(image, IMAGE) \ + macro(linearGradient, LINEARGRADIENT) \ + macro(line, LINE) \ + macro(marker, MARKER) \ + macro(mask, MASK) \ + macro(metadata, METADATA) \ + macro(path, PATH) \ + macro(pattern, PATTERN) \ + macro(polyline, POLYLINE) \ + macro(polygon, POLYGON) \ + macro(radialGradient, RADIALGRADIENT) \ + macro(rect, RECT) \ + macro(script, SCRIPT) \ + macro(stop, STOP) \ + macro(style, STYLE) \ + macro(svg, SVG) \ + macro(switch, SWITCH) \ + macro(symbol, SYMBOL) \ + macro(text, TEXT) \ + macro(textPath, TEXTPATH) \ + macro(title, TITLE) \ + macro(tref, TREF) \ + macro(tspan, TSPAN) \ + macro(view, VIEW) \ + // end of macro + +V8ClassIndex::V8WrapperType V8Proxy::GetSVGElementType(SVGElement* element) +{ + static HashMap<String, V8ClassIndex::V8WrapperType> map; + if (map.isEmpty()) { +#define ADD_TO_HASH_MAP(tag, name) \ + map.set(#tag, V8ClassIndex::SVG##name##ELEMENT); +FOR_EACH_TAG(ADD_TO_HASH_MAP) +#undef ADD_TO_HASH_MAP + } + + V8ClassIndex::V8WrapperType t = map.get(element->localName().impl()); + if (t == 0) return V8ClassIndex::SVGELEMENT; + return t; +} +#undef FOR_EACH_TAG + +#endif // ENABLE(SVG) + + +v8::Handle<v8::Value> V8Proxy::EventToV8Object(Event* event) +{ + if (!event) + return v8::Null(); + + v8::Handle<v8::Object> wrapper = getDOMObjectMap().get(event); + if (!wrapper.IsEmpty()) + return wrapper; + + V8ClassIndex::V8WrapperType type = V8ClassIndex::EVENT; + + if (event->isUIEvent()) { + if (event->isKeyboardEvent()) + type = V8ClassIndex::KEYBOARDEVENT; + else if (event->isTextEvent()) + type = V8ClassIndex::TEXTEVENT; + else if (event->isMouseEvent()) + type = V8ClassIndex::MOUSEEVENT; + else if (event->isWheelEvent()) + type = V8ClassIndex::WHEELEVENT; +#if ENABLE(SVG) + else if (event->isSVGZoomEvent()) + type = V8ClassIndex::SVGZOOMEVENT; +#endif + else + type = V8ClassIndex::UIEVENT; + } else if (event->isMutationEvent()) + type = V8ClassIndex::MUTATIONEVENT; + else if (event->isOverflowEvent()) + type = V8ClassIndex::OVERFLOWEVENT; + else if (event->isMessageEvent()) + type = V8ClassIndex::MESSAGEEVENT; + else if (event->isProgressEvent()) { + if (event->isXMLHttpRequestProgressEvent()) + type = V8ClassIndex::XMLHTTPREQUESTPROGRESSEVENT; + else + type = V8ClassIndex::PROGRESSEVENT; + } else if (event->isWebKitAnimationEvent()) + type = V8ClassIndex::WEBKITANIMATIONEVENT; + else if (event->isWebKitTransitionEvent()) + type = V8ClassIndex::WEBKITTRANSITIONEVENT; + + + v8::Handle<v8::Object> result = + InstantiateV8Object(type, V8ClassIndex::EVENT, event); + if (result.IsEmpty()) { + // Instantiation failed. Avoid updating the DOM object map and + // return null which is already handled by callers of this function + // in case the event is NULL. + return v8::Null(); + } + + event->ref(); // fast ref + SetJSWrapperForDOMObject(event, v8::Persistent<v8::Object>::New(result)); + + return result; +} + + +// Caller checks node is not null. +v8::Handle<v8::Value> V8Proxy::NodeToV8Object(Node* node) +{ + if (!node) return v8::Null(); + + v8::Handle<v8::Object> wrapper = getDOMNodeMap().get(node); + if (!wrapper.IsEmpty()) + return wrapper; + + bool is_document = false; // document type node has special handling + V8ClassIndex::V8WrapperType type; + + switch (node->nodeType()) { + case Node::ELEMENT_NODE: + if (node->isHTMLElement()) + type = GetHTMLElementType(static_cast<HTMLElement*>(node)); +#if ENABLE(SVG) + else if (node->isSVGElement()) + type = GetSVGElementType(static_cast<SVGElement*>(node)); +#endif + else + type = V8ClassIndex::ELEMENT; + break; + case Node::ATTRIBUTE_NODE: + type = V8ClassIndex::ATTR; + break; + case Node::TEXT_NODE: + type = V8ClassIndex::TEXT; + break; + case Node::CDATA_SECTION_NODE: + type = V8ClassIndex::CDATASECTION; + break; + case Node::ENTITY_NODE: + type = V8ClassIndex::ENTITY; + break; + case Node::PROCESSING_INSTRUCTION_NODE: + type = V8ClassIndex::PROCESSINGINSTRUCTION; + break; + case Node::COMMENT_NODE: + type = V8ClassIndex::COMMENT; + break; + case Node::DOCUMENT_NODE: { + is_document = true; + Document* doc = static_cast<Document*>(node); + if (doc->isHTMLDocument()) + type = V8ClassIndex::HTMLDOCUMENT; +#if ENABLE(SVG) + else if (doc->isSVGDocument()) + type = V8ClassIndex::SVGDOCUMENT; +#endif + else + type = V8ClassIndex::DOCUMENT; + break; + } + case Node::DOCUMENT_TYPE_NODE: + type = V8ClassIndex::DOCUMENTTYPE; + break; + case Node::NOTATION_NODE: + type = V8ClassIndex::NOTATION; + break; + case Node::DOCUMENT_FRAGMENT_NODE: + type = V8ClassIndex::DOCUMENTFRAGMENT; + break; + case Node::ENTITY_REFERENCE_NODE: + type = V8ClassIndex::ENTITYREFERENCE; + break; + default: + type = V8ClassIndex::NODE; + } + + // Find the context to which the node belongs and create the wrapper + // in that context. If the node is not in a document, the current + // context is used. + v8::Local<v8::Context> context; + Document* doc = node->document(); + if (doc) { + context = V8Proxy::GetContext(doc->frame()); + } + if (!context.IsEmpty()) { + context->Enter(); + } + + v8::Local<v8::Object> result = + InstantiateV8Object(type, V8ClassIndex::NODE, node); + + // Exit the node's context if it was entered. + if (!context.IsEmpty()) { + context->Exit(); + } + + if (result.IsEmpty()) { + // If instantiation failed it's important not to add the result + // to the DOM node map. Instead we return an empty handle, which + // should already be handled by callers of this function in case + // the node is NULL. + return result; + } + + node->ref(); + SetJSWrapperForDOMNode(node, v8::Persistent<v8::Object>::New(result)); + + if (is_document) { + Document* doc = static_cast<Document*>(node); + V8Proxy* proxy = V8Proxy::retrieve(doc->frame()); + if (proxy) + proxy->UpdateDocumentWrapper(result); + + if (type == V8ClassIndex::HTMLDOCUMENT) { + // Create marker object and insert it in two internal fields. + // This is used to implement temporary shadowing of + // document.all. + ASSERT(result->InternalFieldCount() == + V8Custom::kHTMLDocumentInternalFieldCount); + v8::Local<v8::Object> marker = v8::Object::New(); + result->SetInternalField(V8Custom::kHTMLDocumentMarkerIndex, marker); + result->SetInternalField(V8Custom::kHTMLDocumentShadowIndex, marker); + } + } + + return result; +} + + +// A JS object of type EventTarget can only be the following possible types: +// 1) EventTargetNode; 2) XMLHttpRequest; 3) MessagePort; 4) SVGElementInstance; +// 5) XMLHttpRequestUpload 6) Worker +// check EventTarget.h for new type conversion methods +v8::Handle<v8::Value> V8Proxy::EventTargetToV8Object(EventTarget* target) +{ + if (!target) + return v8::Null(); + +#if ENABLE(SVG) + SVGElementInstance* instance = target->toSVGElementInstance(); + if (instance) + return ToV8Object(V8ClassIndex::SVGELEMENTINSTANCE, instance); +#endif + +#if ENABLE(WORKERS) + Worker* worker = target->toWorker(); + if (worker) + return ToV8Object(V8ClassIndex::WORKER, worker); +#endif // WORKERS + +#if ENABLE(OFFLINE_WEB_APPLICATIONS) + DOMApplicationCache* app_cache = target->toDOMApplicationCache(); + if (app_cache) + return ToV8Object(V8ClassIndex::DOMAPPLICATIONCACHE, app_cache); +#endif + + Node* node = target->toNode(); + if (node) + return NodeToV8Object(node); + + // XMLHttpRequest is created within its JS counterpart. + XMLHttpRequest* xhr = target->toXMLHttpRequest(); + if (xhr) { + v8::Handle<v8::Object> wrapper = getActiveDOMObjectMap().get(xhr); + ASSERT(!wrapper.IsEmpty()); + return wrapper; + } + + // MessagePort is created within its JS counterpart + MessagePort* port = target->toMessagePort(); + if (port) { + v8::Handle<v8::Object> wrapper = getActiveDOMObjectMap().get(port); + ASSERT(!wrapper.IsEmpty()); + return wrapper; + } + + XMLHttpRequestUpload* upload = target->toXMLHttpRequestUpload(); + if (upload) { + v8::Handle<v8::Object> wrapper = getDOMObjectMap().get(upload); + ASSERT(!wrapper.IsEmpty()); + return wrapper; + } + + ASSERT(0); + return v8::Handle<v8::Value>(); +} + + +v8::Handle<v8::Value> V8Proxy::EventListenerToV8Object( + EventListener* listener) +{ + if (listener == 0) return v8::Null(); + + // TODO(fqian): can a user take a lazy event listener and set to other places? + V8AbstractEventListener* v8listener = + static_cast<V8AbstractEventListener*>(listener); + return v8listener->getListenerObject(); +} + + +v8::Handle<v8::Value> V8Proxy::DOMImplementationToV8Object( + DOMImplementation* impl) +{ + v8::Handle<v8::Object> result = + InstantiateV8Object(V8ClassIndex::DOMIMPLEMENTATION, + V8ClassIndex::DOMIMPLEMENTATION, + impl); + if (result.IsEmpty()) { + // If the instantiation failed, we ignore it and return null instead + // of returning an empty handle. + return v8::Null(); + } + return result; +} + + +v8::Handle<v8::Value> V8Proxy::StyleSheetToV8Object(StyleSheet* sheet) +{ + if (!sheet) return v8::Null(); + + v8::Handle<v8::Object> wrapper = getDOMObjectMap().get(sheet); + if (!wrapper.IsEmpty()) + return wrapper; + + V8ClassIndex::V8WrapperType type = V8ClassIndex::STYLESHEET; + if (sheet->isCSSStyleSheet()) + type = V8ClassIndex::CSSSTYLESHEET; + + v8::Handle<v8::Object> result = + InstantiateV8Object(type, V8ClassIndex::STYLESHEET, sheet); + if (!result.IsEmpty()) { + // Only update the DOM object map if the result is non-empty. + sheet->ref(); + SetJSWrapperForDOMObject(sheet, v8::Persistent<v8::Object>::New(result)); + } + + // Add a hidden reference from stylesheet object to its owner node. + Node* owner_node = sheet->ownerNode(); + if (owner_node) { + v8::Handle<v8::Object> owner = + v8::Handle<v8::Object>::Cast(NodeToV8Object(owner_node)); + result->SetInternalField(V8Custom::kStyleSheetOwnerNodeIndex, owner); + } + + return result; +} + + +v8::Handle<v8::Value> V8Proxy::CSSValueToV8Object(CSSValue* value) +{ + if (!value) return v8::Null(); + + v8::Handle<v8::Object> wrapper = getDOMObjectMap().get(value); + if (!wrapper.IsEmpty()) + return wrapper; + + V8ClassIndex::V8WrapperType type; + + if (value->isWebKitCSSTransformValue()) + type = V8ClassIndex::WEBKITCSSTRANSFORMVALUE; + else if (value->isValueList()) + type = V8ClassIndex::CSSVALUELIST; + else if (value->isPrimitiveValue()) + type = V8ClassIndex::CSSPRIMITIVEVALUE; +#if ENABLE(SVG) + else if (value->isSVGPaint()) + type = V8ClassIndex::SVGPAINT; + else if (value->isSVGColor()) + type = V8ClassIndex::SVGCOLOR; +#endif + else + type = V8ClassIndex::CSSVALUE; + + v8::Handle<v8::Object> result = + InstantiateV8Object(type, V8ClassIndex::CSSVALUE, value); + if (!result.IsEmpty()) { + // Only update the DOM object map if the result is non-empty. + value->ref(); + SetJSWrapperForDOMObject(value, v8::Persistent<v8::Object>::New(result)); + } + + return result; +} + + +v8::Handle<v8::Value> V8Proxy::CSSRuleToV8Object(CSSRule* rule) +{ + if (!rule) return v8::Null(); + + v8::Handle<v8::Object> wrapper = getDOMObjectMap().get(rule); + if (!wrapper.IsEmpty()) + return wrapper; + + V8ClassIndex::V8WrapperType type; + + switch (rule->type()) { + case CSSRule::STYLE_RULE: + type = V8ClassIndex::CSSSTYLERULE; + break; + case CSSRule::CHARSET_RULE: + type = V8ClassIndex::CSSCHARSETRULE; + break; + case CSSRule::IMPORT_RULE: + type = V8ClassIndex::CSSIMPORTRULE; + break; + case CSSRule::MEDIA_RULE: + type = V8ClassIndex::CSSMEDIARULE; + break; + case CSSRule::FONT_FACE_RULE: + type = V8ClassIndex::CSSFONTFACERULE; + break; + case CSSRule::PAGE_RULE: + type = V8ClassIndex::CSSPAGERULE; + break; + case CSSRule::VARIABLES_RULE: + type = V8ClassIndex::CSSVARIABLESRULE; + break; + case CSSRule::WEBKIT_KEYFRAME_RULE: + type = V8ClassIndex::WEBKITCSSKEYFRAMERULE; + break; + case CSSRule::WEBKIT_KEYFRAMES_RULE: + type = V8ClassIndex::WEBKITCSSKEYFRAMESRULE; + break; + default: // CSSRule::UNKNOWN_RULE + type = V8ClassIndex::CSSRULE; + break; + } + + v8::Handle<v8::Object> result = + InstantiateV8Object(type, V8ClassIndex::CSSRULE, rule); + if (!result.IsEmpty()) { + // Only update the DOM object map if the result is non-empty. + rule->ref(); + SetJSWrapperForDOMObject(rule, v8::Persistent<v8::Object>::New(result)); + } + return result; +} + +v8::Handle<v8::Value> V8Proxy::WindowToV8Object(DOMWindow* window) +{ + if (!window) return v8::Null(); + // Initializes environment of a frame, and return the global object + // of the frame. + Frame* frame = window->frame(); + if (!frame) + return v8::Handle<v8::Object>(); + + // Special case: Because of evaluateInNewContext() one DOMWindow can have + // multipe contexts and multiple global objects associated with it. When + // code running in one of those contexts accesses the window object, we + // want to return the global object associated with that context, not + // necessarily the first global object associated with that DOMWindow. + v8::Handle<v8::Context> current_context = v8::Context::GetCurrent(); + v8::Handle<v8::Object> current_global = current_context->Global(); + v8::Handle<v8::Object> windowWrapper = + LookupDOMWrapper(V8ClassIndex::DOMWINDOW, current_global); + if (!windowWrapper.IsEmpty()) + if (DOMWrapperToNative<DOMWindow>(windowWrapper) == window) + return current_global; + + // Otherwise, return the global object associated with this frame. + v8::Handle<v8::Context> context = GetContext(frame); + if (context.IsEmpty()) + return v8::Handle<v8::Object>(); + + v8::Handle<v8::Object> global = context->Global(); + ASSERT(!global.IsEmpty()); + return global; +} + +void V8Proxy::BindJSObjectToWindow(Frame* frame, + const char* name, + int type, + v8::Handle<v8::FunctionTemplate> desc, + void* imp) +{ + // Get environment. + v8::Handle<v8::Context> context = V8Proxy::GetContext(frame); + if (context.IsEmpty()) + return; // JS not enabled. + + v8::Context::Scope scope(context); + v8::Handle<v8::Object> instance = desc->GetFunction(); + SetDOMWrapper(instance, type, imp); + + v8::Handle<v8::Object> global = context->Global(); + global->Set(v8::String::New(name), instance); +} + +void V8Proxy::ProcessConsoleMessages() +{ + ConsoleMessageManager::ProcessDelayedMessages(); +} + + +// Create the utility context for holding JavaScript functions used internally +// which are not visible to JavaScript executing on the page. +void V8Proxy::CreateUtilityContext() { + ASSERT(m_utilityContext.IsEmpty()); + + v8::HandleScope scope; + v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New(); + m_utilityContext = v8::Context::New(NULL, global_template); + v8::Context::Scope context_scope(m_utilityContext); + + // Compile JavaScript function for retrieving the source line of the top + // JavaScript stack frame. + static const char* frame_source_line_source = + "function frame_source_line(exec_state) {" + " return exec_state.frame(0).sourceLine();" + "}"; + v8::Script::Compile(v8::String::New(frame_source_line_source))->Run(); + + // Compile JavaScript function for retrieving the source name of the top + // JavaScript stack frame. + static const char* frame_source_name_source = + "function frame_source_name(exec_state) {" + " var frame = exec_state.frame(0);" + " if (frame.func().resolved() && " + " frame.func().script() && " + " frame.func().script().name()) {" + " return frame.func().script().name();" + " }" + "}"; + v8::Script::Compile(v8::String::New(frame_source_name_source))->Run(); +} + + +int V8Proxy::GetSourceLineNumber() { +#if PLATFORM(ANDROID) + return 0; +#else + v8::HandleScope scope; + v8::Handle<v8::Context> utility_context = V8Proxy::GetUtilityContext(); + if (utility_context.IsEmpty()) { + return 0; + } + v8::Context::Scope context_scope(utility_context); + v8::Handle<v8::Function> frame_source_line; + frame_source_line = v8::Local<v8::Function>::Cast( + utility_context->Global()->Get(v8::String::New("frame_source_line"))); + if (frame_source_line.IsEmpty()) { + return 0; + } + v8::Handle<v8::Value> result = v8::Debug::Call(frame_source_line); + if (result.IsEmpty()) { + return 0; + } + return result->Int32Value(); +#endif +} + + +String V8Proxy::GetSourceName() { +#if PLATFORM(ANDROID) + return String(); +#else + v8::HandleScope scope; + v8::Handle<v8::Context> utility_context = GetUtilityContext(); + if (utility_context.IsEmpty()) { + return String(); + } + v8::Context::Scope context_scope(utility_context); + v8::Handle<v8::Function> frame_source_name; + frame_source_name = v8::Local<v8::Function>::Cast( + utility_context->Global()->Get(v8::String::New("frame_source_name"))); + if (frame_source_name.IsEmpty()) { + return String(); + } + return ToWebCoreString(v8::Debug::Call(frame_source_name)); +#endif +} + +void V8Proxy::RegisterExtension(v8::Extension* extension, + const String& schemeRestriction) { + v8::RegisterExtension(extension); + V8ExtensionInfo info = {schemeRestriction, extension}; + m_extensions.append(info); +} + +} // namespace WebCore diff --git a/V8Binding/binding/v8_proxy.h b/V8Binding/binding/v8_proxy.h new file mode 100644 index 0000000..17a2d1b --- /dev/null +++ b/V8Binding/binding/v8_proxy.h @@ -0,0 +1,645 @@ +// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef V8_PROXY_H__ +#define V8_PROXY_H__ + +#include <v8.h> +#include "v8_index.h" +#include "v8_custom.h" +#include "V8Utilities.h" +#include "Node.h" +#include "NodeFilter.h" +#include "PlatformString.h" // for WebCore::String +#include "ScriptSourceCode.h" // for WebCore::ScriptSourceCode +#include "SecurityOrigin.h" // for WebCore::SecurityOrigin +#include "V8DOMMap.h" +#include <wtf/Assertions.h> +#include <wtf/PassRefPtr.h> // so generated bindings don't have to +#include <wtf/Vector.h> + +#if defined(ENABLE_DOM_STATS_COUNTERS) && PLATFORM(CHROMIUM) +#include "ChromiumBridge.h" +#define INC_STATS(name) ChromiumBridge::incrementStatsCounter(name) +#else +#define INC_STATS(name) +#endif + +// FIXME: Remove the following hack when we replace all references to GetDOMObjectMap. +#define GetDOMObjectMap getDOMObjectMap + +namespace WebCore { + +class CSSStyleDeclaration; +class DOMImplementation; +class Element; +class Event; +class EventListener; +class Frame; +class HTMLCollection; +class HTMLOptionsCollection; +class HTMLElement; +class HTMLDocument; +class MediaList; +class NamedNodeMap; +class Node; +class NodeList; +class Screen; +class String; +class StyleSheet; +class SVGElement; +class DOMWindow; +class Document; +class EventTarget; +class Event; +class EventListener; +class Navigator; +class MimeType; +class MimeTypeArray; +class Plugin; +class PluginArray; +class StyleSheetList; +class CSSValue; +class CSSRule; +class CSSRuleList; +class CSSValueList; +class NodeFilter; +class ScriptExecutionContext; + +#if ENABLE(SVG) +class SVGElementInstance; +#endif + +class V8EventListener; +class V8ObjectEventListener; + +// This is a container for V8EventListener objects that also does some +// caching to speed up finding entries by v8::Object. +class V8EventListenerList { + public: + static const size_t kMaxKeyNameLength = 254; + // The name should be distinct from any other V8EventListenerList + // within the same process, and <= kMaxKeyNameLength characters. + explicit V8EventListenerList(const char* name); + ~V8EventListenerList(); + + typedef Vector<V8EventListener*>::iterator iterator; + V8EventListenerList::iterator begin(); + iterator end(); + + // In addition to adding the listener to this list, this also caches the + // V8EventListener as a hidden property on its wrapped v8 listener object, + // so we can quickly look it up later. + void add(V8EventListener*); + void remove(V8EventListener*); + V8EventListener* find(v8::Local<v8::Object>, bool isInline); + void clear(); + + private: + v8::Handle<v8::String> getKey(bool isInline); + v8::Persistent<v8::String> m_inlineKey; + v8::Persistent<v8::String> m_nonInlineKey; + Vector<V8EventListener*> m_list; +}; + + +// TODO(fqian): use standard logging facilities in WebCore. +void log_info(Frame* frame, const String& msg, const String& url); + + +#ifndef NDEBUG + +#define GlobalHandleTypeList(V) \ + V(PROXY) \ + V(NPOBJECT) \ + V(SCHEDULED_ACTION) \ + V(EVENT_LISTENER) \ + V(NODE_FILTER) \ + V(SCRIPTINSTANCE) \ + V(SCRIPTVALUE) + + +// Host information of persistent handles. +enum GlobalHandleType { +#define ENUM(name) name, + GlobalHandleTypeList(ENUM) +#undef ENUM +}; + + +class GlobalHandleInfo { + public: + GlobalHandleInfo(void* host, GlobalHandleType type) + : host_(host), type_(type) { } + void* host_; + GlobalHandleType type_; +}; + +#endif // NDEBUG + +// The following Batch structs and methods are used for setting multiple +// properties on an ObjectTemplate, used from the generated bindings +// initialization (ConfigureXXXTemplate). This greatly reduces the binary +// size by moving from code driven setup to data table driven setup. + +// BatchedAttribute translates into calls to SetAccessor() on either the +// instance or the prototype ObjectTemplate, based on |on_proto|. +struct BatchedAttribute { + const char* const name; + v8::AccessorGetter getter; + v8::AccessorSetter setter; + V8ClassIndex::V8WrapperType data; + v8::AccessControl settings; + v8::PropertyAttribute attribute; + bool on_proto; +}; + +void BatchConfigureAttributes(v8::Handle<v8::ObjectTemplate> inst, + v8::Handle<v8::ObjectTemplate> proto, + const BatchedAttribute* attrs, + size_t num_attrs); + +// BatchedConstant translates into calls to Set() for setting up an object's +// constants. It sets the constant on both the FunctionTemplate |desc| and the +// ObjectTemplate |proto|. PropertyAttributes is always ReadOnly. +struct BatchedConstant { + const char* const name; + int value; +}; + +void BatchConfigureConstants(v8::Handle<v8::FunctionTemplate> desc, + v8::Handle<v8::ObjectTemplate> proto, + const BatchedConstant* consts, + size_t num_consts); + +const int kMaxRecursionDepth = 20; + +// Information about an extension that is registered for use with V8. If scheme +// is non-empty, it contains the URL scheme the extension should be used with. +// Otherwise, the extension is used with all schemes. +struct V8ExtensionInfo { + String scheme; + v8::Extension* extension; +}; +typedef WTF::Vector<V8ExtensionInfo> V8ExtensionList; + +class V8Proxy { + public: + // The types of javascript errors that can be thrown. + enum ErrorType { + RANGE_ERROR, + REFERENCE_ERROR, + SYNTAX_ERROR, + TYPE_ERROR, + GENERAL_ERROR + }; + + explicit V8Proxy(Frame* frame) + : m_frame(frame), m_event_listeners("m_event_listeners"), + m_xhr_listeners("m_xhr_listeners"), m_inlineCode(false), + m_timerCallback(false), m_recursion(0) { } + + ~V8Proxy(); + + Frame* frame() { return m_frame; } + + // Clear page-specific data, but keep the global object identify. + void clearForNavigation(); + + // Clear page-specific data before shutting down the proxy object. + void clearForClose(); + + // Update document object of the frame. + void updateDocument(); + + // Update the security origin of a document + // (e.g., after setting docoument.domain). + void updateSecurityOrigin(); + + // Destroy the global object. + void DestroyGlobal(); + + // TODO(mpcomplete): Need comment. User Gesture related. + bool inlineCode() const { return m_inlineCode; } + void setInlineCode(bool value) { m_inlineCode = value; } + + bool timerCallback() const { return m_timerCallback; } + void setTimerCallback(bool value) { m_timerCallback = value; } + + // Has the context for this proxy been initialized? + bool ContextInitialized(); + + // Disconnects the proxy from its owner frame, + // and clears all timeouts on the DOM window. + void disconnectFrame(); + + bool isEnabled(); + + // Find/Create/Remove event listener wrappers. + PassRefPtr<V8EventListener> FindV8EventListener(v8::Local<v8::Value> listener, + bool html); + PassRefPtr<V8EventListener> FindOrCreateV8EventListener(v8::Local<v8::Value> listener, + bool html); + + PassRefPtr<V8EventListener> FindObjectEventListener(v8::Local<v8::Value> listener, + bool html); + PassRefPtr<V8EventListener> FindOrCreateObjectEventListener(v8::Local<v8::Value> listener, + bool html); + + void RemoveV8EventListener(V8EventListener* listener); + void RemoveObjectEventListener(V8ObjectEventListener* listener); + + // Protect/Unprotect JS wrappers of a DOM object. + static void GCProtect(void* dom_object); + static void GCUnprotect(void* dom_object); + + // Create a lazy event listener. + PassRefPtr<EventListener> createInlineEventListener( + const String& functionName, const String& code, Node* node); +#if ENABLE(SVG) + PassRefPtr<EventListener> createSVGEventHandler( + const String& functionName, const String& code, Node* node); + + static void SetSVGContext(void* object, SVGElement* context); + static SVGElement* GetSVGContext(void* object); +#endif + + void setEventHandlerLineno(int lineno) { m_handlerLineno = lineno; } + void finishedWithEvent(Event* event) { } + + // Evaluate JavaScript in a new context. The script gets its own global scope + // and its own prototypes for intrinsic JavaScript objects (String, Array, + // and so-on). It shares the wrappers for all DOM nodes and DOM constructors. + void evaluateInNewContext(const Vector<ScriptSourceCode>& sources); + + // Evaluate a script file in the current execution environment. + // The caller must hold an execution context. + // If cannot evalute the script, it returns an error. + v8::Local<v8::Value> evaluate(const ScriptSourceCode& source, + Node* node); + + // Run an already compiled script. + v8::Local<v8::Value> RunScript(v8::Handle<v8::Script> script, + bool inline_code); + + // Call the function with the given receiver and arguments. + v8::Local<v8::Value> CallFunction(v8::Handle<v8::Function> function, + v8::Handle<v8::Object> receiver, + int argc, + v8::Handle<v8::Value> argv[]); + + // Returns the dom constructor function for the given node type. + v8::Local<v8::Function> GetConstructor(V8ClassIndex::V8WrapperType type); + + // To create JS Wrapper objects, we create a cache of a 'boiler plate' + // object, and then simply Clone that object each time we need a new one. + // This is faster than going through the full object creation process. + v8::Local<v8::Object> CreateWrapperFromCache(V8ClassIndex::V8WrapperType type); + + // Returns the window object of the currently executing context. + static DOMWindow* retrieveWindow(); + // Returns the window object associated with a context. + static DOMWindow* retrieveWindow(v8::Handle<v8::Context> context); + // Returns V8Proxy object of the currently executing context. + static V8Proxy* retrieve(); + // Returns V8Proxy object associated with a frame. + static V8Proxy* retrieve(Frame* frame); + // Returns V8Proxy object associated with a script execution context. + static V8Proxy* retrieve(ScriptExecutionContext* context); + + // Returns the frame object of the window object associated + // with the currently executing context. + static Frame* retrieveFrame(); + // Returns the frame object of the window object associated with + // a context. + static Frame* retrieveFrame(v8::Handle<v8::Context> context); + // Returns the frame that started JS execution. + // NOTE: cannot declare retrieveActiveFrame as inline function, + // VS complains at linking time. + static Frame* retrieveActiveFrame(); + + // Returns V8 Context of a frame. If none exists, creates + // a new context. It is potentially slow and consumes memory. + static v8::Local<v8::Context> GetContext(Frame* frame); + static v8::Local<v8::Context> GetCurrentContext(); + + // If the current context causes out of memory, JavaScript setting + // is disabled and it returns true. + static bool HandleOutOfMemory(); + + // Check if the active execution context can access the target frame. + static bool CanAccessFrame(Frame* target, bool report_error); + + // Check if it is safe to access the given node from the + // current security context. + static bool CheckNodeSecurity(Node* node); + + static v8::Handle<v8::Value> CheckNewLegal(const v8::Arguments& args); + + // Create a V8 wrapper for a C pointer + static v8::Handle<v8::Value> WrapCPointer(void* cptr) { + // Represent void* as int + int addr = reinterpret_cast<int>(cptr); + ASSERT((addr & 0x01) == 0); // the address must be aligned. + return v8::Integer::New(addr >> 1); + } + + // Take C pointer out of a v8 wrapper + template <class C> + static C* ExtractCPointer(v8::Handle<v8::Value> obj) { + return static_cast<C*>(ExtractCPointerImpl(obj)); + } + + static v8::Handle<v8::Script> CompileScript(v8::Handle<v8::String> code, + const String& fileName, + int baseLine); + +#ifndef NDEBUG + // Checks if a v8 value can be a DOM wrapper + static bool MaybeDOMWrapper(v8::Handle<v8::Value> value); +#endif + + // Sets contents of a DOM wrapper. + static void SetDOMWrapper(v8::Handle<v8::Object> obj, int type, void* ptr); + + static v8::Handle<v8::Object> LookupDOMWrapper( + V8ClassIndex::V8WrapperType type, v8::Handle<v8::Value> value); + + // A helper function extract native object pointer from a DOM wrapper + // and cast to the specified type. + template <class C> + static C* DOMWrapperToNative(v8::Handle<v8::Value> object) { + ASSERT(MaybeDOMWrapper(object)); + v8::Handle<v8::Value> ptr = + v8::Handle<v8::Object>::Cast(object)->GetInternalField( + V8Custom::kDOMWrapperObjectIndex); + return ExtractCPointer<C>(ptr); + } + + // A help function extract a node type pointer from a DOM wrapper. + // Wrapped pointer must be cast to Node* first. + template <class C> + static C* DOMWrapperToNode(v8::Handle<v8::Value> value) { + ASSERT(MaybeDOMWrapper(value)); + + v8::Handle<v8::Object> object = v8::Handle<v8::Object>::Cast(value); + + ASSERT(GetDOMWrapperType(object) == V8ClassIndex::NODE); + + v8::Handle<v8::Value> wrapper = + object->GetInternalField(V8Custom::kDOMWrapperObjectIndex); + return static_cast<C*>(ExtractCPointer<Node>(wrapper)); + } + + template<typename T> + static v8::Handle<v8::Value> ToV8Object(V8ClassIndex::V8WrapperType type, PassRefPtr<T> imp) + { + return ToV8Object(type, imp.get()); + } + static v8::Handle<v8::Value> ToV8Object(V8ClassIndex::V8WrapperType type, + void* imp); + // Fast-path for Node objects. + static v8::Handle<v8::Value> NodeToV8Object(Node* node); + + template <class C> + static C* ToNativeObject(V8ClassIndex::V8WrapperType type, + v8::Handle<v8::Value> object) { + return static_cast<C*>(ToNativeObjectImpl(type, object)); + } + + static V8ClassIndex::V8WrapperType GetDOMWrapperType( + v8::Handle<v8::Object> object); + + // If the exception code is different from zero, a DOM exception is + // schedule to be thrown. + static void SetDOMException(int exception_code); + + // Schedule an error object to be thrown. + static v8::Handle<v8::Value> ThrowError(ErrorType type, const char* message); + + // Create an instance of a function descriptor and set to the global object + // as a named property. Used by v8_test_shell. + static void BindJSObjectToWindow(Frame* frame, + const char* name, + int type, + v8::Handle<v8::FunctionTemplate> desc, + void* imp); + + static v8::Handle<v8::Value> EventToV8Object(Event* event); + static Event* ToNativeEvent(v8::Handle<v8::Value> jsevent) { + if (!IsDOMEventWrapper(jsevent)) return 0; + return DOMWrapperToNative<Event>(jsevent); + } + + static v8::Handle<v8::Value> EventTargetToV8Object(EventTarget* target); + // Wrap and unwrap JS event listeners + static v8::Handle<v8::Value> EventListenerToV8Object(EventListener* target); + + // DOMImplementation is a singleton and it is handled in a special + // way. A wrapper is generated per document and stored in an + // internal field of the document. + static v8::Handle<v8::Value> DOMImplementationToV8Object( + DOMImplementation* impl); + + // Wrap JS node filter in C++ + static PassRefPtr<NodeFilter> ToNativeNodeFilter(v8::Handle<v8::Value> filter); + + static v8::Persistent<v8::FunctionTemplate> GetTemplate( + V8ClassIndex::V8WrapperType type); + + template <int tag, typename T> + static v8::Handle<v8::Value> ConstructDOMObject(const v8::Arguments& args); + + // Checks whether a DOM object has a JS wrapper. + static bool DOMObjectHasJSWrapper(void* obj); + // Set JS wrapper of a DOM object, the caller in charge of increase ref. + static void SetJSWrapperForDOMObject(void* obj, + v8::Persistent<v8::Object> wrapper); + static void SetJSWrapperForActiveDOMObject(void* obj, + v8::Persistent<v8::Object> wrapper); + static void SetJSWrapperForDOMNode(Node* node, + v8::Persistent<v8::Object> wrapper); + + // Process any pending JavaScript console messages. + static void ProcessConsoleMessages(); + +#ifndef NDEBUG + // For debugging and leak detection purpose + static void RegisterGlobalHandle(GlobalHandleType type, + void* host, + v8::Persistent<v8::Value> handle); + static void UnregisterGlobalHandle(void* host, + v8::Persistent<v8::Value> handle); +#endif + + // Check whether a V8 value is a wrapper of type |classType|. + static bool IsWrapperOfType(v8::Handle<v8::Value> obj, + V8ClassIndex::V8WrapperType classType); + + // Function for retrieving the line number and source name for the top + // JavaScript stack frame. + static int GetSourceLineNumber(); + static String GetSourceName(); + + + // Returns a local handle of the context. + v8::Local<v8::Context> GetContext() { + return v8::Local<v8::Context>::New(m_context); + } + + // Registers an extension to be available on webpages with a particular scheme + // If the scheme argument is empty, the extension is available on all pages. + // Will only affect v8 contexts initialized after this call. Takes ownership + // of the v8::Extension object passed. + static void RegisterExtension(v8::Extension* extension, + const String& schemeRestriction); + + private: + v8::Persistent<v8::Context> createNewContext(v8::Handle<v8::Object> global); + void InitContextIfNeeded(); + void DisconnectEventListeners(); + void SetSecurityToken(); + void ClearDocumentWrapper(); + void UpdateDocumentWrapper(v8::Handle<v8::Value> wrapper); + // Dispose global handles of m_contexts and friends. + void DisposeContextHandles(); + + static bool CanAccessPrivate(DOMWindow* target); + + // Check whether a V8 value is a DOM Event wrapper + static bool IsDOMEventWrapper(v8::Handle<v8::Value> obj); + + static void* ToNativeObjectImpl(V8ClassIndex::V8WrapperType type, + v8::Handle<v8::Value> object); + + // Take C pointer out of a v8 wrapper + static void* ExtractCPointerImpl(v8::Handle<v8::Value> obj) { + ASSERT(obj->IsNumber()); + int addr = obj->Int32Value(); + return reinterpret_cast<void*>(addr << 1); + } + + + static v8::Handle<v8::Value> StyleSheetToV8Object(StyleSheet* sheet); + static v8::Handle<v8::Value> CSSValueToV8Object(CSSValue* value); + static v8::Handle<v8::Value> CSSRuleToV8Object(CSSRule* rule); + // Returns the JS wrapper of a window object, initializes the environment + // of the window frame if needed. + static v8::Handle<v8::Value> WindowToV8Object(DOMWindow* window); + +#if ENABLE(SVG) + static v8::Handle<v8::Value> SVGElementInstanceToV8Object( + SVGElementInstance* instance); + static v8::Handle<v8::Value> SVGObjectWithContextToV8Object( + V8ClassIndex::V8WrapperType type, void* object); +#endif + + // Set hidden references in a DOMWindow object of a frame. + static void SetHiddenWindowReference(Frame* frame, + const int internal_index, + v8::Handle<v8::Object> jsobj); + + static V8ClassIndex::V8WrapperType GetHTMLElementType(HTMLElement* elm); + + // The first parameter, desc_type, specifies the function descriptor + // used to create JS object. The second parameter, cptr_type, specifies + // the type of third parameter, impl, for type casting. + // For example, a HTML element has HTMLELEMENT desc_type, but always + // use NODE as cptr_type. JS wrapper stores cptr_type and impl as + // internal fields. + static v8::Local<v8::Object> InstantiateV8Object( + V8ClassIndex::V8WrapperType desc_type, + V8ClassIndex::V8WrapperType cptr_type, + void* impl); + + static const char* GetRangeExceptionName(int exception_code); + static const char* GetEventExceptionName(int exception_code); + static const char* GetXMLHttpRequestExceptionName(int exception_code); + static const char* GetDOMExceptionName(int exception_code); + +#if ENABLE(XPATH) + static const char* GetXPathExceptionName(int exception_code); +#endif + +#if ENABLE(SVG) + static V8ClassIndex::V8WrapperType GetSVGElementType(SVGElement* elm); + static const char* GetSVGExceptionName(int exception_code); +#endif + + // Create and populate the utility context. + static void CreateUtilityContext(); + + // Returns a local handle of the utility context. + static v8::Local<v8::Context> GetUtilityContext() { + if (m_utilityContext.IsEmpty()) { + CreateUtilityContext(); + } + return v8::Local<v8::Context>::New(m_utilityContext); + } + + Frame* m_frame; + + v8::Persistent<v8::Context> m_context; + // For each possible type of wrapper, we keep a boilerplate object. + // The boilerplate is used to create additional wrappers of the same type. + // We keep a single persistent handle to an array of the activated + // boilerplates. + v8::Persistent<v8::Array> m_wrapper_boilerplates; + v8::Persistent<v8::Value> m_object_prototype; + + v8::Persistent<v8::Object> m_global; + v8::Persistent<v8::Value> m_document; + + // Utility context holding JavaScript functions used internally. + static v8::Persistent<v8::Context> m_utilityContext; + + int m_handlerLineno; + + // A list of event listeners created for this frame, + // the list gets cleared when removing all timeouts. + V8EventListenerList m_event_listeners; + + // A list of event listeners create for XMLHttpRequest object for this frame, + // the list gets cleared when removing all timeouts. + V8EventListenerList m_xhr_listeners; + + // True for <a href="javascript:foo()"> and false for <script>foo()</script>. + // Only valid during execution. + bool m_inlineCode; + + // True when executing from within a timer callback. Only valid during + // execution. + bool m_timerCallback; + + // Track the recursion depth to be able to avoid too deep recursion. The V8 + // engine allows much more recursion than KJS does so we need to guard against + // excessive recursion in the binding layer. + int m_recursion; + + // List of extensions registered with the context. + static V8ExtensionList m_extensions; +}; + +template <int tag, typename T> +v8::Handle<v8::Value> V8Proxy::ConstructDOMObject(const v8::Arguments& args) { + if (!args.IsConstructCall()) { + V8Proxy::ThrowError(V8Proxy::TYPE_ERROR, + "DOM object constructor cannot be called as a function."); + return v8::Undefined(); + } + + + // Note: it's OK to let this RefPtr go out of scope because we also call + // SetDOMWrapper(), which effectively holds a reference to obj. + RefPtr<T> obj = T::create(); + V8Proxy::SetDOMWrapper(args.Holder(), tag, obj.get()); + obj->ref(); + V8Proxy::SetJSWrapperForDOMObject( + obj.get(), v8::Persistent<v8::Object>::New(args.Holder())); + return args.Holder(); +} + +} // namespace WebCore + +#endif // V8_PROXY_H__ |