Title: [115245] trunk/Source/WebKit/blackberry
Revision
115245
Author
commit-qu...@webkit.org
Date
2012-04-25 14:22:53 -0700 (Wed, 25 Apr 2012)

Log Message

[BlackBerry] Possible JS re-entrancy caused by UI events.
https://bugs.webkit.org/show_bug.cgi?id=84862

Patch by Yong Li <y...@rim.com> on 2012-04-25
Reviewed by Antonio Gomes.

1. block UI events when running in nested event loop
2. defer some tasks we still want to perform when it is safe to do,
   with cached data.
3. deferred task can be cancelled by clearing the flag. duplicate tasks
   is not a problem because they share same flag and data.
4. move deferred manual script from FrameLoaderClientBlackBerry to WebPagePrivate
   and make it a deferred task

* Api/WebPage.cpp:
(WebKit):
(BlackBerry::WebKit::WebPagePrivate::WebPagePrivate):
(BlackBerry::WebKit::WebPagePrivate::load):
(BlackBerry::WebKit::WebPagePrivate::stopCurrentLoad):
(BlackBerry::WebKit::WebPagePrivate::willDeferLoading):
(BlackBerry::WebKit::WebPagePrivate::didResumeLoading):
(BlackBerry::WebKit::WebPagePrivate::deferredTasksTimerFired):
(BlackBerry::WebKit::WebPage::assignFocus):
(BlackBerry::WebKit::WebPagePrivate::setPageVisibilityState):
(BlackBerry::WebKit::WebPage::setInputSelection):
(BlackBerry::WebKit::WebPage::popupListClosed):
(BlackBerry::WebKit::WebPage::setDateTimeInput):
(BlackBerry::WebKit::WebPage::setColorInput):
(BlackBerry::WebKit::WebPage::mouseEvent):
(BlackBerry::WebKit::WebPage::touchEvent):
(BlackBerry::WebKit::WebPage::touchPointAsMouseEvent):
(BlackBerry::WebKit::WebPage::touchEventCancel):
(BlackBerry::WebKit::WebPage::touchEventCancelAndClearFocusedNode):
(BlackBerry::WebKit::WebPage::keyEvent):
(BlackBerry::WebKit::WebPage::deleteTextRelativeToCursor):
(BlackBerry::WebKit::WebPage::setComposingText):
(BlackBerry::WebKit::WebPage::commitText):
(BlackBerry::WebKit::WebPage::selectionCancelled):
(BlackBerry::WebKit::WebPage::cutSelectedText):
(BlackBerry::WebKit::WebPage::insertText):
(BlackBerry::WebKit::WebPage::clearCurrentInputField):
(BlackBerry::WebKit::WebPage::cut):
(BlackBerry::WebKit::WebPage::paste):
(BlackBerry::WebKit::WebPage::setSelection):
(BlackBerry::WebKit::WebPage::setCaretPosition):
(BlackBerry::WebKit::WebPage::selectAtPoint):
(BlackBerry::WebKit::WebPage::setFocused):
* Api/WebPage.h:
* Api/WebPage_p.h:
(WebCore):
(WebPagePrivate):
(DeferredTaskBase):
(BlackBerry::WebKit::WebPagePrivate::DeferredTaskBase::perform):
(BlackBerry::WebKit::WebPagePrivate::DeferredTaskBase::DeferredTaskBase):
* WebCoreSupport/FrameLoaderClientBlackBerry.cpp:
(WebCore::FrameLoaderClientBlackBerry::FrameLoaderClientBlackBerry):
(WebCore::FrameLoaderClientBlackBerry::~FrameLoaderClientBlackBerry):
(WebCore::FrameLoaderClientBlackBerry::willDeferLoading):
(WebCore::FrameLoaderClientBlackBerry::didResumeLoading):
* WebCoreSupport/FrameLoaderClientBlackBerry.h:
(FrameLoaderClientBlackBerry):
* WebKitSupport/InputHandler.cpp:
(BlackBerry::WebKit::InputHandler::setPopupListIndexes):
* WebKitSupport/InputHandler.h:
(InputHandler):

Modified Paths

Diff

Modified: trunk/Source/WebKit/blackberry/Api/WebPage.cpp (115244 => 115245)


--- trunk/Source/WebKit/blackberry/Api/WebPage.cpp	2012-04-25 21:15:39 UTC (rev 115244)
+++ trunk/Source/WebKit/blackberry/Api/WebPage.cpp	2012-04-25 21:22:53 UTC (rev 115245)
@@ -289,6 +289,21 @@
     d->m_userViewportArguments = ViewportArguments();
 }
 
