diff options
author | aa@chromium.org <aa@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-03-13 23:26:13 +0000 |
---|---|---|
committer | aa@chromium.org <aa@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-03-13 23:26:13 +0000 |
commit | bad146c5b3b1a7d0368320fecdbd5b50dbe97501 (patch) | |
tree | 8d5aad70f51fcfba24ccebd3359b7d33209370d7 /webkit/port | |
parent | ccef48cca72fbc8905a643759092ee0d913aca9c (diff) | |
download | chromium_src-bad146c5b3b1a7d0368320fecdbd5b50dbe97501.zip chromium_src-bad146c5b3b1a7d0368320fecdbd5b50dbe97501.tar.gz chromium_src-bad146c5b3b1a7d0368320fecdbd5b50dbe97501.tar.bz2 |
Commit 40144. I had to move to to a separate CL to use gcl's
"try multiple commits" feature.
Review URL: http://codereview.chromium.org/46062
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@11683 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'webkit/port')
-rw-r--r-- | webkit/port/bindings/v8/NPV8Object.cpp | 2 | ||||
-rw-r--r-- | webkit/port/bindings/v8/ScriptController.cpp | 15 | ||||
-rw-r--r-- | webkit/port/bindings/v8/ScriptController.h | 7 | ||||
-rw-r--r-- | webkit/port/bindings/v8/v8_proxy.cpp | 135 | ||||
-rw-r--r-- | webkit/port/bindings/v8/v8_proxy.h | 16 |
5 files changed, 127 insertions, 48 deletions
diff --git a/webkit/port/bindings/v8/NPV8Object.cpp b/webkit/port/bindings/v8/NPV8Object.cpp index 829fd074..411439f 100644 --- a/webkit/port/bindings/v8/NPV8Object.cpp +++ b/webkit/port/bindings/v8/NPV8Object.cpp @@ -272,7 +272,7 @@ bool NPN_EvaluateHelper(NPP npp, bool popupsAllowed, NPObject* npobj, NPString* // Convert UTF-8 stream to WebCore::String. WebCore::String script = WebCore::String::fromUTF8(npscript->UTF8Characters, npscript->UTF8Length); - v8::Local<v8::Value> v8result = proxy->Evaluate(filename, 0, script, 0); + v8::Local<v8::Value> v8result = proxy->evaluate(WebCore::ScriptSourceCode(script, WebCore::KURL(filename)), 0); // If we had an error, return false. if (v8result.IsEmpty()) diff --git a/webkit/port/bindings/v8/ScriptController.cpp b/webkit/port/bindings/v8/ScriptController.cpp index 9dff0b8..84ad8b4 100644 --- a/webkit/port/bindings/v8/ScriptController.cpp +++ b/webkit/port/bindings/v8/ScriptController.cpp @@ -207,6 +207,10 @@ bool ScriptController::processingUserGesture() const return false; } +void ScriptController::evaluateInNewContext( + const Vector<ScriptSourceCode>& sources) { + m_proxy->evaluateInNewContext(sources); +} // Evaluate a script file in the environment of this proxy. ScriptValue ScriptController::evaluate(const ScriptSourceCode& sourceCode) @@ -217,14 +221,7 @@ ScriptValue ScriptController::evaluate(const ScriptSourceCode& sourceCode) return ScriptValue(); v8::Context::Scope scope(context); - - // HTMLTokenizer used to use base zero line numbers for scripts, now it - // uses base 1. This confuses v8, which uses line offsets from the - // first line. - v8::Local<v8::Value> obj = m_proxy->Evaluate(sourceCode.url(), - sourceCode.startLine() - 1, - sourceCode.source(), - NULL); + v8::Local<v8::Value> obj = m_proxy->evaluate(sourceCode, NULL); if (obj.IsEmpty() || obj->IsUndefined()) return ScriptValue(); @@ -289,7 +286,7 @@ void ScriptController::collectGarbage() v8::Context::Scope scope(context); - m_proxy->Evaluate("", 0, "if (window.gc) void(gc());", NULL); + m_proxy->evaluate(ScriptSourceCode("if (window.gc) void(gc());"), NULL); } NPRuntimeFunctions* ScriptController::functions() diff --git a/webkit/port/bindings/v8/ScriptController.h b/webkit/port/bindings/v8/ScriptController.h index 1d580fe..e1e9e25 100644 --- a/webkit/port/bindings/v8/ScriptController.h +++ b/webkit/port/bindings/v8/ScriptController.h @@ -42,6 +42,7 @@ #include "bindings/npruntime.h" #include <wtf/HashMap.h> +#include <wtf/Vector.h> #include "v8.h" #include "v8_proxy.h" @@ -151,6 +152,12 @@ public: // as a string. ScriptValue evaluate(const ScriptSourceCode&); + // Executes JavaScript in a new context associated with the web frame. The + // script gets its own global scope and its own prototypes for intrinsic + // JavaScript objects (String, Array, and so-on). It shares the wrappers for + // all DOM nodes and DOM constructors. + void evaluateInNewContext(const Vector<ScriptSourceCode>& sources); + // JSC has a WindowShell object, but for V8, the ScriptController // is the WindowShell. bool haveWindowShell() const { return true; } diff --git a/webkit/port/bindings/v8/v8_proxy.cpp b/webkit/port/bindings/v8/v8_proxy.cpp index 3ad7143..2725b99 100644 --- a/webkit/port/bindings/v8/v8_proxy.cpp +++ b/webkit/port/bindings/v8/v8_proxy.cpp @@ -42,6 +42,7 @@ #include "v8_custom.h" #include "v8_collection.h" #include "v8_nodefilter.h" +#include "V8DOMWindow.h" #include "ChromiumBridge.h" @@ -1356,20 +1357,60 @@ bool V8Proxy::HandleOutOfMemory() return true; } -v8::Local<v8::Value> V8Proxy::Evaluate(const String& fileName, int baseLine, - const String& str, Node* n) +void V8Proxy::evaluateInNewContext(const Vector<ScriptSourceCode>& sources) +{ + InitContextIfNeeded(); + + v8::HandleScope handleScope; + + // Set up the DOM window as the prototype of the new global object. + v8::Handle<v8::Context> windowContext = m_context; + v8::Handle<v8::Object> windowGlobal = windowContext->Global(); + v8::Handle<v8::Value> windowWrapper = + V8Proxy::LookupDOMWrapper(V8ClassIndex::DOMWINDOW, windowGlobal); + + ASSERT(V8Proxy::DOMWrapperToNative<DOMWindow>(windowWrapper) == + m_frame->domWindow()); + + v8::Persistent<v8::Context> context = + createNewContext(v8::Handle<v8::Object>()); + v8::Context::Scope context_scope(context); + v8::Handle<v8::Object> global = context->Global(); + + v8::Handle<v8::String> implicitProtoString = v8::String::New("__proto__"); + global->Set(implicitProtoString, windowWrapper); + + // Give the code running in the new context a way to get access to the + // original context. + global->Set(v8::String::New("contentWindow"), windowGlobal); + + // Run code in the new context. + for (size_t i = 0; i < sources.size(); ++i) + evaluate(sources[i], 0); + + // Using the default security token means that the canAccess is always + // called, which is slow. + // TODO(aa): Use tokens where possible. This will mean keeping track of all + // created contexts so that they can all be updated when the document domain + // changes. + context->UseDefaultSecurityToken(); + context.Dispose(); +} + +v8::Local<v8::Value> V8Proxy::evaluate(const ScriptSourceCode& source, Node* n) { ASSERT(v8::Context::InContext()); // Compile the script. - v8::Local<v8::String> code = v8ExternalString(str); + v8::Local<v8::String> code = v8ExternalString(source.source()); ChromiumBridge::traceEventBegin("v8.compile", n, ""); - v8::Handle<v8::Script> script = CompileScript(code, fileName, baseLine); + + // NOTE: For compatibility with WebCore, ScriptSourceCode's line starts at + // 1, whereas v8 starts at 0. + v8::Handle<v8::Script> script = CompileScript(code, source.url(), + source.startLine() - 1); ChromiumBridge::traceEventEnd("v8.compile", n, ""); - // Set inlineCode to true for <a href="javascript:doSomething()"> - // and false for <script>doSomething</script>. For some reason, fileName - // gives us this information. ChromiumBridge::traceEventBegin("v8.run", n, ""); v8::Local<v8::Value> result; { @@ -1378,7 +1419,11 @@ v8::Local<v8::Value> V8Proxy::Evaluate(const String& fileName, int baseLine, // evaluate from C++ when returning from here v8::TryCatch try_catch; try_catch.SetVerbose(true); - result = RunScript(script, fileName.isNull()); + + // Set inlineCode to true for <a href="javascript:doSomething()"> + // and false for <script>doSomething</script>. We make a rough guess at + // this based on whether the script source has a URL. + result = RunScript(script, source.url().string().isNull()); } ChromiumBridge::traceEventEnd("v8.run", n, ""); return result; @@ -2255,6 +2300,39 @@ bool V8Proxy::CheckNodeSecurity(Node* node) return CanAccessFrame(target, true); } +v8::Persistent<v8::Context> V8Proxy::createNewContext( + v8::Handle<v8::Object> global) +{ + v8::Persistent<v8::Context> 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; + + // Install a security handler with V8. + globalTemplate->SetAccessCheckCallbacks( + V8Custom::v8DOMWindowNamedSecurityCheck, + V8Custom::v8DOMWindowIndexedSecurityCheck, + v8::Integer::New(V8ClassIndex::DOMWINDOW)); + + // Dynamically tell v8 about our extensions now. + const char** extensionNames = new const char*[m_extensions.size()]; + int index = 0; + V8ExtensionList::iterator it = m_extensions.begin(); + while (it != m_extensions.end()) { + extensionNames[index++] = (*it)->name(); + ++it; + } + v8::ExtensionConfiguration extensions(m_extensions.size(), extensionNames); + result = v8::Context::New(&extensions, globalTemplate, global); + delete [] extensionNames; + extensionNames = 0; + + return result; +} // Create a new environment and setup the global object. // @@ -2316,32 +2394,7 @@ void V8Proxy::InitContextIfNeeded() v8_initialized = true; } - // 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> global_template = - V8DOMWindow::GetShadowObjectTemplate(); - if (global_template.IsEmpty()) - return; - - // Install a security handler with V8. - global_template->SetAccessCheckCallbacks( - V8Custom::v8DOMWindowNamedSecurityCheck, - V8Custom::v8DOMWindowIndexedSecurityCheck, - v8::Integer::New(V8ClassIndex::DOMWINDOW)); - - // Dynamically tell v8 about our extensions now. - const char** extension_names = new const char*[m_extensions.size()]; - int index = 0; - V8ExtensionList::iterator it = m_extensions.begin(); - while (it != m_extensions.end()) { - extension_names[index++] = (*it)->name(); - ++it; - } - v8::ExtensionConfiguration extensions(m_extensions.size(), extension_names); - m_context = v8::Context::New(&extensions, global_template, m_global); - delete [] extension_names; - extension_names = 0; - + m_context = createNewContext(m_global); if (m_context.IsEmpty()) return; @@ -3409,6 +3462,20 @@ v8::Handle<v8::Value> V8Proxy::WindowToV8Object(DOMWindow* window) if (!frame) return v8::Handle<v8::Object>(); + // Special case: Because of evaluateInNewContext() one DOMWindow can have + // multipe contexts and multiple global objects associated with it. When + // code running in one of those contexts accesses the window object, we + // want to return the global object associated with that context, not + // necessarily the first global object associated with that DOMWindow. + v8::Handle<v8::Context> current_context = v8::Context::GetCurrent(); + v8::Handle<v8::Object> current_global = current_context->Global(); + v8::Handle<v8::Object> windowWrapper = + LookupDOMWrapper(V8ClassIndex::DOMWINDOW, current_global); + if (!windowWrapper.IsEmpty()) + if (DOMWrapperToNative<DOMWindow>(windowWrapper) == window) + return current_global; + + // Otherwise, return the global object associated with this frame. v8::Handle<v8::Context> context = GetContext(frame); if (context.IsEmpty()) return v8::Handle<v8::Object>(); diff --git a/webkit/port/bindings/v8/v8_proxy.h b/webkit/port/bindings/v8/v8_proxy.h index 69747b5..cb0e433 100644 --- a/webkit/port/bindings/v8/v8_proxy.h +++ b/webkit/port/bindings/v8/v8_proxy.h @@ -13,10 +13,12 @@ #include "ChromiumBridge.h" #include "Node.h" #include "NodeFilter.h" -#include "SecurityOrigin.h" // for WebCore::SecurityOrigin #include "PlatformString.h" // for WebCore::String -#include <wtf/PassRefPtr.h> // so generated bindings don't have to +#include "ScriptSourceCode.h" // for WebCore::ScriptSourceCode +#include "SecurityOrigin.h" // for WebCore::SecurityOrigin #include <wtf/Assertions.h> +#include <wtf/PassRefPtr.h> // so generated bindings don't have to +#include <wtf/Vector.h> #include <iterator> #include <list> @@ -230,11 +232,16 @@ class V8Proxy { void setEventHandlerLineno(int lineno) { m_handlerLineno = lineno; } void finishedWithEvent(Event* event) { } + // Evaluate JavaScript in a new context. The script gets its own global scope + // and its own prototypes for intrinsic JavaScript objects (String, Array, + // and so-on). It shares the wrappers for all DOM nodes and DOM constructors. + void evaluateInNewContext(const Vector<ScriptSourceCode>& sources); + // Evaluate a script file in the current execution environment. // The caller must hold an execution context. // If cannot evalute the script, it returns an error. - v8::Local<v8::Value> Evaluate(const String& filename, int baseLine, - const String& code, Node* node); + v8::Local<v8::Value> evaluate(const ScriptSourceCode& source, + Node* node); // Run an already compiled script. v8::Local<v8::Value> RunScript(v8::Handle<v8::Script> script, @@ -445,6 +452,7 @@ class V8Proxy { static void RegisterExtension(v8::Extension* extension); private: + v8::Persistent<v8::Context> createNewContext(v8::Handle<v8::Object> global); void InitContextIfNeeded(); void DisconnectEventListeners(); void SetSecurityToken(); |