servo: Merge #13705 - layout: Don't touch the inline positions of block children unless they are to be reflowed (from pcwalton:incremental-float); r=notriddle
authorPatrick Walton <pcwalton@mimiga.net>
Wed, 12 Oct 2016 16:00:37 -0500
changeset 339903 aa53d9352196e3d283c910edb06cbd430b9a419a
parent 339902 442b914ad2ee1234e5886f2e58d3c68bb8b54417
child 339904 9c339f7972bad5b87662d79c3612ec644c142cd4
push id31307
push usergszorc@mozilla.com
push dateSat, 04 Feb 2017 00:59:06 +0000
treeherdermozilla-central@94079d43835f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersnotriddle
servo: Merge #13705 - layout: Don't touch the inline positions of block children unless they are to be reflowed (from pcwalton:incremental-float); r=notriddle See the comment added to `BlockFlow::propagate_assigned_inline_size_to_children()` for details. Closes #13704. r? @notriddle Source-Repo: https://github.com/servo/servo Source-Revision: 0ffbba94fa141f0049c96b3c30dccc22b1b43e6c
servo/components/layout/block.rs
servo/tests/html/incremental_float.html
--- a/servo/components/layout/block.rs
+++ b/servo/components/layout/block.rs
@@ -1385,18 +1385,32 @@ impl BlockFlow {
         let mut iterator = self.base.child_iter_mut().enumerate().peekable();
         while let Some((i, kid)) = iterator.next() {
             flow::mut_base(kid).block_container_explicit_block_size = explicit_content_size;
 
             // The inline-start margin edge of the child flow is at our inline-start content edge,
             // and its inline-size is our content inline-size.
             let kid_mode = flow::base(kid).writing_mode;
             {
+                // Don't assign positions to children unless they're going to be reflowed.
+                // Otherwise, the position we assign might be incorrect and never fixed up. (Issue
+                // #13704.)
+                //
+                // For instance, floats have their true inline position calculated in
+                // `assign_block_size()`, which won't do anything unless `REFLOW` is set. So, if a
+                // float child does not have `REFLOW` set, we must be careful to avoid touching its
+                // inline position, as no logic will run afterward to set its true value.
                 let kid_base = flow::mut_base(kid);
-                if kid_base.flags.contains(INLINE_POSITION_IS_STATIC) {
+                let reflow_damage = if kid_base.flags.contains(IS_ABSOLUTELY_POSITIONED) {
+                    REFLOW_OUT_OF_FLOW
+                } else {
+                    REFLOW
+                };
+                if kid_base.flags.contains(INLINE_POSITION_IS_STATIC) &&
+                        kid_base.restyle_damage.contains(reflow_damage) {
                     kid_base.position.start.i =
                         if kid_mode.is_bidi_ltr() == containing_block_mode.is_bidi_ltr() {
                             inline_start_content_edge
                         } else {
                             // The kid's inline 'start' is at the parent's 'end'
                             inline_end_content_edge
                         };
                 }
new file mode 100644
--- /dev/null
+++ b/servo/tests/html/incremental_float.html
@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<style>
+.float {
+    float: right;
+}
+.bad {
+    display: inline-block;
+    background-color: gray;
+    height: 30px;
+    width: 30px;
+}
+.bad:hover {
+    opacity: .85;
+}
+</style>
+<div class=float>
+    <a class="bad"></a>
+</div>
+<p style="clear: both">Mouse over the preceding gray square. It should change color but remain in place.</p>
+