:hover style not applied on hover if its display property is different from original...
authorcommit-queue@webkit.org <commit-queue@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 6 Jun 2013 17:18:09 +0000 (17:18 +0000)
committercommit-queue@webkit.org <commit-queue@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 6 Jun 2013 17:18:09 +0000 (17:18 +0000)
https://bugs.webkit.org/show_bug.cgi?id=7555

Source/WebCore:

Properly apply the :hover pseudo-class when reattaching is required (e.g. when changing the display type)

A new AttachContext class was created to be passed along as an optional parameter to the attach/detach/reattach methods.
This new parameter is used to:
    - prevent the element from being removed from the list of hovered/active elements upon detach when a reattach is in progress
    - prevent the style from being incorrectly computed (due to the previous point)
    - prevent the style from being computed twice (the attach() method used to recompute it)

Special care was required to the case when display:none is specified in the :hover class. Enabling the :hover style
was leaving the element without a renderer, which was causing it to remain stuck in the :hover state (subsequent mouseMove
events were not able to reset the element to its normal style due to the fact that it had no renderer).

The DragController::startDrag method was updated to properly handle the case when dragImage is NULL
(for instance by setting display:none inside the -webkit-drag pseudo-class).

Patch by Radu Stavila <stavila@adobe.com> on 2013-06-06
Reviewed by Antti Koivisto.

Tests: fast/regions/hover-display-block-inline.html
       fast/regions/hover-display-block-none.html

* page/DragController.cpp:
(WebCore::DragController::startDrag):
* dom/ContainerNode.cpp:
(WebCore::ContainerNode::attach):
(WebCore::ContainerNode::detach):
* dom/ContainerNode.h:
* dom/Document.cpp:
(WebCore::Document::attach):
(WebCore::Document::detach):
(WebCore::Document::updateHoverActiveState):
* dom/Document.h:
* dom/Element.cpp:
(WebCore::Element::setHovered):
(WebCore::Element::createRendererIfNeeded):
(WebCore::Element::attach):
(WebCore::Element::detach):
(WebCore::Element::recalcStyle):
* dom/Element.h:
* dom/Node.cpp:
(WebCore::Node::AttachDetachContext::AttachDetachContext):
(WebCore::Node::AttachDetachContext::~AttachDetachContext):
(WebCore::Node::attach):
(WebCore::Node::detach):
* dom/Node.h:
(WebCore::Node::reattach):
(WebCore::Node::reattachIfAttached):
* dom/NodeRenderingContext.cpp:
(WebCore::NodeRenderingContext::NodeRenderingContext):
* dom/PseudoElement.cpp:
(WebCore::PseudoElement::attach):
* dom/PseudoElement.h:
* dom/ShadowRoot.cpp:
(WebCore::ShadowRoot::attach):
* dom/ShadowRoot.h:
* dom/Text.cpp:
(WebCore::Text::attach):
* dom/Text.h:
* html/HTMLCanvasElement.cpp:
(WebCore::HTMLCanvasElement::attach):
* html/HTMLCanvasElement.h:
* html/HTMLFormControlElement.cpp:
(WebCore::HTMLFormControlElement::attach):
* html/HTMLFormControlElement.h:
* html/HTMLFrameElement.cpp:
(WebCore::HTMLFrameElement::attach):
* html/HTMLFrameElement.h:
* html/HTMLFrameElementBase.cpp:
(WebCore::HTMLFrameElementBase::attach):
* html/HTMLFrameElementBase.h:
* html/HTMLFrameSetElement.cpp:
(WebCore::HTMLFrameSetElement::attach):
* html/HTMLFrameSetElement.h:
* html/HTMLImageElement.cpp:
(WebCore::HTMLImageElement::attach):
* html/HTMLImageElement.h:
* html/HTMLInputElement.cpp:
(WebCore::HTMLInputElement::attach):
(WebCore::HTMLInputElement::detach):
* html/HTMLInputElement.h:
* html/HTMLLIElement.cpp:
(WebCore::HTMLLIElement::attach):
* html/HTMLLIElement.h:
* html/HTMLMediaElement.cpp:
(WebCore::HTMLMediaElement::attach):
* html/HTMLMediaElement.h:
* html/HTMLOptGroupElement.cpp:
(WebCore::HTMLOptGroupElement::attach):
(WebCore::HTMLOptGroupElement::detach):
* html/HTMLOptGroupElement.h:
* html/HTMLOptionElement.cpp:
(WebCore::HTMLOptionElement::attach):
(WebCore::HTMLOptionElement::detach):
* html/HTMLOptionElement.h:
* html/HTMLPlugInElement.cpp:
(WebCore::HTMLPlugInElement::detach):
* html/HTMLPlugInElement.h:
* html/HTMLPlugInImageElement.cpp:
(WebCore::HTMLPlugInImageElement::attach):
(WebCore::HTMLPlugInImageElement::detach):
* html/HTMLPlugInImageElement.h:
* html/HTMLProgressElement.cpp:
(WebCore::HTMLProgressElement::attach):
* html/HTMLProgressElement.h:
* html/HTMLTextAreaElement.cpp:
(WebCore::HTMLTextAreaElement::attach):
* html/HTMLTextAreaElement.h:
* html/HTMLVideoElement.cpp:
(WebCore::HTMLVideoElement::attach):
* html/HTMLVideoElement.h:
* html/PluginDocument.cpp:
(WebCore::PluginDocument::detach):
* html/PluginDocument.h:
* html/shadow/InsertionPoint.cpp:
(WebCore::InsertionPoint::attach):
(WebCore::InsertionPoint::detach):
* html/shadow/InsertionPoint.h:
* html/shadow/SliderThumbElement.cpp:
(WebCore::SliderThumbElement::detach):
* html/shadow/SliderThumbElement.h:
* html/shadow/SpinButtonElement.cpp:
(WebCore::SpinButtonElement::detach):
* html/shadow/SpinButtonElement.h:
* html/shadow/TextControlInnerElements.cpp:
(WebCore::SearchFieldCancelButtonElement::detach):
(WebCore::InputFieldSpeechButtonElement::attach):
(WebCore::InputFieldSpeechButtonElement::detach):
* html/shadow/TextControlInnerElements.h:
* loader/PlaceholderDocument.cpp:
(WebCore::PlaceholderDocument::attach):
* loader/PlaceholderDocument.h:
* svg/SVGImageElement.cpp:
(WebCore::SVGImageElement::attach):
* svg/SVGImageElement.h:

LayoutTests:

Patch by Radu Stavila <stavila@adobe.com> on 2013-06-06
Reviewed by Antti Koivisto.

* fast/regions/hover-display-block-inline-expected.txt: Added.
* fast/regions/hover-display-block-inline.html: Added.
* fast/regions/hover-display-block-none-expected.txt: Added.
* fast/regions/hover-display-block-none.html: Added.
* fast/events/drag-display-none-element-expected.txt:
* fast/events/drag-display-none-element:

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

71 files changed:
LayoutTests/ChangeLog
LayoutTests/fast/events/drag-display-none-element-expected.txt
LayoutTests/fast/events/drag-display-none-element.html
LayoutTests/fast/regions/hover-display-block-inline-expected.txt [new file with mode: 0644]
LayoutTests/fast/regions/hover-display-block-inline.html [new file with mode: 0644]
LayoutTests/fast/regions/hover-display-block-none-expected.txt [new file with mode: 0644]
LayoutTests/fast/regions/hover-display-block-none.html [new file with mode: 0644]
Source/WebCore/ChangeLog
Source/WebCore/dom/ContainerNode.cpp
Source/WebCore/dom/ContainerNode.h
Source/WebCore/dom/Document.cpp
Source/WebCore/dom/Document.h
Source/WebCore/dom/Element.cpp
Source/WebCore/dom/Element.h
Source/WebCore/dom/Node.cpp
Source/WebCore/dom/Node.h
Source/WebCore/dom/NodeRenderingContext.cpp
Source/WebCore/dom/NodeRenderingContext.h
Source/WebCore/dom/PseudoElement.cpp
Source/WebCore/dom/PseudoElement.h
Source/WebCore/dom/ShadowRoot.cpp
Source/WebCore/dom/ShadowRoot.h
Source/WebCore/dom/Text.cpp
Source/WebCore/dom/Text.h
Source/WebCore/html/HTMLCanvasElement.cpp
Source/WebCore/html/HTMLCanvasElement.h
Source/WebCore/html/HTMLFormControlElement.cpp
Source/WebCore/html/HTMLFormControlElement.h
Source/WebCore/html/HTMLFrameElement.cpp
Source/WebCore/html/HTMLFrameElement.h
Source/WebCore/html/HTMLFrameElementBase.cpp
Source/WebCore/html/HTMLFrameElementBase.h
Source/WebCore/html/HTMLFrameSetElement.cpp
Source/WebCore/html/HTMLFrameSetElement.h
Source/WebCore/html/HTMLImageElement.cpp
Source/WebCore/html/HTMLImageElement.h
Source/WebCore/html/HTMLInputElement.cpp
Source/WebCore/html/HTMLInputElement.h
Source/WebCore/html/HTMLLIElement.cpp
Source/WebCore/html/HTMLLIElement.h
Source/WebCore/html/HTMLMediaElement.cpp
Source/WebCore/html/HTMLMediaElement.h
Source/WebCore/html/HTMLOptGroupElement.cpp
Source/WebCore/html/HTMLOptGroupElement.h
Source/WebCore/html/HTMLOptionElement.cpp
Source/WebCore/html/HTMLOptionElement.h
Source/WebCore/html/HTMLPlugInElement.cpp
Source/WebCore/html/HTMLPlugInElement.h
Source/WebCore/html/HTMLPlugInImageElement.cpp
Source/WebCore/html/HTMLPlugInImageElement.h
Source/WebCore/html/HTMLProgressElement.cpp
Source/WebCore/html/HTMLProgressElement.h
Source/WebCore/html/HTMLTextAreaElement.cpp
Source/WebCore/html/HTMLTextAreaElement.h
Source/WebCore/html/HTMLVideoElement.cpp
Source/WebCore/html/HTMLVideoElement.h
Source/WebCore/html/PluginDocument.cpp
Source/WebCore/html/PluginDocument.h
Source/WebCore/html/shadow/InsertionPoint.cpp
Source/WebCore/html/shadow/InsertionPoint.h
Source/WebCore/html/shadow/SliderThumbElement.cpp
Source/WebCore/html/shadow/SliderThumbElement.h
Source/WebCore/html/shadow/SpinButtonElement.cpp
Source/WebCore/html/shadow/SpinButtonElement.h
Source/WebCore/html/shadow/TextControlInnerElements.cpp
Source/WebCore/html/shadow/TextControlInnerElements.h
Source/WebCore/loader/PlaceholderDocument.cpp
Source/WebCore/loader/PlaceholderDocument.h
Source/WebCore/page/DragController.cpp
Source/WebCore/svg/SVGImageElement.cpp
Source/WebCore/svg/SVGImageElement.h

