[SCM] WebKit Debian packaging branch, webkit-1.1, updated. upstream/1.1.19-706-ge5415e9

dimich at chromium.org dimich at chromium.org
Thu Feb 4 21:28:27 UTC 2010


The following commit has been merged in the webkit-1.1 branch:
commit 4fd60a1b2baf14528f7e61fe9f012a81b14d81eb
Author: dimich at chromium.org <dimich at chromium.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Date:   Wed Jan 27 00:22:37 2010 +0000

    Avoid reloading iframe on re-parenting between documents.
    https://bugs.webkit.org/show_bug.cgi?id=32848
    
    Reviewed by David Levin.
    
    WebCore:
    
    Achieved by setting a flag on iframe element when it is a target of document.adoptNode(node) operation.
    The flag prevents unload/load cycle and is reset once element is attached to a new document.
    If iframe is adopted but not actually inserted into the tree, it gets unloaded by async timer
    once JS yields, to avoid having active content in non-attached iframe.
    
    Test: fast/frames/iframe-reparenting.html
    
    * dom/Document.cpp:
    (WebCore::Document::adoptNode): If the adopted node is iframe, set a remainsAliveOnRemovalFromTree on it.
    * html/HTMLFrameElementBase.h:
    * html/HTMLFrameElementBase.cpp:
    (WebCore::HTMLFrameElementBase::HTMLFrameElementBase):
    (WebCore::HTMLFrameElementBase::attach): Skip actual loading of the frame if it has remainsAliveOnRemovalFromTree flag. Reset the flag.
    (WebCore::HTMLFrameElementBase::willRemove): Skip unloading the frame if it has remainsAliveOnRemovalFromTree flag set.
    (WebCore::HTMLFrameElementBase::setRemainsAliveOnRemovalFromTree): Set the flag, start the async timer to check if the frame was actually attached.
    (WebCore::HTMLFrameElementBase::checkAttachedTimerFired):
    * html/HTMLFrameOwnerElement.h:
    (WebCore::HTMLFrameOwnerElement::willRemove): Move from private to protected, since it is conditionally called in HTMLFrameElementBase::willRemove now.
    
    LayoutTests:
    
    * fast/frames/iframe-reparenting-expected.txt: Added.
    * fast/frames/iframe-reparenting.html: Added.
    * fast/frames/resources/iframe-reparenting-frame1.html: Added.
    * fast/frames/resources/iframe-reparenting-frame2.html: Added.
    * fast/frames/resources/iframe-reparenting-iframe-content.html: Added.
    
    git-svn-id: http://svn.webkit.org/repository/webkit/trunk@53871 268f45cc-cd09-0410-ab3c-d52691b4dbfc

diff --git a/LayoutTests/ChangeLog b/LayoutTests/ChangeLog
index 4e8dea8..44347ff 100644
--- a/LayoutTests/ChangeLog
+++ b/LayoutTests/ChangeLog
@@ -1,3 +1,16 @@
+2010-01-26  Dmitry Titov  <dimich at chromium.org>
+
+        Reviewed by David Levin.
+
+        Avoid reloading iframe on re-parenting between documents.
+        https://bugs.webkit.org/show_bug.cgi?id=32848
+
+        * fast/frames/iframe-reparenting-expected.txt: Added.
+        * fast/frames/iframe-reparenting.html: Added.
+        * fast/frames/resources/iframe-reparenting-frame1.html: Added.
+        * fast/frames/resources/iframe-reparenting-frame2.html: Added.
+        * fast/frames/resources/iframe-reparenting-iframe-content.html: Added.
+
 2010-01-26  Adam Roben  <aroben at apple.com>
 
         No review, rolling out r53861.
