WebCore:
authormitz@apple.com <mitz@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 23 Nov 2007 06:04:36 +0000 (06:04 +0000)
committermitz@apple.com <mitz@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 23 Nov 2007 06:04:36 +0000 (06:04 +0000)
        Reviewed by Antti Koivisto.

        - fix http://bugs.webkit.org/show_bug.cgi?id=15811
          WebKit plug-ins can re-enter WebKit under attach()
          <rdar://problem/5577978>

        Defer plug-in loading until after attach and recalcStyle using the
        post-attach callback mechanism. Netscape plug-ins are still loaded only
        after layout.

        * dom/ContainerNode.cpp:
        Made NodeCallbackQueue elements retain the Node because callbacks might
        delete nodes that are in the callback queue.
        (WebCore::ContainerNode::suspendPostAttachCallbacks): Added. Needed to
        prevent post-attach callbacks from being dispatched under recalcStyle().
        (WebCore::ContainerNode::resumePostAttachCallbacks): Ditto.
        (WebCore::ContainerNode::dispatchPostAttachCallbacks): Factored out from
        attach().
        (WebCore::ContainerNode::attach):
        * dom/ContainerNode.h:
        * dom/Document.cpp:
        (WebCore::Document::recalcStyle): Added calls to
        suspendPostAttachCallbacks() and resumePostAttachCallbacks().
        * html/HTMLEmbedElement.cpp:
        (WebCore::HTMLEmbedElement::HTMLEmbedElement):
        (WebCore::HTMLEmbedElement::attach): Changed to queue the widget update
        for post-attach.
        (WebCore::HTMLEmbedElement::updateWidget): Added. Called by the
        post-attach callback.
        * html/HTMLEmbedElement.h: Added an m_needWidgetUpdate member needed to
        prevent a double update if another plug-in's post-attach updateWidget()
        triggers a layout which updates the widget before this plug-in's
        post-attach callback is invoked.
        (WebCore::HTMLEmbedElement::setNeedWidgetUpdate): Added a setter for
        m_needWidgetUpdate.
        * html/HTMLObjectElement.cpp:
        (WebCore::HTMLObjectElement::attach): Changed to queue the widget update
        for post-attach.
        (WebCore::HTMLObjectElement::updateWidget): Added. Called by the
        post-attach callback.
        * html/HTMLObjectElement.h:
        (WebCore::HTMLObjectElement::setNeedWidgetUpdate): Added a setter for
        m_needWidgetUpdate.
        * html/HTMLPlugInElement.cpp:
        (WebCore::HTMLPlugInElement::updateWidgetCallback): Added.
        * html/HTMLPlugInElement.h:
        (WebCore::HTMLPlugInElement::updateWidget):
        * rendering/RenderPartObject.cpp:
        (WebCore::RenderPartObject::updateWidget): Added calls to
        setNeedWidgetUpdate(false) so that if this method is called from
        FrameView::layout() during post-attach dispatch of another plug-in,
        it will not be called again when this plug-in's post-attach callback
        is dispatched.
        * rendering/RenderPartObject.h:
        (WebCore::RenderPartObject::updateWidget) Renamed argument to match
        the method definition.

WebKit/mac:

        Reviewed by Antti Koivisto.

        - http://bugs.webkit.org/show_bug.cgi?id=15811
          WebKit plug-ins can re-enter WebKit under attach()
          <rdar://problem/5577978>

        * Plugins/WebNullPluginView.mm:
        (-[WebNullPluginView viewDidMoveToWindow]): Removed workaround for the
        above bug that added as part of fixing
        <http://bugs.webkit.org/show_bug.cgi?id=15804>.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@27982 268f45cc-cd09-0410-ab3c-d52691b4dbfc

14 files changed:
WebCore/ChangeLog
WebCore/dom/ContainerNode.cpp
WebCore/dom/ContainerNode.h
WebCore/dom/Document.cpp
WebCore/html/HTMLEmbedElement.cpp
WebCore/html/HTMLEmbedElement.h
WebCore/html/HTMLObjectElement.cpp
WebCore/html/HTMLObjectElement.h
WebCore/html/HTMLPlugInElement.cpp
WebCore/html/HTMLPlugInElement.h
WebCore/rendering/RenderPartObject.cpp
WebCore/rendering/RenderPartObject.h
WebKit/mac/ChangeLog
WebKit/mac/Plugins/WebNullPluginView.mm

