| OLD | NEW |
| (Empty) |
| 1 /* | |
| 2 * Copyright (C) 2008, 2009, 2011 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 "sky/engine/config.h" | |
| 32 #include "sky/engine/bindings/core/v8/WindowProxy.h" | |
| 33 | |
| 34 #include <algorithm> | |
| 35 #include <utility> | |
| 36 | |
| 37 #include "bindings/core/v8/V8Document.h" | |
| 38 #include "bindings/core/v8/V8Window.h" | |
| 39 #include "gen/sky/platform/RuntimeEnabledFeatures.h" | |
| 40 #include "sky/engine/bindings/core/v8/DOMWrapperWorld.h" | |
| 41 #include "sky/engine/bindings/core/v8/ScriptController.h" | |
| 42 #include "sky/engine/bindings/core/v8/V8Binding.h" | |
| 43 #include "sky/engine/bindings/core/v8/V8GCForContextDispose.h" | |
| 44 #include "sky/engine/bindings/core/v8/V8HiddenValue.h" | |
| 45 #include "sky/engine/bindings/core/v8/V8Initializer.h" | |
| 46 #include "sky/engine/bindings/core/v8/V8ObjectConstructor.h" | |
| 47 #include "sky/engine/core/frame/LocalFrame.h" | |
| 48 #include "sky/engine/core/loader/FrameLoaderClient.h" | |
| 49 #include "sky/engine/platform/ScriptForbiddenScope.h" | |
| 50 #include "sky/engine/platform/TraceEvent.h" | |
| 51 #include "sky/engine/public/platform/Platform.h" | |
| 52 #include "sky/engine/wtf/Assertions.h" | |
| 53 #include "sky/engine/wtf/OwnPtr.h" | |
| 54 #include "sky/engine/wtf/StringExtras.h" | |
| 55 #include "sky/engine/wtf/text/CString.h" | |
| 56 #include "v8/include/v8-debug.h" | |
| 57 #include "v8/include/v8.h" | |
| 58 | |
| 59 namespace blink { | |
| 60 | |
| 61 PassOwnPtr<WindowProxy> WindowProxy::create(LocalFrame* frame, DOMWrapperWorld&
world, v8::Isolate* isolate) | |
| 62 { | |
| 63 return adoptPtr(new WindowProxy(frame, &world, isolate)); | |
| 64 } | |
| 65 | |
| 66 WindowProxy::WindowProxy(LocalFrame* frame, PassRefPtr<DOMWrapperWorld> world, v
8::Isolate* isolate) | |
| 67 : m_frame(frame) | |
| 68 , m_isolate(isolate) | |
| 69 , m_world(world) | |
| 70 { | |
| 71 } | |
| 72 | |
| 73 void WindowProxy::disposeContext(GlobalDetachmentBehavior behavior) | |
| 74 { | |
| 75 if (!isContextInitialized()) | |
| 76 return; | |
| 77 | |
| 78 v8::HandleScope handleScope(m_isolate); | |
| 79 v8::Handle<v8::Context> context = m_scriptState->context(); | |
| 80 m_frame->loaderClient()->willReleaseScriptContext(context); | |
| 81 | |
| 82 if (behavior == DetachGlobal) | |
| 83 context->DetachGlobal(); | |
| 84 | |
| 85 m_scriptState->disposePerContextData(); | |
| 86 | |
| 87 // It's likely that disposing the context has created a lot of | |
| 88 // garbage. Notify V8 about this so it'll have a chance of cleaning | |
| 89 // it up when idle. | |
| 90 V8GCForContextDispose::instanceTemplate().notifyContextDisposed(); | |
| 91 } | |
| 92 | |
| 93 void WindowProxy::clearForClose() | |
| 94 { | |
| 95 if (!isContextInitialized()) | |
| 96 return; | |
| 97 | |
| 98 m_document.clear(); | |
| 99 disposeContext(DoNotDetachGlobal); | |
| 100 } | |
| 101 | |
| 102 void WindowProxy::clearForNavigation() | |
| 103 { | |
| 104 if (!isContextInitialized()) | |
| 105 return; | |
| 106 | |
| 107 ScriptState::Scope scope(m_scriptState.get()); | |
| 108 | |
| 109 m_document.clear(); | |
| 110 | |
| 111 v8::Handle<v8::Object> windowWrapper = V8Window::findInstanceInPrototypeChai
n(m_global.newLocal(m_isolate), m_isolate); | |
| 112 ASSERT(!windowWrapper.IsEmpty()); | |
| 113 windowWrapper->TurnOnAccessCheck(); | |
| 114 disposeContext(DetachGlobal); | |
| 115 } | |
| 116 | |
| 117 // Create a new environment and setup the global object. | |
| 118 // | |
| 119 // The global object corresponds to a LocalDOMWindow instance. However, to | |
| 120 // allow properties of the JS LocalDOMWindow instance to be shadowed, we | |
| 121 // use a shadow object as the global object and use the JS LocalDOMWindow | |
| 122 // instance as the prototype for that shadow object. The JS LocalDOMWindow | |
| 123 // instance is undetectable from JavaScript code because the __proto__ | |
| 124 // accessors skip that object. | |
| 125 // | |
| 126 // The shadow object and the LocalDOMWindow instance are seen as one object | |
| 127 // from JavaScript. The JavaScript object that corresponds to a | |
| 128 // LocalDOMWindow instance is the shadow object. When mapping a LocalDOMWindow | |
| 129 // instance to a V8 object, we return the shadow object. | |
| 130 // | |
| 131 // To implement split-window, see | |
| 132 // 1) https://bugs.webkit.org/show_bug.cgi?id=17249 | |
| 133 // 2) https://wiki.mozilla.org/Gecko:SplitWindow | |
| 134 // 3) https://bugzilla.mozilla.org/show_bug.cgi?id=296639 | |
| 135 // we need to split the shadow object further into two objects: | |
| 136 // an outer window and an inner window. The inner window is the hidden | |
| 137 // prototype of the outer window. The inner window is the default | |
| 138 // global object of the context. A variable declared in the global | |
| 139 // scope is a property of the inner window. | |
| 140 // | |
| 141 // The outer window sticks to a LocalFrame, it is exposed to JavaScript | |
| 142 // via window.window, window.self, window.parent, etc. The outer window | |
| 143 // has a security token which is the domain. The outer window cannot | |
| 144 // have its own properties. window.foo = 'x' is delegated to the | |
| 145 // inner window. | |
| 146 // | |
| 147 // When a frame navigates to a new page, the inner window is cut off | |
| 148 // the outer window, and the outer window identify is preserved for | |
| 149 // the frame. However, a new inner window is created for the new page. | |
| 150 // If there are JS code holds a closure to the old inner window, | |
| 151 // it won't be able to reach the outer window via its global object. | |
| 152 bool WindowProxy::initializeIfNeeded() | |
| 153 { | |
| 154 if (isContextInitialized()) | |
| 155 return true; | |
| 156 | |
| 157 DOMWrapperWorld::setWorldOfInitializingWindow(m_world.get()); | |
| 158 bool result = initialize(); | |
| 159 DOMWrapperWorld::setWorldOfInitializingWindow(0); | |
| 160 return result; | |
| 161 } | |
| 162 | |
| 163 bool WindowProxy::initialize() | |
| 164 { | |
| 165 TRACE_EVENT0("v8", "WindowProxy::initialize"); | |
| 166 TRACE_EVENT_SCOPED_SAMPLING_STATE("blink", "InitializeWindow"); | |
| 167 | |
| 168 ScriptForbiddenScope::AllowUserAgentScript allowScript; | |
| 169 | |
| 170 v8::HandleScope handleScope(m_isolate); | |
| 171 | |
| 172 createContext(); | |
| 173 | |
| 174 if (!isContextInitialized()) | |
| 175 return false; | |
| 176 | |
| 177 ScriptState::Scope scope(m_scriptState.get()); | |
| 178 v8::Handle<v8::Context> context = m_scriptState->context(); | |
| 179 if (m_global.isEmpty()) { | |
| 180 m_global.set(m_isolate, context->Global()); | |
| 181 if (m_global.isEmpty()) { | |
| 182 disposeContext(DoNotDetachGlobal); | |
| 183 return false; | |
| 184 } | |
| 185 } | |
| 186 | |
| 187 if (!installDOMWindow()) { | |
| 188 disposeContext(DoNotDetachGlobal); | |
| 189 return false; | |
| 190 } | |
| 191 | |
| 192 updateDocument(); | |
| 193 m_frame->loaderClient()->didCreateScriptContext(context); | |
| 194 return true; | |
| 195 } | |
| 196 | |
| 197 void WindowProxy::createContext() | |
| 198 { | |
| 199 // Create a new environment using an empty template for the shadow | |
| 200 // object. Reuse the global object if one has been created earlier. | |
| 201 v8::Handle<v8::ObjectTemplate> globalTemplate = V8Window::getShadowObjectTem
plate(m_isolate); | |
| 202 if (globalTemplate.IsEmpty()) | |
| 203 return; | |
| 204 | |
| 205 double contextCreationStartInSeconds = currentTime(); | |
| 206 | |
| 207 // Dynamically tell v8 about our extensions now. | |
| 208 const V8Extensions& extensions = ScriptController::registeredExtensions(); | |
| 209 OwnPtr<const char*[]> extensionNames = adoptArrayPtr(new const char*[extensi
ons.size()]); | |
| 210 int index = 0; | |
| 211 for (size_t i = 0; i < extensions.size(); ++i) { | |
| 212 extensionNames[index++] = extensions[i]->name(); | |
| 213 } | |
| 214 v8::ExtensionConfiguration extensionConfiguration(index, extensionNames.get(
)); | |
| 215 | |
| 216 v8::Handle<v8::Context> context = v8::Context::New(m_isolate, &extensionConf
iguration, globalTemplate, m_global.newLocal(m_isolate)); | |
| 217 if (context.IsEmpty()) | |
| 218 return; | |
| 219 m_scriptState = ScriptState::create(context, m_world); | |
| 220 | |
| 221 double contextCreationDurationInMilliseconds = (currentTime() - contextCreat
ionStartInSeconds) * 1000; | |
| 222 const char* histogramName = "WebCore.WindowProxy.createContext.MainWorld"; | |
| 223 if (!m_world->isMainWorld()) | |
| 224 histogramName = "WebCore.WindowProxy.createContext.IsolatedWorld"; | |
| 225 blink::Platform::current()->histogramCustomCounts(histogramName, contextCrea
tionDurationInMilliseconds, 0, 10000, 50); | |
| 226 } | |
| 227 | |
| 228 static v8::Handle<v8::Object> toInnerGlobalObject(v8::Handle<v8::Context> contex
t) | |
| 229 { | |
| 230 return v8::Handle<v8::Object>::Cast(context->Global()->GetPrototype()); | |
| 231 } | |
| 232 | |
| 233 bool WindowProxy::installDOMWindow() | |
| 234 { | |
| 235 LocalDOMWindow* window = m_frame->domWindow(); | |
| 236 v8::Local<v8::Object> windowWrapper = V8ObjectConstructor::newInstance(m_iso
late, m_scriptState->perContextData()->constructorForType(&V8Window::wrapperType
Info)); | |
| 237 if (windowWrapper.IsEmpty()) | |
| 238 return false; | |
| 239 | |
| 240 V8DOMWrapper::setNativeInfoForHiddenWrapper(v8::Handle<v8::Object>::Cast(win
dowWrapper->GetPrototype()), &V8Window::wrapperTypeInfo, V8Window::toScriptWrapp
ableBase(window)); | |
| 241 | |
| 242 // Install the windowWrapper as the prototype of the innerGlobalObject. | |
| 243 // The full structure of the global object is as follows: | |
| 244 // | |
| 245 // outerGlobalObject (Empty object, remains after navigation) | |
| 246 // -- has prototype --> innerGlobalObject (Holds global variables, changes
during navigation) | |
| 247 // -- has prototype --> LocalDOMWindow instance | |
| 248 // -- has prototype --> Window.prototype | |
| 249 // -- has prototype --> Object.prototype | |
| 250 // | |
| 251 // Note: Much of this prototype structure is hidden from web content. The | |
| 252 // outer, inner, and LocalDOMWindow instance all appear to be the same | |
| 253 // JavaScript object. | |
| 254 // | |
| 255 // Note: With Oilpan, the LocalDOMWindow object is garbage collected. | |
| 256 // Persistent references to this inner global object view of the Local
DOMWindow | |
| 257 // aren't kept, as that would prevent the global object from ever bein
g released. | |
| 258 // It is safe not to do so, as the wrapper for the LocalDOMWindow bein
g installed here | |
| 259 // already keeps a persistent reference, and it along with the inner g
lobal object | |
| 260 // views of the LocalDOMWindow will die together once that wrapper cle
ars the persistent | |
| 261 // reference. | |
| 262 v8::Handle<v8::Object> innerGlobalObject = toInnerGlobalObject(m_scriptState
->context()); | |
| 263 V8DOMWrapper::setNativeInfoForHiddenWrapper(innerGlobalObject, &V8Window::wr
apperTypeInfo, V8Window::toScriptWrappableBase(window)); | |
| 264 innerGlobalObject->SetPrototype(windowWrapper); | |
| 265 V8DOMWrapper::associateObjectWithWrapper<V8Window>(PassRefPtr<LocalDOMWindow
>(window), &V8Window::wrapperTypeInfo, windowWrapper, m_isolate); | |
| 266 V8Window::installConditionallyEnabledProperties(windowWrapper, m_isolate); | |
| 267 return true; | |
| 268 } | |
| 269 | |
| 270 void WindowProxy::updateDocumentWrapper(v8::Handle<v8::Object> wrapper) | |
| 271 { | |
| 272 ASSERT(m_world->isMainWorld()); | |
| 273 m_document.set(m_isolate, wrapper); | |
| 274 } | |
| 275 | |
| 276 void WindowProxy::updateDocumentProperty() | |
| 277 { | |
| 278 ScriptState::Scope scope(m_scriptState.get()); | |
| 279 v8::Handle<v8::Context> context = m_scriptState->context(); | |
| 280 v8::Handle<v8::Value> documentWrapper = toV8(m_frame->document(), context->G
lobal(), context->GetIsolate()); | |
| 281 ASSERT(documentWrapper == m_document.newLocal(m_isolate) || m_document.isEmp
ty()); | |
| 282 if (m_document.isEmpty()) | |
| 283 updateDocumentWrapper(v8::Handle<v8::Object>::Cast(documentWrapper)); | |
| 284 | |
| 285 ASSERT(documentWrapper->IsObject()); | |
| 286 context->Global()->ForceSet(v8AtomicString(m_isolate, "document"), documentW
rapper, static_cast<v8::PropertyAttribute>(v8::ReadOnly | v8::DontDelete)); | |
| 287 | |
| 288 // We also stash a reference to the document on the inner global object so t
hat | |
| 289 // LocalDOMWindow objects we obtain from JavaScript references are guarantee
d to have | |
| 290 // live Document objects. | |
| 291 V8HiddenValue::setHiddenValue(m_isolate, toInnerGlobalObject(context), V8Hid
denValue::document(m_isolate), documentWrapper); | |
| 292 } | |
| 293 | |
| 294 void WindowProxy::updateDocument() | |
| 295 { | |
| 296 ASSERT(m_world->isMainWorld()); | |
| 297 if (!isGlobalInitialized()) | |
| 298 return; | |
| 299 if (!isContextInitialized()) | |
| 300 return; | |
| 301 updateDocumentProperty(); | |
| 302 } | |
| 303 | |
| 304 } // namespace blink | |
| OLD | NEW |