blob: 7ecc29cb95d50f1f60473d27ae27fec226359abd [file] [log] [blame]
/*
* 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 "V8DOMWrapper.h"
#include "CSSMutableStyleDeclaration.h"
#if PLATFORM(CHROMIUM)
#include "ChromiumBridge.h"
#endif
#include "DOMObjectsInclude.h"
#include "DocumentLoader.h"
#include "FrameLoaderClient.h"
#include "Notification.h"
#if PLATFORM(ANDROID)
// TODO: Upstream SVG guard.
#if ENABLE(SVG)
#include "SVGElementInstance.h"
#endif
#endif
#include "ScriptController.h"
#include "V8AbstractEventListener.h"
#include "V8Binding.h"
#include "V8Collection.h"
#include "V8CustomBinding.h"
#include "V8CustomEventListener.h"
#include "V8DOMMap.h"
#include "V8DOMWindow.h"
#include "V8EventListenerList.h"
#include "V8Index.h"
#include "V8IsolatedWorld.h"
#include "V8Proxy.h"
#include "WebGLArray.h"
#include "WebGLUniformLocation.h"
#include "WorkerContextExecutionProxy.h"
#include <algorithm>
#include <utility>
#include <v8.h>
#include <v8-debug.h>
#include <wtf/Assertions.h>
#include <wtf/OwnArrayPtr.h>
#include <wtf/StdLibExtras.h>
#include <wtf/UnusedParam.h>
namespace WebCore {
typedef HashMap<Node*, v8::Object*> DOMNodeMap;
typedef HashMap<void*, v8::Object*> DOMObjectMap;
// Get the string 'toString'.
static v8::Persistent<v8::String> GetToStringName()
{
DEFINE_STATIC_LOCAL(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> value = args.Callee()->Get(GetToStringName());
if (!value->IsFunction())
return v8::String::New("");
return v8::Handle<v8::Function>::Cast(value)->Call(args.This(), 0, 0);
}
#if ENABLE(SVG)
v8::Handle<v8::Value> V8DOMWrapper::convertSVGElementInstanceToV8Object(SVGElementInstance* instance)
{
if (!instance)
return v8::Null();
v8::Handle<v8::Object> existingInstance = getDOMSVGElementInstanceMap().get(instance);
if (!existingInstance.IsEmpty())
return existingInstance;
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;
}
v8::Handle<v8::Value> V8DOMWrapper::convertSVGObjectWithContextToV8Object(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> v8Object = instantiateV8Object(type, type, object);
if (!v8Object.IsEmpty()) {
result = v8::Persistent<v8::Object>::New(v8Object);
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_NOT_REACHED();
}
getDOMSVGObjectWithContextMap().set(object, result);
}
return result;
}
#endif
#if ENABLE(3D_CANVAS)
void V8DOMWrapper::setIndexedPropertiesToExternalArray(v8::Handle<v8::Object> wrapper,
int index,
void* address,
int length)
{
v8::ExternalArrayType array_type = v8::kExternalByteArray;
V8ClassIndex::V8WrapperType classIndex = V8ClassIndex::FromInt(index);
switch (classIndex) {
case V8ClassIndex::WEBGLBYTEARRAY:
array_type = v8::kExternalByteArray;
break;
case V8ClassIndex::WEBGLUNSIGNEDBYTEARRAY:
array_type = v8::kExternalUnsignedByteArray;
break;
case V8ClassIndex::WEBGLSHORTARRAY:
array_type = v8::kExternalShortArray;
break;
case V8ClassIndex::WEBGLUNSIGNEDSHORTARRAY:
array_type = v8::kExternalUnsignedShortArray;
break;
case V8ClassIndex::WEBGLINTARRAY:
array_type = v8::kExternalIntArray;
break;
case V8ClassIndex::WEBGLUNSIGNEDINTARRAY:
array_type = v8::kExternalUnsignedIntArray;
break;
case V8ClassIndex::WEBGLFLOATARRAY:
array_type = v8::kExternalFloatArray;
break;
default:
ASSERT_NOT_REACHED();
}
wrapper->SetIndexedPropertiesToExternalArrayData(address,
array_type,
length);
}
#endif
bool V8DOMWrapper::domObjectHasJSWrapper(void* object)
{
return getDOMObjectMap().contains(object) || getActiveDOMObjectMap().contains(object);
}
v8::Persistent<v8::Object> V8DOMWrapper::jsWrapperForDOMObject(void* object)
{
v8::Persistent<v8::Object> wrapper = getDOMObjectMap().get(object);
ASSERT(!wrapper.IsEmpty());
return wrapper;
}
v8::Persistent<v8::Object> V8DOMWrapper::jsWrapperForActiveDOMObject(void* object)
{
v8::Persistent<v8::Object> wrapper = getActiveDOMObjectMap().get(object);
ASSERT(!wrapper.IsEmpty());
return wrapper;
}
// The caller must have increased obj's ref count.
void V8DOMWrapper::setJSWrapperForDOMObject(void* object, v8::Persistent<v8::Object> wrapper)
{
ASSERT(V8DOMWrapper::maybeDOMWrapper(wrapper));
#ifndef NDEBUG
V8ClassIndex::V8WrapperType type = V8DOMWrapper::domWrapperType(wrapper);
switch (type) {
#define MAKE_CASE(TYPE, NAME) case V8ClassIndex::TYPE:
ACTIVE_DOM_OBJECT_TYPES(MAKE_CASE)
ASSERT_NOT_REACHED();
#undef MAKE_CASE
default:
break;
}
#endif
getDOMObjectMap().set(object, wrapper);
}
// The caller must have increased obj's ref count.
void V8DOMWrapper::setJSWrapperForActiveDOMObject(void* object, v8::Persistent<v8::Object> wrapper)
{
ASSERT(V8DOMWrapper::maybeDOMWrapper(wrapper));
#ifndef NDEBUG
V8ClassIndex::V8WrapperType type = V8DOMWrapper::domWrapperType(wrapper);
switch (type) {
#define MAKE_CASE(TYPE, NAME) case V8ClassIndex::TYPE: break;
ACTIVE_DOM_OBJECT_TYPES(MAKE_CASE)
default:
ASSERT_NOT_REACHED();
#undef MAKE_CASE
}
#endif
getActiveDOMObjectMap().set(object, wrapper);
}
// The caller must have increased node's ref count.
void V8DOMWrapper::setJSWrapperForDOMNode(Node* node, v8::Persistent<v8::Object> wrapper)
{
ASSERT(V8DOMWrapper::maybeDOMWrapper(wrapper));
getDOMNodeMap().set(node, wrapper);
}
v8::Persistent<v8::FunctionTemplate> V8DOMWrapper::getTemplate(V8ClassIndex::V8WrapperType type)
{
v8::Persistent<v8::FunctionTemplate>* cacheCell = V8ClassIndex::GetCache(type);
if (!cacheCell->IsEmpty())
return *cacheCell;
// Not in the cache.
FunctionTemplateFactory factory = V8ClassIndex::GetFactory(type);
v8::Persistent<v8::FunctionTemplate> descriptor = 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.
DEFINE_STATIC_LOCAL(v8::Persistent<v8::FunctionTemplate>, toStringTemplate, ());
if (toStringTemplate.IsEmpty())
toStringTemplate = v8::Persistent<v8::FunctionTemplate>::New(v8::FunctionTemplate::New(ConstructorToString));
descriptor->Set(GetToStringName(), toStringTemplate);
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.
descriptor->InstanceTemplate()->SetNamedPropertyHandler( USE_NAMED_PROPERTY_GETTER(CSSStyleDeclaration), USE_NAMED_PROPERTY_SETTER(CSSStyleDeclaration));
setCollectionStringIndexedGetter<CSSStyleDeclaration>(descriptor);
break;
case V8ClassIndex::CSSRULELIST:
setCollectionIndexedGetter<CSSRuleList, CSSRule>(descriptor, V8ClassIndex::CSSRULE);
break;
case V8ClassIndex::CSSVALUELIST:
setCollectionIndexedGetter<CSSValueList, CSSValue>(descriptor, V8ClassIndex::CSSVALUE);
break;
case V8ClassIndex::CSSVARIABLESDECLARATION:
setCollectionStringIndexedGetter<CSSVariablesDeclaration>(descriptor);
break;
case V8ClassIndex::WEBKITCSSTRANSFORMVALUE:
setCollectionIndexedGetter<WebKitCSSTransformValue, CSSValue>(descriptor, V8ClassIndex::CSSVALUE);
break;
case V8ClassIndex::HTMLALLCOLLECTION:
descriptor->InstanceTemplate()->MarkAsUndetectable(); // fall through
case V8ClassIndex::HTMLCOLLECTION:
descriptor->InstanceTemplate()->SetNamedPropertyHandler(USE_NAMED_PROPERTY_GETTER(HTMLCollection));
descriptor->InstanceTemplate()->SetCallAsFunctionHandler(USE_CALLBACK(HTMLCollectionCallAsFunction));
setCollectionIndexedGetter<HTMLCollection, Node>(descriptor, V8ClassIndex::NODE);
break;
case V8ClassIndex::HTMLOPTIONSCOLLECTION:
descriptor->InstanceTemplate()->SetNamedPropertyHandler(USE_NAMED_PROPERTY_GETTER(HTMLCollection));
descriptor->InstanceTemplate()->SetIndexedPropertyHandler(USE_INDEXED_PROPERTY_GETTER(HTMLOptionsCollection), USE_INDEXED_PROPERTY_SETTER(HTMLOptionsCollection));
descriptor->InstanceTemplate()->SetCallAsFunctionHandler(USE_CALLBACK(HTMLCollectionCallAsFunction));
break;
case V8ClassIndex::HTMLSELECTELEMENT:
descriptor->InstanceTemplate()->SetNamedPropertyHandler(USE_NAMED_PROPERTY_GETTER(HTMLSelectElementCollection));
descriptor->InstanceTemplate()->SetIndexedPropertyHandler(nodeCollectionIndexedPropertyGetter<HTMLSelectElement>, USE_INDEXED_PROPERTY_SETTER(HTMLSelectElementCollection),
0, 0, nodeCollectionIndexedPropertyEnumerator<HTMLSelectElement>, v8::Integer::New(V8ClassIndex::NODE));
break;
case V8ClassIndex::HTMLDOCUMENT: {
descriptor->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> instanceTemplate = descriptor->InstanceTemplate();
ASSERT(instanceTemplate->InternalFieldCount() == V8Custom::kNodeMinimumInternalFieldCount);
instanceTemplate->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> instanceTemplate = descriptor->InstanceTemplate();
ASSERT(instanceTemplate->InternalFieldCount() == V8Custom::kNodeMinimumInternalFieldCount);
instanceTemplate->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.
descriptor->InstanceTemplate()->SetNamedPropertyHandler(USE_NAMED_PROPERTY_GETTER(HTMLPlugInElement), USE_NAMED_PROPERTY_SETTER(HTMLPlugInElement));
descriptor->InstanceTemplate()->SetIndexedPropertyHandler(USE_INDEXED_PROPERTY_GETTER(HTMLPlugInElement), USE_INDEXED_PROPERTY_SETTER(HTMLPlugInElement));
descriptor->InstanceTemplate()->SetCallAsFunctionHandler(USE_CALLBACK(HTMLPlugInElement));
break;
case V8ClassIndex::HTMLFRAMESETELEMENT:
descriptor->InstanceTemplate()->SetNamedPropertyHandler(USE_NAMED_PROPERTY_GETTER(HTMLFrameSetElement));
break;
case V8ClassIndex::HTMLFORMELEMENT:
descriptor->InstanceTemplate()->SetNamedPropertyHandler(USE_NAMED_PROPERTY_GETTER(HTMLFormElement));
descriptor->InstanceTemplate()->SetIndexedPropertyHandler(USE_INDEXED_PROPERTY_GETTER(HTMLFormElement), 0, 0, 0, nodeCollectionIndexedPropertyEnumerator<HTMLFormElement>, v8::Integer::New(V8ClassIndex::NODE));
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> instanceTemplate = descriptor->InstanceTemplate();
ASSERT(instanceTemplate->InternalFieldCount() == V8Custom::kDefaultWrapperInternalFieldCount);
instanceTemplate->SetInternalFieldCount(V8Custom::kStyleSheetInternalFieldCount);
break;
}
case V8ClassIndex::MEDIALIST:
setCollectionStringOrNullIndexedGetter<MediaList>(descriptor);
break;
case V8ClassIndex::MIMETYPEARRAY:
setCollectionIndexedAndNamedGetters<MimeTypeArray, MimeType>(descriptor, V8ClassIndex::MIMETYPE);
break;
case V8ClassIndex::NAMEDNODEMAP: {
// We add an extra internal field to hold a reference to the owner node.
v8::Local<v8::ObjectTemplate> instanceTemplate = descriptor->InstanceTemplate();
ASSERT(instanceTemplate->InternalFieldCount() == V8Custom::kDefaultWrapperInternalFieldCount);
instanceTemplate->SetInternalFieldCount(V8Custom::kNamedNodeMapInternalFieldCount);
instanceTemplate->SetNamedPropertyHandler(USE_NAMED_PROPERTY_GETTER(NamedNodeMap));
instanceTemplate->SetIndexedPropertyHandler(USE_INDEXED_PROPERTY_GETTER(NamedNodeMap), 0, 0, 0, collectionIndexedPropertyEnumerator<NamedNodeMap>, v8::Integer::New(V8ClassIndex::NODE));
break;
}
#if ENABLE(DOM_STORAGE)
case V8ClassIndex::STORAGE:
descriptor->InstanceTemplate()->SetNamedPropertyHandler(USE_NAMED_PROPERTY_GETTER(Storage), USE_NAMED_PROPERTY_SETTER(Storage), 0, USE_NAMED_PROPERTY_DELETER(Storage), V8Custom::v8StorageNamedPropertyEnumerator);
descriptor->InstanceTemplate()->SetIndexedPropertyHandler(USE_INDEXED_PROPERTY_GETTER(Storage), USE_INDEXED_PROPERTY_SETTER(Storage), 0, USE_INDEXED_PROPERTY_DELETER(Storage));
break;
#endif
case V8ClassIndex::NODELIST:
setCollectionIndexedGetter<NodeList, Node>(descriptor, V8ClassIndex::NODE);
descriptor->InstanceTemplate()->SetNamedPropertyHandler(USE_NAMED_PROPERTY_GETTER(NodeList));
break;
case V8ClassIndex::PLUGIN:
setCollectionIndexedAndNamedGetters<Plugin, MimeType>(descriptor, V8ClassIndex::MIMETYPE);
break;
case V8ClassIndex::PLUGINARRAY:
setCollectionIndexedAndNamedGetters<PluginArray, Plugin>(descriptor, V8ClassIndex::PLUGIN);
break;
case V8ClassIndex::STYLESHEETLIST:
descriptor->InstanceTemplate()->SetNamedPropertyHandler(USE_NAMED_PROPERTY_GETTER(StyleSheetList));
setCollectionIndexedGetter<StyleSheetList, StyleSheet>(descriptor, V8ClassIndex::STYLESHEET);
break;
case V8ClassIndex::DOMWINDOW: {
v8::Local<v8::Signature> defaultSignature = v8::Signature::New(descriptor);
descriptor->PrototypeTemplate()->SetNamedPropertyHandler(USE_NAMED_PROPERTY_GETTER(DOMWindow));
descriptor->PrototypeTemplate()->SetIndexedPropertyHandler(USE_INDEXED_PROPERTY_GETTER(DOMWindow));
descriptor->PrototypeTemplate()->SetInternalFieldCount(V8Custom::kDOMWindowInternalFieldCount);
descriptor->SetHiddenPrototype(true);
// Reserve spaces for references to location, history and
// navigator objects.
v8::Local<v8::ObjectTemplate> instanceTemplate = descriptor->InstanceTemplate();
instanceTemplate->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.
instanceTemplate->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 = descriptor->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.
descriptor->SetCallHandler(USE_CALLBACK(MessageChannelConstructor));
v8::Local<v8::ObjectTemplate> instanceTemplate = descriptor->InstanceTemplate();
instanceTemplate->SetInternalFieldCount(V8Custom::kMessageChannelInternalFieldCount);
break;
}
case V8ClassIndex::MESSAGEPORT: {
// Reserve one more internal field for keeping event listeners.
v8::Local<v8::ObjectTemplate> instanceTemplate = descriptor->InstanceTemplate();
instanceTemplate->SetInternalFieldCount(V8Custom::kMessagePortInternalFieldCount);
break;
}
#if ENABLE(NOTIFICATIONS)
case V8ClassIndex::NOTIFICATION: {
// Reserve one more internal field for keeping event listeners.
v8::Local<v8::ObjectTemplate> instanceTemplate = descriptor->InstanceTemplate();
instanceTemplate->SetInternalFieldCount(V8Custom::kNotificationInternalFieldCount);
break;
}
#endif // NOTIFICATIONS
#if ENABLE(SVG)
case V8ClassIndex::SVGELEMENTINSTANCE: {
// Reserve one more internal field for keeping event listeners.
v8::Local<v8::ObjectTemplate> instanceTemplate = descriptor->InstanceTemplate();
instanceTemplate->SetInternalFieldCount(V8Custom::kSVGElementInstanceInternalFieldCount);
break;
}
#endif
#if ENABLE(WORKERS)
case V8ClassIndex::ABSTRACTWORKER: {
// Reserve one more internal field for keeping event listeners.
v8::Local<v8::ObjectTemplate> instanceTemplate = descriptor->InstanceTemplate();
instanceTemplate->SetInternalFieldCount(V8Custom::kAbstractWorkerInternalFieldCount);
break;
}
case V8ClassIndex::DEDICATEDWORKERCONTEXT: {
// Reserve internal fields for keeping event listeners.
v8::Local<v8::ObjectTemplate> instanceTemplate = descriptor->InstanceTemplate();
ASSERT(instanceTemplate->InternalFieldCount() == V8Custom::kDefaultWrapperInternalFieldCount);
instanceTemplate->SetInternalFieldCount(V8Custom::kDedicatedWorkerContextInternalFieldCount);
break;
}
case V8ClassIndex::WORKER: {
// Reserve one more internal field for keeping event listeners.
v8::Local<v8::ObjectTemplate> instanceTemplate = descriptor->InstanceTemplate();
instanceTemplate->SetInternalFieldCount(V8Custom::kWorkerInternalFieldCount);
descriptor->SetCallHandler(USE_CALLBACK(WorkerConstructor));
break;
}
case V8ClassIndex::WORKERCONTEXT: {
// Reserve one more internal field for keeping event listeners.
v8::Local<v8::ObjectTemplate> instanceTemplate = descriptor->InstanceTemplate();
ASSERT(instanceTemplate->InternalFieldCount() == V8Custom::kDefaultWrapperInternalFieldCount);
instanceTemplate->SetInternalFieldCount(V8Custom::kWorkerContextMinimumInternalFieldCount);
break;
}
#endif // WORKERS
#if ENABLE(SHARED_WORKERS)
case V8ClassIndex::SHAREDWORKER: {
// Reserve one more internal field for keeping event listeners.
v8::Local<v8::ObjectTemplate> instanceTemplate = descriptor->InstanceTemplate();
instanceTemplate->SetInternalFieldCount(V8Custom::kSharedWorkerInternalFieldCount);
descriptor->SetCallHandler(USE_CALLBACK(SharedWorkerConstructor));
break;
}
case V8ClassIndex::SHAREDWORKERCONTEXT: {
// Reserve internal fields for keeping event listeners.
v8::Local<v8::ObjectTemplate> instanceTemplate = descriptor->InstanceTemplate();
ASSERT(instanceTemplate->InternalFieldCount() == V8Custom::kDefaultWrapperInternalFieldCount);
instanceTemplate->SetInternalFieldCount(V8Custom::kSharedWorkerContextInternalFieldCount);
break;
}
#endif // SHARED_WORKERS
#if ENABLE(OFFLINE_WEB_APPLICATIONS)
case V8ClassIndex::DOMAPPLICATIONCACHE: {
// Reserve one more internal field for keeping event listeners.
v8::Local<v8::ObjectTemplate> instanceTemplate = descriptor->InstanceTemplate();
instanceTemplate->SetInternalFieldCount(V8Custom::kDOMApplicationCacheFieldCount);
break;
}
#endif
#if ENABLE(3D_CANVAS)
// The following objects are created from JavaScript.
case V8ClassIndex::WEBGLARRAYBUFFER:
descriptor->SetCallHandler(USE_CALLBACK(WebGLArrayBufferConstructor));
break;
case V8ClassIndex::WEBGLBYTEARRAY:
descriptor->SetCallHandler(USE_CALLBACK(WebGLByteArrayConstructor));
break;
case V8ClassIndex::WEBGLFLOATARRAY:
descriptor->SetCallHandler(USE_CALLBACK(WebGLFloatArrayConstructor));
break;
case V8ClassIndex::WEBGLINTARRAY:
descriptor->SetCallHandler(USE_CALLBACK(WebGLIntArrayConstructor));
break;
case V8ClassIndex::WEBGLSHORTARRAY:
descriptor->SetCallHandler(USE_CALLBACK(WebGLShortArrayConstructor));
break;
case V8ClassIndex::WEBGLUNSIGNEDBYTEARRAY:
descriptor->SetCallHandler(USE_CALLBACK(WebGLUnsignedByteArrayConstructor));
break;
case V8ClassIndex::WEBGLUNSIGNEDINTARRAY:
descriptor->SetCallHandler(USE_CALLBACK(WebGLUnsignedIntArrayConstructor));
break;
case V8ClassIndex::WEBGLUNSIGNEDSHORTARRAY:
descriptor->SetCallHandler(USE_CALLBACK(WebGLUnsignedShortArrayConstructor));
break;
#endif
case V8ClassIndex::DOMPARSER:
descriptor->SetCallHandler(USE_CALLBACK(DOMParserConstructor));
break;
case V8ClassIndex::WEBKITCSSMATRIX:
descriptor->SetCallHandler(USE_CALLBACK(WebKitCSSMatrixConstructor));
break;
case V8ClassIndex::WEBKITPOINT:
descriptor->SetCallHandler(USE_CALLBACK(WebKitPointConstructor));
break;
#if ENABLE(WEB_SOCKETS)
case V8ClassIndex::WEBSOCKET: {
// Reserve one more internal field for keeping event listeners.
v8::Local<v8::ObjectTemplate> instanceTemplate = descriptor->InstanceTemplate();
instanceTemplate->SetInternalFieldCount(V8Custom::kWebSocketInternalFieldCount);
descriptor->SetCallHandler(USE_CALLBACK(WebSocketConstructor));
break;
}
#endif
case V8ClassIndex::XMLSERIALIZER:
descriptor->SetCallHandler(USE_CALLBACK(XMLSerializerConstructor));
break;
case V8ClassIndex::XMLHTTPREQUEST: {
// Reserve one more internal field for keeping event listeners.
v8::Local<v8::ObjectTemplate> instanceTemplate = descriptor->InstanceTemplate();
instanceTemplate->SetInternalFieldCount(V8Custom::kXMLHttpRequestInternalFieldCount);
descriptor->SetCallHandler(USE_CALLBACK(XMLHttpRequestConstructor));
break;
}
case V8ClassIndex::XMLHTTPREQUESTUPLOAD: {
// Reserve one more internal field for keeping event listeners.
v8::Local<v8::ObjectTemplate> instanceTemplate = descriptor->InstanceTemplate();
instanceTemplate->SetInternalFieldCount(V8Custom::kXMLHttpRequestInternalFieldCount);
break;
}
#if ENABLE(XPATH)
case V8ClassIndex::XPATHEVALUATOR:
descriptor->SetCallHandler(USE_CALLBACK(XPathEvaluatorConstructor));
break;
#endif
#if ENABLE(XSLT)
case V8ClassIndex::XSLTPROCESSOR:
descriptor->SetCallHandler(USE_CALLBACK(XSLTProcessorConstructor));
break;
#endif
#if ENABLE(TOUCH_EVENTS)
// TODO(andreip): upstream touch related changes to Chromium
case V8ClassIndex::TOUCHLIST: {
v8::Local<v8::ObjectTemplate> instanceTemplate = descriptor->InstanceTemplate();
instanceTemplate->SetIndexedPropertyHandler(USE_INDEXED_PROPERTY_GETTER(TouchList));
break;
}
#endif
case V8ClassIndex::CLIENTRECTLIST:
descriptor->InstanceTemplate()->SetIndexedPropertyHandler(USE_INDEXED_PROPERTY_GETTER(ClientRectList));
break;
case V8ClassIndex::FILELIST:
descriptor->InstanceTemplate()->SetIndexedPropertyHandler(USE_INDEXED_PROPERTY_GETTER(FileList));
break;
#if ENABLE(DATAGRID)
case V8ClassIndex::DATAGRIDCOLUMNLIST:
descriptor->InstanceTemplate()->SetIndexedPropertyHandler(USE_INDEXED_PROPERTY_GETTER(DataGridColumnList));
descriptor->InstanceTemplate()->SetNamedPropertyHandler(USE_NAMED_PROPERTY_GETTER(DataGridColumnList));
break;
#endif
default:
break;
}
*cacheCell = descriptor;
return descriptor;
}
v8::Local<v8::Function> V8DOMWrapper::getConstructor(V8ClassIndex::V8WrapperType type, v8::Handle<v8::Value> objectPrototype)
{
// 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.
v8::Handle<v8::FunctionTemplate> functionTemplate = getTemplate(type);
// Getting the function might fail if we're running out of
// stack or memory.
v8::TryCatch tryCatch;
v8::Local<v8::Function> value = functionTemplate->GetFunction();
if (value.IsEmpty())
return v8::Local<v8::Function>();
// Hotmail fix, see comments above.
if (!objectPrototype.IsEmpty())
value->Set(v8::String::New("__proto__"), objectPrototype);
return value;
}
v8::Local<v8::Function> V8DOMWrapper::getConstructorForContext(V8ClassIndex::V8WrapperType type, v8::Handle<v8::Context> context)
{
// Enter the scope for this context to get the correct constructor.
v8::Context::Scope scope(context);
return getConstructor(type, V8Proxy::getHiddenObjectPrototype(context));
}
v8::Local<v8::Function> V8DOMWrapper::getConstructor(V8ClassIndex::V8WrapperType type, DOMWindow* window)
{
Frame* frame = window->frame();
if (!frame)
return v8::Local<v8::Function>();
v8::Handle<v8::Context> context = V8Proxy::context(frame);
if (context.IsEmpty())
return v8::Local<v8::Function>();
return getConstructorForContext(type, context);
}
v8::Local<v8::Function> V8DOMWrapper::getConstructor(V8ClassIndex::V8WrapperType type, WorkerContext*)
{
WorkerContextExecutionProxy* proxy = WorkerContextExecutionProxy::retrieve();
if (!proxy)
return v8::Local<v8::Function>();
v8::Handle<v8::Context> context = proxy->context();
if (context.IsEmpty())
return v8::Local<v8::Function>();
return getConstructorForContext(type, context);
}
v8::Handle<v8::Value> V8DOMWrapper::convertToV8Object(V8ClassIndex::V8WrapperType type, void* impl)
{
ASSERT(type != V8ClassIndex::EVENTLISTENER);
ASSERT(type != V8ClassIndex::EVENTTARGET);
ASSERT(type != V8ClassIndex::EVENT);
// These objects can be constructed under WorkerContextExecutionProxy. They need special
// handling, since if we proceed below V8Proxy::retrieve() will get called and will crash.
// TODO(ukai): websocket?
if ((type == V8ClassIndex::DOMCOREEXCEPTION
|| type == V8ClassIndex::RANGEEXCEPTION
|| type == V8ClassIndex::EVENTEXCEPTION
|| type == V8ClassIndex::XMLHTTPREQUESTEXCEPTION
|| type == V8ClassIndex::MESSAGEPORT)
&& WorkerContextExecutionProxy::retrieve()) {
return WorkerContextExecutionProxy::convertToV8Object(type, impl);
}
bool isActiveDomObject = 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 convertNodeToV8Object(static_cast<Node*>(impl));
case V8ClassIndex::CSSVALUE:
return convertCSSValueToV8Object(static_cast<CSSValue*>(impl));
case V8ClassIndex::CSSRULE:
return convertCSSRuleToV8Object(static_cast<CSSRule*>(impl));
case V8ClassIndex::STYLESHEET:
return convertStyleSheetToV8Object(static_cast<StyleSheet*>(impl));
case V8ClassIndex::DOMWINDOW:
return convertWindowToV8Object(static_cast<DOMWindow*>(impl));
case V8ClassIndex::NAMEDNODEMAP:
return convertNamedNodeMapToV8Object(static_cast<NamedNodeMap*>(impl));
#if ENABLE(SVG)
SVG_NONNODE_TYPES(MAKE_CASE)
if (type == V8ClassIndex::SVGELEMENTINSTANCE)
return convertSVGElementInstanceToV8Object(static_cast<SVGElementInstance*>(impl));
return convertSVGObjectWithContextToV8Object(type, impl);
#endif
ACTIVE_DOM_OBJECT_TYPES(MAKE_CASE)
isActiveDomObject = true;
break;
default:
break;
}
#undef MAKE_CASE
if (!impl)
return v8::Null();
// Non DOM node
v8::Persistent<v8::Object> result = isActiveDomObject ? getActiveDOMObjectMap().get(impl) : getDOMObjectMap().get(impl);
if (result.IsEmpty()) {
#if ENABLE(3D_CANVAS)
if (type == V8ClassIndex::WEBGLARRAY && impl) {
// Determine which subclass we are wrapping.
WebGLArray* array = reinterpret_cast<WebGLArray*>(impl);
if (array->isByteArray())
type = V8ClassIndex::WEBGLBYTEARRAY;
else if (array->isFloatArray())
type = V8ClassIndex::WEBGLFLOATARRAY;
else if (array->isIntArray())
type = V8ClassIndex::WEBGLINTARRAY;
else if (array->isShortArray())
type = V8ClassIndex::WEBGLSHORTARRAY;
else if (array->isUnsignedByteArray())
type = V8ClassIndex::WEBGLUNSIGNEDBYTEARRAY;
else if (array->isUnsignedIntArray())
type = V8ClassIndex::WEBGLUNSIGNEDINTARRAY;
else if (array->isUnsignedShortArray())
type = V8ClassIndex::WEBGLUNSIGNEDSHORTARRAY;
}
#endif
v8::Local<v8::Object> v8Object = instantiateV8Object(type, type, impl);
if (!v8Object.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*>(impl)->ref(); break;
DOM_OBJECT_TYPES(MAKE_CASE)
#undef MAKE_CASE
default:
ASSERT_NOT_REACHED();
}
result = v8::Persistent<v8::Object>::New(v8Object);
if (isActiveDomObject)
setJSWrapperForActiveDOMObject(impl, result);
else
setJSWrapperForDOMObject(impl, result);
if (type == V8ClassIndex::CANVASPIXELARRAY) {
CanvasPixelArray* pixels = reinterpret_cast<CanvasPixelArray*>(impl);
result->SetIndexedPropertiesToPixelData(pixels->data()->data(), pixels->length());
}
#if ENABLE(3D_CANVAS)
// Set up WebGLArray subclasses' accesses similarly.
switch (type) {
case V8ClassIndex::WEBGLBYTEARRAY:
case V8ClassIndex::WEBGLUNSIGNEDBYTEARRAY:
case V8ClassIndex::WEBGLSHORTARRAY:
case V8ClassIndex::WEBGLUNSIGNEDSHORTARRAY:
case V8ClassIndex::WEBGLINTARRAY:
case V8ClassIndex::WEBGLUNSIGNEDINTARRAY:
case V8ClassIndex::WEBGLFLOATARRAY: {
WebGLArray* array = reinterpret_cast<WebGLArray*>(impl);
setIndexedPropertiesToExternalArray(result,
V8ClassIndex::ToInt(type),
array->baseAddress(),
array->length());
break;
}
default:
break;
}
#endif
// Special case for non-node objects associated with a
// DOMWindow. Both Safari and FF let the JS wrappers for these
// objects survive GC. To mimic their behavior, 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::CONSOLE:
setHiddenWindowReference(static_cast<Console*>(impl)->frame(), V8Custom::kDOMWindowConsoleIndex, result);
break;
case V8ClassIndex::HISTORY:
setHiddenWindowReference(static_cast<History*>(impl)->frame(), V8Custom::kDOMWindowHistoryIndex, result);
break;
case V8ClassIndex::NAVIGATOR:
setHiddenWindowReference(static_cast<Navigator*>(impl)->frame(), V8Custom::kDOMWindowNavigatorIndex, result);
break;
case V8ClassIndex::SCREEN:
setHiddenWindowReference(static_cast<Screen*>(impl)->frame(), V8Custom::kDOMWindowScreenIndex, result);
break;
case V8ClassIndex::LOCATION:
setHiddenWindowReference(static_cast<Location*>(impl)->frame(), V8Custom::kDOMWindowLocationIndex, result);
break;
case V8ClassIndex::DOMSELECTION:
setHiddenWindowReference(static_cast<DOMSelection*>(impl)->frame(), V8Custom::kDOMWindowDOMSelectionIndex, result);
break;
case V8ClassIndex::BARINFO: {
BarInfo* barInfo = static_cast<BarInfo*>(impl);
Frame* frame = barInfo->frame();
switch (barInfo->type()) {
case BarInfo::Locationbar:
setHiddenWindowReference(frame, V8Custom::kDOMWindowLocationbarIndex, result);
break;
case BarInfo::Menubar:
setHiddenWindowReference(frame, V8Custom::kDOMWindowMenubarIndex, result);
break;
case BarInfo::Personalbar:
setHiddenWindowReference(frame, V8Custom::kDOMWindowPersonalbarIndex, result);
break;
case BarInfo::Scrollbars:
setHiddenWindowReference(frame, V8Custom::kDOMWindowScrollbarsIndex, result);
break;
case BarInfo::Statusbar:
setHiddenWindowReference(frame, V8Custom::kDOMWindowStatusbarIndex, result);
break;
case BarInfo::Toolbar:
setHiddenWindowReference(frame, V8Custom::kDOMWindowToolbarIndex, result);
break;
}
break;
}
default:
break;
}
}
}
return result;
}
void V8DOMWrapper::setHiddenWindowReference(Frame* frame, const int internalIndex, v8::Handle<v8::Object> jsObject)
{
// Get DOMWindow
if (!frame)
return; // Object might be detached from window
v8::Handle<v8::Context> context = V8Proxy::context(frame);
if (context.IsEmpty())
return;
ASSERT(internalIndex < V8Custom::kDOMWindowInternalFieldCount);
v8::Handle<v8::Object> global = context->Global();
// Look for real DOM wrapper.
global = V8DOMWrapper::lookupDOMWrapper(V8ClassIndex::DOMWINDOW, global);
ASSERT(!global.IsEmpty());
ASSERT(global->GetInternalField(internalIndex)->IsUndefined());
global->SetInternalField(internalIndex, jsObject);
}
V8ClassIndex::V8WrapperType V8DOMWrapper::domWrapperType(v8::Handle<v8::Object> object)
{
ASSERT(V8DOMWrapper::maybeDOMWrapper(object));
v8::Handle<v8::Value> type = object->GetInternalField(V8Custom::kDOMWrapperTypeIndex);
return V8ClassIndex::FromInt(type->Int32Value());
}
void* V8DOMWrapper::convertToSVGPODTypeImpl(V8ClassIndex::V8WrapperType type, v8::Handle<v8::Value> object)
{
return isWrapperOfType(object, type) ? convertDOMWrapperToNative<void>(v8::Handle<v8::Object>::Cast(object)) : 0;
}
PassRefPtr<NodeFilter> V8DOMWrapper::wrapNativeNodeFilter(v8::Handle<v8::Value> filter)
{
// A NodeFilter is used when walking through a DOM tree or iterating tree
// nodes.
// FIXME: 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* condition = new V8NodeFilterCondition(filter);
return NodeFilter::create(condition);
}
v8::Local<v8::Object> V8DOMWrapper::instantiateV8Object(V8Proxy* proxy, V8ClassIndex::V8WrapperType descriptorType, V8ClassIndex::V8WrapperType cptrType, void* impl)
{
// Make a special case for document.all
if (descriptorType == V8ClassIndex::HTMLCOLLECTION && static_cast<HTMLCollection*>(impl)->type() == DocAll)
descriptorType = V8ClassIndex::HTMLALLCOLLECTION;
if (V8IsolatedWorld::getEntered()) {
// This effectively disables the wrapper cache for isolated worlds.
proxy = 0;
// FIXME: Do we need a wrapper cache for the isolated world? We should
// see if the performance gains are worth while.
} else if (!proxy)
proxy = V8Proxy::retrieve();
v8::Local<v8::Object> instance;
if (proxy)
instance = proxy->createWrapperFromCache(descriptorType);
else {
v8::Local<v8::Function> function = getTemplate(descriptorType)->GetFunction();
instance = SafeAllocation::newInstance(function);
}
if (!instance.IsEmpty()) {
// Avoid setting the DOM wrapper for failed allocations.
setDOMWrapper(instance, V8ClassIndex::ToInt(cptrType), impl);
}
return instance;
}
#ifndef NDEBUG
bool V8DOMWrapper::maybeDOMWrapper(v8::Handle<v8::Value> value)
{
if (value.IsEmpty() || !value->IsObject())
return false;
v8::Handle<v8::Object> object = v8::Handle<v8::Object>::Cast(value);
if (!object->InternalFieldCount())
return false;
ASSERT(object->InternalFieldCount() >= V8Custom::kDefaultWrapperInternalFieldCount);
v8::Handle<v8::Value> type = object->GetInternalField(V8Custom::kDOMWrapperTypeIndex);
ASSERT(type->IsInt32());
ASSERT(V8ClassIndex::INVALID_CLASS_INDEX < type->Int32Value() && type->Int32Value() < V8ClassIndex::CLASSINDEX_END);
v8::Handle<v8::Value> wrapper = object->GetInternalField(V8Custom::kDOMWrapperObjectIndex);
ASSERT(wrapper->IsNumber() || wrapper->IsExternal());
return true;
}
#endif
bool V8DOMWrapper::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 V8DOMWrapper::isWrapperOfType(v8::Handle<v8::Value> value, V8ClassIndex::V8WrapperType classType)
{
if (value.IsEmpty() || !value->IsObject())
return false;
v8::Handle<v8::Object> object = v8::Handle<v8::Object>::Cast(value);
if (!object->InternalFieldCount())
return false;
ASSERT(object->InternalFieldCount() >= V8Custom::kDefaultWrapperInternalFieldCount);
v8::Handle<v8::Value> wrapper = object->GetInternalField(V8Custom::kDOMWrapperObjectIndex);
ASSERT(wrapper->IsNumber() || wrapper->IsExternal());
v8::Handle<v8::Value> type = object->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
#if ENABLE(DATAGRID)
#define FOR_EACH_DATAGRID_TAG(macro) \
macro(datagrid, DATAGRID) \
macro(dcell, DATAGRIDCELL) \
macro(dcol, DATAGRIDCOL) \
macro(drow, DATAGRIDROW)
#else
#define FOR_EACH_DATAGRID_TAG(macro)
#endif
#define FOR_EACH_TAG(macro) \
FOR_EACH_DATAGRID_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 V8DOMWrapper::htmlElementType(HTMLElement* element)
{
typedef HashMap<String, V8ClassIndex::V8WrapperType> WrapperTypeMap;
DEFINE_STATIC_LOCAL(WrapperTypeMap, wrapperTypeMap, ());
if (wrapperTypeMap.isEmpty()) {
#define ADD_TO_HASH_MAP(tag, name) \
wrapperTypeMap.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 type = wrapperTypeMap.get(element->localName().impl());
if (!type)
return V8ClassIndex::HTMLELEMENT;
return type;
}
#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) && ENABLE(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(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 V8DOMWrapper::svgElementType(SVGElement* element)
{
typedef HashMap<String, V8ClassIndex::V8WrapperType> WrapperTypeMap;
DEFINE_STATIC_LOCAL(WrapperTypeMap, wrapperTypeMap, ());
if (wrapperTypeMap.isEmpty()) {
#define ADD_TO_HASH_MAP(tag, name) \
wrapperTypeMap.set(#tag, V8ClassIndex::SVG##name##ELEMENT);
FOR_EACH_TAG(ADD_TO_HASH_MAP)
#undef ADD_TO_HASH_MAP
}
V8ClassIndex::V8WrapperType type = wrapperTypeMap.get(element->localName().impl());
if (!type)
return V8ClassIndex::SVGELEMENT;
return type;
}
#undef FOR_EACH_TAG
#endif // ENABLE(SVG)
v8::Handle<v8::Value> V8DOMWrapper::convertEventToV8Object(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(TOUCH_EVENTS)
// TODO(andreip): upstream touch related changes to WebKit
else if (event->isTouchEvent())
type = V8ClassIndex::TOUCHEVENT;
#endif
#if ENABLE(SVG)
else if (event->isSVGZoomEvent())
type = V8ClassIndex::SVGZOOMEVENT;
#endif
else if (event->isCompositionEvent())
type = V8ClassIndex::COMPOSITIONEVENT;
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->isPageTransitionEvent())
type = V8ClassIndex::PAGETRANSITIONEVENT;
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;
#if ENABLE(WORKERS)
else if (event->isErrorEvent())
type = V8ClassIndex::ERROREVENT;
#endif
#if ENABLE(DOM_STORAGE)
else if (event->isStorageEvent())
type = V8ClassIndex::STORAGEEVENT;
#endif
else if (event->isBeforeLoadEvent())
type = V8ClassIndex::BEFORELOADEVENT;
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;
}
static const V8ClassIndex::V8WrapperType mapping[] = {
V8ClassIndex::INVALID_CLASS_INDEX, // NONE
V8ClassIndex::INVALID_CLASS_INDEX, // ELEMENT_NODE needs special treatment
V8ClassIndex::ATTR, // ATTRIBUTE_NODE
V8ClassIndex::TEXT, // TEXT_NODE
V8ClassIndex::CDATASECTION, // CDATA_SECTION_NODE
V8ClassIndex::ENTITYREFERENCE, // ENTITY_REFERENCE_NODE
V8ClassIndex::ENTITY, // ENTITY_NODE
V8ClassIndex::PROCESSINGINSTRUCTION, // PROCESSING_INSTRUCTION_NODE
V8ClassIndex::COMMENT, // COMMENT_NODE
V8ClassIndex::INVALID_CLASS_INDEX, // DOCUMENT_NODE needs special treatment
V8ClassIndex::DOCUMENTTYPE, // DOCUMENT_TYPE_NODE
V8ClassIndex::DOCUMENTFRAGMENT, // DOCUMENT_FRAGMENT_NODE
V8ClassIndex::NOTATION, // NOTATION_NODE
V8ClassIndex::NODE, // XPATH_NAMESPACE_NODE
};
v8::Handle<v8::Value> V8DOMWrapper::convertDocumentToV8Object(Document* document)
{
// Find a proxy for this node.
//
// Note that if proxy is found, we might initialize the context which can
// instantiate a document wrapper. Therefore, we get the proxy before
// checking if the node already has a wrapper.
V8Proxy* proxy = V8Proxy::retrieve(document->frame());
if (proxy)
proxy->initContextIfNeeded();
DOMWrapperMap<Node>& domNodeMap = getDOMNodeMap();
v8::Handle<v8::Object> wrapper = domNodeMap.get(document);
if (wrapper.IsEmpty())
return convertNewNodeToV8Object(document, proxy, domNodeMap);
return wrapper;
}
v8::Handle<v8::Value> V8DOMWrapper::convertNodeToV8Object(Node* node)
{
if (!node)
return v8::Null();
Document* document = node->document();
if (node == document)
return convertDocumentToV8Object(document);
DOMWrapperMap<Node>& domNodeMap = getDOMNodeMap();
v8::Handle<v8::Object> wrapper = domNodeMap.get(node);
if (wrapper.IsEmpty())
return convertNewNodeToV8Object(node, 0, domNodeMap);
return wrapper;
}
// Caller checks node is not null.
v8::Handle<v8::Value> V8DOMWrapper::convertNewNodeToV8Object(Node* node, V8Proxy* proxy, DOMWrapperMap<Node>& domNodeMap)
{
if (!proxy && node->document())
proxy = V8Proxy::retrieve(node->document()->frame());
bool isDocument = false; // document type node has special handling
V8ClassIndex::V8WrapperType type;
Node::NodeType nodeType = node->nodeType();
if (nodeType == Node::ELEMENT_NODE) {
if (node->isHTMLElement())
type = htmlElementType(static_cast<HTMLElement*>(node));
#if ENABLE(SVG)
else if (node->isSVGElement())
type = svgElementType(static_cast<SVGElement*>(node));
#endif
else
type = V8ClassIndex::ELEMENT;
} else if (nodeType == Node::DOCUMENT_NODE) {
isDocument = true;
Document* document = static_cast<Document*>(node);
if (document->isHTMLDocument())
type = V8ClassIndex::HTMLDOCUMENT;
#if ENABLE(SVG)
else if (document->isSVGDocument())
type = V8ClassIndex::SVGDOCUMENT;
#endif
else
type = V8ClassIndex::DOCUMENT;
} else {
ASSERT(nodeType < static_cast<int>(sizeof(mapping)/sizeof(mapping[0])));
type = mapping[nodeType];
ASSERT(type != V8ClassIndex::INVALID_CLASS_INDEX);
}
v8::Handle<v8::Context> context;
if (proxy)
context = proxy->context();
// Enter the node's context and create the wrapper in that context.
if (!context.IsEmpty())
context->Enter();
v8::Local<v8::Object> result = instantiateV8Object(proxy, 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();
domNodeMap.set(node, v8::Persistent<v8::Object>::New(result));
if (isDocument) {
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 is limited to a small number of possible classes.
// Check EventTarget.h for new type conversion methods
v8::Handle<v8::Value> V8DOMWrapper::convertEventTargetToV8Object(EventTarget* target)
{
if (!target)
return v8::Null();
#if ENABLE(SVG)
SVGElementInstance* instance = target->toSVGElementInstance();
if (instance)
return convertToV8Object(V8ClassIndex::SVGELEMENTINSTANCE, instance);
#endif
#if ENABLE(WORKERS)
Worker* worker = target->toWorker();
if (worker)
return convertToV8Object(V8ClassIndex::WORKER, worker);
#endif // WORKERS
#if ENABLE(SHARED_WORKERS)
SharedWorker* sharedWorker = target->toSharedWorker();
if (sharedWorker)
return convertToV8Object(V8ClassIndex::SHAREDWORKER, sharedWorker);
#endif // SHARED_WORKERS
#if ENABLE(NOTIFICATIONS)
Notification* notification = target->toNotification();
if (notification)
return convertToV8Object(V8ClassIndex::NOTIFICATION, notification);
#endif
#if ENABLE(WEB_SOCKETS)
WebSocket* webSocket = target->toWebSocket();
if (webSocket)
return convertToV8Object(V8ClassIndex::WEBSOCKET, webSocket);
#endif
Node* node = target->toNode();
if (node)
return convertNodeToV8Object(node);
if (DOMWindow* domWindow = target->toDOMWindow())
return convertToV8Object(V8ClassIndex::DOMWINDOW, domWindow);
// XMLHttpRequest is created within its JS counterpart.
XMLHttpRequest* xmlHttpRequest = target->toXMLHttpRequest();
if (xmlHttpRequest) {
v8::Handle<v8::Object> wrapper = getActiveDOMObjectMap().get(xmlHttpRequest);
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;
}
#if ENABLE(OFFLINE_WEB_APPLICATIONS)
DOMApplicationCache* domAppCache = target->toDOMApplicationCache();
if (domAppCache)
return convertToV8Object(V8ClassIndex::DOMAPPLICATIONCACHE, domAppCache);
#endif
ASSERT(0);
return notHandledByInterceptor();
}
v8::Handle<v8::Value> V8DOMWrapper::convertEventListenerToV8Object(ScriptExecutionContext* context, EventListener* listener)
{
if (!listener)
return v8::Null();
// FIXME: can a user take a lazy event listener and set to other places?
V8AbstractEventListener* v8listener = static_cast<V8AbstractEventListener*>(listener);
return v8listener->getListenerObject(context);
}
PassRefPtr<EventListener> V8DOMWrapper::getEventListener(Node* node, v8::Local<v8::Value> value, bool isAttribute, ListenerLookupType lookup)
{
return (lookup == ListenerFindOnly) ? V8EventListenerList::findWrapper(value, isAttribute) : V8EventListenerList::findOrCreateWrapper<V8EventListener>(value, isAttribute);
}
<<<<<<< HEAD:WebCore/bindings/v8/V8DOMWrapper.cpp
#if PLATFORM(ANDROID)
=======
>>>>>>> webkit.org at r51976:WebCore/bindings/v8/V8DOMWrapper.cpp
#if ENABLE(SVG)
PassRefPtr<EventListener> V8DOMWrapper::getEventListener(SVGElementInstance* element, v8::Local<v8::Value> value, bool isAttribute, ListenerLookupType lookup)
{
return getEventListener(element->correspondingElement(), value, isAttribute, lookup);
}
#endif
<<<<<<< HEAD:WebCore/bindings/v8/V8DOMWrapper.cpp
#endif
=======
>>>>>>> webkit.org at r51976:WebCore/bindings/v8/V8DOMWrapper.cpp
PassRefPtr<EventListener> V8DOMWrapper::getEventListener(AbstractWorker* worker, v8::Local<v8::Value> value, bool isAttribute, ListenerLookupType lookup)
{
if (worker->scriptExecutionContext()->isWorkerContext()) {
WorkerContextExecutionProxy* workerContextProxy = WorkerContextExecutionProxy::retrieve();
ASSERT(workerContextProxy);
return workerContextProxy->findOrCreateEventListener(value, isAttribute, lookup == ListenerFindOnly);
}
return (lookup == ListenerFindOnly) ? V8EventListenerList::findWrapper(value, isAttribute) : V8EventListenerList::findOrCreateWrapper<V8EventListener>(value, isAttribute);
}
#if ENABLE(NOTIFICATIONS)
PassRefPtr<EventListener> V8DOMWrapper::getEventListener(Notification* notification, v8::Local<v8::Value> value, bool isAttribute, ListenerLookupType lookup)
{
if (notification->scriptExecutionContext()->isWorkerContext()) {
WorkerContextExecutionProxy* workerContextProxy = WorkerContextExecutionProxy::retrieve();
ASSERT(workerContextProxy);
return workerContextProxy->findOrCreateEventListener(value, isAttribute, lookup == ListenerFindOnly);
}
return (lookup == ListenerFindOnly) ? V8EventListenerList::findWrapper(value, isAttribute) : V8EventListenerList::findOrCreateWrapper<V8EventListener>(value, isAttribute);
}
#endif
PassRefPtr<EventListener> V8DOMWrapper::getEventListener(WorkerContext* workerContext, v8::Local<v8::Value> value, bool isAttribute, ListenerLookupType lookup)
{
WorkerContextExecutionProxy* workerContextProxy = workerContext->script()->proxy();
if (workerContextProxy)
return workerContextProxy->findOrCreateEventListener(value, isAttribute, lookup == ListenerFindOnly);
return 0;
}
PassRefPtr<EventListener> V8DOMWrapper::getEventListener(XMLHttpRequestUpload* upload, v8::Local<v8::Value> value, bool isAttribute, ListenerLookupType lookup)
{
return getEventListener(upload->associatedXMLHttpRequest(), value, isAttribute, lookup);
}
PassRefPtr<EventListener> V8DOMWrapper::getEventListener(EventTarget* eventTarget, v8::Local<v8::Value> value, bool isAttribute, ListenerLookupType lookup)
{
if (V8Proxy::retrieve(eventTarget->scriptExecutionContext()))
return (lookup == ListenerFindOnly) ? V8EventListenerList::findWrapper(value, isAttribute) : V8EventListenerList::findOrCreateWrapper<V8EventListener>(value, isAttribute);
#if ENABLE(WORKERS)
WorkerContextExecutionProxy* workerContextProxy = WorkerContextExecutionProxy::retrieve();
if (workerContextProxy)
return workerContextProxy->findOrCreateEventListener(value, isAttribute, lookup == ListenerFindOnly);
#endif
return 0;
}
PassRefPtr<EventListener> V8DOMWrapper::getEventListener(V8Proxy* proxy, v8::Local<v8::Value> value, bool isAttribute, ListenerLookupType lookup)
{
return (lookup == ListenerFindOnly) ? V8EventListenerList::findWrapper(value, isAttribute) : V8EventListenerList::findOrCreateWrapper<V8EventListener>(value, isAttribute);
}
v8::Handle<v8::Value> V8DOMWrapper::convertDOMImplementationToV8Object(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> V8DOMWrapper::convertStyleSheetToV8Object(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* ownerNode = sheet->ownerNode();
if (ownerNode) {
v8::Handle<v8::Object> owner = v8::Handle<v8::Object>::Cast(convertNodeToV8Object(ownerNode));
result->SetInternalField(V8Custom::kStyleSheetOwnerNodeIndex, owner);
}
return result;
}
v8::Handle<v8::Value> V8DOMWrapper::convertCSSValueToV8Object(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> V8DOMWrapper::convertCSSRuleToV8Object(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> V8DOMWrapper::convertWindowToV8Object(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
// multiple 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> currentContext = v8::Context::GetCurrent();
v8::Handle<v8::Object> currentGlobal = currentContext->Global();
v8::Handle<v8::Object> windowWrapper = V8DOMWrapper::lookupDOMWrapper(V8ClassIndex::DOMWINDOW, currentGlobal);
if (!windowWrapper.IsEmpty()) {
if (convertDOMWrapperToNative<DOMWindow>(windowWrapper) == window)
return currentGlobal;
}
// Otherwise, return the global object associated with this frame.
v8::Handle<v8::Context> context = V8Proxy::context(frame);
if (context.IsEmpty())
return v8::Handle<v8::Object>();
v8::Handle<v8::Object> global = context->Global();
ASSERT(!global.IsEmpty());
return global;
}
v8::Handle<v8::Value> V8DOMWrapper::convertNamedNodeMapToV8Object(NamedNodeMap* map)
{
if (!map)
return v8::Null();
v8::Handle<v8::Object> wrapper = getDOMObjectMap().get(map);
if (!wrapper.IsEmpty())
return wrapper;
v8::Handle<v8::Object> result = instantiateV8Object(V8ClassIndex::NAMEDNODEMAP, V8ClassIndex::NAMEDNODEMAP, map);
if (result.IsEmpty())
return result;
// Only update the DOM object map if the result is non-empty.
map->ref();
setJSWrapperForDOMObject(map, v8::Persistent<v8::Object>::New(result));
// Add a hidden reference from named node map to its owner node.
if (Element* element = map->element()) {
v8::Handle<v8::Object> owner = v8::Handle<v8::Object>::Cast(convertNodeToV8Object(element));
result->SetInternalField(V8Custom::kNamedNodeMapOwnerNodeIndex, owner);
}
return result;
}
} // namespace WebCore