index b7866d906d7e61a1d0450c6fb3c29ff75cbeb2ca..3987dcfaf36c6d49f5283fa08bc89de8b0711bef 100644 (file)
@@ -1,3 +1,62 @@
+2007-11-22  Dan Bernstein  <mitz@apple.com>
+
+        Reviewed by Antti Koivisto.
+
+        - fix http://bugs.webkit.org/show_bug.cgi?id=15811
+          WebKit plug-ins can re-enter WebKit under attach()
+          <rdar://problem/5577978>
+
+        Defer plug-in loading until after attach and recalcStyle using the
+        post-attach callback mechanism. Netscape plug-ins are still loaded only
+        after layout.
+
+        * dom/ContainerNode.cpp:
+        Made NodeCallbackQueue elements retain the Node because callbacks might
+        delete nodes that are in the callback queue.
+        (WebCore::ContainerNode::suspendPostAttachCallbacks): Added. Needed to
+        prevent post-attach callbacks from being dispatched under recalcStyle().
+        (WebCore::ContainerNode::resumePostAttachCallbacks): Ditto.
+        (WebCore::ContainerNode::dispatchPostAttachCallbacks): Factored out from
+        attach().
+        (WebCore::ContainerNode::attach):
+        * dom/ContainerNode.h:
+        * dom/Document.cpp:
+        (WebCore::Document::recalcStyle): Added calls to
+        suspendPostAttachCallbacks() and resumePostAttachCallbacks().
+        * html/HTMLEmbedElement.cpp:
+        (WebCore::HTMLEmbedElement::HTMLEmbedElement):
+        (WebCore::HTMLEmbedElement::attach): Changed to queue the widget update
+        for post-attach.
+        (WebCore::HTMLEmbedElement::updateWidget): Added. Called by the
+        post-attach callback.
+        * html/HTMLEmbedElement.h: Added an m_needWidgetUpdate member needed to
+        prevent a double update if another plug-in's post-attach updateWidget()
+        triggers a layout which updates the widget before this plug-in's
+        post-attach callback is invoked.
+        (WebCore::HTMLEmbedElement::setNeedWidgetUpdate): Added a setter for
+        m_needWidgetUpdate.
+        * html/HTMLObjectElement.cpp:
+        (WebCore::HTMLObjectElement::attach): Changed to queue the widget update
+        for post-attach.
+        (WebCore::HTMLObjectElement::updateWidget): Added. Called by the
+        post-attach callback.
+        * html/HTMLObjectElement.h:
+        (WebCore::HTMLObjectElement::setNeedWidgetUpdate): Added a setter for
+        m_needWidgetUpdate.
+        * html/HTMLPlugInElement.cpp:
+        (WebCore::HTMLPlugInElement::updateWidgetCallback): Added.
+        * html/HTMLPlugInElement.h:
+        (WebCore::HTMLPlugInElement::updateWidget):
+        * rendering/RenderPartObject.cpp:
+        (WebCore::RenderPartObject::updateWidget): Added calls to
+        setNeedWidgetUpdate(false) so that if this method is called from
+        FrameView::layout() during post-attach dispatch of another plug-in,
+        it will not be called again when this plug-in's post-attach callback
+        is dispatched.
+        * rendering/RenderPartObject.h:
+        (WebCore::RenderPartObject::updateWidget) Renamed argument to match
+        the method definition.
+
 2007-11-22  Timothy Hatcher  <timothy@apple.com>
 
         Reviewed by Dan Bernstein.
index 553af80cadc0b3d9cb0026f8109e018653875d46..408781dc827df869a3b79f47f585d6423edd5891 100644 (file)
@@ -45,7 +45,7 @@ using namespace EventNames;
 static void dispatchChildInsertionEvents(Node*, ExceptionCode&);
 static void dispatchChildRemovalEvents(Node*, ExceptionCode&);
 
-typedef Vector<std::pair<NodeCallback, Node*> > NodeCallbackQueue;
+typedef Vector<std::pair<NodeCallback, RefPtr<Node> > > NodeCallbackQueue;
 static NodeCallbackQueue* s_postAttachCallbackQueue = 0;
 
 static size_t s_attachDepth = 0;
