From bc2496aadbfd048e16807257f7278c5cf1472f43 Mon Sep 17 00:00:00 2001 From: "pkasting@chromium.org" Date: Wed, 15 Oct 2008 21:49:17 +0000 Subject: Fork ScriptController into KJS- and V8-specific versions. The KJS files already live in third_party/WebKit/WebCore/bindings/js/; the V8 ones will now live in webkit/bindings/v8/. The V8 version is V8-specific and doesn't have any #if USE(...) junk in it anymore; this matches the KJS one. This will break the Mac and SCons builds. Review URL: http://codereview.chromium.org/7368 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@3424 0039d316-1c4b-4281-b951-d872f2087c98 --- webkit/build/KJSBindings/KJSBindings.vcproj | 68 +-- webkit/build/V8Bindings/V8Bindings.vcproj | 6 +- webkit/build/port/port.vcproj | 4 - webkit/pending/ScriptController.h | 365 ----------------- webkit/port/bindings/v8/ScriptController.cpp | 589 ++++++++++++++++++++++++++ webkit/port/bindings/v8/ScriptController.h | 290 +++++++++++++ webkit/port/bridge/ScriptControllerKJS.cpp | 544 ------------------------ webkit/port/bridge/ScriptControllerV8.cpp | 590 --------------------------- 8 files changed, 922 insertions(+), 1534 deletions(-) delete mode 100644 webkit/pending/ScriptController.h create mode 100644 webkit/port/bindings/v8/ScriptController.cpp create mode 100644 webkit/port/bindings/v8/ScriptController.h delete mode 100644 webkit/port/bridge/ScriptControllerKJS.cpp delete mode 100644 webkit/port/bridge/ScriptControllerV8.cpp (limited to 'webkit') diff --git a/webkit/build/KJSBindings/KJSBindings.vcproj b/webkit/build/KJSBindings/KJSBindings.vcproj index 39867ef..0de53be 100644 --- a/webkit/build/KJSBindings/KJSBindings.vcproj +++ b/webkit/build/KJSBindings/KJSBindings.vcproj @@ -1434,6 +1434,14 @@ + + + + @@ -1608,6 +1616,14 @@ + + + + + + + + + - - - - - - - - - - diff --git a/webkit/build/V8Bindings/V8Bindings.vcproj b/webkit/build/V8Bindings/V8Bindings.vcproj index cc48ed2..096ea37 100644 --- a/webkit/build/V8Bindings/V8Bindings.vcproj +++ b/webkit/build/V8Bindings/V8Bindings.vcproj @@ -2437,7 +2437,11 @@ > + + - - -#endif - -#include - -#if USE(V8) -#include "v8.h" -#include "v8_proxy.h" -#endif - -// JavaScript implementations which expose NPObject will need to implement -// these methods. -typedef void (*NPN_ReleaseVariantValueProcPtr) (NPVariant *variant); - -typedef NPIdentifier(*NPN_GetStringIdentifierProcPtr) (const NPUTF8 *name); -typedef void (*NPN_GetStringIdentifiersProcPtr) (const NPUTF8 **names, - int32_t nameCount, - NPIdentifier *identifiers); -typedef NPIdentifier(*NPN_GetIntIdentifierProcPtr) (int32_t intid); -typedef int32_t (*NPN_IntFromIdentifierProcPtr) (NPIdentifier identifier); -typedef bool (*NPN_IdentifierIsStringProcPtr) (NPIdentifier identifier); -typedef NPUTF8 * (*NPN_UTF8FromIdentifierProcPtr) (NPIdentifier identifier); - -typedef NPObject* (*NPN_CreateObjectProcPtr) (NPP, - NPClass *aClass); -typedef NPObject* (*NPN_RetainObjectProcPtr) (NPObject *obj); -typedef void (*NPN_ReleaseObjectProcPtr) (NPObject *obj); -typedef bool (*NPN_InvokeProcPtr) (NPP npp, - NPObject *obj, - NPIdentifier methodName, - const NPVariant *args, - unsigned argCount, - NPVariant *result); -typedef bool (*NPN_InvokeDefaultProcPtr) (NPP npp, - NPObject *obj, - const NPVariant *args, - unsigned argCount, - NPVariant *result); -typedef bool (*NPN_EvaluateProcPtr) (NPP npp, - NPObject *obj, - NPString *script, - NPVariant *result); -typedef bool (*NPN_GetPropertyProcPtr) (NPP npp, - NPObject *obj, - NPIdentifier propertyName, - NPVariant *result); -typedef bool (*NPN_SetPropertyProcPtr) (NPP npp, - NPObject *obj, - NPIdentifier propertyName, - const NPVariant *value); -typedef bool (*NPN_HasPropertyProcPtr) (NPP, - NPObject *npobj, - NPIdentifier propertyName); -typedef bool (*NPN_HasMethodProcPtr) (NPP npp, - NPObject *npobj, - NPIdentifier methodName); -typedef bool (*NPN_RemovePropertyProcPtr) (NPP npp, - NPObject *obj, - NPIdentifier propertyName); -typedef void (*NPN_SetExceptionProcPtr) (NPObject *obj, - const NPUTF8 *message); - -typedef struct _NPRuntimeFunctions { - NPN_GetStringIdentifierProcPtr getStringIdentifier; - NPN_GetStringIdentifiersProcPtr getStringIdentifiers; - NPN_GetIntIdentifierProcPtr getIntIdentifier; - NPN_IdentifierIsStringProcPtr identifierIsString; - NPN_UTF8FromIdentifierProcPtr utf8FromIdentifier; - NPN_IntFromIdentifierProcPtr intFromIdentifier; - NPN_CreateObjectProcPtr createObject; - NPN_RetainObjectProcPtr retainObject; - NPN_ReleaseObjectProcPtr releaseObject; - NPN_InvokeProcPtr invoke; - NPN_InvokeDefaultProcPtr invokeDefault; - NPN_EvaluateProcPtr evaluate; - NPN_GetPropertyProcPtr getProperty; - NPN_SetPropertyProcPtr setProperty; - NPN_RemovePropertyProcPtr removeProperty; - NPN_HasPropertyProcPtr hasProperty; - NPN_HasMethodProcPtr hasMethod; - NPN_ReleaseVariantValueProcPtr releaseVariantValue; - NPN_SetExceptionProcPtr setException; -} NPRuntimeFunctions; - -#if USE(JSC) -namespace KJS { - namespace Bindings { - class Instance; - class RootObject; - } -} -#endif - -namespace WebCore { -class Document; -class EventListener; -class Event; -class Frame; -class HTMLPlugInElement; -class Node; -class PausedTimeouts; -class String; -class Widget; - -// JSString is the string class used for XMLHttpRequest's -// m_responseText field. -#if USE(JSC) -typedef HashMap > RootObjectMap; -typedef KJS::UString JSString; -typedef KJS::Bindings::Instance* JSInstance; -typedef PassRefPtr JSInstanceHandle; -typedef RefPtr JSPersistentInstance; -typedef KJS::JSValue* JSException; -typedef KJS::JSValue* JSResult; -#endif - -#if USE(V8) -typedef String JSString; -typedef v8::Local JSInstance; -typedef v8::Local JSInstanceHandle; -typedef v8::Persistent JSPersistentInstance; -typedef v8::Local JSException; -typedef v8::Persistent JSResult; -#endif - -class ScriptController { -public: - ScriptController(Frame*); - ~ScriptController(); - -#if USE(JSC) - bool haveWindowShell() const { return m_windowShell; } - JSDOMWindowShell* windowShell() - { - initScriptIfNeeded(); - return m_windowShell; - } - - JSDOMWindow* globalObject() - { - initScriptIfNeeded(); - return m_windowShell->window(); - } -#endif - -#if USE(V8) - // TODO(eseidel): V8Proxy should either be folded into ScriptController - // or this accessor should be made JSProxy* - V8Proxy* proxy() { return m_proxy.get(); } -#endif - - // Evaluate a script file in the environment of this proxy. - // If succeeded, 'succ' is set to true and result is returned - // as a string. - String evaluate(const String& filename, int baseLine, const String& code, Node* node = NULL, bool* succ = NULL); - - // Second API function for evaluating a JS code. - // It returns a JSResult which must be disposed by calling - // disposeJSResult. If the result is not disposed, it can cause - // serious memory leak. The caller determines whether the evaluation - // is successful by checking the value of JSResult. - JSResult evaluate(const String& filename, int baseLine, const String& code, Node*); - void disposeJSResult(JSResult result); - void collectGarbage(); - - PassRefPtr createHTMLEventHandler(const String& functionName, const String& code, Node*); -#if ENABLE(SVG) - PassRefPtr createSVGEventHandler(const String& functionName, const String& code, Node*); -#endif - - // Creates a property of the global object of a frame. - void BindToWindowObject(Frame*, const String& key, NPObject*); - - NPRuntimeFunctions* functions(); - - JSInstanceHandle createScriptInstanceForWidget(Widget*); - - void clearPluginObjects(); - void clearDocumentWrapper(); - void disconnectFrame(); - - // Check if the javascript engine has been initialized. - bool haveInterpreter() const; - - bool isEnabled() const; - - // TODO(eseidel): void* is a compile hack - void attachDebugger(void*); - - // Create a NPObject wrapper for a JSObject - // NPObject *WrapScriptObject(NPP pluginId, JSObject* objectToWrap, - // JSRootObject* originRootObject, - // JSRootObject* rootObject); - - // --- Static methods assume we are running VM in single thread, --- - // --- and there is only one VM instance. --- - - // Returns the frame of the calling code is in. - // Not necessary the frame of this proxy. - // For example, JS code in frame A calls windowB.open(...). - // Window::open method has the frame pointer of B, but - // the execution context is in frame A, so it needs - // frame A's loader to complete URL. - static Frame* retrieveActiveFrame(); - - // Check whether it is safe to access a frame in another domain. - static bool isSafeScript(Frame* target); - - // Tell the proxy that document.domain is set. - static void setDomain(Frame* target, const String& newDomain); - - // Pass command-line flags to the JS engine - static void setFlags(const char* str, int length); - - // Protect and unprotect the JS wrapper from garbage collected. - static void gcProtectJSWrapper(void* object); - static void gcUnprotectJSWrapper(void* object); - - // Get/Set RecordPlaybackMode flag. - // This is a special mode where JS helps the browser implement - // playback/record mode. Generally, in this mode, some functions - // of client-side randomness are removed. For example, in - // this mode Math.random() and Date.getTime() may not return - // values which vary. - static bool RecordPlaybackMode() { return m_recordPlaybackMode; } - static void setRecordPlaybackMode(bool value) { m_recordPlaybackMode = value; } - - void finishedWithEvent(Event*); - void setEventHandlerLineno(int lineno); - - void setProcessingTimerCallback(bool b) { m_processingTimerCallback = b; } - bool processingUserGesture() const; - - void setPaused(bool b) { m_paused = b; } - bool isPaused() const { return m_paused; } - - const String* sourceURL() const { return m_sourceURL; } // 0 if we are not evaluating any script - - void clearWindowShell(); - void updateDocument(); - - void pauseTimeouts(OwnPtr&); - void resumeTimeouts(OwnPtr&); - - void clearScriptObjects(); - void cleanupScriptObjectsForPlugin(void*); - -#if USE(JSC) - KJS::Bindings::RootObject* bindingRootObject(); -#endif - -#if ENABLE(NETSCAPE_PLUGIN_API) - NPObject* createScriptObjectForPluginElement(HTMLPlugInElement*); - NPObject* windowScriptNPObject(); -#endif - -private: -#if USE(JSC) - void initScriptIfNeeded() - { - if (!m_windowShell) - initScript(); - } - void initScript(); - - void clearPlatformScriptObjects(); - void disconnectPlatformScriptObjects(); - - KJS::ProtectedPtr m_windowShell; - HashSet m_liveFormerWindows; - int m_handlerLineno; -#endif - - static bool m_recordPlaybackMode; - - Frame* m_frame; - const String* m_sourceURL; - - bool m_processingTimerCallback; - bool m_paused; - -#if USE(V8) - OwnPtr m_proxy; - typedef HashMap PluginObjectMap; -#endif - -#if USE(JSC) - // The root object used for objects bound outside the context of a plugin. - RefPtr m_bindingRootObject; - RootObjectMap m_rootObjects; -#elif USE(V8) - // A mapping between Widgets and their corresponding script object. - // This list is used so that when the plugin dies, we can immediately - // invalidate all sub-objects which are associated with that plugin. - // The frame keeps a NPObject reference for each item on the list. - PluginObjectMap m_pluginObjects; -#endif -#if ENABLE(NETSCAPE_PLUGIN_API) - NPObject* m_windowScriptNPObject; -#endif -}; - -// JSInstance is an abstraction for a wrapped C class. JSC and V8 -// have very different implementations. -class JSInstanceHolder { -public: - JSInstanceHolder(); - JSInstanceHolder(JSInstanceHandle); - ~JSInstanceHolder(); - // Returns true if the holder is empty. - bool IsEmpty(); - // Get the contained JSInstance. - JSInstance Get(); - // Clear the contained JSInstance. - void Clear(); - JSInstanceHolder& operator=(JSInstanceHandle); - static JSInstance EmptyInstance(); - -private: - JSPersistentInstance m_instance; -}; - -} // namespace WebCore - -#endif // ScriptController_h diff --git a/webkit/port/bindings/v8/ScriptController.cpp b/webkit/port/bindings/v8/ScriptController.cpp new file mode 100644 index 0000000..fa751a7 --- /dev/null +++ b/webkit/port/bindings/v8/ScriptController.cpp @@ -0,0 +1,589 @@ +// Copyright (c) 2008, 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 "ScriptController.h" + +#include "CString.h" +#include "Document.h" +#include "DOMWindow.h" +#include "Event.h" +#include "EventListener.h" +#include "EventNames.h" +#include "Frame.h" +#include "Node.h" +#include "NotImplemented.h" +#include "npruntime_priv.h" +#include "np_v8object.h" +#include "Widget.h" + +#include "v8_proxy.h" +#include "v8_binding.h" +#include "v8_npobject.h" + +//TODO(eseidel): We should remove this glue dependency +#undef LOG // glue defines its own LOG macro +#include "webkit/glue/webplugin_impl.h" + +NPRuntimeFunctions npruntime_functions = { + NPN_GetStringIdentifier, + NPN_GetStringIdentifiers, + NPN_GetIntIdentifier, + NPN_IdentifierIsString, + NPN_UTF8FromIdentifier, + NPN_IntFromIdentifier, + NPN_CreateObject, + NPN_RetainObject, + NPN_ReleaseObject, + NPN_Invoke, + NPN_InvokeDefault, + NPN_Evaluate, + NPN_GetProperty, + NPN_SetProperty, + NPN_RemoveProperty, + NPN_HasProperty, + NPN_HasMethod, + NPN_ReleaseVariantValue, + NPN_SetException +}; + + +namespace WebCore { + +bool ScriptController::m_recordPlaybackMode = false; + +void ScriptController::setFlags(const char* str, int length) +{ + v8::V8::SetFlagsFromString(str, length); +} + +void ScriptController::setDomain(Frame* frame, const String&) +{ + V8Proxy::DomainChanged(frame); +} + +Frame* ScriptController::retrieveActiveFrame() +{ + return V8Proxy::retrieveActiveFrame(); +} + +bool ScriptController::isSafeScript(Frame* target) +{ + return V8Proxy::IsFromSameOrigin(target, true); +} + +void ScriptController::gcProtectJSWrapper(void* dom_object) +{ + V8Proxy::GCProtect(static_cast(dom_object)); +} + +void ScriptController::gcUnprotectJSWrapper(void* dom_object) +{ + V8Proxy::GCUnprotect(static_cast(dom_object)); +} + +void ScriptController::pauseTimeouts(OwnPtr& result) +{ + DOMWindow* window = m_frame->domWindow(); + if (!window) { + result.clear(); + return; + } + window->pauseTimeouts(result); +} + +void ScriptController::resumeTimeouts(OwnPtr& timeouts) +{ + DOMWindow* window = m_frame->domWindow(); + if (!window) { + timeouts.clear(); + return; + } + window->resumeTimeouts(timeouts); +} + +ScriptController::ScriptController(Frame* frame) + : m_frame(frame) + , m_sourceURL(0) + , m_processingTimerCallback(false) + , m_paused(false) + , m_proxy(new V8Proxy(frame)) +#if ENABLE(NETSCAPE_PLUGIN_API) + , m_windowScriptNPObject(0) +#endif +{ +} + +ScriptController::~ScriptController() +{ +} + +void ScriptController::clearScriptObjects() +{ + // TODO(eseidel): JSC handles binding root objects here, why don't we? + +#if ENABLE(NETSCAPE_PLUGIN_API) + if (m_windowScriptNPObject) { + // Call _NPN_DeallocateObject() instead of _NPN_ReleaseObject() so that we don't leak if a plugin fails to release the window + // script object properly. + // This shouldn't cause any problems for plugins since they should have already been stopped and destroyed at this point. + _NPN_DeallocateObject(m_windowScriptNPObject); + m_windowScriptNPObject = 0; + } +#endif +} + +void ScriptController::clearPluginObjects() +{ + PluginObjectMap::iterator it = m_pluginObjects.begin(); + for (; it != m_pluginObjects.end(); ++it) { + _NPN_UnregisterObject(it->second); + NPN_ReleaseObject(it->second); + } + m_pluginObjects.clear(); +} + +// Disconnect the proxy from its owner frame; +void ScriptController::disconnectFrame() +{ + m_proxy->disconnectFrame(); +} + +bool ScriptController::processingUserGesture() const +{ + Frame* active_frame = V8Proxy::retrieveActiveFrame(); + // No script is running, must be run by users. + if (!active_frame) + return true; + + V8Proxy* active_proxy = active_frame->script()->proxy(); + + v8::HandleScope handle_scope; + v8::Handle context = V8Proxy::GetContext(active_frame); + // TODO(fqian): find all cases context can be empty: + // 1) JS is disabled; + // 2) page is NULL; + if (context.IsEmpty()) + return true; + + v8::Context::Scope scope(context); + + v8::Handle global = context->Global(); + v8::Handle jsevent = global->Get(v8::String::NewSymbol("event")); + Event* event = V8Proxy::ToNativeEvent(jsevent); + + // Based on code from kjs_bindings.cpp. + // Note: This is more liberal than Firefox's implementation. + if (event) { + const AtomicString& type = event->type(); + bool event_ok = + // mouse events + type == EventNames::clickEvent || + type == EventNames::mousedownEvent || + type == EventNames::mouseupEvent || + type == EventNames::dblclickEvent || + // keyboard events + type == EventNames::keydownEvent || + type == EventNames::keypressEvent || + type == EventNames::keyupEvent || + // other accepted events + type == EventNames::selectEvent || + type == EventNames::changeEvent || + type == EventNames::focusEvent || + type == EventNames::blurEvent || + type == EventNames::submitEvent; + + if (event_ok) + return true; + } else if (active_proxy->inlineCode() && !active_proxy->timerCallback()) + // This is the ScriptController::evaluate(const String& filename, + int baseLine, + const String& code, + Node* node) +{ + v8::HandleScope hs; + v8::Handle context = V8Proxy::GetContext(m_proxy->frame()); + if (context.IsEmpty()) + return v8::Persistent(); + + v8::Context::Scope scope(context); + + v8::Local obj = m_proxy->Evaluate(filename, baseLine, code, node); + + if (obj.IsEmpty()) + return v8::Persistent(); + + // TODO(fqian): keep track the global handle created. + return v8::Persistent::New(obj); +} + +void ScriptController::disposeJSResult(v8::Persistent result) +{ + result.Dispose(); + result.Clear(); +} + +PassRefPtr ScriptController::createHTMLEventHandler( + const String& functionName, const String& code, Node* node) +{ + return m_proxy->createHTMLEventHandler(functionName, code, node); +} + +#if ENABLE(SVG) +PassRefPtr ScriptController::createSVGEventHandler( + const String& functionName, const String& code, Node* node) +{ + return m_proxy->createSVGEventHandler(functionName, code, node); +} +#endif + +void ScriptController::setEventHandlerLineno(int lineno) +{ + m_proxy->setEventHandlerLineno(lineno); +} + +void ScriptController::finishedWithEvent(Event* evt) +{ + m_proxy->finishedWithEvent(evt); +} + +void ScriptController::clearDocumentWrapper() +{ + m_proxy->clearDocumentWrapper(); +} + +// Create a V8 object with an interceptor of NPObjectPropertyGetter +void ScriptController::BindToWindowObject(Frame* frame, const String& key, NPObject* object) +{ + v8::HandleScope handle_scope; + + v8::Handle context = V8Proxy::GetContext(frame); + if (context.IsEmpty()) + return; + + v8::Context::Scope scope(context); + + v8::Handle value = CreateV8ObjectForNPObject(object, NULL); + + // Attach to the global object + v8::Handle global = context->Global(); + global->Set(v8String(key), value); +} + +void ScriptController::collectGarbage() +{ + v8::HandleScope hs; + v8::Handle context = V8Proxy::GetContext(m_proxy->frame()); + if (context.IsEmpty()) + return; + + v8::Context::Scope scope(context); + + m_proxy->Evaluate("", 0, "if (window.gc) void(gc());", NULL); +} + +NPRuntimeFunctions* ScriptController::functions() +{ + return &npruntime_functions; +} + + +bool ScriptController::haveInterpreter() const +{ + return m_proxy->ContextInitialized(); +} + +bool ScriptController::isEnabled() const +{ + return m_proxy->isEnabled(); +} + +JSInstanceHandle ScriptController::createScriptInstanceForWidget(Widget* widget) +{ + ASSERT(widget != 0); + + if (widget->isFrameView()) + return JSInstanceHolder::EmptyInstance(); + + // Note: We have to trust that the widget passed to us here + // is a WebPluginImpl. There isn't a way to dynamically verify + // it, since the derived class (Widget) has no identifier. + WebPluginContainer* container = static_cast(widget); + if (!container) + return JSInstanceHolder::EmptyInstance(); + + NPObject* npObject = container->GetPluginScriptableObject(); + if (!npObject) + return JSInstanceHolder::EmptyInstance(); + +#if USE(JSC) + // Register 'widget' with the frame so that we can teardown + // subobjects when the container goes away. + RefPtr root = script()->createRootObject(widget); + KJS::Bindings::Instance* instance = + KJS::Bindings::Instance::createBindingForLanguageInstance( + KJS::Bindings::Instance::CLanguage, npObject, + root.release()); + // GetPluginScriptableObject returns a retained NPObject. + // The caller is expected to release it. + NPN_ReleaseObject(npObject); + return instance; +#elif USE(V8) + // Frame Memory Management for NPObjects + // ------------------------------------- + // NPObjects are treated differently than other objects wrapped by JS. + // NPObjects are not Peerable, and cannot be made peerable, since NPObjects + // can be created either by the browser (e.g. the main window object) or by + // the plugin (the main plugin object for a HTMLEmbedElement). Further, + // unlike most DOM Objects, the frame is especially careful to ensure + // NPObjects terminate at frame teardown because if a plugin leaks a + // reference, it could leak its objects (or the browser's objects). + // + // The Frame maintains a list of plugin objects (m_pluginObjects) + // which it can use to quickly find the wrapped embed object. + // + // Inside the NPRuntime, we've added a few methods for registering + // wrapped NPObjects. The purpose of the registration is because + // javascript garbage collection is non-deterministic, yet we need to + // be able to tear down the plugin objects immediately. When an object + // is registered, javascript can use it. When the object is destroyed, + // or when the object's "owning" object is destroyed, the object will + // be un-registered, and the javascript engine must not use it. + // + // Inside the javascript engine, the engine can keep a reference to the + // NPObject as part of its wrapper. However, before accessing the object + // it must consult the NPN_Registry. + + v8::Local wrapper = CreateV8ObjectForNPObject(npObject, NULL); + + // Track the plugin object. We've been given a reference to the object. + m_pluginObjects.set(widget, npObject); + + JSInstance instance = wrapper; + return instance; +#endif +} + +void ScriptController::cleanupScriptObjectsForPlugin(void* nativeHandle) +{ + PluginObjectMap::iterator it = m_pluginObjects.find(nativeHandle); + if (it == m_pluginObjects.end()) + return; + _NPN_UnregisterObject(it->second); + NPN_ReleaseObject(it->second); + m_pluginObjects.remove(it); +} + +static NPObject* createNoScriptObject() +{ + notImplemented(); + return 0; +} + +static NPObject* createScriptObject(Frame* frame) +{ + v8::HandleScope handleScope; + v8::Handle context = V8Proxy::GetContext(frame); + if (context.IsEmpty()) + return createNoScriptObject(); + + v8::Context::Scope scope(context); + DOMWindow* window = frame->domWindow(); + v8::Handle global = V8Proxy::ToV8Object(V8ClassIndex::DOMWINDOW, window); + ASSERT(global->IsObject()); + return NPN_CreateScriptObject(0, v8::Handle::Cast(global), window); +} + +NPObject* ScriptController::windowScriptNPObject() +{ + if (m_windowScriptNPObject) + return m_windowScriptNPObject; + + if (isEnabled()) { + // JavaScript is enabled, so there is a JavaScript window object. + // Return an NPObject bound to the window object. + m_windowScriptNPObject = createScriptObject(m_frame); + _NPN_RegisterObject(m_windowScriptNPObject, NULL); + } else { + // JavaScript is not enabled, so we cannot bind the NPObject to the + // JavaScript window object. Instead, we create an NPObject of a + // different class, one which is not bound to a JavaScript object. + m_windowScriptNPObject = createNoScriptObject(); + } + return m_windowScriptNPObject; +} + +NPObject* ScriptController::createScriptObjectForPluginElement(HTMLPlugInElement* plugin) +{ + // Can't create NPObjects when JavaScript is disabled + if (!isEnabled()) + return createNoScriptObject(); + + v8::HandleScope handleScope; + v8::Handle context = V8Proxy::GetContext(m_frame); + if (context.IsEmpty()) + return createNoScriptObject(); + v8::Context::Scope scope(context); + + DOMWindow* window = m_frame->domWindow(); + v8::Handle v8plugin = V8Proxy::ToV8Object(V8ClassIndex::HTMLEMBEDELEMENT, plugin); + if (!v8plugin->IsObject()) + return createNoScriptObject(); + + return NPN_CreateScriptObject(0, v8::Handle::Cast(v8plugin), window); +} + + +void ScriptController::clearWindowShell() +{ + // TODO(eseidel): we don't yet have a split window implementation + // we need to clear the window object here. + m_proxy->clear(); +} + +void ScriptController::attachDebugger(void*) +{ + notImplemented(); +} + +void ScriptController::updateDocument() +{ + // TODO(eseidel): Should update document property on current window object + // and all previous window objects which may still be alive. + notImplemented(); +} + + +JSInstanceHolder::JSInstanceHolder() +{ +} + +JSInstanceHolder::JSInstanceHolder(JSInstanceHandle instance) +{ + *this = instance; +} + +JSInstanceHolder::~JSInstanceHolder() +{ + Clear(); +} + +bool JSInstanceHolder::IsEmpty() +{ + return m_instance.IsEmpty(); +} + +JSInstance JSInstanceHolder::Get() +{ + return v8::Local::New(m_instance); +} + +void JSInstanceHolder::Clear() +{ + if (m_instance.IsEmpty()) + return; + v8::HandleScope scope; + v8::Persistent handle(m_instance); +#ifndef NDEBUG + V8Proxy::UnregisterGlobalHandle(this, handle); +#endif + handle.Dispose(); + m_instance.Clear(); +} + +JSInstance JSInstanceHolder::EmptyInstance() +{ + return v8::Local(); +} + +JSInstanceHolder& JSInstanceHolder::operator=(JSInstanceHandle instance) +{ + Clear(); + if (instance.IsEmpty()) + return *this; + + v8::Persistent handle = + v8::Persistent::New(instance); + m_instance = handle; +#ifndef NDEBUG + V8Proxy::RegisterGlobalHandle(JSINSTANCE, this, handle); +#endif + return *this; +} + +} // namespace WebCpre diff --git a/webkit/port/bindings/v8/ScriptController.h b/webkit/port/bindings/v8/ScriptController.h new file mode 100644 index 0000000..19eb533 --- /dev/null +++ b/webkit/port/bindings/v8/ScriptController.h @@ -0,0 +1,290 @@ +// Copyright 2008, 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. + +// An interface to abstract implementation differences +// for various Javascript engines. + +#ifndef ScriptController_h +#define ScriptController_h + +#include "HashMap.h" + +#include "bindings/npruntime.h" + +#include + +#include "v8.h" +#include "v8_proxy.h" + +// JavaScript implementations which expose NPObject will need to implement +// these methods. +typedef void (*NPN_ReleaseVariantValueProcPtr) (NPVariant *variant); + +typedef NPIdentifier(*NPN_GetStringIdentifierProcPtr) (const NPUTF8 *name); +typedef void (*NPN_GetStringIdentifiersProcPtr) (const NPUTF8 **names, + int32_t nameCount, + NPIdentifier *identifiers); +typedef NPIdentifier(*NPN_GetIntIdentifierProcPtr) (int32_t intid); +typedef int32_t (*NPN_IntFromIdentifierProcPtr) (NPIdentifier identifier); +typedef bool (*NPN_IdentifierIsStringProcPtr) (NPIdentifier identifier); +typedef NPUTF8 * (*NPN_UTF8FromIdentifierProcPtr) (NPIdentifier identifier); + +typedef NPObject* (*NPN_CreateObjectProcPtr) (NPP, + NPClass *aClass); +typedef NPObject* (*NPN_RetainObjectProcPtr) (NPObject *obj); +typedef void (*NPN_ReleaseObjectProcPtr) (NPObject *obj); +typedef bool (*NPN_InvokeProcPtr) (NPP npp, + NPObject *obj, + NPIdentifier methodName, + const NPVariant *args, + unsigned argCount, + NPVariant *result); +typedef bool (*NPN_InvokeDefaultProcPtr) (NPP npp, + NPObject *obj, + const NPVariant *args, + unsigned argCount, + NPVariant *result); +typedef bool (*NPN_EvaluateProcPtr) (NPP npp, + NPObject *obj, + NPString *script, + NPVariant *result); +typedef bool (*NPN_GetPropertyProcPtr) (NPP npp, + NPObject *obj, + NPIdentifier propertyName, + NPVariant *result); +typedef bool (*NPN_SetPropertyProcPtr) (NPP npp, + NPObject *obj, + NPIdentifier propertyName, + const NPVariant *value); +typedef bool (*NPN_HasPropertyProcPtr) (NPP, + NPObject *npobj, + NPIdentifier propertyName); +typedef bool (*NPN_HasMethodProcPtr) (NPP npp, + NPObject *npobj, + NPIdentifier methodName); +typedef bool (*NPN_RemovePropertyProcPtr) (NPP npp, + NPObject *obj, + NPIdentifier propertyName); +typedef void (*NPN_SetExceptionProcPtr) (NPObject *obj, + const NPUTF8 *message); + +typedef struct _NPRuntimeFunctions { + NPN_GetStringIdentifierProcPtr getStringIdentifier; + NPN_GetStringIdentifiersProcPtr getStringIdentifiers; + NPN_GetIntIdentifierProcPtr getIntIdentifier; + NPN_IdentifierIsStringProcPtr identifierIsString; + NPN_UTF8FromIdentifierProcPtr utf8FromIdentifier; + NPN_IntFromIdentifierProcPtr intFromIdentifier; + NPN_CreateObjectProcPtr createObject; + NPN_RetainObjectProcPtr retainObject; + NPN_ReleaseObjectProcPtr releaseObject; + NPN_InvokeProcPtr invoke; + NPN_InvokeDefaultProcPtr invokeDefault; + NPN_EvaluateProcPtr evaluate; + NPN_GetPropertyProcPtr getProperty; + NPN_SetPropertyProcPtr setProperty; + NPN_RemovePropertyProcPtr removeProperty; + NPN_HasPropertyProcPtr hasProperty; + NPN_HasMethodProcPtr hasMethod; + NPN_ReleaseVariantValueProcPtr releaseVariantValue; + NPN_SetExceptionProcPtr setException; +} NPRuntimeFunctions; + +namespace WebCore { +class Document; +class EventListener; +class Event; +class Frame; +class HTMLPlugInElement; +class Node; +class PausedTimeouts; +class String; +class Widget; + +typedef v8::Local JSInstance; +typedef v8::Local JSInstanceHandle; +typedef v8::Persistent JSPersistentInstance; +typedef v8::Local JSException; +typedef v8::Persistent JSResult; + +class ScriptController { +public: + ScriptController(Frame*); + ~ScriptController(); + + // TODO(eseidel): V8Proxy should either be folded into ScriptController + // or this accessor should be made JSProxy* + V8Proxy* proxy() { return m_proxy.get(); } + + // Evaluate a script file in the environment of this proxy. + // If succeeded, 'succ' is set to true and result is returned + // as a string. + String evaluate(const String& filename, int baseLine, const String& code, Node* node = NULL, bool* succ = NULL); + + // Second API function for evaluating a JS code. + // It returns a JSResult which must be disposed by calling + // disposeJSResult. If the result is not disposed, it can cause + // serious memory leak. The caller determines whether the evaluation + // is successful by checking the value of JSResult. + JSResult evaluate(const String& filename, int baseLine, const String& code, Node*); + void disposeJSResult(JSResult result); + void collectGarbage(); + + PassRefPtr createHTMLEventHandler(const String& functionName, const String& code, Node*); +#if ENABLE(SVG) + PassRefPtr createSVGEventHandler(const String& functionName, const String& code, Node*); +#endif + + // Creates a property of the global object of a frame. + void BindToWindowObject(Frame*, const String& key, NPObject*); + + NPRuntimeFunctions* functions(); + + JSInstanceHandle createScriptInstanceForWidget(Widget*); + + void clearPluginObjects(); + void clearDocumentWrapper(); + void disconnectFrame(); + + // Check if the javascript engine has been initialized. + bool haveInterpreter() const; + + bool isEnabled() const; + + // TODO(eseidel): void* is a compile hack + void attachDebugger(void*); + + // Create a NPObject wrapper for a JSObject + // NPObject *WrapScriptObject(NPP pluginId, JSObject* objectToWrap, + // JSRootObject* originRootObject, + // JSRootObject* rootObject); + + // --- Static methods assume we are running VM in single thread, --- + // --- and there is only one VM instance. --- + + // Returns the frame of the calling code is in. + // Not necessary the frame of this proxy. + // For example, JS code in frame A calls windowB.open(...). + // Window::open method has the frame pointer of B, but + // the execution context is in frame A, so it needs + // frame A's loader to complete URL. + static Frame* retrieveActiveFrame(); + + // Check whether it is safe to access a frame in another domain. + static bool isSafeScript(Frame* target); + + // Tell the proxy that document.domain is set. + static void setDomain(Frame* target, const String& newDomain); + + // Pass command-line flags to the JS engine + static void setFlags(const char* str, int length); + + // Protect and unprotect the JS wrapper from garbage collected. + static void gcProtectJSWrapper(void* object); + static void gcUnprotectJSWrapper(void* object); + + // Get/Set RecordPlaybackMode flag. + // This is a special mode where JS helps the browser implement + // playback/record mode. Generally, in this mode, some functions + // of client-side randomness are removed. For example, in + // this mode Math.random() and Date.getTime() may not return + // values which vary. + static bool RecordPlaybackMode() { return m_recordPlaybackMode; } + static void setRecordPlaybackMode(bool value) { m_recordPlaybackMode = value; } + + void finishedWithEvent(Event*); + void setEventHandlerLineno(int lineno); + + void setProcessingTimerCallback(bool b) { m_processingTimerCallback = b; } + bool processingUserGesture() const; + + void setPaused(bool b) { m_paused = b; } + bool isPaused() const { return m_paused; } + + const String* sourceURL() const { return m_sourceURL; } // 0 if we are not evaluating any script + + void clearWindowShell(); + void updateDocument(); + + void pauseTimeouts(OwnPtr&); + void resumeTimeouts(OwnPtr&); + + void clearScriptObjects(); + void cleanupScriptObjectsForPlugin(void*); + +#if ENABLE(NETSCAPE_PLUGIN_API) + NPObject* createScriptObjectForPluginElement(HTMLPlugInElement*); + NPObject* windowScriptNPObject(); +#endif + +private: + static bool m_recordPlaybackMode; + + Frame* m_frame; + const String* m_sourceURL; + + bool m_processingTimerCallback; + bool m_paused; + + OwnPtr m_proxy; + typedef HashMap PluginObjectMap; + + // A mapping between Widgets and their corresponding script object. + // This list is used so that when the plugin dies, we can immediately + // invalidate all sub-objects which are associated with that plugin. + // The frame keeps a NPObject reference for each item on the list. + PluginObjectMap m_pluginObjects; +#if ENABLE(NETSCAPE_PLUGIN_API) + NPObject* m_windowScriptNPObject; +#endif +}; + +// JSInstance is an abstraction for a wrapped C class. JSC and V8 +// have very different implementations. +class JSInstanceHolder { +public: + JSInstanceHolder(); + JSInstanceHolder(JSInstanceHandle); + ~JSInstanceHolder(); + // Returns true if the holder is empty. + bool IsEmpty(); + // Get the contained JSInstance. + JSInstance Get(); + // Clear the contained JSInstance. + void Clear(); + JSInstanceHolder& operator=(JSInstanceHandle); + static JSInstance EmptyInstance(); + +private: + JSPersistentInstance m_instance; +}; + +} // namespace WebCore + +#endif // ScriptController_h diff --git a/webkit/port/bridge/ScriptControllerKJS.cpp b/webkit/port/bridge/ScriptControllerKJS.cpp deleted file mode 100644 index 6e3d830..0000000 --- a/webkit/port/bridge/ScriptControllerKJS.cpp +++ /dev/null @@ -1,544 +0,0 @@ -// Copyright (c) 2008, 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 "ScriptController.h" - -#include "Event.h" -#include "EventNames.h" -#include "Frame.h" -#include "FrameLoader.h" -#include "GCController.h" -#include "JSEventListener.h" -#include "npruntime_impl.h" -#include "NP_jsobject.h" -#include "Page.h" -#include "PageGroup.h" -#include "runtime_root.h" -#include "Settings.h" - -#include -#include - -#if ENABLE(NETSCAPE_PLUGIN_API) -#include "HTMLPlugInElement.h" -#endif - -#if ENABLE(SVG) -#include "JSSVGLazyEventListener.h" -#endif - -using namespace KJS; -using namespace WebCore::EventNames; - -namespace WebCore { - -bool ScriptController::m_recordPlaybackMode = false; - -ScriptController::ScriptController(Frame* frame) - : m_frame(frame) - , m_handlerLineno(0) - , m_sourceURL(0) - , m_processingTimerCallback(false) - , m_paused(false) -#if ENABLE(NETSCAPE_PLUGIN_API) - , m_windowScriptNPObject(0) -#endif -#if PLATFORM(MAC) - , m_windowScriptObject(0) -#endif -{ -#if PLATFORM(MAC) && ENABLE(MAC_JAVA_BRIDGE) - static bool initializedJavaJSBindings; - if (!initializedJavaJSBindings) { - initializedJavaJSBindings = true; - initJavaJSBindings(); - } -#endif -} - -ScriptController::~ScriptController() -{ - if (m_windowShell) { - m_windowShell = 0; - - // It's likely that releasing the global object has created a lot of garbage. - gcController().garbageCollectSoon(); - } - - disconnectPlatformScriptObjects(); -} - -// Evaluate a script file in the environment of this proxy. -String ScriptController::evaluate(const String& filename, int baseLine, const String& code, Node* node, bool* succ) { - // Not implemented. - ASSERT(false); - return String(); -} - - -// Evaluate a script file in the environment of this proxy. -JSResult ScriptController::evaluate(const String& filename, int baseLine, const String& code, Node* node) { - // Not implemented. - ASSERT(false); - return 0; -} - -void ScriptController::clearWindowShell() -{ - if (!m_windowShell) - return; - - JSLock lock(false); - m_windowShell->window()->clear(); - m_liveFormerWindows.add(m_windowShell->window()); - m_windowShell->setWindow(new (JSDOMWindow::commonJSGlobalData()) JSDOMWindow(m_frame->domWindow(), m_windowShell)); - if (Page* page = m_frame->page()) { - attachDebugger(page->debugger()); - m_windowShell->window()->setProfileGroup(page->group().identifier()); - } - - // There is likely to be a lot of garbage now. - gcController().garbageCollectSoon(); -} - -PassRefPtr ScriptController::createHTMLEventHandler(const String& functionName, const String& code, Node* node) -{ - initScriptIfNeeded(); - JSLock lock(false); - return JSLazyEventListener::create(functionName, code, m_windowShell->window(), node, m_handlerLineno); -} - -#if ENABLE(SVG) -PassRefPtr ScriptController::createSVGEventHandler(const String& functionName, const String& code, Node* node) -{ - initScriptIfNeeded(); - JSLock lock(false); - return JSSVGLazyEventListener::create(functionName, code, m_windowShell->window(), node, m_handlerLineno); -} -#endif - -void ScriptController::BindToWindowObject(Frame* frame, const String& key, NPObject* object) { - // Not implemented. - ASSERT(false); -} - -NPRuntimeFunctions npruntime_functions = { - _NPN_GetStringIdentifier, - _NPN_GetStringIdentifiers, - _NPN_GetIntIdentifier, - _NPN_IdentifierIsString, - _NPN_UTF8FromIdentifier, - _NPN_IntFromIdentifier, - _NPN_CreateObject, - _NPN_RetainObject, - _NPN_ReleaseObject, - _NPN_Invoke, - _NPN_InvokeDefault, - _NPN_Evaluate, - _NPN_GetProperty, - _NPN_SetProperty, - _NPN_RemoveProperty, - _NPN_HasProperty, - _NPN_HasMethod, - _NPN_ReleaseVariantValue, - _NPN_SetException -}; - -NPRuntimeFunctions* ScriptController::functions() -{ - return &npruntime_functions; -} - -// static -Frame* ScriptController::retrieveActiveFrame() { - // Not implemented. - ASSERT(false); - return 0; -} - -// static -bool ScriptController::isSafeScript(Frame* target) { - // Not implemented. - ASSERT(false); - return false; -} - -// static -void ScriptController::setDomain(Frame*, const String&) { - // empty -} - -// static -void ScriptController::setFlags(const char*, int) { - // empty -} - -// static -void ScriptController::gcProtectJSWrapper(void* dom_object) { - KJS::JSLock lock(false); - KJS::gcProtectNullTolerant(ScriptInterpreter::getDOMObject(dom_object)); -} - -// static -void ScriptController::gcUnprotectJSWrapper(void* dom_object) { - KJS::JSLock lock(false); - KJS::gcUnprotectNullTolerant(ScriptInterpreter::getDOMObject(dom_object)); -} - -void ScriptController::finishedWithEvent(Event* event) -{ - // This is called when the DOM implementation has finished with a particular event. This - // is the case in sitations where an event has been created just for temporary usage, - // e.g. an image load or mouse move. Once the event has been dispatched, it is forgotten - // by the DOM implementation and so does not need to be cached still by the interpreter - ScriptInterpreter::forgetDOMObject(event); -} - -void ScriptController::setEventHandlerLineno(int lineno) { - m_handlerLineno = lineno; -} - -void ScriptController::initScript() -{ - if (m_windowShell) - return; - - JSLock lock(false); - - m_windowShell = new JSDOMWindowShell(m_frame->domWindow()); - updateDocument(); - - if (Page* page = m_frame->page()) { - attachDebugger(page->debugger()); - m_windowShell->window()->setProfileGroup(page->group().identifier()); - } - - m_frame->loader()->dispatchWindowObjectAvailable(); -} - -void ScriptController::disconnectFrame() -{ - // Not implemented. - ASSERT(false); -} - -bool ScriptController::processingUserGesture() const -{ - if (!m_windowShell) - return false; - - if (Event* event = m_windowShell->window()->currentEvent()) { - const AtomicString& type = event->type(); - if ( // mouse events - type == clickEvent || type == mousedownEvent || - type == mouseupEvent || type == dblclickEvent || - // keyboard events - type == keydownEvent || type == keypressEvent || - type == keyupEvent || - // other accepted events - type == selectEvent || type == changeEvent || - type == focusEvent || type == blurEvent || - type == submitEvent) - return true; - } else { // no event - if (m_sourceURL && m_sourceURL->isNull() && !m_processingTimerCallback) { - // This is the (dom_object)); -} - -void ScriptController::gcUnprotectJSWrapper(void* dom_object) -{ - V8Proxy::GCUnprotect(static_cast(dom_object)); -} - -void ScriptController::pauseTimeouts(OwnPtr& result) -{ - DOMWindow* window = m_frame->domWindow(); - if (!window) { - result.clear(); - return; - } - window->pauseTimeouts(result); -} - -void ScriptController::resumeTimeouts(OwnPtr& timeouts) -{ - DOMWindow* window = m_frame->domWindow(); - if (!window) { - timeouts.clear(); - return; - } - window->resumeTimeouts(timeouts); -} - -ScriptController::ScriptController(Frame* frame) - : m_frame(frame) - , m_sourceURL(0) - , m_processingTimerCallback(false) - , m_paused(false) - , m_proxy(new V8Proxy(frame)) -#if ENABLE(NETSCAPE_PLUGIN_API) - , m_windowScriptNPObject(0) -#endif -{ -} - -ScriptController::~ScriptController() -{ -} - -void ScriptController::clearScriptObjects() -{ - // TODO(eseidel): JSC handles binding root objects here, why don't we? - -#if ENABLE(NETSCAPE_PLUGIN_API) - if (m_windowScriptNPObject) { - // Call _NPN_DeallocateObject() instead of _NPN_ReleaseObject() so that we don't leak if a plugin fails to release the window - // script object properly. - // This shouldn't cause any problems for plugins since they should have already been stopped and destroyed at this point. - _NPN_DeallocateObject(m_windowScriptNPObject); - m_windowScriptNPObject = 0; - } -#endif -} - -void ScriptController::clearPluginObjects() -{ - PluginObjectMap::iterator it = m_pluginObjects.begin(); - for (; it != m_pluginObjects.end(); ++it) { - _NPN_UnregisterObject(it->second); - NPN_ReleaseObject(it->second); - } - m_pluginObjects.clear(); -} - -// Disconnect the proxy from its owner frame; -void ScriptController::disconnectFrame() -{ - m_proxy->disconnectFrame(); -} - -bool ScriptController::processingUserGesture() const -{ - Frame* active_frame = V8Proxy::retrieveActiveFrame(); - // No script is running, must be run by users. - if (!active_frame) - return true; - - V8Proxy* active_proxy = active_frame->script()->proxy(); - - v8::HandleScope handle_scope; - v8::Handle context = V8Proxy::GetContext(active_frame); - // TODO(fqian): find all cases context can be empty: - // 1) JS is disabled; - // 2) page is NULL; - if (context.IsEmpty()) - return true; - - v8::Context::Scope scope(context); - - v8::Handle global = context->Global(); - v8::Handle jsevent = global->Get(v8::String::NewSymbol("event")); - Event* event = V8Proxy::ToNativeEvent(jsevent); - - // Based on code from kjs_bindings.cpp. - // Note: This is more liberal than Firefox's implementation. - if (event) { - const AtomicString& type = event->type(); - bool event_ok = - // mouse events - type == EventNames::clickEvent || - type == EventNames::mousedownEvent || - type == EventNames::mouseupEvent || - type == EventNames::dblclickEvent || - // keyboard events - type == EventNames::keydownEvent || - type == EventNames::keypressEvent || - type == EventNames::keyupEvent || - // other accepted events - type == EventNames::selectEvent || - type == EventNames::changeEvent || - type == EventNames::focusEvent || - type == EventNames::blurEvent || - type == EventNames::submitEvent; - - if (event_ok) - return true; - } else if (active_proxy->inlineCode() && !active_proxy->timerCallback()) - // This is the ScriptController::evaluate(const String& filename, - int baseLine, - const String& code, - Node* node) -{ - v8::HandleScope hs; - v8::Handle context = V8Proxy::GetContext(m_proxy->frame()); - if (context.IsEmpty()) - return v8::Persistent(); - - v8::Context::Scope scope(context); - - v8::Local obj = m_proxy->Evaluate(filename, baseLine, code, node); - - if (obj.IsEmpty()) - return v8::Persistent(); - - // TODO(fqian): keep track the global handle created. - return v8::Persistent::New(obj); -} - -void ScriptController::disposeJSResult(v8::Persistent result) -{ - result.Dispose(); - result.Clear(); -} - -PassRefPtr ScriptController::createHTMLEventHandler( - const String& functionName, const String& code, Node* node) -{ - return m_proxy->createHTMLEventHandler(functionName, code, node); -} - -#if ENABLE(SVG) -PassRefPtr ScriptController::createSVGEventHandler( - const String& functionName, const String& code, Node* node) -{ - return m_proxy->createSVGEventHandler(functionName, code, node); -} -#endif - -void ScriptController::setEventHandlerLineno(int lineno) -{ - m_proxy->setEventHandlerLineno(lineno); -} - -void ScriptController::finishedWithEvent(Event* evt) -{ - m_proxy->finishedWithEvent(evt); -} - -void ScriptController::clearDocumentWrapper() -{ - m_proxy->clearDocumentWrapper(); -} - -// Create a V8 object with an interceptor of NPObjectPropertyGetter -void ScriptController::BindToWindowObject(Frame* frame, const String& key, NPObject* object) -{ - v8::HandleScope handle_scope; - - v8::Handle context = V8Proxy::GetContext(frame); - if (context.IsEmpty()) - return; - - v8::Context::Scope scope(context); - - v8::Handle value = CreateV8ObjectForNPObject(object, NULL); - - // Attach to the global object - v8::Handle global = context->Global(); - global->Set(v8String(key), value); -} - -void ScriptController::collectGarbage() -{ - v8::HandleScope hs; - v8::Handle context = V8Proxy::GetContext(m_proxy->frame()); - if (context.IsEmpty()) - return; - - v8::Context::Scope scope(context); - - m_proxy->Evaluate("", 0, "if (window.gc) void(gc());", NULL); -} - -NPRuntimeFunctions* ScriptController::functions() -{ - return &npruntime_functions; -} - - -bool ScriptController::haveInterpreter() const -{ - return m_proxy->ContextInitialized(); -} - -bool ScriptController::isEnabled() const -{ - return m_proxy->isEnabled(); -} - -JSInstanceHandle ScriptController::createScriptInstanceForWidget(Widget* widget) -{ - ASSERT(widget != 0); - - if (widget->isFrameView()) - return JSInstanceHolder::EmptyInstance(); - - // Note: We have to trust that the widget passed to us here - // is a WebPluginImpl. There isn't a way to dynamically verify - // it, since the derived class (Widget) has no identifier. - WebPluginContainer* container = static_cast(widget); - if (!container) - return JSInstanceHolder::EmptyInstance(); - - NPObject* npObject = container->GetPluginScriptableObject(); - if (!npObject) - return JSInstanceHolder::EmptyInstance(); - -#if USE(JSC) - // Register 'widget' with the frame so that we can teardown - // subobjects when the container goes away. - RefPtr root = script()->createRootObject(widget); - KJS::Bindings::Instance* instance = - KJS::Bindings::Instance::createBindingForLanguageInstance( - KJS::Bindings::Instance::CLanguage, npObject, - root.release()); - // GetPluginScriptableObject returns a retained NPObject. - // The caller is expected to release it. - NPN_ReleaseObject(npObject); - return instance; -#elif USE(V8) - // Frame Memory Management for NPObjects - // ------------------------------------- - // NPObjects are treated differently than other objects wrapped by JS. - // NPObjects are not Peerable, and cannot be made peerable, since NPObjects - // can be created either by the browser (e.g. the main window object) or by - // the plugin (the main plugin object for a HTMLEmbedElement). Further, - // unlike most DOM Objects, the frame is especially careful to ensure - // NPObjects terminate at frame teardown because if a plugin leaks a - // reference, it could leak its objects (or the browser's objects). - // - // The Frame maintains a list of plugin objects (m_pluginObjects) - // which it can use to quickly find the wrapped embed object. - // - // Inside the NPRuntime, we've added a few methods for registering - // wrapped NPObjects. The purpose of the registration is because - // javascript garbage collection is non-deterministic, yet we need to - // be able to tear down the plugin objects immediately. When an object - // is registered, javascript can use it. When the object is destroyed, - // or when the object's "owning" object is destroyed, the object will - // be un-registered, and the javascript engine must not use it. - // - // Inside the javascript engine, the engine can keep a reference to the - // NPObject as part of its wrapper. However, before accessing the object - // it must consult the NPN_Registry. - - v8::Local wrapper = CreateV8ObjectForNPObject(npObject, NULL); - - // Track the plugin object. We've been given a reference to the object. - m_pluginObjects.set(widget, npObject); - - JSInstance instance = wrapper; - return instance; -#endif -} - -void ScriptController::cleanupScriptObjectsForPlugin(void* nativeHandle) -{ - PluginObjectMap::iterator it = m_pluginObjects.find(nativeHandle); - if (it == m_pluginObjects.end()) - return; - _NPN_UnregisterObject(it->second); - NPN_ReleaseObject(it->second); - m_pluginObjects.remove(it); -} - -static NPObject* createNoScriptObject() -{ - notImplemented(); - return 0; -} - -static NPObject* createScriptObject(Frame* frame) -{ - v8::HandleScope handleScope; - v8::Handle context = V8Proxy::GetContext(frame); - if (context.IsEmpty()) - return createNoScriptObject(); - - v8::Context::Scope scope(context); - DOMWindow* window = frame->domWindow(); - v8::Handle global = V8Proxy::ToV8Object(V8ClassIndex::DOMWINDOW, window); - ASSERT(global->IsObject()); - return NPN_CreateScriptObject(0, v8::Handle::Cast(global), window); -} - -NPObject* ScriptController::windowScriptNPObject() -{ - if (m_windowScriptNPObject) - return m_windowScriptNPObject; - - if (isEnabled()) { - // JavaScript is enabled, so there is a JavaScript window object. - // Return an NPObject bound to the window object. - m_windowScriptNPObject = createScriptObject(m_frame); - _NPN_RegisterObject(m_windowScriptNPObject, NULL); - } else { - // JavaScript is not enabled, so we cannot bind the NPObject to the - // JavaScript window object. Instead, we create an NPObject of a - // different class, one which is not bound to a JavaScript object. - m_windowScriptNPObject = createNoScriptObject(); - } - return m_windowScriptNPObject; -} - -NPObject* ScriptController::createScriptObjectForPluginElement(HTMLPlugInElement* plugin) -{ - // Can't create NPObjects when JavaScript is disabled - if (!isEnabled()) - return createNoScriptObject(); - - v8::HandleScope handleScope; - v8::Handle context = V8Proxy::GetContext(m_frame); - if (context.IsEmpty()) - return createNoScriptObject(); - v8::Context::Scope scope(context); - - DOMWindow* window = m_frame->domWindow(); - v8::Handle v8plugin = V8Proxy::ToV8Object(V8ClassIndex::HTMLEMBEDELEMENT, plugin); - if (!v8plugin->IsObject()) - return createNoScriptObject(); - - return NPN_CreateScriptObject(0, v8::Handle::Cast(v8plugin), window); -} - - -void ScriptController::clearWindowShell() -{ - // TODO(eseidel): we don't yet have a split window implementation - // we need to clear the window object here. - m_proxy->clear(); -} - -void ScriptController::attachDebugger(void*) -{ - notImplemented(); -} - -void ScriptController::updateDocument() -{ - // TODO(eseidel): Should update document property on current window object - // and all previous window objects which may still be alive. - notImplemented(); -} - - -JSInstanceHolder::JSInstanceHolder() -{ -} - -JSInstanceHolder::JSInstanceHolder(JSInstanceHandle instance) -{ - *this = instance; -} - -JSInstanceHolder::~JSInstanceHolder() -{ - Clear(); -} - -bool JSInstanceHolder::IsEmpty() -{ - return m_instance.IsEmpty(); -} - -JSInstance JSInstanceHolder::Get() -{ - return v8::Local::New(m_instance); -} - -void JSInstanceHolder::Clear() -{ - if (m_instance.IsEmpty()) - return; - v8::HandleScope scope; - v8::Persistent handle(m_instance); -#ifndef NDEBUG - V8Proxy::UnregisterGlobalHandle(this, handle); -#endif - handle.Dispose(); - m_instance.Clear(); -} - -JSInstance JSInstanceHolder::EmptyInstance() -{ - return v8::Local(); -} - -JSInstanceHolder& JSInstanceHolder::operator=(JSInstanceHandle instance) -{ - Clear(); - if (instance.IsEmpty()) - return *this; - - v8::Persistent handle = - v8::Persistent::New(instance); - m_instance = handle; -#ifndef NDEBUG - V8Proxy::RegisterGlobalHandle(JSINSTANCE, this, handle); -#endif - return *this; -} - -} // namespace WebCpre -- cgit v1.1