Changeset 87315 in webkit


Ignore:
Timestamp:
May 25, 2011 12:28:22 PM (13 years ago)
Author:
caio.oliveira@openbossa.org
Message:

2011-05-25 Caio Marcelo de Oliveira Filho <caio.oliveira@openbossa.org>

Reviewed by Andreas Kling.

[Qt] JSC bridge: implement qt_sender without using Scope Chain
https://bugs.webkit.org/show_bug.cgi?id=61343

Create a stack to keep track of the sender objects. This is simpler than
the similar mechanism in QObject (C++ API), that keeps a stack per-object.

Since we do not support multiple threads, one static stack will be enough for
handling the behavior.

This behavior is covered by the tst_QWebFrame::connectAndDisconnect() auto test.

  • bridge/qt/qt_instance.cpp: (JSC::Bindings::QtInstance::qtSenderStack): We have one static stack of QObject*. The top of the stack contains the last object that emitted signal that called a JavaScript function.
  • bridge/qt/qt_instance.h: (JSC::Bindings::QtInstance::QtSenderStack::top): (JSC::Bindings::QtInstance::QtSenderStack::push): (JSC::Bindings::QtInstance::QtSenderStack::pop): Minimal functionality to manipulate the sender stack.
  • bridge/qt/qt_runtime.cpp: (JSC::Bindings::QtConnectionObject::execute): Remove the previous code that modified the scope chain. Push the sender object to the stack before calling the JavaScript function (the "slot" in Qt-speak) and pop it afterwards.

2011-05-25 Caio Marcelo de Oliveira Filho <caio.oliveira@openbossa.org>

Reviewed by Andreas Kling.

[Qt] JSC bridge: implement qt_sender without using Scope Chain
https://bugs.webkit.org/show_bug.cgi?id=61343

Create a 'qt_sender' property in the global object, that returns the top of
the qtSenderStack. This is an alternative implementation for the feature of
providing a way for a function (acting as a Qt 'slot') discover which object
emitted the signal that caused it to be executed.

This reduces the coupling of the Qt bridge and JSC internal implementation. The
patch tries to use as much JSC public API as possible.

This behavior is covered by the tst_QWebFrame::connectAndDisconnect() auto test.

  • WebCoreSupport/FrameLoaderClientQt.cpp: (WebCore::FrameLoaderClientQt::dispatchDidClearWindowObjectInWorld): Instead of emitting the QWebPage::javaScriptWindowObjectCleared() directly, calls a QWebPagePrivate function to do it.
  • Api/qwebframe_p.h:
  • Api/qwebframe.cpp: (QWebFramePrivate::didClearedWindowObject): Before emitting the signal mentioned, adds the 'qt_sender' to the fresh global object.

(qtSenderCallback):
Returns the JSObjectRef corresponding to the top of qtSenderStack.

(QWebFramePrivate::addQtSenderToGlobalObject):
Create a property with a qtSenderCallback as getter function in the global object.