@@ -584,12 +584,38 @@ ContainerNode* ContainerNode::addChild(PassRefPtr<Node> newChild)
     return this;
 }
 
+void ContainerNode::suspendPostAttachCallbacks()
+{
+    ++s_attachDepth;
+}
+
+void ContainerNode::resumePostAttachCallbacks()
+{
+    if (s_attachDepth == 1 && s_postAttachCallbackQueue)
+        dispatchPostAttachCallbacks();
+    --s_attachDepth;
+}
+
 void ContainerNode::queuePostAttachCallback(NodeCallback callback, Node* node)
 {
     if (!s_postAttachCallbackQueue)
         s_postAttachCallbackQueue = new NodeCallbackQueue;
     
-    s_postAttachCallbackQueue->append(std::pair<NodeCallback, Node*>(callback, node));
+    s_postAttachCallbackQueue->append(std::pair<NodeCallback, RefPtr<Node> >(callback, node));
+}
+
+void ContainerNode::dispatchPostAttachCallbacks()
+{
+    // We recalculate size() each time through the loop because a callback
+    // can add more callbacks to the end of the queue.
+    for (size_t i = 0; i < s_postAttachCallbackQueue->size(); ++i) {
+        std::pair<NodeCallback, RefPtr<Node> >& pair = (*s_postAttachCallbackQueue)[i];
+        NodeCallback callback = pair.first;
+        Node* node = pair.second.get();
+
+        callback(node);
+    }
+    s_postAttachCallbackQueue->clear();
 }
 
 void ContainerNode::attach()
@@ -600,20 +626,8 @@ void ContainerNode::attach()
         child->attach();
     EventTargetNode::attach();
 
-    if (s_attachDepth == 1) {
-        if (s_postAttachCallbackQueue) {
-            // We recalculate size() each time through the loop because a callback
-            // can add more callbacks to the end of the queue.
-            for (size_t i = 0; i < s_postAttachCallbackQueue->size(); ++i) {
-                std::pair<NodeCallback, Node*>& pair = (*s_postAttachCallbackQueue)[i];
-                NodeCallback callback = pair.first;
-                Node* node = pair.second;
-                
-                callback(node);
-            }
-            s_postAttachCallbackQueue->clear();
-        }
-    }    
+    if (s_attachDepth == 1 && s_postAttachCallbackQueue)
+        dispatchPostAttachCallbacks();
     --s_attachDepth;
 }
 
index 995b1fad87a8b3094c27502149f431fd79bffd3c..ea6661d600d074b2bbc9ea3f540d53613fc26729 100644 (file)
@@ -68,11 +68,15 @@ public:
 
 protected:
     static void queuePostAttachCallback(NodeCallback, Node*);
+    static void suspendPostAttachCallbacks();
+    static void resumePostAttachCallbacks();
 
     void setFirstChild(Node* child) { m_firstChild = child; }
     void setLastChild(Node* child) { m_lastChild = child; }
     
 private:
+    static void dispatchPostAttachCallbacks();
+
     virtual Node* virtualFirstChild() const;
     virtual Node* virtualLastChild() const;
     
index 2437c8984d9bba10fc20c6a05b426b53830e9ecb..d0828e5be0f78a728595d24c108b9f573db6fc83 100644 (file)
@@ -1045,6 +1045,7 @@ void Document::recalcStyle(StyleChange change)
         return; // Guard against re-entrancy. -dwh
         
     m_inStyleRecalc = true;
+    suspendPostAttachCallbacks();
     
     ASSERT(!renderer() || renderArena());
     if (!renderer() || !renderArena())
@@ -1105,6 +1106,7 @@ bail_out:
     setHasChangedChild(false);
     setDocumentChanged(false);
     
+    resumePostAttachCallbacks();
     m_inStyleRecalc = false;
     
     // If we wanted to call implicitClose() during recalcStyle, do so now that we're finished.
index b76c2a900c4735b2bf7eb63b01ac256f28302ab8..ad21775a0a9c4af6f5b4fac09a833ff58dfc7c46 100644 (file)
@@ -45,6 +45,7 @@ using namespace HTMLNames;
 
 HTMLEmbedElement::HTMLEmbedElement(Document* doc)
     : HTMLPlugInElement(embedTag, doc)