index 3c3001a..b1d88f5 100644 (file)
@@ -1,3 +1,17 @@
+2013-06-06  Radu Stavila  <stavila@adobe.com>
+
+        :hover style not applied on hover if its display property is different from original style's
+        https://bugs.webkit.org/show_bug.cgi?id=7555
+
+        Reviewed by Antti Koivisto.
+
+        * fast/regions/hover-display-block-inline-expected.txt: Added.
+        * fast/regions/hover-display-block-inline.html: Added.
+        * fast/regions/hover-display-block-none-expected.txt: Added.
+        * fast/regions/hover-display-block-none.html: Added.
+        * fast/events/drag-display-none-element-expected.txt:
+        * fast/events/drag-display-none-element:
+
 2013-06-06  Mihnea Ovidenie  <mihnea@adobe.com>
 
         [CSSRegions] Make positioned-object-inline-cb-crash.html output readable in browser
index 2524b6d..7ef22e9 100644 (file)
@@ -1,2 +1 @@
-To test, try dragging this div around. It shouldn't crash, and PASS should appear below when you end the drag.
 PASS
index 41b5444..e24503c 100644 (file)
@@ -15,6 +15,7 @@ function runTest()
         if (window.testRunner)
             testRunner.notifyDone();
         document.getElementById('console').appendChild(document.createTextNode('PASS'));
+        dragme.style.display = "none";
     });
 
     if (!window.testRunner)
@@ -33,7 +34,7 @@ window.addEventListener('load', runTest);
 </script>
 </head>
 <body>
-<div id="dragme" draggable="true">To test, try dragging this div around. It shouldn't crash, and PASS should appear below when you end the drag.</div>
+<div id="dragme" draggable="true">To test, try dragging this div around. It shouldn't crash, the div should disappear and PASS should appear.</div>
 <div id="console"></div>
 </body>
 </html>
