Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(215)

Side by Side Diff: third_party/WebKit/Source/bindings/core/v8/LocalWindowProxy.cpp

Issue 2620313002: Refactor WindowProxy into Local and Remote subclasses. (Closed)
Patch Set: Cleanup comments Created 3 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 /* 1 /*
2 * Copyright (C) 2008, 2009, 2011 Google Inc. All rights reserved. 2 * Copyright (C) 2008, 2009, 2011 Google Inc. All rights reserved.
3 * 3 *
4 * Redistribution and use in source and binary forms, with or without 4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are 5 * modification, are permitted provided that the following conditions are
6 * met: 6 * met:
7 * 7 *
8 * * Redistributions of source code must retain the above copyright 8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer. 9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above 10 * * Redistributions in binary form must reproduce the above
(...skipping 10 matching lines...) Expand all
21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 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. 28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */ 29 */
30 30
31 #include "bindings/core/v8/WindowProxy.h" 31 #include "bindings/core/v8/LocalWindowProxy.h"
32 32
33 #include "bindings/core/v8/ConditionalFeatures.h" 33 #include "bindings/core/v8/ConditionalFeatures.h"
34 #include "bindings/core/v8/DOMWrapperWorld.h" 34 #include "bindings/core/v8/DOMWrapperWorld.h"
35 #include "bindings/core/v8/ScriptController.h" 35 #include "bindings/core/v8/ScriptController.h"
36 #include "bindings/core/v8/ToV8.h" 36 #include "bindings/core/v8/ToV8.h"
37 #include "bindings/core/v8/V8Binding.h" 37 #include "bindings/core/v8/V8Binding.h"
38 #include "bindings/core/v8/V8DOMActivityLogger.h" 38 #include "bindings/core/v8/V8DOMActivityLogger.h"
39 #include "bindings/core/v8/V8Document.h"
40 #include "bindings/core/v8/V8GCForContextDispose.h"
41 #include "bindings/core/v8/V8HTMLCollection.h"
42 #include "bindings/core/v8/V8HTMLDocument.h" 39 #include "bindings/core/v8/V8HTMLDocument.h"
43 #include "bindings/core/v8/V8HiddenValue.h" 40 #include "bindings/core/v8/V8HiddenValue.h"
44 #include "bindings/core/v8/V8Initializer.h" 41 #include "bindings/core/v8/V8Initializer.h"
45 #include "bindings/core/v8/V8ObjectConstructor.h"
46 #include "bindings/core/v8/V8PagePopupControllerBinding.h"
47 #include "bindings/core/v8/V8PrivateProperty.h" 42 #include "bindings/core/v8/V8PrivateProperty.h"
48 #include "bindings/core/v8/V8Window.h" 43 #include "bindings/core/v8/V8Window.h"
49 #include "core/frame/LocalFrame.h" 44 #include "core/frame/LocalFrame.h"
50 #include "core/frame/csp/ContentSecurityPolicy.h" 45 #include "core/frame/csp/ContentSecurityPolicy.h"
51 #include "core/html/DocumentNameCollection.h" 46 #include "core/html/DocumentNameCollection.h"
52 #include "core/html/HTMLCollection.h"
53 #include "core/html/HTMLIFrameElement.h" 47 #include "core/html/HTMLIFrameElement.h"
54 #include "core/inspector/InspectorInstrumentation.h"
55 #include "core/inspector/MainThreadDebugger.h" 48 #include "core/inspector/MainThreadDebugger.h"
56 #include "core/loader/DocumentLoader.h"
57 #include "core/loader/FrameLoader.h" 49 #include "core/loader/FrameLoader.h"
58 #include "core/loader/FrameLoaderClient.h" 50 #include "core/loader/FrameLoaderClient.h"
59 #include "core/origin_trials/OriginTrialContext.h" 51 #include "core/origin_trials/OriginTrialContext.h"
60 #include "platform/Histogram.h" 52 #include "platform/Histogram.h"
61 #include "platform/RuntimeEnabledFeatures.h" 53 #include "platform/RuntimeEnabledFeatures.h"
62 #include "platform/ScriptForbiddenScope.h" 54 #include "platform/ScriptForbiddenScope.h"
63 #include "platform/heap/Handle.h" 55 #include "platform/heap/Handle.h"
64 #include "platform/instrumentation/tracing/TraceEvent.h" 56 #include "platform/instrumentation/tracing/TraceEvent.h"
65 #include "platform/weborigin/SecurityOrigin.h" 57 #include "platform/weborigin/SecurityOrigin.h"
66 #include "public/platform/Platform.h"
67 #include "wtf/Assertions.h" 58 #include "wtf/Assertions.h"
68 #include "wtf/StringExtras.h"
69 #include "wtf/text/CString.h"
70 #include <algorithm>
71 #include <utility>
72 #include <v8-debug.h>
73 #include <v8.h> 59 #include <v8.h>
74 60
75 namespace blink { 61 namespace blink {
76 62
77 WindowProxy* WindowProxy::create(v8::Isolate* isolate, 63 LocalWindowProxy::~LocalWindowProxy() {
78 Frame* frame,
79 DOMWrapperWorld& world) {
80 return new WindowProxy(frame, &world, isolate);
81 }
82
83 WindowProxy::WindowProxy(Frame* frame,
84 PassRefPtr<DOMWrapperWorld> world,
85 v8::Isolate* isolate)
86 : m_frame(frame),
87 m_isolate(isolate),
88 m_world(world),
89 m_lifecycle(Lifecycle::ContextUninitialized) {}
90
91 WindowProxy::~WindowProxy() {
92 // clearForClose() or clearForNavigation() must be invoked before destruction 64 // clearForClose() or clearForNavigation() must be invoked before destruction
93 // starts. 65 // starts.
94 DCHECK(m_lifecycle != Lifecycle::ContextInitialized); 66 DCHECK(m_lifecycle != Lifecycle::ContextInitialized);
95 } 67 }
96 68
97 DEFINE_TRACE(WindowProxy) { 69 void LocalWindowProxy::disposeContext(GlobalDetachmentBehavior behavior) {
98 visitor->trace(m_frame);
99 }
100
101 void WindowProxy::disposeContext(GlobalDetachmentBehavior behavior) {
102 if (m_lifecycle != Lifecycle::ContextInitialized) 70 if (m_lifecycle != Lifecycle::ContextInitialized)
103 return; 71 return;
104 72
105 ScriptState::Scope scope(m_scriptState.get()); 73 ScriptState::Scope scope(m_scriptState.get());
106 v8::Local<v8::Context> context = m_scriptState->context(); 74 v8::Local<v8::Context> context = m_scriptState->context();
107 if (m_frame->isLocalFrame()) { 75 // The embedder could run arbitrary code in response to the
108 LocalFrame* frame = toLocalFrame(m_frame); 76 // willReleaseScriptContext callback, so all disposing should happen after
109 // The embedder could run arbitrary code in response to the 77 // it returns.
110 // willReleaseScriptContext callback, so all disposing should happen after 78 frame()->loader().client()->willReleaseScriptContext(context,
111 // it returns.
112 frame->loader().client()->willReleaseScriptContext(context,
113 m_world->worldId()); 79 m_world->worldId());
114 MainThreadDebugger::instance()->contextWillBeDestroyed(m_scriptState.get()); 80 MainThreadDebugger::instance()->contextWillBeDestroyed(m_scriptState.get());
115 }
116 81
117 if (behavior == DetachGlobal) { 82 WindowProxy::disposeContext(behavior);
118 // Clean up state on the global proxy, which will be reused.
119 if (!m_globalProxy.isEmpty()) {
120 // TODO(yukishiino): This DCHECK failed on Canary (M57) and Dev (M56).
121 // We need to figure out why m_globalProxy != context->Global().
122 DCHECK(m_globalProxy == context->Global());
123 DCHECK_EQ(toScriptWrappable(context->Global()),
124 toScriptWrappable(
125 context->Global()->GetPrototype().As<v8::Object>()));
126 m_globalProxy.get().SetWrapperClassId(0);
127 }
128 V8DOMWrapper::clearNativeInfo(m_isolate, context->Global());
129 m_scriptState->detachGlobalObject();
130 }
131
132 m_scriptState->disposePerContextData();
133
134 // It's likely that disposing the context has created a lot of
135 // garbage. Notify V8 about this so it'll have a chance of cleaning
136 // it up when idle.
137 V8GCForContextDispose::instance().notifyContextDisposed(
138 m_frame->isMainFrame());
139
140 DCHECK(m_lifecycle == Lifecycle::ContextInitialized);
141 m_lifecycle = Lifecycle::ContextDetached;
142 } 83 }
143 84
144 void WindowProxy::clearForClose() { 85 void LocalWindowProxy::initialize() {
145 disposeContext(DoNotDetachGlobal); 86 TRACE_EVENT1("v8", "LocalWindowProxy::initialize", "isMainWindow",
146 } 87 frame()->isMainFrame());
147
148 void WindowProxy::clearForNavigation() {
149 disposeContext(DetachGlobal);
150 }
151
152 v8::Local<v8::Object> WindowProxy::globalIfNotDetached() {
153 if (m_lifecycle == Lifecycle::ContextInitialized) {
154 DCHECK(m_scriptState->contextIsValid());
155 DCHECK(m_globalProxy == m_scriptState->context()->Global());
156 return m_globalProxy.newLocal(m_isolate);
157 }
158 return v8::Local<v8::Object>();
159 }
160
161 v8::Local<v8::Object> WindowProxy::releaseGlobal() {
162 DCHECK(m_lifecycle != Lifecycle::ContextInitialized);
163 // Make sure the global object was detached from the proxy by calling
164 // clearForNavigation().
165 if (m_lifecycle == Lifecycle::ContextDetached)
166 ASSERT(m_scriptState->isGlobalObjectDetached());
167
168 v8::Local<v8::Object> global = m_globalProxy.newLocal(m_isolate);
169 m_globalProxy.clear();
170 return global;
171 }
172
173 void WindowProxy::setGlobal(v8::Local<v8::Object> global) {
174 m_globalProxy.set(m_isolate, global);
175
176 // Initialize the window proxy now, to re-establish the connection between
177 // the global object and the v8::Context. This is really only needed for a
178 // RemoteDOMWindow, since it has no scripting environment of its own.
179 // Without this, existing script references to a swapped in RemoteDOMWindow
180 // would be broken until that RemoteDOMWindow was vended again through an
181 // interface like window.frames.
182 initializeIfNeeded();
183 }
184
185 // Create a new environment and setup the global object.
186 //
187 // The global object corresponds to a DOMWindow instance. However, to
188 // allow properties of the JS DOMWindow instance to be shadowed, we
189 // use a shadow object as the global object and use the JS DOMWindow
190 // instance as the prototype for that shadow object. The JS DOMWindow
191 // instance is undetectable from JavaScript code because the __proto__
192 // accessors skip that object.
193 //
194 // The shadow object and the DOMWindow instance are seen as one object
195 // from JavaScript. The JavaScript object that corresponds to a
196 // DOMWindow instance is the shadow object. When mapping a DOMWindow
197 // instance to a V8 object, we return the shadow object.
198 //
199 // To implement split-window, see
200 // 1) https://bugs.webkit.org/show_bug.cgi?id=17249
201 // 2) https://wiki.mozilla.org/Gecko:SplitWindow
202 // 3) https://bugzilla.mozilla.org/show_bug.cgi?id=296639
203 // we need to split the shadow object further into two objects:
204 // an outer window and an inner window. The inner window is the hidden
205 // prototype of the outer window. The inner window is the default
206 // global object of the context. A variable declared in the global
207 // scope is a property of the inner window.
208 //
209 // The outer window sticks to a LocalFrame, it is exposed to JavaScript
210 // via window.window, window.self, window.parent, etc. The outer window
211 // has a security token which is the domain. The outer window cannot
212 // have its own properties. window.foo = 'x' is delegated to the
213 // inner window.
214 //
215 // When a frame navigates to a new page, the inner window is cut off
216 // the outer window, and the outer window identify is preserved for
217 // the frame. However, a new inner window is created for the new page.
218 // If there are JS code holds a closure to the old inner window,
219 // it won't be able to reach the outer window via its global object.
220 void WindowProxy::initializeIfNeeded() {
221 // TODO(haraken): It is wrong to re-initialize an already detached window
222 // proxy. This must be 'if(m_lifecycle == Lifecycle::ContextUninitialized)'.
223 if (m_lifecycle != Lifecycle::ContextInitialized) {
224 initialize();
225 if (m_world->isMainWorld() && m_frame->isLocalFrame())
226 toLocalFrame(m_frame)->loader().dispatchDidClearWindowObjectInMainWorld();
227 }
228 }
229
230 void WindowProxy::initialize() {
231 TRACE_EVENT1("v8", "WindowProxy::initialize", "isMainWindow",
232 m_frame->isMainFrame());
233 SCOPED_BLINK_UMA_HISTOGRAM_TIMER( 88 SCOPED_BLINK_UMA_HISTOGRAM_TIMER(
234 m_frame->isMainFrame() ? "Blink.Binding.InitializeMainWindowProxy" 89 frame()->isMainFrame() ? "Blink.Binding.InitializeMainWindowProxy"
235 : "Blink.Binding.InitializeNonMainWindowProxy"); 90 : "Blink.Binding.InitializeNonMainWindowProxy");
236 91
237 ScriptForbiddenScope::AllowUserAgentScript allowScript; 92 ScriptForbiddenScope::AllowUserAgentScript allowScript;
238 93
239 v8::HandleScope handleScope(m_isolate); 94 v8::HandleScope handleScope(isolate());
240 95
241 createContext(); 96 createContext();
242 97
243 ScriptState::Scope scope(m_scriptState.get()); 98 ScriptState::Scope scope(m_scriptState.get());
244 v8::Local<v8::Context> context = m_scriptState->context(); 99 v8::Local<v8::Context> context = m_scriptState->context();
245 if (m_globalProxy.isEmpty()) { 100 if (m_globalProxy.isEmpty()) {
246 m_globalProxy.set(m_isolate, context->Global()); 101 m_globalProxy.set(isolate(), context->Global());
247 CHECK(!m_globalProxy.isEmpty()); 102 CHECK(!m_globalProxy.isEmpty());
248 } 103 }
249 104
250 setupWindowPrototypeChain(); 105 setupWindowPrototypeChain();
251 106
252 SecurityOrigin* origin = 0; 107 SecurityOrigin* origin = 0;
253 if (m_world->isMainWorld()) { 108 if (m_world->isMainWorld()) {
254 // ActivityLogger for main world is updated within updateDocument(). 109 // ActivityLogger for main world is updated within updateDocument().
255 updateDocument(); 110 updateDocument();
256 origin = m_frame->securityContext()->getSecurityOrigin(); 111 origin = frame()->document()->getSecurityOrigin();
257 // FIXME: Can this be removed when CSP moves to browser? 112 // FIXME: Can this be removed when CSP moves to browser?
258 ContentSecurityPolicy* csp = 113 ContentSecurityPolicy* csp = frame()->document()->contentSecurityPolicy();
259 m_frame->securityContext()->contentSecurityPolicy();
260 context->AllowCodeGenerationFromStrings( 114 context->AllowCodeGenerationFromStrings(
261 csp->allowEval(0, ContentSecurityPolicy::SuppressReport)); 115 csp->allowEval(0, ContentSecurityPolicy::SuppressReport));
262 context->SetErrorMessageForCodeGenerationFromStrings( 116 context->SetErrorMessageForCodeGenerationFromStrings(
263 v8String(m_isolate, csp->evalDisabledErrorMessage())); 117 v8String(isolate(), csp->evalDisabledErrorMessage()));
264 } else { 118 } else {
265 updateActivityLogger(); 119 updateActivityLogger();
266 origin = m_world->isolatedWorldSecurityOrigin(); 120 origin = m_world->isolatedWorldSecurityOrigin();
267 setSecurityToken(origin); 121 setSecurityToken(origin);
268 } 122 }
269 123
270 if (m_frame->isLocalFrame()) { 124 MainThreadDebugger::instance()->contextCreated(m_scriptState.get(), frame(),
271 LocalFrame* frame = toLocalFrame(m_frame); 125 origin);
272 MainThreadDebugger::instance()->contextCreated(m_scriptState.get(), frame, 126 frame()->loader().client()->didCreateScriptContext(
273 origin); 127 context, m_world->extensionGroup(), m_world->worldId());
274 frame->loader().client()->didCreateScriptContext(
275 context, m_world->extensionGroup(), m_world->worldId());
276 }
277 // If conditional features for window have been queued before the V8 context 128 // If conditional features for window have been queued before the V8 context
278 // was ready, then inject them into the context now 129 // was ready, then inject them into the context now
279 if (m_world->isMainWorld()) { 130 if (m_world->isMainWorld()) {
280 installPendingConditionalFeaturesOnWindow(m_scriptState.get()); 131 installPendingConditionalFeaturesOnWindow(m_scriptState.get());
281 } 132 }
133
134 if (m_world->isMainWorld())
135 frame()->loader().dispatchDidClearWindowObjectInMainWorld();
dcheng 2017/01/11 08:35:16 Moved from initializeIfNeeded(), since this logic
282 } 136 }
283 137
284 void WindowProxy::createContext() { 138 void LocalWindowProxy::createContext() {
285 // Create a new v8::Context with the window object as the global object 139 // Create a new v8::Context with the window object as the global object
286 // (aka the inner global). Reuse the global proxy object (aka the outer 140 // (aka the inner global). Reuse the global proxy object (aka the outer
287 // global) if it already exists. See the comments in 141 // global) if it already exists. See the comments in
288 // setupWindowPrototypeChain for the structure of the prototype chain of 142 // setupWindowPrototypeChain for the structure of the prototype chain of
289 // the global object. 143 // the global object.
290 v8::Local<v8::ObjectTemplate> globalTemplate = 144 v8::Local<v8::ObjectTemplate> globalTemplate =
291 V8Window::domTemplate(m_isolate, *m_world)->InstanceTemplate(); 145 V8Window::domTemplate(isolate(), *m_world)->InstanceTemplate();
292 CHECK(!globalTemplate.IsEmpty()); 146 CHECK(!globalTemplate.IsEmpty());
293 147
294 // FIXME: It's not clear what the right thing to do for remote frames is. 148 // FIXME: It's not clear what the right thing to do for remote frames is.
295 // The extensions registered don't generally seem to make sense for remote 149 // The extensions registered don't generally seem to make sense for remote
296 // frames, so skip it for now. 150 // frames, so skip it for now.
297 Vector<const char*> extensionNames; 151 Vector<const char*> extensionNames;
298 if (m_frame->isLocalFrame()) { 152 // Dynamically tell v8 about our extensions now.
299 LocalFrame* frame = toLocalFrame(m_frame); 153 const V8Extensions& extensions = ScriptController::registeredExtensions();
300 // Dynamically tell v8 about our extensions now. 154 extensionNames.reserveInitialCapacity(extensions.size());
301 const V8Extensions& extensions = ScriptController::registeredExtensions(); 155 int extensionGroup = m_world->extensionGroup();
302 extensionNames.reserveInitialCapacity(extensions.size()); 156 int worldId = m_world->worldId();
303 int extensionGroup = m_world->extensionGroup(); 157 for (const auto* extension : extensions) {
304 int worldId = m_world->worldId(); 158 if (!frame()->loader().client()->allowScriptExtension(
305 for (const auto* extension : extensions) { 159 extension->name(), extensionGroup, worldId))
306 if (!frame->loader().client()->allowScriptExtension( 160 continue;
307 extension->name(), extensionGroup, worldId))
308 continue;
309 161
310 extensionNames.push_back(extension->name()); 162 extensionNames.push_back(extension->name());
311 }
312 } 163 }
313 v8::ExtensionConfiguration extensionConfiguration(extensionNames.size(), 164 v8::ExtensionConfiguration extensionConfiguration(extensionNames.size(),
314 extensionNames.data()); 165 extensionNames.data());
315 166
316 v8::Local<v8::Context> context; 167 v8::Local<v8::Context> context;
317 { 168 {
318 V8PerIsolateData::UseCounterDisabledScope useCounterDisabled( 169 V8PerIsolateData::UseCounterDisabledScope useCounterDisabled(
319 V8PerIsolateData::from(m_isolate)); 170 V8PerIsolateData::from(isolate()));
320 context = 171 context =
321 v8::Context::New(m_isolate, &extensionConfiguration, globalTemplate, 172 v8::Context::New(isolate(), &extensionConfiguration, globalTemplate,
322 m_globalProxy.newLocal(m_isolate)); 173 m_globalProxy.newLocal(isolate()));
323 } 174 }
324 CHECK(!context.IsEmpty()); 175 CHECK(!context.IsEmpty());
325 176
326 m_scriptState = ScriptState::create(context, m_world); 177 m_scriptState = ScriptState::create(context, m_world);
327 178
328 // TODO(haraken): Currently we cannot enable the following DCHECK because 179 // TODO(haraken): Currently we cannot enable the following DCHECK because
329 // an already detached window proxy can be re-initialized. This is wrong. 180 // an already detached window proxy can be re-initialized. This is wrong.
330 // DCHECK(m_lifecycle == Lifecycle::ContextUninitialized); 181 // DCHECK(m_lifecycle == Lifecycle::ContextUninitialized);
331 m_lifecycle = Lifecycle::ContextInitialized; 182 m_lifecycle = Lifecycle::ContextInitialized;
332 DCHECK(m_scriptState->contextIsValid()); 183 DCHECK(m_scriptState->contextIsValid());
333 } 184 }
334 185
335 void WindowProxy::setupWindowPrototypeChain() { 186 void LocalWindowProxy::updateDocumentProperty() {
336 // Associate the window wrapper object and its prototype chain with the
337 // corresponding native DOMWindow object.
338 // The full structure of the global object's prototype chain is as follows:
339 //
340 // global proxy object [1]
341 // -- has prototype --> global object (window wrapper object) [2]
342 // -- has prototype --> Window.prototype
343 // -- has prototype --> WindowProperties [3]
344 // -- has prototype --> EventTarget.prototype
345 // -- has prototype --> Object.prototype
346 // -- has prototype --> null
347 //
348 // [1] Global proxy object is as known as "outer global object". It's an
349 // empty object and remains after navigation. When navigated, points to
350 // a different global object as the prototype object.
351 // [2] Global object is as known as "inner global object" or "window wrapper
352 // object". The prototype chain between global proxy object and global
353 // object is NOT observable from user JavaScript code. All other
354 // prototype chains are observable. Global proxy object and global object
355 // together appear to be the same single JavaScript object. See also:
356 // https://wiki.mozilla.org/Gecko:SplitWindow
357 // global object (= window wrapper object) provides most of Window's DOM
358 // attributes and operations. Also global variables defined by user
359 // JavaScript are placed on this object. When navigated, a new global
360 // object is created together with a new v8::Context, but the global proxy
361 // object doesn't change.
362 // [3] WindowProperties is a named properties object of Window interface.
363
364 DOMWindow* window = m_frame->domWindow();
365 const WrapperTypeInfo* wrapperTypeInfo = window->wrapperTypeInfo();
366 v8::Local<v8::Context> context = m_scriptState->context();
367
368 // The global proxy object. Note this is not the global object.
369 v8::Local<v8::Object> globalProxy = context->Global();
370 CHECK(m_globalProxy == globalProxy);
371 V8DOMWrapper::setNativeInfo(m_isolate, globalProxy, wrapperTypeInfo, window);
372 // Mark the handle to be traced by Oilpan, since the global proxy has a
373 // reference to the DOMWindow.
374 m_globalProxy.get().SetWrapperClassId(wrapperTypeInfo->wrapperClassId);
375
376 // The global object, aka window wrapper object.
377 v8::Local<v8::Object> windowWrapper =
378 globalProxy->GetPrototype().As<v8::Object>();
379 windowWrapper = V8DOMWrapper::associateObjectWithWrapper(
380 m_isolate, window, wrapperTypeInfo, windowWrapper);
381
382 // The prototype object of Window interface.
383 v8::Local<v8::Object> windowPrototype =
384 windowWrapper->GetPrototype().As<v8::Object>();
385 CHECK(!windowPrototype.IsEmpty());
386 V8DOMWrapper::setNativeInfo(m_isolate, windowPrototype, wrapperTypeInfo,
387 window);
388
389 // The named properties object of Window interface.
390 v8::Local<v8::Object> windowProperties =
391 windowPrototype->GetPrototype().As<v8::Object>();
392 CHECK(!windowProperties.IsEmpty());
393 V8DOMWrapper::setNativeInfo(m_isolate, windowProperties, wrapperTypeInfo,
394 window);
395
396 // TODO(keishi): Remove installPagePopupController and implement
397 // PagePopupController in another way.
398 V8PagePopupControllerBinding::installPagePopupController(context,
399 windowWrapper);
400 }
401
402 void WindowProxy::updateDocumentProperty() {
403 DCHECK(m_world->isMainWorld()); 187 DCHECK(m_world->isMainWorld());
404 188
405 if (m_frame->isRemoteFrame())
406 return;
407
408 ScriptState::Scope scope(m_scriptState.get()); 189 ScriptState::Scope scope(m_scriptState.get());
409 v8::Local<v8::Context> context = m_scriptState->context(); 190 v8::Local<v8::Context> context = m_scriptState->context();
410 LocalFrame* frame = toLocalFrame(m_frame);
411 v8::Local<v8::Value> documentWrapper = 191 v8::Local<v8::Value> documentWrapper =
412 ToV8(frame->document(), context->Global(), m_isolate); 192 ToV8(frame()->document(), context->Global(), isolate());
413 DCHECK(documentWrapper->IsObject()); 193 DCHECK(documentWrapper->IsObject());
414 // Update the cached accessor for window.document. 194 // Update the cached accessor for window.document.
415 CHECK(V8PrivateProperty::getWindowDocumentCachedAccessor(m_isolate).set( 195 CHECK(V8PrivateProperty::getWindowDocumentCachedAccessor(isolate()).set(
416 context, context->Global(), documentWrapper)); 196 context, context->Global(), documentWrapper));
417 } 197 }
418 198
419 void WindowProxy::updateActivityLogger() { 199 void LocalWindowProxy::updateActivityLogger() {
420 m_scriptState->perContextData()->setActivityLogger( 200 m_scriptState->perContextData()->setActivityLogger(
421 V8DOMActivityLogger::activityLogger( 201 V8DOMActivityLogger::activityLogger(
422 m_world->worldId(), 202 m_world->worldId(),
423 m_frame->isLocalFrame() && toLocalFrame(m_frame)->document() 203 frame()->document() ? frame()->document()->baseURI() : KURL()));
424 ? toLocalFrame(m_frame)->document()->baseURI()
425 : KURL()));
426 } 204 }
427 205
428 void WindowProxy::setSecurityToken(SecurityOrigin* origin) { 206 void LocalWindowProxy::setSecurityToken(SecurityOrigin* origin) {
429 // If two tokens are equal, then the SecurityOrigins canAccess each other. 207 // If two tokens are equal, then the SecurityOrigins canAccess each other.
430 // If two tokens are not equal, then we have to call canAccess. 208 // If two tokens are not equal, then we have to call canAccess.
431 // Note: we can't use the HTTPOrigin if it was set from the DOM. 209 // Note: we can't use the HTTPOrigin if it was set from the DOM.
432 String token; 210 String token;
433 // There are two situations where v8 needs to do a full canAccess check, 211 // If document.domain is modified, v8 needs to do a full canAccess check,
434 // so set an empty security token instead: 212 // so always use an empty security token in that case.
435 // - document.domain was modified 213 bool delaySet = m_world->isMainWorld() && origin->domainWasSetInDOM();
436 // - the frame is remote
437 bool delaySet = m_frame->isRemoteFrame() ||
438 (m_world->isMainWorld() && origin->domainWasSetInDOM());
439 if (origin && !delaySet) 214 if (origin && !delaySet)
440 token = origin->toString(); 215 token = origin->toString();
441 216
442 // An empty or "null" token means we always have to call 217 // An empty or "null" token means we always have to call
443 // canAccess. The toString method on securityOrigins returns the 218 // canAccess. The toString method on securityOrigins returns the
444 // string "null" for empty security origins and for security 219 // string "null" for empty security origins and for security
445 // origins that should only allow access to themselves. In this 220 // origins that should only allow access to themselves. In this
446 // case, we use the global object as the security token to avoid 221 // case, we use the global object as the security token to avoid
447 // calling canAccess when a script accesses its own objects. 222 // calling canAccess when a script accesses its own objects.
448 v8::HandleScope handleScope(m_isolate); 223 v8::HandleScope handleScope(isolate());
449 v8::Local<v8::Context> context = m_scriptState->context(); 224 v8::Local<v8::Context> context = m_scriptState->context();
450 if (token.isEmpty() || token == "null") { 225 if (token.isEmpty() || token == "null") {
451 context->UseDefaultSecurityToken(); 226 context->UseDefaultSecurityToken();
452 return; 227 return;
453 } 228 }
454 229
455 if (m_world->isIsolatedWorld()) { 230 if (m_world->isIsolatedWorld()) {
456 SecurityOrigin* frameSecurityOrigin = 231 SecurityOrigin* frameSecurityOrigin =
457 m_frame->securityContext()->getSecurityOrigin(); 232 frame()->document()->getSecurityOrigin();
458 String frameSecurityToken = frameSecurityOrigin->toString(); 233 String frameSecurityToken = frameSecurityOrigin->toString();
459 // We need to check the return value of domainWasSetInDOM() on the 234 // We need to check the return value of domainWasSetInDOM() on the
460 // frame's SecurityOrigin because, if that's the case, only 235 // frame's SecurityOrigin because, if that's the case, only
461 // SecurityOrigin::m_domain would have been modified. 236 // SecurityOrigin::m_domain would have been modified.
462 // m_domain is not used by SecurityOrigin::toString(), so we would end 237 // m_domain is not used by SecurityOrigin::toString(), so we would end
463 // up generating the same token that was already set. 238 // up generating the same token that was already set.
464 if (frameSecurityOrigin->domainWasSetInDOM() || 239 if (frameSecurityOrigin->domainWasSetInDOM() ||
465 frameSecurityToken.isEmpty() || frameSecurityToken == "null") { 240 frameSecurityToken.isEmpty() || frameSecurityToken == "null") {
466 context->UseDefaultSecurityToken(); 241 context->UseDefaultSecurityToken();
467 return; 242 return;
468 } 243 }
469 token = frameSecurityToken + token; 244 token = frameSecurityToken + token;
470 } 245 }
471 246
472 // NOTE: V8 does identity comparison in fast path, must use a symbol 247 // NOTE: V8 does identity comparison in fast path, must use a symbol
473 // as the security token. 248 // as the security token.
474 context->SetSecurityToken(v8AtomicString(m_isolate, token)); 249 context->SetSecurityToken(v8AtomicString(isolate(), token));
475 } 250 }
476 251
477 void WindowProxy::updateDocument() { 252 void LocalWindowProxy::updateDocument() {
478 DCHECK(m_world->isMainWorld()); 253 DCHECK(m_world->isMainWorld());
479 // For an uninitialized main window proxy, there's nothing we need 254 // For an uninitialized main window proxy, there's nothing we need
480 // to update. The update is done when the window proxy gets initialized later. 255 // to update. The update is done when the window proxy gets initialized later.
481 if (m_lifecycle == Lifecycle::ContextUninitialized) 256 if (m_lifecycle == Lifecycle::ContextUninitialized)
482 return; 257 return;
483 // TODO(yukishiino): Is it okay to not update document when the context 258 // TODO(yukishiino): Is it okay to not update document when the context
484 // is detached? It's not trivial to fix this because udpateDocumentProperty 259 // is detached? It's not trivial to fix this because udpateDocumentProperty
485 // requires a not-yet-detached context to instantiate a document wrapper. 260 // requires a not-yet-detached context to instantiate a document wrapper.
486 if (m_lifecycle == Lifecycle::ContextDetached) 261 if (m_lifecycle == Lifecycle::ContextDetached)
487 return; 262 return;
488 263
489 updateActivityLogger(); 264 updateActivityLogger();
490 updateDocumentProperty(); 265 updateDocumentProperty();
491 updateSecurityOrigin(m_frame->securityContext()->getSecurityOrigin()); 266 updateSecurityOrigin(frame()->document()->getSecurityOrigin());
492 } 267 }
493 268
494 static v8::Local<v8::Value> getNamedProperty( 269 static v8::Local<v8::Value> getNamedProperty(
495 HTMLDocument* htmlDocument, 270 HTMLDocument* htmlDocument,
496 const AtomicString& key, 271 const AtomicString& key,
497 v8::Local<v8::Object> creationContext, 272 v8::Local<v8::Object> creationContext,
498 v8::Isolate* isolate) { 273 v8::Isolate* isolate) {
499 if (!htmlDocument->hasNamedItem(key) && !htmlDocument->hasExtraNamedItem(key)) 274 if (!htmlDocument->hasNamedItem(key) && !htmlDocument->hasExtraNamedItem(key))
500 return v8Undefined(); 275 return v8Undefined();
501 276
502 DocumentNameCollection* items = htmlDocument->documentNamedItems(key); 277 DocumentNameCollection* items = htmlDocument->documentNamedItems(key);
503 if (items->isEmpty()) 278 if (items->isEmpty())
504 return v8Undefined(); 279 return v8Undefined();
505 280
506 if (items->hasExactlyOneItem()) { 281 if (items->hasExactlyOneItem()) {
507 HTMLElement* element = items->item(0); 282 HTMLElement* element = items->item(0);
508 ASSERT(element); 283 DCHECK(element);
509 Frame* frame = isHTMLIFrameElement(*element) 284 Frame* frame = isHTMLIFrameElement(*element)
510 ? toHTMLIFrameElement(*element).contentFrame() 285 ? toHTMLIFrameElement(*element).contentFrame()
511 : 0; 286 : 0;
512 if (frame) 287 if (frame)
513 return ToV8(frame->domWindow(), creationContext, isolate); 288 return ToV8(frame->domWindow(), creationContext, isolate);
514 return ToV8(element, creationContext, isolate); 289 return ToV8(element, creationContext, isolate);
515 } 290 }
516 return ToV8(items, creationContext, isolate); 291 return ToV8(items, creationContext, isolate);
517 } 292 }
518 293
519 static void getter(v8::Local<v8::Name> property, 294 static void getter(v8::Local<v8::Name> property,
520 const v8::PropertyCallbackInfo<v8::Value>& info) { 295 const v8::PropertyCallbackInfo<v8::Value>& info) {
521 if (!property->IsString()) 296 if (!property->IsString())
522 return; 297 return;
523 // FIXME: Consider passing StringImpl directly. 298 // FIXME: Consider passing StringImpl directly.
524 AtomicString name = toCoreAtomicString(property.As<v8::String>()); 299 AtomicString name = toCoreAtomicString(property.As<v8::String>());
525 HTMLDocument* htmlDocument = V8HTMLDocument::toImpl(info.Holder()); 300 HTMLDocument* htmlDocument = V8HTMLDocument::toImpl(info.Holder());
526 ASSERT(htmlDocument); 301 DCHECK(htmlDocument);
527 v8::Local<v8::Value> result = 302 v8::Local<v8::Value> result =
528 getNamedProperty(htmlDocument, name, info.Holder(), info.GetIsolate()); 303 getNamedProperty(htmlDocument, name, info.Holder(), info.GetIsolate());
529 if (!result.IsEmpty()) { 304 if (!result.IsEmpty()) {
530 v8SetReturnValue(info, result); 305 v8SetReturnValue(info, result);
531 return; 306 return;
532 } 307 }
533 v8::Local<v8::Value> value; 308 v8::Local<v8::Value> value;
534 if (info.Holder() 309 if (info.Holder()
535 ->GetRealNamedPropertyInPrototypeChain( 310 ->GetRealNamedPropertyInPrototypeChain(
536 info.GetIsolate()->GetCurrentContext(), property.As<v8::String>()) 311 info.GetIsolate()->GetCurrentContext(), property.As<v8::String>())
537 .ToLocal(&value)) 312 .ToLocal(&value))
538 v8SetReturnValue(info, value); 313 v8SetReturnValue(info, value);
539 } 314 }
540 315
541 void WindowProxy::namedItemAdded(HTMLDocument* document, 316 void LocalWindowProxy::namedItemAdded(HTMLDocument* document,
542 const AtomicString& name) { 317 const AtomicString& name) {
543 DCHECK(m_world->isMainWorld()); 318 DCHECK(m_world->isMainWorld());
544 319
545 // Context must be initialized before this point. 320 // Context must be initialized before this point.
546 DCHECK(m_lifecycle >= Lifecycle::ContextInitialized); 321 DCHECK(m_lifecycle >= Lifecycle::ContextInitialized);
547 // TODO(yukishiino): Is it okay to not update named properties 322 // TODO(yukishiino): Is it okay to not update named properties
548 // after the context gets detached? 323 // after the context gets detached?
549 if (m_lifecycle == Lifecycle::ContextDetached) 324 if (m_lifecycle == Lifecycle::ContextDetached)
550 return; 325 return;
551 326
552 ScriptState::Scope scope(m_scriptState.get()); 327 ScriptState::Scope scope(m_scriptState.get());
553 v8::Local<v8::Object> documentWrapper = 328 v8::Local<v8::Object> documentWrapper =
554 m_world->domDataStore().get(document, m_isolate); 329 m_world->domDataStore().get(document, isolate());
555 // TODO(yukishiino,peria): We should check if the own property with the same 330 // TODO(yukishiino,peria): We should check if the own property with the same
556 // name already exists or not, and if it exists, we shouldn't define a new 331 // name already exists or not, and if it exists, we shouldn't define a new
557 // accessor property (it fails). 332 // accessor property (it fails).
558 documentWrapper->SetAccessor(m_isolate->GetCurrentContext(), 333 documentWrapper->SetAccessor(isolate()->GetCurrentContext(),
559 v8String(m_isolate, name), getter); 334 v8String(isolate(), name), getter);
560 } 335 }
561 336
562 void WindowProxy::namedItemRemoved(HTMLDocument* document, 337 void LocalWindowProxy::namedItemRemoved(HTMLDocument* document,
563 const AtomicString& name) { 338 const AtomicString& name) {
564 DCHECK(m_world->isMainWorld()); 339 DCHECK(m_world->isMainWorld());
565 340
566 // Context must be initialized before this point. 341 // Context must be initialized before this point.
567 DCHECK(m_lifecycle >= Lifecycle::ContextInitialized); 342 DCHECK(m_lifecycle >= Lifecycle::ContextInitialized);
568 // TODO(yukishiino): Is it okay to not update named properties 343 // TODO(yukishiino): Is it okay to not update named properties
569 // after the context gets detached? 344 // after the context gets detached?
570 if (m_lifecycle == Lifecycle::ContextDetached) 345 if (m_lifecycle == Lifecycle::ContextDetached)
571 return; 346 return;
572 347
573 if (document->hasNamedItem(name) || document->hasExtraNamedItem(name)) 348 if (document->hasNamedItem(name) || document->hasExtraNamedItem(name))
574 return; 349 return;
575 ScriptState::Scope scope(m_scriptState.get()); 350 ScriptState::Scope scope(m_scriptState.get());
576 v8::Local<v8::Object> documentWrapper = 351 v8::Local<v8::Object> documentWrapper =
577 m_world->domDataStore().get(document, m_isolate); 352 m_world->domDataStore().get(document, isolate());
578 documentWrapper 353 documentWrapper
579 ->Delete(m_isolate->GetCurrentContext(), v8String(m_isolate, name)) 354 ->Delete(isolate()->GetCurrentContext(), v8String(isolate(), name))
580 .ToChecked(); 355 .ToChecked();
581 } 356 }
582 357
583 void WindowProxy::updateSecurityOrigin(SecurityOrigin* origin) { 358 void LocalWindowProxy::updateSecurityOrigin(SecurityOrigin* origin) {
584 // For an uninitialized main window proxy, there's nothing we need 359 // For an uninitialized main window proxy, there's nothing we need
585 // to update. The update is done when the window proxy gets initialized later. 360 // to update. The update is done when the window proxy gets initialized later.
586 if (m_lifecycle == Lifecycle::ContextUninitialized) 361 if (m_lifecycle == Lifecycle::ContextUninitialized)
587 return; 362 return;
588 // TODO(yukishiino): Is it okay to not update security origin when the context 363 // TODO(yukishiino): Is it okay to not update security origin when the context
589 // is detached? 364 // is detached?
590 if (m_lifecycle == Lifecycle::ContextDetached) 365 if (m_lifecycle == Lifecycle::ContextDetached)
591 return; 366 return;
592 367
593 setSecurityToken(origin); 368 setSecurityToken(origin);
594 } 369 }
595 370
371 LocalWindowProxy::LocalWindowProxy(LocalFrame& frame,
372 v8::Isolate* isolate,
373 RefPtr<DOMWrapperWorld> world)
374 : WindowProxy(frame, isolate, std::move(world)) {}
375
596 } // namespace blink 376 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698