diff --git a/LayoutTests/fast/frames/iframe-reparenting-expected.txt b/LayoutTests/fast/frames/iframe-reparenting-expected.txt
new file mode 100644
index 0000000..400a98b
--- /dev/null
+++ b/LayoutTests/fast/frames/iframe-reparenting-expected.txt
@@ -0,0 +1,30 @@
+This test moves the iframe between two documents - once using this sequence:
+
+    document1.body.removeChild(iframe);
+    document2.body.appendChild(iframe);
+
+and then using 'adoptNode':
+
+    document2.adoptNode(iframe);
+    document2.body.appendChild(iframe);
+
+In the second case, the content of iframe should not be re-loaded and 'load' event should not be fired. Also, the timer started before reparenting should survive transition and fire.
+
+Test also verifies that document.adoptNode() in case of not-rendered document (loaded by XMLHttpRequest) does not preserve the content of iframe.
+
+Test succeeds if there are 'PASS' messages below and no 'FAIL' messages.
+
+ 
+PASS: Iframe loaded, verify token, expected: loaded, actual: loaded
+PASS: Iframe token modified, expected: modified-1, actual: modified-1
+Reparent iframe - the content should re-load.
+PASS: iframe is unloaded.
+PASS: Iframe re-loaded, verify token, expected: loaded, actual: loaded
+PASS: Iframe token modified, expected: modified-2, actual: modified-2
+Reparent iframe using adoptNode - the content should not unload.
+PASS: iframe is NOT unloaded.
+PASS: Iframe token should be the same as before reparenting, expected: modified-2, actual: modified-2
+PASS: XHR-loaded Document is correct.
+PASS: iframe is unloaded.
+Test Finished.
+
diff --git a/LayoutTests/fast/frames/iframe-reparenting.html b/LayoutTests/fast/frames/iframe-reparenting.html
new file mode 100755
index 0000000..ec1b5bb
--- /dev/null
+++ b/LayoutTests/fast/frames/iframe-reparenting.html
@@ -0,0 +1,103 @@
+<html>
+<script>
+function log(message)
+{
+    document.getElementById("log").innerText += message + "\n";
+}
+
+function verifyToken(message, expectedToken)
+{
+    var actualToken = iframe.contentWindow.token;
+    log((expectedToken == actualToken ? "PASS" : "FAIL") + ": " + message + ", expected: " + expectedToken + ", actual: " + actualToken);
+}
+
+function test()
+{
+    if (window.layoutTestController) {
+        layoutTestController.dumpAsText();
+        layoutTestController.waitUntilDone();
+    }
+
+    frame1 = document.getElementById("frame1");
+    frame2 = document.getElementById("frame2");
+    iframe = frame1.contentDocument.getElementsByTagName("iframe")[0];
+
+    verifyToken("Iframe loaded, verify token", "loaded");
+    iframe.contentWindow.token = "modified-1";
+    verifyToken("Iframe token modified", "modified-1");
+
+    // Start timeout in iframe - it should not survive reparenting.
+    iframe.contentWindow.startDoomedTimer();
+    log("Reparent iframe - the content should re-load.")
+    frame1.contentDocument.body.removeChild(iframe);
+    // contentWindow should not be available, the iframe is unloaded.
+    log(iframe.contentWindow ? "FAIL: iframe is not unloaded." : "PASS: iframe is unloaded.");
+    frame2.contentDocument.body.appendChild(iframe);
+    iframe.onload = test2;
+}
+
+function test2()
+{
+    verifyToken("Iframe re-loaded, verify token", "loaded");
+    iframe.contentWindow.token = "modified-2";
+    verifyToken("Iframe token modified", "modified-2");
+
+    // Start timeout in iframe - it should survive reparenting and call finish() to end the test.
+    iframe.contentWindow.startFinishTimer();
+    log("Reparent iframe using adoptNode - the content should not unload.")
+    frame1.contentDocument.adoptNode(iframe);
+    frame1.contentDocument.body.appendChild(iframe);
+    // contentWindow should be available, the iframe is not unloaded.
+    log(iframe.contentWindow ? "PASS: iframe is NOT unloaded." : "FAIL: iframe is unloaded.");
+    iframe.onload = notReached;
+}
+
+notReached = function()
+{
+    log("FAIL: iframe should not fire 'load' event when reparented using 'adoptNode'");
+}
+
+finish = function()
+{
+    verifyToken("Iframe token should be the same as before reparenting", "modified-2");
+
+    // Last test - verify that non-attached document does not keep iframe alive even if adoptNode() is used.
+    var xhr = new XMLHttpRequest();
+    xhr.open("GET","data:text/html,<html xmlns='http://www.w3.org/1999/xhtml'><body id='body'>Hello</body></html>", false);
+    xhr.send(null);
+    var doc = xhr.responseXML;
+    log(doc.getElementById("body").innerText == "Hello" ? "PASS: XHR-loaded Document is correct." : "FAIL: XHR-loaded document is not correct.");
+
+    doc.adoptNode(iframe);
+    // contentWindow should not be available, the iframe is unloaded.
+    log(iframe.contentWindow ? "FAIL: iframe is not unloaded." : "PASS: iframe is unloaded.");
+
+    log("Test Finished.");
+
+    if (window.layoutTestController)
+        layoutTestController.notifyDone();
+
+}
+
+</script>
+<body onload=test()>
+<p>This test moves the iframe between two documents - once using this sequence:</p>
+<pre>
+    document1.body.removeChild(iframe);
+    document2.body.appendChild(iframe);
+
+</pre>
+<p>and then using 'adoptNode':</p>
+<pre>
+    document2.adoptNode(iframe);
+    document2.body.appendChild(iframe);
+
+</pre>
+<p>In the second case, the content of iframe should not be re-loaded and 'load' event should not be fired. Also, the timer started before reparenting should survive transition and fire.</p>
+<p>Test also verifies that document.adoptNode() in case of not-rendered document (loaded by XMLHttpRequest) does not preserve the content of iframe.</p>
+<p>Test succeeds if there are 'PASS' messages below and no 'FAIL' messages.</p>
+<iframe id=frame1 src=resources/iframe-reparenting-frame1.html></iframe>
+<iframe id=frame2 src=resources/iframe-reparenting-frame2.html></iframe>
+<pre id=log></pre>
+</body>
+</html>
diff --git a/LayoutTests/fast/frames/resources/iframe-reparenting-frame1.html b/LayoutTests/fast/frames/resources/iframe-reparenting-frame1.html
new file mode 100755
index 0000000..6cc81ef
--- /dev/null
+++ b/LayoutTests/fast/frames/resources/iframe-reparenting-frame1.html
@@ -0,0 +1,2 @@
+<body>
+<iframe src=iframe-reparenting-iframe-content.html></iframe>
diff --git a/LayoutTests/fast/frames/resources/iframe-reparenting-frame2.html b/LayoutTests/fast/frames/resources/iframe-reparenting-frame2.html
new file mode 100755
index 0000000..335eec5
--- /dev/null
+++ b/LayoutTests/fast/frames/resources/iframe-reparenting-frame2.html
@@ -0,0 +1 @@
+<body>
diff --git a/LayoutTests/fast/frames/resources/iframe-reparenting-iframe-content.html b/LayoutTests/fast/frames/resources/iframe-reparenting-iframe-content.html
new file mode 100755
index 0000000..9576789
--- /dev/null
+++ b/LayoutTests/fast/frames/resources/iframe-reparenting-iframe-content.html
@@ -0,0 +1,20 @@
+<script>
+token = "loading";
+
+function init()
+{
+    token = "loaded";
+}
+
+startFinishTimer = function()
+{
+    setTimeout(parent.parent.finish, 0);
+}
+
+startDoomedTimer = function()
+{
+    setTimeout(parent.parent.notReached, 0);
+}
+
+</script>
+<body onload=init()>
diff --git a/WebCore/ChangeLog b/WebCore/ChangeLog
index db61ab1..b0ff96c 100644
--- a/WebCore/ChangeLog
+++ b/WebCore/ChangeLog
@@ -1,3 +1,29 @@
+2010-01-26  Dmitry Titov  <dimich at chromium.org>
+
+        Reviewed by David Levin.
+
+        Avoid reloading iframe on re-parenting between documents.
+        https://bugs.webkit.org/show_bug.cgi?id=32848
+
+        Achieved by setting a flag on iframe element when it is a target of document.adoptNode(node) operation.
+        The flag prevents unload/load cycle and is reset once element is attached to a new document.
+        If iframe is adopted but not actually inserted into the tree, it gets unloaded by async timer
+        once JS yields, to avoid having active content in non-attached iframe.
+
+        Test: fast/frames/iframe-reparenting.html
+
+        * dom/Document.cpp:
+        (WebCore::Document::adoptNode): If the adopted node is iframe, set a remainsAliveOnRemovalFromTree on it.
+        * html/HTMLFrameElementBase.h:
+        * html/HTMLFrameElementBase.cpp:
+        (WebCore::HTMLFrameElementBase::HTMLFrameElementBase):
+        (WebCore::HTMLFrameElementBase::attach): Skip actual loading of the frame if it has remainsAliveOnRemovalFromTree flag. Reset the flag.
+        (WebCore::HTMLFrameElementBase::willRemove): Skip unloading the frame if it has remainsAliveOnRemovalFromTree flag set.
+        (WebCore::HTMLFrameElementBase::setRemainsAliveOnRemovalFromTree): Set the flag, start the async timer to check if the frame was actually attached.
+        (WebCore::HTMLFrameElementBase::checkAttachedTimerFired):
+        * html/HTMLFrameOwnerElement.h:
+        (WebCore::HTMLFrameOwnerElement::willRemove): Move from private to protected, since it is conditionally called in HTMLFrameElementBase::willRemove now.
+
 2010-01-26  Adam Roben  <aroben at apple.com>
 
         No review, rolling out r53861.