+    , m_needWidgetUpdate(false)
 {
 }
 
@@ -153,10 +154,9 @@ RenderObject *HTMLEmbedElement::createRenderer(RenderArena *arena, RenderStyle *
 
 void HTMLEmbedElement::attach()
 {
+    m_needWidgetUpdate = true;
+    queuePostAttachCallback(&HTMLPlugInElement::updateWidgetCallback, this);
     HTMLPlugInElement::attach();
-
-    if (renderer())
-        static_cast<RenderPartObject*>(renderer())->updateWidget(true);
 }
 
 void HTMLEmbedElement::detach()
@@ -167,6 +167,12 @@ void HTMLEmbedElement::detach()
     HTMLPlugInElement::detach();
 }
 
+void HTMLEmbedElement::updateWidget()
+{
+    if (m_needWidgetUpdate && renderer())
+        static_cast<RenderPartObject*>(renderer())->updateWidget(true);
+}
+
 void HTMLEmbedElement::insertedIntoDocument()
 {
     if (document()->isHTMLDocument()) {
index 5fdef30737ad37d020086b22089ef8e26f698c32..5e2e42c4875acec12825a5f7df90039659dcb97c 100644 (file)
@@ -56,6 +56,9 @@ public:
     
     virtual bool isURLAttribute(Attribute*) const;
 
+    virtual void updateWidget();
+    void setNeedWidgetUpdate(bool needWidgetUpdate) { m_needWidgetUpdate = needWidgetUpdate; }
+
 #if USE(JAVASCRIPTCORE_BINDINGS)
     virtual KJS::Bindings::Instance* getInstance() const;
 #endif
@@ -73,6 +76,7 @@ public:
     DeprecatedString url;
     String m_pluginPage;
     String m_serviceType;
+    bool m_needWidgetUpdate;
 };
 
 }