Location:
trunk/Source
Files:
8 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/WebCore/ChangeLog

    r87313 r87315  
     12011-05-25  Caio Marcelo de Oliveira Filho  <caio.oliveira@openbossa.org>
     2
     3        Reviewed by Andreas Kling.
     4
     5        [Qt] JSC bridge: implement __qt_sender__ without using Scope Chain
     6        https://bugs.webkit.org/show_bug.cgi?id=61343
     7
     8        Create a stack to keep track of the sender objects. This is simpler than
     9        the similar mechanism in QObject (C++ API), that keeps a stack per-object.
     10
     11        Since we do not support multiple threads, one static stack will be enough for
     12        handling the behavior.
     13
     14        This behavior is covered by the tst_QWebFrame::connectAndDisconnect() auto test.
     15
     16        * bridge/qt/qt_instance.cpp:
     17        (JSC::Bindings::QtInstance::qtSenderStack):
     18        We have one static stack of QObject*. The top of the stack contains the
     19        last object that emitted signal that called a JavaScript function.
     20
     21        * bridge/qt/qt_instance.h:
     22        (JSC::Bindings::QtInstance::QtSenderStack::top):
     23        (JSC::Bindings::QtInstance::QtSenderStack::push):
     24        (JSC::Bindings::QtInstance::QtSenderStack::pop):
     25        Minimal functionality to manipulate the sender stack.
     26
     27        * bridge/qt/qt_runtime.cpp:
     28        (JSC::Bindings::QtConnectionObject::execute):
     29        Remove the previous code that modified the scope chain. Push the sender object
     30        to the stack before calling the JavaScript function (the "slot" in Qt-speak) and
     31        pop it afterwards.
     32
    1332011-05-25  Sheriff Bot  <webkit.review.bot@gmail.com>
    234
  • trunk/Source/WebCore/bridge/qt/qt_instance.cpp

    r84556 r87315  
    4545static QObjectInstanceMap cachedInstances;
    4646
     47// Used for implementing '__qt_sender__'.
     48Q_GLOBAL_STATIC(QtInstance::QtSenderStack, senderStack)
     49
    4750// Derived RuntimeObject
    4851class QtRuntimeObject : public RuntimeObject {
     
    322325}
    323326
     327QtInstance::QtSenderStack* QtInstance::qtSenderStack()
     328{
     329    return senderStack();
     330}
     331
    324332// In qt_runtime.cpp
    325333JSValue convertQVariantToValue(ExecState*, PassRefPtr<RootObject> root, const QVariant& variant);
  • trunk/Source/WebCore/bridge/qt/qt_instance.h

    r84556 r87315  
    2323#include "BridgeJSC.h"
    2424#include "runtime_root.h"
     25#include <QStack>
    2526#include <QtScript/qscriptengine.h>
    2627#include <qhash.h>
     
    7273    static QtInstance* getInstance(JSObject*);
    7374
     75    class QtSenderStack {
     76    public:
     77        QObject* top() const { return m_stack.isEmpty() ? 0 : m_stack.top(); }
     78        void push(QObject* object) { m_stack.push(object); }
     79        void pop() { Q_ASSERT(!m_stack.isEmpty()); m_stack.pop(); }
     80    private:
     81        QStack<QObject*> m_stack;
     82    };
     83
     84    // Used to implement '__qt_sender__'.
     85    static QtSenderStack* qtSenderStack();
     86
    7487private:
    7588    static PassRefPtr<QtInstance> create(QObject *instance, PassRefPtr<RootObject> rootObject, QScriptEngine::ValueOwnership ownership)
  • trunk/Source/WebCore/bridge/qt/qt_runtime.cpp

    r86758 r87315  
    18391839                        }
    18401840                    }
    1841                     // Stuff in the __qt_sender property, if we can
    1842                     ScopeChainNode* oldsc = 0;
    1843                     JSFunction* fimp = 0;
    1844                     if (m_funcObject->inherits(&JSFunction::s_info)) {
    1845                         fimp = static_cast<JSFunction*>(m_funcObject.get());
    1846 
    1847                         JSObject* qt_sender = QtInstance::getQtInstance(sender(), ro, QScriptEngine::QtOwnership)->createRuntimeObject(exec);
    1848                         JSObject* wrapper = constructEmptyObject(exec, createEmptyObjectStructure(exec->globalData(), jsNull()));
    1849                         PutPropertySlot slot;
    1850                         wrapper->put(exec, Identifier(exec, "__qt_sender__"), qt_sender, slot);
    1851                         oldsc = fimp->scope();
    1852                         fimp->setScope(exec->globalData(), oldsc->push(wrapper));
    1853                     }
     1841
     1842                    const bool withQtSenderStack = m_funcObject->inherits(&JSFunction::s_info);
     1843                    if (withQtSenderStack)
     1844                        QtInstance::qtSenderStack()->push(QObject::sender());
    18541845
    18551846                    CallData callData;
     
    18571848                    call(exec, m_funcObject.get(), callType, callData, m_thisObject.get(), l);
    18581849
    1859                     if (fimp)
    1860                         fimp->setScope(exec->globalData(), oldsc);
     1850                    if (withQtSenderStack)
     1851                        QtInstance::qtSenderStack()->pop();
    18611852                }
    18621853            }
  • trunk/Source/WebKit/qt/Api/qwebframe.cpp

    r86949 r87315  
    2323
    2424#if USE(JSC)
     25#include "APICast.h"
    2526#include "BridgeJSC.h"
    2627#include "CallFrame.h"
     
    5051#include "InspectorController.h"
    5152#if USE(JSC)
     53#include "JavaScript.h"
    5254#include "JSDOMBinding.h"
    5355#include "JSDOMWindowBase.h"
    5456#include "JSLock.h"
    5557#include "JSObject.h"
     58#include "JSRetainPtr.h"
     59#include "OpaqueJSString.h"
    5660#elif USE(V8)
    5761#include "V8DOMWrapper.h"
     
    472476#endif
    473477}
     478
     479void QWebFramePrivate::didClearWindowObject()
     480{
     481#if USE(JSC)
     482    if (page->settings()->testAttribute(QWebSettings::JavascriptEnabled))
     483        addQtSenderToGlobalObject();
     484#endif
     485    emit q->javaScriptWindowObjectCleared();
     486}
     487
     488#if USE(JSC)
     489static JSValueRef qtSenderCallback(JSContextRef context, JSObjectRef, JSObjectRef, size_t, const JSValueRef[], JSValueRef*)
     490{
     491    QObject* sender = JSC::Bindings::QtInstance::qtSenderStack()->top();
     492    if (!sender)
     493        return JSValueMakeUndefined(context);
     494
     495    JSC::ExecState* exec = ::toJS(context);
     496    RefPtr<JSC::Bindings::RootObject> rootObject = JSC::Bindings::findRootObject(exec->dynamicGlobalObject());
     497    JSC::JSObject* jsSender = JSC::Bindings::QtInstance::getQtInstance(sender, rootObject, QScriptEngine::QtOwnership)->createRuntimeObject(exec);
     498    return ::toRef(jsSender);
     499}
     500
     501void QWebFramePrivate::addQtSenderToGlobalObject()
     502{
     503    JSC::JSLock lock(JSC::SilenceAssertionsOnly);
     504
     505    JSDOMWindow* window = toJSDOMWindow(frame, mainThreadNormalWorld());
     506    Q_ASSERT(window);
     507
     508    JSC::ExecState* exec = window->globalExec();
     509    Q_ASSERT(exec);
     510
     511    JSContextRef context = ::toRef(exec);
     512    JSRetainPtr<JSStringRef> propertyName(Adopt, JSStringCreateWithUTF8CString("__qt_sender__"));
     513    JSObjectRef function = JSObjectMakeFunctionWithCallback(context, propertyName.get(), qtSenderCallback);
     514
     515    // JSC public API doesn't support setting a Getter for a property of a given object, https://bugs.webkit.org/show_bug.cgi?id=61374.
     516    window->defineGetter(exec, propertyName.get()->identifier(&exec->globalData()), ::toJS(function),
     517                         JSC::ReadOnly | JSC::DontEnum | JSC::DontDelete);
     518}
     519#endif
     520
    474521/*!
    475522    \class QWebFrame
  • trunk/Source/WebKit/qt/Api/qwebframe_p.h

    r86276 r87315  
    109109    void _q_orientationChanged();
    110110
     111    void didClearWindowObject();
     112
    111113    QWebFrame *q;
    112114    Qt::ScrollBarPolicy horizontalScrollBarPolicy;
     
    127129#if ENABLE(ORIENTATION_EVENTS) && ENABLE(DEVICE_ORIENTATION)
    128130    QtMobility::QOrientationSensor m_orientation;
     131#endif
     132
     133private:
     134#if USE(JSC)
     135    void addQtSenderToGlobalObject();
    129136#endif
    130137};
  • trunk/Source/WebKit/qt/ChangeLog

    r87312 r87315  
     12011-05-25  Caio Marcelo de Oliveira Filho  <caio.oliveira@openbossa.org>
     2
     3        Reviewed by Andreas Kling.
     4
     5        [Qt] JSC bridge: implement __qt_sender__ without using Scope Chain
     6        https://bugs.webkit.org/show_bug.cgi?id=61343
     7
     8        Create a '__qt_sender__' property in the global object, that returns the top of
     9        the qtSenderStack. This is an alternative implementation for the feature of
     10        providing a way for a function (acting as a Qt 'slot') discover which object
     11        emitted the signal that caused it to be executed.
     12
     13        This reduces the coupling of the Qt bridge and JSC internal implementation. The
     14        patch tries to use as much JSC public API as possible.
     15
     16        This behavior is covered by the tst_QWebFrame::connectAndDisconnect() auto test.
     17
     18        * WebCoreSupport/FrameLoaderClientQt.cpp:
     19        (WebCore::FrameLoaderClientQt::dispatchDidClearWindowObjectInWorld):
     20        Instead of emitting the QWebPage::javaScriptWindowObjectCleared() directly, calls
     21        a QWebPagePrivate function to do it.
     22
     23        * Api/qwebframe_p.h:
     24        * Api/qwebframe.cpp:
     25        (QWebFramePrivate::didClearedWindowObject):
     26        Before emitting the signal mentioned, adds the '__qt_sender__' to the fresh
     27        global object.
     28
     29        (qtSenderCallback):
     30        Returns the JSObjectRef corresponding to the top of qtSenderStack.
     31
     32        (QWebFramePrivate::addQtSenderToGlobalObject):
     33        Create a property with a qtSenderCallback as getter function in the global object.
     34
    1352011-05-25  Alexis Menard  <alexis.menard@openbossa.org>
    236
  • trunk/Source/WebKit/qt/WebCoreSupport/FrameLoaderClientQt.cpp

    r87260 r87315  
    764764
    765765    if (m_webFrame)
    766         emit m_webFrame->javaScriptWindowObjectCleared();
     766        m_webFrame->d->didClearWindowObject();
    767767}
    768768
Note: See TracChangeset for help on using the changeset viewer.