diff --git a/components/layout/block.rs b/components/layout/block.rs index 2d768b0c55d..4f69a9487d8 100644 --- a/components/layout/block.rs +++ b/components/layout/block.rs @@ -809,7 +809,7 @@ impl BlockFlow { // At this point, `cur_b` is at the content edge of our box. Now iterate over children. let mut floats = self.base.floats.clone(); let thread_id = self.base.thread_id; - let mut had_float_children = false; + let (mut had_floated_children, mut had_children_with_clearance) = (false, false); for (child_index, kid) in self.base.child_iter_mut().enumerate() { if flow::base(kid).flags.contains(IS_ABSOLUTELY_POSITIONED) { // Assume that the *hypothetical box* for an absolute flow starts immediately @@ -845,12 +845,12 @@ impl BlockFlow { // before. flow::mut_base(kid).floats = floats.clone(); if flow::base(kid).flags.is_float() { - had_float_children = true; + had_floated_children = true; flow::mut_base(kid).position.start.b = cur_b; { let kid_block = kid.as_mut_block(); - kid_block.float.as_mut().unwrap().float_ceiling = - margin_collapse_info.current_float_ceiling(); + let float_ceiling = margin_collapse_info.current_float_ceiling(); + kid_block.float.as_mut().unwrap().float_ceiling = float_ceiling } kid.place_float_if_applicable(layout_context); @@ -875,9 +875,17 @@ impl BlockFlow { kid.assign_block_size_for_inorder_child_if_necessary(layout_context, thread_id); + if !had_children_with_clearance && + floats.is_present() && + (flow::base(kid).flags.contains(CLEARS_LEFT) || + flow::base(kid).flags.contains(CLEARS_RIGHT)) { + had_children_with_clearance = true + } + // Handle any (possibly collapsed) top margin. let delta = margin_collapse_info.advance_block_start_margin( - &flow::base(kid).collapsible_margins); + &flow::base(kid).collapsible_margins, + !had_children_with_clearance); translate_including_floats(&mut cur_b, delta, &mut floats); // Clear past the floats that came in, if necessary. @@ -935,7 +943,7 @@ impl BlockFlow { &self.fragment, self.base.block_container_explicit_block_size, can_collapse_block_end_margin_with_kids, - !had_float_children); + !had_floated_children); self.base.collapsible_margins = collapsible_margins; translate_including_floats(&mut cur_b, delta, &mut floats); diff --git a/components/layout/floats.rs b/components/layout/floats.rs index a31d7461db0..63fdc6da796 100644 --- a/components/layout/floats.rs +++ b/components/layout/floats.rs @@ -413,6 +413,10 @@ impl Floats { } clearance } + + pub fn is_present(&self) -> bool { + self.list.is_present() + } } /// The speculated inline sizes of floats flowing through or around a flow (depending on whether diff --git a/components/layout/model.rs b/components/layout/model.rs index 7bb4cf23cbe..ac592bb4139 100644 --- a/components/layout/model.rs +++ b/components/layout/model.rs @@ -18,7 +18,7 @@ use style::values::computed::{BorderRadiusSize, LengthOrPercentageOrAuto}; use style::values::computed::{LengthOrPercentage, LengthOrPercentageOrNone}; /// A collapsible margin. See CSS 2.1 § 8.3.1. -#[derive(Copy, Clone)] +#[derive(Copy, Clone, Debug)] pub struct AdjoiningMargins { /// The value of the greatest positive margin. pub most_positive: Au, @@ -61,7 +61,7 @@ impl AdjoiningMargins { } /// Represents the block-start and block-end margins of a flow with collapsible margins. See CSS 2.1 § 8.3.1. -#[derive(Copy, Clone)] +#[derive(Copy, Clone, Debug)] pub enum CollapsibleMargins { /// Margins may not collapse with this flow. None(Au, Au), @@ -169,12 +169,14 @@ impl MarginCollapseInfo { FinalMarginState::MarginsCollapseThrough => { let advance = self.block_start_margin.collapse(); self.margin_in.union(AdjoiningMargins::from_margin(block_end_margin)); - (CollapsibleMargins::Collapse(self.block_start_margin, self.margin_in), advance) + (CollapsibleMargins::Collapse(self.block_start_margin, self.margin_in), + advance) } FinalMarginState::BottomMarginCollapses => { let advance = self.margin_in.collapse(); self.margin_in.union(AdjoiningMargins::from_margin(block_end_margin)); - (CollapsibleMargins::Collapse(self.block_start_margin, self.margin_in), advance) + (CollapsibleMargins::Collapse(self.block_start_margin, self.margin_in), + advance) } } } else { @@ -206,8 +208,14 @@ impl MarginCollapseInfo { /// Adds the child's potentially collapsible block-start margin to the current margin state and /// advances the Y offset by the appropriate amount to handle that margin. Returns the amount /// that should be added to the Y offset during block layout. - pub fn advance_block_start_margin(&mut self, child_collapsible_margins: &CollapsibleMargins) + pub fn advance_block_start_margin(&mut self, + child_collapsible_margins: &CollapsibleMargins, + can_collapse_block_start_margin: bool) -> Au { + if !can_collapse_block_start_margin { + self.state = MarginCollapseState::AccumulatingMarginIn + } + match (self.state, *child_collapsible_margins) { (MarginCollapseState::AccumulatingCollapsibleTopMargin, CollapsibleMargins::None(block_start, _)) => { @@ -226,14 +234,16 @@ impl MarginCollapseInfo { self.margin_in = AdjoiningMargins::new(); previous_margin_value + block_start } - (MarginCollapseState::AccumulatingMarginIn, CollapsibleMargins::Collapse(block_start, _)) => { + (MarginCollapseState::AccumulatingMarginIn, + CollapsibleMargins::Collapse(block_start, _)) => { self.margin_in.union(block_start); let margin_value = self.margin_in.collapse(); self.margin_in = AdjoiningMargins::new(); margin_value } (_, CollapsibleMargins::CollapseThrough(_)) => { - // For now, we ignore this; this will be handled by `advance_block-end_margin` below. + // For now, we ignore this; this will be handled by `advance_block_end_margin` + // below. Au(0) } } @@ -274,9 +284,11 @@ impl MarginCollapseInfo { } } -#[derive(Copy, Clone)] +#[derive(Copy, Clone, Debug)] pub enum MarginCollapseState { + /// We are accumulating margin on the logical top of this flow. AccumulatingCollapsibleTopMargin, + /// We are accumulating margin between two blocks. AccumulatingMarginIn, } diff --git a/tests/wpt/css-tests/css21_dev/html4/margin-collapse-018.htm b/tests/wpt/css-tests/css21_dev/html4/margin-collapse-018.htm index 54628a0f05a..48df2b5173e 100644 --- a/tests/wpt/css-tests/css21_dev/html4/margin-collapse-018.htm +++ b/tests/wpt/css-tests/css21_dev/html4/margin-collapse-018.htm @@ -51,4 +51,4 @@