<!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>[169128] 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/169128">169128</a></dd>
<dt>Author</dt> <dd>dbates@webkit.org</dd>
<dt>Date</dt> <dd>2014-05-20 13:34:35 -0700 (Tue, 20 May 2014)</dd>
</dl>

<h3>Log Message</h3>
<pre>Element within flattened frame may update its scroll state during the layout phase of the wrong RenderView
https://bugs.webkit.org/show_bug.cgi?id=133013
&lt;rdar://problem/16760154&gt;

Reviewed by David Hyatt.

Source/WebCore:
Fixes an issue where the scroll state of an element may be updated during the layout of the wrong
RenderView. In particular, the scroll state of an element inside a CSS flex box in a flattened
frame f is updated during the layout of the RenderView associated with the parent frame of f instead
of during the layout of the RenderView associated with f.

The layout machinery assumes that the scroll state of each scrollable element is updated before the
completion of layout for its associated RenderView. Currently we have logic to defer updating the scroll
state of a scrollable element until completion of recursive layout. For a page with a flattened frame, we
defer such updates until completion of layout for all RenderViews along the ancestor frame hierarchy of
each flattened frame regardless of the RenderView associated with the element that originated the
deferred scroll state request. Instead, only the RenderView associated with the element that deferred its
scroll state update should dispatch the scroll state update.

Tests: fast/frames/flattening/scrollable-flexbox-inside-iframe-with-zero-height-and-needs-full-repaint-crash.html
       fast/frames/flattening/scrollable-flexbox-inside-iframe-with-zero-height-assertion-failure.html

* rendering/RenderBlock.cpp: Removed WTF::-prefix in typedef definition for ContinuationOutlineTableMap.
(WebCore::UpdateScrollInfoAfterLayoutTransaction::UpdateScrollInfoAfterLayoutTransaction): Added; a struct
that represents a RenderView v, nested transaction count, and a list of RenderBlocks in v that will need
to have their scroll state updated.
(WebCore::updateScrollInfoAfterLayoutTransactionStack): Added; returns the global stack of transactions.
(WebCore::RenderBlock::willBeDestroyed): Call removeFromUpdateScrollInfoAfterLayoutTransaction(), which
was formerly named as removeFromDelayedUpdateScrollInfoSet.
(WebCore::currentUpdateScrollInfoAfterLayoutTransaction): Added; returns the top-most transaction in the
global stack.
(WebCore::RenderBlock::beginUpdateScrollInfoAfterLayoutTransaction): Modified as appropriate to make use
of the global stack of transactions; formerly named startDelayUpdateScrollInfo.
(WebCore::RenderBlock::endAndCommitUpdateScrollInfoAfterLayoutTransaction): Modified as appropriate to
make use of the global stack of transactions; formerly named finishDelayUpdateScrollInfo.
(WebCore::RenderBlock::removeFromUpdateScrollInfoAfterLayoutTransaction): Modified as appropriate to make
use of the global stack of transactions; formerly named removeFromDelayedUpdateScrollInfoSet.
(WebCore::RenderBlock::updateScrollInfoAfterLayout): Modified as appropriate to make use of the global
stack of transactions.
(WebCore::RenderBlock::layout): Ditto.
(WebCore::RenderBlock::startDelayUpdateScrollInfo): Deleted.
(WebCore::RenderBlock::finishDelayUpdateScrollInfo): Deleted.
(WebCore::RenderBlock::removeFromDelayedUpdateScrollInfoSet): Deleted.
* rendering/RenderBlock.h:
* rendering/RenderBlockFlow.cpp:
(WebCore::RenderBlockFlow::willBeDestroyed): Call removeFromUpdateScrollInfoAfterLayoutTransaction(), which
was formerly named removeFromDelayedUpdateScrollInfoSet.
* rendering/RenderDeprecatedFlexibleBox.cpp:
(WebCore::RenderDeprecatedFlexibleBox::layoutHorizontalBox): Call {begin, end}UpdateScrollInfoAfterLayoutTransaction(),
which was formerly named {start, end}DelayUpdateScrollInfo.
(WebCore::RenderDeprecatedFlexibleBox::layoutVerticalBox): Ditto.
* rendering/RenderFlexibleBox.cpp:
(WebCore::RenderFlexibleBox::layoutBlock): Ditto.

LayoutTests:
Added tests to ensure that that we update the scroll state of an element during the layout phase of its
associated RenderView.

