<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[202324] trunk</title>
</head>
<body>

<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt;  }
#msg dl a { font-weight: bold}
#msg dl a:link    { color:#fc3; }
#msg dl a:active  { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff  {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta">
<dt>Revision</dt> <dd><a href="http://trac.webkit.org/projects/webkit/changeset/202324">202324</a></dd>
<dt>Author</dt> <dd>commit-queue@webkit.org</dd>
<dt>Date</dt> <dd>2016-06-21 22:52:05 -0700 (Tue, 21 Jun 2016)</dd>
</dl>

<h3>Log Message</h3>
<pre>:hover CSS pseudo-class sometimes keeps matching ever after mouse has left the element
https://bugs.webkit.org/show_bug.cgi?id=158340

Patch by Benjamin Poulain &lt;bpoulain@apple.com&gt; on 2016-06-21
Reviewed by Simon Fraser.

Source/WebCore:

When removing a hovered subtree from the document, we were getting
into an inconsistent state where m_hoveredElement is in the detached
subtree and we have no way of clearing the existing IsHovered flags.

What happens is:
-The root &quot;a&quot; has an child &quot;b&quot; that is hovered.
-&quot;a&quot; starts being removed from the tree, its renderer is destroyed.
-RenderTreeUpdater::tearDownRenderers() pushes &quot;a&quot; on the teardownStack
 and calls hoveredElementDidDetach().
-hoveredElementDidDetach() is called with &quot;a&quot;. &quot;a&quot; is not the hovered
 element, the function does nothing.
-RenderTreeUpdater::tearDownRenderers() pushes &quot;b&quot; on the teardownStack
 and calls hoveredElementDidDetach().
-hoveredElementDidDetach() is called with &quot;b&quot;. The next parent with a renderer
 is &quot;a&quot;, m_hoveredElement is set to &quot;a&quot;.
-&quot;a&quot;'s parent is set to nullptr.

-&gt; We have a m_hoveredElement on the root of a detached tree, making
   it impossible to clear the real dirty tree.

This patch changes the order in which we clear the flags.
It is done in the order in which we clear the renderers to ensure
the last element with a dead renderer is the last to update m_hoveredElement.

Tests: fast/css/ancestor-of-hovered-element-detached.html
       fast/css/ancestor-of-hovered-element-removed.html

* Source/WebCore/style/RenderTreeUpdater.cpp:

LayoutTests:

* fast/css/ancestor-of-hovered-element-detached-expected.txt: Added.
* fast/css/ancestor-of-hovered-element-detached.html: Added.
* fast/css/ancestor-of-hovered-element-removed-expected.txt: Added.
* fast/css/ancestor-of-hovered-element-removed.html: Added.</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkLayoutTestsChangeLog">trunk/LayoutTests/ChangeLog</a></li>
<li><a href="#trunkLayoutTestsplatformiossimulatorTestExpectations">trunk/LayoutTests/platform/ios-simulator/TestExpectations</a></li>
<li><a href="#trunkSourceWebCoreChangeLog">trunk/Source/WebCore/ChangeLog</a></li>
<li><a href="#trunkSourceWebCorestyleRenderTreeUpdatercpp">trunk/Source/WebCore/style/RenderTreeUpdater.cpp</a></li>
</ul>

