summaryrefslogtreecommitdiffstats
path: root/WebCore/bindings/v8/V8DOMWindowShell.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'WebCore/bindings/v8/V8DOMWindowShell.cpp')
-rw-r--r--WebCore/bindings/v8/V8DOMWindowShell.cpp619
1 files changed, 0 insertions, 619 deletions
diff --git a/WebCore/bindings/v8/V8DOMWindowShell.cpp b/WebCore/bindings/v8/V8DOMWindowShell.cpp
deleted file mode 100644
index 1a39a15..0000000
--- a/WebCore/bindings/v8/V8DOMWindowShell.cpp
+++ /dev/null
@@ -1,619 +0,0 @@
-/*
- * Copyright (C) 2008, 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 "V8DOMWindowShell.h"
-
-#include "PlatformBridge.h"
-#include "CSSMutableStyleDeclaration.h"
-#include "DateExtension.h"
-#include "DocumentLoader.h"
-#include "Frame.h"
-#include "FrameLoaderClient.h"
-#include "Page.h"
-#include "PageGroup.h"
-#include "ScriptController.h"
-#include "StorageNamespace.h"
-#include "V8Binding.h"
-#include "V8BindingState.h"
-#include "V8Collection.h"
-#include "V8ConsoleMessage.h"
-#include "V8DOMMap.h"
-#include "V8DOMWindow.h"
-#include "V8Document.h"
-#include "V8GCForContextDispose.h"
-#include "V8HTMLDocument.h"
-#include "V8HiddenPropertyName.h"
-#include "V8History.h"
-#include "V8Location.h"
-#include "V8Proxy.h"
-#include "WorkerContextExecutionProxy.h"
-
-#include <algorithm>
-#include <stdio.h>
-#include <utility>
-#include <v8-debug.h>
-#include <v8.h>
-#include <wtf/Assertions.h>
-#include <wtf/OwnArrayPtr.h>
-#include <wtf/StdLibExtras.h>
-#include <wtf/StringExtras.h>
-#include <wtf/UnusedParam.h>
-#include <wtf/text/CString.h>
-
-#ifdef ANDROID_INSTRUMENT
-#include "TimeCounter.h"
-#endif
-
-namespace WebCore {
-
-static void handleFatalErrorInV8()
-{
- // FIXME: We temporarily deal with V8 internal error situations
- // such as out-of-memory by crashing the renderer.
- CRASH();
-}
-
-static void reportFatalErrorInV8(const char* location, const char* message)
-{
- // V8 is shutdown, we cannot use V8 api.
- // The only thing we can do is to disable JavaScript.
- // FIXME: clean up V8Proxy and disable JavaScript.
- int memoryUsageMB = -1;
-#if PLATFORM(CHROMIUM)
- memoryUsageMB = ChromiumBridge::actualMemoryUsageMB();
-#endif
- printf("V8 error: %s (%s). Current memory usage: %d MB\n", message, location, memoryUsageMB);
- handleFatalErrorInV8();
-}
-
-// Returns the owner frame pointer of a DOM wrapper object. It only works for
-// these DOM objects requiring cross-domain access check.
-static Frame* getTargetFrame(v8::Local<v8::Object> host, v8::Local<v8::Value> data)
-{
- Frame* target = 0;
- WrapperTypeInfo* type = WrapperTypeInfo::unwrap(data);
- if (V8DOMWindow::info.equals(type)) {
- v8::Handle<v8::Object> window = V8DOMWrapper::lookupDOMWrapper(V8DOMWindow::GetTemplate(), host);
- if (window.IsEmpty())
- return target;
-
- DOMWindow* targetWindow = V8DOMWindow::toNative(window);
- target = targetWindow->frame();
- } else if (V8History::info.equals(type)) {
- History* history = V8History::toNative(host);
- target = history->frame();
- } else if (V8Location::info.equals(type)) {
- Location* location = V8Location::toNative(host);
- target = location->frame();
- }
- return target;
-}
-
-static void reportUnsafeJavaScriptAccess(v8::Local<v8::Object> host, v8::AccessType type, v8::Local<v8::Value> data)
-{
- Frame* target = getTargetFrame(host, data);
- if (target)
- V8Proxy::reportUnsafeAccessTo(target, V8Proxy::ReportLater);
-}
-
-PassRefPtr<V8DOMWindowShell> V8DOMWindowShell::create(Frame* frame)
-{
- return adoptRef(new V8DOMWindowShell(frame));
-}
-
-V8DOMWindowShell::V8DOMWindowShell(Frame* frame)
- : m_frame(frame)
-{
-}
-
-bool V8DOMWindowShell::isContextInitialized()
-{
- // m_context, m_global, and m_wrapperBoilerplates should
- // all be non-empty if if m_context is non-empty.
- ASSERT(m_context.IsEmpty() || !m_global.IsEmpty());
- return !m_context.IsEmpty();
-}
-
-void V8DOMWindowShell::disposeContextHandles()
-{
- if (!m_context.IsEmpty()) {
- m_frame->loader()->client()->didDestroyScriptContextForFrame();
- m_context.Dispose();
- m_context.Clear();
-
- // It's likely that disposing the context has created a lot of
- // garbage. Notify V8 about this so it'll have a chance of cleaning
- // it up when idle.
- V8GCForContextDispose::instance().notifyContextDisposed();
- }
-
- WrapperBoilerplateMap::iterator it = m_wrapperBoilerplates.begin();
- for (; it != m_wrapperBoilerplates.end(); ++it) {
- v8::Persistent<v8::Object> wrapper = it->second;
- wrapper.Dispose();
- wrapper.Clear();
- }
- m_wrapperBoilerplates.clear();
-}
-
-void V8DOMWindowShell::destroyGlobal()
-{
- if (!m_global.IsEmpty()) {
-#ifndef NDEBUG
- V8GCController::unregisterGlobalHandle(this, m_global);
-#endif
- m_global.Dispose();
- m_global.Clear();
- }
-}
-
-void V8DOMWindowShell::clearForClose()
-{
- if (!m_context.IsEmpty()) {
- v8::HandleScope handleScope;
-
- clearDocumentWrapper();
- disposeContextHandles();
- }
-}
-
-void V8DOMWindowShell::clearForNavigation()
-{
- if (!m_context.IsEmpty()) {
- v8::HandleScope handle;
- clearDocumentWrapper();
-
- v8::Context::Scope contextScope(m_context);
-
- // Clear the document wrapper cache before turning on access checks on
- // the old DOMWindow wrapper. This way, access to the document wrapper
- // will be protected by the security checks on the DOMWindow wrapper.
- clearDocumentWrapperCache();
-
- // Turn on access check on the old DOMWindow wrapper.
- v8::Handle<v8::Object> wrapper = V8DOMWrapper::lookupDOMWrapper(V8DOMWindow::GetTemplate(), m_global);
- ASSERT(!wrapper.IsEmpty());
- wrapper->TurnOnAccessCheck();
-
- // Separate the context from its global object.
- m_context->DetachGlobal();
-
- disposeContextHandles();
- }
-}
-
-// Create a new environment and setup the global object.
-//
-// The global object corresponds to a DOMWindow instance. However, to
-// allow properties of the JS DOMWindow instance to be shadowed, we
-// use a shadow object as the global object and use the JS DOMWindow
-// instance as the prototype for that shadow object. The JS DOMWindow
-// instance is undetectable from javascript code because the __proto__
-// accessors skip that object.
-//
-// The shadow object and the DOMWindow instance are seen as one object
-// from javascript. The javascript object that corresponds to a
-// DOMWindow instance is the shadow object. When mapping a DOMWindow
-// instance to a V8 object, we return the shadow object.
-//
-// To implement split-window, see
-// 1) https://bugs.webkit.org/show_bug.cgi?id=17249
-// 2) https://wiki.mozilla.org/Gecko:SplitWindow
-// 3) https://bugzilla.mozilla.org/show_bug.cgi?id=296639
-// we need to split the shadow object further into two objects:
-// an outer window and an inner window. The inner window is the hidden
-// prototype of the outer window. The inner window is the default
-// global object of the context. A variable declared in the global
-// scope is a property of the inner window.
-//
-// The outer window sticks to a Frame, it is exposed to JavaScript
-// via window.window, window.self, window.parent, etc. The outer window
-// has a security token which is the domain. The outer window cannot
-// have its own properties. window.foo = 'x' is delegated to the
-// inner window.
-//
-// When a frame navigates to a new page, the inner window is cut off
-// the outer window, and the outer window identify is preserved for
-// the frame. However, a new inner window is created for the new page.
-// If there are JS code holds a closure to the old inner window,
-// it won't be able to reach the outer window via its global object.
-bool V8DOMWindowShell::initContextIfNeeded()
-{
- // Bail out if the context has already been initialized.
- if (!m_context.IsEmpty())
- return false;
-
-#ifdef ANDROID_INSTRUMENT
- android::TimeCounter::start(android::TimeCounter::JavaScriptInitTimeCounter);
-#endif
-
- // Create a handle scope for all local handles.
- v8::HandleScope handleScope;
-
- // Setup the security handlers and message listener. This only has
- // to be done once.
- static bool isV8Initialized = false;
- if (!isV8Initialized) {
- // Tells V8 not to call the default OOM handler, binding code
- // will handle it.
- v8::V8::IgnoreOutOfMemoryException();
- v8::V8::SetFatalErrorHandler(reportFatalErrorInV8);
-
- v8::V8::SetGlobalGCPrologueCallback(&V8GCController::gcPrologue);
- v8::V8::SetGlobalGCEpilogueCallback(&V8GCController::gcEpilogue);
-
- v8::V8::AddMessageListener(&V8ConsoleMessage::handler);
-
- v8::V8::SetFailedAccessCheckCallbackFunction(reportUnsafeJavaScriptAccess);
-
- isV8Initialized = true;
- }
-
-
- m_context = createNewContext(m_global, 0);
- if (m_context.IsEmpty())
- return false;
-
- v8::Local<v8::Context> v8Context = v8::Local<v8::Context>::New(m_context);
- v8::Context::Scope contextScope(v8Context);
-
- // Store the first global object created so we can reuse it.
- if (m_global.IsEmpty()) {
- m_global = v8::Persistent<v8::Object>::New(v8Context->Global());
- // Bail out if allocation of the first global objects fails.
- if (m_global.IsEmpty()) {
- disposeContextHandles();
- return false;
- }
-#ifndef NDEBUG
- V8GCController::registerGlobalHandle(PROXY, this, m_global);
-#endif
- }
-
- if (!installHiddenObjectPrototype(v8Context)) {
- disposeContextHandles();
- return false;
- }
-
- if (!installDOMWindow(v8Context, m_frame->domWindow())) {
- disposeContextHandles();
- return false;
- }
-
- updateDocument();
-
- setSecurityToken();
-
- m_frame->loader()->client()->didCreateScriptContextForFrame();
-
- // FIXME: This is wrong. We should actually do this for the proper world once
- // we do isolated worlds the WebCore way.
- m_frame->loader()->dispatchDidClearWindowObjectInWorld(0);
-
-#ifdef ANDROID_INSTRUMENT
- android::TimeCounter::record(android::TimeCounter::JavaScriptInitTimeCounter, __FUNCTION__);
-#endif
-
- return true;
-}
-
-v8::Persistent<v8::Context> V8DOMWindowShell::createNewContext(v8::Handle<v8::Object> global, int extensionGroup)
-{
- v8::Persistent<v8::Context> result;
-
- // The activeDocumentLoader pointer could be 0 during frame shutdown.
- if (!m_frame->loader()->activeDocumentLoader())
- return result;
-
- // Create a new environment using an empty template for the shadow
- // object. Reuse the global object if one has been created earlier.
- v8::Persistent<v8::ObjectTemplate> globalTemplate = V8DOMWindow::GetShadowObjectTemplate();
- if (globalTemplate.IsEmpty())
- return result;
-
- // Used to avoid sleep calls in unload handlers.
- if (!V8Proxy::registeredExtensionWithV8(DateExtension::get()))
- V8Proxy::registerExtension(DateExtension::get());
-
- // Dynamically tell v8 about our extensions now.
- const V8Extensions& extensions = V8Proxy::extensions();
- OwnArrayPtr<const char*> extensionNames(new const char*[extensions.size()]);
- int index = 0;
- for (size_t i = 0; i < extensions.size(); ++i) {
- // Ensure our date extension is always allowed.
- if (extensions[i] != DateExtension::get()
- && !m_frame->loader()->client()->allowScriptExtension(extensions[i]->name(), extensionGroup))
- continue;
-
- extensionNames[index++] = extensions[i]->name();
- }
- v8::ExtensionConfiguration extensionConfiguration(index, extensionNames.get());
- result = v8::Context::New(&extensionConfiguration, globalTemplate, global);
-
- return result;
-}
-
-void V8DOMWindowShell::setContext(v8::Handle<v8::Context> context)
-{
- // if we already have a context, clear it before setting the new one.
- if (!m_context.IsEmpty()) {
- m_context.Dispose();
- m_context.Clear();
- }
- m_context = v8::Persistent<v8::Context>::New(context);
-}
-
-bool V8DOMWindowShell::installDOMWindow(v8::Handle<v8::Context> context, DOMWindow* window)
-{
- // Create a new JS window object and use it as the prototype for the shadow global object.
- v8::Handle<v8::Function> windowConstructor = V8DOMWrapper::getConstructor(&V8DOMWindow::info, getHiddenObjectPrototype(context));
- v8::Local<v8::Object> jsWindow = SafeAllocation::newInstance(windowConstructor);
- // Bail out if allocation failed.
- if (jsWindow.IsEmpty())
- return false;
-
- // Wrap the window.
- V8DOMWrapper::setDOMWrapper(jsWindow, &V8DOMWindow::info, window);
- V8DOMWrapper::setDOMWrapper(v8::Handle<v8::Object>::Cast(jsWindow->GetPrototype()), &V8DOMWindow::info, window);
-
- window->ref();
- V8DOMWrapper::setJSWrapperForDOMObject(window, v8::Persistent<v8::Object>::New(jsWindow));
-
- // Insert the window instance as the prototype of the shadow object.
- v8::Handle<v8::Object> v8RealGlobal = v8::Handle<v8::Object>::Cast(context->Global()->GetPrototype());
- V8DOMWrapper::setDOMWrapper(v8RealGlobal, &V8DOMWindow::info, window);
- v8RealGlobal->SetPrototype(jsWindow);
- return true;
-}
-
-void V8DOMWindowShell::updateDocumentWrapper(v8::Handle<v8::Object> wrapper)
-{
- clearDocumentWrapper();
-
- ASSERT(m_document.IsEmpty());
- m_document = v8::Persistent<v8::Object>::New(wrapper);
-#ifndef NDEBUG
- V8GCController::registerGlobalHandle(PROXY, this, m_document);
-#endif
-}
-
-void V8DOMWindowShell::clearDocumentWrapper()
-{
- if (!m_document.IsEmpty()) {
-#ifndef NDEBUG
- V8GCController::unregisterGlobalHandle(this, m_document);
-#endif
- m_document.Dispose();
- m_document.Clear();
- }
-}
-
-static void checkDocumentWrapper(v8::Handle<v8::Object> wrapper, Document* document)
-{
- ASSERT(V8Document::toNative(wrapper) == document);
- ASSERT(!document->isHTMLDocument() || (V8Document::toNative(v8::Handle<v8::Object>::Cast(wrapper->GetPrototype())) == document));
-}
-
-void V8DOMWindowShell::updateDocumentWrapperCache()
-{
- v8::HandleScope handleScope;
- v8::Context::Scope contextScope(m_context);
-
- // If the document has no frame, NodeToV8Object might get the
- // document wrapper for a document that is about to be deleted.
- // If the ForceSet below causes a garbage collection, the document
- // might get deleted and the global handle for the document
- // wrapper cleared. Using the cleared global handle will lead to
- // crashes. In this case we clear the cache and let the DOMWindow
- // accessor handle access to the document.
- if (!m_frame->document()->frame()) {
- clearDocumentWrapperCache();
- return;
- }
-
- v8::Handle<v8::Value> documentWrapper = toV8(m_frame->document());
- ASSERT(documentWrapper == m_document || m_document.IsEmpty());
- if (m_document.IsEmpty())
- updateDocumentWrapper(v8::Handle<v8::Object>::Cast(documentWrapper));
- checkDocumentWrapper(m_document, m_frame->document());
-
- // If instantiation of the document wrapper fails, clear the cache
- // and let the DOMWindow accessor handle access to the document.
- if (documentWrapper.IsEmpty()) {
- clearDocumentWrapperCache();
- return;
- }
- ASSERT(documentWrapper->IsObject());
- m_context->Global()->ForceSet(v8::String::New("document"), documentWrapper, static_cast<v8::PropertyAttribute>(v8::ReadOnly | v8::DontDelete));
-}
-
-void V8DOMWindowShell::clearDocumentWrapperCache()
-{
- ASSERT(!m_context.IsEmpty());
- m_context->Global()->ForceDelete(v8::String::New("document"));
-}
-
-void V8DOMWindowShell::setSecurityToken()
-{
- Document* document = m_frame->document();
- // Setup security origin and security token.
- if (!document) {
- m_context->UseDefaultSecurityToken();
- return;
- }
-
- // Ask the document's SecurityOrigin to generate a security token.
- // If two tokens are equal, then the SecurityOrigins canAccess each other.
- // If two tokens are not equal, then we have to call canAccess.
- // Note: we can't use the HTTPOrigin if it was set from the DOM.
- SecurityOrigin* origin = document->securityOrigin();
- String token;
- if (!origin->domainWasSetInDOM())
- token = document->securityOrigin()->toString();
-
- // An empty or "null" token means we always have to call
- // canAccess. The toString method on securityOrigins returns the
- // string "null" for empty security origins and for security
- // origins that should only allow access to themselves. In this
- // case, we use the global object as the security token to avoid
- // calling canAccess when a script accesses its own objects.
- if (token.isEmpty() || token == "null") {
- m_context->UseDefaultSecurityToken();
- return;
- }
-
- CString utf8Token = token.utf8();
- // NOTE: V8 does identity comparison in fast path, must use a symbol
- // as the security token.
- m_context->SetSecurityToken(v8::String::NewSymbol(utf8Token.data(), utf8Token.length()));
-}
-
-void V8DOMWindowShell::updateDocument()
-{
- if (!m_frame->document())
- return;
-
- if (m_global.IsEmpty())
- return;
-
- // There is an existing JavaScript wrapper for the global object
- // of this frame. JavaScript code in other frames might hold a
- // reference to this wrapper. We eagerly initialize the JavaScript
- // context for the new document to make property access on the
- // global object wrapper succeed.
- initContextIfNeeded();
-
- // Bail out if context initialization failed.
- if (m_context.IsEmpty())
- return;
-
- // We have a new document and we need to update the cache.
- updateDocumentWrapperCache();
-
- updateSecurityOrigin();
-}
-
-v8::Handle<v8::Value> getter(v8::Local<v8::String> property, const v8::AccessorInfo& info)
-{
- // FIXME(antonm): consider passing AtomicStringImpl directly.
- AtomicString name = v8StringToAtomicWebCoreString(property);
- HTMLDocument* htmlDocument = V8HTMLDocument::toNative(info.Holder());
- ASSERT(htmlDocument);
- v8::Handle<v8::Value> result = V8HTMLDocument::GetNamedProperty(htmlDocument, name);
- if (!result.IsEmpty())
- return result;
- v8::Handle<v8::Value> prototype = info.Holder()->GetPrototype();
- if (prototype->IsObject())
- return prototype.As<v8::Object>()->Get(property);
- return v8::Undefined();
-}
-
-void V8DOMWindowShell::namedItemAdded(HTMLDocument* doc, const AtomicString& name)
-{
- initContextIfNeeded();
-
- v8::HandleScope handleScope;
- v8::Context::Scope contextScope(m_context);
-
- ASSERT(!m_document.IsEmpty());
- checkDocumentWrapper(m_document, doc);
- m_document->SetAccessor(v8String(name), getter);
-}
-
-void V8DOMWindowShell::namedItemRemoved(HTMLDocument* doc, const AtomicString& name)
-{
-}
-
-void V8DOMWindowShell::updateSecurityOrigin()
-{
- v8::HandleScope scope;
- setSecurityToken();
-}
-
-v8::Handle<v8::Value> V8DOMWindowShell::getHiddenObjectPrototype(v8::Handle<v8::Context> context)
-{
- return context->Global()->GetHiddenValue(V8HiddenPropertyName::objectPrototype());
-}
-
-bool V8DOMWindowShell::installHiddenObjectPrototype(v8::Handle<v8::Context> context)
-{
- v8::Handle<v8::String> objectString = v8::String::New("Object");
- v8::Handle<v8::String> prototypeString = v8::String::New("prototype");
- v8::Handle<v8::String> hiddenObjectPrototypeString = V8HiddenPropertyName::objectPrototype();
- // Bail out if allocation failed.
- if (objectString.IsEmpty() || prototypeString.IsEmpty() || hiddenObjectPrototypeString.IsEmpty())
- return false;
-
- v8::Handle<v8::Object> object = v8::Handle<v8::Object>::Cast(context->Global()->Get(objectString));
- // Bail out if fetching failed.
- if (object.IsEmpty())
- return false;
- v8::Handle<v8::Value> objectPrototype = object->Get(prototypeString);
- // Bail out if fetching failed.
- if (objectPrototype.IsEmpty())
- return false;
-
- context->Global()->SetHiddenValue(hiddenObjectPrototypeString, objectPrototype);
-
- return true;
-}
-
-v8::Local<v8::Object> V8DOMWindowShell::createWrapperFromCacheSlowCase(WrapperTypeInfo* type)
-{
- // Not in cache.
- initContextIfNeeded();
- v8::Context::Scope scope(m_context);
- v8::Local<v8::Function> function = V8DOMWrapper::getConstructor(type, getHiddenObjectPrototype(m_context));
- v8::Local<v8::Object> instance = SafeAllocation::newInstance(function);
- if (!instance.IsEmpty()) {
- m_wrapperBoilerplates.set(type, v8::Persistent<v8::Object>::New(instance));
- return instance->Clone();
- }
- return notHandledByInterceptor();
-}
-
-void V8DOMWindowShell::setLocation(DOMWindow* window, const String& relativeURL)
-{
- Frame* frame = window->frame();
- if (!frame)
- return;
-
- KURL url = completeURL(relativeURL);
- if (url.isNull())
- return;
-
- if (!shouldAllowNavigation(frame))
- return;
-
- navigateIfAllowed(frame, url, false, false);
-}
-
-} // WebCore