1pub mod construct;
72pub mod inline_box;
73pub mod line;
74mod line_breaker;
75pub mod text_run;
76
77use std::cell::{OnceCell, RefCell};
78use std::mem;
79use std::rc::Rc;
80use std::sync::Arc;
81
82use app_units::{Au, MAX_AU};
83use bitflags::bitflags;
84use construct::InlineFormattingContextBuilder;
85use fonts::{FontMetrics, FontRef, GlyphStore};
86use icu_segmenter::{LineBreakOptions, LineBreakStrictness, LineBreakWordOption};
87use inline_box::{InlineBox, InlineBoxContainerState, InlineBoxIdentifier, InlineBoxes};
88use layout_api::wrapper_traits::SharedSelection;
89use line::{
90 AbsolutelyPositionedLineItem, AtomicLineItem, FloatLineItem, LineItem, LineItemLayout,
91 TextRunLineItem,
92};
93use line_breaker::LineBreaker;
94use malloc_size_of_derive::MallocSizeOf;
95use script::layout_dom::ServoThreadSafeLayoutNode;
96use servo_arc::Arc as ServoArc;
97use style::Zero;
98use style::computed_values::line_break::T as LineBreak;
99use style::computed_values::text_wrap_mode::T as TextWrapMode;
100use style::computed_values::white_space_collapse::T as WhiteSpaceCollapse;
101use style::computed_values::word_break::T as WordBreak;
102use style::context::{QuirksMode, SharedStyleContext};
103use style::properties::ComputedValues;
104use style::properties::style_structs::InheritedText;
105use style::values::computed::BaselineShift;
106use style::values::generics::box_::BaselineShiftKeyword;
107use style::values::generics::font::LineHeight;
108use style::values::specified::box_::BaselineSource;
109use style::values::specified::text::TextAlignKeyword;
110use style::values::specified::{AlignmentBaseline, TextAlignLast, TextJustify};
111use text_run::{
112 TextRun, XI_LINE_BREAKING_CLASS_GL, XI_LINE_BREAKING_CLASS_WJ, XI_LINE_BREAKING_CLASS_ZWJ,
113 get_font_for_first_font_for_style,
114};
115use unicode_bidi::{BidiInfo, Level};
116use xi_unicode::linebreak_property;
117
118use super::float::{Clear, PlacementAmongFloats};
119use super::{CacheableLayoutResult, IndependentFloatOrAtomicLayoutResult};
120use crate::cell::{ArcRefCell, WeakRefCell};
121use crate::context::LayoutContext;
122use crate::dom::WeakLayoutBox;
123use crate::dom_traversal::NodeAndStyleInfo;
124use crate::flow::float::{FloatBox, SequentialLayoutState};
125use crate::flow::inline::line::TextRunOffsets;
126use crate::flow::{
127 BlockLevelBox, CollapsibleWithParentStartMargin, FloatSide, PlacementState,
128 compute_inline_content_sizes_for_block_level_boxes, layout_block_level_child,
129};
130use crate::formatting_contexts::{Baselines, IndependentFormattingContext};
131use crate::fragment_tree::{
132 BoxFragment, CollapsedMargin, Fragment, FragmentFlags, PositioningFragment,
133};
134use crate::geom::{LogicalRect, LogicalSides1D, LogicalVec2, ToLogical};
135use crate::layout_box_base::LayoutBoxBase;
136use crate::positioned::{AbsolutelyPositionedBox, PositioningContext};
137use crate::sizing::{ComputeInlineContentSizes, ContentSizes, InlineContentSizesResult};
138use crate::style_ext::{ComputedValuesExt, PaddingBorderMargin};
139use crate::{ConstraintSpace, ContainingBlock, IndefiniteContainingBlock, SharedStyle};
140
141static FONT_SUBSCRIPT_OFFSET_RATIO: f32 = 0.20;
143static FONT_SUPERSCRIPT_OFFSET_RATIO: f32 = 0.34;
144
145#[derive(Debug, MallocSizeOf)]
146pub(crate) struct InlineFormattingContext {
147 inline_items: Vec<InlineItem>,
152
153 inline_boxes: InlineBoxes,
156
157 text_content: String,
159
160 shared_inline_styles: SharedInlineStyles,
163
164 has_first_formatted_line: bool,
167
168 pub(super) contains_floats: bool,
170
171 is_single_line_text_input: bool,
174
175 has_right_to_left_content: bool,
178
179 #[ignore_malloc_size_of = "This is stored primarily in the DOM"]
182 shared_selection: Option<SharedSelection>,
183}
184
185#[derive(Clone, Debug, MallocSizeOf)]
190pub(crate) struct SharedInlineStyles {
191 pub style: SharedStyle,
192 pub selected: SharedStyle,
193}
194
195impl SharedInlineStyles {
196 pub(crate) fn ptr_eq(&self, other: &Self) -> bool {
197 self.style.ptr_eq(&other.style) && self.selected.ptr_eq(&other.selected)
198 }
199
200 pub(crate) fn from_info_and_context(info: &NodeAndStyleInfo, context: &LayoutContext) -> Self {
201 Self {
202 style: SharedStyle::new(info.style.clone()),
203 selected: SharedStyle::new(info.node.selected_style(&context.style_context)),
204 }
205 }
206}
207
208impl BlockLevelBox {
209 fn layout_into_line_items(&self, layout: &mut InlineFormattingContextLayout) {
210 layout.process_soft_wrap_opportunity();
211 layout.commit_current_segment_to_line();
212 layout.process_line_break(true);
213 layout.current_line.for_block_level = true;
214
215 let fragment = layout_block_level_child(
216 layout.layout_context,
217 layout.positioning_context,
218 self,
219 layout.sequential_layout_state.as_deref_mut(),
220 &mut layout.placement_state,
221 LogicalSides1D::new(false, false),
223 true, );
225
226 let Fragment::Box(fragment) = fragment else {
227 unreachable!("The fragment should be a Fragment::Box()");
228 };
229
230 layout.depends_on_block_constraints |= fragment.borrow().base.flags.contains(
233 FragmentFlags::SIZE_DEPENDS_ON_BLOCK_CONSTRAINTS_AND_CAN_BE_CHILD_OF_FLEX_ITEM,
234 );
235
236 layout.push_line_item_to_unbreakable_segment(LineItem::BlockLevel(
237 layout.current_inline_box_identifier(),
238 fragment,
239 ));
240
241 layout.commit_current_segment_to_line();
242 layout.process_line_break(true);
243 layout.current_line.for_block_level = false;
244 }
245}
246
247#[derive(Clone, Debug, MallocSizeOf)]
248pub(crate) enum InlineItem {
249 StartInlineBox(ArcRefCell<InlineBox>),
250 EndInlineBox,
251 TextRun(ArcRefCell<TextRun>),
252 OutOfFlowAbsolutelyPositionedBox(
253 ArcRefCell<AbsolutelyPositionedBox>,
254 usize, ),
256 OutOfFlowFloatBox(ArcRefCell<FloatBox>),
257 Atomic(
258 ArcRefCell<IndependentFormattingContext>,
259 usize, Level, ),
262 BlockLevel(ArcRefCell<BlockLevelBox>),
263}
264
265impl InlineItem {
266 pub(crate) fn repair_style(
267 &self,
268 context: &SharedStyleContext,
269 node: &ServoThreadSafeLayoutNode,
270 new_style: &ServoArc<ComputedValues>,
271 ) {
272 match self {
273 InlineItem::StartInlineBox(inline_box) => {
274 inline_box
275 .borrow_mut()
276 .repair_style(context, node, new_style);
277 },
278 InlineItem::EndInlineBox => {},
279 InlineItem::TextRun(..) => {},
282 InlineItem::OutOfFlowAbsolutelyPositionedBox(positioned_box, ..) => positioned_box
283 .borrow_mut()
284 .context
285 .repair_style(context, node, new_style),
286 InlineItem::OutOfFlowFloatBox(float_box) => float_box
287 .borrow_mut()
288 .contents
289 .repair_style(context, node, new_style),
290 InlineItem::Atomic(atomic, ..) => {
291 atomic.borrow_mut().repair_style(context, node, new_style)
292 },
293 InlineItem::BlockLevel(block_level) => block_level
294 .borrow_mut()
295 .repair_style(context, node, new_style),
296 }
297 }
298
299 pub(crate) fn with_base<T>(&self, callback: impl FnOnce(&LayoutBoxBase) -> T) -> T {
300 match self {
301 InlineItem::StartInlineBox(inline_box) => callback(&inline_box.borrow().base),
302 InlineItem::EndInlineBox | InlineItem::TextRun(..) => {
303 unreachable!("Should never have these kind of fragments attached to a DOM node")
304 },
305 InlineItem::OutOfFlowAbsolutelyPositionedBox(positioned_box, ..) => {
306 callback(&positioned_box.borrow().context.base)
307 },
308 InlineItem::OutOfFlowFloatBox(float_box) => callback(&float_box.borrow().contents.base),
309 InlineItem::Atomic(independent_formatting_context, ..) => {
310 callback(&independent_formatting_context.borrow().base)
311 },
312 InlineItem::BlockLevel(block_level) => block_level.borrow().with_base(callback),
313 }
314 }
315
316 pub(crate) fn with_base_mut<T>(&self, callback: impl FnOnce(&mut LayoutBoxBase) -> T) -> T {
317 match self {
318 InlineItem::StartInlineBox(inline_box) => callback(&mut inline_box.borrow_mut().base),
319 InlineItem::EndInlineBox | InlineItem::TextRun(..) => {
320 unreachable!("Should never have these kind of fragments attached to a DOM node")
321 },
322 InlineItem::OutOfFlowAbsolutelyPositionedBox(positioned_box, ..) => {
323 callback(&mut positioned_box.borrow_mut().context.base)
324 },
325 InlineItem::OutOfFlowFloatBox(float_box) => {
326 callback(&mut float_box.borrow_mut().contents.base)
327 },
328 InlineItem::Atomic(independent_formatting_context, ..) => {
329 callback(&mut independent_formatting_context.borrow_mut().base)
330 },
331 InlineItem::BlockLevel(block_level) => block_level.borrow_mut().with_base_mut(callback),
332 }
333 }
334
335 pub(crate) fn attached_to_tree(&self, layout_box: WeakLayoutBox) {
336 match self {
337 Self::StartInlineBox(_) | InlineItem::EndInlineBox => {
338 },
341 Self::TextRun(_) => {
342 },
344 Self::OutOfFlowAbsolutelyPositionedBox(positioned_box, ..) => {
345 positioned_box.borrow().context.attached_to_tree(layout_box)
346 },
347 Self::OutOfFlowFloatBox(float_box) => {
348 float_box.borrow().contents.attached_to_tree(layout_box)
349 },
350 Self::Atomic(atomic, ..) => atomic.borrow().attached_to_tree(layout_box),
351 Self::BlockLevel(block_level) => block_level.borrow().attached_to_tree(layout_box),
352 }
353 }
354
355 pub(crate) fn downgrade(&self) -> WeakInlineItem {
356 match self {
357 Self::StartInlineBox(inline_box) => {
358 WeakInlineItem::StartInlineBox(inline_box.downgrade())
359 },
360 Self::EndInlineBox => WeakInlineItem::EndInlineBox,
361 Self::TextRun(text_run) => WeakInlineItem::TextRun(text_run.downgrade()),
362 Self::OutOfFlowAbsolutelyPositionedBox(positioned_box, offset_in_text) => {
363 WeakInlineItem::OutOfFlowAbsolutelyPositionedBox(
364 positioned_box.downgrade(),
365 *offset_in_text,
366 )
367 },
368 Self::OutOfFlowFloatBox(float_box) => {
369 WeakInlineItem::OutOfFlowFloatBox(float_box.downgrade())
370 },
371 Self::Atomic(atomic, offset_in_text, bidi_level) => {
372 WeakInlineItem::Atomic(atomic.downgrade(), *offset_in_text, *bidi_level)
373 },
374 Self::BlockLevel(block_level) => WeakInlineItem::BlockLevel(block_level.downgrade()),
375 }
376 }
377}
378
379#[derive(Clone, Debug, MallocSizeOf)]
380pub(crate) enum WeakInlineItem {
381 StartInlineBox(WeakRefCell<InlineBox>),
382 EndInlineBox,
383 TextRun(WeakRefCell<TextRun>),
384 OutOfFlowAbsolutelyPositionedBox(
385 WeakRefCell<AbsolutelyPositionedBox>,
386 usize, ),
388 OutOfFlowFloatBox(WeakRefCell<FloatBox>),
389 Atomic(
390 WeakRefCell<IndependentFormattingContext>,
391 usize, Level, ),
394 BlockLevel(WeakRefCell<BlockLevelBox>),
395}
396
397impl WeakInlineItem {
398 pub(crate) fn upgrade(&self) -> Option<InlineItem> {
399 Some(match self {
400 Self::StartInlineBox(inline_box) => InlineItem::StartInlineBox(inline_box.upgrade()?),
401 Self::EndInlineBox => InlineItem::EndInlineBox,
402 Self::TextRun(text_run) => InlineItem::TextRun(text_run.upgrade()?),
403 Self::OutOfFlowAbsolutelyPositionedBox(positioned_box, offset_in_text) => {
404 InlineItem::OutOfFlowAbsolutelyPositionedBox(
405 positioned_box.upgrade()?,
406 *offset_in_text,
407 )
408 },
409 Self::OutOfFlowFloatBox(float_box) => {
410 InlineItem::OutOfFlowFloatBox(float_box.upgrade()?)
411 },
412 Self::Atomic(atomic, offset_in_text, bidi_level) => {
413 InlineItem::Atomic(atomic.upgrade()?, *offset_in_text, *bidi_level)
414 },
415 Self::BlockLevel(block_level) => InlineItem::BlockLevel(block_level.upgrade()?),
416 })
417 }
418}
419
420struct LineUnderConstruction {
427 start_position: LogicalVec2<Au>,
430
431 inline_position: Au,
434
435 max_block_size: LineBlockSizes,
439
440 has_content: bool,
443
444 has_inline_pbm: bool,
447
448 has_floats_waiting_to_be_placed: bool,
452
453 placement_among_floats: OnceCell<LogicalRect<Au>>,
458
459 line_items: Vec<LineItem>,
462
463 for_block_level: bool,
465}
466
467impl LineUnderConstruction {
468 fn new(start_position: LogicalVec2<Au>) -> Self {
469 Self {
470 inline_position: start_position.inline,
471 start_position,
472 max_block_size: LineBlockSizes::zero(),
473 has_content: false,
474 has_inline_pbm: false,
475 has_floats_waiting_to_be_placed: false,
476 placement_among_floats: OnceCell::new(),
477 line_items: Vec::new(),
478 for_block_level: false,
479 }
480 }
481
482 fn replace_placement_among_floats(&mut self, new_placement: LogicalRect<Au>) {
483 self.placement_among_floats.take();
484 let _ = self.placement_among_floats.set(new_placement);
485 }
486
487 fn trim_trailing_whitespace(&mut self) -> Au {
489 let mut whitespace_trimmed = Au::zero();
494 for item in self.line_items.iter_mut().rev() {
495 if !item.trim_whitespace_at_end(&mut whitespace_trimmed) {
496 break;
497 }
498 }
499
500 whitespace_trimmed
501 }
502
503 fn count_justification_opportunities(&self) -> usize {
505 self.line_items
506 .iter()
507 .filter_map(|item| match item {
508 LineItem::TextRun(_, text_run) => Some(
509 text_run
510 .text
511 .iter()
512 .map(|glyph_store| glyph_store.total_word_separators())
513 .sum::<usize>(),
514 ),
515 _ => None,
516 })
517 .sum()
518 }
519
520 fn is_phantom(&self) -> bool {
523 !self.has_content && !self.has_inline_pbm
525 }
526}
527
528#[derive(Clone, Debug)]
534struct BaselineRelativeSize {
535 ascent: Au,
539
540 descent: Au,
544}
545
546impl BaselineRelativeSize {
547 fn zero() -> Self {
548 Self {
549 ascent: Au::zero(),
550 descent: Au::zero(),
551 }
552 }
553
554 fn max(&self, other: &Self) -> Self {
555 BaselineRelativeSize {
556 ascent: self.ascent.max(other.ascent),
557 descent: self.descent.max(other.descent),
558 }
559 }
560
561 fn adjust_for_nested_baseline_offset(&mut self, baseline_offset: Au) {
575 self.ascent -= baseline_offset;
576 self.descent += baseline_offset;
577 }
578}
579
580#[derive(Clone, Debug)]
581struct LineBlockSizes {
582 line_height: Au,
583 baseline_relative_size_for_line_height: Option<BaselineRelativeSize>,
584 size_for_baseline_positioning: BaselineRelativeSize,
585}
586
587impl LineBlockSizes {
588 fn zero() -> Self {
589 LineBlockSizes {
590 line_height: Au::zero(),
591 baseline_relative_size_for_line_height: None,
592 size_for_baseline_positioning: BaselineRelativeSize::zero(),
593 }
594 }
595
596 fn resolve(&self) -> Au {
597 let height_from_ascent_and_descent = self
598 .baseline_relative_size_for_line_height
599 .as_ref()
600 .map(|size| (size.ascent + size.descent).abs())
601 .unwrap_or_else(Au::zero);
602 self.line_height.max(height_from_ascent_and_descent)
603 }
604
605 fn max(&self, other: &LineBlockSizes) -> LineBlockSizes {
606 let baseline_relative_size = match (
607 self.baseline_relative_size_for_line_height.as_ref(),
608 other.baseline_relative_size_for_line_height.as_ref(),
609 ) {
610 (Some(our_size), Some(other_size)) => Some(our_size.max(other_size)),
611 (our_size, other_size) => our_size.or(other_size).cloned(),
612 };
613 Self {
614 line_height: self.line_height.max(other.line_height),
615 baseline_relative_size_for_line_height: baseline_relative_size,
616 size_for_baseline_positioning: self
617 .size_for_baseline_positioning
618 .max(&other.size_for_baseline_positioning),
619 }
620 }
621
622 fn max_assign(&mut self, other: &LineBlockSizes) {
623 *self = self.max(other);
624 }
625
626 fn adjust_for_baseline_offset(&mut self, baseline_offset: Au) {
627 if let Some(size) = self.baseline_relative_size_for_line_height.as_mut() {
628 size.adjust_for_nested_baseline_offset(baseline_offset)
629 }
630 self.size_for_baseline_positioning
631 .adjust_for_nested_baseline_offset(baseline_offset);
632 }
633
634 fn find_baseline_offset(&self) -> Au {
641 match self.baseline_relative_size_for_line_height.as_ref() {
642 Some(size) => size.ascent,
643 None => {
644 let leading = self.resolve() -
647 (self.size_for_baseline_positioning.ascent +
648 self.size_for_baseline_positioning.descent);
649 leading.scale_by(0.5) + self.size_for_baseline_positioning.ascent
650 },
651 }
652 }
653}
654
655struct UnbreakableSegmentUnderConstruction {
659 inline_size: Au,
661
662 max_block_size: LineBlockSizes,
665
666 line_items: Vec<LineItem>,
668
669 inline_box_hierarchy_depth: Option<usize>,
672
673 has_content: bool,
677
678 has_inline_pbm: bool,
681
682 trailing_whitespace_size: Au,
684}
685
686impl UnbreakableSegmentUnderConstruction {
687 fn new() -> Self {
688 Self {
689 inline_size: Au::zero(),
690 max_block_size: LineBlockSizes {
691 line_height: Au::zero(),
692 baseline_relative_size_for_line_height: None,
693 size_for_baseline_positioning: BaselineRelativeSize::zero(),
694 },
695 line_items: Vec::new(),
696 inline_box_hierarchy_depth: None,
697 has_content: false,
698 has_inline_pbm: false,
699 trailing_whitespace_size: Au::zero(),
700 }
701 }
702
703 fn reset(&mut self) {
705 assert!(self.line_items.is_empty()); self.inline_size = Au::zero();
707 self.max_block_size = LineBlockSizes::zero();
708 self.inline_box_hierarchy_depth = None;
709 self.has_content = false;
710 self.has_inline_pbm = false;
711 self.trailing_whitespace_size = Au::zero();
712 }
713
714 fn push_line_item(&mut self, line_item: LineItem, inline_box_hierarchy_depth: usize) {
719 if self.line_items.is_empty() {
720 self.inline_box_hierarchy_depth = Some(inline_box_hierarchy_depth);
721 }
722 self.line_items.push(line_item);
723 }
724
725 fn trim_leading_whitespace(&mut self) {
736 let mut whitespace_trimmed = Au::zero();
737 for item in self.line_items.iter_mut() {
738 if !item.trim_whitespace_at_start(&mut whitespace_trimmed) {
739 break;
740 }
741 }
742 self.inline_size -= whitespace_trimmed;
743 }
744
745 fn is_phantom(&self) -> bool {
748 !self.has_content && !self.has_inline_pbm
750 }
751}
752
753bitflags! {
754 struct InlineContainerStateFlags: u8 {
755 const CREATE_STRUT = 0b0001;
756 const IS_SINGLE_LINE_TEXT_INPUT = 0b0010;
757 }
758}
759
760struct InlineContainerState {
761 style: ServoArc<ComputedValues>,
763
764 flags: InlineContainerStateFlags,
766
767 has_content: RefCell<bool>,
770
771 strut_block_sizes: LineBlockSizes,
776
777 nested_strut_block_sizes: LineBlockSizes,
781
782 pub baseline_offset: Au,
788
789 font_metrics: Arc<FontMetrics>,
791}
792
793struct InlineFormattingContextLayout<'layout_data> {
794 positioning_context: &'layout_data mut PositioningContext,
795 placement_state: PlacementState<'layout_data>,
796 sequential_layout_state: Option<&'layout_data mut SequentialLayoutState>,
797 layout_context: &'layout_data LayoutContext<'layout_data>,
798
799 ifc: &'layout_data InlineFormattingContext,
801
802 root_nesting_level: InlineContainerState,
812
813 inline_box_state_stack: Vec<Rc<InlineBoxContainerState>>,
817
818 inline_box_states: Vec<Rc<InlineBoxContainerState>>,
823
824 fragments: Vec<Fragment>,
828
829 current_line: LineUnderConstruction,
831
832 current_line_segment: UnbreakableSegmentUnderConstruction,
834
835 linebreak_before_new_content: bool,
854
855 deferred_br_clear: Clear,
859
860 pub have_deferred_soft_wrap_opportunity: bool,
864
865 depends_on_block_constraints: bool,
868
869 white_space_collapse: WhiteSpaceCollapse,
874
875 text_wrap_mode: TextWrapMode,
880}
881
882impl InlineFormattingContextLayout<'_> {
883 fn current_inline_container_state(&self) -> &InlineContainerState {
884 match self.inline_box_state_stack.last() {
885 Some(inline_box_state) => &inline_box_state.base,
886 None => &self.root_nesting_level,
887 }
888 }
889
890 fn current_inline_box_identifier(&self) -> Option<InlineBoxIdentifier> {
891 self.inline_box_state_stack
892 .last()
893 .map(|state| state.identifier)
894 }
895
896 fn current_line_max_block_size_including_nested_containers(&self) -> LineBlockSizes {
897 self.current_inline_container_state()
898 .nested_strut_block_sizes
899 .max(&self.current_line.max_block_size)
900 }
901
902 fn current_line_block_start_considering_placement_among_floats(&self) -> Au {
903 self.current_line.placement_among_floats.get().map_or(
904 self.current_line.start_position.block,
905 |placement_among_floats| placement_among_floats.start_corner.block,
906 )
907 }
908
909 fn propagate_current_nesting_level_white_space_style(&mut self) {
910 let style = match self.inline_box_state_stack.last() {
911 Some(inline_box_state) => &inline_box_state.base.style,
912 None => self.placement_state.containing_block.style,
913 };
914 let style_text = style.get_inherited_text();
915 self.white_space_collapse = style_text.white_space_collapse;
916 self.text_wrap_mode = style_text.text_wrap_mode;
917 }
918
919 fn processing_br_element(&self) -> bool {
920 self.inline_box_state_stack.last().is_some_and(|state| {
921 state
922 .base_fragment_info
923 .flags
924 .contains(FragmentFlags::IS_BR_ELEMENT)
925 })
926 }
927
928 fn start_inline_box(&mut self, inline_box: &InlineBox) {
931 let containing_block = self.containing_block();
932 let inline_box_state = InlineBoxContainerState::new(
933 inline_box,
934 containing_block,
935 self.layout_context,
936 self.current_inline_container_state(),
937 inline_box
938 .default_font
939 .as_ref()
940 .map(|font| font.metrics.clone()),
941 );
942
943 self.depends_on_block_constraints |= inline_box
944 .base
945 .style
946 .depends_on_block_constraints_due_to_relative_positioning(
947 containing_block.style.writing_mode,
948 );
949
950 if inline_box_state
955 .base_fragment_info
956 .flags
957 .contains(FragmentFlags::IS_BR_ELEMENT) &&
958 self.deferred_br_clear == Clear::None
959 {
960 self.deferred_br_clear = Clear::from_style_and_container_writing_mode(
961 &inline_box_state.base.style,
962 self.containing_block().style.writing_mode,
963 );
964 }
965
966 let padding = inline_box_state.pbm.padding.inline_start;
967 let border = inline_box_state.pbm.border.inline_start;
968 let margin = inline_box_state.pbm.margin.inline_start.auto_is(Au::zero);
969 if !padding.is_zero() || !border.is_zero() || !margin.is_zero() {
972 self.current_line_segment.has_inline_pbm = true;
973 }
974 self.current_line_segment.inline_size += padding + border + margin;
975 self.current_line_segment
976 .line_items
977 .push(LineItem::InlineStartBoxPaddingBorderMargin(
978 inline_box.identifier,
979 ));
980
981 let inline_box_state = Rc::new(inline_box_state);
982
983 assert_eq!(
987 self.inline_box_states.len(),
988 inline_box.identifier.index_in_inline_boxes as usize
989 );
990 self.inline_box_states.push(inline_box_state.clone());
991 self.inline_box_state_stack.push(inline_box_state);
992 }
993
994 fn finish_inline_box(&mut self) {
997 let inline_box_state = match self.inline_box_state_stack.pop() {
998 Some(inline_box_state) => inline_box_state,
999 None => return, };
1001
1002 self.current_line_segment
1003 .max_block_size
1004 .max_assign(&inline_box_state.base.nested_strut_block_sizes);
1005
1006 if *inline_box_state.base.has_content.borrow() {
1011 self.propagate_current_nesting_level_white_space_style();
1012 }
1013
1014 let padding = inline_box_state.pbm.padding.inline_end;
1015 let border = inline_box_state.pbm.border.inline_end;
1016 let margin = inline_box_state.pbm.margin.inline_end.auto_is(Au::zero);
1017 if !padding.is_zero() || !border.is_zero() || !margin.is_zero() {
1020 self.current_line_segment.has_inline_pbm = true;
1021 }
1022 self.current_line_segment.inline_size += padding + border + margin;
1023 self.current_line_segment
1024 .line_items
1025 .push(LineItem::InlineEndBoxPaddingBorderMargin(
1026 inline_box_state.identifier,
1027 ))
1028 }
1029
1030 fn finish_last_line(&mut self) {
1031 self.process_soft_wrap_opportunity();
1037
1038 self.commit_current_segment_to_line();
1041
1042 self.finish_current_line_and_reset(true );
1045 }
1046
1047 fn finish_current_line_and_reset(&mut self, last_line_or_forced_line_break: bool) {
1051 let whitespace_trimmed = self.current_line.trim_trailing_whitespace();
1052 let (inline_start_position, justification_adjustment) = self
1053 .calculate_current_line_inline_start_and_justification_adjustment(
1054 whitespace_trimmed,
1055 last_line_or_forced_line_break,
1056 );
1057
1058 let is_phantom_line = self.current_line.is_phantom();
1067 if !is_phantom_line {
1068 self.current_line.start_position.block += self.placement_state.current_margin.solve();
1069 self.placement_state.current_margin = CollapsedMargin::zero();
1070 }
1071 let block_start_position =
1072 self.current_line_block_start_considering_placement_among_floats();
1073
1074 let effective_block_advance = if is_phantom_line {
1075 LineBlockSizes::zero()
1076 } else {
1077 self.current_line_max_block_size_including_nested_containers()
1078 };
1079
1080 let resolved_block_advance = effective_block_advance.resolve();
1081 let block_end_position = if self.current_line.for_block_level {
1082 self.placement_state.current_block_direction_position
1083 } else {
1084 let mut block_end_position = block_start_position + resolved_block_advance;
1085 if let Some(sequential_layout_state) = self.sequential_layout_state.as_mut() {
1086 if !is_phantom_line {
1087 sequential_layout_state.collapse_margins();
1088 }
1089
1090 let increment = block_end_position - self.current_line.start_position.block;
1093 sequential_layout_state.advance_block_position(increment);
1094
1095 if let Some(clearance) = sequential_layout_state
1099 .calculate_clearance(self.deferred_br_clear, &CollapsedMargin::zero())
1100 {
1101 sequential_layout_state.advance_block_position(clearance);
1102 block_end_position += clearance;
1103 };
1104 self.deferred_br_clear = Clear::None;
1105 }
1106 block_end_position
1107 };
1108
1109 let mut line_to_layout = std::mem::replace(
1111 &mut self.current_line,
1112 LineUnderConstruction::new(LogicalVec2 {
1113 inline: Au::zero(),
1114 block: block_end_position,
1115 }),
1116 );
1117 if !line_to_layout.for_block_level {
1118 self.placement_state.current_block_direction_position = block_end_position;
1119 }
1120
1121 if line_to_layout.has_floats_waiting_to_be_placed {
1122 place_pending_floats(self, &mut line_to_layout.line_items);
1123 }
1124
1125 let start_position = LogicalVec2 {
1126 block: block_start_position,
1127 inline: inline_start_position,
1128 };
1129
1130 let baseline_offset = effective_block_advance.find_baseline_offset();
1131 let start_positioning_context_length = self.positioning_context.len();
1132 let fragments = LineItemLayout::layout_line_items(
1133 self,
1134 line_to_layout.line_items,
1135 start_position,
1136 &effective_block_advance,
1137 justification_adjustment,
1138 is_phantom_line,
1139 );
1140
1141 if !is_phantom_line {
1142 let baseline = baseline_offset + block_start_position;
1143 self.placement_state
1144 .inflow_baselines
1145 .first
1146 .get_or_insert(baseline);
1147 self.placement_state.inflow_baselines.last = Some(baseline);
1148 self.placement_state
1149 .next_in_flow_margin_collapses_with_parent_start_margin = false;
1150 }
1151
1152 if fragments.is_empty() &&
1154 self.positioning_context.len() == start_positioning_context_length
1155 {
1156 return;
1157 }
1158
1159 let start_corner = LogicalVec2 {
1163 inline: Au::zero(),
1164 block: block_start_position,
1165 };
1166
1167 let logical_origin_in_physical_coordinates =
1168 start_corner.to_physical_vector(self.containing_block().style.writing_mode);
1169 self.positioning_context
1170 .adjust_static_position_of_hoisted_fragments_with_offset(
1171 &logical_origin_in_physical_coordinates,
1172 start_positioning_context_length,
1173 );
1174
1175 let containing_block = self.containing_block();
1176 let physical_line_rect = LogicalRect {
1177 start_corner,
1178 size: LogicalVec2 {
1179 inline: containing_block.size.inline,
1180 block: effective_block_advance.resolve(),
1181 },
1182 }
1183 .as_physical(Some(containing_block));
1184 self.fragments
1185 .push(Fragment::Positioning(PositioningFragment::new_anonymous(
1186 self.root_nesting_level.style.clone(),
1187 physical_line_rect,
1188 fragments,
1189 )));
1190 }
1191
1192 fn calculate_current_line_inline_start_and_justification_adjustment(
1197 &self,
1198 whitespace_trimmed: Au,
1199 last_line_or_forced_line_break: bool,
1200 ) -> (Au, Au) {
1201 enum TextAlign {
1202 Start,
1203 Center,
1204 End,
1205 }
1206 let containing_block = self.containing_block();
1207 let style = containing_block.style;
1208 let mut text_align_keyword = style.clone_text_align();
1209
1210 if last_line_or_forced_line_break {
1211 text_align_keyword = match style.clone_text_align_last() {
1212 TextAlignLast::Auto if text_align_keyword == TextAlignKeyword::Justify => {
1213 TextAlignKeyword::Start
1214 },
1215 TextAlignLast::Auto => text_align_keyword,
1216 TextAlignLast::Start => TextAlignKeyword::Start,
1217 TextAlignLast::End => TextAlignKeyword::End,
1218 TextAlignLast::Left => TextAlignKeyword::Left,
1219 TextAlignLast::Right => TextAlignKeyword::Right,
1220 TextAlignLast::Center => TextAlignKeyword::Center,
1221 TextAlignLast::Justify => TextAlignKeyword::Justify,
1222 };
1223 }
1224
1225 let text_align = match text_align_keyword {
1226 TextAlignKeyword::Start => TextAlign::Start,
1227 TextAlignKeyword::Center | TextAlignKeyword::MozCenter => TextAlign::Center,
1228 TextAlignKeyword::End => TextAlign::End,
1229 TextAlignKeyword::Left | TextAlignKeyword::MozLeft => {
1230 if style.writing_mode.line_left_is_inline_start() {
1231 TextAlign::Start
1232 } else {
1233 TextAlign::End
1234 }
1235 },
1236 TextAlignKeyword::Right | TextAlignKeyword::MozRight => {
1237 if style.writing_mode.line_left_is_inline_start() {
1238 TextAlign::End
1239 } else {
1240 TextAlign::Start
1241 }
1242 },
1243 TextAlignKeyword::Justify => TextAlign::Start,
1244 };
1245
1246 let (line_start, available_space) = match self.current_line.placement_among_floats.get() {
1247 Some(placement_among_floats) => (
1248 placement_among_floats.start_corner.inline,
1249 placement_among_floats.size.inline,
1250 ),
1251 None => (Au::zero(), containing_block.size.inline),
1252 };
1253
1254 let text_indent = self.current_line.start_position.inline;
1261 let line_length = self.current_line.inline_position - whitespace_trimmed - text_indent;
1262 let adjusted_line_start = line_start +
1263 match text_align {
1264 TextAlign::Start => text_indent,
1265 TextAlign::End => (available_space - line_length).max(text_indent),
1266 TextAlign::Center => (available_space - line_length + text_indent)
1267 .scale_by(0.5)
1268 .max(text_indent),
1269 };
1270
1271 let text_justify = containing_block.style.clone_text_justify();
1275 let justification_adjustment = match (text_align_keyword, text_justify) {
1276 (TextAlignKeyword::Justify, TextJustify::None) => Au::zero(),
1279 (TextAlignKeyword::Justify, _) => {
1280 match self.current_line.count_justification_opportunities() {
1281 0 => Au::zero(),
1282 num_justification_opportunities => {
1283 (available_space - text_indent - line_length)
1284 .scale_by(1. / num_justification_opportunities as f32)
1285 },
1286 }
1287 },
1288 _ => Au::zero(),
1289 };
1290
1291 let justification_adjustment = justification_adjustment.max(Au::zero());
1294
1295 (adjusted_line_start, justification_adjustment)
1296 }
1297
1298 fn place_float_fragment(&mut self, fragment: &mut BoxFragment) {
1299 let state = self
1300 .sequential_layout_state
1301 .as_mut()
1302 .expect("Tried to lay out a float with no sequential placement state!");
1303
1304 let block_offset_from_containining_block_top = state
1305 .current_block_position_including_margins() -
1306 state.current_containing_block_offset();
1307 state.place_float_fragment(
1308 fragment,
1309 self.placement_state.containing_block,
1310 CollapsedMargin::zero(),
1311 block_offset_from_containining_block_top,
1312 );
1313 }
1314
1315 fn place_float_line_item_for_commit_to_line(
1324 &mut self,
1325 float_item: &mut FloatLineItem,
1326 line_inline_size_without_trailing_whitespace: Au,
1327 ) {
1328 let containing_block = self.containing_block();
1329 let mut float_fragment = float_item.fragment.borrow_mut();
1330 let logical_margin_rect_size = float_fragment
1331 .margin_rect()
1332 .size
1333 .to_logical(containing_block.style.writing_mode);
1334 let inline_size = logical_margin_rect_size.inline.max(Au::zero());
1335
1336 let available_inline_size = match self.current_line.placement_among_floats.get() {
1337 Some(placement_among_floats) => placement_among_floats.size.inline,
1338 None => containing_block.size.inline,
1339 } - line_inline_size_without_trailing_whitespace;
1340
1341 let has_content = self.current_line.has_content || self.current_line_segment.has_content;
1347 let fits_on_line = !has_content || inline_size <= available_inline_size;
1348 let needs_placement_later =
1349 self.current_line.has_floats_waiting_to_be_placed || !fits_on_line;
1350
1351 if needs_placement_later {
1352 self.current_line.has_floats_waiting_to_be_placed = true;
1353 } else {
1354 self.place_float_fragment(&mut float_fragment);
1355 float_item.needs_placement = false;
1356 }
1357
1358 let new_placement = self.place_line_among_floats(&LogicalVec2 {
1363 inline: line_inline_size_without_trailing_whitespace,
1364 block: self.current_line.max_block_size.resolve(),
1365 });
1366 self.current_line
1367 .replace_placement_among_floats(new_placement);
1368 }
1369
1370 fn place_line_among_floats(&self, potential_line_size: &LogicalVec2<Au>) -> LogicalRect<Au> {
1375 let sequential_layout_state = self
1376 .sequential_layout_state
1377 .as_ref()
1378 .expect("Should not have called this function without having floats.");
1379
1380 let ifc_offset_in_float_container = LogicalVec2 {
1381 inline: sequential_layout_state
1382 .floats
1383 .containing_block_info
1384 .inline_start,
1385 block: sequential_layout_state.current_containing_block_offset(),
1386 };
1387
1388 let ceiling = self.current_line_block_start_considering_placement_among_floats();
1389 let mut placement = PlacementAmongFloats::new(
1390 &sequential_layout_state.floats,
1391 ceiling + ifc_offset_in_float_container.block,
1392 LogicalVec2 {
1393 inline: potential_line_size.inline,
1394 block: potential_line_size.block,
1395 },
1396 &PaddingBorderMargin::zero(),
1397 );
1398
1399 let mut placement_rect = placement.place();
1400 placement_rect.start_corner -= ifc_offset_in_float_container;
1401 placement_rect
1402 }
1403
1404 fn new_potential_line_size_causes_line_break(
1411 &mut self,
1412 potential_line_size: &LogicalVec2<Au>,
1413 ) -> bool {
1414 let containing_block = self.containing_block();
1415 let available_line_space = if self.sequential_layout_state.is_some() {
1416 self.current_line
1417 .placement_among_floats
1418 .get_or_init(|| self.place_line_among_floats(potential_line_size))
1419 .size
1420 } else {
1421 LogicalVec2 {
1422 inline: containing_block.size.inline,
1423 block: MAX_AU,
1424 }
1425 };
1426
1427 let inline_would_overflow = potential_line_size.inline > available_line_space.inline;
1428 let block_would_overflow = potential_line_size.block > available_line_space.block;
1429
1430 let can_break = self.current_line.has_content;
1433
1434 if !can_break {
1440 if self.sequential_layout_state.is_some() &&
1443 (inline_would_overflow || block_would_overflow)
1444 {
1445 let new_placement = self.place_line_among_floats(potential_line_size);
1446 self.current_line
1447 .replace_placement_among_floats(new_placement);
1448 }
1449
1450 return false;
1451 }
1452
1453 if potential_line_size.inline > containing_block.size.inline {
1456 return true;
1457 }
1458
1459 if block_would_overflow {
1463 assert!(self.sequential_layout_state.is_some());
1465 let new_placement = self.place_line_among_floats(potential_line_size);
1466 if new_placement.start_corner.block !=
1467 self.current_line_block_start_considering_placement_among_floats()
1468 {
1469 return true;
1470 } else {
1471 self.current_line
1472 .replace_placement_among_floats(new_placement);
1473 return false;
1474 }
1475 }
1476
1477 inline_would_overflow
1481 }
1482
1483 fn defer_forced_line_break(&mut self) {
1484 if !self.unbreakable_segment_fits_on_line() {
1487 self.process_line_break(false );
1488 }
1489
1490 self.linebreak_before_new_content = true;
1492
1493 let line_is_empty =
1501 !self.current_line_segment.has_content && !self.current_line.has_content;
1502 if !self.processing_br_element() || line_is_empty {
1503 let strut_size = self
1504 .current_inline_container_state()
1505 .strut_block_sizes
1506 .clone();
1507 self.update_unbreakable_segment_for_new_content(
1508 &strut_size,
1509 Au::zero(),
1510 SegmentContentFlags::empty(),
1511 );
1512 }
1513 }
1514
1515 fn possibly_flush_deferred_forced_line_break(&mut self) {
1516 if !self.linebreak_before_new_content {
1517 return;
1518 }
1519
1520 self.commit_current_segment_to_line();
1521 self.process_line_break(true );
1522 self.linebreak_before_new_content = false;
1523 }
1524
1525 fn push_line_item_to_unbreakable_segment(&mut self, line_item: LineItem) {
1526 self.current_line_segment
1527 .push_line_item(line_item, self.inline_box_state_stack.len());
1528 }
1529
1530 fn push_glyph_store_to_unbreakable_segment(
1531 &mut self,
1532 glyph_store: Arc<GlyphStore>,
1533 text_run: &TextRun,
1534 font: &FontRef,
1535 bidi_level: Level,
1536 offsets: Option<TextRunOffsets>,
1537 ) {
1538 let inline_advance = glyph_store.total_advance();
1539 let flags = if glyph_store.is_whitespace() {
1540 SegmentContentFlags::from(text_run.inline_styles.style.borrow().get_inherited_text())
1541 } else {
1542 SegmentContentFlags::empty()
1543 };
1544
1545 let font_metrics = &font.metrics;
1546 let font_key = font.key(
1547 self.layout_context.painter_id,
1548 &self.layout_context.font_context,
1549 );
1550
1551 let mut block_contribution = LineBlockSizes::zero();
1552 let quirks_mode = self.layout_context.style_context.quirks_mode() != QuirksMode::NoQuirks;
1553 if quirks_mode && !flags.is_collapsible_whitespace() {
1554 block_contribution.max_assign(&self.current_inline_container_state().strut_block_sizes);
1559 }
1560
1561 if self
1565 .current_inline_container_state()
1566 .font_metrics
1567 .block_metrics_meaningfully_differ(&font.metrics)
1568 {
1569 let container_state = self.current_inline_container_state();
1571 let baseline_shift = effective_baseline_shift(
1572 &container_state.style,
1573 self.inline_box_state_stack.last().map(|c| &c.base),
1574 );
1575 let mut font_block_conribution = container_state.get_block_size_contribution(
1576 baseline_shift,
1577 font_metrics,
1578 &container_state.font_metrics,
1579 );
1580 font_block_conribution.adjust_for_baseline_offset(container_state.baseline_offset);
1581 block_contribution.max_assign(&font_block_conribution);
1582 }
1583
1584 self.update_unbreakable_segment_for_new_content(&block_contribution, inline_advance, flags);
1585
1586 let current_inline_box_identifier = self.current_inline_box_identifier();
1587 if let Some(LineItem::TextRun(inline_box_identifier, line_item)) =
1588 self.current_line_segment.line_items.last_mut()
1589 {
1590 if *inline_box_identifier == current_inline_box_identifier &&
1591 line_item.merge_if_possible(
1592 font_key,
1593 bidi_level,
1594 &glyph_store,
1595 &offsets,
1596 &text_run.inline_styles,
1597 )
1598 {
1599 return;
1600 }
1601 }
1602
1603 self.push_line_item_to_unbreakable_segment(LineItem::TextRun(
1604 current_inline_box_identifier,
1605 TextRunLineItem {
1606 text: vec![glyph_store],
1607 base_fragment_info: text_run.base_fragment_info,
1608 inline_styles: text_run.inline_styles.clone(),
1609 font_metrics: font_metrics.clone(),
1610 font_key,
1611 bidi_level,
1612 offsets: offsets.map(Box::new),
1613 is_empty_for_text_cursor: false,
1614 },
1615 ));
1616 }
1617
1618 fn possibly_push_empty_text_run_to_unbreakable_segment(
1622 &mut self,
1623 text_run: &TextRun,
1624 font: &FontRef,
1625 bidi_level: Level,
1626 offsets: Option<TextRunOffsets>,
1627 ) {
1628 if offsets.is_none() || self.current_line_segment.has_content {
1629 return;
1630 }
1631
1632 let font_metrics = &font.metrics;
1633 let font_key = font.key(
1634 self.layout_context.painter_id,
1635 &self.layout_context.font_context,
1636 );
1637
1638 self.push_line_item_to_unbreakable_segment(LineItem::TextRun(
1639 self.current_inline_box_identifier(),
1640 TextRunLineItem {
1641 text: Default::default(),
1642 base_fragment_info: text_run.base_fragment_info,
1643 inline_styles: text_run.inline_styles.clone(),
1644 font_metrics: font_metrics.clone(),
1645 font_key,
1646 bidi_level,
1647 offsets: offsets.map(Box::new),
1648 is_empty_for_text_cursor: true,
1649 },
1650 ));
1651 self.current_line_segment.has_content = true;
1652 }
1653
1654 fn update_unbreakable_segment_for_new_content(
1655 &mut self,
1656 block_sizes_of_content: &LineBlockSizes,
1657 inline_size: Au,
1658 flags: SegmentContentFlags,
1659 ) {
1660 if flags.is_collapsible_whitespace() || flags.is_wrappable_and_hangable() {
1661 self.current_line_segment.trailing_whitespace_size = inline_size;
1662 } else {
1663 self.current_line_segment.trailing_whitespace_size = Au::zero();
1664 }
1665 if !flags.is_collapsible_whitespace() {
1666 self.current_line_segment.has_content = true;
1667 }
1668
1669 let container_max_block_size = &self
1671 .current_inline_container_state()
1672 .nested_strut_block_sizes
1673 .clone();
1674 self.current_line_segment
1675 .max_block_size
1676 .max_assign(container_max_block_size);
1677 self.current_line_segment
1678 .max_block_size
1679 .max_assign(block_sizes_of_content);
1680
1681 self.current_line_segment.inline_size += inline_size;
1682
1683 *self
1685 .current_inline_container_state()
1686 .has_content
1687 .borrow_mut() = true;
1688 self.propagate_current_nesting_level_white_space_style();
1689 }
1690
1691 fn process_line_break(&mut self, forced_line_break: bool) {
1692 self.current_line_segment.trim_leading_whitespace();
1693 self.finish_current_line_and_reset(forced_line_break);
1694 }
1695
1696 fn unbreakable_segment_fits_on_line(&mut self) -> bool {
1697 let potential_line_size = LogicalVec2 {
1698 inline: self.current_line.inline_position + self.current_line_segment.inline_size -
1699 self.current_line_segment.trailing_whitespace_size,
1700 block: self
1701 .current_line_max_block_size_including_nested_containers()
1702 .max(&self.current_line_segment.max_block_size)
1703 .resolve(),
1704 };
1705
1706 !self.new_potential_line_size_causes_line_break(&potential_line_size)
1707 }
1708
1709 fn process_soft_wrap_opportunity(&mut self) {
1713 if self.current_line_segment.line_items.is_empty() {
1714 return;
1715 }
1716 if self.text_wrap_mode == TextWrapMode::Nowrap {
1717 return;
1718 }
1719 if !self.unbreakable_segment_fits_on_line() {
1720 self.process_line_break(false );
1721 }
1722 self.commit_current_segment_to_line();
1723 }
1724
1725 fn commit_current_segment_to_line(&mut self) {
1728 if self.current_line_segment.line_items.is_empty() && !self.current_line_segment.has_content
1731 {
1732 return;
1733 }
1734
1735 if !self.current_line.has_content {
1736 self.current_line_segment.trim_leading_whitespace();
1737 }
1738
1739 self.current_line.inline_position += self.current_line_segment.inline_size;
1740 self.current_line.max_block_size = self
1741 .current_line_max_block_size_including_nested_containers()
1742 .max(&self.current_line_segment.max_block_size);
1743 let line_inline_size_without_trailing_whitespace =
1744 self.current_line.inline_position - self.current_line_segment.trailing_whitespace_size;
1745
1746 let mut segment_items = mem::take(&mut self.current_line_segment.line_items);
1748 for item in segment_items.iter_mut() {
1749 if let LineItem::Float(_, float_item) = item {
1750 self.place_float_line_item_for_commit_to_line(
1751 float_item,
1752 line_inline_size_without_trailing_whitespace,
1753 );
1754 }
1755 }
1756
1757 if self.current_line.line_items.is_empty() {
1762 let will_break = self.new_potential_line_size_causes_line_break(&LogicalVec2 {
1763 inline: line_inline_size_without_trailing_whitespace,
1764 block: self.current_line_segment.max_block_size.resolve(),
1765 });
1766 assert!(!will_break);
1767 }
1768
1769 self.current_line.line_items.extend(segment_items);
1770 self.current_line.has_content |= self.current_line_segment.has_content;
1771 self.current_line.has_inline_pbm |= self.current_line_segment.has_inline_pbm;
1772
1773 self.current_line_segment.reset();
1774 }
1775
1776 #[inline]
1777 fn containing_block(&self) -> &ContainingBlock<'_> {
1778 self.placement_state.containing_block
1779 }
1780}
1781
1782bitflags! {
1783 struct SegmentContentFlags: u8 {
1784 const COLLAPSIBLE_WHITESPACE = 0b00000001;
1785 const WRAPPABLE_AND_HANGABLE_WHITESPACE = 0b00000010;
1786 }
1787}
1788
1789impl SegmentContentFlags {
1790 fn is_collapsible_whitespace(&self) -> bool {
1791 self.contains(Self::COLLAPSIBLE_WHITESPACE)
1792 }
1793
1794 fn is_wrappable_and_hangable(&self) -> bool {
1795 self.contains(Self::WRAPPABLE_AND_HANGABLE_WHITESPACE)
1796 }
1797}
1798
1799impl From<&InheritedText> for SegmentContentFlags {
1800 fn from(style_text: &InheritedText) -> Self {
1801 let mut flags = Self::empty();
1802
1803 if !matches!(
1806 style_text.white_space_collapse,
1807 WhiteSpaceCollapse::Preserve | WhiteSpaceCollapse::BreakSpaces
1808 ) {
1809 flags.insert(Self::COLLAPSIBLE_WHITESPACE);
1810 }
1811
1812 if style_text.text_wrap_mode == TextWrapMode::Wrap &&
1815 style_text.white_space_collapse != WhiteSpaceCollapse::BreakSpaces
1816 {
1817 flags.insert(Self::WRAPPABLE_AND_HANGABLE_WHITESPACE);
1818 }
1819 flags
1820 }
1821}
1822
1823impl InlineFormattingContext {
1824 #[servo_tracing::instrument(name = "InlineFormattingContext::new_with_builder", skip_all)]
1825 fn new_with_builder(
1826 mut builder: InlineFormattingContextBuilder,
1827 layout_context: &LayoutContext,
1828 has_first_formatted_line: bool,
1829 is_single_line_text_input: bool,
1830 starting_bidi_level: Level,
1831 ) -> Self {
1832 let text_content: String = builder.text_segments.into_iter().collect();
1834
1835 let bidi_info = BidiInfo::new(&text_content, Some(starting_bidi_level));
1836 let has_right_to_left_content = bidi_info.has_rtl();
1837 let shared_inline_styles = builder
1838 .shared_inline_styles_stack
1839 .last()
1840 .expect("Should have at least one SharedInlineStyle for the root of an IFC")
1841 .clone();
1842 let (word_break, line_break) = {
1843 let styles = shared_inline_styles.style.borrow();
1844 let text_style = styles.get_inherited_text();
1845 (text_style.word_break, text_style.line_break)
1846 };
1847
1848 let mut options = LineBreakOptions::default();
1849
1850 options.strictness = match line_break {
1851 LineBreak::Loose => LineBreakStrictness::Loose,
1852 LineBreak::Normal => LineBreakStrictness::Normal,
1853 LineBreak::Strict => LineBreakStrictness::Strict,
1854 LineBreak::Anywhere => LineBreakStrictness::Anywhere,
1855 LineBreak::Auto => LineBreakStrictness::Normal,
1858 };
1859 options.word_option = match word_break {
1860 WordBreak::Normal => LineBreakWordOption::Normal,
1861 WordBreak::BreakAll => LineBreakWordOption::BreakAll,
1862 WordBreak::KeepAll => LineBreakWordOption::KeepAll,
1863 };
1864 options.ja_zh = false; let mut new_linebreaker = LineBreaker::new(text_content.as_str(), options);
1867 for item in &mut builder.inline_items {
1868 match item {
1869 InlineItem::TextRun(text_run) => {
1870 text_run.borrow_mut().segment_and_shape(
1871 &text_content,
1872 layout_context,
1873 &mut new_linebreaker,
1874 &bidi_info,
1875 );
1876 },
1877 InlineItem::StartInlineBox(inline_box) => {
1878 let inline_box = &mut *inline_box.borrow_mut();
1879 if let Some(font) = get_font_for_first_font_for_style(
1880 &inline_box.base.style,
1881 &layout_context.font_context,
1882 ) {
1883 inline_box.default_font = Some(font);
1884 }
1885 },
1886 InlineItem::Atomic(_, index_in_text, bidi_level) => {
1887 *bidi_level = bidi_info.levels[*index_in_text];
1888 },
1889 InlineItem::OutOfFlowAbsolutelyPositionedBox(..) |
1890 InlineItem::OutOfFlowFloatBox(_) |
1891 InlineItem::EndInlineBox |
1892 InlineItem::BlockLevel { .. } => {},
1893 }
1894 }
1895
1896 InlineFormattingContext {
1897 text_content,
1898 inline_items: builder.inline_items,
1899 inline_boxes: builder.inline_boxes,
1900 shared_inline_styles,
1901 has_first_formatted_line,
1902 contains_floats: builder.contains_floats,
1903 is_single_line_text_input,
1904 has_right_to_left_content,
1905 shared_selection: builder.shared_selection,
1906 }
1907 }
1908
1909 pub(crate) fn repair_style(
1910 &self,
1911 context: &SharedStyleContext,
1912 node: &ServoThreadSafeLayoutNode,
1913 new_style: &ServoArc<ComputedValues>,
1914 ) {
1915 *self.shared_inline_styles.style.borrow_mut() = new_style.clone();
1916 *self.shared_inline_styles.selected.borrow_mut() = node.selected_style(context);
1917 }
1918
1919 fn inline_start_for_first_line(&self, containing_block: IndefiniteContainingBlock) -> Au {
1920 if !self.has_first_formatted_line {
1921 return Au::zero();
1922 }
1923 containing_block
1924 .style
1925 .get_inherited_text()
1926 .text_indent
1927 .length
1928 .to_used_value(containing_block.size.inline.unwrap_or_default())
1929 }
1930
1931 pub(super) fn layout(
1932 &self,
1933 layout_context: &LayoutContext,
1934 positioning_context: &mut PositioningContext,
1935 containing_block: &ContainingBlock,
1936 sequential_layout_state: Option<&mut SequentialLayoutState>,
1937 collapsible_with_parent_start_margin: CollapsibleWithParentStartMargin,
1938 ) -> CacheableLayoutResult {
1939 for inline_box in self.inline_boxes.iter() {
1941 inline_box.borrow().base.clear_fragments();
1942 }
1943
1944 let style = containing_block.style;
1945
1946 let default_font_metrics =
1949 get_font_for_first_font_for_style(style, &layout_context.font_context)
1950 .map(|font| font.metrics.clone());
1951
1952 let style_text = containing_block.style.get_inherited_text();
1953 let mut inline_container_state_flags = InlineContainerStateFlags::empty();
1954 if inline_container_needs_strut(style, layout_context, None) {
1955 inline_container_state_flags.insert(InlineContainerStateFlags::CREATE_STRUT);
1956 }
1957 if self.is_single_line_text_input {
1958 inline_container_state_flags
1959 .insert(InlineContainerStateFlags::IS_SINGLE_LINE_TEXT_INPUT);
1960 }
1961 let placement_state =
1962 PlacementState::new(collapsible_with_parent_start_margin, containing_block);
1963
1964 let mut layout = InlineFormattingContextLayout {
1965 positioning_context,
1966 placement_state,
1967 sequential_layout_state,
1968 layout_context,
1969 ifc: self,
1970 fragments: Vec::new(),
1971 current_line: LineUnderConstruction::new(LogicalVec2 {
1972 inline: self.inline_start_for_first_line(containing_block.into()),
1973 block: Au::zero(),
1974 }),
1975 root_nesting_level: InlineContainerState::new(
1976 style.to_arc(),
1977 inline_container_state_flags,
1978 None, default_font_metrics,
1980 ),
1981 inline_box_state_stack: Vec::new(),
1982 inline_box_states: Vec::with_capacity(self.inline_boxes.len()),
1983 current_line_segment: UnbreakableSegmentUnderConstruction::new(),
1984 linebreak_before_new_content: false,
1985 deferred_br_clear: Clear::None,
1986 have_deferred_soft_wrap_opportunity: false,
1987 depends_on_block_constraints: false,
1988 white_space_collapse: style_text.white_space_collapse,
1989 text_wrap_mode: style_text.text_wrap_mode,
1990 };
1991
1992 for item in self.inline_items.iter() {
1993 if !matches!(item, InlineItem::EndInlineBox) {
1995 layout.possibly_flush_deferred_forced_line_break();
1996 }
1997
1998 match item {
1999 InlineItem::StartInlineBox(inline_box) => {
2000 layout.start_inline_box(&inline_box.borrow());
2001 },
2002 InlineItem::EndInlineBox => layout.finish_inline_box(),
2003 InlineItem::TextRun(run) => run.borrow().layout_into_line_items(&mut layout),
2004 InlineItem::Atomic(atomic_formatting_context, offset_in_text, bidi_level) => {
2005 atomic_formatting_context.borrow().layout_into_line_items(
2006 &mut layout,
2007 *offset_in_text,
2008 *bidi_level,
2009 );
2010 },
2011 InlineItem::OutOfFlowAbsolutelyPositionedBox(positioned_box, _) => {
2012 layout.push_line_item_to_unbreakable_segment(LineItem::AbsolutelyPositioned(
2013 layout.current_inline_box_identifier(),
2014 AbsolutelyPositionedLineItem {
2015 absolutely_positioned_box: positioned_box.clone(),
2016 preceding_line_content_would_produce_phantom_line: layout
2017 .current_line
2018 .is_phantom() &&
2019 layout.current_line_segment.is_phantom(),
2020 },
2021 ));
2022 },
2023 InlineItem::OutOfFlowFloatBox(float_box) => {
2024 float_box.borrow().layout_into_line_items(&mut layout);
2025 },
2026 InlineItem::BlockLevel(block_level) => {
2027 block_level.borrow().layout_into_line_items(&mut layout);
2028 },
2029 }
2030 }
2031
2032 layout.finish_last_line();
2033 let (content_block_size, collapsible_margins_in_children, baselines) =
2034 layout.placement_state.finish();
2035
2036 CacheableLayoutResult {
2037 fragments: layout.fragments,
2038 content_block_size,
2039 collapsible_margins_in_children,
2040 baselines,
2041 depends_on_block_constraints: layout.depends_on_block_constraints,
2042 content_inline_size_for_table: None,
2043 specific_layout_info: None,
2044 }
2045 }
2046
2047 fn next_character_prevents_soft_wrap_opportunity(&self, index: usize) -> bool {
2048 let Some(character) = self.text_content[index..].chars().nth(1) else {
2049 return false;
2050 };
2051 char_prevents_soft_wrap_opportunity_when_before_or_after_atomic(character)
2052 }
2053
2054 fn previous_character_prevents_soft_wrap_opportunity(&self, index: usize) -> bool {
2055 let Some(character) = self.text_content[0..index].chars().next_back() else {
2056 return false;
2057 };
2058 char_prevents_soft_wrap_opportunity_when_before_or_after_atomic(character)
2059 }
2060
2061 pub(crate) fn find_block_margin_collapsing_with_parent(
2062 &self,
2063 layout_context: &LayoutContext,
2064 collected_margin: &mut CollapsedMargin,
2065 containing_block_for_children: &ContainingBlock,
2066 ) -> bool {
2067 let mut nesting_levels_from_nonzero_end_pbm: u32 = 1;
2073 let mut items_iter = self.inline_items.iter();
2074 items_iter.all(|inline_item| match inline_item {
2075 InlineItem::StartInlineBox(inline_box) => {
2076 let pbm = inline_box
2077 .borrow()
2078 .layout_style()
2079 .padding_border_margin(containing_block_for_children);
2080 if pbm.padding.inline_end.is_zero() &&
2081 pbm.border.inline_end.is_zero() &&
2082 pbm.margin.inline_end.auto_is(Au::zero).is_zero()
2083 {
2084 nesting_levels_from_nonzero_end_pbm += 1;
2085 } else {
2086 nesting_levels_from_nonzero_end_pbm = 0;
2087 }
2088 pbm.padding.inline_start.is_zero() &&
2089 pbm.border.inline_start.is_zero() &&
2090 pbm.margin.inline_start.auto_is(Au::zero).is_zero()
2091 },
2092 InlineItem::EndInlineBox => {
2093 if nesting_levels_from_nonzero_end_pbm == 0 {
2094 false
2095 } else {
2096 nesting_levels_from_nonzero_end_pbm -= 1;
2097 true
2098 }
2099 },
2100 InlineItem::TextRun(text_run) => {
2101 let text_run = &*text_run.borrow();
2102 let parent_style = text_run.inline_styles.style.borrow();
2103 text_run.shaped_text.iter().all(|segment| {
2104 segment.runs.iter().all(|run| {
2105 run.is_whitespace() &&
2106 !run.is_single_preserved_newline() &&
2107 !matches!(
2108 parent_style.get_inherited_text().white_space_collapse,
2109 WhiteSpaceCollapse::Preserve | WhiteSpaceCollapse::BreakSpaces
2110 )
2111 })
2112 })
2113 },
2114 InlineItem::OutOfFlowAbsolutelyPositionedBox(..) => true,
2115 InlineItem::OutOfFlowFloatBox(..) => true,
2116 InlineItem::Atomic(..) => false,
2117 InlineItem::BlockLevel(block_level) => block_level
2118 .borrow()
2119 .find_block_margin_collapsing_with_parent(
2120 layout_context,
2121 collected_margin,
2122 containing_block_for_children,
2123 ),
2124 })
2125 }
2126
2127 pub(crate) fn attached_to_tree(&self, layout_box: WeakLayoutBox) {
2128 let mut parent_box_stack = Vec::new();
2129 let current_parent_box = |parent_box_stack: &[WeakLayoutBox]| {
2130 parent_box_stack.last().unwrap_or(&layout_box).clone()
2131 };
2132 for inline_item in &self.inline_items {
2133 match inline_item {
2134 InlineItem::StartInlineBox(inline_box) => {
2135 inline_box
2136 .borrow_mut()
2137 .base
2138 .parent_box
2139 .replace(current_parent_box(&parent_box_stack));
2140 parent_box_stack.push(WeakLayoutBox::InlineLevel(
2141 WeakInlineItem::StartInlineBox(inline_box.downgrade()),
2142 ));
2143 },
2144 InlineItem::EndInlineBox => {
2145 parent_box_stack.pop();
2146 },
2147 InlineItem::TextRun(text_run) => {
2148 text_run
2149 .borrow_mut()
2150 .parent_box
2151 .replace(current_parent_box(&parent_box_stack));
2152 },
2153 _ => inline_item.with_base_mut(|base| {
2154 base.parent_box
2155 .replace(current_parent_box(&parent_box_stack));
2156 }),
2157 }
2158 }
2159 }
2160}
2161
2162impl InlineContainerState {
2163 fn new(
2164 style: ServoArc<ComputedValues>,
2165 flags: InlineContainerStateFlags,
2166 parent_container: Option<&InlineContainerState>,
2167 font_metrics: Option<Arc<FontMetrics>>,
2168 ) -> Self {
2169 let font_metrics = font_metrics.unwrap_or_else(FontMetrics::empty);
2170 let mut baseline_offset = Au::zero();
2171 let mut strut_block_sizes = Self::get_block_sizes_with_style(
2172 effective_baseline_shift(&style, parent_container),
2173 &style,
2174 &font_metrics,
2175 &font_metrics,
2176 &flags,
2177 );
2178 if let Some(parent_container) = parent_container {
2179 baseline_offset = parent_container.get_cumulative_baseline_offset_for_child(
2182 style.clone_alignment_baseline(),
2183 style.clone_baseline_shift(),
2184 &strut_block_sizes,
2185 );
2186 strut_block_sizes.adjust_for_baseline_offset(baseline_offset);
2187 }
2188
2189 let mut nested_block_sizes = parent_container
2190 .map(|container| container.nested_strut_block_sizes.clone())
2191 .unwrap_or_else(LineBlockSizes::zero);
2192 if flags.contains(InlineContainerStateFlags::CREATE_STRUT) {
2193 nested_block_sizes.max_assign(&strut_block_sizes);
2194 }
2195
2196 Self {
2197 style,
2198 flags,
2199 has_content: RefCell::new(false),
2200 nested_strut_block_sizes: nested_block_sizes,
2201 strut_block_sizes,
2202 baseline_offset,
2203 font_metrics,
2204 }
2205 }
2206
2207 fn get_block_sizes_with_style(
2208 baseline_shift: BaselineShift,
2209 style: &ComputedValues,
2210 font_metrics: &FontMetrics,
2211 font_metrics_of_first_font: &FontMetrics,
2212 flags: &InlineContainerStateFlags,
2213 ) -> LineBlockSizes {
2214 let line_height = line_height(style, font_metrics, flags);
2215
2216 if !is_baseline_relative(baseline_shift) {
2217 return LineBlockSizes {
2218 line_height,
2219 baseline_relative_size_for_line_height: None,
2220 size_for_baseline_positioning: BaselineRelativeSize::zero(),
2221 };
2222 }
2223
2224 let mut ascent = font_metrics.ascent;
2233 let mut descent = font_metrics.descent;
2234 if style.get_font().line_height == LineHeight::Normal {
2235 let half_leading_from_line_gap =
2236 (font_metrics.line_gap - descent - ascent).scale_by(0.5);
2237 ascent += half_leading_from_line_gap;
2238 descent += half_leading_from_line_gap;
2239 }
2240
2241 let size_for_baseline_positioning = BaselineRelativeSize { ascent, descent };
2245
2246 if style.get_font().line_height != LineHeight::Normal {
2262 ascent = font_metrics_of_first_font.ascent;
2263 descent = font_metrics_of_first_font.descent;
2264 let half_leading = (line_height - (ascent + descent)).scale_by(0.5);
2265 ascent += half_leading;
2270 descent = line_height - ascent;
2271 }
2272
2273 LineBlockSizes {
2274 line_height,
2275 baseline_relative_size_for_line_height: Some(BaselineRelativeSize { ascent, descent }),
2276 size_for_baseline_positioning,
2277 }
2278 }
2279
2280 fn get_block_size_contribution(
2281 &self,
2282 baseline_shift: BaselineShift,
2283 font_metrics: &FontMetrics,
2284 font_metrics_of_first_font: &FontMetrics,
2285 ) -> LineBlockSizes {
2286 Self::get_block_sizes_with_style(
2287 baseline_shift,
2288 &self.style,
2289 font_metrics,
2290 font_metrics_of_first_font,
2291 &self.flags,
2292 )
2293 }
2294
2295 fn get_cumulative_baseline_offset_for_child(
2296 &self,
2297 child_alignment_baseline: AlignmentBaseline,
2298 child_baseline_shift: BaselineShift,
2299 child_block_size: &LineBlockSizes,
2300 ) -> Au {
2301 let block_size = self.get_block_size_contribution(
2302 child_baseline_shift.clone(),
2303 &self.font_metrics,
2304 &self.font_metrics,
2305 );
2306 self.baseline_offset +
2307 match child_alignment_baseline {
2308 AlignmentBaseline::Baseline => Au::zero(),
2309 AlignmentBaseline::TextTop => {
2310 child_block_size.size_for_baseline_positioning.ascent - self.font_metrics.ascent
2311 },
2312 AlignmentBaseline::Middle => {
2313 (child_block_size.size_for_baseline_positioning.ascent -
2316 child_block_size.size_for_baseline_positioning.descent -
2317 self.font_metrics.x_height)
2318 .scale_by(0.5)
2319 },
2320 AlignmentBaseline::TextBottom => {
2321 self.font_metrics.descent -
2322 child_block_size.size_for_baseline_positioning.descent
2323 },
2324 AlignmentBaseline::Alphabetic |
2325 AlignmentBaseline::Ideographic |
2326 AlignmentBaseline::Central |
2327 AlignmentBaseline::Mathematical |
2328 AlignmentBaseline::Hanging => {
2329 unreachable!("Got alignment-baseline value that should be disabled in Stylo")
2330 },
2331 } +
2332 match child_baseline_shift {
2333 BaselineShift::Keyword(
2338 BaselineShiftKeyword::Top |
2339 BaselineShiftKeyword::Bottom |
2340 BaselineShiftKeyword::Center,
2341 ) => Au::zero(),
2342 BaselineShift::Keyword(BaselineShiftKeyword::Sub) => {
2343 block_size.resolve().scale_by(FONT_SUBSCRIPT_OFFSET_RATIO)
2344 },
2345 BaselineShift::Keyword(BaselineShiftKeyword::Super) => {
2346 -block_size.resolve().scale_by(FONT_SUPERSCRIPT_OFFSET_RATIO)
2347 },
2348 BaselineShift::Length(length_percentage) => {
2349 -length_percentage.to_used_value(child_block_size.line_height)
2350 },
2351 }
2352 }
2353}
2354
2355impl IndependentFormattingContext {
2356 fn layout_into_line_items(
2357 &self,
2358 layout: &mut InlineFormattingContextLayout,
2359 offset_in_text: usize,
2360 bidi_level: Level,
2361 ) {
2362 let mut child_positioning_context = PositioningContext::default();
2364 let IndependentFloatOrAtomicLayoutResult {
2365 mut fragment,
2366 baselines,
2367 pbm_sums,
2368 } = self.layout_float_or_atomic_inline(
2369 layout.layout_context,
2370 &mut child_positioning_context,
2371 layout.containing_block(),
2372 );
2373
2374 layout.depends_on_block_constraints |= fragment.base.flags.contains(
2377 FragmentFlags::SIZE_DEPENDS_ON_BLOCK_CONSTRAINTS_AND_CAN_BE_CHILD_OF_FLEX_ITEM,
2378 );
2379
2380 let container_writing_mode = layout.containing_block().style.writing_mode;
2382 let pbm_physical_offset = pbm_sums
2383 .start_offset()
2384 .to_physical_size(container_writing_mode);
2385 fragment.base.rect.origin += pbm_physical_offset.to_vector();
2386
2387 fragment = fragment.with_baselines(baselines);
2389
2390 let positioning_context = if self.is_replaced() {
2393 None
2394 } else {
2395 if fragment
2396 .style()
2397 .establishes_containing_block_for_absolute_descendants(fragment.base.flags)
2398 {
2399 child_positioning_context
2400 .layout_collected_children(layout.layout_context, &mut fragment);
2401 }
2402 Some(child_positioning_context)
2403 };
2404
2405 if layout.text_wrap_mode == TextWrapMode::Wrap &&
2406 !layout
2407 .ifc
2408 .previous_character_prevents_soft_wrap_opportunity(offset_in_text)
2409 {
2410 layout.process_soft_wrap_opportunity();
2411 }
2412
2413 let size = pbm_sums.sum() + fragment.base.rect.size.to_logical(container_writing_mode);
2414 let baseline_offset = self
2415 .pick_baseline(&fragment.baselines(container_writing_mode))
2416 .map(|baseline| pbm_sums.block_start + baseline)
2417 .unwrap_or(size.block);
2418
2419 let (block_sizes, baseline_offset_in_parent) =
2420 self.get_block_sizes_and_baseline_offset(layout, size.block, baseline_offset);
2421 layout.update_unbreakable_segment_for_new_content(
2422 &block_sizes,
2423 size.inline,
2424 SegmentContentFlags::empty(),
2425 );
2426
2427 let fragment = ArcRefCell::new(fragment);
2428 self.base.set_fragment(Fragment::Box(fragment.clone()));
2429
2430 layout.push_line_item_to_unbreakable_segment(LineItem::Atomic(
2431 layout.current_inline_box_identifier(),
2432 AtomicLineItem {
2433 fragment,
2434 size,
2435 positioning_context,
2436 baseline_offset_in_parent,
2437 baseline_offset_in_item: baseline_offset,
2438 bidi_level,
2439 },
2440 ));
2441
2442 if !layout
2445 .ifc
2446 .next_character_prevents_soft_wrap_opportunity(offset_in_text)
2447 {
2448 layout.have_deferred_soft_wrap_opportunity = true;
2449 }
2450 }
2451
2452 fn pick_baseline(&self, baselines: &Baselines) -> Option<Au> {
2456 match self.style().clone_baseline_source() {
2457 BaselineSource::First => baselines.first,
2458 BaselineSource::Last => baselines.last,
2459 BaselineSource::Auto if self.is_block_container() => baselines.last,
2460 BaselineSource::Auto => baselines.first,
2461 }
2462 }
2463
2464 fn get_block_sizes_and_baseline_offset(
2465 &self,
2466 ifc: &InlineFormattingContextLayout,
2467 block_size: Au,
2468 baseline_offset_in_content_area: Au,
2469 ) -> (LineBlockSizes, Au) {
2470 let mut contribution = if !is_baseline_relative(self.style().clone_baseline_shift()) {
2471 LineBlockSizes {
2472 line_height: block_size,
2473 baseline_relative_size_for_line_height: None,
2474 size_for_baseline_positioning: BaselineRelativeSize::zero(),
2475 }
2476 } else {
2477 let baseline_relative_size = BaselineRelativeSize {
2478 ascent: baseline_offset_in_content_area,
2479 descent: block_size - baseline_offset_in_content_area,
2480 };
2481 LineBlockSizes {
2482 line_height: block_size,
2483 baseline_relative_size_for_line_height: Some(baseline_relative_size.clone()),
2484 size_for_baseline_positioning: baseline_relative_size,
2485 }
2486 };
2487
2488 let style = self.style();
2489 let baseline_offset = ifc
2490 .current_inline_container_state()
2491 .get_cumulative_baseline_offset_for_child(
2492 style.clone_alignment_baseline(),
2493 style.clone_baseline_shift(),
2494 &contribution,
2495 );
2496 contribution.adjust_for_baseline_offset(baseline_offset);
2497
2498 (contribution, baseline_offset)
2499 }
2500}
2501
2502impl FloatBox {
2503 fn layout_into_line_items(&self, layout: &mut InlineFormattingContextLayout) {
2504 let fragment = ArcRefCell::new(self.layout(
2505 layout.layout_context,
2506 layout.positioning_context,
2507 layout.placement_state.containing_block,
2508 ));
2509
2510 self.contents
2511 .base
2512 .set_fragment(Fragment::Box(fragment.clone()));
2513 layout.push_line_item_to_unbreakable_segment(LineItem::Float(
2514 layout.current_inline_box_identifier(),
2515 FloatLineItem {
2516 fragment,
2517 needs_placement: true,
2518 },
2519 ));
2520 }
2521}
2522
2523fn place_pending_floats(ifc: &mut InlineFormattingContextLayout, line_items: &mut [LineItem]) {
2524 for item in line_items.iter_mut() {
2525 if let LineItem::Float(_, float_line_item) = item {
2526 if float_line_item.needs_placement {
2527 ifc.place_float_fragment(&mut float_line_item.fragment.borrow_mut());
2528 }
2529 }
2530 }
2531}
2532
2533fn line_height(
2534 parent_style: &ComputedValues,
2535 font_metrics: &FontMetrics,
2536 flags: &InlineContainerStateFlags,
2537) -> Au {
2538 let font = parent_style.get_font();
2539 let font_size = font.font_size.computed_size();
2540 let mut line_height = match font.line_height {
2541 LineHeight::Normal => font_metrics.line_gap,
2542 LineHeight::Number(number) => (font_size * number.0).into(),
2543 LineHeight::Length(length) => length.0.into(),
2544 };
2545
2546 if flags.contains(InlineContainerStateFlags::IS_SINGLE_LINE_TEXT_INPUT) {
2550 line_height.max_assign(font_metrics.line_gap);
2551 }
2552
2553 line_height
2554}
2555
2556fn effective_baseline_shift(
2557 style: &ComputedValues,
2558 container: Option<&InlineContainerState>,
2559) -> BaselineShift {
2560 if container.is_none() {
2561 BaselineShift::zero()
2565 } else {
2566 style.clone_baseline_shift()
2567 }
2568}
2569
2570fn is_baseline_relative(baseline_shift: BaselineShift) -> bool {
2571 !matches!(
2572 baseline_shift,
2573 BaselineShift::Keyword(
2574 BaselineShiftKeyword::Top | BaselineShiftKeyword::Bottom | BaselineShiftKeyword::Center
2575 )
2576 )
2577}
2578
2579fn inline_container_needs_strut(
2605 style: &ComputedValues,
2606 layout_context: &LayoutContext,
2607 pbm: Option<&PaddingBorderMargin>,
2608) -> bool {
2609 if layout_context.style_context.quirks_mode() == QuirksMode::NoQuirks {
2610 return true;
2611 }
2612
2613 if style.get_box().display.is_list_item() {
2616 return true;
2617 }
2618
2619 pbm.is_some_and(|pbm| !pbm.padding_border_sums.inline.is_zero())
2620}
2621
2622impl ComputeInlineContentSizes for InlineFormattingContext {
2623 fn compute_inline_content_sizes(
2627 &self,
2628 layout_context: &LayoutContext,
2629 constraint_space: &ConstraintSpace,
2630 ) -> InlineContentSizesResult {
2631 ContentSizesComputation::compute(self, layout_context, constraint_space)
2632 }
2633}
2634
2635struct ContentSizesComputation<'layout_data> {
2637 layout_context: &'layout_data LayoutContext<'layout_data>,
2638 constraint_space: &'layout_data ConstraintSpace<'layout_data>,
2639 paragraph: ContentSizes,
2640 current_line: ContentSizes,
2641 pending_whitespace: ContentSizes,
2643 uncleared_floats: LogicalSides1D<ContentSizes>,
2645 cleared_floats: LogicalSides1D<ContentSizes>,
2647 had_content_yet_for_min_content: bool,
2650 had_content_yet_for_max_content: bool,
2653 ending_inline_pbm_stack: Vec<Au>,
2656 depends_on_block_constraints: bool,
2657}
2658
2659impl<'layout_data> ContentSizesComputation<'layout_data> {
2660 fn traverse(
2661 mut self,
2662 inline_formatting_context: &InlineFormattingContext,
2663 ) -> InlineContentSizesResult {
2664 self.add_inline_size(
2665 inline_formatting_context.inline_start_for_first_line(self.constraint_space.into()),
2666 );
2667 for inline_item in &inline_formatting_context.inline_items {
2668 self.process_item(inline_item, inline_formatting_context);
2669 }
2670 self.forced_line_break();
2671 self.flush_floats();
2672
2673 InlineContentSizesResult {
2674 sizes: self.paragraph,
2675 depends_on_block_constraints: self.depends_on_block_constraints,
2676 }
2677 }
2678
2679 fn process_item(
2680 &mut self,
2681 inline_item: &InlineItem,
2682 inline_formatting_context: &InlineFormattingContext,
2683 ) {
2684 match inline_item {
2685 InlineItem::StartInlineBox(inline_box) => {
2686 let inline_box = inline_box.borrow();
2690 let zero = Au::zero();
2691 let writing_mode = self.constraint_space.style.writing_mode;
2692 let layout_style = inline_box.layout_style();
2693 let padding = layout_style
2694 .padding(writing_mode)
2695 .percentages_relative_to(zero);
2696 let border = layout_style.border_width(writing_mode);
2697 let margin = inline_box
2698 .base
2699 .style
2700 .margin(writing_mode)
2701 .percentages_relative_to(zero)
2702 .auto_is(Au::zero);
2703
2704 let pbm = margin + padding + border;
2705 self.add_inline_size(pbm.inline_start);
2706 self.ending_inline_pbm_stack.push(pbm.inline_end);
2707 },
2708 InlineItem::EndInlineBox => {
2709 let length = self.ending_inline_pbm_stack.pop().unwrap_or_else(Au::zero);
2710 self.add_inline_size(length);
2711 },
2712 InlineItem::TextRun(text_run) => {
2713 let text_run = &*text_run.borrow();
2714 let parent_style = text_run.inline_styles.style.borrow();
2715 for segment in text_run.shaped_text.iter() {
2716 let style_text = parent_style.get_inherited_text();
2717 let can_wrap = style_text.text_wrap_mode == TextWrapMode::Wrap;
2718
2719 let break_at_start =
2722 segment.break_at_start && self.had_content_yet_for_min_content;
2723
2724 for (run_index, run) in segment.runs.iter().enumerate() {
2725 if can_wrap && (run_index != 0 || break_at_start) {
2728 self.line_break_opportunity();
2729 }
2730
2731 let advance = run.total_advance();
2732 if run.is_whitespace() {
2733 if run.is_single_preserved_newline() {
2736 self.forced_line_break();
2737 continue;
2738 }
2739 if !matches!(
2740 style_text.white_space_collapse,
2741 WhiteSpaceCollapse::Preserve | WhiteSpaceCollapse::BreakSpaces
2742 ) {
2743 if self.had_content_yet_for_min_content {
2744 if can_wrap {
2745 self.line_break_opportunity();
2746 } else {
2747 self.pending_whitespace.min_content += advance;
2748 }
2749 }
2750 if self.had_content_yet_for_max_content {
2751 self.pending_whitespace.max_content += advance;
2752 }
2753 continue;
2754 }
2755 if can_wrap {
2756 self.pending_whitespace.max_content += advance;
2757 self.commit_pending_whitespace();
2758 self.line_break_opportunity();
2759 continue;
2760 }
2761 }
2762
2763 self.commit_pending_whitespace();
2764 self.add_inline_size(advance);
2765
2766 if can_wrap && run.ends_with_whitespace() {
2771 self.line_break_opportunity();
2772 }
2773 }
2774 }
2775 },
2776 InlineItem::Atomic(atomic, offset_in_text, _level) => {
2777 if self.had_content_yet_for_min_content &&
2779 !inline_formatting_context
2780 .previous_character_prevents_soft_wrap_opportunity(*offset_in_text)
2781 {
2782 self.line_break_opportunity();
2783 }
2784
2785 self.commit_pending_whitespace();
2786 let outer = self.outer_inline_content_sizes_of_float_or_atomic(&atomic.borrow());
2787 self.current_line += outer;
2788
2789 if !inline_formatting_context
2791 .next_character_prevents_soft_wrap_opportunity(*offset_in_text)
2792 {
2793 self.line_break_opportunity();
2794 }
2795 },
2796 InlineItem::OutOfFlowFloatBox(float_box) => {
2797 let float_box = float_box.borrow();
2798 let sizes = self.outer_inline_content_sizes_of_float_or_atomic(&float_box.contents);
2799 let style = &float_box.contents.style();
2800 let container_writing_mode = self.constraint_space.style.writing_mode;
2801 let clear =
2802 Clear::from_style_and_container_writing_mode(style, container_writing_mode);
2803 self.clear_floats(clear);
2804 let float_side =
2805 FloatSide::from_style_and_container_writing_mode(style, container_writing_mode);
2806 match float_side.expect("A float box needs to float to some side") {
2807 FloatSide::InlineStart => self.uncleared_floats.start.union_assign(&sizes),
2808 FloatSide::InlineEnd => self.uncleared_floats.end.union_assign(&sizes),
2809 }
2810 },
2811 InlineItem::BlockLevel(block_level) => {
2812 self.forced_line_break();
2813 self.flush_floats();
2814 let inline_content_sizes_result =
2815 compute_inline_content_sizes_for_block_level_boxes(
2816 std::slice::from_ref(block_level),
2817 self.layout_context,
2818 &self.constraint_space.into(),
2819 );
2820 self.depends_on_block_constraints |=
2821 inline_content_sizes_result.depends_on_block_constraints;
2822 self.current_line = inline_content_sizes_result.sizes;
2823 self.forced_line_break();
2824 },
2825 InlineItem::OutOfFlowAbsolutelyPositionedBox(..) => {},
2826 }
2827 }
2828
2829 fn add_inline_size(&mut self, l: Au) {
2830 self.current_line.min_content += l;
2831 self.current_line.max_content += l;
2832 }
2833
2834 fn line_break_opportunity(&mut self) {
2835 self.pending_whitespace.min_content = Au::zero();
2839 let current_min_content = mem::take(&mut self.current_line.min_content);
2840 self.paragraph.min_content.max_assign(current_min_content);
2841 self.had_content_yet_for_min_content = false;
2842 }
2843
2844 fn forced_line_break(&mut self) {
2845 self.line_break_opportunity();
2847
2848 self.pending_whitespace.max_content = Au::zero();
2850 let current_max_content = mem::take(&mut self.current_line.max_content);
2851 self.paragraph.max_content.max_assign(current_max_content);
2852 self.had_content_yet_for_max_content = false;
2853 }
2854
2855 fn commit_pending_whitespace(&mut self) {
2856 self.current_line += mem::take(&mut self.pending_whitespace);
2857 self.had_content_yet_for_min_content = true;
2858 self.had_content_yet_for_max_content = true;
2859 }
2860
2861 fn outer_inline_content_sizes_of_float_or_atomic(
2862 &mut self,
2863 context: &IndependentFormattingContext,
2864 ) -> ContentSizes {
2865 let result = context.outer_inline_content_sizes(
2866 self.layout_context,
2867 &self.constraint_space.into(),
2868 &LogicalVec2::zero(),
2869 false, );
2871 self.depends_on_block_constraints |= result.depends_on_block_constraints;
2872 result.sizes
2873 }
2874
2875 fn clear_floats(&mut self, clear: Clear) {
2876 match clear {
2877 Clear::InlineStart => {
2878 let start_floats = mem::take(&mut self.uncleared_floats.start);
2879 self.cleared_floats.start.max_assign(start_floats);
2880 },
2881 Clear::InlineEnd => {
2882 let end_floats = mem::take(&mut self.uncleared_floats.end);
2883 self.cleared_floats.end.max_assign(end_floats);
2884 },
2885 Clear::Both => {
2886 let start_floats = mem::take(&mut self.uncleared_floats.start);
2887 let end_floats = mem::take(&mut self.uncleared_floats.end);
2888 self.cleared_floats.start.max_assign(start_floats);
2889 self.cleared_floats.end.max_assign(end_floats);
2890 },
2891 Clear::None => {},
2892 }
2893 }
2894
2895 fn flush_floats(&mut self) {
2896 self.clear_floats(Clear::Both);
2897 let start_floats = mem::take(&mut self.cleared_floats.start);
2898 let end_floats = mem::take(&mut self.cleared_floats.end);
2899 self.paragraph.union_assign(&start_floats);
2900 self.paragraph.union_assign(&end_floats);
2901 }
2902
2903 fn compute(
2905 inline_formatting_context: &InlineFormattingContext,
2906 layout_context: &'layout_data LayoutContext,
2907 constraint_space: &'layout_data ConstraintSpace,
2908 ) -> InlineContentSizesResult {
2909 Self {
2910 layout_context,
2911 constraint_space,
2912 paragraph: ContentSizes::zero(),
2913 current_line: ContentSizes::zero(),
2914 pending_whitespace: ContentSizes::zero(),
2915 uncleared_floats: LogicalSides1D::default(),
2916 cleared_floats: LogicalSides1D::default(),
2917 had_content_yet_for_min_content: false,
2918 had_content_yet_for_max_content: false,
2919 ending_inline_pbm_stack: Vec::new(),
2920 depends_on_block_constraints: false,
2921 }
2922 .traverse(inline_formatting_context)
2923 }
2924}
2925
2926fn char_prevents_soft_wrap_opportunity_when_before_or_after_atomic(character: char) -> bool {
2938 if character == '\u{00A0}' {
2939 return false;
2940 }
2941 let class = linebreak_property(character);
2942 class == XI_LINE_BREAKING_CLASS_GL ||
2943 class == XI_LINE_BREAKING_CLASS_WJ ||
2944 class == XI_LINE_BREAKING_CLASS_ZWJ
2945}