<h3>Added Paths</h3>
<ul>
<li><a href="#trunkLayoutTestsfastcssancestorofhoveredelementdetachedexpectedtxt">trunk/LayoutTests/fast/css/ancestor-of-hovered-element-detached-expected.txt</a></li>
<li><a href="#trunkLayoutTestsfastcssancestorofhoveredelementdetachedhtml">trunk/LayoutTests/fast/css/ancestor-of-hovered-element-detached.html</a></li>
<li><a href="#trunkLayoutTestsfastcssancestorofhoveredelementremovedexpectedtxt">trunk/LayoutTests/fast/css/ancestor-of-hovered-element-removed-expected.txt</a></li>
<li><a href="#trunkLayoutTestsfastcssancestorofhoveredelementremovedhtml">trunk/LayoutTests/fast/css/ancestor-of-hovered-element-removed.html</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkLayoutTestsChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/ChangeLog (202323 => 202324)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/ChangeLog        2016-06-22 05:47:58 UTC (rev 202323)
+++ trunk/LayoutTests/ChangeLog        2016-06-22 05:52:05 UTC (rev 202324)
</span><span class="lines">@@ -1,3 +1,15 @@
</span><ins>+2016-06-21  Benjamin Poulain  &lt;bpoulain@apple.com&gt;
+
+        :hover CSS pseudo-class sometimes keeps matching ever after mouse has left the element
+        https://bugs.webkit.org/show_bug.cgi?id=158340
+
+        Reviewed by Simon Fraser.
+
+        * fast/css/ancestor-of-hovered-element-detached-expected.txt: Added.
+        * fast/css/ancestor-of-hovered-element-detached.html: Added.
+        * fast/css/ancestor-of-hovered-element-removed-expected.txt: Added.
+        * fast/css/ancestor-of-hovered-element-removed.html: Added.
+
</ins><span class="cx"> 2016-06-21  Alexey Proskuryakov  &lt;ap@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         Test expectations gardening.
</span></span></pre></div>
<a id="trunkLayoutTestsfastcssancestorofhoveredelementdetachedexpectedtxt"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/fast/css/ancestor-of-hovered-element-detached-expected.txt (0 => 202324)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/fast/css/ancestor-of-hovered-element-detached-expected.txt                                (rev 0)
+++ trunk/LayoutTests/fast/css/ancestor-of-hovered-element-detached-expected.txt        2016-06-22 05:52:05 UTC (rev 202324)
</span><span class="lines">@@ -0,0 +1,16 @@
</span><ins>+Verify the hovered state is updated correctly when an ancestor of the hovered element loses its renderer
+On success, you will see a series of &quot;PASS&quot; messages, followed by &quot;TEST COMPLETE&quot;.
+
+    Initial state
+PASS elementsWithHoverStyle() is [&quot;html&quot;, &quot;body&quot;, &quot;prime-ancestor&quot;]
+PASS elementsMatchingHoverSelector() is [&quot;html&quot;, &quot;body&quot;, &quot;prime-ancestor&quot;]
+Moving over #target
+PASS elementsWithHoverStyle() is [&quot;html&quot;, &quot;body&quot;, &quot;prime-ancestor&quot;, &quot;group&quot;, &quot;element-to-remove&quot;, &quot;target&quot;]
+PASS elementsMatchingHoverSelector() is [&quot;html&quot;, &quot;body&quot;, &quot;prime-ancestor&quot;, &quot;group&quot;, &quot;element-to-remove&quot;, &quot;target&quot;]
+Removing the renderer of #element-to-remove
+PASS elementsWithHoverStyle() is [&quot;html&quot;, &quot;body&quot;, &quot;prime-ancestor&quot;, &quot;interceptor&quot;]
+PASS elementsMatchingHoverSelector() is [&quot;html&quot;, &quot;body&quot;, &quot;prime-ancestor&quot;, &quot;interceptor&quot;]
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
</ins></span></pre></div>
<a id="trunkLayoutTestsfastcssancestorofhoveredelementdetachedhtml"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/fast/css/ancestor-of-hovered-element-detached.html (0 => 202324)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/fast/css/ancestor-of-hovered-element-detached.html                                (rev 0)
+++ trunk/LayoutTests/fast/css/ancestor-of-hovered-element-detached.html        2016-06-22 05:52:05 UTC (rev 202324)
</span><span class="lines">@@ -0,0 +1,98 @@
</span><ins>+&lt;!DOCTYPE html&gt;
+&lt;html id=&quot;html&quot;&gt;
+&lt;head&gt;
+&lt;style&gt;
+    * {
+        background-color: white;
+        margin: 0;
+        padding: 0;
+    }
+    :hover {
+        background-color: rgb(50, 100, 150) !important;
+    }
+    #prime-ancestor &gt;&gt; div {
+        width: 100px;
+        height: 100px;
+    }
+    #target {
+        width: 100px;
+        height: 100px;
+        background-color: green;
+        position: absolute;
+        left: 100px;
+    }
+    #interceptor {
+        position: absolute;
+        left: 100px;
+    }
+&lt;/style&gt;
+&lt;/head&gt;
+&lt;script src=&quot;../../resources/js-test-pre.js&quot;&gt;&lt;/script&gt;
+&lt;body id=&quot;body&quot;&gt;
+    &lt;div id=&quot;prime-ancestor&quot;&gt;
+        &lt;div id=&quot;interceptor&quot;&gt;
+        &lt;/div&gt;
+        &lt;div id=&quot;group&quot;&gt;
+            &lt;div id=&quot;element-to-remove&quot;&gt;
+                &lt;div id=&quot;target&quot;&gt;
+                &lt;/div&gt;
+            &lt;/div&gt;
+        &lt;/div&gt;
+    &lt;/div&gt;
+    &lt;div id=&quot;console&quot;&gt;
+    &lt;/div&gt;
+    &lt;script&gt;
+    description(&quot;Verify the hovered state is updated correctly when an ancestor of the hovered element loses its renderer&quot;);
+    window.jsTestIsAsync = true;
+
+    function elementsWithHoverStyle() {
+        let elements = [];
+        for (let element of document.querySelectorAll(&quot;*&quot;)) {
+            if (getComputedStyle(element).backgroundColor === &quot;rgb(50, 100, 150)&quot;)
+                elements.push(element.id);
+        }
+        return elements;
+    }
+    function elementsMatchingHoverSelector() {
+        let elements = [];
+        for (let element of document.querySelectorAll(&quot;:hover&quot;)) {
+            elements.push(element.id);
+        }
+        return elements;
+    }
+
+    if (!window.eventSender) {
+        debug(&quot;This test requires eventSender&quot;);
+    }
+    eventSender.mouseMoveTo(300, 50);
+    {
+        // See https://bugs.webkit.org/show_bug.cgi?id=74264
+        eventSender.mouseDown()
+        eventSender.mouseUp()
+    }
+
+    debug(&quot;Initial state&quot;);
+    shouldBe('elementsWithHoverStyle()', '[&quot;html&quot;, &quot;body&quot;, &quot;prime-ancestor&quot;]');
+    shouldBe('elementsMatchingHoverSelector()', '[&quot;html&quot;, &quot;body&quot;, &quot;prime-ancestor&quot;]');
+
+    debug(&quot;Moving over #target&quot;)
+    eventSender.mouseMoveTo(150, 50);
+    shouldBe('elementsWithHoverStyle()', '[&quot;html&quot;, &quot;body&quot;, &quot;prime-ancestor&quot;, &quot;group&quot;, &quot;element-to-remove&quot;, &quot;target&quot;]');
+    shouldBe('elementsMatchingHoverSelector()', '[&quot;html&quot;, &quot;body&quot;, &quot;prime-ancestor&quot;, &quot;group&quot;, &quot;element-to-remove&quot;, &quot;target&quot;]');
+
+    debug(&quot;Removing the renderer of #element-to-remove&quot;);
+    var elementToRemove = document.getElementById(&quot;element-to-remove&quot;);
+    elementToRemove.style.display = &quot;none&quot;;
+    // Force layout.
+    offsetTop = elementToRemove.offsetTop;
+
+    // hover updates happen on timer.
+    setTimeout(function() {
+        shouldBe('elementsWithHoverStyle()', '[&quot;html&quot;, &quot;body&quot;, &quot;prime-ancestor&quot;, &quot;interceptor&quot;]');
+        shouldBe('elementsMatchingHoverSelector()', '[&quot;html&quot;, &quot;body&quot;, &quot;prime-ancestor&quot;, &quot;interceptor&quot;]');
+        finishJSTest();
+    }, 125);
+    &lt;/script&gt;
+    &lt;script src=&quot;../../resources/js-test-post.js&quot;&gt;&lt;/script&gt;
+&lt;/body&gt;
+&lt;/html&gt;
</ins></span></pre></div>
<a id="trunkLayoutTestsfastcssancestorofhoveredelementremovedexpectedtxt"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/fast/css/ancestor-of-hovered-element-removed-expected.txt (0 => 202324)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/fast/css/ancestor-of-hovered-element-removed-expected.txt                                (rev 0)
+++ trunk/LayoutTests/fast/css/ancestor-of-hovered-element-removed-expected.txt        2016-06-22 05:52:05 UTC (rev 202324)
</span><span class="lines">@@ -0,0 +1,17 @@
</span><ins>+Verify the hovered state is updated correctly when an ancestor of the hovered element is detached from the document's tree
+On success, you will see a series of &quot;PASS&quot; messages, followed by &quot;TEST COMPLETE&quot;.
+
+    Initial state
+PASS elementsWithHoverStyle() is [&quot;html&quot;, &quot;body&quot;, &quot;prime-ancestor&quot;]
+PASS elementsMatchingHoverSelector() is [&quot;html&quot;, &quot;body&quot;, &quot;prime-ancestor&quot;]
+Moving over #target
+PASS elementsWithHoverStyle() is [&quot;html&quot;, &quot;body&quot;, &quot;prime-ancestor&quot;, &quot;group&quot;, &quot;element-to-remove&quot;, &quot;target&quot;]
+PASS elementsMatchingHoverSelector() is [&quot;html&quot;, &quot;body&quot;, &quot;prime-ancestor&quot;, &quot;group&quot;, &quot;element-to-remove&quot;, &quot;target&quot;]
+Removing the renderer of #element-to-remove
+PASS elementsMatchingHoverSelector(elementToRemove) is []
+PASS elementsWithHoverStyle() is [&quot;html&quot;, &quot;body&quot;, &quot;prime-ancestor&quot;, &quot;interceptor&quot;]
+PASS elementsMatchingHoverSelector() is [&quot;html&quot;, &quot;body&quot;, &quot;prime-ancestor&quot;, &quot;interceptor&quot;]
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
</ins></span></pre></div>
<a id="trunkLayoutTestsfastcssancestorofhoveredelementremovedhtml"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/fast/css/ancestor-of-hovered-element-removed.html (0 => 202324)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/fast/css/ancestor-of-hovered-element-removed.html                                (rev 0)
+++ trunk/LayoutTests/fast/css/ancestor-of-hovered-element-removed.html        2016-06-22 05:52:05 UTC (rev 202324)
</span><span class="lines">@@ -0,0 +1,100 @@
</span><ins>+&lt;!DOCTYPE html&gt;
+&lt;html id=&quot;html&quot;&gt;
+&lt;head&gt;
+&lt;style&gt;
+    * {
+        background-color: white;
+        margin: 0;
+        padding: 0;
+    }
+    :hover {
+        background-color: rgb(50, 100, 150) !important;
+    }
+    #prime-ancestor &gt;&gt; div {
+        width: 100px;
+        height: 100px;
+    }
+    #target {
+        width: 100px;
+        height: 100px;
+        background-color: green;
+        position: absolute;
+        left: 100px;
+    }
+    #interceptor {
+        position: absolute;
+        left: 100px;
+    }
+&lt;/style&gt;
+&lt;/head&gt;
+&lt;script src=&quot;../../resources/js-test-pre.js&quot;&gt;&lt;/script&gt;
+&lt;body id=&quot;body&quot;&gt;
+    &lt;div id=&quot;prime-ancestor&quot;&gt;
+        &lt;div id=&quot;interceptor&quot;&gt;
+        &lt;/div&gt;
+        &lt;div id=&quot;group&quot;&gt;
+            &lt;div id=&quot;element-to-remove&quot;&gt;
+                &lt;div id=&quot;target&quot;&gt;
+                &lt;/div&gt;
+            &lt;/div&gt;
+        &lt;/div&gt;
+    &lt;/div&gt;
+    &lt;div id=&quot;console&quot;&gt;
+    &lt;/div&gt;
+    &lt;script&gt;
+    description(&quot;Verify the hovered state is updated correctly when an ancestor of the hovered element is detached from the document's tree&quot;);
+    window.jsTestIsAsync = true;
+
+    function elementsWithHoverStyle() {
+        let elements = [];
+        for (let element of document.querySelectorAll(&quot;*&quot;)) {
+            if (getComputedStyle(element).backgroundColor === &quot;rgb(50, 100, 150)&quot;)
+                elements.push(element.id);
+        }
+        return elements;
+    }
+    function elementsMatchingHoverSelector(root = document) {
+        let elements = [];
+        for (let element of root.querySelectorAll(&quot;:hover&quot;)) {
+            elements.push(element.id);
+        }
+        return elements;
+    }
+
+    if (!window.eventSender) {
+        debug(&quot;This test requires eventSender&quot;);
+    }
+    eventSender.mouseMoveTo(300, 50);
+    {
+        // See https://bugs.webkit.org/show_bug.cgi?id=74264
+        eventSender.mouseDown()
+        eventSender.mouseUp()
+    }
+
+    debug(&quot;Initial state&quot;);
+    shouldBe('elementsWithHoverStyle()', '[&quot;html&quot;, &quot;body&quot;, &quot;prime-ancestor&quot;]');
+    shouldBe('elementsMatchingHoverSelector()', '[&quot;html&quot;, &quot;body&quot;, &quot;prime-ancestor&quot;]');
+
+    debug(&quot;Moving over #target&quot;)
+    eventSender.mouseMoveTo(150, 50);
+    shouldBe('elementsWithHoverStyle()', '[&quot;html&quot;, &quot;body&quot;, &quot;prime-ancestor&quot;, &quot;group&quot;, &quot;element-to-remove&quot;, &quot;target&quot;]');
+    shouldBe('elementsMatchingHoverSelector()', '[&quot;html&quot;, &quot;body&quot;, &quot;prime-ancestor&quot;, &quot;group&quot;, &quot;element-to-remove&quot;, &quot;target&quot;]');
+
+    debug(&quot;Removing the renderer of #element-to-remove&quot;);
+    var elementToRemove = document.getElementById(&quot;element-to-remove&quot;);
+    elementToRemove.parentElement.removeChild(elementToRemove);
+    shouldBe('elementsMatchingHoverSelector(elementToRemove)', '[]');
+
+    // Force layout.
+    offsetTop = elementToRemove.offsetTop;
+
+    // hover updates happen on timer.
+    setTimeout(function() {
+        shouldBe('elementsWithHoverStyle()', '[&quot;html&quot;, &quot;body&quot;, &quot;prime-ancestor&quot;, &quot;interceptor&quot;]');
+        shouldBe('elementsMatchingHoverSelector()', '[&quot;html&quot;, &quot;body&quot;, &quot;prime-ancestor&quot;, &quot;interceptor&quot;]');
+        finishJSTest();
+    }, 125);
+    &lt;/script&gt;
+    &lt;script src=&quot;../../resources/js-test-post.js&quot;&gt;&lt;/script&gt;
+&lt;/body&gt;
+&lt;/html&gt;
</ins></span></pre></div>
<a id="trunkLayoutTestsplatformiossimulatorTestExpectations"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/platform/ios-simulator/TestExpectations (202323 => 202324)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/platform/ios-simulator/TestExpectations        2016-06-22 05:47:58 UTC (rev 202323)
+++ trunk/LayoutTests/platform/ios-simulator/TestExpectations        2016-06-22 05:52:05 UTC (rev 202324)
</span><span class="lines">@@ -1389,6 +1389,8 @@
</span><span class="cx"> fast/clip/clip-when-rect-has-fractional-pixel-value.html [ ImageOnlyFailure ]
</span><span class="cx"> fast/css-generated-content/table-parts-before-and-after.html [ Failure ]
</span><span class="cx"> fast/css/absolute-child-with-percent-height-inside-relative-parent.html [ Failure ]
</span><ins>+fast/css/ancestor-of-hovered-element-detached.html [ Failure ]
+fast/css/ancestor-of-hovered-element-removed.html [ Failure ]
</ins><span class="cx"> fast/css/background-image-with-baseurl.html [ Failure ]
</span><span class="cx"> fast/css/button-height.html [ Failure ]
</span><span class="cx"> fast/css/caption-width-absolute-position-offset-top.htm [ Failure ]
</span></span></pre></div>
<a id="trunkSourceWebCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/ChangeLog (202323 => 202324)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/ChangeLog        2016-06-22 05:47:58 UTC (rev 202323)
+++ trunk/Source/WebCore/ChangeLog        2016-06-22 05:52:05 UTC (rev 202324)
</span><span class="lines">@@ -1,3 +1,39 @@
</span><ins>+2016-06-21  Benjamin Poulain  &lt;bpoulain@apple.com&gt;
+
+        :hover CSS pseudo-class sometimes keeps matching ever after mouse has left the element
+        https://bugs.webkit.org/show_bug.cgi?id=158340
+
+        Reviewed by Simon Fraser.
+
+        When removing a hovered subtree from the document, we were getting
+        into an inconsistent state where m_hoveredElement is in the detached
+        subtree and we have no way of clearing the existing IsHovered flags.
+
+        What happens is:
+        -The root &quot;a&quot; has an child &quot;b&quot; that is hovered.
+        -&quot;a&quot; starts being removed from the tree, its renderer is destroyed.
+        -RenderTreeUpdater::tearDownRenderers() pushes &quot;a&quot; on the teardownStack
+         and calls hoveredElementDidDetach().
+        -hoveredElementDidDetach() is called with &quot;a&quot;. &quot;a&quot; is not the hovered
+         element, the function does nothing.
+        -RenderTreeUpdater::tearDownRenderers() pushes &quot;b&quot; on the teardownStack
+         and calls hoveredElementDidDetach().
+        -hoveredElementDidDetach() is called with &quot;b&quot;. The next parent with a renderer
+         is &quot;a&quot;, m_hoveredElement is set to &quot;a&quot;.
+        -&quot;a&quot;'s parent is set to nullptr.
+
+        -&gt; We have a m_hoveredElement on the root of a detached tree, making
+           it impossible to clear the real dirty tree.
+
+        This patch changes the order in which we clear the flags.
+        It is done in the order in which we clear the renderers to ensure
+        the last element with a dead renderer is the last to update m_hoveredElement.
+
+        Tests: fast/css/ancestor-of-hovered-element-detached.html
+               fast/css/ancestor-of-hovered-element-removed.html
+
+        * Source/WebCore/style/RenderTreeUpdater.cpp:
+
</ins><span class="cx"> 2016-06-21  Youenn Fablet  &lt;youennf@gmail.com&gt;
</span><span class="cx"> 
</span><span class="cx">         [Fetch API] Rename 'origin-only' referrer policy to 'origin'
</span></span></pre></div>
<a id="trunkSourceWebCorestyleRenderTreeUpdatercpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/style/RenderTreeUpdater.cpp (202323 => 202324)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/style/RenderTreeUpdater.cpp        2016-06-22 05:47:58 UTC (rev 202323)
+++ trunk/Source/WebCore/style/RenderTreeUpdater.cpp        2016-06-22 05:52:05 UTC (rev 202324)
</span><span class="lines">@@ -518,10 +518,6 @@
</span><span class="cx">     auto push = [&amp;] (Element&amp; element) {
</span><span class="cx">         if (element.hasCustomStyleResolveCallbacks())
</span><span class="cx">             element.willDetachRenderers();
</span><del>-        if (teardownType != TeardownType::KeepHoverAndActive)
-            element.clearHoverAndActiveStatusBeforeDetachingRenderer();
-        element.clearStyleDerivedDataBeforeDetachingRenderer();
-
</del><span class="cx">         teardownStack.append(&amp;element);
</span><span class="cx">     };
</span><span class="cx"> 
</span><span class="lines">@@ -529,6 +525,10 @@
</span><span class="cx">         while (teardownStack.size() &gt; depth) {
</span><span class="cx">             auto&amp; element = *teardownStack.takeLast();
</span><span class="cx"> 
</span><ins>+            if (teardownType != TeardownType::KeepHoverAndActive)
+                element.clearHoverAndActiveStatusBeforeDetachingRenderer();
+            element.clearStyleDerivedDataBeforeDetachingRenderer();
+
</ins><span class="cx">             if (auto* renderer = element.renderer()) {
</span><span class="cx">                 renderer-&gt;destroyAndCleanupAnonymousWrappers();
</span><span class="cx">                 element.setRenderer(nullptr);
</span></span></pre>
</div>
</div>

</body>
</html>