@@ -116,7 +142,7 @@
         * WebCore.vcproj/QTMovieWin.vcproj:
         * WebCore.vcproj/WebCoreCommon.vsprops:
 
-2010-01-25  Darin Fisher  <darin at chromium.org>
+2010-01-26  Darin Fisher  <darin at chromium.org>
 
         Reviewed by Brady Eidson.
 
diff --git a/WebCore/dom/Document.cpp b/WebCore/dom/Document.cpp
index af456b4..571210d 100644
--- a/WebCore/dom/Document.cpp
+++ b/WebCore/dom/Document.cpp
@@ -69,6 +69,7 @@
 #include "HTMLElementFactory.h"
 #include "HTMLFrameOwnerElement.h"
 #include "HTMLHeadElement.h"
+#include "HTMLIFrameElement.h"
 #include "HTMLInputElement.h"
 #include "HTMLLinkElement.h"
 #include "HTMLMapElement.h"
@@ -796,6 +797,9 @@ PassRefPtr<Node> Document::adoptNode(PassRefPtr<Node> source, ExceptionCode& ec)
             break;
         }       
         default:
+            if (source->hasTagName(iframeTag))
+                static_cast<HTMLIFrameElement*>(source.get())->setRemainsAliveOnRemovalFromTree(attached());
+
             if (source->parentNode())
                 source->parentNode()->removeChild(source.get(), ec);
     }
