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;
80
81use app_units::{Au, MAX_AU};
82use bitflags::bitflags;
83use construct::InlineFormattingContextBuilder;
84use fonts::{ByteIndex, FontMetrics, GlyphStore};
85use inline_box::{InlineBox, InlineBoxContainerState, InlineBoxIdentifier, InlineBoxes};
86use line::{
87 AbsolutelyPositionedLineItem, AtomicLineItem, FloatLineItem, LineItem, LineItemLayout,
88 TextRunLineItem,
89};
90use line_breaker::LineBreaker;
91use malloc_size_of_derive::MallocSizeOf;
92use range::Range;
93use script::layout_dom::ServoThreadSafeLayoutNode;
94use servo_arc::Arc;
95use style::Zero;
96use style::computed_values::text_wrap_mode::T as TextWrapMode;
97use style::computed_values::vertical_align::T as VerticalAlign;
98use style::computed_values::white_space_collapse::T as WhiteSpaceCollapse;
99use style::context::{QuirksMode, SharedStyleContext};
100use style::properties::ComputedValues;
101use style::properties::style_structs::InheritedText;
102use style::values::generics::box_::VerticalAlignKeyword;
103use style::values::generics::font::LineHeight;
104use style::values::specified::box_::BaselineSource;
105use style::values::specified::text::TextAlignKeyword;
106use style::values::specified::{TextAlignLast, TextJustify};
107use text_run::{
108 TextRun, XI_LINE_BREAKING_CLASS_GL, XI_LINE_BREAKING_CLASS_WJ, XI_LINE_BREAKING_CLASS_ZWJ,
109 add_or_get_font, get_font_for_first_font_for_style,
110};
111use unicode_bidi::{BidiInfo, Level};
112use webrender_api::FontInstanceKey;
113use xi_unicode::linebreak_property;
114
115use super::float::{Clear, PlacementAmongFloats};
116use super::{CacheableLayoutResult, IndependentFloatOrAtomicLayoutResult};
117use crate::cell::ArcRefCell;
118use crate::context::LayoutContext;
119use crate::dom_traversal::NodeAndStyleInfo;
120use crate::flow::CollapsibleWithParentStartMargin;
121use crate::flow::float::{FloatBox, SequentialLayoutState};
122use crate::formatting_contexts::{Baselines, IndependentFormattingContext};
123use crate::fragment_tree::{
124 BoxFragment, CollapsedBlockMargins, CollapsedMargin, Fragment, FragmentFlags,
125 PositioningFragment,
126};
127use crate::geom::{LogicalRect, LogicalVec2, ToLogical};
128use crate::layout_box_base::LayoutBoxBase;
129use crate::positioned::{AbsolutelyPositionedBox, PositioningContext};
130use crate::sizing::{ComputeInlineContentSizes, ContentSizes, InlineContentSizesResult};
131use crate::style_ext::{ComputedValuesExt, PaddingBorderMargin};
132use crate::{ConstraintSpace, ContainingBlock, IndefiniteContainingBlock, SharedStyle};
133
134static FONT_SUBSCRIPT_OFFSET_RATIO: f32 = 0.20;
136static FONT_SUPERSCRIPT_OFFSET_RATIO: f32 = 0.34;
137
138#[derive(Debug, MallocSizeOf)]
139pub(crate) struct InlineFormattingContext {
140 pub(super) inline_items: Vec<ArcRefCell<InlineItem>>,
145
146 pub(super) inline_boxes: InlineBoxes,
149
150 pub(super) text_content: String,
152
153 pub font_metrics: Vec<FontKeyAndMetrics>,
156
157 pub(super) shared_inline_styles: SharedInlineStyles,
160
161 pub(super) has_first_formatted_line: bool,
164
165 pub(super) contains_floats: bool,
167
168 pub(super) is_single_line_text_input: bool,
171
172 pub(super) has_right_to_left_content: bool,
175}
176
177#[derive(Clone, Debug, MallocSizeOf)]
182pub(crate) struct SharedInlineStyles {
183 pub style: SharedStyle,
184 pub selected: SharedStyle,
185}
186
187impl From<&NodeAndStyleInfo<'_>> for SharedInlineStyles {
188 fn from(info: &NodeAndStyleInfo) -> Self {
189 Self {
190 style: SharedStyle::new(info.style.clone()),
191 selected: SharedStyle::new(info.node.selected_style()),
192 }
193 }
194}
195
196#[derive(Debug, MallocSizeOf)]
198pub(crate) struct FontKeyAndMetrics {
199 pub key: FontInstanceKey,
200 pub pt_size: Au,
201 pub metrics: FontMetrics,
202}
203
204#[derive(Debug, MallocSizeOf)]
205pub(crate) enum InlineItem {
206 StartInlineBox(ArcRefCell<InlineBox>),
207 EndInlineBox,
208 TextRun(ArcRefCell<TextRun>),
209 OutOfFlowAbsolutelyPositionedBox(
210 ArcRefCell<AbsolutelyPositionedBox>,
211 usize, ),
213 OutOfFlowFloatBox(ArcRefCell<FloatBox>),
214 Atomic(
215 ArcRefCell<IndependentFormattingContext>,
216 usize, Level, ),
219}
220
221impl InlineItem {
222 pub(crate) fn repair_style(
223 &self,
224 context: &SharedStyleContext,
225 node: &ServoThreadSafeLayoutNode,
226 new_style: &Arc<ComputedValues>,
227 ) {
228 match self {
229 InlineItem::StartInlineBox(inline_box) => {
230 inline_box.borrow_mut().repair_style(node, new_style);
231 },
232 InlineItem::EndInlineBox => {},
233 InlineItem::TextRun(..) => {},
236 InlineItem::OutOfFlowAbsolutelyPositionedBox(positioned_box, ..) => positioned_box
237 .borrow_mut()
238 .context
239 .repair_style(context, node, new_style),
240 InlineItem::OutOfFlowFloatBox(float_box) => float_box
241 .borrow_mut()
242 .contents
243 .repair_style(context, node, new_style),
244 InlineItem::Atomic(atomic, ..) => {
245 atomic.borrow_mut().repair_style(context, node, new_style)
246 },
247 }
248 }
249
250 pub(crate) fn with_base<T>(&self, callback: impl FnOnce(&LayoutBoxBase) -> T) -> T {
251 match self {
252 InlineItem::StartInlineBox(inline_box) => callback(&inline_box.borrow().base),
253 InlineItem::EndInlineBox | InlineItem::TextRun(..) => {
254 unreachable!("Should never have these kind of fragments attached to a DOM node")
255 },
256 InlineItem::OutOfFlowAbsolutelyPositionedBox(positioned_box, ..) => {
257 callback(&positioned_box.borrow().context.base)
258 },
259 InlineItem::OutOfFlowFloatBox(float_box) => callback(&float_box.borrow().contents.base),
260 InlineItem::Atomic(independent_formatting_context, ..) => {
261 callback(&independent_formatting_context.borrow().base)
262 },
263 }
264 }
265
266 pub(crate) fn with_base_mut<T>(&mut self, callback: impl FnOnce(&mut LayoutBoxBase) -> T) -> T {
267 match self {
268 InlineItem::StartInlineBox(inline_box) => callback(&mut inline_box.borrow_mut().base),
269 InlineItem::EndInlineBox | InlineItem::TextRun(..) => {
270 unreachable!("Should never have these kind of fragments attached to a DOM node")
271 },
272 InlineItem::OutOfFlowAbsolutelyPositionedBox(positioned_box, ..) => {
273 callback(&mut positioned_box.borrow_mut().context.base)
274 },
275 InlineItem::OutOfFlowFloatBox(float_box) => {
276 callback(&mut float_box.borrow_mut().contents.base)
277 },
278 InlineItem::Atomic(independent_formatting_context, ..) => {
279 callback(&mut independent_formatting_context.borrow_mut().base)
280 },
281 }
282 }
283}
284
285struct LineUnderConstruction {
292 start_position: LogicalVec2<Au>,
295
296 inline_position: Au,
299
300 max_block_size: LineBlockSizes,
304
305 has_content: bool,
308
309 has_inline_pbm: bool,
312
313 has_floats_waiting_to_be_placed: bool,
317
318 placement_among_floats: OnceCell<LogicalRect<Au>>,
323
324 line_items: Vec<LineItem>,
327}
328
329impl LineUnderConstruction {
330 fn new(start_position: LogicalVec2<Au>) -> Self {
331 Self {
332 inline_position: start_position.inline,
333 start_position,
334 max_block_size: LineBlockSizes::zero(),
335 has_content: false,
336 has_inline_pbm: false,
337 has_floats_waiting_to_be_placed: false,
338 placement_among_floats: OnceCell::new(),
339 line_items: Vec::new(),
340 }
341 }
342
343 fn line_block_start_considering_placement_among_floats(&self) -> Au {
344 match self.placement_among_floats.get() {
345 Some(placement_among_floats) => placement_among_floats.start_corner.block,
346 None => self.start_position.block,
347 }
348 }
349
350 fn replace_placement_among_floats(&mut self, new_placement: LogicalRect<Au>) {
351 self.placement_among_floats.take();
352 let _ = self.placement_among_floats.set(new_placement);
353 }
354
355 fn trim_trailing_whitespace(&mut self) -> Au {
357 let mut whitespace_trimmed = Au::zero();
362 for item in self.line_items.iter_mut().rev() {
363 if !item.trim_whitespace_at_end(&mut whitespace_trimmed) {
364 break;
365 }
366 }
367
368 whitespace_trimmed
369 }
370
371 fn count_justification_opportunities(&self) -> usize {
373 self.line_items
374 .iter()
375 .filter_map(|item| match item {
376 LineItem::TextRun(_, text_run) => Some(
377 text_run
378 .text
379 .iter()
380 .map(|glyph_store| glyph_store.total_word_separators())
381 .sum::<usize>(),
382 ),
383 _ => None,
384 })
385 .sum()
386 }
387}
388
389#[derive(Clone, Debug)]
395struct BaselineRelativeSize {
396 ascent: Au,
400
401 descent: Au,
405}
406
407impl BaselineRelativeSize {
408 fn zero() -> Self {
409 Self {
410 ascent: Au::zero(),
411 descent: Au::zero(),
412 }
413 }
414
415 fn max(&self, other: &Self) -> Self {
416 BaselineRelativeSize {
417 ascent: self.ascent.max(other.ascent),
418 descent: self.descent.max(other.descent),
419 }
420 }
421
422 fn adjust_for_nested_baseline_offset(&mut self, baseline_offset: Au) {
436 self.ascent -= baseline_offset;
437 self.descent += baseline_offset;
438 }
439}
440
441#[derive(Clone, Debug)]
442struct LineBlockSizes {
443 line_height: Au,
444 baseline_relative_size_for_line_height: Option<BaselineRelativeSize>,
445 size_for_baseline_positioning: BaselineRelativeSize,
446}
447
448impl LineBlockSizes {
449 fn zero() -> Self {
450 LineBlockSizes {
451 line_height: Au::zero(),
452 baseline_relative_size_for_line_height: None,
453 size_for_baseline_positioning: BaselineRelativeSize::zero(),
454 }
455 }
456
457 fn resolve(&self) -> Au {
458 let height_from_ascent_and_descent = self
459 .baseline_relative_size_for_line_height
460 .as_ref()
461 .map(|size| (size.ascent + size.descent).abs())
462 .unwrap_or_else(Au::zero);
463 self.line_height.max(height_from_ascent_and_descent)
464 }
465
466 fn max(&self, other: &LineBlockSizes) -> LineBlockSizes {
467 let baseline_relative_size = match (
468 self.baseline_relative_size_for_line_height.as_ref(),
469 other.baseline_relative_size_for_line_height.as_ref(),
470 ) {
471 (Some(our_size), Some(other_size)) => Some(our_size.max(other_size)),
472 (our_size, other_size) => our_size.or(other_size).cloned(),
473 };
474 Self {
475 line_height: self.line_height.max(other.line_height),
476 baseline_relative_size_for_line_height: baseline_relative_size,
477 size_for_baseline_positioning: self
478 .size_for_baseline_positioning
479 .max(&other.size_for_baseline_positioning),
480 }
481 }
482
483 fn max_assign(&mut self, other: &LineBlockSizes) {
484 *self = self.max(other);
485 }
486
487 fn adjust_for_baseline_offset(&mut self, baseline_offset: Au) {
488 if let Some(size) = self.baseline_relative_size_for_line_height.as_mut() {
489 size.adjust_for_nested_baseline_offset(baseline_offset)
490 }
491 self.size_for_baseline_positioning
492 .adjust_for_nested_baseline_offset(baseline_offset);
493 }
494
495 fn find_baseline_offset(&self) -> Au {
502 match self.baseline_relative_size_for_line_height.as_ref() {
503 Some(size) => size.ascent,
504 None => {
505 let leading = self.resolve() -
508 (self.size_for_baseline_positioning.ascent +
509 self.size_for_baseline_positioning.descent);
510 leading.scale_by(0.5) + self.size_for_baseline_positioning.ascent
511 },
512 }
513 }
514}
515
516struct UnbreakableSegmentUnderConstruction {
520 inline_size: Au,
522
523 max_block_size: LineBlockSizes,
526
527 line_items: Vec<LineItem>,
529
530 inline_box_hierarchy_depth: Option<usize>,
533
534 has_content: bool,
538
539 has_inline_pbm: bool,
542
543 trailing_whitespace_size: Au,
545}
546
547impl UnbreakableSegmentUnderConstruction {
548 fn new() -> Self {
549 Self {
550 inline_size: Au::zero(),
551 max_block_size: LineBlockSizes {
552 line_height: Au::zero(),
553 baseline_relative_size_for_line_height: None,
554 size_for_baseline_positioning: BaselineRelativeSize::zero(),
555 },
556 line_items: Vec::new(),
557 inline_box_hierarchy_depth: None,
558 has_content: false,
559 has_inline_pbm: false,
560 trailing_whitespace_size: Au::zero(),
561 }
562 }
563
564 fn reset(&mut self) {
566 assert!(self.line_items.is_empty()); self.inline_size = Au::zero();
568 self.max_block_size = LineBlockSizes::zero();
569 self.inline_box_hierarchy_depth = None;
570 self.has_content = false;
571 self.has_inline_pbm = false;
572 self.trailing_whitespace_size = Au::zero();
573 }
574
575 fn push_line_item(&mut self, line_item: LineItem, inline_box_hierarchy_depth: usize) {
580 if self.line_items.is_empty() {
581 self.inline_box_hierarchy_depth = Some(inline_box_hierarchy_depth);
582 }
583 self.line_items.push(line_item);
584 }
585
586 fn trim_leading_whitespace(&mut self) {
597 let mut whitespace_trimmed = Au::zero();
598 for item in self.line_items.iter_mut() {
599 if !item.trim_whitespace_at_start(&mut whitespace_trimmed) {
600 break;
601 }
602 }
603 self.inline_size -= whitespace_trimmed;
604 }
605}
606
607bitflags! {
608 pub struct InlineContainerStateFlags: u8 {
609 const CREATE_STRUT = 0b0001;
610 const IS_SINGLE_LINE_TEXT_INPUT = 0b0010;
611 }
612}
613
614pub(super) struct InlineContainerState {
615 style: Arc<ComputedValues>,
617
618 flags: InlineContainerStateFlags,
620
621 has_content: RefCell<bool>,
624
625 strut_block_sizes: LineBlockSizes,
630
631 nested_strut_block_sizes: LineBlockSizes,
635
636 pub baseline_offset: Au,
642
643 font_metrics: FontMetrics,
645}
646
647pub(super) struct InlineFormattingContextLayout<'layout_data> {
648 positioning_context: &'layout_data mut PositioningContext,
649 containing_block: &'layout_data ContainingBlock<'layout_data>,
650 sequential_layout_state: Option<&'layout_data mut SequentialLayoutState>,
651 layout_context: &'layout_data LayoutContext<'layout_data>,
652
653 ifc: &'layout_data InlineFormattingContext,
655
656 root_nesting_level: InlineContainerState,
666
667 inline_box_state_stack: Vec<Rc<InlineBoxContainerState>>,
671
672 inline_box_states: Vec<Rc<InlineBoxContainerState>>,
677
678 fragments: Vec<Fragment>,
682
683 current_line: LineUnderConstruction,
685
686 current_line_segment: UnbreakableSegmentUnderConstruction,
688
689 linebreak_before_new_content: bool,
708
709 deferred_br_clear: Clear,
713
714 pub have_deferred_soft_wrap_opportunity: bool,
718
719 has_line_boxes: bool,
722
723 depends_on_block_constraints: bool,
726
727 white_space_collapse: WhiteSpaceCollapse,
732
733 text_wrap_mode: TextWrapMode,
738
739 baselines: Baselines,
743}
744
745impl InlineFormattingContextLayout<'_> {
746 fn current_inline_container_state(&self) -> &InlineContainerState {
747 match self.inline_box_state_stack.last() {
748 Some(inline_box_state) => &inline_box_state.base,
749 None => &self.root_nesting_level,
750 }
751 }
752
753 fn current_inline_box_identifier(&self) -> Option<InlineBoxIdentifier> {
754 self.inline_box_state_stack
755 .last()
756 .map(|state| state.identifier)
757 }
758
759 fn current_line_max_block_size_including_nested_containers(&self) -> LineBlockSizes {
760 self.current_inline_container_state()
761 .nested_strut_block_sizes
762 .max(&self.current_line.max_block_size)
763 }
764
765 fn propagate_current_nesting_level_white_space_style(&mut self) {
766 let style = match self.inline_box_state_stack.last() {
767 Some(inline_box_state) => &inline_box_state.base.style,
768 None => self.containing_block.style,
769 };
770 let style_text = style.get_inherited_text();
771 self.white_space_collapse = style_text.white_space_collapse;
772 self.text_wrap_mode = style_text.text_wrap_mode;
773 }
774
775 fn processing_br_element(&self) -> bool {
776 self.inline_box_state_stack.last().is_some_and(|state| {
777 state
778 .base_fragment_info
779 .flags
780 .contains(FragmentFlags::IS_BR_ELEMENT)
781 })
782 }
783
784 fn start_inline_box(&mut self, inline_box: &InlineBox) {
787 let inline_box_state = InlineBoxContainerState::new(
788 inline_box,
789 self.containing_block,
790 self.layout_context,
791 self.current_inline_container_state(),
792 inline_box.is_last_split,
793 inline_box
794 .default_font_index
795 .map(|index| &self.ifc.font_metrics[index].metrics),
796 );
797
798 self.depends_on_block_constraints |= inline_box
799 .base
800 .style
801 .depends_on_block_constraints_due_to_relative_positioning(
802 self.containing_block.style.writing_mode,
803 );
804
805 if inline_box_state
810 .base_fragment_info
811 .flags
812 .contains(FragmentFlags::IS_BR_ELEMENT) &&
813 self.deferred_br_clear == Clear::None
814 {
815 self.deferred_br_clear = Clear::from_style_and_container_writing_mode(
816 &inline_box_state.base.style,
817 self.containing_block.style.writing_mode,
818 );
819 }
820
821 if inline_box.is_first_split {
822 let padding = inline_box_state.pbm.padding.inline_start;
823 let border = inline_box_state.pbm.border.inline_start;
824 let margin = inline_box_state.pbm.margin.inline_start.auto_is(Au::zero);
825 if !padding.is_zero() || !border.is_zero() || !margin.is_zero() {
828 self.current_line_segment.has_inline_pbm = true;
829 }
830 self.current_line_segment.inline_size += padding + border + margin;
831 self.current_line_segment
832 .line_items
833 .push(LineItem::InlineStartBoxPaddingBorderMargin(
834 inline_box.identifier,
835 ));
836 }
837
838 let inline_box_state = Rc::new(inline_box_state);
839
840 assert_eq!(
844 self.inline_box_states.len(),
845 inline_box.identifier.index_in_inline_boxes as usize
846 );
847 self.inline_box_states.push(inline_box_state.clone());
848 self.inline_box_state_stack.push(inline_box_state);
849 }
850
851 fn finish_inline_box(&mut self) {
854 let inline_box_state = match self.inline_box_state_stack.pop() {
855 Some(inline_box_state) => inline_box_state,
856 None => return, };
858
859 self.current_line_segment
860 .max_block_size
861 .max_assign(&inline_box_state.base.nested_strut_block_sizes);
862
863 if *inline_box_state.base.has_content.borrow() {
868 self.propagate_current_nesting_level_white_space_style();
869 }
870
871 if inline_box_state.is_last_fragment {
872 let padding = inline_box_state.pbm.padding.inline_end;
873 let border = inline_box_state.pbm.border.inline_end;
874 let margin = inline_box_state.pbm.margin.inline_end.auto_is(Au::zero);
875 if !padding.is_zero() || !border.is_zero() || !margin.is_zero() {
878 self.current_line_segment.has_inline_pbm = true;
879 }
880 self.current_line_segment.inline_size += padding + border + margin;
881 self.current_line_segment
882 .line_items
883 .push(LineItem::InlineEndBoxPaddingBorderMargin(
884 inline_box_state.identifier,
885 ))
886 }
887 }
888
889 fn finish_last_line(&mut self) {
890 self.process_soft_wrap_opportunity();
896
897 self.commit_current_segment_to_line();
900
901 self.finish_current_line_and_reset(true );
904 }
905
906 fn finish_current_line_and_reset(&mut self, last_line_or_forced_line_break: bool) {
910 let whitespace_trimmed = self.current_line.trim_trailing_whitespace();
911 let (inline_start_position, justification_adjustment) = self
912 .calculate_current_line_inline_start_and_justification_adjustment(
913 whitespace_trimmed,
914 last_line_or_forced_line_break,
915 );
916
917 let block_start_position = self
918 .current_line
919 .line_block_start_considering_placement_among_floats();
920
921 let is_phantom_line = !self.current_line.has_content && !self.current_line.has_inline_pbm;
930 let effective_block_advance = if is_phantom_line {
931 LineBlockSizes::zero()
932 } else {
933 self.current_line_max_block_size_including_nested_containers()
934 };
935
936 let resolved_block_advance = effective_block_advance.resolve();
937 let mut block_end_position = block_start_position + resolved_block_advance;
938 if let Some(sequential_layout_state) = self.sequential_layout_state.as_mut() {
939 let increment = block_end_position - self.current_line.start_position.block;
942 sequential_layout_state.advance_block_position(increment);
943
944 if let Some(clearance) = sequential_layout_state
948 .calculate_clearance(self.deferred_br_clear, &CollapsedMargin::zero())
949 {
950 sequential_layout_state.advance_block_position(clearance);
951 block_end_position += clearance;
952 };
953 self.deferred_br_clear = Clear::None;
954 }
955
956 let mut line_to_layout = std::mem::replace(
958 &mut self.current_line,
959 LineUnderConstruction::new(LogicalVec2 {
960 inline: Au::zero(),
961 block: block_end_position,
962 }),
963 );
964
965 if line_to_layout.has_floats_waiting_to_be_placed {
966 place_pending_floats(self, &mut line_to_layout.line_items);
967 }
968
969 let start_position = LogicalVec2 {
970 block: block_start_position,
971 inline: inline_start_position,
972 };
973
974 let baseline_offset = effective_block_advance.find_baseline_offset();
975 let start_positioning_context_length = self.positioning_context.len();
976 let fragments = LineItemLayout::layout_line_items(
977 self,
978 line_to_layout.line_items,
979 start_position,
980 &effective_block_advance,
981 justification_adjustment,
982 is_phantom_line,
983 );
984
985 if !is_phantom_line {
986 let baseline = baseline_offset + block_start_position;
987 self.baselines.first.get_or_insert(baseline);
988 self.baselines.last = Some(baseline);
989 self.has_line_boxes = true;
990 }
991
992 if fragments.is_empty() &&
994 self.positioning_context.len() == start_positioning_context_length
995 {
996 return;
997 }
998
999 let start_corner = LogicalVec2 {
1003 inline: Au::zero(),
1004 block: block_start_position,
1005 };
1006
1007 let logical_origin_in_physical_coordinates =
1008 start_corner.to_physical_vector(self.containing_block.style.writing_mode);
1009 self.positioning_context
1010 .adjust_static_position_of_hoisted_fragments_with_offset(
1011 &logical_origin_in_physical_coordinates,
1012 start_positioning_context_length,
1013 );
1014
1015 let physical_line_rect = LogicalRect {
1016 start_corner,
1017 size: LogicalVec2 {
1018 inline: self.containing_block.size.inline,
1019 block: effective_block_advance.resolve(),
1020 },
1021 }
1022 .as_physical(Some(self.containing_block));
1023 self.fragments
1024 .push(Fragment::Positioning(PositioningFragment::new_anonymous(
1025 self.root_nesting_level.style.clone(),
1026 physical_line_rect,
1027 fragments,
1028 )));
1029 }
1030
1031 fn calculate_current_line_inline_start_and_justification_adjustment(
1036 &self,
1037 whitespace_trimmed: Au,
1038 last_line_or_forced_line_break: bool,
1039 ) -> (Au, Au) {
1040 enum TextAlign {
1041 Start,
1042 Center,
1043 End,
1044 }
1045 let style = self.containing_block.style;
1046 let mut text_align_keyword = style.clone_text_align();
1047
1048 if last_line_or_forced_line_break {
1049 text_align_keyword = match style.clone_text_align_last() {
1050 TextAlignLast::Auto if text_align_keyword == TextAlignKeyword::Justify => {
1051 TextAlignKeyword::Start
1052 },
1053 TextAlignLast::Auto => text_align_keyword,
1054 TextAlignLast::Start => TextAlignKeyword::Start,
1055 TextAlignLast::End => TextAlignKeyword::End,
1056 TextAlignLast::Left => TextAlignKeyword::Left,
1057 TextAlignLast::Right => TextAlignKeyword::Right,
1058 TextAlignLast::Center => TextAlignKeyword::Center,
1059 TextAlignLast::Justify => TextAlignKeyword::Justify,
1060 };
1061 }
1062
1063 let text_align = match text_align_keyword {
1064 TextAlignKeyword::Start => TextAlign::Start,
1065 TextAlignKeyword::Center | TextAlignKeyword::MozCenter => TextAlign::Center,
1066 TextAlignKeyword::End => TextAlign::End,
1067 TextAlignKeyword::Left | TextAlignKeyword::MozLeft => {
1068 if style.writing_mode.line_left_is_inline_start() {
1069 TextAlign::Start
1070 } else {
1071 TextAlign::End
1072 }
1073 },
1074 TextAlignKeyword::Right | TextAlignKeyword::MozRight => {
1075 if style.writing_mode.line_left_is_inline_start() {
1076 TextAlign::End
1077 } else {
1078 TextAlign::Start
1079 }
1080 },
1081 TextAlignKeyword::Justify => TextAlign::Start,
1082 };
1083
1084 let (line_start, available_space) = match self.current_line.placement_among_floats.get() {
1085 Some(placement_among_floats) => (
1086 placement_among_floats.start_corner.inline,
1087 placement_among_floats.size.inline,
1088 ),
1089 None => (Au::zero(), self.containing_block.size.inline),
1090 };
1091
1092 let text_indent = self.current_line.start_position.inline;
1099 let line_length = self.current_line.inline_position - whitespace_trimmed - text_indent;
1100 let adjusted_line_start = line_start +
1101 match text_align {
1102 TextAlign::Start => text_indent,
1103 TextAlign::End => (available_space - line_length).max(text_indent),
1104 TextAlign::Center => (available_space - line_length + text_indent)
1105 .scale_by(0.5)
1106 .max(text_indent),
1107 };
1108
1109 let text_justify = self.containing_block.style.clone_text_justify();
1113 let justification_adjustment = match (text_align_keyword, text_justify) {
1114 (TextAlignKeyword::Justify, TextJustify::None) => Au::zero(),
1117 (TextAlignKeyword::Justify, _) => {
1118 match self.current_line.count_justification_opportunities() {
1119 0 => Au::zero(),
1120 num_justification_opportunities => {
1121 (available_space - text_indent - line_length)
1122 .scale_by(1. / num_justification_opportunities as f32)
1123 },
1124 }
1125 },
1126 _ => Au::zero(),
1127 };
1128
1129 let justification_adjustment = justification_adjustment.max(Au::zero());
1132
1133 (adjusted_line_start, justification_adjustment)
1134 }
1135
1136 fn place_float_fragment(&mut self, fragment: &mut BoxFragment) {
1137 let state = self
1138 .sequential_layout_state
1139 .as_mut()
1140 .expect("Tried to lay out a float with no sequential placement state!");
1141
1142 let block_offset_from_containining_block_top = state
1143 .current_block_position_including_margins() -
1144 state.current_containing_block_offset();
1145 state.place_float_fragment(
1146 fragment,
1147 self.containing_block,
1148 CollapsedMargin::zero(),
1149 block_offset_from_containining_block_top,
1150 );
1151 }
1152
1153 fn place_float_line_item_for_commit_to_line(
1162 &mut self,
1163 float_item: &mut FloatLineItem,
1164 line_inline_size_without_trailing_whitespace: Au,
1165 ) {
1166 let mut float_fragment = float_item.fragment.borrow_mut();
1167 let logical_margin_rect_size = float_fragment
1168 .margin_rect()
1169 .size
1170 .to_logical(self.containing_block.style.writing_mode);
1171 let inline_size = logical_margin_rect_size.inline.max(Au::zero());
1172
1173 let available_inline_size = match self.current_line.placement_among_floats.get() {
1174 Some(placement_among_floats) => placement_among_floats.size.inline,
1175 None => self.containing_block.size.inline,
1176 } - line_inline_size_without_trailing_whitespace;
1177
1178 let has_content = self.current_line.has_content || self.current_line_segment.has_content;
1184 let fits_on_line = !has_content || inline_size <= available_inline_size;
1185 let needs_placement_later =
1186 self.current_line.has_floats_waiting_to_be_placed || !fits_on_line;
1187
1188 if needs_placement_later {
1189 self.current_line.has_floats_waiting_to_be_placed = true;
1190 } else {
1191 self.place_float_fragment(&mut float_fragment);
1192 float_item.needs_placement = false;
1193 }
1194
1195 let new_placement = self.place_line_among_floats(&LogicalVec2 {
1200 inline: line_inline_size_without_trailing_whitespace,
1201 block: self.current_line.max_block_size.resolve(),
1202 });
1203 self.current_line
1204 .replace_placement_among_floats(new_placement);
1205 }
1206
1207 fn place_line_among_floats(&self, potential_line_size: &LogicalVec2<Au>) -> LogicalRect<Au> {
1212 let sequential_layout_state = self
1213 .sequential_layout_state
1214 .as_ref()
1215 .expect("Should not have called this function without having floats.");
1216
1217 let ifc_offset_in_float_container = LogicalVec2 {
1218 inline: sequential_layout_state
1219 .floats
1220 .containing_block_info
1221 .inline_start,
1222 block: sequential_layout_state.current_containing_block_offset(),
1223 };
1224
1225 let ceiling = self
1226 .current_line
1227 .line_block_start_considering_placement_among_floats();
1228 let mut placement = PlacementAmongFloats::new(
1229 &sequential_layout_state.floats,
1230 ceiling + ifc_offset_in_float_container.block,
1231 LogicalVec2 {
1232 inline: potential_line_size.inline,
1233 block: potential_line_size.block,
1234 },
1235 &PaddingBorderMargin::zero(),
1236 );
1237
1238 let mut placement_rect = placement.place();
1239 placement_rect.start_corner -= ifc_offset_in_float_container;
1240 placement_rect
1241 }
1242
1243 fn new_potential_line_size_causes_line_break(
1250 &mut self,
1251 potential_line_size: &LogicalVec2<Au>,
1252 ) -> bool {
1253 let available_line_space = if self.sequential_layout_state.is_some() {
1254 self.current_line
1255 .placement_among_floats
1256 .get_or_init(|| self.place_line_among_floats(potential_line_size))
1257 .size
1258 } else {
1259 LogicalVec2 {
1260 inline: self.containing_block.size.inline,
1261 block: MAX_AU,
1262 }
1263 };
1264
1265 let inline_would_overflow = potential_line_size.inline > available_line_space.inline;
1266 let block_would_overflow = potential_line_size.block > available_line_space.block;
1267
1268 let can_break = self.current_line.has_content;
1271
1272 if !can_break {
1278 if self.sequential_layout_state.is_some() &&
1281 (inline_would_overflow || block_would_overflow)
1282 {
1283 let new_placement = self.place_line_among_floats(potential_line_size);
1284 self.current_line
1285 .replace_placement_among_floats(new_placement);
1286 }
1287
1288 return false;
1289 }
1290
1291 if potential_line_size.inline > self.containing_block.size.inline {
1294 return true;
1295 }
1296
1297 if block_would_overflow {
1301 assert!(self.sequential_layout_state.is_some());
1303 let new_placement = self.place_line_among_floats(potential_line_size);
1304 if new_placement.start_corner.block !=
1305 self.current_line
1306 .line_block_start_considering_placement_among_floats()
1307 {
1308 return true;
1309 } else {
1310 self.current_line
1311 .replace_placement_among_floats(new_placement);
1312 return false;
1313 }
1314 }
1315
1316 inline_would_overflow
1320 }
1321
1322 pub(super) fn defer_forced_line_break(&mut self) {
1323 if !self.unbreakable_segment_fits_on_line() {
1326 self.process_line_break(false );
1327 }
1328
1329 self.linebreak_before_new_content = true;
1331
1332 let line_is_empty =
1340 !self.current_line_segment.has_content && !self.current_line.has_content;
1341 if !self.processing_br_element() || line_is_empty {
1342 let strut_size = self
1343 .current_inline_container_state()
1344 .strut_block_sizes
1345 .clone();
1346 self.update_unbreakable_segment_for_new_content(
1347 &strut_size,
1348 Au::zero(),
1349 SegmentContentFlags::empty(),
1350 );
1351 }
1352 }
1353
1354 pub(super) fn possibly_flush_deferred_forced_line_break(&mut self) {
1355 if !self.linebreak_before_new_content {
1356 return;
1357 }
1358
1359 self.commit_current_segment_to_line();
1360 self.process_line_break(true );
1361 self.linebreak_before_new_content = false;
1362 }
1363
1364 fn push_line_item_to_unbreakable_segment(&mut self, line_item: LineItem) {
1365 self.current_line_segment
1366 .push_line_item(line_item, self.inline_box_state_stack.len());
1367 }
1368
1369 pub(super) fn push_glyph_store_to_unbreakable_segment(
1370 &mut self,
1371 glyph_store: std::sync::Arc<GlyphStore>,
1372 text_run: &TextRun,
1373 font_index: usize,
1374 bidi_level: Level,
1375 range: range::Range<ByteIndex>,
1376 ) {
1377 let inline_advance = glyph_store.total_advance();
1378 let flags = if glyph_store.is_whitespace() {
1379 SegmentContentFlags::from(text_run.inline_styles.style.borrow().get_inherited_text())
1380 } else {
1381 SegmentContentFlags::empty()
1382 };
1383
1384 let ifc_font_info = &self.ifc.font_metrics[font_index];
1388 let font_metrics = ifc_font_info.metrics.clone();
1389 let using_fallback_font =
1390 self.current_inline_container_state().font_metrics != font_metrics;
1391
1392 let quirks_mode = self.layout_context.style_context.quirks_mode() != QuirksMode::NoQuirks;
1393 let strut_size = if using_fallback_font {
1394 let container_state = self.current_inline_container_state();
1396 let vertical_align = effective_vertical_align(
1397 &container_state.style,
1398 self.inline_box_state_stack.last().map(|c| &c.base),
1399 );
1400 let mut block_size = container_state.get_block_size_contribution(
1401 vertical_align,
1402 &font_metrics,
1403 &container_state.font_metrics,
1404 );
1405 block_size.adjust_for_baseline_offset(container_state.baseline_offset);
1406 block_size
1407 } else if quirks_mode && !flags.is_collapsible_whitespace() {
1408 self.current_inline_container_state()
1413 .strut_block_sizes
1414 .clone()
1415 } else {
1416 LineBlockSizes::zero()
1417 };
1418 self.update_unbreakable_segment_for_new_content(&strut_size, inline_advance, flags);
1419
1420 let current_inline_box_identifier = self.current_inline_box_identifier();
1421 match self.current_line_segment.line_items.last_mut() {
1422 Some(LineItem::TextRun(inline_box_identifier, line_item))
1423 if *inline_box_identifier == current_inline_box_identifier &&
1424 line_item.can_merge(ifc_font_info.key, bidi_level) =>
1425 {
1426 line_item.text.push(glyph_store);
1427 return;
1428 },
1429 _ => {},
1430 }
1431
1432 let selection_range = if let Some(selection) = &text_run.selection_range {
1433 let intersection = selection.intersect(&range);
1434 if intersection.is_empty() {
1435 let insertion_point_index = selection.begin();
1436 if insertion_point_index >= range.begin() &&
1439 insertion_point_index <= range.end() &&
1440 (range.begin() != insertion_point_index || range.begin().0 == 0)
1441 {
1442 Some(Range::new(
1443 insertion_point_index - range.begin(),
1444 ByteIndex(0),
1445 ))
1446 } else {
1447 None
1448 }
1449 } else {
1450 Some(Range::new(
1451 intersection.begin() - range.begin(),
1452 intersection.length(),
1453 ))
1454 }
1455 } else {
1456 None
1457 };
1458
1459 self.push_line_item_to_unbreakable_segment(LineItem::TextRun(
1460 current_inline_box_identifier,
1461 TextRunLineItem {
1462 text: vec![glyph_store],
1463 base_fragment_info: text_run.base_fragment_info,
1464 inline_styles: text_run.inline_styles.clone(),
1465 font_metrics,
1466 font_key: ifc_font_info.key,
1467 bidi_level,
1468 selection_range,
1469 },
1470 ));
1471 }
1472
1473 fn update_unbreakable_segment_for_new_content(
1474 &mut self,
1475 block_sizes_of_content: &LineBlockSizes,
1476 inline_size: Au,
1477 flags: SegmentContentFlags,
1478 ) {
1479 if flags.is_collapsible_whitespace() || flags.is_wrappable_and_hangable() {
1480 self.current_line_segment.trailing_whitespace_size = inline_size;
1481 } else {
1482 self.current_line_segment.trailing_whitespace_size = Au::zero();
1483 }
1484 if !flags.is_collapsible_whitespace() {
1485 self.current_line_segment.has_content = true;
1486 }
1487
1488 let container_max_block_size = &self
1490 .current_inline_container_state()
1491 .nested_strut_block_sizes
1492 .clone();
1493 self.current_line_segment
1494 .max_block_size
1495 .max_assign(container_max_block_size);
1496 self.current_line_segment
1497 .max_block_size
1498 .max_assign(block_sizes_of_content);
1499
1500 self.current_line_segment.inline_size += inline_size;
1501
1502 *self
1504 .current_inline_container_state()
1505 .has_content
1506 .borrow_mut() = true;
1507 self.propagate_current_nesting_level_white_space_style();
1508 }
1509
1510 fn process_line_break(&mut self, forced_line_break: bool) {
1511 self.current_line_segment.trim_leading_whitespace();
1512 self.finish_current_line_and_reset(forced_line_break);
1513 }
1514
1515 pub(super) fn unbreakable_segment_fits_on_line(&mut self) -> bool {
1516 let potential_line_size = LogicalVec2 {
1517 inline: self.current_line.inline_position + self.current_line_segment.inline_size -
1518 self.current_line_segment.trailing_whitespace_size,
1519 block: self
1520 .current_line_max_block_size_including_nested_containers()
1521 .max(&self.current_line_segment.max_block_size)
1522 .resolve(),
1523 };
1524
1525 !self.new_potential_line_size_causes_line_break(&potential_line_size)
1526 }
1527
1528 pub(super) fn process_soft_wrap_opportunity(&mut self) {
1532 if self.current_line_segment.line_items.is_empty() {
1533 return;
1534 }
1535 if self.text_wrap_mode == TextWrapMode::Nowrap {
1536 return;
1537 }
1538
1539 let potential_line_size = LogicalVec2 {
1540 inline: self.current_line.inline_position + self.current_line_segment.inline_size -
1541 self.current_line_segment.trailing_whitespace_size,
1542 block: self
1543 .current_line_max_block_size_including_nested_containers()
1544 .max(&self.current_line_segment.max_block_size)
1545 .resolve(),
1546 };
1547
1548 if self.new_potential_line_size_causes_line_break(&potential_line_size) {
1549 self.process_line_break(false );
1550 }
1551 self.commit_current_segment_to_line();
1552 }
1553
1554 fn commit_current_segment_to_line(&mut self) {
1557 if self.current_line_segment.line_items.is_empty() && !self.current_line_segment.has_content
1560 {
1561 return;
1562 }
1563
1564 if !self.current_line.has_content {
1565 self.current_line_segment.trim_leading_whitespace();
1566 }
1567
1568 self.current_line.inline_position += self.current_line_segment.inline_size;
1569 self.current_line.max_block_size = self
1570 .current_line_max_block_size_including_nested_containers()
1571 .max(&self.current_line_segment.max_block_size);
1572 let line_inline_size_without_trailing_whitespace =
1573 self.current_line.inline_position - self.current_line_segment.trailing_whitespace_size;
1574
1575 let mut segment_items = mem::take(&mut self.current_line_segment.line_items);
1577 for item in segment_items.iter_mut() {
1578 if let LineItem::Float(_, float_item) = item {
1579 self.place_float_line_item_for_commit_to_line(
1580 float_item,
1581 line_inline_size_without_trailing_whitespace,
1582 );
1583 }
1584 }
1585
1586 if self.current_line.line_items.is_empty() {
1591 let will_break = self.new_potential_line_size_causes_line_break(&LogicalVec2 {
1592 inline: line_inline_size_without_trailing_whitespace,
1593 block: self.current_line_segment.max_block_size.resolve(),
1594 });
1595 assert!(!will_break);
1596 }
1597
1598 self.current_line.line_items.extend(segment_items);
1599 self.current_line.has_content |= self.current_line_segment.has_content;
1600 self.current_line.has_inline_pbm |= self.current_line_segment.has_inline_pbm;
1601
1602 self.current_line_segment.reset();
1603 }
1604}
1605
1606bitflags! {
1607 pub struct SegmentContentFlags: u8 {
1608 const COLLAPSIBLE_WHITESPACE = 0b00000001;
1609 const WRAPPABLE_AND_HANGABLE_WHITESPACE = 0b00000010;
1610 }
1611}
1612
1613impl SegmentContentFlags {
1614 fn is_collapsible_whitespace(&self) -> bool {
1615 self.contains(Self::COLLAPSIBLE_WHITESPACE)
1616 }
1617
1618 fn is_wrappable_and_hangable(&self) -> bool {
1619 self.contains(Self::WRAPPABLE_AND_HANGABLE_WHITESPACE)
1620 }
1621}
1622
1623impl From<&InheritedText> for SegmentContentFlags {
1624 fn from(style_text: &InheritedText) -> Self {
1625 let mut flags = Self::empty();
1626
1627 if !matches!(
1630 style_text.white_space_collapse,
1631 WhiteSpaceCollapse::Preserve | WhiteSpaceCollapse::BreakSpaces
1632 ) {
1633 flags.insert(Self::COLLAPSIBLE_WHITESPACE);
1634 }
1635
1636 if style_text.text_wrap_mode == TextWrapMode::Wrap &&
1639 style_text.white_space_collapse != WhiteSpaceCollapse::BreakSpaces
1640 {
1641 flags.insert(Self::WRAPPABLE_AND_HANGABLE_WHITESPACE);
1642 }
1643 flags
1644 }
1645}
1646
1647impl InlineFormattingContext {
1648 #[servo_tracing::instrument(name = "InlineFormattingContext::new_with_builder", skip_all)]
1649 pub(super) fn new_with_builder(
1650 builder: InlineFormattingContextBuilder,
1651 layout_context: &LayoutContext,
1652 has_first_formatted_line: bool,
1653 is_single_line_text_input: bool,
1654 starting_bidi_level: Level,
1655 ) -> Self {
1656 let text_content: String = builder.text_segments.into_iter().collect();
1658 let mut font_metrics = Vec::new();
1659
1660 let bidi_info = BidiInfo::new(&text_content, Some(starting_bidi_level));
1661 let has_right_to_left_content = bidi_info.has_rtl();
1662
1663 let mut new_linebreaker = LineBreaker::new(text_content.as_str());
1664 for item in builder.inline_items.iter() {
1665 match &mut *item.borrow_mut() {
1666 InlineItem::TextRun(text_run) => {
1667 text_run.borrow_mut().segment_and_shape(
1668 &text_content,
1669 layout_context,
1670 &mut new_linebreaker,
1671 &mut font_metrics,
1672 &bidi_info,
1673 );
1674 },
1675 InlineItem::StartInlineBox(inline_box) => {
1676 let inline_box = &mut *inline_box.borrow_mut();
1677 if let Some(font) = get_font_for_first_font_for_style(
1678 &inline_box.base.style,
1679 &layout_context.font_context,
1680 ) {
1681 inline_box.default_font_index =
1682 Some(add_or_get_font(layout_context, &font, &mut font_metrics));
1683 }
1684 },
1685 InlineItem::Atomic(_, index_in_text, bidi_level) => {
1686 *bidi_level = bidi_info.levels[*index_in_text];
1687 },
1688 InlineItem::OutOfFlowAbsolutelyPositionedBox(..) |
1689 InlineItem::OutOfFlowFloatBox(_) |
1690 InlineItem::EndInlineBox => {},
1691 }
1692 }
1693
1694 InlineFormattingContext {
1695 text_content,
1696 inline_items: builder.inline_items,
1697 inline_boxes: builder.inline_boxes,
1698 font_metrics,
1699 shared_inline_styles: builder
1700 .shared_inline_styles_stack
1701 .last()
1702 .expect("Should have at least one SharedInlineStyle for the root of an IFC")
1703 .clone(),
1704 has_first_formatted_line,
1705 contains_floats: builder.contains_floats,
1706 is_single_line_text_input,
1707 has_right_to_left_content,
1708 }
1709 }
1710
1711 pub(crate) fn repair_style(
1712 &self,
1713 node: &ServoThreadSafeLayoutNode,
1714 new_style: &Arc<ComputedValues>,
1715 ) {
1716 *self.shared_inline_styles.style.borrow_mut() = new_style.clone();
1717 *self.shared_inline_styles.selected.borrow_mut() = node.selected_style();
1718 }
1719
1720 pub(crate) fn inline_start_for_first_line(
1721 &self,
1722 containing_block: IndefiniteContainingBlock,
1723 ) -> Au {
1724 if !self.has_first_formatted_line {
1725 return Au::zero();
1726 }
1727 containing_block
1728 .style
1729 .get_inherited_text()
1730 .text_indent
1731 .length
1732 .to_used_value(containing_block.size.inline.unwrap_or_default())
1733 }
1734
1735 pub(super) fn layout(
1736 &self,
1737 layout_context: &LayoutContext,
1738 positioning_context: &mut PositioningContext,
1739 containing_block: &ContainingBlock,
1740 sequential_layout_state: Option<&mut SequentialLayoutState>,
1741 collapsible_with_parent_start_margin: CollapsibleWithParentStartMargin,
1742 ) -> CacheableLayoutResult {
1743 for inline_box in self.inline_boxes.iter() {
1745 inline_box.borrow().base.clear_fragments();
1746 }
1747
1748 let style = containing_block.style;
1749
1750 let default_font_metrics =
1753 get_font_for_first_font_for_style(style, &layout_context.font_context)
1754 .map(|font| font.metrics.clone());
1755
1756 let style_text = containing_block.style.get_inherited_text();
1757 let mut inline_container_state_flags = InlineContainerStateFlags::empty();
1758 if inline_container_needs_strut(style, layout_context, None) {
1759 inline_container_state_flags.insert(InlineContainerStateFlags::CREATE_STRUT);
1760 }
1761 if self.is_single_line_text_input {
1762 inline_container_state_flags
1763 .insert(InlineContainerStateFlags::IS_SINGLE_LINE_TEXT_INPUT);
1764 }
1765
1766 let mut layout = InlineFormattingContextLayout {
1767 positioning_context,
1768 containing_block,
1769 sequential_layout_state,
1770 layout_context,
1771 ifc: self,
1772 fragments: Vec::new(),
1773 current_line: LineUnderConstruction::new(LogicalVec2 {
1774 inline: self.inline_start_for_first_line(containing_block.into()),
1775 block: Au::zero(),
1776 }),
1777 root_nesting_level: InlineContainerState::new(
1778 style.to_arc(),
1779 inline_container_state_flags,
1780 None, default_font_metrics.as_ref(),
1782 ),
1783 inline_box_state_stack: Vec::new(),
1784 inline_box_states: Vec::with_capacity(self.inline_boxes.len()),
1785 current_line_segment: UnbreakableSegmentUnderConstruction::new(),
1786 linebreak_before_new_content: false,
1787 deferred_br_clear: Clear::None,
1788 have_deferred_soft_wrap_opportunity: false,
1789 has_line_boxes: false,
1790 depends_on_block_constraints: false,
1791 white_space_collapse: style_text.white_space_collapse,
1792 text_wrap_mode: style_text.text_wrap_mode,
1793 baselines: Baselines::default(),
1794 };
1795
1796 if let Some(ref mut sequential_layout_state) = layout.sequential_layout_state {
1800 sequential_layout_state.collapse_margins();
1801 }
1803
1804 for item in self.inline_items.iter() {
1805 let item = &*item.borrow();
1806
1807 if !matches!(item, InlineItem::EndInlineBox) {
1809 layout.possibly_flush_deferred_forced_line_break();
1810 }
1811
1812 match item {
1813 InlineItem::StartInlineBox(inline_box) => {
1814 layout.start_inline_box(&inline_box.borrow());
1815 },
1816 InlineItem::EndInlineBox => layout.finish_inline_box(),
1817 InlineItem::TextRun(run) => run.borrow().layout_into_line_items(&mut layout),
1818 InlineItem::Atomic(atomic_formatting_context, offset_in_text, bidi_level) => {
1819 atomic_formatting_context.borrow().layout_into_line_items(
1820 &mut layout,
1821 *offset_in_text,
1822 *bidi_level,
1823 );
1824 },
1825 InlineItem::OutOfFlowAbsolutelyPositionedBox(positioned_box, _) => {
1826 layout.push_line_item_to_unbreakable_segment(LineItem::AbsolutelyPositioned(
1827 layout.current_inline_box_identifier(),
1828 AbsolutelyPositionedLineItem {
1829 absolutely_positioned_box: positioned_box.clone(),
1830 },
1831 ));
1832 },
1833 InlineItem::OutOfFlowFloatBox(float_box) => {
1834 float_box.borrow().layout_into_line_items(&mut layout);
1835 },
1836 }
1837 }
1838
1839 layout.finish_last_line();
1840
1841 let mut collapsible_margins_in_children = CollapsedBlockMargins::zero();
1842 let content_block_size = layout.current_line.start_position.block;
1843 collapsible_margins_in_children.collapsed_through = !layout.has_line_boxes &&
1844 content_block_size.is_zero() &&
1845 collapsible_with_parent_start_margin.0;
1846
1847 CacheableLayoutResult {
1848 fragments: layout.fragments,
1849 content_block_size,
1850 collapsible_margins_in_children,
1851 baselines: layout.baselines,
1852 depends_on_block_constraints: layout.depends_on_block_constraints,
1853 content_inline_size_for_table: None,
1854 specific_layout_info: None,
1855 }
1856 }
1857
1858 fn next_character_prevents_soft_wrap_opportunity(&self, index: usize) -> bool {
1859 let Some(character) = self.text_content[index..].chars().nth(1) else {
1860 return false;
1861 };
1862 char_prevents_soft_wrap_opportunity_when_before_or_after_atomic(character)
1863 }
1864
1865 fn previous_character_prevents_soft_wrap_opportunity(&self, index: usize) -> bool {
1866 let Some(character) = self.text_content[0..index].chars().next_back() else {
1867 return false;
1868 };
1869 char_prevents_soft_wrap_opportunity_when_before_or_after_atomic(character)
1870 }
1871}
1872
1873impl InlineContainerState {
1874 fn new(
1875 style: Arc<ComputedValues>,
1876 flags: InlineContainerStateFlags,
1877 parent_container: Option<&InlineContainerState>,
1878 font_metrics: Option<&FontMetrics>,
1879 ) -> Self {
1880 let font_metrics = font_metrics.cloned().unwrap_or_else(FontMetrics::empty);
1881 let mut baseline_offset = Au::zero();
1882 let mut strut_block_sizes = Self::get_block_sizes_with_style(
1883 effective_vertical_align(&style, parent_container),
1884 &style,
1885 &font_metrics,
1886 &font_metrics,
1887 &flags,
1888 );
1889 if let Some(parent_container) = parent_container {
1890 baseline_offset = parent_container.get_cumulative_baseline_offset_for_child(
1893 style.clone_vertical_align(),
1894 &strut_block_sizes,
1895 );
1896 strut_block_sizes.adjust_for_baseline_offset(baseline_offset);
1897 }
1898
1899 let mut nested_block_sizes = parent_container
1900 .map(|container| container.nested_strut_block_sizes.clone())
1901 .unwrap_or_else(LineBlockSizes::zero);
1902 if flags.contains(InlineContainerStateFlags::CREATE_STRUT) {
1903 nested_block_sizes.max_assign(&strut_block_sizes);
1904 }
1905
1906 Self {
1907 style,
1908 flags,
1909 has_content: RefCell::new(false),
1910 nested_strut_block_sizes: nested_block_sizes,
1911 strut_block_sizes,
1912 baseline_offset,
1913 font_metrics,
1914 }
1915 }
1916
1917 fn get_block_sizes_with_style(
1918 vertical_align: VerticalAlign,
1919 style: &ComputedValues,
1920 font_metrics: &FontMetrics,
1921 font_metrics_of_first_font: &FontMetrics,
1922 flags: &InlineContainerStateFlags,
1923 ) -> LineBlockSizes {
1924 let line_height = line_height(style, font_metrics, flags);
1925
1926 if !is_baseline_relative(vertical_align) {
1927 return LineBlockSizes {
1928 line_height,
1929 baseline_relative_size_for_line_height: None,
1930 size_for_baseline_positioning: BaselineRelativeSize::zero(),
1931 };
1932 }
1933
1934 let mut ascent = font_metrics.ascent;
1943 let mut descent = font_metrics.descent;
1944 if style.get_font().line_height == LineHeight::Normal {
1945 let half_leading_from_line_gap =
1946 (font_metrics.line_gap - descent - ascent).scale_by(0.5);
1947 ascent += half_leading_from_line_gap;
1948 descent += half_leading_from_line_gap;
1949 }
1950
1951 let size_for_baseline_positioning = BaselineRelativeSize { ascent, descent };
1955
1956 if style.get_font().line_height != LineHeight::Normal {
1972 ascent = font_metrics_of_first_font.ascent;
1973 descent = font_metrics_of_first_font.descent;
1974 let half_leading = (line_height - (ascent + descent)).scale_by(0.5);
1975 ascent += half_leading;
1980 descent = line_height - ascent;
1981 }
1982
1983 LineBlockSizes {
1984 line_height,
1985 baseline_relative_size_for_line_height: Some(BaselineRelativeSize { ascent, descent }),
1986 size_for_baseline_positioning,
1987 }
1988 }
1989
1990 fn get_block_size_contribution(
1991 &self,
1992 vertical_align: VerticalAlign,
1993 font_metrics: &FontMetrics,
1994 font_metrics_of_first_font: &FontMetrics,
1995 ) -> LineBlockSizes {
1996 Self::get_block_sizes_with_style(
1997 vertical_align,
1998 &self.style,
1999 font_metrics,
2000 font_metrics_of_first_font,
2001 &self.flags,
2002 )
2003 }
2004
2005 fn get_cumulative_baseline_offset_for_child(
2006 &self,
2007 child_vertical_align: VerticalAlign,
2008 child_block_size: &LineBlockSizes,
2009 ) -> Au {
2010 let block_size = self.get_block_size_contribution(
2011 child_vertical_align.clone(),
2012 &self.font_metrics,
2013 &self.font_metrics,
2014 );
2015 self.baseline_offset +
2016 match child_vertical_align {
2017 VerticalAlign::Keyword(VerticalAlignKeyword::Baseline) |
2022 VerticalAlign::Keyword(VerticalAlignKeyword::Top) |
2023 VerticalAlign::Keyword(VerticalAlignKeyword::Bottom) => Au::zero(),
2024 VerticalAlign::Keyword(VerticalAlignKeyword::Sub) => {
2025 block_size.resolve().scale_by(FONT_SUBSCRIPT_OFFSET_RATIO)
2026 },
2027 VerticalAlign::Keyword(VerticalAlignKeyword::Super) => {
2028 -block_size.resolve().scale_by(FONT_SUPERSCRIPT_OFFSET_RATIO)
2029 },
2030 VerticalAlign::Keyword(VerticalAlignKeyword::TextTop) => {
2031 child_block_size.size_for_baseline_positioning.ascent - self.font_metrics.ascent
2032 },
2033 VerticalAlign::Keyword(VerticalAlignKeyword::Middle) => {
2034 (child_block_size.size_for_baseline_positioning.ascent -
2037 child_block_size.size_for_baseline_positioning.descent -
2038 self.font_metrics.x_height)
2039 .scale_by(0.5)
2040 },
2041 VerticalAlign::Keyword(VerticalAlignKeyword::TextBottom) => {
2042 self.font_metrics.descent -
2043 child_block_size.size_for_baseline_positioning.descent
2044 },
2045 VerticalAlign::Length(length_percentage) => {
2046 -length_percentage.to_used_value(child_block_size.line_height)
2047 },
2048 }
2049 }
2050}
2051
2052impl IndependentFormattingContext {
2053 fn layout_into_line_items(
2054 &self,
2055 layout: &mut InlineFormattingContextLayout,
2056 offset_in_text: usize,
2057 bidi_level: Level,
2058 ) {
2059 let mut child_positioning_context = PositioningContext::default();
2061 let IndependentFloatOrAtomicLayoutResult {
2062 mut fragment,
2063 baselines,
2064 pbm_sums,
2065 } = self.layout_float_or_atomic_inline(
2066 layout.layout_context,
2067 &mut child_positioning_context,
2068 layout.containing_block,
2069 );
2070
2071 layout.depends_on_block_constraints |= fragment.base.flags.contains(
2074 FragmentFlags::SIZE_DEPENDS_ON_BLOCK_CONSTRAINTS_AND_CAN_BE_CHILD_OF_FLEX_ITEM,
2075 );
2076
2077 let container_writing_mode = layout.containing_block.style.writing_mode;
2079 let pbm_physical_offset = pbm_sums
2080 .start_offset()
2081 .to_physical_size(container_writing_mode);
2082 fragment.content_rect = fragment
2083 .content_rect
2084 .translate(pbm_physical_offset.to_vector());
2085
2086 fragment = fragment.with_baselines(baselines);
2088
2089 let positioning_context = if self.is_replaced() {
2092 None
2093 } else {
2094 if fragment
2095 .style
2096 .establishes_containing_block_for_absolute_descendants(fragment.base.flags)
2097 {
2098 child_positioning_context
2099 .layout_collected_children(layout.layout_context, &mut fragment);
2100 }
2101 Some(child_positioning_context)
2102 };
2103
2104 if layout.text_wrap_mode == TextWrapMode::Wrap &&
2105 !layout
2106 .ifc
2107 .previous_character_prevents_soft_wrap_opportunity(offset_in_text)
2108 {
2109 layout.process_soft_wrap_opportunity();
2110 }
2111
2112 let size = pbm_sums.sum() +
2113 fragment
2114 .content_rect
2115 .size
2116 .to_logical(container_writing_mode);
2117 let baseline_offset = self
2118 .pick_baseline(&fragment.baselines(container_writing_mode))
2119 .map(|baseline| pbm_sums.block_start + baseline)
2120 .unwrap_or(size.block);
2121
2122 let (block_sizes, baseline_offset_in_parent) =
2123 self.get_block_sizes_and_baseline_offset(layout, size.block, baseline_offset);
2124 layout.update_unbreakable_segment_for_new_content(
2125 &block_sizes,
2126 size.inline,
2127 SegmentContentFlags::empty(),
2128 );
2129
2130 let fragment = ArcRefCell::new(fragment);
2131 self.base.set_fragment(Fragment::Box(fragment.clone()));
2132
2133 layout.push_line_item_to_unbreakable_segment(LineItem::Atomic(
2134 layout.current_inline_box_identifier(),
2135 AtomicLineItem {
2136 fragment,
2137 size,
2138 positioning_context,
2139 baseline_offset_in_parent,
2140 baseline_offset_in_item: baseline_offset,
2141 bidi_level,
2142 },
2143 ));
2144
2145 if !layout
2148 .ifc
2149 .next_character_prevents_soft_wrap_opportunity(offset_in_text)
2150 {
2151 layout.have_deferred_soft_wrap_opportunity = true;
2152 }
2153 }
2154
2155 fn pick_baseline(&self, baselines: &Baselines) -> Option<Au> {
2159 match self.style().clone_baseline_source() {
2160 BaselineSource::First => baselines.first,
2161 BaselineSource::Last => baselines.last,
2162 BaselineSource::Auto if self.is_block_container() => baselines.last,
2163 BaselineSource::Auto => baselines.first,
2164 }
2165 }
2166
2167 fn get_block_sizes_and_baseline_offset(
2168 &self,
2169 ifc: &InlineFormattingContextLayout,
2170 block_size: Au,
2171 baseline_offset_in_content_area: Au,
2172 ) -> (LineBlockSizes, Au) {
2173 let mut contribution = if !is_baseline_relative(self.style().clone_vertical_align()) {
2174 LineBlockSizes {
2175 line_height: block_size,
2176 baseline_relative_size_for_line_height: None,
2177 size_for_baseline_positioning: BaselineRelativeSize::zero(),
2178 }
2179 } else {
2180 let baseline_relative_size = BaselineRelativeSize {
2181 ascent: baseline_offset_in_content_area,
2182 descent: block_size - baseline_offset_in_content_area,
2183 };
2184 LineBlockSizes {
2185 line_height: block_size,
2186 baseline_relative_size_for_line_height: Some(baseline_relative_size.clone()),
2187 size_for_baseline_positioning: baseline_relative_size,
2188 }
2189 };
2190
2191 let baseline_offset = ifc
2192 .current_inline_container_state()
2193 .get_cumulative_baseline_offset_for_child(
2194 self.style().clone_vertical_align(),
2195 &contribution,
2196 );
2197 contribution.adjust_for_baseline_offset(baseline_offset);
2198
2199 (contribution, baseline_offset)
2200 }
2201}
2202
2203impl FloatBox {
2204 fn layout_into_line_items(&self, layout: &mut InlineFormattingContextLayout) {
2205 let fragment = ArcRefCell::new(self.layout(
2206 layout.layout_context,
2207 layout.positioning_context,
2208 layout.containing_block,
2209 ));
2210
2211 self.contents
2212 .base
2213 .set_fragment(Fragment::Box(fragment.clone()));
2214 layout.push_line_item_to_unbreakable_segment(LineItem::Float(
2215 layout.current_inline_box_identifier(),
2216 FloatLineItem {
2217 fragment,
2218 needs_placement: true,
2219 },
2220 ));
2221 }
2222}
2223
2224fn place_pending_floats(ifc: &mut InlineFormattingContextLayout, line_items: &mut [LineItem]) {
2225 for item in line_items.iter_mut() {
2226 if let LineItem::Float(_, float_line_item) = item {
2227 if float_line_item.needs_placement {
2228 ifc.place_float_fragment(&mut float_line_item.fragment.borrow_mut());
2229 }
2230 }
2231 }
2232}
2233
2234fn line_height(
2235 parent_style: &ComputedValues,
2236 font_metrics: &FontMetrics,
2237 flags: &InlineContainerStateFlags,
2238) -> Au {
2239 let font = parent_style.get_font();
2240 let font_size = font.font_size.computed_size();
2241 let mut line_height = match font.line_height {
2242 LineHeight::Normal => font_metrics.line_gap,
2243 LineHeight::Number(number) => (font_size * number.0).into(),
2244 LineHeight::Length(length) => length.0.into(),
2245 };
2246
2247 if flags.contains(InlineContainerStateFlags::IS_SINGLE_LINE_TEXT_INPUT) {
2251 line_height.max_assign(font_metrics.line_gap);
2252 }
2253
2254 line_height
2255}
2256
2257fn effective_vertical_align(
2258 style: &ComputedValues,
2259 container: Option<&InlineContainerState>,
2260) -> VerticalAlign {
2261 if container.is_none() {
2262 VerticalAlign::Keyword(VerticalAlignKeyword::Baseline)
2266 } else {
2267 style.clone_vertical_align()
2268 }
2269}
2270
2271fn is_baseline_relative(vertical_align: VerticalAlign) -> bool {
2272 !matches!(
2273 vertical_align,
2274 VerticalAlign::Keyword(VerticalAlignKeyword::Top) |
2275 VerticalAlign::Keyword(VerticalAlignKeyword::Bottom)
2276 )
2277}
2278
2279fn inline_container_needs_strut(
2305 style: &ComputedValues,
2306 layout_context: &LayoutContext,
2307 pbm: Option<&PaddingBorderMargin>,
2308) -> bool {
2309 if layout_context.style_context.quirks_mode() == QuirksMode::NoQuirks {
2310 return true;
2311 }
2312
2313 if style.get_box().display.is_list_item() {
2316 return true;
2317 }
2318
2319 pbm.is_some_and(|pbm| !pbm.padding_border_sums.inline.is_zero())
2320}
2321
2322impl ComputeInlineContentSizes for InlineFormattingContext {
2323 fn compute_inline_content_sizes(
2327 &self,
2328 layout_context: &LayoutContext,
2329 constraint_space: &ConstraintSpace,
2330 ) -> InlineContentSizesResult {
2331 ContentSizesComputation::compute(self, layout_context, constraint_space)
2332 }
2333}
2334
2335struct ContentSizesComputation<'layout_data> {
2337 layout_context: &'layout_data LayoutContext<'layout_data>,
2338 constraint_space: &'layout_data ConstraintSpace<'layout_data>,
2339 paragraph: ContentSizes,
2340 current_line: ContentSizes,
2341 pending_whitespace: ContentSizes,
2343 had_content_yet_for_min_content: bool,
2346 had_content_yet_for_max_content: bool,
2349 ending_inline_pbm_stack: Vec<Au>,
2352 depends_on_block_constraints: bool,
2353}
2354
2355impl<'layout_data> ContentSizesComputation<'layout_data> {
2356 fn traverse(
2357 mut self,
2358 inline_formatting_context: &InlineFormattingContext,
2359 ) -> InlineContentSizesResult {
2360 self.add_inline_size(
2361 inline_formatting_context.inline_start_for_first_line(self.constraint_space.into()),
2362 );
2363 for inline_item in inline_formatting_context.inline_items.iter() {
2364 self.process_item(&inline_item.borrow(), inline_formatting_context);
2365 }
2366 self.forced_line_break();
2367
2368 InlineContentSizesResult {
2369 sizes: self.paragraph,
2370 depends_on_block_constraints: self.depends_on_block_constraints,
2371 }
2372 }
2373
2374 fn process_item(
2375 &mut self,
2376 inline_item: &InlineItem,
2377 inline_formatting_context: &InlineFormattingContext,
2378 ) {
2379 match inline_item {
2380 InlineItem::StartInlineBox(inline_box) => {
2381 let inline_box = inline_box.borrow();
2385 let zero = Au::zero();
2386 let writing_mode = self.constraint_space.style.writing_mode;
2387 let layout_style = inline_box.layout_style();
2388 let padding = layout_style
2389 .padding(writing_mode)
2390 .percentages_relative_to(zero);
2391 let border = layout_style.border_width(writing_mode);
2392 let margin = inline_box
2393 .base
2394 .style
2395 .margin(writing_mode)
2396 .percentages_relative_to(zero)
2397 .auto_is(Au::zero);
2398
2399 let pbm = margin + padding + border;
2400 if inline_box.is_first_split {
2401 self.add_inline_size(pbm.inline_start);
2402 }
2403 if inline_box.is_last_split {
2404 self.ending_inline_pbm_stack.push(pbm.inline_end);
2405 } else {
2406 self.ending_inline_pbm_stack.push(Au::zero());
2407 }
2408 },
2409 InlineItem::EndInlineBox => {
2410 let length = self.ending_inline_pbm_stack.pop().unwrap_or_else(Au::zero);
2411 self.add_inline_size(length);
2412 },
2413 InlineItem::TextRun(text_run) => {
2414 let text_run = &*text_run.borrow();
2415 let parent_style = text_run.inline_styles.style.borrow();
2416 for segment in text_run.shaped_text.iter() {
2417 let style_text = parent_style.get_inherited_text();
2418 let can_wrap = style_text.text_wrap_mode == TextWrapMode::Wrap;
2419
2420 let break_at_start =
2423 segment.break_at_start && self.had_content_yet_for_min_content;
2424
2425 for (run_index, run) in segment.runs.iter().enumerate() {
2426 if can_wrap && (run_index != 0 || break_at_start) {
2429 self.line_break_opportunity();
2430 }
2431
2432 let advance = run.glyph_store.total_advance();
2433 if run.glyph_store.is_whitespace() {
2434 if run.is_single_preserved_newline() {
2437 self.forced_line_break();
2438 continue;
2439 }
2440 if !matches!(
2441 style_text.white_space_collapse,
2442 WhiteSpaceCollapse::Preserve | WhiteSpaceCollapse::BreakSpaces
2443 ) {
2444 if self.had_content_yet_for_min_content {
2445 if can_wrap {
2446 self.line_break_opportunity();
2447 } else {
2448 self.pending_whitespace.min_content += advance;
2449 }
2450 }
2451 if self.had_content_yet_for_max_content {
2452 self.pending_whitespace.max_content += advance;
2453 }
2454 continue;
2455 }
2456 if can_wrap {
2457 self.pending_whitespace.max_content += advance;
2458 self.commit_pending_whitespace();
2459 self.line_break_opportunity();
2460 continue;
2461 }
2462 }
2463
2464 self.commit_pending_whitespace();
2465 self.add_inline_size(advance);
2466
2467 if can_wrap && run.glyph_store.ends_with_whitespace() {
2472 self.line_break_opportunity();
2473 }
2474 }
2475 }
2476 },
2477 InlineItem::Atomic(atomic, offset_in_text, _level) => {
2478 let InlineContentSizesResult {
2479 sizes: outer,
2480 depends_on_block_constraints,
2481 } = atomic.borrow().outer_inline_content_sizes(
2482 self.layout_context,
2483 &self.constraint_space.into(),
2484 &LogicalVec2::zero(),
2485 false, );
2487 self.depends_on_block_constraints |= depends_on_block_constraints;
2488
2489 if self.had_content_yet_for_min_content &&
2491 !inline_formatting_context
2492 .previous_character_prevents_soft_wrap_opportunity(*offset_in_text)
2493 {
2494 self.line_break_opportunity();
2495 }
2496
2497 self.commit_pending_whitespace();
2498 self.current_line += outer;
2499
2500 if !inline_formatting_context
2502 .next_character_prevents_soft_wrap_opportunity(*offset_in_text)
2503 {
2504 self.line_break_opportunity();
2505 }
2506 },
2507 _ => {},
2508 }
2509 }
2510
2511 fn add_inline_size(&mut self, l: Au) {
2512 self.current_line.min_content += l;
2513 self.current_line.max_content += l;
2514 }
2515
2516 fn line_break_opportunity(&mut self) {
2517 self.pending_whitespace.min_content = Au::zero();
2521 let current_min_content = mem::take(&mut self.current_line.min_content);
2522 self.paragraph.min_content.max_assign(current_min_content);
2523 self.had_content_yet_for_min_content = false;
2524 }
2525
2526 fn forced_line_break(&mut self) {
2527 self.line_break_opportunity();
2529
2530 self.pending_whitespace.max_content = Au::zero();
2532 let current_max_content = mem::take(&mut self.current_line.max_content);
2533 self.paragraph.max_content.max_assign(current_max_content);
2534 self.had_content_yet_for_max_content = false;
2535 }
2536
2537 fn commit_pending_whitespace(&mut self) {
2538 self.current_line += mem::take(&mut self.pending_whitespace);
2539 self.had_content_yet_for_min_content = true;
2540 self.had_content_yet_for_max_content = true;
2541 }
2542
2543 fn compute(
2545 inline_formatting_context: &InlineFormattingContext,
2546 layout_context: &'layout_data LayoutContext,
2547 constraint_space: &'layout_data ConstraintSpace,
2548 ) -> InlineContentSizesResult {
2549 Self {
2550 layout_context,
2551 constraint_space,
2552 paragraph: ContentSizes::zero(),
2553 current_line: ContentSizes::zero(),
2554 pending_whitespace: ContentSizes::zero(),
2555 had_content_yet_for_min_content: false,
2556 had_content_yet_for_max_content: false,
2557 ending_inline_pbm_stack: Vec::new(),
2558 depends_on_block_constraints: false,
2559 }
2560 .traverse(inline_formatting_context)
2561 }
2562}
2563
2564fn char_prevents_soft_wrap_opportunity_when_before_or_after_atomic(character: char) -> bool {
2576 if character == '\u{00A0}' {
2577 return false;
2578 }
2579 let class = linebreak_property(character);
2580 class == XI_LINE_BREAKING_CLASS_GL ||
2581 class == XI_LINE_BREAKING_CLASS_WJ ||
2582 class == XI_LINE_BREAKING_CLASS_ZWJ
2583}