1 /* 2 * Copyright (C) 2009 Google Inc. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions are 6 * met: 7 * 8 * * Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * * Redistributions in binary form must reproduce the above 11 * copyright notice, this list of conditions and the following disclaimer 12 * in the documentation and/or other materials provided with the 13 * distribution. 14 * * Neither the name of Google Inc. nor the names of its 15 * contributors may be used to endorse or promote products derived from 16 * this software without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 */ 30 31 #include "config.h" 32 #include "bindings/v8/V8DOMWrapper.h" 33 34 #include "V8HTMLCollection.h" 35 #include "V8HTMLDocument.h" 36 #include "V8Window.h" 37 #include "bindings/v8/V8Binding.h" 38 #include "bindings/v8/V8HiddenPropertyName.h" 39 #include "bindings/v8/V8ObjectConstructor.h" 40 #include "bindings/v8/V8PerContextData.h" 41 #include "bindings/v8/V8ScriptRunner.h" 42 43 namespace WebCore { 44 45 class V8WrapperInstantiationScope { 46 public: 47 explicit V8WrapperInstantiationScope(v8::Handle<v8::Object> creationContext) 48 : m_didEnterContext(false) 49 , m_context(v8::Context::GetCurrent()) 50 { 51 // FIXME: Remove all empty creationContexts from caller sites. 52 // If a creationContext is empty, we will end up creating a new object 53 // in the context currently entered. This is wrong. 54 if (creationContext.IsEmpty()) 55 return; 56 v8::Handle<v8::Context> contextForWrapper = creationContext->CreationContext(); 57 // For performance, we enter the context only if the currently running context 58 // is different from the context that we are about to enter. 59 if (contextForWrapper == m_context) 60 return; 61 m_context = v8::Local<v8::Context>::New(contextForWrapper); 62 m_didEnterContext = true; 63 m_context->Enter(); 64 } 65 66 ~V8WrapperInstantiationScope() 67 { 68 if (!m_didEnterContext) 69 return; 70 m_context->Exit(); 71 } 72 73 v8::Handle<v8::Context> context() const { return m_context; } 74 75 private: 76 bool m_didEnterContext; 77 v8::Handle<v8::Context> m_context; 78 }; 79 80 static v8::Local<v8::Object> wrapInShadowTemplate(v8::Local<v8::Object> wrapper, Node* impl, v8::Isolate* isolate) 81 { 82 // This is only for getting a unique pointer which we can pass to privateTemplate. 83 static const char* shadowTemplateUniqueKey = "wrapInShadowTemplate"; 84 WrapperWorldType currentWorldType = worldType(isolate); 85 V8PerIsolateData* data = V8PerIsolateData::from(isolate); 86 v8::Handle<v8::FunctionTemplate> shadowTemplate = data->privateTemplateIfExists(currentWorldType, &shadowTemplateUniqueKey); 87 if (shadowTemplate.IsEmpty()) { 88 shadowTemplate = v8::FunctionTemplate::New(); 89 if (shadowTemplate.IsEmpty()) 90 return v8::Local<v8::Object>(); 91 shadowTemplate->SetClassName(v8::String::NewSymbol("HTMLDocument")); 92 shadowTemplate->Inherit(V8HTMLDocument::GetTemplate(isolate, currentWorldType)); 93 shadowTemplate->InstanceTemplate()->SetInternalFieldCount(V8HTMLDocument::internalFieldCount); 94 data->setPrivateTemplate(currentWorldType, &shadowTemplateUniqueKey, shadowTemplate); 95 } 96 97 v8::Local<v8::Function> shadowConstructor = shadowTemplate->GetFunction(); 98 if (shadowConstructor.IsEmpty()) 99 return v8::Local<v8::Object>(); 100 101 v8::Local<v8::Object> shadow = V8ScriptRunner::instantiateObject(shadowConstructor); 102 if (shadow.IsEmpty()) 103 return v8::Local<v8::Object>(); 104 shadow->SetPrototype(wrapper); 105 V8DOMWrapper::setNativeInfo(wrapper, &V8HTMLDocument::info, impl); 106 return shadow; 107 } 108 109 v8::Local<v8::Object> V8DOMWrapper::createWrapper(v8::Handle<v8::Object> creationContext, WrapperTypeInfo* type, void* impl, v8::Isolate* isolate) 110 { 111 V8WrapperInstantiationScope scope(creationContext); 112 113 V8PerContextData* perContextData = V8PerContextData::from(scope.context()); 114 v8::Local<v8::Object> wrapper = perContextData ? perContextData->createWrapperFromCache(type) : V8ObjectConstructor::newInstance(type->getTemplate(isolate, worldTypeInMainThread(isolate))->GetFunction()); 115 116 if (type == &V8HTMLDocument::info && !wrapper.IsEmpty()) 117 wrapper = wrapInShadowTemplate(wrapper, static_cast<Node*>(impl), isolate); 118 119 return wrapper; 120 } 121 122 static bool hasInternalField(v8::Handle<v8::Value> value) 123 { 124 if (value.IsEmpty() || !value->IsObject()) 125 return false; 126 return v8::Handle<v8::Object>::Cast(value)->InternalFieldCount(); 127 } 128 129 #ifndef NDEBUG 130 bool V8DOMWrapper::maybeDOMWrapper(v8::Handle<v8::Value> value) 131 { 132 if (!hasInternalField(value)) 133 return false; 134 135 v8::Handle<v8::Object> object = v8::Handle<v8::Object>::Cast(value); 136 ASSERT(object->InternalFieldCount() >= v8DefaultWrapperInternalFieldCount); 137 138 v8::HandleScope scope; 139 ASSERT(object->GetAlignedPointerFromInternalField(v8DOMWrapperObjectIndex)); 140 141 return true; 142 } 143 #endif 144 145 bool V8DOMWrapper::isDOMWrapper(v8::Handle<v8::Value> value) 146 { 147 if (value.IsEmpty() || !value->IsObject()) 148 return false; 149 150 v8::Handle<v8::Object> wrapper = v8::Handle<v8::Object>::Cast(value); 151 if (wrapper->InternalFieldCount() < v8DefaultWrapperInternalFieldCount) 152 return false; 153 ASSERT(wrapper->GetAlignedPointerFromInternalField(v8DOMWrapperObjectIndex)); 154 ASSERT(wrapper->GetAlignedPointerFromInternalField(v8DOMWrapperTypeIndex)); 155 156 // FIXME: Add class id checks. 157 return true; 158 } 159 160 bool V8DOMWrapper::isWrapperOfType(v8::Handle<v8::Value> value, WrapperTypeInfo* type) 161 { 162 if (!hasInternalField(value)) 163 return false; 164 165 v8::Handle<v8::Object> wrapper = v8::Handle<v8::Object>::Cast(value); 166 ASSERT(wrapper->InternalFieldCount() >= v8DefaultWrapperInternalFieldCount); 167 ASSERT(wrapper->GetAlignedPointerFromInternalField(v8DOMWrapperObjectIndex)); 168 169 WrapperTypeInfo* typeInfo = static_cast<WrapperTypeInfo*>(wrapper->GetAlignedPointerFromInternalField(v8DOMWrapperTypeIndex)); 170 return typeInfo == type; 171 } 172 173 } // namespace WebCore 174