mirror of
https://github.com/servo/servo.git
synced 2025-08-03 20:50:07 +01:00
layout: Enhance the heuristic that guesses the inline size of block
formatting contexts. The widths of block formatting contexts depend on the floats prior to them. To avoid a circular dependency between width assignment and height assignment, we must guess their widths during the assign-widths pass. The old code simply used the size of the last float, whether left-floated or right-floated, but this proved insufficient to handle layouts like those seen on Reddit. The new heuristic keeps track of both left and right floats independently and sums the width of all left and right floats to determine the width of a block formatting context. This is still insufficient to properly lay out Reddit, but the results are much more acceptable. A fully correct approach will require that blocks be laid out again if the initial guess proved to be incorrect. A `TODO` is in the code to handle this case.
This commit is contained in:
parent
9fb47b7636
commit
5b4380389e
4 changed files with 151 additions and 30 deletions
|
@ -510,9 +510,13 @@ pub struct BlockFlow {
|
|||
/// Static y offset of an absolute flow from its CB.
|
||||
pub static_b_offset: Au,
|
||||
|
||||
/// The inline-size of the last float prior to this block. This is used to speculatively lay out
|
||||
/// block formatting contexts.
|
||||
previous_float_inline_size: Option<Au>,
|
||||
/// The sum of the inline-sizes of all logically left floats that precede this block. This is
|
||||
/// used to speculatively lay out block formatting contexts.
|
||||
inline_size_of_preceding_left_floats: Au,
|
||||
|
||||
/// The sum of the inline-sizes of all logically right floats that precede this block. This is
|
||||
/// used to speculatively lay out block formatting contexts.
|
||||
inline_size_of_preceding_right_floats: Au,
|
||||
|
||||
/// Additional floating flow members.
|
||||
pub float: Option<Box<FloatedBlockInfo>>
|
||||
|
@ -525,7 +529,8 @@ impl BlockFlow {
|
|||
fragment: Fragment::new(constructor, node),
|
||||
is_root: false,
|
||||
static_b_offset: Au::new(0),
|
||||
previous_float_inline_size: None,
|
||||
inline_size_of_preceding_left_floats: Au(0),
|
||||
inline_size_of_preceding_right_floats: Au(0),
|
||||
float: None
|
||||
}
|
||||
}
|
||||
|
@ -536,7 +541,8 @@ impl BlockFlow {
|
|||
fragment: fragment,
|
||||
is_root: false,
|
||||
static_b_offset: Au::new(0),
|
||||
previous_float_inline_size: None,
|
||||
inline_size_of_preceding_left_floats: Au(0),
|
||||
inline_size_of_preceding_right_floats: Au(0),
|
||||
float: None
|
||||
}
|
||||
}
|
||||
|
@ -550,7 +556,8 @@ impl BlockFlow {
|
|||
fragment: Fragment::new(constructor, node),
|
||||
is_root: false,
|
||||
static_b_offset: Au::new(0),
|
||||
previous_float_inline_size: None,
|
||||
inline_size_of_preceding_left_floats: Au(0),
|
||||
inline_size_of_preceding_right_floats: Au(0),
|
||||
float: Some(box FloatedBlockInfo::new(float_kind)),
|
||||
base: base,
|
||||
}
|
||||
|
@ -565,7 +572,8 @@ impl BlockFlow {
|
|||
fragment: fragment,
|
||||
is_root: false,
|
||||
static_b_offset: Au::new(0),
|
||||
previous_float_inline_size: None,
|
||||
inline_size_of_preceding_left_floats: Au(0),
|
||||
inline_size_of_preceding_right_floats: Au(0),
|
||||
float: Some(box FloatedBlockInfo::new(float_kind)),
|
||||
base: base,
|
||||
}
|
||||
|
@ -1321,11 +1329,17 @@ impl BlockFlow {
|
|||
// This value is used only for table cells.
|
||||
let mut inline_start_margin_edge = inline_start_content_edge;
|
||||
|
||||
// The inline-size of the last float, if there was one. This is used for estimating the
|
||||
// inline-sizes of block formatting contexts. (We estimate that the inline-size of any
|
||||
// block formatting context that we see will be based on the inline-size of the containing
|
||||
// block as well as the last float seen before it.)
|
||||
let mut last_float_inline_size = None;
|
||||
// Remember the inline-sizes of the last left and right floats, if there were any. These
|
||||
// are used for estimating the inline-sizes of block formatting contexts. (We estimate that
|
||||
// the inline-size of any block formatting context that we see will be based on the
|
||||
// inline-size of the containing block as well as the last float seen before it in each
|
||||
// direction.)
|
||||
let mut inline_size_of_preceding_left_floats = Au(0);
|
||||
let mut inline_size_of_preceding_right_floats = Au(0);
|
||||
if self.formatting_context_type() == NonformattingContext {
|
||||
inline_size_of_preceding_left_floats = self.inline_size_of_preceding_left_floats;
|
||||
inline_size_of_preceding_right_floats = self.inline_size_of_preceding_right_floats;
|
||||
}
|
||||
|
||||
// Calculate non-auto block size to pass to children.
|
||||
let content_block_size = self.fragment.style().content_block_size();
|
||||
|
@ -1345,29 +1359,44 @@ impl BlockFlow {
|
|||
let kid_block = kid.as_block();
|
||||
kid_block.base.absolute_static_i_offset = absolute_static_i_offset;
|
||||
kid_block.base.fixed_static_i_offset = fixed_static_i_offset;
|
||||
}
|
||||
|
||||
if kid_block.is_float() {
|
||||
last_float_inline_size = Some(kid_block.base.intrinsic_inline_sizes.preferred_inline_size)
|
||||
} else {
|
||||
kid_block.previous_float_inline_size = last_float_inline_size
|
||||
match kid.float_kind() {
|
||||
float::none => {}
|
||||
float::left => {
|
||||
inline_size_of_preceding_left_floats = inline_size_of_preceding_left_floats +
|
||||
flow::base(kid).intrinsic_inline_sizes.preferred_inline_size;
|
||||
}
|
||||
float::right => {
|
||||
inline_size_of_preceding_right_floats = inline_size_of_preceding_right_floats +
|
||||
flow::base(kid).intrinsic_inline_sizes.preferred_inline_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.
|
||||
// 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.
|
||||
flow::mut_base(kid).position.start.i = inline_start_content_edge;
|
||||
flow::mut_base(kid).position.size.inline = content_inline_size;
|
||||
|
||||
// Determine float impaction.
|
||||
match kid.float_clearance() {
|
||||
clear::none => {}
|
||||
clear::left => inline_start_floats_impact_child = false,
|
||||
clear::right => inline_end_floats_impact_child = false,
|
||||
clear::left => {
|
||||
inline_start_floats_impact_child = false;
|
||||
inline_size_of_preceding_left_floats = Au(0);
|
||||
}
|
||||
clear::right => {
|
||||
inline_end_floats_impact_child = false;
|
||||
inline_size_of_preceding_right_floats = Au(0);
|
||||
}
|
||||
clear::both => {
|
||||
inline_start_floats_impact_child = false;
|
||||
inline_end_floats_impact_child = false;
|
||||
inline_size_of_preceding_left_floats = Au(0);
|
||||
inline_size_of_preceding_right_floats = Au(0);
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
let kid_base = flow::mut_base(kid);
|
||||
inline_start_floats_impact_child = inline_start_floats_impact_child ||
|
||||
|
@ -1378,6 +1407,14 @@ impl BlockFlow {
|
|||
kid_base.flags.set_impacted_by_right_floats(inline_end_floats_impact_child);
|
||||
}
|
||||
|
||||
if kid.is_block_flow() {
|
||||
let kid_block = kid.as_block();
|
||||
kid_block.inline_size_of_preceding_left_floats =
|
||||
inline_size_of_preceding_left_floats;
|
||||
kid_block.inline_size_of_preceding_right_floats =
|
||||
inline_size_of_preceding_right_floats;
|
||||
}
|
||||
|
||||
// Handle tables.
|
||||
match opt_col_inline_sizes {
|
||||
Some(ref col_inline_sizes) => {
|
||||
|
@ -1591,16 +1628,13 @@ impl Flow for BlockFlow {
|
|||
self.base.flags.set_impacted_by_left_floats(false);
|
||||
self.base.flags.set_impacted_by_right_floats(false);
|
||||
|
||||
// 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 float.
|
||||
match self.previous_float_inline_size {
|
||||
None => {}
|
||||
Some(previous_float_inline_size) => {
|
||||
self.fragment.border_box.size.inline =
|
||||
self.fragment.border_box.size.inline - previous_float_inline_size
|
||||
}
|
||||
}
|
||||
// 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.
|
||||
self.fragment.border_box.size.inline =
|
||||
self.fragment.border_box.size.inline -
|
||||
self.inline_size_of_preceding_left_floats -
|
||||
self.inline_size_of_preceding_right_floats;
|
||||
}
|
||||
OtherFormattingContext => {
|
||||
self.base.flags.set_impacted_by_left_floats(false);
|
||||
|
|
|
@ -146,3 +146,4 @@ flaky_gpu,flaky_linux == acid2_noscroll.html acid2_ref_broken.html
|
|||
== block_formatting_context_translation_a.html block_formatting_context_translation_ref.html
|
||||
== floated_table_with_margin_a.html floated_table_with_margin_ref.html
|
||||
== margins_inside_floats_a.html margins_inside_floats_ref.html
|
||||
== block_formatting_context_complex_a.html block_formatting_context_complex_ref.html
|
||||
|
|
43
tests/ref/block_formatting_context_complex_a.html
Normal file
43
tests/ref/block_formatting_context_complex_a.html
Normal file
|
@ -0,0 +1,43 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<style>
|
||||
.a {
|
||||
height: 999999px;
|
||||
color: white;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class=a style="float: right; width: 200px; background: blue;">Meow</div>
|
||||
<div class=a style="float: left; width: 50px; background: orange;">Mimi</div>
|
||||
<div class=a style="float: left; width: 50px; background: green;">the</div>
|
||||
<div class=a style="float: left; width: 50px; background: violet;">cat</div>
|
||||
<div style="overflow: hidden;">
|
||||
There once was an engine named Servo
|
||||
There once was an engine named Servo
|
||||
There once was an engine named Servo
|
||||
There once was an engine named Servo
|
||||
There once was an engine named Servo
|
||||
There once was an engine named Servo
|
||||
There once was an engine named Servo
|
||||
There once was an engine named Servo
|
||||
There once was an engine named Servo
|
||||
There once was an engine named Servo
|
||||
There once was an engine named Servo
|
||||
There once was an engine named Servo
|
||||
There once was an engine named Servo
|
||||
There once was an engine named Servo
|
||||
There once was an engine named Servo
|
||||
There once was an engine named Servo
|
||||
There once was an engine named Servo
|
||||
There once was an engine named Servo
|
||||
There once was an engine named Servo
|
||||
There once was an engine named Servo
|
||||
There once was an engine named Servo
|
||||
There once was an engine named Servo
|
||||
There once was an engine named Servo
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
43
tests/ref/block_formatting_context_complex_ref.html
Normal file
43
tests/ref/block_formatting_context_complex_ref.html
Normal file
|
@ -0,0 +1,43 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<style>
|
||||
.a {
|
||||
height: 999999px;
|
||||
color: white;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class=a style="float: right; width: 200px; background: blue;">Meow</div>
|
||||
<div class=a style="float: left; width: 50px; background: orange;">Mimi</div>
|
||||
<div class=a style="float: left; width: 50px; background: green;">the</div>
|
||||
<div class=a style="float: left; width: 50px; background: violet;">cat</div>
|
||||
<div>
|
||||
There once was an engine named Servo
|
||||
There once was an engine named Servo
|
||||
There once was an engine named Servo
|
||||
There once was an engine named Servo
|
||||
There once was an engine named Servo
|
||||
There once was an engine named Servo
|
||||
There once was an engine named Servo
|
||||
There once was an engine named Servo
|
||||
There once was an engine named Servo
|
||||
There once was an engine named Servo
|
||||
There once was an engine named Servo
|
||||
There once was an engine named Servo
|
||||
There once was an engine named Servo
|
||||
There once was an engine named Servo
|
||||
There once was an engine named Servo
|
||||
There once was an engine named Servo
|
||||
There once was an engine named Servo
|
||||
There once was an engine named Servo
|
||||
There once was an engine named Servo
|
||||
There once was an engine named Servo
|
||||
There once was an engine named Servo
|
||||
There once was an engine named Servo
|
||||
There once was an engine named Servo
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
Loading…
Add table
Add a link
Reference in a new issue