diff --git a/LayoutTests/fast/regions/hover-display-block-inline-expected.txt b/LayoutTests/fast/regions/hover-display-block-inline-expected.txt
new file mode 100644 (file)
index 0000000..b67e6dd
--- /dev/null
@@ -0,0 +1,2 @@
+PASS Setting display to inline on hover processed OK.
+
diff --git a/LayoutTests/fast/regions/hover-display-block-inline.html b/LayoutTests/fast/regions/hover-display-block-inline.html
new file mode 100644 (file)
index 0000000..a252ef0
--- /dev/null
@@ -0,0 +1,77 @@
+<!doctype html>
+<html lang="en">
+<head>
+       <title>Switch between display block and inline on :hover</title>
+       <style>
+               .box {
+                       width: 100px;
+                       height: 100px;
+               }
+               #dummy {
+                       background-color: black;
+               }
+               #hoverTest {
+                       border: 5px solid green;
+                       border-left: 100px solid green;
+                       color: black;
+                       display: block;
+               }
+               #hoverTest:hover {
+                       border-color: darkred;
+                       display: inline;
+               }
+               #after_hoverTest {
+                       background-color: blue;
+                       color: white;
+                       padding: 10px;
+               }
+       </style>
+
+       <script src="../js/resources/js-test-pre.js"></script>
+</head>
+
+<script type="text/javascript">
+       if (window.testRunner)
+               testRunner.waitUntilDone();
+
+       function beginTest() {
+               if (window.eventSender) {
+                       var hoverTest  = document.querySelector("#hoverTest");
+
+                       // move mouse on the hover test object
+                       eventSender.mouseMoveTo(hoverTest.offsetLeft + 50, hoverTest.offsetTop + 10);
+                       eventSender.mouseDown(0);
+
+                       setTimeout(release, 0);
+               }
+       }
+
+       function release() {
+               if (window.eventSender) {
+                       var hoverTest  = document.querySelector("#hoverTest");
+                       var displayMode = window.getComputedStyle(hoverTest).getPropertyValue("display");
+
+                       if (displayMode == "inline")
+                               testPassed("Setting display to inline on hover processed OK.");
+                       else
+                               testFailed("Setting display to inline on hover FAILED." + " (expected 'inline', got '" + displayMode + "')");
+
+                       var elementsToHide = document.querySelectorAll(".box");
+                       for (var i=0; i<elementsToHide.length; i++)
+                               elementsToHide[i].style.visibility = "hidden";
+
+               eventSender.mouseUp(0);
+
+               if (window.testRunner)
+                               setTimeout("testRunner.notifyDone()", 0);
+               }
+       }
+
+</script>
+
+<body onload="beginTest()">
+       <div id="dummy" class="box"></div>
+       <div id="hoverTest" class="box">When hovered, this box's display will switch from <b>block</b> to <b>inline</b></div>
+       <div id="after_hoverTest" class="box">This is here to show the layout being recomputed</div>
+</body>
+</html>
\ No newline at end of file
diff --git a/LayoutTests/fast/regions/hover-display-block-none-expected.txt b/LayoutTests/fast/regions/hover-display-block-none-expected.txt
new file mode 100644 (file)
index 0000000..fbb3e2f
--- /dev/null
@@ -0,0 +1,2 @@
+PASS Setting display to none on hover processed OK.
+
diff --git a/LayoutTests/fast/regions/hover-display-block-none.html b/LayoutTests/fast/regions/hover-display-block-none.html
new file mode 100644 (file)
index 0000000..a1df7b3
--- /dev/null
@@ -0,0 +1,75 @@
+<!doctype html>
+<html lang="en">
+<head>
+       <title>Switch between display block and none on :hover</title>
+       <style>
+               .box {
+                       width: 100px;
+                       height: 100px;
+               }
+               #dummy {
+                       background-color: black;
+               }
+               #hoverTest {
+                       border: 5px solid green;
+                       border-left: 100px solid green;
+                       color: black;
+                       display: block;
+                       width: 230px;
+               }
+               #hoverTest:hover {
+                       border-color: darkred;
+                       display: none;
+               }
+               #after_hoverTest {
+                       background-color: blue;
+                       color: white;
+                       padding: 10px;
+               }
+       </style>
+
+       <script src="../js/resources/js-test-pre.js"></script>
+</head>
+
+<script type="text/javascript">
+       if (window.testRunner)
+               testRunner.waitUntilDone();
+
+       function beginTest() {
+               if (window.eventSender) {
+                       var hoverTest  = document.querySelector("#hoverTest");
+
+                       // move mouse on the hover test object
+                       eventSender.mouseMoveTo(hoverTest.offsetLeft + 50, hoverTest.offsetTop + 10);
+
+                       setTimeout(release, 0);
+               }
+       }
+
+       function release() {
+               if (window.eventSender) {
+                       var hoverTest  = document.querySelector("#hoverTest");
+                       var displayMode = window.getComputedStyle(hoverTest).getPropertyValue("display");
+
+                       if (displayMode == "none")
+                               testPassed("Setting display to none on hover processed OK.");
+                       else
+                               testFailed("Setting display to none on hover FAILED." + " (expected 'none', got '" + displayMode + "')");
+
+                       var elementsToHide = document.querySelectorAll(".box");
+                       for (var i=0; i<elementsToHide.length; i++)
+                               elementsToHide[i].style.visibility = "hidden";
+
+                       if (window.testRunner)
+                               setTimeout("testRunner.notifyDone()", 0);
+               }
+       }
+
+</script>
+
+<body onload="beginTest()">
+       <div id="dummy" class="box"></div>
+       <div id="hoverTest" class="box">When hovered, this box's display will switch from <b>block</b> to <b>none</b> (click on it and keep the mouse button pushed to avoid flicker and get a more clear view)</div>
+       <div id="after_hoverTest" class="box">This is here to show the layout being recomputed</div>
+</body>
+</html>
\ No newline at end of file
index 26ce7af..3ec1127 100644 (file)
@@ -1,3 +1,142 @@
+2013-06-06  Radu Stavila  <stavila@adobe.com>
+
+        :hover style not applied on hover if its display property is different from original style's
+        https://bugs.webkit.org/show_bug.cgi?id=7555
+
+        Properly apply the :hover pseudo-class when reattaching is required (e.g. when changing the display type)
+
+        A new AttachContext class was created to be passed along as an optional parameter to the attach/detach/reattach methods.
+        This new parameter is used to:
+            - prevent the element from being removed from the list of hovered/active elements upon detach when a reattach is in progress
+            - prevent the style from being incorrectly computed (due to the previous point)
+            - prevent the style from being computed twice (the attach() method used to recompute it)
+
+        Special care was required to the case when display:none is specified in the :hover class. Enabling the :hover style
+        was leaving the element without a renderer, which was causing it to remain stuck in the :hover state (subsequent mouseMove
+        events were not able to reset the element to its normal style due to the fact that it had no renderer).
+
+        The DragController::startDrag method was updated to properly handle the case when dragImage is NULL 
+        (for instance by setting display:none inside the -webkit-drag pseudo-class).
+
+        Reviewed by Antti Koivisto.
+
+        Tests: fast/regions/hover-display-block-inline.html
+               fast/regions/hover-display-block-none.html
+
+        * page/DragController.cpp:
+        (WebCore::DragController::startDrag):
+        * dom/ContainerNode.cpp:
+        (WebCore::ContainerNode::attach):
+        (WebCore::ContainerNode::detach):
+        * dom/ContainerNode.h:
+        * dom/Document.cpp:
+        (WebCore::Document::attach):
+        (WebCore::Document::detach):
+        (WebCore::Document::updateHoverActiveState):
+        * dom/Document.h:
+        * dom/Element.cpp:
+        (WebCore::Element::setHovered):
+        (WebCore::Element::createRendererIfNeeded):
+        (WebCore::Element::attach):
+        (WebCore::Element::detach):
+        (WebCore::Element::recalcStyle):
+        * dom/Element.h:
+        * dom/Node.cpp:
+        (WebCore::Node::AttachDetachContext::AttachDetachContext):
+        (WebCore::Node::AttachDetachContext::~AttachDetachContext):
+        (WebCore::Node::attach):
+        (WebCore::Node::detach):
+        * dom/Node.h:
+        (WebCore::Node::reattach):
+        (WebCore::Node::reattachIfAttached):
+        * dom/NodeRenderingContext.cpp:
+        (WebCore::NodeRenderingContext::NodeRenderingContext):
+        * dom/PseudoElement.cpp:
+        (WebCore::PseudoElement::attach):
+        * dom/PseudoElement.h:
+        * dom/ShadowRoot.cpp:
+        (WebCore::ShadowRoot::attach):
+        * dom/ShadowRoot.h:
+        * dom/Text.cpp:
+        (WebCore::Text::attach):
+        * dom/Text.h:
+        * html/HTMLCanvasElement.cpp:
+        (WebCore::HTMLCanvasElement::attach):
+        * html/HTMLCanvasElement.h:
+        * html/HTMLFormControlElement.cpp:
+        (WebCore::HTMLFormControlElement::attach):
+        * html/HTMLFormControlElement.h:
+        * html/HTMLFrameElement.cpp:
+        (WebCore::HTMLFrameElement::attach):
+        * html/HTMLFrameElement.h:
+        * html/HTMLFrameElementBase.cpp:
+        (WebCore::HTMLFrameElementBase::attach):
+        * html/HTMLFrameElementBase.h:
+        * html/HTMLFrameSetElement.cpp:
+        (WebCore::HTMLFrameSetElement::attach):
+        * html/HTMLFrameSetElement.h:
+        * html/HTMLImageElement.cpp:
+        (WebCore::HTMLImageElement::attach):
+        * html/HTMLImageElement.h:
+        * html/HTMLInputElement.cpp:
+        (WebCore::HTMLInputElement::attach):
+        (WebCore::HTMLInputElement::detach):
+        * html/HTMLInputElement.h:
+        * html/HTMLLIElement.cpp:
+        (WebCore::HTMLLIElement::attach):
+        * html/HTMLLIElement.h:
+        * html/HTMLMediaElement.cpp:
+        (WebCore::HTMLMediaElement::attach):
+        * html/HTMLMediaElement.h:
+        * html/HTMLOptGroupElement.cpp:
+        (WebCore::HTMLOptGroupElement::attach):
+        (WebCore::HTMLOptGroupElement::detach):
+        * html/HTMLOptGroupElement.h:
+        * html/HTMLOptionElement.cpp:
+        (WebCore::HTMLOptionElement::attach):
+        (WebCore::HTMLOptionElement::detach):
+        * html/HTMLOptionElement.h:
+        * html/HTMLPlugInElement.cpp:
+        (WebCore::HTMLPlugInElement::detach):
+        * html/HTMLPlugInElement.h:
+        * html/HTMLPlugInImageElement.cpp:
+        (WebCore::HTMLPlugInImageElement::attach):
+        (WebCore::HTMLPlugInImageElement::detach):
+        * html/HTMLPlugInImageElement.h:
+        * html/HTMLProgressElement.cpp:
+        (WebCore::HTMLProgressElement::attach):
+        * html/HTMLProgressElement.h:
+        * html/HTMLTextAreaElement.cpp:
+        (WebCore::HTMLTextAreaElement::attach):
+        * html/HTMLTextAreaElement.h:
+        * html/HTMLVideoElement.cpp:
+        (WebCore::HTMLVideoElement::attach):
+        * html/HTMLVideoElement.h:
+        * html/PluginDocument.cpp:
+        (WebCore::PluginDocument::detach):
+        * html/PluginDocument.h:
+        * html/shadow/InsertionPoint.cpp:
+        (WebCore::InsertionPoint::attach):
+        (WebCore::InsertionPoint::detach):
+        * html/shadow/InsertionPoint.h:
+        * html/shadow/SliderThumbElement.cpp:
+        (WebCore::SliderThumbElement::detach):
+        * html/shadow/SliderThumbElement.h:
+        * html/shadow/SpinButtonElement.cpp:
+        (WebCore::SpinButtonElement::detach):
+        * html/shadow/SpinButtonElement.h:
+        * html/shadow/TextControlInnerElements.cpp:
+        (WebCore::SearchFieldCancelButtonElement::detach):
+        (WebCore::InputFieldSpeechButtonElement::attach):
+        (WebCore::InputFieldSpeechButtonElement::detach):
+        * html/shadow/TextControlInnerElements.h:
+        * loader/PlaceholderDocument.cpp:
+        (WebCore::PlaceholderDocument::attach):
+        * loader/PlaceholderDocument.h:
+        * svg/SVGImageElement.cpp:
+        (WebCore::SVGImageElement::attach):
+        * svg/SVGImageElement.h:
+
 2013-06-06  Allan Sandfeld Jensen  <allan.jensen@digia.com>
 
         ENABLE(PAN_SCROLLING) AutoscrollController::updateAutoscrollRenderer calls hitTestResultAtPoint with `true` for HitTestRequestType
index 4b3fe1c..212623c 100644 (file)
@@ -787,17 +787,17 @@ void ContainerNode::scheduleSetNeedsStyleRecalc(StyleChangeType changeType)
         setNeedsStyleRecalc(changeType);
 }
 
-void ContainerNode::attach()
+void ContainerNode::attach(const AttachContext& context)
 {
     attachChildren();
-    Node::attach();
+    Node::attach(context);
 }
 
-void ContainerNode::detach()
+void ContainerNode::detach(const AttachContext& context)
 {
     detachChildren();
     clearChildNeedsStyleRecalc();
-    Node::detach();
+    Node::detach(context);
 }
 
 void ContainerNode::childrenChanged(bool changedByParser, Node*, Node*, int childCountDelta)
index 1f92c1c..70517f3 100644 (file)
@@ -106,8 +106,8 @@ public:
 
     void cloneChildNodes(ContainerNode* clone);
 