* fast/frames/flattening/scrollable-flexbox-inside-iframe-with-zero-height-and-needs-full-repaint-crash-expected.txt: Added.
* fast/frames/flattening/scrollable-flexbox-inside-iframe-with-zero-height-and-needs-full-repaint-crash.html: Added.
* fast/frames/flattening/scrollable-flexbox-inside-iframe-with-zero-height-assertion-failure-expected.txt: Added.
* fast/frames/flattening/scrollable-flexbox-inside-iframe-with-zero-height-assertion-failure.html: Added.</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkLayoutTestsChangeLog">trunk/LayoutTests/ChangeLog</a></li>
<li><a href="#trunkSourceWebCoreChangeLog">trunk/Source/WebCore/ChangeLog</a></li>
<li><a href="#trunkSourceWebCorerenderingRenderBlockcpp">trunk/Source/WebCore/rendering/RenderBlock.cpp</a></li>
<li><a href="#trunkSourceWebCorerenderingRenderBlockh">trunk/Source/WebCore/rendering/RenderBlock.h</a></li>
<li><a href="#trunkSourceWebCorerenderingRenderBlockFlowcpp">trunk/Source/WebCore/rendering/RenderBlockFlow.cpp</a></li>
<li><a href="#trunkSourceWebCorerenderingRenderDeprecatedFlexibleBoxcpp">trunk/Source/WebCore/rendering/RenderDeprecatedFlexibleBox.cpp</a></li>
<li><a href="#trunkSourceWebCorerenderingRenderFlexibleBoxcpp">trunk/Source/WebCore/rendering/RenderFlexibleBox.cpp</a></li>
</ul>

