diff --git a/crates/web/core/src/css/layout/flow/block.rs b/crates/web/core/src/css/layout/flow/block.rs index fc652012..fe01281e 100644 --- a/crates/web/core/src/css/layout/flow/block.rs +++ b/crates/web/core/src/css/layout/flow/block.rs @@ -295,9 +295,29 @@ impl<'box_tree, 'formatting_context> BlockFlowState<'box_tree, 'formatting_conte } } + fn respect_clearance(&mut self, clear: &values::Clear) { + let clear_to = match clear { + values::Clear::Left => self.block_formatting_context.float_context.clear_left(), + values::Clear::Right => self.block_formatting_context.float_context.clear_right(), + values::Clear::Both => self.block_formatting_context.float_context.clear_both(), + _ => return, + }; + + log::info!("cursor {:?}, clear to {:?}", self.cursor.y, clear_to); + if self.cursor.y < clear_to { + // Introduce "clearance". + // This prevents margin collapse + self.block_formatting_context.prevent_margin_collapse(); + + self.cursor.y = clear_to; + } + } + pub fn visit_block_box(&mut self, block_box: &'box_tree BlockLevelBox) { match block_box { BlockLevelBox::Floating(float_box) => { + self.respect_clearance(float_box.style.clear()); + // Floats are placed at or below the flow position self.block_formatting_context .float_context @@ -312,6 +332,8 @@ impl<'box_tree, 'formatting_context> BlockFlowState<'box_tree, 'formatting_conte self.fragments_so_far.push(box_fragment.into()) }, BlockLevelBox::InFlow(in_flow_box) => { + self.respect_clearance(in_flow_box.style.clear()); + // Every block box creates exactly one box fragment let box_fragment = in_flow_box.fragment( self.cursor, diff --git a/crates/web/core/src/css/layout/flow/float.rs b/crates/web/core/src/css/layout/flow/float.rs index c55c473e..5fabd29d 100644 --- a/crates/web/core/src/css/layout/flow/float.rs +++ b/crates/web/core/src/css/layout/flow/float.rs @@ -176,6 +176,9 @@ pub struct FloatContext { /// Describes how the available space is reduced by floating elements content_bands: Vec, + + lowest_float_left: Pixels, + lowest_float_right: Pixels, } impl FloatContext { @@ -193,9 +196,26 @@ impl FloatContext { float_ceiling: Pixels::ZERO, containing_block, content_bands: vec![content_band], + lowest_float_left: Pixels::ZERO, + lowest_float_right: Pixels::ZERO, } } + #[must_use] + pub fn clear_left(&self) -> Pixels { + self.lowest_float_left + } + + #[must_use] + pub fn clear_right(&self) -> Pixels { + self.lowest_float_right + } + + #[must_use] + pub fn clear_both(&self) -> Pixels { + self.lowest_float_left.max(self.lowest_float_right) + } + pub fn lower_float_ceiling(&mut self, new_ceiling: Pixels) { self.float_ceiling = new_ceiling; } @@ -250,6 +270,15 @@ impl FloatContext { // Lower the float ceiling: New floats may not appear above this box self.lower_float_ceiling(placement.position.y); + + match side { + Side::Left => { + self.lowest_float_left = placement.position.y + margin_area.height; + }, + Side::Right => { + self.lowest_float_right = placement.position.y + margin_area.height; + }, + } } fn find_position_for_float(&self, float_width: Pixels, side: Side) -> Placement {