-    virtual void attach() OVERRIDE;
-    virtual void detach() OVERRIDE;
+    virtual void attach(const AttachContext& = AttachContext()) OVERRIDE;
+    virtual void detach(const AttachContext& = AttachContext()) OVERRIDE;
     virtual LayoutRect boundingBox() const OVERRIDE;
     virtual void scheduleSetNeedsStyleRecalc(StyleChangeType = FullStyleChange) OVERRIDE FINAL;
 
index cb0841c..95c5e99 100644 (file)
@@ -2038,7 +2038,7 @@ void Document::clearStyleResolver()
     m_styleResolver.clear();
 }
 
-void Document::attach()
+void Document::attach(const AttachContext& context)
 {
     ASSERT(!attached());
     ASSERT(!m_inPageCache);
@@ -2058,12 +2058,12 @@ void Document::attach()
     RenderObject* render = renderer();
     setRenderer(0);
 
-    ContainerNode::attach();
+    ContainerNode::attach(context);
 
     setRenderer(render);
 }
 
-void Document::detach()
+void Document::detach(const AttachContext& context)
 {
     ASSERT(attached());
     ASSERT(!m_inPageCache);
@@ -2114,7 +2114,7 @@ void Document::detach()
     m_focusedElement = 0;
     m_activeElement = 0;
 
-    ContainerNode::detach();
+    ContainerNode::detach(context);
 
     unscheduleStyleRecalc();
 
@@ -5892,6 +5892,14 @@ void Document::updateHoverActiveState(const HitTestRequest& request, Element* in
     }
 
     if (oldHoverObj != newHoverObj) {
+        // If the old hovered element is not nil but it's renderer is, it was probably detached as part of the :hover style
+        // (for instance by setting display:none in the :hover pseudo-class). In this case, the old hovered element
+        // must be updated, to ensure it's normal style is re-applied.
+        if (oldHoveredElement && !oldHoverObj) {
+            if (!mustBeInActiveChain || (oldHoveredElement->isElementNode() && oldHoveredElement->inActiveChain()))
+                nodesToRemoveFromChain.append(oldHoveredElement);
+        }
+
         // The old hover path only needs to be cleared up to (and not including) the common ancestor;
         for (RenderObject* curr = oldHoverObj; curr && curr != ancestor; curr = curr->hoverAncestor()) {
             if (!curr->node() || curr->isText())
index a3503d8..7ae15ae 100644 (file)
@@ -532,8 +532,8 @@ public:
     static void updateStyleForAllDocuments(); // FIXME: Try to reduce the # of calls to this function.
     CachedResourceLoader* cachedResourceLoader() { return m_cachedResourceLoader.get(); }
 
-    virtual void attach();
-    virtual void detach();
+    virtual void attach(const AttachContext& = AttachContext()) OVERRIDE;
+    virtual void detach(const AttachContext& = AttachContext()) OVERRIDE;
     void prepareForDestruction();
 
     // Override ScriptExecutionContext methods to do additional work
index 583a262..709a8cf 100644 (file)
@@ -549,8 +549,17 @@ void Element::setHovered(bool flag)
     if (Document* document = this->document())
         document->userActionElements().setHovered(this, flag);
 
-    if (!renderer())
+    if (!renderer()) {
+        // When setting hover to false, the style needs to be recalc'd even when
+        // there's no renderer (imagine setting display:none in the :hover class,
+        // if a nil renderer would prevent this element from recalculating its
+        // style, it would never go back to its normal style and remain
+        // stuck in its hovered style).
+        if (!flag)
+            setNeedsStyleRecalc();
+
         return;
+    }
 
     if (renderer()->style()->affectedByHover() || childrenAffectedByHover())
         setNeedsStyleRecalc();
@@ -1405,18 +1414,18 @@ void Element::removedFrom(ContainerNode* insertionPoint)
 #endif
 }
 
-void Element::createRendererIfNeeded()
+void Element::createRendererIfNeeded(const AttachContext& context)
 {
-    NodeRenderingContext(this).createRendererForElementIfNeeded();
+    NodeRenderingContext(this, context).createRendererForElementIfNeeded();
 }
 
-void Element::attach()
+void Element::attach(const AttachContext& context)
 {
     PostAttachCallbackDisabler callbackDisabler(this);
     StyleResolverParentPusher parentPusher(this);
     WidgetHierarchyUpdatesSuspensionScope suspendWidgetHierarchyUpdates;
 
-    createRendererIfNeeded();
+    createRendererIfNeeded(context);
 
     if (parentElement() && parentElement()->isInCanvasSubtree())
         setIsInCanvasSubtree(true);
@@ -1430,7 +1439,7 @@ void Element::attach()
     } else if (firstChild())
         parentPusher.push();
 
-    ContainerNode::attach();
+    ContainerNode::attach(context);
 
     updatePseudoElement(AFTER);
 
@@ -1450,7 +1459,7 @@ void Element::unregisterNamedFlowContentNode()
         document()->renderView()->flowThreadController()->unregisterNamedFlowContentNode(this);
 }
 
-void Element::detach()
+void Element::detach(const AttachContext& context)
 {
     WidgetHierarchyUpdatesSuspensionScope suspendWidgetHierarchyUpdates;
     unregisterNamedFlowContentNode();
@@ -1469,15 +1478,19 @@ void Element::detach()
         shadow->detach();
     }
 
-    if (isUserActionElement()) {
-        if (hovered())
-            document()->hoveredElementDidDetach(this);
-        if (inActiveChain())
-            document()->elementInActiveChainDidDetach(this);
-        document()->userActionElements().didDetach(this);
+    // Do not remove the element's hovered and active status
+    // if performing a reattach.
+    if (!context.performingReattach) {
+        if (isUserActionElement()) {
+            if (hovered())
+                document()->hoveredElementDidDetach(this);
+            if (inActiveChain())
+                document()->elementInActiveChainDidDetach(this);
+            document()->userActionElements().didDetach(this);
+        }
     }
 
-    ContainerNode::detach();
+    ContainerNode::detach(context);
 }
 
 bool Element::pseudoStyleCacheIsInvalid(const RenderStyle* currentStyle, RenderStyle* newStyle)
@@ -1553,8 +1566,10 @@ void Element::recalcStyle(StyleChange change)
             localChange = Node::diff(currentStyle.get(), newStyle.get(), document());
         }
         if (localChange == Detach) {
-            // FIXME: The style gets computed twice by calling attach. We could do better if we passed the style along.
-            reattach();
+            AttachContext reattachContext;
+            reattachContext.resolvedStyle = newStyle.get();
+            reattach(reattachContext);
+
             // attach recalculates the style for all children. No need to do it twice.
             clearNeedsStyleRecalc();
             clearChildNeedsStyleRecalc();
index 47c4887..0f1cd39 100644 (file)
@@ -409,8 +409,8 @@ public:
 
     virtual void copyNonAttributePropertiesFromElement(const Element&) { }
 
-    virtual void attach();
-    virtual void detach();
+    virtual void attach(const AttachContext& = AttachContext()) OVERRIDE;
+    virtual void detach(const AttachContext& = AttachContext()) OVERRIDE;
     virtual RenderObject* createRenderer(RenderArena*, RenderStyle*);
     virtual bool rendererIsNeeded(const NodeRenderingContext&);
     void recalcStyle(StyleChange = NoChange);
@@ -756,7 +756,7 @@ private:
     void detachAllAttrNodesFromElement();
     void detachAttrNodeFromElementWithValue(Attr*, const AtomicString& value);
 
-    void createRendererIfNeeded();
+    void createRendererIfNeeded(const AttachContext&);
 
     bool isJavaScriptURLAttribute(const Attribute&) const;
 
index 8fdb4ad..bc93511 100644 (file)
@@ -973,7 +973,7 @@ bool Node::containsIncludingHostElements(const Node* node) const
 #endif
 }
 
-void Node::attach()
+void Node::attach(const AttachContext&)
 {
     ASSERT(!attached());
     ASSERT(!renderer() || (renderer()->style() && renderer()->parent()));
@@ -1016,7 +1016,7 @@ bool Node::inDetach() const
 }
 #endif
 
-void Node::detach()
+void Node::detach(const AttachContext&)
 {
 #ifndef NDEBUG
     ASSERT(!detachingNode);
index 771ea74..dcc70c1 100644 (file)
@@ -475,21 +475,28 @@ public:
     RenderBox* renderBox() const;
     RenderBoxModelObject* renderBoxModelObject() const;
 
+    struct AttachContext {
+        RenderStyle* resolvedStyle;
+        bool performingReattach;
+
+        AttachContext() : resolvedStyle(0), performingReattach(false) { }
+    };
+
     // Attaches this node to the rendering tree. This calculates the style to be applied to the node and creates an
     // appropriate RenderObject which will be inserted into the tree (except when the style has display: none). This
     // makes the node visible in the FrameView.
-    virtual void attach();
+    virtual void attach(const AttachContext& = AttachContext());
 
     // Detaches the node from the rendering tree, making it invisible in the rendered view. This method will remove
     // the node's rendering object from the rendering tree and delete it.
-    virtual void detach();
+    virtual void detach(const AttachContext& = AttachContext());
 
 #ifndef NDEBUG
     bool inDetach() const;
 #endif
 
-    void reattach();
-    void reattachIfAttached();
+    void reattach(const AttachContext& = AttachContext());
+    void reattachIfAttached(const AttachContext& = AttachContext());
     ContainerNode* parentNodeForRenderingAndStyle();
     
     // Wrapper for nodes that don't have a renderer, but still cache the style (like HTMLOptionElement).
@@ -807,17 +814,20 @@ inline ContainerNode* Node::parentNodeGuaranteedHostFree() const
     return parentOrShadowHostNode();
 }
 