<h3>Added Paths</h3>
<ul>
<li><a href="#trunkLayoutTestsfastframesflatteningscrollableflexboxinsideiframewithzeroheightandneedsfullrepaintcrashexpectedtxt">trunk/LayoutTests/fast/frames/flattening/scrollable-flexbox-inside-iframe-with-zero-height-and-needs-full-repaint-crash-expected.txt</a></li>
<li><a href="#trunkLayoutTestsfastframesflatteningscrollableflexboxinsideiframewithzeroheightandneedsfullrepaintcrashhtml">trunk/LayoutTests/fast/frames/flattening/scrollable-flexbox-inside-iframe-with-zero-height-and-needs-full-repaint-crash.html</a></li>
<li><a href="#trunkLayoutTestsfastframesflatteningscrollableflexboxinsideiframewithzeroheightassertionfailureexpectedtxt">trunk/LayoutTests/fast/frames/flattening/scrollable-flexbox-inside-iframe-with-zero-height-assertion-failure-expected.txt</a></li>
<li><a href="#trunkLayoutTestsfastframesflatteningscrollableflexboxinsideiframewithzeroheightassertionfailurehtml">trunk/LayoutTests/fast/frames/flattening/scrollable-flexbox-inside-iframe-with-zero-height-assertion-failure.html</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkLayoutTestsChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/ChangeLog (169127 => 169128)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/ChangeLog        2014-05-20 20:21:23 UTC (rev 169127)
+++ trunk/LayoutTests/ChangeLog        2014-05-20 20:34:35 UTC (rev 169128)
</span><span class="lines">@@ -1,3 +1,19 @@
</span><ins>+2014-05-20  Daniel Bates  &lt;dabates@apple.com&gt;
+
+        Element within flattened frame may update its scroll state during the layout phase of the wrong RenderView
+        https://bugs.webkit.org/show_bug.cgi?id=133013
+        &lt;rdar://problem/16760154&gt;
+
+        Reviewed by David Hyatt.
+
+        Added tests to ensure that that we update the scroll state of an element during the layout phase of its
+        associated RenderView.
+
+        * fast/frames/flattening/scrollable-flexbox-inside-iframe-with-zero-height-and-needs-full-repaint-crash-expected.txt: Added.
+        * fast/frames/flattening/scrollable-flexbox-inside-iframe-with-zero-height-and-needs-full-repaint-crash.html: Added.
+        * fast/frames/flattening/scrollable-flexbox-inside-iframe-with-zero-height-assertion-failure-expected.txt: Added.
+        * fast/frames/flattening/scrollable-flexbox-inside-iframe-with-zero-height-assertion-failure.html: Added.
+
</ins><span class="cx"> 2014-05-19  Mark Hahnenberg  &lt;mhahnenberg@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         JSArray::shiftCountWith* could be more efficient
</span></span></pre></div>
<a id="trunkLayoutTestsfastframesflatteningscrollableflexboxinsideiframewithzeroheightandneedsfullrepaintcrashexpectedtxt"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/fast/frames/flattening/scrollable-flexbox-inside-iframe-with-zero-height-and-needs-full-repaint-crash-expected.txt (0 => 169128)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/fast/frames/flattening/scrollable-flexbox-inside-iframe-with-zero-height-and-needs-full-repaint-crash-expected.txt                                (rev 0)
+++ trunk/LayoutTests/fast/frames/flattening/scrollable-flexbox-inside-iframe-with-zero-height-and-needs-full-repaint-crash-expected.txt        2014-05-20 20:34:35 UTC (rev 169128)
</span><span class="lines">@@ -0,0 +1,4 @@
</span><ins>+This tests that we don't cause a crash when performing a full repaint of an &lt;iframe&gt; with zero height, enclosed in a flex box, whose content document contains a flex box with a child scrollable &lt;div&gt;.
+
+
+PASS
</ins></span></pre></div>
<a id="trunkLayoutTestsfastframesflatteningscrollableflexboxinsideiframewithzeroheightandneedsfullrepaintcrashhtml"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/fast/frames/flattening/scrollable-flexbox-inside-iframe-with-zero-height-and-needs-full-repaint-crash.html (0 => 169128)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/fast/frames/flattening/scrollable-flexbox-inside-iframe-with-zero-height-and-needs-full-repaint-crash.html                                (rev 0)
+++ trunk/LayoutTests/fast/frames/flattening/scrollable-flexbox-inside-iframe-with-zero-height-and-needs-full-repaint-crash.html        2014-05-20 20:34:35 UTC (rev 169128)
</span><span class="lines">@@ -0,0 +1,38 @@
</span><ins>+&lt;!DOCTYPE html&gt;
+&lt;html&gt;
+&lt;head&gt;
+&lt;script&gt;
+if (window.testRunner) {
+    testRunner.dumpAsText();
+    testRunner.waitUntilDone();
+}
+
+if (window.internals)
+    internals.settings.setFrameFlatteningEnabled(true);
+
+function done()
+{
+    document.getElementById(&quot;console&quot;).innerText = &quot;PASS&quot;;
+    if (window.testRunner)
+        testRunner.notifyDone();
+}
+&lt;/script&gt;
+&lt;/head&gt;
+&lt;body&gt;
+&lt;p&gt;This tests that we don't cause a crash when performing a full repaint of an &amp;lt;iframe&amp;gt; with zero height, enclosed in a flex box, whose content document contains a flex box with a child scrollable &amp;lt;div&amp;gt;.&lt;/p&gt;
+&lt;div id=&quot;test-container&quot; style=&quot;display: -webkit-flex; -webkit-flex-direction: column; height: 512px;&quot;&gt;
+    &lt;iframe style=&quot;width: 100%; overflow: hidden&quot; height=&quot;0&quot; srcdoc=&quot;
+        &lt;div style='display: -webkit-flex; -webkit-flex-direction: column; height: 128px; width: 128px; background-color: blue'&gt;
+            &lt;div id='scrollableDiv' style='overflow-y: scroll; outline: none; width: 10px; height: 10px; -webkit-flex: 1;'&gt;
+                &lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;Lorem ipsum
+            &lt;/div&gt;
+        &lt;/div&gt;
+        &lt;script&gt;
+        document.getElementById('scrollableDiv').scrollTop = 108;
+        window.parent.done();
+        &lt;/script&gt;
+    &quot;&gt;&lt;/iframe&gt;
+&lt;/div&gt;
+&lt;pre id=&quot;console&quot;&gt;FAIL&lt;/pre&gt;
+&lt;/body&gt;
+&lt;/html&gt;
</ins></span></pre></div>
<a id="trunkLayoutTestsfastframesflatteningscrollableflexboxinsideiframewithzeroheightassertionfailureexpectedtxt"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/fast/frames/flattening/scrollable-flexbox-inside-iframe-with-zero-height-assertion-failure-expected.txt (0 => 169128)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/fast/frames/flattening/scrollable-flexbox-inside-iframe-with-zero-height-assertion-failure-expected.txt                                (rev 0)
+++ trunk/LayoutTests/fast/frames/flattening/scrollable-flexbox-inside-iframe-with-zero-height-assertion-failure-expected.txt        2014-05-20 20:34:35 UTC (rev 169128)
</span><span class="lines">@@ -0,0 +1,4 @@
</span><ins>+This tests that we don't cause an assertion failure when performing a partial repaint of an &lt;iframe&gt; with zero height, enclosed in a flex box, whose content document contains a flex box with a child scrollable &lt;div&gt;.
+
+
+PASS
</ins></span></pre></div>
<a id="trunkLayoutTestsfastframesflatteningscrollableflexboxinsideiframewithzeroheightassertionfailurehtml"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/fast/frames/flattening/scrollable-flexbox-inside-iframe-with-zero-height-assertion-failure.html (0 => 169128)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/fast/frames/flattening/scrollable-flexbox-inside-iframe-with-zero-height-assertion-failure.html                                (rev 0)
+++ trunk/LayoutTests/fast/frames/flattening/scrollable-flexbox-inside-iframe-with-zero-height-assertion-failure.html        2014-05-20 20:34:35 UTC (rev 169128)
</span><span class="lines">@@ -0,0 +1,40 @@
</span><ins>+&lt;!DOCTYPE html&gt;
+&lt;html&gt;
+&lt;head&gt;
+&lt;script&gt;
+if (window.testRunner) {
+    testRunner.dumpAsText();
+    testRunner.waitUntilDone();
+}
+
+if (window.internals)
+    internals.settings.setFrameFlatteningEnabled(true);
+
+function done()
+{
+    document.getElementById(&quot;console&quot;).innerText = &quot;PASS&quot;;
+    if (window.testRunner)
+        testRunner.notifyDone();
+}
+&lt;/script&gt;
+&lt;/head&gt;
+&lt;body&gt;
+&lt;p&gt;This tests that we don't cause an assertion failure when performing a partial repaint of an &amp;lt;iframe&amp;gt; with zero height, enclosed in a flex box, whose content document contains a flex box with a child scrollable &amp;lt;div&amp;gt;.&lt;/p&gt;
+&lt;div id=&quot;test-container&quot; style=&quot;display: -webkit-flex; -webkit-flex-direction: column; height: 512px;&quot;&gt;
+    &lt;iframe style=&quot;width: 100%; overflow: hidden&quot; height=&quot;0&quot; srcdoc=&quot;
+        &lt;div style='display: -webkit-flex; -webkit-flex-direction: column; height: 128px; width: 128px; background-color: blue'&gt;
+            &lt;div id='scrollableDiv' style='display: none; overflow-y: scroll; width: 100px;'&gt;&lt;/div&gt;
+        &lt;/div&gt;
+        &lt;script&gt;
+        window.setTimeout(function () {
+            var scrollableDiv = document.getElementById('scrollableDiv');
+            scrollableDiv.innerHTML = 'Supercalifragilisticexpialidocious'; /* A string that cannot be word-wrapped and exceeds the width of the scrollableDiv. */
+            scrollableDiv.style.display = 'block';
+            window.parent.done();
+        }, 0);
+        &lt;/script&gt;
+    &quot;&gt;&lt;/iframe&gt;
+&lt;/div&gt;
+&lt;pre id=&quot;console&quot;&gt;FAIL&lt;/pre&gt;
+&lt;/body&gt;
+&lt;/html&gt;
</ins></span></pre></div>
<a id="trunkSourceWebCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/ChangeLog (169127 => 169128)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/ChangeLog        2014-05-20 20:21:23 UTC (rev 169127)
+++ trunk/Source/WebCore/ChangeLog        2014-05-20 20:34:35 UTC (rev 169128)
</span><span class="lines">@@ -1,3 +1,59 @@
</span><ins>+2014-05-20  Daniel Bates  &lt;dabates@apple.com&gt;
+
+        Element within flattened frame may update its scroll state during the layout phase of the wrong RenderView
+        https://bugs.webkit.org/show_bug.cgi?id=133013
+        &lt;rdar://problem/16760154&gt;
+
+        Reviewed by David Hyatt.
+
+        Fixes an issue where the scroll state of an element may be updated during the layout of the wrong
+        RenderView. In particular, the scroll state of an element inside a CSS flex box in a flattened
+        frame f is updated during the layout of the RenderView associated with the parent frame of f instead
+        of during the layout of the RenderView associated with f.
+
+        The layout machinery assumes that the scroll state of each scrollable element is updated before the
+        completion of layout for its associated RenderView. Currently we have logic to defer updating the scroll
+        state of a scrollable element until completion of recursive layout. For a page with a flattened frame, we
+        defer such updates until completion of layout for all RenderViews along the ancestor frame hierarchy of
+        each flattened frame regardless of the RenderView associated with the element that originated the
+        deferred scroll state request. Instead, only the RenderView associated with the element that deferred its
+        scroll state update should dispatch the scroll state update.
+
+        Tests: fast/frames/flattening/scrollable-flexbox-inside-iframe-with-zero-height-and-needs-full-repaint-crash.html
+               fast/frames/flattening/scrollable-flexbox-inside-iframe-with-zero-height-assertion-failure.html
+
+        * rendering/RenderBlock.cpp: Removed WTF::-prefix in typedef definition for ContinuationOutlineTableMap.
+        (WebCore::UpdateScrollInfoAfterLayoutTransaction::UpdateScrollInfoAfterLayoutTransaction): Added; a struct
+        that represents a RenderView v, nested transaction count, and a list of RenderBlocks in v that will need
+        to have their scroll state updated.
+        (WebCore::updateScrollInfoAfterLayoutTransactionStack): Added; returns the global stack of transactions.
+        (WebCore::RenderBlock::willBeDestroyed): Call removeFromUpdateScrollInfoAfterLayoutTransaction(), which
+        was formerly named as removeFromDelayedUpdateScrollInfoSet.
+        (WebCore::currentUpdateScrollInfoAfterLayoutTransaction): Added; returns the top-most transaction in the
+        global stack.
+        (WebCore::RenderBlock::beginUpdateScrollInfoAfterLayoutTransaction): Modified as appropriate to make use
+        of the global stack of transactions; formerly named startDelayUpdateScrollInfo.
+        (WebCore::RenderBlock::endAndCommitUpdateScrollInfoAfterLayoutTransaction): Modified as appropriate to
+        make use of the global stack of transactions; formerly named finishDelayUpdateScrollInfo.
+        (WebCore::RenderBlock::removeFromUpdateScrollInfoAfterLayoutTransaction): Modified as appropriate to make
+        use of the global stack of transactions; formerly named removeFromDelayedUpdateScrollInfoSet.
+        (WebCore::RenderBlock::updateScrollInfoAfterLayout): Modified as appropriate to make use of the global
+        stack of transactions.
+        (WebCore::RenderBlock::layout): Ditto.
+        (WebCore::RenderBlock::startDelayUpdateScrollInfo): Deleted.
+        (WebCore::RenderBlock::finishDelayUpdateScrollInfo): Deleted.
+        (WebCore::RenderBlock::removeFromDelayedUpdateScrollInfoSet): Deleted.
+        * rendering/RenderBlock.h:
+        * rendering/RenderBlockFlow.cpp:
+        (WebCore::RenderBlockFlow::willBeDestroyed): Call removeFromUpdateScrollInfoAfterLayoutTransaction(), which
+        was formerly named removeFromDelayedUpdateScrollInfoSet.
+        * rendering/RenderDeprecatedFlexibleBox.cpp:
+        (WebCore::RenderDeprecatedFlexibleBox::layoutHorizontalBox): Call {begin, end}UpdateScrollInfoAfterLayoutTransaction(),
+        which was formerly named {start, end}DelayUpdateScrollInfo.
+        (WebCore::RenderDeprecatedFlexibleBox::layoutVerticalBox): Ditto.
+        * rendering/RenderFlexibleBox.cpp:
+        (WebCore::RenderFlexibleBox::layoutBlock): Ditto.
+
</ins><span class="cx"> 2014-05-20  Beth Dakin  &lt;bdakin@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         REGRESSION (r169065): Mountain Lion run-api-tests failures: ASSERTION FAILED: 
</span></span></pre></div>
<a id="trunkSourceWebCorerenderingRenderBlockcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/rendering/RenderBlock.cpp (169127 => 169128)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/rendering/RenderBlock.cpp        2014-05-20 20:21:23 UTC (rev 169127)
+++ trunk/Source/WebCore/rendering/RenderBlock.cpp        2014-05-20 20:34:35 UTC (rev 169128)
</span><span class="lines">@@ -64,6 +64,7 @@
</span><span class="cx"> #include &quot;Settings.h&quot;
</span><span class="cx"> #include &quot;ShadowRoot.h&quot;
</span><span class="cx"> #include &quot;TransformState.h&quot;
</span><ins>+#include &lt;wtf/NeverDestroyed.h&gt;
</ins><span class="cx"> #include &lt;wtf/StackStats.h&gt;
</span><span class="cx"> #include &lt;wtf/TemporaryChange.h&gt;
</span><span class="cx"> 
</span><span class="lines">@@ -90,12 +91,27 @@
</span><span class="cx"> static TrackedContainerMap* gPositionedContainerMap = 0;
</span><span class="cx"> static TrackedContainerMap* gPercentHeightContainerMap = 0;
</span><span class="cx">     
</span><del>-typedef WTF::HashMap&lt;RenderBlock*, std::unique_ptr&lt;ListHashSet&lt;RenderInline*&gt;&gt;&gt; ContinuationOutlineTableMap;
</del><ins>+typedef HashMap&lt;RenderBlock*, std::unique_ptr&lt;ListHashSet&lt;RenderInline*&gt;&gt;&gt; ContinuationOutlineTableMap;
</ins><span class="cx"> 
</span><del>-typedef WTF::HashSet&lt;RenderBlock*&gt; DelayedUpdateScrollInfoSet;
-static int gDelayUpdateScrollInfo = 0;
-static DelayedUpdateScrollInfoSet* gDelayedUpdateScrollInfoSet = 0;
</del><ins>+struct UpdateScrollInfoAfterLayoutTransaction {
+    UpdateScrollInfoAfterLayoutTransaction(const RenderView&amp; view)
+        : nestedCount(0)
+        , view(&amp;view)
+    {
+    }
</ins><span class="cx"> 
</span><ins>+    int nestedCount;
+    const RenderView* view;
+    HashSet&lt;RenderBlock*&gt; blocks;
+};
+
+typedef Vector&lt;UpdateScrollInfoAfterLayoutTransaction&gt; DelayedUpdateScrollInfoStack;
+static std::unique_ptr&lt;DelayedUpdateScrollInfoStack&gt;&amp; updateScrollInfoAfterLayoutTransactionStack()
+{
+    static NeverDestroyed&lt;std::unique_ptr&lt;DelayedUpdateScrollInfoStack&gt;&gt; delayedUpdatedScrollInfoStack;
+    return delayedUpdatedScrollInfoStack;
+}
+
</ins><span class="cx"> // Allocated only when some of these fields have non-default values
</span><span class="cx"> 
</span><span class="cx"> struct RenderBlockRareData {
</span><span class="lines">@@ -236,7 +252,7 @@
</span><span class="cx">             parent()-&gt;dirtyLinesFromChangedChild(this);
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    removeFromDelayedUpdateScrollInfoSet();
</del><ins>+    removeFromUpdateScrollInfoAfterLayoutTransaction();
</ins><span class="cx"> 
</span><span class="cx">     RenderBox::willBeDestroyed();
</span><span class="cx"> }
</span><span class="lines">@@ -919,40 +935,56 @@
</span><span class="cx">     return false;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-void RenderBlock::startDelayUpdateScrollInfo()
</del><ins>+static inline UpdateScrollInfoAfterLayoutTransaction* currentUpdateScrollInfoAfterLayoutTransaction()
</ins><span class="cx"> {
</span><del>-    if (gDelayUpdateScrollInfo == 0) {
-        ASSERT(!gDelayedUpdateScrollInfoSet);
-        gDelayedUpdateScrollInfoSet = new DelayedUpdateScrollInfoSet;
-    }
-    ASSERT(gDelayedUpdateScrollInfoSet);
-    ++gDelayUpdateScrollInfo;
</del><ins>+    if (!updateScrollInfoAfterLayoutTransactionStack())
+        return nullptr;
+    return &amp;updateScrollInfoAfterLayoutTransactionStack()-&gt;last();
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-void RenderBlock::finishDelayUpdateScrollInfo()
</del><ins>+void RenderBlock::beginUpdateScrollInfoAfterLayoutTransaction()
</ins><span class="cx"> {
</span><del>-    --gDelayUpdateScrollInfo;
-    ASSERT(gDelayUpdateScrollInfo &gt;= 0);
-    if (gDelayUpdateScrollInfo == 0) {
-        ASSERT(gDelayedUpdateScrollInfoSet);
</del><ins>+    if (!updateScrollInfoAfterLayoutTransactionStack())
+        updateScrollInfoAfterLayoutTransactionStack() = std::make_unique&lt;DelayedUpdateScrollInfoStack&gt;();
+    if (updateScrollInfoAfterLayoutTransactionStack()-&gt;isEmpty() || currentUpdateScrollInfoAfterLayoutTransaction()-&gt;view != &amp;view())
+        updateScrollInfoAfterLayoutTransactionStack()-&gt;append(UpdateScrollInfoAfterLayoutTransaction(view()));
+    ++currentUpdateScrollInfoAfterLayoutTransaction()-&gt;nestedCount;
+}
</ins><span class="cx"> 
</span><del>-        std::unique_ptr&lt;DelayedUpdateScrollInfoSet&gt; infoSet(gDelayedUpdateScrollInfoSet);
-        gDelayedUpdateScrollInfoSet = 0;
</del><ins>+void RenderBlock::endAndCommitUpdateScrollInfoAfterLayoutTransaction()
+{
+    UpdateScrollInfoAfterLayoutTransaction* transaction = currentUpdateScrollInfoAfterLayoutTransaction();
+    ASSERT(transaction);
+    ASSERT(transaction-&gt;view == &amp;view());
+    if (--transaction-&gt;nestedCount)
+        return;
</ins><span class="cx"> 
</span><del>-        for (DelayedUpdateScrollInfoSet::iterator it = infoSet-&gt;begin(); it != infoSet-&gt;end(); ++it) {
-            RenderBlock* block = *it;
-            if (block-&gt;hasOverflowClip()) {
-                block-&gt;layer()-&gt;updateScrollInfoAfterLayout();
-                block-&gt;clearLayoutOverflow();
-            }
-        }
</del><ins>+    // Calling RenderLayer::updateScrollInfoAfterLayout() may cause its associated block to layout again and
+    // updates its scroll info (i.e. call RenderBlock::updateScrollInfoAfterLayout()). We remove |transaction|
+    // from the transaction stack to ensure that all subsequent calls to RenderBlock::updateScrollInfoAfterLayout()
+    // are dispatched immediately. That is, to ensure that such subsequent calls aren't added to |transaction|
+    // while we are processing it.
+    Vector&lt;RenderBlock*&gt; blocksToUpdate;
+    copyToVector(transaction-&gt;blocks, blocksToUpdate);
+    updateScrollInfoAfterLayoutTransactionStack()-&gt;removeLast();
+    if (updateScrollInfoAfterLayoutTransactionStack()-&gt;isEmpty())
+        updateScrollInfoAfterLayoutTransactionStack() = nullptr;
+
+    for (auto* block : blocksToUpdate) {
+        ASSERT(block-&gt;hasOverflowClip());
+        block-&gt;layer()-&gt;updateScrollInfoAfterLayout();
+        block-&gt;clearLayoutOverflow();
</ins><span class="cx">     }
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-void RenderBlock::removeFromDelayedUpdateScrollInfoSet()
</del><ins>+void RenderBlock::removeFromUpdateScrollInfoAfterLayoutTransaction()
</ins><span class="cx"> {
</span><del>-    if (UNLIKELY(gDelayedUpdateScrollInfoSet != 0))
-        gDelayedUpdateScrollInfoSet-&gt;remove(this);
</del><ins>+    if (UNLIKELY(updateScrollInfoAfterLayoutTransactionStack().get() != 0)) {
+        UpdateScrollInfoAfterLayoutTransaction* transaction = currentUpdateScrollInfoAfterLayoutTransaction();
+        ASSERT(transaction);
+        ASSERT(transaction-&gt;view == &amp;view());
+        transaction-&gt;blocks.remove(this);
+    }
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> void RenderBlock::updateScrollInfoAfterLayout()
</span><span class="lines">@@ -967,10 +999,12 @@
</span><span class="cx">             return;
</span><span class="cx">         }
</span><span class="cx"> 
</span><del>-        if (gDelayUpdateScrollInfo)
-            gDelayedUpdateScrollInfoSet-&gt;add(this);
-        else
-            layer()-&gt;updateScrollInfoAfterLayout();
</del><ins>+        UpdateScrollInfoAfterLayoutTransaction* transaction = currentUpdateScrollInfoAfterLayoutTransaction();
+        if (transaction &amp;&amp; transaction-&gt;view == &amp;view()) {
+            transaction-&gt;blocks.add(this);
+            return;
+        }
+        layer()-&gt;updateScrollInfoAfterLayout();
</ins><span class="cx">     }
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -988,7 +1022,9 @@
</span><span class="cx">     
</span><span class="cx">     // It's safe to check for control clip here, since controls can never be table cells.
</span><span class="cx">     // If we have a lightweight clip, there can never be any overflow from children.
</span><del>-    if (hasControlClip() &amp;&amp; m_overflow &amp;&amp; !gDelayUpdateScrollInfo)
</del><ins>+    UpdateScrollInfoAfterLayoutTransaction* transaction = currentUpdateScrollInfoAfterLayoutTransaction();
+    bool isDelayingUpdateScrollInfoAfterLayoutInView = transaction &amp;&amp; transaction-&gt;view == &amp;view();
+    if (hasControlClip() &amp;&amp; m_overflow &amp;&amp; !isDelayingUpdateScrollInfoAfterLayoutInView)
</ins><span class="cx">         clearLayoutOverflow();
</span><span class="cx"> 
</span><span class="cx">     invalidateBackgroundObscurationStatus();
</span></span></pre></div>
<a id="trunkSourceWebCorerenderingRenderBlockh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/rendering/RenderBlock.h (169127 => 169128)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/rendering/RenderBlock.h        2014-05-20 20:21:23 UTC (rev 169127)
+++ trunk/Source/WebCore/rendering/RenderBlock.h        2014-05-20 20:34:35 UTC (rev 169128)
</span><span class="lines">@@ -345,16 +345,15 @@
</span><span class="cx">     virtual int firstLineBaseline() const override;
</span><span class="cx">     virtual int inlineBlockBaseline(LineDirectionMode) const override;
</span><span class="cx"> 
</span><del>-    // Delay update scrollbar until finishDelayRepaint() will be
-    // called. This function is used when a flexbox is laying out its
-    // descendant. If multiple calls are made to startDelayRepaint(),
-    // finishDelayRepaint() will do nothing until finishDelayRepaint()
-    // is called the same number of times.
-    static void startDelayUpdateScrollInfo();
-    static void finishDelayUpdateScrollInfo();
</del><ins>+    // Delay updating scrollbars until endAndCommitUpdateScrollInfoAfterLayoutTransaction() is called. These functions are used
+    // when a flexbox is laying out its descendants. If multiple calls are made to beginUpdateScrollInfoAfterLayoutTransaction()
+    // then endAndCommitUpdateScrollInfoAfterLayoutTransaction() will do nothing until it is called the same number of times.
+    void beginUpdateScrollInfoAfterLayoutTransaction();
+    void endAndCommitUpdateScrollInfoAfterLayoutTransaction();
</ins><span class="cx"> 
</span><ins>+    void removeFromUpdateScrollInfoAfterLayoutTransaction();
+
</ins><span class="cx">     void updateScrollInfoAfterLayout();
</span><del>-    void removeFromDelayedUpdateScrollInfoSet();
</del><span class="cx"> 
</span><span class="cx">     virtual void styleWillChange(StyleDifference, const RenderStyle&amp; newStyle) override;
</span><span class="cx">     virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle) override;
</span></span></pre></div>
<a id="trunkSourceWebCorerenderingRenderBlockFlowcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/rendering/RenderBlockFlow.cpp (169127 => 169128)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/rendering/RenderBlockFlow.cpp        2014-05-20 20:21:23 UTC (rev 169127)
+++ trunk/Source/WebCore/rendering/RenderBlockFlow.cpp        2014-05-20 20:34:35 UTC (rev 169128)
</span><span class="lines">@@ -182,7 +182,7 @@
</span><span class="cx"> 
</span><span class="cx">     m_lineBoxes.deleteLineBoxes();
</span><span class="cx"> 
</span><del>-    removeFromDelayedUpdateScrollInfoSet();
</del><ins>+    removeFromUpdateScrollInfoAfterLayoutTransaction();
</ins><span class="cx"> 
</span><span class="cx">     // NOTE: This jumps down to RenderBox, bypassing RenderBlock since it would do duplicate work.
</span><span class="cx">     RenderBox::willBeDestroyed();
</span></span></pre></div>
<a id="trunkSourceWebCorerenderingRenderDeprecatedFlexibleBoxcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/rendering/RenderDeprecatedFlexibleBox.cpp (169127 => 169128)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/rendering/RenderDeprecatedFlexibleBox.cpp        2014-05-20 20:21:23 UTC (rev 169127)
+++ trunk/Source/WebCore/rendering/RenderDeprecatedFlexibleBox.cpp        2014-05-20 20:34:35 UTC (rev 169128)
</span><span class="lines">@@ -391,7 +391,7 @@
</span><span class="cx">     bool haveFlex = false, flexingChildren = false; 
</span><span class="cx">     gatherFlexChildrenInfo(iterator, relayoutChildren, highestFlexGroup, lowestFlexGroup, haveFlex);
</span><span class="cx"> 
</span><del>-    RenderBlock::startDelayUpdateScrollInfo();
</del><ins>+    beginUpdateScrollInfoAfterLayoutTransaction();
</ins><span class="cx"> 
</span><span class="cx">     ChildLayoutDeltas childLayoutDeltas;
</span><span class="cx">     appendChildLayoutDeltas(this, childLayoutDeltas);
</span><span class="lines">@@ -621,7 +621,7 @@
</span><span class="cx">         }
</span><span class="cx">     } while (haveFlex);
</span><span class="cx"> 
</span><del>-    RenderBlock::finishDelayUpdateScrollInfo();
</del><ins>+    endAndCommitUpdateScrollInfoAfterLayoutTransaction();
</ins><span class="cx"> 
</span><span class="cx">     if (remainingSpace &gt; 0 &amp;&amp; ((style().isLeftToRightDirection() &amp;&amp; style().boxPack() != Start)
</span><span class="cx">         || (!style().isLeftToRightDirection() &amp;&amp; style().boxPack() != End))) {
</span><span class="lines">@@ -698,7 +698,7 @@
</span><span class="cx">     if (haveLineClamp)
</span><span class="cx">         applyLineClamp(iterator, relayoutChildren);
</span><span class="cx"> 
</span><del>-    RenderBlock::startDelayUpdateScrollInfo();
</del><ins>+    beginUpdateScrollInfoAfterLayoutTransaction();
</ins><span class="cx"> 
</span><span class="cx">     ChildLayoutDeltas childLayoutDeltas;
</span><span class="cx">     appendChildLayoutDeltas(this, childLayoutDeltas);
</span><span class="lines">@@ -879,7 +879,7 @@
</span><span class="cx">         }
</span><span class="cx">     } while (haveFlex);
</span><span class="cx"> 
</span><del>-    RenderBlock::finishDelayUpdateScrollInfo();
</del><ins>+    endAndCommitUpdateScrollInfoAfterLayoutTransaction();
</ins><span class="cx"> 
</span><span class="cx">     if (style().boxPack() != Start &amp;&amp; remainingSpace &gt; 0) {
</span><span class="cx">         // Children must be repositioned.
</span></span></pre></div>
<a id="trunkSourceWebCorerenderingRenderFlexibleBoxcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/rendering/RenderFlexibleBox.cpp (169127 => 169128)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/rendering/RenderFlexibleBox.cpp        2014-05-20 20:21:23 UTC (rev 169127)
+++ trunk/Source/WebCore/rendering/RenderFlexibleBox.cpp        2014-05-20 20:34:35 UTC (rev 169128)
</span><span class="lines">@@ -271,7 +271,7 @@
</span><span class="cx"> 
</span><span class="cx">     m_numberOfInFlowChildrenOnFirstLine = -1;
</span><span class="cx"> 
</span><del>-    RenderBlock::startDelayUpdateScrollInfo();
</del><ins>+    beginUpdateScrollInfoAfterLayoutTransaction();
</ins><span class="cx"> 
</span><span class="cx">     dirtyForLayoutFromPercentageHeightDescendants();
</span><span class="cx"> 
</span><span class="lines">@@ -287,7 +287,7 @@
</span><span class="cx">     updateLogicalHeight();
</span><span class="cx">     repositionLogicalHeightDependentFlexItems(lineContexts);
</span><span class="cx"> 
</span><del>-    RenderBlock::finishDelayUpdateScrollInfo();
</del><ins>+    endAndCommitUpdateScrollInfoAfterLayoutTransaction();
</ins><span class="cx"> 
</span><span class="cx">     if (logicalHeight() != previousHeight)
</span><span class="cx">         relayoutChildren = true;
</span></span></pre>
</div>
</div>

</body>
</html>