diff --git a/WebCore/html/HTMLFrameElementBase.cpp b/WebCore/html/HTMLFrameElementBase.cpp
index 9551b6e..3890850 100644
--- a/WebCore/html/HTMLFrameElementBase.cpp
+++ b/WebCore/html/HTMLFrameElementBase.cpp
@@ -50,8 +50,10 @@ HTMLFrameElementBase::HTMLFrameElementBase(const QualifiedName& tagName, Documen
     , m_scrolling(ScrollbarAuto)
     , m_marginWidth(-1)
     , m_marginHeight(-1)
+    , m_checkAttachedTimer(this, &HTMLFrameElementBase::checkAttachedTimerFired)
     , m_viewSource(false)
     , m_shouldOpenURLAfterAttach(false)
+    , m_remainsAliveOnRemovalFromTree(false)
 {
 }
 
@@ -186,9 +188,12 @@ void HTMLFrameElementBase::attach()
 {
     if (m_shouldOpenURLAfterAttach) {
         m_shouldOpenURLAfterAttach = false;
-        queuePostAttachCallback(&HTMLFrameElementBase::setNameAndOpenURLCallback, this);
+        if (!m_remainsAliveOnRemovalFromTree)
+            queuePostAttachCallback(&HTMLFrameElementBase::setNameAndOpenURLCallback, this);
     }
 
+    setRemainsAliveOnRemovalFromTree(false);
+
     HTMLFrameOwnerElement::attach();
     
     if (RenderPart* renderPart = toRenderPart(renderer())) {
@@ -249,4 +254,33 @@ int HTMLFrameElementBase::height() const
     return toRenderBox(renderer())->height();
 }
 
+void HTMLFrameElementBase::setRemainsAliveOnRemovalFromTree(bool value)
+{
+    m_remainsAliveOnRemovalFromTree = value;
+
+    // There is a possibility that JS will do document.adoptNode() on this element but will not insert it into the tree.
+    // Start the async timer that is normally stopped by attach(). If it's not stopped and fires, it'll unload the frame.
+    if (value)
+        m_checkAttachedTimer.startOneShot(0);
+    else
+        m_checkAttachedTimer.stop();
+}
+
+void HTMLFrameElementBase::checkAttachedTimerFired(Timer<HTMLFrameElementBase>*)
+{
+    ASSERT(!attached());
+    ASSERT(m_remainsAliveOnRemovalFromTree);
+
+    m_remainsAliveOnRemovalFromTree = false;
+    willRemove();
+}
+
+void HTMLFrameElementBase::willRemove()
+{
+    if (m_remainsAliveOnRemovalFromTree)
+        return;
+
+    HTMLFrameOwnerElement::willRemove();
+}
+
 } // namespace WebCore
diff --git a/WebCore/html/HTMLFrameElementBase.h b/WebCore/html/HTMLFrameElementBase.h
index c211ba7..ea93ae7 100644
--- a/WebCore/html/HTMLFrameElementBase.h
+++ b/WebCore/html/HTMLFrameElementBase.h
@@ -42,6 +42,8 @@ public:
     int width() const;
     int height() const;
 
+    void setRemainsAliveOnRemovalFromTree(bool);
+
 protected:
     HTMLFrameElementBase(const QualifiedName&, Document*);
 
@@ -62,6 +64,9 @@ private:
     
     virtual bool isURLAttribute(Attribute*) const;
 
+    virtual void willRemove();
+    void checkAttachedTimerFired(Timer<HTMLFrameElementBase>*);
+
     bool viewSourceMode() const { return m_viewSource; }
 
     void setNameAndOpenURL();
@@ -77,9 +82,13 @@ private:
     int m_marginWidth;
     int m_marginHeight;
 
+    Timer<HTMLFrameElementBase> m_checkAttachedTimer;
+
     bool m_viewSource;
 
     bool m_shouldOpenURLAfterAttach;
+
+    bool m_remainsAliveOnRemovalFromTree;
 };
 
 } // namespace WebCore
diff --git a/WebCore/html/HTMLFrameOwnerElement.h b/WebCore/html/HTMLFrameOwnerElement.h
index 308a100..4a56e45 100644
--- a/WebCore/html/HTMLFrameOwnerElement.h
+++ b/WebCore/html/HTMLFrameOwnerElement.h
@@ -48,19 +48,19 @@ public:
     virtual ScrollbarMode scrollingMode() const { return ScrollbarAuto; }
 
     SandboxFlags sandboxFlags() const { return m_sandboxFlags; }
-    
+
 protected:
     HTMLFrameOwnerElement(const QualifiedName& tagName, Document*);
 
     void setSandboxFlags(SandboxFlags);
-    
+
+    virtual void willRemove();
+
 private:
     friend class Frame;
 
     virtual bool isFrameOwnerElement() const { return true; }
     virtual bool isKeyboardFocusable(KeyboardEvent*) const { return m_contentFrame; }
-    
-    virtual void willRemove();
 
     Frame* m_contentFrame;
     SandboxFlags m_sandboxFlags;

-- 
WebKit Debian packaging



More information about the Pkg-webkit-commits mailing list