diff --git a/components/layout/block.rs b/components/layout/block.rs index 2b7f17729df7..1c7925feb0ec 100644 --- a/components/layout/block.rs +++ b/components/layout/block.rs @@ -1666,33 +1666,40 @@ impl BlockFlow { // Now compute the real value. self.propagate_and_compute_used_inline_size(shared_context); - // Now for some speculation. - match self.formatting_context_type() { - FormattingContextType::Block => { - // We can't actually compute the inline-size of this block now, because floats - // might affect it. Speculate that its inline-size is equal to the inline-size - // computed above minus the inline-size of the previous left and/or right floats. - // - // (If `max-width` is set, then don't perform this speculation. We guess that the - // page set `max-width` in order to avoid hitting floats. The search box on Google - // SERPs falls into this category.) - if self.fragment.style.max_inline_size() == LengthOrPercentageOrNone::None { - let speculated_left_float_size = - max(Au(0), - self.base.speculated_float_placement_in.left - - self.fragment.margin.inline_start); - let speculated_right_float_size = - max(Au(0), - self.base.speculated_float_placement_in.right - - self.fragment.margin.inline_end); - self.fragment.border_box.size.inline = - self.fragment.border_box.size.inline - - speculated_left_float_size - - speculated_right_float_size; - } - } - FormattingContextType::None | FormattingContextType::Other => {} + self.guess_inline_size_for_block_formatting_context_if_necessary() + } + + fn guess_inline_size_for_block_formatting_context_if_necessary(&mut self) { + // We don't need to guess anything unless this is a block formatting context. + if self.formatting_context_type() != FormattingContextType::Block { + return + } + + // If `max-width` is set, then don't perform this speculation. We guess that the + // page set `max-width` in order to avoid hitting floats. The search box on Google + // SERPs falls into this category. + if self.fragment.style.max_inline_size() != LengthOrPercentageOrNone::None { + return } + + // At this point, we know we can't precisely compute the inline-size of this block now, + // because floats might affect it. Speculate that its inline-size is equal to the + // inline-size computed above minus the inline-size of the previous left and/or right + // floats. + let speculated_left_float_size = if self.fragment.margin.inline_start >= Au(0) && + self.base.speculated_float_placement_in.left > self.fragment.margin.inline_start { + self.base.speculated_float_placement_in.left - self.fragment.margin.inline_start + } else { + Au(0) + }; + let speculated_right_float_size = if self.fragment.margin.inline_end >= Au(0) && + self.base.speculated_float_placement_in.right > self.fragment.margin.inline_end { + self.base.speculated_float_placement_in.right - self.fragment.margin.inline_end + } else { + Au(0) + }; + self.fragment.border_box.size.inline = self.fragment.border_box.size.inline - + speculated_left_float_size - speculated_right_float_size } fn definitely_has_zero_block_size(&self) -> bool { diff --git a/tests/wpt/mozilla/meta/MANIFEST.json b/tests/wpt/mozilla/meta/MANIFEST.json index ec188e4011fc..dc9d239eac0d 100644 --- a/tests/wpt/mozilla/meta/MANIFEST.json +++ b/tests/wpt/mozilla/meta/MANIFEST.json @@ -652,6 +652,18 @@ "url": "/_mozilla/css/block_formatting_context_max_width_a.html" } ], + "css/block_formatting_context_negative_margins_a.html": [ + { + "path": "css/block_formatting_context_negative_margins_a.html", + "references": [ + [ + "/_mozilla/css/block_formatting_context_negative_margins_ref.html", + "==" + ] + ], + "url": "/_mozilla/css/block_formatting_context_negative_margins_a.html" + } + ], "css/block_formatting_context_overflow_a.html": [ { "path": "css/block_formatting_context_overflow_a.html", @@ -10058,6 +10070,18 @@ "url": "/_mozilla/css/block_formatting_context_max_width_a.html" } ], + "css/block_formatting_context_negative_margins_a.html": [ + { + "path": "css/block_formatting_context_negative_margins_a.html", + "references": [ + [ + "/_mozilla/css/block_formatting_context_negative_margins_ref.html", + "==" + ] + ], + "url": "/_mozilla/css/block_formatting_context_negative_margins_a.html" + } + ], "css/block_formatting_context_overflow_a.html": [ { "path": "css/block_formatting_context_overflow_a.html", diff --git a/tests/wpt/mozilla/tests/css/block_formatting_context_negative_margins_a.html b/tests/wpt/mozilla/tests/css/block_formatting_context_negative_margins_a.html new file mode 100644 index 000000000000..41bc3ccabb58 --- /dev/null +++ b/tests/wpt/mozilla/tests/css/block_formatting_context_negative_margins_a.html @@ -0,0 +1,69 @@ + + + + + + Servo test case: wrong block width with negative margins and overflow + + + + + +
+

Servo test case: wrong block width with negative margins and overflow

+ +
+

With width: auto

+

The following blocks have negative margins on the sides. They + should end up being as large as the red container, with their left and +right borders should overlap the container’s border.

+

In Servo Nightly 0.0.1-e3d946b (2016-09-16), when the value of overflow is not visible, the rendered width is wrong (as if a box-sizing: border-box; width: 100%; had been applied).

+
+
+
+
+
+
+ +
+

With box-sizing: border-box; width: 100%

+

If we do use box-sizing: border-box; width: 100%;, for the overflow: visible block we get the expected rendering, but for the other values the width is wrong once again.

+
+
+
+
+
+
+ +
+ + + + + diff --git a/tests/wpt/mozilla/tests/css/block_formatting_context_negative_margins_ref.html b/tests/wpt/mozilla/tests/css/block_formatting_context_negative_margins_ref.html new file mode 100644 index 000000000000..058da5f64f39 --- /dev/null +++ b/tests/wpt/mozilla/tests/css/block_formatting_context_negative_margins_ref.html @@ -0,0 +1,69 @@ + + + + + + Servo test case: wrong block width with negative margins and overflow + + + + +
+

Servo test case: wrong block width with negative margins and overflow

+ +
+

With width: auto

+

The following blocks have negative margins on the sides. They + should end up being as large as the red container, with their left and +right borders should overlap the container’s border.

+

In Servo Nightly 0.0.1-e3d946b (2016-09-16), when the value of overflow is not visible, the rendered width is wrong (as if a box-sizing: border-box; width: 100%; had been applied).

+
+
+
+
+
+
+ +
+

With box-sizing: border-box; width: 100%

+

If we do use box-sizing: border-box; width: 100%;, for the overflow: visible block we get the expected rendering, but for the other values the width is wrong once again.

+
+
+
+
+
+
+ +
+ + + + + +