-inline void Node::reattach()
+inline void Node::reattach(const AttachContext& context)
 {
+    AttachContext reattachContext(context);
+    reattachContext.performingReattach = true;
+
     if (attached())
-        detach();
-    attach();
+        detach(reattachContext);
+    attach(reattachContext);
 }
 
-inline void Node::reattachIfAttached()
+inline void Node::reattachIfAttached(const AttachContext& context)
 {
     if (attached())
-        reattach();
+        reattach(context);
 }
 
 inline void Node::lazyReattach(ShouldSetAttached shouldSetAttached)
index eb4a0a2..5849428 100644 (file)
@@ -68,6 +68,14 @@ NodeRenderingContext::NodeRenderingContext(Node* node, RenderStyle* style)
 {
 }
 
+NodeRenderingContext::NodeRenderingContext(Node* node, const Node::AttachContext& context)
+    : m_node(node)
+    , m_style(context.resolvedStyle)
+    , m_parentFlowRenderer(0)
+{
+    m_renderingParent = NodeRenderingTraversal::parent(node, &m_parentDetails);
+}
+
 NodeRenderingContext::~NodeRenderingContext()
 {
 }
index 9230520..0f10a0d 100644 (file)
@@ -47,6 +47,7 @@ class NodeRenderingContext {
 public:
     explicit NodeRenderingContext(Node*);
     NodeRenderingContext(Node*, RenderStyle*);
+    NodeRenderingContext(Node*, const Node::AttachContext&);
     ~NodeRenderingContext();
 
     void createRendererForTextIfNeeded();
index d282ec0..731f139 100644 (file)
@@ -76,11 +76,11 @@ PassRefPtr<RenderStyle> PseudoElement::customStyleForRenderer()
     return parentOrShadowHostElement()->renderer()->getCachedPseudoStyle(m_pseudoId);
 }
 
-void PseudoElement::attach()
+void PseudoElement::attach(const AttachContext& context)
 {
     ASSERT(!renderer());
 
-    Element::attach();
+    Element::attach(context);
 
     RenderObject* renderer = this->renderer();
     if (!renderer || !renderer->style()->regionThread().isEmpty())
index 67106b2..b8a407c 100644 (file)
@@ -43,7 +43,7 @@ public:
     ~PseudoElement();
 
     virtual PassRefPtr<RenderStyle> customStyleForRenderer() OVERRIDE;
-    virtual void attach() OVERRIDE;
+    virtual void attach(const AttachContext& = AttachContext()) OVERRIDE;
     virtual bool rendererIsNeeded(const NodeRenderingContext&) OVERRIDE;
 
     // As per http://dev.w3.org/csswg/css3-regions/#flow-into, pseudo-elements such as ::first-line, ::first-letter, ::before or ::after
index 9d54836..aefdc66 100644 (file)
@@ -165,11 +165,11 @@ void ShadowRoot::setResetStyleInheritance(bool value)
     }
 }
 
-void ShadowRoot::attach()
+void ShadowRoot::attach(const AttachContext& context)
 {
     StyleResolver* styleResolver = document()->ensureStyleResolver();
     styleResolver->pushParentShadowRoot(this);
-    DocumentFragment::attach();
+    DocumentFragment::attach(context);
     styleResolver->popParentShadowRoot(this);
 }
 
index d24117f..393add7 100644 (file)
@@ -71,7 +71,7 @@ public:
 
     Element* activeElement() const;
 
-    virtual void attach();
+    virtual void attach(const AttachContext& = AttachContext()) OVERRIDE;
 
     virtual void registerScopedHTMLStyleChild() OVERRIDE;
     virtual void unregisterScopedHTMLStyleChild() OVERRIDE;
index 736c932..1d25fbc 100644 (file)
@@ -277,10 +277,10 @@ RenderText* Text::createTextRenderer(RenderArena* arena, RenderStyle* style)
     return new (arena) RenderText(this, dataImpl());
 }
 
-void Text::attach()
+void Text::attach(const AttachContext& context)
 {
     createTextRendererIfNeeded();
-    CharacterData::attach();
+    CharacterData::attach(context);
 }
 
 void Text::recalcTextStyle(StyleChange change)
index e785a4b..af9b248 100644 (file)
@@ -50,7 +50,7 @@ public:
     RenderText* createTextRenderer(RenderArena*, RenderStyle*);
     void updateTextRenderer(unsigned offsetOfReplacedData, unsigned lengthOfReplacedData);
 
-    virtual void attach() OVERRIDE FINAL;
+    virtual void attach(const AttachContext& = AttachContext()) OVERRIDE FINAL;
     
     virtual bool canContainRangeEndPoint() const OVERRIDE FINAL { return true; }
 
index e1a62dc..ec18c9c 100644 (file)
@@ -121,10 +121,10 @@ RenderObject* HTMLCanvasElement::createRenderer(RenderArena* arena, RenderStyle*
     return HTMLElement::createRenderer(arena, style);
 }
 
-void HTMLCanvasElement::attach()
+void HTMLCanvasElement::attach(const AttachContext& context)
 {
     setIsInCanvasSubtree(true);
-    HTMLElement::attach();
+    HTMLElement::attach(context);
 }
 
 void HTMLCanvasElement::addObserver(CanvasObserver* observer)
index 282bab7..ebbb1bb 100644 (file)
@@ -144,7 +144,7 @@ private:
 
     virtual void parseAttribute(const QualifiedName&, const AtomicString&) OVERRIDE;
     virtual RenderObject* createRenderer(RenderArena*, RenderStyle*);
-    virtual void attach();
+    virtual void attach(const AttachContext& = AttachContext()) OVERRIDE;
     virtual bool areAuthorShadowsAllowed() const OVERRIDE { return false; }
 
     void reset();
index 071688d..9fac53e 100644 (file)
@@ -208,11 +208,11 @@ static void focusPostAttach(Node* element, unsigned)
     element->deref(); 
 }
 
-void HTMLFormControlElement::attach()
+void HTMLFormControlElement::attach(const AttachContext& context)
 {
     PostAttachCallbackDisabler disabler(this);
 
-    HTMLElement::attach();
+    HTMLElement::attach(context);
 
     // The call to updateFromElement() needs to go after the call through
     // to the base class's attach() because that can sometimes do a close
index 7b71773..28b2047 100644 (file)
@@ -111,7 +111,7 @@ protected:
     virtual void parseAttribute(const QualifiedName&, const AtomicString&) OVERRIDE;
     virtual void requiredAttributeChanged();
     virtual void disabledAttributeChanged();
-    virtual void attach();
+    virtual void attach(const AttachContext& = AttachContext()) OVERRIDE;
     virtual InsertionNotificationRequest insertedInto(ContainerNode*) OVERRIDE;
     virtual void removedFrom(ContainerNode*) OVERRIDE;
     virtual void didMoveToNewDocument(Document* oldDocument) OVERRIDE;
index 1b28c21..ed5b9b8 100644 (file)
@@ -72,9 +72,9 @@ bool HTMLFrameElement::noResize() const
     return hasAttribute(noresizeAttr);
 }
 