+template <bool WebPagePrivate::* isActive>
+class DeferredTask: public WebPagePrivate::DeferredTaskBase {
+public:
+    static void finishOrCancel(WebPagePrivate* webPagePrivate)
+    {
+        webPagePrivate->*isActive = false;
+    }
+protected:
+    DeferredTask(WebPagePrivate* webPagePrivate)
+        : DeferredTaskBase(webPagePrivate, isActive)
+    {
+    }
+    typedef DeferredTask<isActive> DeferredTaskType;
+};
+
 WebPagePrivate::WebPagePrivate(WebPage* webPage, WebPageClient* client, const IntRect& rect)
     : m_webPage(webPage)
     , m_client(client)
@@ -356,6 +371,7 @@
     , m_fullscreenVideoNode(0)
     , m_hasInRegionScrollableAreas(false)
     , m_updateDelegatedOverlaysDispatched(false)
+    , m_deferredTasksTimer(this, &WebPagePrivate::deferredTasksTimerFired)
 {
     static bool isInitialized = false;
     if (!isInitialized) {
@@ -527,9 +543,24 @@
 #endif
 }
 
+class DeferredTaskLoadManualScript: public DeferredTask<&WebPagePrivate::m_wouldSetFocused> {
+public:
+    explicit DeferredTaskLoadManualScript(WebPagePrivate* webPagePrivate, const KURL& url)
+        : DeferredTaskType(webPagePrivate)
+    {
+        webPagePrivate->m_cachedManualScript = url;
+    }
+private:
+    virtual void performInternal(WebPagePrivate* webPagePrivate)
+    {
+        webPagePrivate->m_mainFrame->script()->executeIfJavaScriptURL(webPagePrivate->m_cachedManualScript, DoNotReplaceDocumentIfJavaScriptURL);
+    }
+};
+
 void WebPagePrivate::load(const char* url, const char* networkToken, const char* method, Platform::NetworkRequest::CachePolicy cachePolicy, const char* data, size_t dataLength, const char* const* headers, size_t headersLength, bool isInitial, bool mustHandleInternally, bool forceDownload, const char* overrideContentType)
 {
     stopCurrentLoad();
+    DeferredTaskLoadManualScript::finishOrCancel(this);
 
     String urlString(url);
     if (urlString.startsWith("vs:", false)) {
@@ -541,10 +572,9 @@
     KURL kurl = parseUrl(urlString);
     if (protocolIs(kurl, "_javascript_")) {
         // Never run _javascript_ while loading is deferred.
-        if (m_page->defersLoading()) {
-            FrameLoaderClientBlackBerry* frameLoaderClient = static_cast<FrameLoaderClientBlackBerry*>(m_mainFrame->loader()->client());
-            frameLoaderClient->setDeferredManualScript(kurl);
-        } else
+        if (m_page->defersLoading())
+            m_deferredTasks.append(adoptPtr(new DeferredTaskLoadManualScript(this, kurl)));
+        else
             m_mainFrame->script()->executeIfJavaScriptURL(kurl, DoNotReplaceDocumentIfJavaScriptURL);
         return;
     }
@@ -751,8 +781,7 @@
     m_mainFrame->loader()->stopAllLoaders();
 
     // Cancel any deferred script that hasn't been processed yet.
-    FrameLoaderClientBlackBerry* frameLoaderClient = static_cast<FrameLoaderClientBlackBerry*>(m_mainFrame->loader()->client());
-    frameLoaderClient->setDeferredManualScript(KURL());
+    DeferredTaskLoadManualScript::finishOrCancel(this);
 }
 
 void WebPage::stopLoading()
@@ -1220,14 +1249,32 @@
 
 void WebPagePrivate::willDeferLoading()
 {
+    m_deferredTasksTimer.stop();
     m_client->willDeferLoading();
 }
 
 void WebPagePrivate::didResumeLoading()
 {
+    if (!m_deferredTasks.isEmpty())
+        m_deferredTasksTimer.startOneShot(0);
     m_client->didResumeLoading();
 }
 
+void WebPagePrivate::deferredTasksTimerFired(WebCore::Timer<WebPagePrivate>*)
+{
+    ASSERT(!m_deferredTasks.isEmpty());
+    if (!m_deferredTasks.isEmpty())
+        return;
+
+    OwnPtr<DeferredTaskBase> task = m_deferredTasks[0].release();
+    m_deferredTasks.remove(0);
+
+    if (!m_deferredTasks.isEmpty())
+        m_deferredTasksTimer.startOneShot(0);
+
+    task->perform(this);
+}
+
 bool WebPagePrivate::scrollBy(int deltaX, int deltaY, bool scrollMainFrame)
 {
     IntSize delta(deltaX, deltaY);
@@ -2449,6 +2496,8 @@
 
 void WebPage::assignFocus(Platform::FocusDirection direction)
 {
+    if (d->m_page->defersLoading())
+       return;
     d->assignFocus(direction);
 }
 
@@ -2982,12 +3031,31 @@
 }
 
 #if ENABLE(PAGE_VISIBILITY_API)
+class DeferredTaskSetPageVisibilityState: public DeferredTask<&WebPagePrivate::m_wouldSetPageVisibilityState> {
+public:
+    explicit DeferredTaskSetPageVisibilityState(WebPagePrivate* webPagePrivate)
+        : DeferredTaskType(webPagePrivate)
+    {
+    }
+private:
+    virtual void performInternal(WebPagePrivate* webPagePrivate)
+    {
+        webPagePrivate->setPageVisibilityState();
+    }
+};
+
 void WebPagePrivate::setPageVisibilityState()
 {
-    static bool s_initialVisibilityState = true;
+    if (m_page->defersLoading())
+        m_deferredTasks.append(adoptPtr(new DeferredTaskSetPageVisibilityState(this)));
+    else {
+        DeferredTaskSetPageVisibilityState::finishOrCancel(this);
 
-    m_page->setVisibilityState(m_visible && m_activationState == ActivationActive ? PageVisibilityStateVisible : PageVisibilityStateHidden, s_initialVisibilityState);
-    s_initialVisibilityState = false;
+        static bool s_initialVisibilityState = true;
+
+        m_page->setVisibilityState(m_visible && m_activationState == ActivationActive ? PageVisibilityStateVisible : PageVisibilityStateHidden, s_initialVisibilityState);
+        s_initialVisibilityState = false;
+    }
 }
 #endif
 
@@ -3093,6 +3161,8 @@
 
 bool WebPage::setInputSelection(unsigned start, unsigned end)
 {
+    if (d->m_page->defersLoading())
+        return false;
     return d->m_inputHandler->setSelection(start, end);
 }
 
@@ -3101,23 +3171,101 @@
     return d->m_inputHandler->caretPosition();
 }
 
-void WebPage::popupListClosed(int size, bool* selecteds)
+class DeferredTaskPopupListSelectMultiple: public DeferredTask<&WebPagePrivate::m_wouldPopupListSelectMultiple> {
+public:
+    DeferredTaskPopupListSelectMultiple(WebPagePrivate* webPagePrivate, int size, const bool* selecteds) 
+        : DeferredTaskType(webPagePrivate)
+    {
+        webPagePrivate->m_cachedPopupListSelecteds.append(selecteds, size);
+    }
+private:
+    virtual void performInternal(WebPagePrivate* webPagePrivate)
+    {
+        webPagePrivate->m_webPage->popupListClosed(webPagePrivate->m_cachedPopupListSelecteds.size(), webPagePrivate->m_cachedPopupListSelecteds.data());
+    }
+};
+
+class DeferredTaskPopupListSelectSingle: public DeferredTask<&WebPagePrivate::m_wouldPopupListSelectSingle> {
+public:
+    explicit DeferredTaskPopupListSelectSingle(WebPagePrivate* webPagePrivate, int index)
+        : DeferredTaskType(webPagePrivate)
+    {
+        webPagePrivate->m_cachedPopupListSelectedIndex = index;
+    }
+private:
+    virtual void performInternal(WebPagePrivate* webPagePrivate)
+    {
+        webPagePrivate->m_webPage->popupListClosed(webPagePrivate->m_cachedPopupListSelectedIndex);
+    }
+};
+
+void WebPage::popupListClosed(int size, const bool* selecteds)
 {
+    DeferredTaskPopupListSelectSingle::finishOrCancel(d);
+    if (d->m_page->defersLoading()) {
+        d->m_deferredTasks.append(adoptPtr(new DeferredTaskPopupListSelectMultiple(d, size, selecteds)));
+        return;
+    }
+    DeferredTaskPopupListSelectMultiple::finishOrCancel(d);
     d->m_inputHandler->setPopupListIndexes(size, selecteds);
 }
 
 void WebPage::popupListClosed(int index)
 {
+    DeferredTaskPopupListSelectMultiple::finishOrCancel(d);
+    if (d->m_page->defersLoading()) {
+        d->m_deferredTasks.append(adoptPtr(new DeferredTaskPopupListSelectSingle(d, index)));
+        return;
+    }
+    DeferredTaskPopupListSelectSingle::finishOrCancel(d);
     d->m_inputHandler->setPopupListIndex(index);
 }
 
+class DeferredTaskSetDateTimeInput: public DeferredTask<&WebPagePrivate::m_wouldSetDateTimeInput> {
+public:
+    explicit DeferredTaskSetDateTimeInput(WebPagePrivate* webPagePrivate, WebString value)
+        : DeferredTaskType(webPagePrivate)
+    {
+        webPagePrivate->m_cachedDateTimeInput = value;
+    }
+private:
+    virtual void performInternal(WebPagePrivate* webPagePrivate)
+    {
+        webPagePrivate->m_webPage->setDateTimeInput(webPagePrivate->m_cachedDateTimeInput);
+    }
+};
+
 void WebPage::setDateTimeInput(const WebString& value)
 {
+    if (d->m_page->defersLoading()) {
+        d->m_deferredTasks.append(adoptPtr(new DeferredTaskSetDateTimeInput(d, value)));
+        return;
+    }
+    DeferredTaskSetDateTimeInput::finishOrCancel(d);
     d->m_inputHandler->setInputValue(String(value.impl()));
 }
 
+class DeferredTaskSetColorInput: public DeferredTask<&WebPagePrivate::m_wouldSetColorInput> {
+public:
+    explicit DeferredTaskSetColorInput(WebPagePrivate* webPagePrivate, WebString value)
+        : DeferredTaskType(webPagePrivate)
+    {
+        webPagePrivate->m_cachedColorInput = value;
+    }
+private:
+    virtual void performInternal(WebPagePrivate* webPagePrivate)
+    {
+        webPagePrivate->m_webPage->setColorInput(webPagePrivate->m_cachedColorInput);
+    }
+};
+
 void WebPage::setColorInput(const WebString& value)
 {
+    if (d->m_page->defersLoading()) {
+        d->m_deferredTasks.append(adoptPtr(new DeferredTaskSetColorInput(d, value)));
+        return;
+    }
+    DeferredTaskSetColorInput::finishOrCancel(d);
     d->m_inputHandler->setInputValue(String(value.impl()));
 }
 
@@ -3553,6 +3701,9 @@
     if (!d->m_mainFrame->view())
         return false;
 
+    if (d->m_page->defersLoading())
+        return false;
+
     PluginView* pluginView = d->m_fullScreenPluginView.get();
     if (pluginView)
         return d->dispatchMouseEventToFullScreenPlugin(pluginView, mouseEvent);
@@ -3729,13 +3880,16 @@
 #endif
 
 #if ENABLE(TOUCH_EVENTS)
+    if (!d->m_mainFrame)
+        return false;
+
+    if (d->m_page->defersLoading())
+        return false;
+
     PluginView* pluginView = d->m_fullScreenPluginView.get();
     if (pluginView)
         return d->dispatchTouchEventToFullScreenPlugin(pluginView, event);
 
-    if (!d->m_mainFrame)
-        return false;
-
     Platform::TouchEvent tEvent = event;
     for (unsigned i = 0; i < event.m_points.size(); i++) {
         tEvent.m_points[i].m_pos = d->mapFromTransformed(tEvent.m_points[i].m_pos);
@@ -3853,6 +4007,9 @@
 
 bool WebPage::touchPointAsMouseEvent(const Platform::TouchPoint& point)
 {
+    if (d->m_page->defersLoading())
+        return false;
+
     PluginView* pluginView = d->m_fullScreenPluginView.get();
     if (pluginView)
         return d->dispatchTouchPointAsMouseEventToFullScreenPlugin(pluginView, point);
@@ -3898,11 +4055,15 @@
 void WebPage::touchEventCancel()
 {
     d->m_pluginMayOpenNewTab = false;
+    if (d->m_page->defersLoading())
+        return;
     d->m_touchEventHandler->touchEventCancel();
 }
 
 void WebPage::touchEventCancelAndClearFocusedNode()
 {
+    if (d->m_page->defersLoading())
+        return;
     d->m_touchEventHandler->touchEventCancelAndClearFocusedNode();
 }
 
@@ -4121,6 +4282,9 @@
     if (!d->m_mainFrame->view())
         return false;
 
+    if (d->m_page->defersLoading())
+        return false;
+
     ASSERT(d->m_page->focusController());
 
     bool handled = d->m_inputHandler->handleKeyboardInput(keyboardEvent);
@@ -4136,6 +4300,9 @@
 
 bool WebPage::deleteTextRelativeToCursor(unsigned int leftOffset, unsigned int rightOffset)
 {
+    if (d->m_page->defersLoading())
+        return false;
+
     return d->m_inputHandler->deleteTextRelativeToCursor(leftOffset, rightOffset);
 }
 
@@ -4171,11 +4338,15 @@
 
 int32_t WebPage::setComposingText(spannable_string_t* spannableString, int32_t relativeCursorPosition)
 {
+    if (d->m_page->defersLoading())
+        return -1;
     return d->m_inputHandler->setComposingText(spannableString, relativeCursorPosition);
 }
 
 int32_t WebPage::commitText(spannable_string_t* spannableString, int32_t relativeCursorPosition)
 {
+    if (d->m_page->defersLoading())
+        return -1;
     return d->m_inputHandler->commitText(spannableString, relativeCursorPosition);
 }
 
@@ -4184,8 +4355,26 @@
     static_cast<EditorClientBlackBerry*>(d->m_page->editorClient())->enableSpellChecking(enabled);
 }
 
+class DeferredTaskSelectionCancelled: public DeferredTask<&WebPagePrivate::m_wouldCancelSelection> {
+public:
+    explicit DeferredTaskSelectionCancelled(WebPagePrivate* webPagePrivate)
+        : DeferredTaskType(webPagePrivate)
+    {
+    }
+private:
+    virtual void performInternal(WebPagePrivate* webPagePrivate)
+    {
+        webPagePrivate->m_webPage->selectionCancelled();
+    }
+};
+
 void WebPage::selectionCancelled()
 {
+    if (d->m_page->defersLoading()) {
+        d->m_deferredTasks.append(adoptPtr(new DeferredTaskSelectionCancelled(d)));
+        return;
+    }
+    DeferredTaskSelectionCancelled::finishOrCancel(d);
     d->m_selectionHandler->cancelSelection();
 }
 
@@ -4209,23 +4398,29 @@
 WebString WebPage::cutSelectedText()
 {
     WebString selectedText = d->m_selectionHandler->selectedText();
-    if (!selectedText.isEmpty())
+    if (!d->m_page->defersLoading() && !selectedText.isEmpty())
         d->m_inputHandler->deleteSelection();
     return selectedText;
 }
 
 void WebPage::insertText(const WebString& string)
 {
+    if (d->m_page->defersLoading())
+        return;
     d->m_inputHandler->insertText(string);
 }
 
 void WebPage::clearCurrentInputField()
 {
+    if (d->m_page->defersLoading())
+        return;
     d->m_inputHandler->clearField();
 }
 
 void WebPage::cut()
 {
+    if (d->m_page->defersLoading())
+        return;
     d->m_inputHandler->cut();
 }
 
@@ -4236,11 +4431,15 @@
 
 void WebPage::paste()
 {
+    if (d->m_page->defersLoading())
+        return;
     d->m_inputHandler->paste();
 }
 
 void WebPage::setSelection(const Platform::IntPoint& startPoint, const Platform::IntPoint& endPoint)
 {
+    if (d->m_page->defersLoading())
+        return;
     // Transform this events coordinates to webkit content coordinates.
     // FIXME: Don't transform the sentinel, because it may be transformed to a floating number
     // which could be rounded to 0 or other numbers. This workaround should be removed after
@@ -4250,18 +4449,22 @@
     invalidPoint = IntPoint(endPoint) == DOMSupport::InvalidPoint;
     IntPoint end = invalidPoint ? DOMSupport::InvalidPoint : d->mapFromTransformed(endPoint);
 
-    d->m_selectionHandler->setSelection(start, end);
+    return d->m_selectionHandler->setSelection(start, end);
 }
 
 void WebPage::setCaretPosition(const Platform::IntPoint& position)
 {
+    if (d->m_page->defersLoading())
+        return;
     // Handled by selection handler as it's point based.
     // Transform this events coordinates to webkit content coordinates.
-    d->m_selectionHandler->setCaretPosition(d->mapFromTransformed(position));
+    return d->m_selectionHandler->setCaretPosition(d->mapFromTransformed(position));
 }
 
 void WebPage::selectAtPoint(const Platform::IntPoint& location)
 {
+    if (d->m_page->defersLoading())
+        return;
     // Transform this events coordinates to webkit content coordinates if it
     // is not the sentinel value.
     IntPoint selectionLocation =
@@ -4695,8 +4898,27 @@
     return d->zoomAboutPoint(scale, d->centerOfVisibleContentsRect());
 }
 
+class DeferredTaskSetFocused: public DeferredTask<&WebPagePrivate::m_wouldSetFocused> {
+public:
+    explicit DeferredTaskSetFocused(WebPagePrivate* webPagePrivate, bool focused)
+        : DeferredTaskType(webPagePrivate)
+    {
+        webPagePrivate->m_cachedFocused = focused;
+    }
+private:
+    virtual void performInternal(WebPagePrivate* webPagePrivate)
+    {
+        webPagePrivate->m_webPage->setFocused(webPagePrivate->m_cachedFocused);
+    }
+};
+
 void WebPage::setFocused(bool focused)
 {
+    if (d->m_page->defersLoading()) {
+        d->m_deferredTasks.append(adoptPtr(new DeferredTaskSetFocused(d, focused)));
+        return;
+    }
+    DeferredTaskSetFocused::finishOrCancel(d);
     FocusController* focusController = d->m_page->focusController();
     focusController->setActive(focused);
     if (focused) {

Modified: trunk/Source/WebKit/blackberry/Api/WebPage.h (115244 => 115245)


--- trunk/Source/WebKit/blackberry/Api/WebPage.h	2012-04-25 21:15:39 UTC (rev 115244)
+++ trunk/Source/WebKit/blackberry/Api/WebPage.h	2012-04-25 21:22:53 UTC (rev 115245)
@@ -251,7 +251,7 @@
     void selectionCancelled();
     bool selectionContains(const Platform::IntPoint&);
 
-    void popupListClosed(int size, bool* selecteds);
+    void popupListClosed(int size, const bool* selecteds);
     void popupListClosed(int index);
     void setDateTimeInput(const WebString& value);
     void setColorInput(const WebString& value);

Modified: trunk/Source/WebKit/blackberry/Api/WebPage_p.h (115244 => 115245)


--- trunk/Source/WebKit/blackberry/Api/WebPage_p.h	2012-04-25 21:15:39 UTC (rev 115244)
+++ trunk/Source/WebKit/blackberry/Api/WebPage_p.h	2012-04-25 21:22:53 UTC (rev 115245)
@@ -24,6 +24,7 @@
 #include "GLES2Context.h"
 #include "LayerRenderer.h"
 #endif
+#include "KURL.h"
 #include "PageClientBlackBerry.h"
 #include "PlatformMouseEvent.h"
 #include "ScriptSourceCode.h"
@@ -40,7 +41,6 @@
 class Frame;
 class GeolocationControllerClientBlackBerry;
 class _javascript_DebuggerBlackBerry;
-class KURL;
 class Node;
 class Page;
 class PluginView;
@@ -415,6 +415,8 @@
 #endif
     void notifyAppActivationStateChange(ActivationStateType);
 
+    void deferredTasksTimerFired(WebCore::Timer<WebPagePrivate>*);
+
     WebPage* m_webPage;
     WebPageClient* m_client;
     WebCore::Page* m_page;
@@ -536,6 +538,46 @@
     bool m_hasInRegionScrollableAreas;
     bool m_updateDelegatedOverlaysDispatched;
 
+    // There is no need to initialize the following members in WebPagePrivate's constructor,
+    // because they are only used by WebPageTasks and the tasks will initialize them when
+    // being constructed.
+    bool m_wouldPopupListSelectMultiple;
+    bool m_wouldPopupListSelectSingle;
+    bool m_wouldSetDateTimeInput;
+    bool m_wouldSetColorInput;
+    bool m_wouldCancelSelection;
+    bool m_wouldSetFocused;
+    bool m_wouldSetPageVisibilityState;
+    Vector<bool> m_cachedPopupListSelecteds;
+    int m_cachedPopupListSelectedIndex;
+    WebString m_cachedDateTimeInput;
+    WebString m_cachedColorInput;
+    WebCore::KURL m_cachedManualScript;
+    bool m_cachedFocused;
+
+    class DeferredTaskBase {
+    public:
+        void perform(WebPagePrivate* webPagePrivate)
+        {
+            if (!(webPagePrivate->*m_isActive))
+                return;
+            performInternal(webPagePrivate);
+        }
+    protected:
+        DeferredTaskBase(WebPagePrivate* webPagePrivate, bool WebPagePrivate::*isActive)
+            : m_isActive(isActive)
+        {
+            webPagePrivate->*m_isActive = true;
+        }
+
+        virtual void performInternal(WebPagePrivate*) = 0;
+
+        bool WebPagePrivate::*m_isActive;
+    };
+
+    Vector<OwnPtr<DeferredTaskBase> > m_deferredTasks;
+    WebCore::Timer<WebPagePrivate> m_deferredTasksTimer;
+
 protected:
     virtual ~WebPagePrivate();
 };

Modified: trunk/Source/WebKit/blackberry/ChangeLog (115244 => 115245)


--- trunk/Source/WebKit/blackberry/ChangeLog	2012-04-25 21:15:39 UTC (rev 115244)
+++ trunk/Source/WebKit/blackberry/ChangeLog	2012-04-25 21:22:53 UTC (rev 115245)
@@ -1,3 +1,70 @@
+2012-04-25  Yong Li  <y...@rim.com>
+
+        [BlackBerry] Possible JS re-entrancy caused by UI events.
+        https://bugs.webkit.org/show_bug.cgi?id=84862
+
+        Reviewed by Antonio Gomes.
+
+        1. block UI events when running in nested event loop
+        2. defer some tasks we still want to perform when it is safe to do,
+           with cached data.
+        3. deferred task can be cancelled by clearing the flag. duplicate tasks
+           is not a problem because they share same flag and data.
+        4. move deferred manual script from FrameLoaderClientBlackBerry to WebPagePrivate
+           and make it a deferred task
+
+        * Api/WebPage.cpp:
+        (WebKit):
+        (BlackBerry::WebKit::WebPagePrivate::WebPagePrivate):
+        (BlackBerry::WebKit::WebPagePrivate::load):
+        (BlackBerry::WebKit::WebPagePrivate::stopCurrentLoad):
+        (BlackBerry::WebKit::WebPagePrivate::willDeferLoading):
+        (BlackBerry::WebKit::WebPagePrivate::didResumeLoading):
+        (BlackBerry::WebKit::WebPagePrivate::deferredTasksTimerFired):
+        (BlackBerry::WebKit::WebPage::assignFocus):
+        (BlackBerry::WebKit::WebPagePrivate::setPageVisibilityState):
+        (BlackBerry::WebKit::WebPage::setInputSelection):
+        (BlackBerry::WebKit::WebPage::popupListClosed):
+        (BlackBerry::WebKit::WebPage::setDateTimeInput):
+        (BlackBerry::WebKit::WebPage::setColorInput):
+        (BlackBerry::WebKit::WebPage::mouseEvent):
+        (BlackBerry::WebKit::WebPage::touchEvent):
+        (BlackBerry::WebKit::WebPage::touchPointAsMouseEvent):
+        (BlackBerry::WebKit::WebPage::touchEventCancel):
+        (BlackBerry::WebKit::WebPage::touchEventCancelAndClearFocusedNode):
+        (BlackBerry::WebKit::WebPage::keyEvent):
+        (BlackBerry::WebKit::WebPage::deleteTextRelativeToCursor):
+        (BlackBerry::WebKit::WebPage::setComposingText):
+        (BlackBerry::WebKit::WebPage::commitText):
+        (BlackBerry::WebKit::WebPage::selectionCancelled):
+        (BlackBerry::WebKit::WebPage::cutSelectedText):
+        (BlackBerry::WebKit::WebPage::insertText):
+        (BlackBerry::WebKit::WebPage::clearCurrentInputField):
+        (BlackBerry::WebKit::WebPage::cut):
+        (BlackBerry::WebKit::WebPage::paste):
+        (BlackBerry::WebKit::WebPage::setSelection):
+        (BlackBerry::WebKit::WebPage::setCaretPosition):
+        (BlackBerry::WebKit::WebPage::selectAtPoint):
+        (BlackBerry::WebKit::WebPage::setFocused):
+        * Api/WebPage.h:
+        * Api/WebPage_p.h:
+        (WebCore):
+        (WebPagePrivate):
+        (DeferredTaskBase):
+        (BlackBerry::WebKit::WebPagePrivate::DeferredTaskBase::perform):
+        (BlackBerry::WebKit::WebPagePrivate::DeferredTaskBase::DeferredTaskBase):
+        * WebCoreSupport/FrameLoaderClientBlackBerry.cpp:
+        (WebCore::FrameLoaderClientBlackBerry::FrameLoaderClientBlackBerry):
+        (WebCore::FrameLoaderClientBlackBerry::~FrameLoaderClientBlackBerry):
+        (WebCore::FrameLoaderClientBlackBerry::willDeferLoading):
+        (WebCore::FrameLoaderClientBlackBerry::didResumeLoading):
+        * WebCoreSupport/FrameLoaderClientBlackBerry.h:
+        (FrameLoaderClientBlackBerry):
+        * WebKitSupport/InputHandler.cpp:
+        (BlackBerry::WebKit::InputHandler::setPopupListIndexes):
+        * WebKitSupport/InputHandler.h:
+        (InputHandler):
+
 2012-04-24  Nima Ghanavatian  <nghanavat...@rim.com>
 
         [BlackBerry] Perform spellcheck before handling TouchRelease event

Modified: trunk/Source/WebKit/blackberry/WebCoreSupport/FrameLoaderClientBlackBerry.cpp (115244 => 115245)


--- trunk/Source/WebKit/blackberry/WebCoreSupport/FrameLoaderClientBlackBerry.cpp	2012-04-25 21:15:39 UTC (rev 115244)
+++ trunk/Source/WebKit/blackberry/WebCoreSupport/FrameLoaderClientBlackBerry.cpp	2012-04-25 21:22:53 UTC (rev 115245)
@@ -101,13 +101,10 @@
     , m_hasSentResponseToPlugin(false)
     , m_cancelLoadOnNextData(false)
 {
-    m_deferredJobsTimer = new Timer<FrameLoaderClientBlackBerry>(this, &FrameLoaderClientBlackBerry::deferredJobsTimerFired);
 }
 
 FrameLoaderClientBlackBerry::~FrameLoaderClientBlackBerry()
 {
-    delete m_deferredJobsTimer;
-    m_deferredJobsTimer = 0;
 }
 
 int FrameLoaderClientBlackBerry::playerId() const
@@ -1114,8 +1111,6 @@
 
 void FrameLoaderClientBlackBerry::willDeferLoading()
 {
-    m_deferredJobsTimer->stop();
-
     if (!isMainFrame())
         return;
 
@@ -1124,36 +1119,12 @@
 
 void FrameLoaderClientBlackBerry::didResumeLoading()
 {
-    if (!m_deferredManualScript.isNull())
-        m_deferredJobsTimer->startOneShot(0);
-
     if (!isMainFrame())
         return;
 
     m_webPagePrivate->didResumeLoading();
 }
 
-void FrameLoaderClientBlackBerry::setDeferredManualScript(const KURL& script)
-{
-    ASSERT(!m_deferredJobsTimer->isActive());
-    m_deferredManualScript = script;
-}
-
-void FrameLoaderClientBlackBerry::deferredJobsTimerFired(Timer<FrameLoaderClientBlackBerry>*)
-{
-    ASSERT(!m_frame->page()->defersLoading());
-
-    if (!m_deferredManualScript.isNull()) {
-        // Executing the script will set deferred loading, which could trigger this timer again if a script is set. So clear the script first.
-        KURL script = m_deferredManualScript;
-        m_deferredManualScript = KURL();
-
-        m_frame->script()->executeIfJavaScriptURL(script);
-    }
-
-    ASSERT(!m_frame->page()->defersLoading());
-}
-
 void FrameLoaderClientBlackBerry::readyToRender(bool pageIsVisuallyNonEmpty)
 {
     // Only send the notification once.

Modified: trunk/Source/WebKit/blackberry/WebCoreSupport/FrameLoaderClientBlackBerry.h (115244 => 115245)


--- trunk/Source/WebKit/blackberry/WebCoreSupport/FrameLoaderClientBlackBerry.h	2012-04-25 21:15:39 UTC (rev 115244)
+++ trunk/Source/WebKit/blackberry/WebCoreSupport/FrameLoaderClientBlackBerry.h	2012-04-25 21:22:53 UTC (rev 115245)
@@ -170,10 +170,6 @@
 
     virtual PassRefPtr<FrameNetworkingContext> createNetworkingContext();
 
-     // Schedule a script that was loaded manually by the user (eg. a
-     // bookmarklet) while page loading was deferred.
-    void setDeferredManualScript(const KURL&);
-
     void readyToRender(bool pageIsVisuallyNonEmpty);
 
     void doPendingFragmentScroll();
@@ -195,14 +191,10 @@
     PolicyAction decidePolicyForExternalLoad(const ResourceRequest &, bool isFragmentScroll);
     void delayPolicyCheckUntilFragmentExists(const String& fragment, FramePolicyFunction);
 
-    void deferredJobsTimerFired(Timer<FrameLoaderClientBlackBerry>*);
-
     Frame* m_frame;
     ResourceError m_loadError;
     BlackBerry::WebKit::WebPagePrivate* m_webPagePrivate;
 
-    Timer<FrameLoaderClientBlackBerry>* m_deferredJobsTimer;
-    KURL m_deferredManualScript;
     Geolocation* m_geolocation;
     bool m_sentReadyToRender;
 

Modified: trunk/Source/WebKit/blackberry/WebKitSupport/InputHandler.cpp (115244 => 115245)


--- trunk/Source/WebKit/blackberry/WebKitSupport/InputHandler.cpp	2012-04-25 21:15:39 UTC (rev 115244)
+++ trunk/Source/WebKit/blackberry/WebKitSupport/InputHandler.cpp	2012-04-25 21:22:53 UTC (rev 115245)
@@ -1189,7 +1189,7 @@
     clearCurrentFocusElement();
 }
 
-void InputHandler::setPopupListIndexes(int size, bool* selecteds)
+void InputHandler::setPopupListIndexes(int size, const bool* selecteds)
 {
     if (!isActiveSelectPopup())
         return clearCurrentFocusElement();

Modified: trunk/Source/WebKit/blackberry/WebKitSupport/InputHandler.h (115244 => 115245)


--- trunk/Source/WebKit/blackberry/WebKitSupport/InputHandler.h	2012-04-25 21:15:39 UTC (rev 115244)
+++ trunk/Source/WebKit/blackberry/WebKitSupport/InputHandler.h	2012-04-25 21:22:53 UTC (rev 115245)
@@ -95,7 +95,7 @@
     bool openLineInputPopup(WebCore::HTMLInputElement*);
     bool openSelectPopup(WebCore::HTMLSelectElement*);
     void setPopupListIndex(int);
-    void setPopupListIndexes(int size, bool* selecteds);
+    void setPopupListIndexes(int size, const bool* selecteds);
 
     bool processingChange() const { return m_processingChange; }
     void setProcessingChange(bool processingChange) { m_processingChange = processingChange; }
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
http://lists.webkit.org/mailman/listinfo.cgi/webkit-changes

Reply via email to