Chromium Code Reviews| OLD | NEW |
|---|---|
| 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 227 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 238 ScriptState::Scope scope(m_scriptState.get()); | 238 ScriptState::Scope scope(m_scriptState.get()); |
| 239 v8::Local<v8::Context> context = m_scriptState->context(); | 239 v8::Local<v8::Context> context = m_scriptState->context(); |
| 240 if (m_global.isEmpty()) { | 240 if (m_global.isEmpty()) { |
| 241 m_global.set(m_isolate, context->Global()); | 241 m_global.set(m_isolate, context->Global()); |
| 242 if (m_global.isEmpty()) { | 242 if (m_global.isEmpty()) { |
| 243 disposeContext(DoNotDetachGlobal); | 243 disposeContext(DoNotDetachGlobal); |
| 244 return false; | 244 return false; |
| 245 } | 245 } |
| 246 } | 246 } |
| 247 | 247 |
| 248 if (!installDOMWindow()) { | 248 if (!setupWindowPrototypeChain()) { |
| 249 disposeContext(DoNotDetachGlobal); | 249 disposeContext(DoNotDetachGlobal); |
| 250 return false; | 250 return false; |
| 251 } | 251 } |
| 252 | 252 |
| 253 SecurityOrigin* origin = 0; | 253 SecurityOrigin* origin = 0; |
| 254 if (m_world->isMainWorld()) { | 254 if (m_world->isMainWorld()) { |
| 255 // ActivityLogger for main world is updated within updateDocument(). | 255 // ActivityLogger for main world is updated within updateDocument(). |
| 256 updateDocument(); | 256 updateDocument(); |
| 257 origin = m_frame->securityContext()->getSecurityOrigin(); | 257 origin = m_frame->securityContext()->getSecurityOrigin(); |
| 258 // FIXME: Can this be removed when CSP moves to browser? | 258 // FIXME: Can this be removed when CSP moves to browser? |
| 259 ContentSecurityPolicy* csp = m_frame->securityContext()->contentSecurity Policy(); | 259 ContentSecurityPolicy* csp = m_frame->securityContext()->contentSecurity Policy(); |
| 260 context->AllowCodeGenerationFromStrings(csp->allowEval(0, ContentSecurit yPolicy::SuppressReport)); | 260 context->AllowCodeGenerationFromStrings(csp->allowEval(0, ContentSecurit yPolicy::SuppressReport)); |
| 261 context->SetErrorMessageForCodeGenerationFromStrings(v8String(m_isolate, csp->evalDisabledErrorMessage())); | 261 context->SetErrorMessageForCodeGenerationFromStrings(v8String(m_isolate, csp->evalDisabledErrorMessage())); |
| 262 } else { | 262 } else { |
| 263 updateActivityLogger(); | 263 updateActivityLogger(); |
| 264 origin = m_world->isolatedWorldSecurityOrigin(); | 264 origin = m_world->isolatedWorldSecurityOrigin(); |
| 265 setSecurityToken(origin); | 265 setSecurityToken(origin); |
| 266 } | 266 } |
| 267 if (m_frame->isLocalFrame()) { | 267 if (m_frame->isLocalFrame()) { |
| 268 LocalFrame* frame = toLocalFrame(m_frame); | 268 LocalFrame* frame = toLocalFrame(m_frame); |
| 269 MainThreadDebugger::instance()->contextCreated(m_scriptState.get(), fram e, origin); | 269 MainThreadDebugger::instance()->contextCreated(m_scriptState.get(), fram e, origin); |
| 270 frame->loader().client()->didCreateScriptContext(context, m_world->exten sionGroup(), m_world->worldId()); | 270 frame->loader().client()->didCreateScriptContext(context, m_world->exten sionGroup(), m_world->worldId()); |
| 271 } | 271 } |
| 272 return true; | 272 return true; |
| 273 } | 273 } |
| 274 | 274 |
| 275 namespace { | |
| 276 | |
| 277 void configureInnerGlobalObjectTemplate(v8::Local<v8::ObjectTemplate> templ, v8: :Isolate* isolate) | |
| 278 { | |
| 279 // Install a security handler with V8. | |
| 280 templ->SetAccessCheckCallback(V8Window::securityCheckCustom, v8::External::N ew(isolate, const_cast<WrapperTypeInfo*>(&V8Window::wrapperTypeInfo))); | |
| 281 templ->SetInternalFieldCount(V8Window::internalFieldCount); | |
| 282 } | |
| 283 | |
| 284 v8::Local<v8::ObjectTemplate> getInnerGlobalObjectTemplate(v8::Isolate* isolate) | |
| 285 { | |
| 286 // It is OK to share the same object template between the main world and | |
| 287 // non-main worlds because the inner global object doesn't install any | |
| 288 // DOM attributes/methods. | |
| 289 DEFINE_STATIC_LOCAL(v8::Persistent<v8::ObjectTemplate>, innerGlobalObjectTem plate, ()); | |
| 290 if (innerGlobalObjectTemplate.IsEmpty()) { | |
| 291 TRACE_EVENT_SCOPED_SAMPLING_STATE("blink", "BuildDOMTemplate"); | |
| 292 v8::Local<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate); | |
| 293 configureInnerGlobalObjectTemplate(templ, isolate); | |
| 294 innerGlobalObjectTemplate.Reset(isolate, templ); | |
| 295 } | |
| 296 return v8::Local<v8::ObjectTemplate>::New(isolate, innerGlobalObjectTemplate ); | |
| 297 } | |
| 298 | |
| 299 } // namespace | |
| 300 | |
| 301 void WindowProxy::createContext() | 275 void WindowProxy::createContext() |
| 302 { | 276 { |
| 303 // FIXME: This should be a null check of m_frame->client(), but there are st ill some edge cases | 277 // FIXME: This should be a null check of m_frame->client(), but there are st ill some edge cases |
| 304 // that this fails to catch during frame detach. | 278 // that this fails to catch during frame detach. |
| 305 if (m_frame->isLocalFrame() && !toLocalFrame(m_frame)->loader().documentLoad er()) | 279 if (m_frame->isLocalFrame() && !toLocalFrame(m_frame)->loader().documentLoad er()) |
| 306 return; | 280 return; |
| 307 | 281 |
| 308 // Create a new environment using an empty template for the shadow | 282 // Create a new v8::Context with the window object as the global object |
| 309 // object. Reuse the global object if one has been created earlier. | 283 // (aka the inner global). Reuse the global proxy object (aka the outer |
| 310 v8::Local<v8::ObjectTemplate> globalTemplate = getInnerGlobalObjectTemplate( m_isolate); | 284 // global) if it already exists. See the comments in |
| 285 // setupWindowPrototypeChain for the structure of the prototype chain of | |
| 286 // the global object. | |
| 287 v8::Local<v8::ObjectTemplate> globalTemplate = V8Window::domTemplate(m_isola te, *m_world)->InstanceTemplate(); | |
| 311 if (globalTemplate.IsEmpty()) | 288 if (globalTemplate.IsEmpty()) |
| 312 return; | 289 return; |
| 313 | 290 |
| 314 // FIXME: It's not clear what the right thing to do for remote frames is. | 291 // FIXME: It's not clear what the right thing to do for remote frames is. |
| 315 // The extensions registered don't generally seem to make sense for remote | 292 // The extensions registered don't generally seem to make sense for remote |
| 316 // frames, so skip it for now. | 293 // frames, so skip it for now. |
| 317 Vector<const char*> extensionNames; | 294 Vector<const char*> extensionNames; |
| 318 if (m_frame->isLocalFrame()) { | 295 if (m_frame->isLocalFrame()) { |
| 319 LocalFrame* frame = toLocalFrame(m_frame); | 296 LocalFrame* frame = toLocalFrame(m_frame); |
| 320 // Dynamically tell v8 about our extensions now. | 297 // Dynamically tell v8 about our extensions now. |
| 321 const V8Extensions& extensions = ScriptController::registeredExtensions( ); | 298 const V8Extensions& extensions = ScriptController::registeredExtensions( ); |
| 322 extensionNames.reserveInitialCapacity(extensions.size()); | 299 extensionNames.reserveInitialCapacity(extensions.size()); |
| 323 int extensionGroup = m_world->extensionGroup(); | 300 int extensionGroup = m_world->extensionGroup(); |
| 324 int worldId = m_world->worldId(); | 301 int worldId = m_world->worldId(); |
| 325 for (const auto* extension : extensions) { | 302 for (const auto* extension : extensions) { |
| 326 if (!frame->loader().client()->allowScriptExtension(extension->name( ), extensionGroup, worldId)) | 303 if (!frame->loader().client()->allowScriptExtension(extension->name( ), extensionGroup, worldId)) |
| 327 continue; | 304 continue; |
| 328 | 305 |
| 329 extensionNames.append(extension->name()); | 306 extensionNames.append(extension->name()); |
| 330 } | 307 } |
| 331 } | 308 } |
| 332 v8::ExtensionConfiguration extensionConfiguration(extensionNames.size(), ext ensionNames.data()); | 309 v8::ExtensionConfiguration extensionConfiguration(extensionNames.size(), ext ensionNames.data()); |
| 333 | 310 |
| 334 v8::Local<v8::Context> context = v8::Context::New(m_isolate, &extensionConfi guration, globalTemplate, m_global.newLocal(m_isolate)); | 311 v8::Local<v8::Context> context; |
| 312 { | |
| 313 V8PerIsolateData::UseCounterDisabledScope useCounterDisabled(V8PerIsolat eData::from(m_isolate)); | |
| 314 context = v8::Context::New(m_isolate, &extensionConfiguration, globalTem plate, m_global.newLocal(m_isolate)); | |
| 315 } | |
| 335 if (context.IsEmpty()) | 316 if (context.IsEmpty()) |
| 336 return; | 317 return; |
| 337 m_scriptState = ScriptState::create(context, m_world); | 318 m_scriptState = ScriptState::create(context, m_world); |
| 338 } | 319 } |
| 339 | 320 |
| 340 static v8::Local<v8::Object> toInnerGlobalObject(v8::Local<v8::Context> context) | 321 bool WindowProxy::setupWindowPrototypeChain() |
| 341 { | 322 { |
| 342 return v8::Local<v8::Object>::Cast(context->Global()->GetPrototype()); | 323 // Associate the window wrapper object and its prototype chain with the |
| 343 } | 324 // corresponding native DOMWindow object. |
| 325 // The full structure of the global object's prototype chain is as follows: | |
| 326 // | |
| 327 // global proxy object [1] | |
| 328 // -- has prototype --> global object (window wrapper object) [2] | |
|
haraken
2016/04/18 08:04:15
I'd rename:
- "global proxy object" => "outer glo
| |
| 329 // -- has prototype --> Window.prototype | |
| 330 // -- has prototype --> WindowProperties [3] | |
| 331 // -- has prototype --> EventTarget.prototype | |
| 332 // -- has prototype --> Object.prototype | |
| 333 // -- has prototype --> null | |
| 334 // | |
| 335 // [1] Global proxy object is as known as "outer global object". It's an | |
| 336 // empty object and remains after navigation. When navigated, points to | |
| 337 // a different global object as the prototype object. | |
| 338 // [2] Global object is as known as "inner global object" or "window wrapper | |
| 339 // object". The prototype chain between global proxy object and global | |
| 340 // object is NOT observable from user JavaScript code. All other | |
| 341 // prototype chains are observable. Global proxy object and global object | |
| 342 // together appear to be the same single JavaScript object. See also: | |
| 343 // https://wiki.mozilla.org/Gecko:SplitWindow | |
| 344 // global object (= window wrapper object) provides most of Window's DOM | |
| 345 // attributes and operations. Also global variables defined by user | |
| 346 // JavaScript are placed on this object. When navigated, a new global | |
| 347 // object is created together with a new v8::Context, but the global proxy | |
| 348 // object doesn't change. | |
| 349 // [3] WindowProperties is a named properties object of Window interface. | |
| 344 | 350 |
| 345 bool WindowProxy::installDOMWindow() | |
| 346 { | |
| 347 DOMWindow* window = m_frame->domWindow(); | 351 DOMWindow* window = m_frame->domWindow(); |
| 348 const WrapperTypeInfo* wrapperTypeInfo = window->wrapperTypeInfo(); | 352 const WrapperTypeInfo* wrapperTypeInfo = window->wrapperTypeInfo(); |
| 349 v8::Local<v8::Object> windowWrapper; | 353 |
| 350 v8::Local<v8::Function> constructor = m_scriptState->perContextData()->const ructorForType(wrapperTypeInfo); | 354 v8::Local<v8::Context> context = m_scriptState->context(); |
| 351 if (constructor.IsEmpty()) | 355 // The global proxy object. Note this is not the global object. |
| 352 return false; | 356 v8::Local<v8::Object> globalProxy = context->Global(); |
| 353 if (!V8ObjectConstructor::newInstance(m_isolate, constructor).ToLocal(&windo wWrapper)) | 357 // The global object, aka window wrapper object. |
| 354 return false; | 358 v8::Local<v8::Object> windowWrapper = globalProxy->GetPrototype().As<v8::Obj ect>(); |
| 355 windowWrapper = V8DOMWrapper::associateObjectWithWrapper(m_isolate, window, wrapperTypeInfo, windowWrapper); | 359 windowWrapper = V8DOMWrapper::associateObjectWithWrapper(m_isolate, window, wrapperTypeInfo, windowWrapper); |
| 356 | 360 // The prototype object of Window interface. |
| 357 v8::Local<v8::Object> windowPrototype = v8::Local<v8::Object>::Cast(windowWr apper->GetPrototype()); | 361 v8::Local<v8::Object> windowPrototype = windowWrapper->GetPrototype().As<v8: :Object>(); |
| 358 RELEASE_ASSERT(!windowPrototype.IsEmpty()); | 362 RELEASE_ASSERT(!windowPrototype.IsEmpty()); |
| 359 V8DOMWrapper::setNativeInfo(windowPrototype, wrapperTypeInfo, window); | 363 V8DOMWrapper::setNativeInfo(windowPrototype, wrapperTypeInfo, window); |
|
haraken
2016/04/18 08:04:15
Not directly related to this CL, do you know why w
Yuki
2016/04/18 08:27:07
Not sure. I vaguely guess that we can remove it.
| |
| 360 v8::Local<v8::Object> windowProperties = v8::Local<v8::Object>::Cast(windowP rototype->GetPrototype()); | 364 // The named properties object of Window interface. |
| 365 v8::Local<v8::Object> windowProperties = windowPrototype->GetPrototype().As< v8::Object>(); | |
| 361 RELEASE_ASSERT(!windowProperties.IsEmpty()); | 366 RELEASE_ASSERT(!windowProperties.IsEmpty()); |
| 362 V8DOMWrapper::setNativeInfo(windowProperties, wrapperTypeInfo, window); | 367 V8DOMWrapper::setNativeInfo(windowProperties, wrapperTypeInfo, window); |
|
haraken
2016/04/18 08:04:15
Ditto.
| |
| 363 | 368 |
| 364 // Install the windowWrapper as the prototype of the innerGlobalObject. | |
| 365 // The full structure of the global object is as follows: | |
| 366 // | |
| 367 // outerGlobalObject (Empty object, remains after navigation) | |
| 368 // -- has prototype --> innerGlobalObject (Holds global variables, changes during navigation) | |
| 369 // -- has prototype --> DOMWindow instance | |
| 370 // -- has prototype --> Window.prototype | |
| 371 // -- has prototype --> WindowProperties (named properties object) | |
| 372 // -- has prototype --> EventTarget.prototype | |
| 373 // -- has prototype --> Object.prototype | |
| 374 // | |
| 375 // Note: Much of this prototype structure is hidden from web content. The | |
| 376 // outer, inner, and DOMWindow instance all appear to be the same | |
| 377 // JavaScript object. | |
| 378 v8::Local<v8::Context> context = m_scriptState->context(); | |
| 379 v8::Local<v8::Object> innerGlobalObject = toInnerGlobalObject(m_scriptState- >context()); | |
| 380 V8DOMWrapper::setNativeInfo(innerGlobalObject, wrapperTypeInfo, window); | |
| 381 if (!v8CallBoolean(innerGlobalObject->SetPrototype(context, windowWrapper))) | |
| 382 return false; | |
| 383 | |
| 384 // TODO(keishi): Remove installPagePopupController and implement | 369 // TODO(keishi): Remove installPagePopupController and implement |
| 385 // PagePopupController in another way. | 370 // PagePopupController in another way. |
| 386 V8PagePopupControllerBinding::installPagePopupController(context, windowWrap per); | 371 V8PagePopupControllerBinding::installPagePopupController(context, windowWrap per); |
| 387 return true; | 372 return true; |
| 388 } | 373 } |
| 389 | 374 |
| 390 void WindowProxy::updateDocumentWrapper(v8::Local<v8::Object> wrapper) | 375 void WindowProxy::updateDocumentWrapper(v8::Local<v8::Object> wrapper) |
| 391 { | 376 { |
| 392 ASSERT(m_world->isMainWorld()); | 377 ASSERT(m_world->isMainWorld()); |
| 393 m_document.set(m_isolate, wrapper); | 378 m_document.set(m_isolate, wrapper); |
| (...skipping 166 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 560 } | 545 } |
| 561 | 546 |
| 562 void WindowProxy::updateSecurityOrigin(SecurityOrigin* origin) | 547 void WindowProxy::updateSecurityOrigin(SecurityOrigin* origin) |
| 563 { | 548 { |
| 564 if (!isContextInitialized()) | 549 if (!isContextInitialized()) |
| 565 return; | 550 return; |
| 566 setSecurityToken(origin); | 551 setSecurityToken(origin); |
| 567 } | 552 } |
| 568 | 553 |
| 569 } // namespace blink | 554 } // namespace blink |
| OLD | NEW |