-void HTMLFrameElement::attach()
+void HTMLFrameElement::attach(const AttachContext& context)
 {
-    HTMLFrameElementBase::attach();
+    HTMLFrameElementBase::attach(context);
     
     if (HTMLFrameSetElement* frameSetElement = containingFrameSetElement(this)) {
         if (!m_frameBorderSet)
index 00dcc95..928429b 100644 (file)
@@ -39,7 +39,7 @@ public:
 private:
     HTMLFrameElement(const QualifiedName&, Document*);
 
-    virtual void attach();
+    virtual void attach(const AttachContext& = AttachContext()) OVERRIDE;
 
     virtual bool rendererIsNeeded(const NodeRenderingContext&);
     virtual RenderObject* createRenderer(RenderArena*, RenderStyle*);
index b7accea..754031e 100644 (file)
@@ -172,9 +172,9 @@ void HTMLFrameElementBase::didNotifySubtreeInsertions(ContainerNode*)
     setNameAndOpenURL();
 }
 
-void HTMLFrameElementBase::attach()
+void HTMLFrameElementBase::attach(const AttachContext& context)
 {
-    HTMLFrameOwnerElement::attach();
+    HTMLFrameOwnerElement::attach(context);
 
     if (RenderPart* part = renderPart()) {
         if (Frame* frame = contentFrame())
index 0c06017..1c5b03a 100644 (file)
@@ -52,7 +52,7 @@ protected:
     virtual void parseAttribute(const QualifiedName&, const AtomicString&) OVERRIDE;
     virtual InsertionNotificationRequest insertedInto(ContainerNode*) OVERRIDE;
     virtual void didNotifySubtreeInsertions(ContainerNode*) OVERRIDE;
-    virtual void attach();
+    virtual void attach(const AttachContext& = AttachContext()) OVERRIDE;
 
 private:
     virtual bool supportsFocus() const OVERRIDE;
index e2f9709..46144bc 100644 (file)
@@ -165,7 +165,7 @@ RenderObject *HTMLFrameSetElement::createRenderer(RenderArena *arena, RenderStyl
     return new (arena) RenderFrameSet(this);
 }
 
-void HTMLFrameSetElement::attach()
+void HTMLFrameSetElement::attach(const AttachContext& context)
 {
     // Inherit default settings from parent frameset
     // FIXME: This is not dynamic.
@@ -186,7 +186,7 @@ void HTMLFrameSetElement::attach()
         }
     }
 
-    HTMLElement::attach();
+    HTMLElement::attach(context);
 }
 
 void HTMLFrameSetElement::defaultEventHandler(Event* evt)
index 38e4144..25a14a8 100644 (file)
@@ -71,7 +71,7 @@ private:
     virtual bool isPresentationAttribute(const QualifiedName&) const OVERRIDE;
     virtual void collectStyleForPresentationAttribute(const QualifiedName&, const AtomicString&, MutableStylePropertySet*) OVERRIDE;
 
-    virtual void attach();
+    virtual void attach(const AttachContext& = AttachContext()) OVERRIDE;
     virtual bool rendererIsNeeded(const NodeRenderingContext&);
     virtual RenderObject* createRenderer(RenderArena*, RenderStyle*);
     
index 9f9b0bc..bcf2c93 100644 (file)
@@ -172,9 +172,9 @@ bool HTMLImageElement::canStartSelection() const
     return false;
 }
 
-void HTMLImageElement::attach()
+void HTMLImageElement::attach(const AttachContext& context)
 {
-    HTMLElement::attach();
+    HTMLElement::attach(context);
 
     if (renderer() && renderer()->isImage() && !m_imageLoader.hasPendingBeforeLoadEvent()) {
         RenderImage* renderImage = toRenderImage(renderer());
index 22bfe2f..a63de2c 100644 (file)
@@ -88,7 +88,7 @@ private:
     virtual bool isPresentationAttribute(const QualifiedName&) const OVERRIDE;
     virtual void collectStyleForPresentationAttribute(const QualifiedName&, const AtomicString&, MutableStylePropertySet*) OVERRIDE;
 
-    virtual void attach();
+    virtual void attach(const AttachContext& = AttachContext()) OVERRIDE;
     virtual RenderObject* createRenderer(RenderArena*, RenderStyle*);
 
     virtual bool canStartSelection() const;
index c91c8db..3ec6bc8 100644 (file)
@@ -799,14 +799,14 @@ RenderObject* HTMLInputElement::createRenderer(RenderArena* arena, RenderStyle*
     return m_inputType->createRenderer(arena, style);
 }
 
-void HTMLInputElement::attach()
+void HTMLInputElement::attach(const AttachContext& context)
 {
     PostAttachCallbackDisabler disabler(this);
 
     if (!m_hasType)
         updateType();
 
-    HTMLTextFormControlElement::attach();
+    HTMLTextFormControlElement::attach(context);
 
     m_inputType->attach();
 
@@ -814,9 +814,9 @@ void HTMLInputElement::attach()
         document()->updateFocusAppearanceSoon(true /* restore selection */);
 }
 
-void HTMLInputElement::detach()
+void HTMLInputElement::detach(const AttachContext& context)
 {
-    HTMLTextFormControlElement::detach();
+    HTMLTextFormControlElement::detach(context);
     setFormControlValueMatchesRenderer(false);
     m_inputType->detach();
 }
index 8101e3b..0d6401e 100644 (file)
@@ -188,7 +188,7 @@ public:
 
     virtual bool rendererIsNeeded(const NodeRenderingContext&);
     virtual RenderObject* createRenderer(RenderArena*, RenderStyle*);
-    virtual void detach();
+    virtual void detach(const AttachContext& = AttachContext()) OVERRIDE;
 
     // FIXME: For isActivatedSubmit and setActivatedSubmit, we should use the NVI-idiom here by making
     // it private virtual in all classes and expose a public method in HTMLFormControlElement to call
@@ -351,7 +351,7 @@ private:
 
     virtual void copyNonAttributePropertiesFromElement(const Element&);
 
-    virtual void attach();
+    virtual void attach(const AttachContext& = AttachContext()) OVERRIDE;
 
     virtual bool appendFormData(FormDataList&, bool);
 
index 2ef0dd7..f41183c 100644 (file)
@@ -85,11 +85,11 @@ void HTMLLIElement::parseAttribute(const QualifiedName& name, const AtomicString
         HTMLElement::parseAttribute(name, value);
 }
 
-void HTMLLIElement::attach()
+void HTMLLIElement::attach(const AttachContext& context)
 {
     ASSERT(!attached());
 
-    HTMLElement::attach();
+    HTMLElement::attach(context);
 
     if (renderer() && renderer()->isListItem()) {
         RenderListItem* listItemRenderer = toRenderListItem(renderer());
index 0048bd9..2e645c4 100644 (file)
@@ -39,7 +39,7 @@ private:
     virtual bool isPresentationAttribute(const QualifiedName&) const OVERRIDE;
     virtual void collectStyleForPresentationAttribute(const QualifiedName&, const AtomicString&, MutableStylePropertySet*) OVERRIDE;
 
-    virtual void attach();
+    virtual void attach(const AttachContext& = AttachContext()) OVERRIDE;
 
     void parseValue(const AtomicString&);
 };
index c16eaea..3c62c8a 100644 (file)
@@ -616,7 +616,7 @@ void HTMLMediaElement::removedFrom(ContainerNode* insertionPoint)
     HTMLElement::removedFrom(insertionPoint);
 }
 
-void HTMLMediaElement::attach()
+void HTMLMediaElement::attach(const AttachContext& context)
 {
     ASSERT(!attached());
 
@@ -624,7 +624,7 @@ void HTMLMediaElement::attach()
     m_needWidgetUpdate = true;
 #endif
 
-    HTMLElement::attach();
+    HTMLElement::attach(context);
 
     if (renderer())
         renderer()->updateFromElement();
index 6e16996..af108c8 100644 (file)
@@ -388,7 +388,7 @@ protected:
     virtual void parseAttribute(const QualifiedName&, const AtomicString&) OVERRIDE;
     virtual void finishParsingChildren();
     virtual bool isURLAttribute(const Attribute&) const OVERRIDE;
-    virtual void attach() OVERRIDE;
+    virtual void attach(const AttachContext& = AttachContext()) OVERRIDE;
 
     virtual void didMoveToNewDocument(Document* oldDocument) OVERRIDE;
 
index 660172a..0d0d933 100644 (file)
@@ -96,9 +96,9 @@ void HTMLOptGroupElement::recalcSelectOptions()
         toHTMLSelectElement(select)->setRecalcListItems();
 }
 
-void HTMLOptGroupElement::attach()
+void HTMLOptGroupElement::attach(const AttachContext& context)
 {
-    HTMLElement::attach();
+    HTMLElement::attach(context);
     // If after attaching nothing called styleForRenderer() on this node we
     // manually cache the value. This happens if our parent doesn't have a
     // renderer like <optgroup> or if it doesn't allow children like <select>.
@@ -106,10 +106,10 @@ void HTMLOptGroupElement::attach()
         updateNonRenderStyle();
 }
 
-void HTMLOptGroupElement::detach()
+void HTMLOptGroupElement::detach(const AttachContext& context)
 {
     m_style.clear();
-    HTMLElement::detach();
+    HTMLElement::detach(context);
 }
 
 void HTMLOptGroupElement::updateNonRenderStyle()
index 775f507..9fcfdcb 100644 (file)
@@ -47,8 +47,8 @@ private:
     virtual bool isFocusable() const OVERRIDE;
     virtual void parseAttribute(const QualifiedName&, const AtomicString&) OVERRIDE;
     virtual bool rendererIsNeeded(const NodeRenderingContext&) { return false; }
-    virtual void attach();
-    virtual void detach();
+    virtual void attach(const AttachContext& = AttachContext()) OVERRIDE;
+    virtual void detach(const AttachContext& = AttachContext()) OVERRIDE;
 
     virtual void childrenChanged(bool changedByParser = false, Node* beforeChange = 0, Node* afterChange = 0, int childCountDelta = 0);
 
index 0ed80e7..59a6225 100644 (file)
@@ -90,9 +90,9 @@ PassRefPtr<HTMLOptionElement> HTMLOptionElement::createForJSConstructor(Document
     return element.release();
 }
 
-void HTMLOptionElement::attach()
+void HTMLOptionElement::attach(const AttachContext& context)
 {
-    HTMLElement::attach();
+    HTMLElement::attach(context);
     // If after attaching nothing called styleForRenderer() on this node we
     // manually cache the value. This happens if our parent doesn't have a
     // renderer like <optgroup> or if it doesn't allow children like <select>.
@@ -100,10 +100,10 @@ void HTMLOptionElement::attach()
         updateNonRenderStyle();
 }
 
-void HTMLOptionElement::detach()
+void HTMLOptionElement::detach(const AttachContext& context)
 {
     m_style.clear();
-    HTMLElement::detach();
+    HTMLElement::detach(context);
 }
 
 bool HTMLOptionElement::supportsFocus() const
index 27b5fcf..8c66753 100644 (file)
@@ -72,8 +72,8 @@ private:
     virtual bool supportsFocus() const OVERRIDE;
     virtual bool isFocusable() const OVERRIDE;
     virtual bool rendererIsNeeded(const NodeRenderingContext&) { return false; }
-    virtual void attach();
-    virtual void detach();
+    virtual void attach(const AttachContext& = AttachContext()) OVERRIDE;
+    virtual void detach(const AttachContext& = AttachContext()) OVERRIDE;
 
     virtual void parseAttribute(const QualifiedName&, const AtomicString&) OVERRIDE;
 
index a1e4228..f5559b5 100644 (file)
@@ -93,7 +93,7 @@ bool HTMLPlugInElement::willRespondToMouseClickEvents()
     return true;
 }
 
-void HTMLPlugInElement::detach()
+void HTMLPlugInElement::detach(const AttachContext& context)
 {
     m_instance.clear();
 
@@ -110,7 +110,7 @@ void HTMLPlugInElement::detach()
     }
 #endif
 
-    HTMLFrameOwnerElement::detach();
+    HTMLFrameOwnerElement::detach(context);
 }
 
 void HTMLPlugInElement::resetInstance()
