diff options
author | Martin Robinson <mrobinson@igalia.com> | 2024-04-17 16:15:06 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-04-17 14:15:06 +0000 |
commit | 4ec61c2cdc46d73a3047f4f7e2454465e022420c (patch) | |
tree | ce34e5c356eb941a1e286389303a297aedcb2a3d /components | |
parent | 83dec920dd5cd0cd3907a794e79c826b6521c054 (diff) | |
download | servo-4ec61c2cdc46d73a3047f4f7e2454465e022420c.tar.gz servo-4ec61c2cdc46d73a3047f4f7e2454465e022420c.zip |
layout: Add support for `clear` on `<br>` elements (#32094)
`<br>` elements are a bit "special" in the sense that they defer a
linebreak, but can also have `clear` applied to them. The `clear` that
they supply should be applie *after* the linebreak is processed. This
change adds special processing for this situation.
Fixes #15402.
Diffstat (limited to 'components')
-rw-r--r-- | components/layout_2020/flow/inline.rs | 36 |
1 files changed, 34 insertions, 2 deletions
diff --git a/components/layout_2020/flow/inline.rs b/components/layout_2020/flow/inline.rs index 247ae3542c4..8ab22124b2a 100644 --- a/components/layout_2020/flow/inline.rs +++ b/components/layout_2020/flow/inline.rs @@ -82,7 +82,7 @@ use style::computed_values::white_space::T as WhiteSpace; use style::context::QuirksMode; use style::logical_geometry::WritingMode; use style::properties::ComputedValues; -use style::values::computed::Length; +use style::values::computed::{Clear, Length}; use style::values::generics::box_::VerticalAlignKeyword; use style::values::generics::font::LineHeight; use style::values::specified::box_::BaselineSource; @@ -640,6 +640,11 @@ pub(super) struct InlineFormattingContextState<'a, 'b> { /// [`InlineFormattingContextState::finish_inline_box()`]. linebreak_before_new_content: bool, + /// When a `<br>` element has `clear`, this needs to be applied after the linebreak, + /// which will be processed *after* the `<br>` element is processed. This member + /// stores any deferred `clear` to apply after a linebreak. + deferred_br_clear: Clear, + /// Whether or not a soft wrap opportunity is queued. Soft wrap opportunities are /// queued after replaced content and they are processed when the next text content /// is encountered. @@ -733,6 +738,20 @@ impl<'a, 'b> InlineFormattingContextState<'a, 'b> { .into() } + // If we are starting a `<br>` element prepare to clear after its deferred linebreak has been + // processed. Note that a `<br>` is composed of the element itself and the inner pseudo-element + // with the actual linebreak. Both will have this `FragmentFlag`; that's why this code only + // sets `deferred_br_clear` if it isn't set yet. + if inline_box_state + .base_fragment_info + .flags + .contains(FragmentFlags::IS_BR_ELEMENT) + { + if self.deferred_br_clear == Clear::None { + self.deferred_br_clear = inline_box_state.base.style.clone_clear(); + } + } + let line_item = inline_box_state .layout_into_line_item(inline_box.is_first_fragment, inline_box.is_last_fragment); self.push_line_item_to_unbreakable_segment(LineItem::StartInlineBox(line_item)); @@ -817,12 +836,24 @@ impl<'a, 'b> InlineFormattingContextState<'a, 'b> { LineBlockSizes::zero() }; - let block_end_position = block_start_position + effective_block_advance.resolve().into(); + let resolved_block_advance = effective_block_advance.resolve().into(); + let mut block_end_position = block_start_position + resolved_block_advance; if let Some(sequential_layout_state) = self.sequential_layout_state.as_mut() { // This amount includes both the block size of the line and any extra space // added to move the line down in order to avoid overlapping floats. let increment = block_end_position - self.current_line.start_position.block.into(); sequential_layout_state.advance_block_position(increment); + + // This newline may have been triggered by a `<br>` with clearance, in which case we + // want to make sure that we make space not only for the current line, but any clearance + // from floats. + if let Some(clearance) = sequential_layout_state + .calculate_clearance(self.deferred_br_clear, &CollapsedMargin::zero()) + { + sequential_layout_state.advance_block_position(clearance); + block_end_position += clearance; + }; + self.deferred_br_clear = Clear::None; } let mut line_items = std::mem::take(&mut self.current_line.line_items); @@ -1624,6 +1655,7 @@ impl InlineFormattingContext { inline_box_state_stack: Vec::new(), current_line_segment: UnbreakableSegmentUnderConstruction::new(), linebreak_before_new_content: false, + deferred_br_clear: Clear::None, have_deferred_soft_wrap_opportunity: false, prevent_soft_wrap_opportunity_before_next_atomic: false, had_inflow_content: false, |