[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