index dcb6631..17bb740 100644 (file)
@@ -83,7 +83,7 @@ public:
 protected:
     HTMLPlugInElement(const QualifiedName& tagName, Document*);
 
-    virtual void detach();
+    virtual void detach(const AttachContext& = AttachContext()) OVERRIDE;
     virtual bool isPresentationAttribute(const QualifiedName&) const OVERRIDE;
     virtual void collectStyleForPresentationAttribute(const QualifiedName&, const AtomicString&, MutableStylePropertySet*) OVERRIDE;
 
index df5b2f8..31a3f34 100644 (file)
@@ -234,7 +234,7 @@ bool HTMLPlugInImageElement::willRecalcStyle(StyleChange)
     return true;
 }
 
-void HTMLPlugInImageElement::attach()
+void HTMLPlugInImageElement::attach(const AttachContext& context)
 {
     PostAttachCallbackDisabler disabler(this);
 
@@ -243,7 +243,7 @@ void HTMLPlugInImageElement::attach()
     if (!isImage)
         queuePostAttachCallback(&HTMLPlugInImageElement::updateWidgetCallback, this);
 
-    HTMLPlugInElement::attach();
+    HTMLPlugInElement::attach(context);
 
     if (isImage && renderer() && !useFallbackContent()) {
         if (!m_imageLoader)
@@ -252,7 +252,7 @@ void HTMLPlugInImageElement::attach()
     }
 }
 
-void HTMLPlugInImageElement::detach()
+void HTMLPlugInImageElement::detach(const AttachContext& context)
 {
     // FIXME: Because of the insanity that is HTMLPlugInImageElement::recalcStyle,
     // we can end up detaching during an attach() call, before we even have a
@@ -260,7 +260,7 @@ void HTMLPlugInImageElement::detach()
     if (attached() && renderer() && !useFallbackContent())
         // Update the widget the next time we attach (detaching destroys the plugin).
         setNeedsWidgetUpdate(true);
-    HTMLPlugInElement::detach();
+    HTMLPlugInElement::detach(context);
 }
 
 void HTMLPlugInImageElement::updateWidgetIfNecessary()
index 2ae6734..15ac504 100644 (file)
@@ -110,8 +110,8 @@ protected:
     KURL m_loadedUrl;
 
     static void updateWidgetCallback(Node*, unsigned = 0);
-    virtual void attach();
-    virtual void detach();
+    virtual void attach(const AttachContext& = AttachContext()) OVERRIDE;
+    virtual void detach(const AttachContext& = AttachContext()) OVERRIDE;
 
     bool allowedToLoadFrameURL(const String& url);
     bool wouldLoadAsNetscapePlugin(const String& url, const String& serviceType);
index 53ef252..862443a 100644 (file)
@@ -92,9 +92,9 @@ void HTMLProgressElement::parseAttribute(const QualifiedName& name, const Atomic
         LabelableElement::parseAttribute(name, value);
 }
 
-void HTMLProgressElement::attach()
+void HTMLProgressElement::attach(const AttachContext& context)
 {
-    LabelableElement::attach();
+    LabelableElement::attach(context);
     if (RenderProgress* render = renderProgress())
         render->updateFromElement();
 }
index 03c5826..4617d6b 100644 (file)
@@ -60,7 +60,7 @@ private:
 
     virtual void parseAttribute(const QualifiedName&, const AtomicString&) OVERRIDE;
 
-    virtual void attach();
+    virtual void attach(const AttachContext& = AttachContext()) OVERRIDE;
 
     void didElementStateChange();
     virtual void didAddUserAgentShadowRoot(ShadowRoot*) OVERRIDE;
index 9a31b5d..b59ba81 100644 (file)
@@ -524,9 +524,9 @@ HTMLElement* HTMLTextAreaElement::placeholderElement() const
     return m_placeholder;
 }
 
-void HTMLTextAreaElement::attach()
+void HTMLTextAreaElement::attach(const AttachContext& context)
 {
-    HTMLTextFormControlElement::attach();
+    HTMLTextFormControlElement::attach(context);
     fixPlaceholderRenderer(m_placeholder, innerTextElement());
 }
 
index d86c3c2..55fbd83 100644 (file)
@@ -111,7 +111,7 @@ private:
     virtual void accessKeyAction(bool sendMouseEvents);
 
     virtual bool shouldUseInputMethod();
-    virtual void attach() OVERRIDE;
+    virtual void attach(const AttachContext& = AttachContext()) OVERRIDE;
     virtual bool matchesReadOnlyPseudoClass() const OVERRIDE;
     virtual bool matchesReadWritePseudoClass() const OVERRIDE;
 
index 21447ec..79f1807 100644 (file)
@@ -74,9 +74,9 @@ RenderObject* HTMLVideoElement::createRenderer(RenderArena* arena, RenderStyle*)
 }
 #endif
 
-void HTMLVideoElement::attach()
+void HTMLVideoElement::attach(const AttachContext& context)
 {
-    HTMLMediaElement::attach();
+    HTMLMediaElement::attach(context);
 
 #if !ENABLE(PLUGIN_PROXY_FOR_VIDEO)
     updateDisplayState();
index 9362c12..d824156 100644 (file)
@@ -78,7 +78,7 @@ private:
 #if !ENABLE(PLUGIN_PROXY_FOR_VIDEO)
     virtual RenderObject* createRenderer(RenderArena*, RenderStyle*);
 #endif
-    virtual void attach();
+    virtual void attach(const AttachContext& = AttachContext()) OVERRIDE;
     virtual void parseAttribute(const QualifiedName&, const AtomicString&) OVERRIDE;
     virtual bool isPresentationAttribute(const QualifiedName&) const OVERRIDE;
     virtual void collectStyleForPresentationAttribute(const QualifiedName&, const AtomicString&, MutableStylePropertySet*) OVERRIDE;
index 2ba2d5a..684b407 100644 (file)
@@ -161,13 +161,13 @@ void PluginDocument::setPluginElement(PassRefPtr<HTMLPlugInElement> element)
     m_pluginElement = element;
 }
 
-void PluginDocument::detach()
+void PluginDocument::detach(const AttachContext& context)
 {
     // Release the plugin Element so that we don't have a circular reference.
     m_pluginElement = 0;
     if (FrameLoader* loader = frame()->loader())
         loader->client()->redirectDataToPlugin(0);
-    HTMLDocument::detach();
+    HTMLDocument::detach(context);
 }
 
 void PluginDocument::cancelManualPluginLoad()
index 8cf0bd0..0a9921c 100644 (file)
@@ -44,7 +44,7 @@ public:
     Widget* pluginWidget();
     HTMLPlugInElement* pluginElement() { return m_pluginElement.get(); }
 
-    virtual void detach() OVERRIDE;
+    virtual void detach(const AttachContext& = AttachContext()) OVERRIDE;
 
     void cancelManualPluginLoad();
 
index 4439651..3b42e56 100644 (file)
@@ -51,27 +51,27 @@ InsertionPoint::~InsertionPoint()
 {
 }
 