index d446389d0de4f2f04d05ac9a8120a83221d2956b..ff2644f2fabb69e045c526eed1b10459ec8236d4 100644 (file)
@@ -165,31 +165,30 @@ RenderObject *HTMLObjectElement::createRenderer(RenderArena* arena, RenderStyle*
 
 void HTMLObjectElement::attach()
 {
+    bool isImage = isImageType();
+
+    if (!isImage)
+        queuePostAttachCallback(&HTMLPlugInElement::updateWidgetCallback, this);
+
     HTMLPlugInElement::attach();
 
-    if (renderer() && !m_useFallbackContent) {
-        if (isImageType()) {
-            if (!m_imageLoader)
-                m_imageLoader.set(new HTMLImageLoader(this));
-            m_imageLoader->updateFromElement();
-            if (renderer()) {
-                RenderImage* imageObj = static_cast<RenderImage*>(renderer());
-                imageObj->setCachedImage(m_imageLoader->image());
-            }
-        } else {
-            if (m_needWidgetUpdate) {
-                // Set m_needWidgetUpdate to false before calling updateWidget because updateWidget may cause
-                // this method or recalcStyle (which also calls updateWidget) to be called.
-                m_needWidgetUpdate = false;
-                static_cast<RenderPartObject*>(renderer())->updateWidget(true);
-            } else {
-                m_needWidgetUpdate = true;
-                setChanged();
-            }
+    if (isImage && renderer() && !m_useFallbackContent) {
+        if (!m_imageLoader)
+            m_imageLoader.set(new HTMLImageLoader(this));
+        m_imageLoader->updateFromElement();
+        if (renderer()) {
+            RenderImage* imageObj = static_cast<RenderImage*>(renderer());
+            imageObj->setCachedImage(m_imageLoader->image());
         }
     }
 }
 
+void HTMLObjectElement::updateWidget()
+{
+    if (m_needWidgetUpdate && renderer() && !m_useFallbackContent && !isImageType())
+        static_cast<RenderPartObject*>(renderer())->updateWidget(true);
+}
+
 void HTMLObjectElement::finishedParsing()
 {
     // The parser just reached </object>.
index 909b8a05a763518bf876f90a6685a5d42b50be75..bc4a029eb48e7e7f8c56c69776c3d062dc0becea 100644 (file)
@@ -57,6 +57,9 @@ public:
     virtual bool isURLAttribute(Attribute*) const;
     virtual const QualifiedName& imageSourceAttributeName() const;
 
+    virtual void updateWidget();
+    void setNeedWidgetUpdate(bool needWidgetUpdate) { m_needWidgetUpdate = needWidgetUpdate; }
+
     bool isImageType();
 
     void renderFallbackContent();
index b31361f8634886d10fb3a47fdeea28eec200016d..d36d571bd09c3295e3932f9a5c44747747c2512e 100644 (file)
@@ -204,4 +204,9 @@ NPObject* HTMLPlugInElement::getNPObject()
 
 #endif /* USE(NPOBJECT) */
 
+void HTMLPlugInElement::updateWidgetCallback(Node* n)
+{
+    static_cast<HTMLPlugInElement*>(n)->updateWidget();
+}
+
 }
index 7ff3d2c9f6ec506794407aa5d4ed5d928bc0ac63..c5017349524c62ced6d45238d9e3852661fe09f9 100644 (file)
@@ -48,6 +48,8 @@ public:
     virtual HTMLTagStatus endTagRequirement() const { return TagStatusRequired; }
     virtual bool checkDTD(const Node* newChild);
 
+    virtual void updateWidget() { }
+
     String align() const;
     void setAlign(const String&);
     
@@ -74,6 +76,8 @@ private:
 #endif
 
 protected:
+    static void updateWidgetCallback(Node*);
+
     String oldNameAttr;
 #if USE(JAVASCRIPTCORE_BINDINGS)
     mutable RefPtr<KJS::Bindings::Instance> m_instance;
index 6575d2f912a6aacc9692661d83694a5996154407..c8aaa3ed686565875e1cdb29d98f2e2b19331c9b 100644 (file)
@@ -120,6 +120,7 @@ void RenderPartObject::updateWidget(bool onlyCreateNonNetscapePlugins)
 
       HTMLObjectElement* o = static_cast<HTMLObjectElement*>(element());
 
+      o->setNeedWidgetUpdate(false);
       if (!o->isComplete())
         return;
       // Check for a child EMBED tag.
@@ -229,6 +230,7 @@ void RenderPartObject::updateWidget(bool onlyCreateNonNetscapePlugins)
           o->renderFallbackContent();
   } else if (element()->hasTagName(embedTag)) {
       HTMLEmbedElement *o = static_cast<HTMLEmbedElement*>(element());
+      o->setNeedWidgetUpdate(false);
       url = o->url;
       serviceType = o->m_serviceType;
 
index 2b1803c19b471f29f39d7d2c1a974ef1c5288842..98de5b9fa656773faec70f4488e4cdc74c5facb4 100644 (file)
@@ -37,7 +37,7 @@ public:
     virtual const char* renderName() const { return "RenderPartObject"; }
 
     virtual void layout();
-    void updateWidget(bool onlyCreateNonPlugins);
+    void updateWidget(bool onlyCreateNonNetscapePlugins);
 
     virtual void viewCleared();
 };
index 79849f2e34de4af831355db4fb66214b1e927e7b..543be902e537fb404ebdd30749f76a75822f760e 100644 (file)
@@ -1,3 +1,16 @@
+2007-11-22  Dan Bernstein  <mitz@apple.com>
+
+        Reviewed by Antti Koivisto.
+
+        - http://bugs.webkit.org/show_bug.cgi?id=15811
+          WebKit plug-ins can re-enter WebKit under attach()
+          <rdar://problem/5577978>
+
+        * Plugins/WebNullPluginView.mm:
+        (-[WebNullPluginView viewDidMoveToWindow]): Removed workaround for the
+        above bug that added as part of fixing
+        <http://bugs.webkit.org/show_bug.cgi?id=15804>.
+
 2007-11-21  Mark Rowe  <mrowe@apple.com>
 
         Reviewed by Eric.
index e173fd721aeccdb5fa5453413cbd47aff941102b..89d71c8ec3ec5a9dd96201fd3264374d670d6dac 100644 (file)
@@ -90,9 +90,8 @@
     if (!error)
         return;
 
-    [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(reportFailure) object:nil];
     if ([self window])
-        [self performSelector:@selector(reportFailure) withObject:nil afterDelay:0.0];
+        [self reportFailure];
 }
 
 @end