-void InsertionPoint::attach()
+void InsertionPoint::attach(const AttachContext& context)
 {
     if (ShadowRoot* shadowRoot = containingShadowRoot())
         ContentDistributor::ensureDistribution(shadowRoot);
     for (Node* current = firstDistributed(); current; current = nextDistributedTo(current)) {
         if (!current->attached())
-            current->attach();
+            current->attach(context);
     }
 
-    HTMLElement::attach();
+    HTMLElement::attach(context);
 }
 
-void InsertionPoint::detach()
+void InsertionPoint::detach(const AttachContext& context)
 {
     if (ShadowRoot* shadowRoot = containingShadowRoot())
         ContentDistributor::ensureDistribution(shadowRoot);
 
     for (Node* current = firstDistributed(); current; current = nextDistributedTo(current))
-        current->detach();
+        current->detach(context);
 
-    HTMLElement::detach();
+    HTMLElement::detach(context);
 }
 
 bool InsertionPoint::shouldUseFallbackElements() const
index 10b082d..00f69e8 100644 (file)
@@ -66,8 +66,8 @@ public:
     bool resetStyleInheritance() const;
     void setResetStyleInheritance(bool);
 
-    virtual void attach();
-    virtual void detach();
+    virtual void attach(const AttachContext& = AttachContext()) OVERRIDE;
+    virtual void detach(const AttachContext& = AttachContext()) OVERRIDE;
 
     bool shouldUseFallbackElements() const;
 
index 57d33b5..43200dd 100644 (file)
@@ -387,13 +387,13 @@ bool SliderThumbElement::willRespondToMouseClickEvents()
     return HTMLDivElement::willRespondToMouseClickEvents();
 }
 
-void SliderThumbElement::detach()
+void SliderThumbElement::detach(const AttachContext& context)
 {
     if (m_inDragMode) {
         if (Frame* frame = document()->frame())
             frame->eventHandler()->setCapturingMouseEventsNode(0);
     }
-    HTMLDivElement::detach();
+    HTMLDivElement::detach(context);
 }
 
 HTMLInputElement* SliderThumbElement::hostInput() const
index 89015f5..e671f38 100644 (file)
@@ -56,7 +56,7 @@ public:
     virtual void defaultEventHandler(Event*);
     virtual bool willRespondToMouseMoveEvents() OVERRIDE;
     virtual bool willRespondToMouseClickEvents() OVERRIDE;
-    virtual void detach();
+    virtual void detach(const AttachContext& = AttachContext()) OVERRIDE;
     virtual const AtomicString& shadowPseudoId() const;
     HTMLInputElement* hostInput() const;
     void setPositionFromPoint(const LayoutPoint&);
index be41cea..1e659b2 100644 (file)
@@ -63,10 +63,10 @@ const AtomicString& SpinButtonElement::shadowPseudoId() const
     return innerPseudoId;
 }
 
-void SpinButtonElement::detach()
+void SpinButtonElement::detach(const AttachContext& context)
 {
     releaseCapture();
-    HTMLDivElement::detach();
+    HTMLDivElement::detach(context);
 }
 
 void SpinButtonElement::defaultEventHandler(Event* event)
index 7aab4ca..ba41c32 100644 (file)
@@ -70,7 +70,7 @@ private:
     SpinButtonElement(Document*, SpinButtonOwner&);
 
     virtual const AtomicString& shadowPseudoId() const;
-    virtual void detach();
+    virtual void detach(const AttachContext& = AttachContext()) OVERRIDE;
     virtual bool isSpinButtonElement() const { return true; }
     virtual bool isDisabledFormControl() const OVERRIDE { return shadowHost() && shadowHost()->isDisabledFormControl(); }
     virtual bool matchesReadOnlyPseudoClass() const OVERRIDE;
index 0c74877..9950c80 100644 (file)
@@ -199,13 +199,13 @@ const AtomicString& SearchFieldCancelButtonElement::shadowPseudoId() const
     return pseudoId;
 }
 
-void SearchFieldCancelButtonElement::detach()
+void SearchFieldCancelButtonElement::detach(const AttachContext& context)
 {
     if (m_capturing) {
         if (Frame* frame = document()->frame())
             frame->eventHandler()->setCapturingMouseEventsNode(0);
     }
-    HTMLDivElement::detach();
+    HTMLDivElement::detach(context);
 }
 
 
@@ -408,15 +408,15 @@ void InputFieldSpeechButtonElement::setRecognitionResult(int, const SpeechInputR
         renderer()->repaint();
 }
 
-void InputFieldSpeechButtonElement::attach()
+void InputFieldSpeechButtonElement::attach(const AttachContext& context)
 {
     ASSERT(!m_listenerId);
     if (SpeechInput* input = SpeechInput::from(document()->page()))
         m_listenerId = input->registerListener(this);
-    HTMLDivElement::attach();
+    HTMLDivElement::attach(context);
 }
 
-void InputFieldSpeechButtonElement::detach()
+void InputFieldSpeechButtonElement::detach(const AttachContext& context)
 {
     if (m_capturing) {
         if (Frame* frame = document()->frame())
@@ -430,7 +430,7 @@ void InputFieldSpeechButtonElement::detach()
         m_listenerId = 0;
     }
 
-    HTMLDivElement::detach();
+    HTMLDivElement::detach(context);
 }
 
 void InputFieldSpeechButtonElement::startSpeechInput()
index 62e2968..f6f5d6b 100644 (file)
@@ -91,7 +91,7 @@ public:
 private:
     SearchFieldCancelButtonElement(Document*);
     virtual const AtomicString& shadowPseudoId() const;
-    virtual void detach();
+    virtual void detach(const AttachContext& = AttachContext()) OVERRIDE;
     virtual bool isMouseFocusable() const OVERRIDE { return false; }
 
     bool m_capturing;
@@ -131,7 +131,7 @@ private:
     void setState(SpeechInputState state);
     virtual const AtomicString& shadowPseudoId() const;
     virtual bool isMouseFocusable() const OVERRIDE { return false; }
-    virtual void attach();
+    virtual void attach(const AttachContext& = AttachContext()) OVERRIDE;
 
     bool m_capturing;
     SpeechInputState m_state;
index 93a26db..58ed3f8 100644 (file)
 
 namespace WebCore {
 
-void PlaceholderDocument::attach()
+void PlaceholderDocument::attach(const AttachContext& context)
 {
     ASSERT(!attached());
 
     // Skipping Document::attach().
-    ContainerNode::attach();
+    ContainerNode::attach(context);
 }
 
 } // namespace WebCore
index 25b893c..6fb42e7 100644 (file)
@@ -37,7 +37,7 @@ public:
         return adoptRef(new PlaceholderDocument(frame, url));
     }
 
-    virtual void attach();
+    virtual void attach(const AttachContext& = AttachContext()) OVERRIDE;
 
 private:
     PlaceholderDocument(Frame* frame, const KURL& url)
index f112ebc..7b422b0 100644 (file)
@@ -850,9 +850,12 @@ bool DragController::startDrag(Frame* src, const DragState& state, DragOperation
         }
         doSystemDrag(dragImage, dragLoc, mouseDraggedPoint, clipboard, src, true);
     } else if (state.type == DragSourceActionDHTML) {
-        ASSERT(m_dragSourceAction & DragSourceActionDHTML);
-        m_client->willPerformDragSourceAction(DragSourceActionDHTML, dragOrigin, clipboard);
-        doSystemDrag(dragImage, dragLoc, dragOrigin, clipboard, src, false);
+        if (dragImage) {
+            ASSERT(m_dragSourceAction & DragSourceActionDHTML);
+            m_client->willPerformDragSourceAction(DragSourceActionDHTML, dragOrigin, clipboard);
+            doSystemDrag(dragImage, dragLoc, dragOrigin, clipboard, src, false);
+        } else
+            startedDrag = false;
     } else {
         // draggableElement() determined an image or link node was draggable, but it turns out the
         // image or link had no URL, so there is nothing to drag.
index 0d23be3..564a9c9 100644 (file)
@@ -199,9 +199,9 @@ bool SVGImageElement::haveLoadedRequiredResources()
     return !externalResourcesRequiredBaseValue() || !m_imageLoader.hasPendingActivity();
 }
 
-void SVGImageElement::attach()
+void SVGImageElement::attach(const AttachContext& context)
 {
-    SVGStyledTransformableElement::attach();
+    SVGStyledTransformableElement::attach(context);
 
     if (RenderSVGImage* imageObj = toRenderSVGImage(renderer())) {
         if (imageObj->imageResource()->hasImage())
index f63b39a..b50d8c5 100644 (file)
@@ -54,7 +54,7 @@ private:
     virtual void collectStyleForPresentationAttribute(const QualifiedName&, const AtomicString&, MutableStylePropertySet*) OVERRIDE;
     virtual void svgAttributeChanged(const QualifiedName&);
 
-    virtual void attach();
+    virtual void attach(const AttachContext& = AttachContext()) OVERRIDE;
     virtual InsertionNotificationRequest insertedInto(ContainerNode*) OVERRIDE;
 
     virtual RenderObject* createRenderer(RenderArena*, RenderStyle*);