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, 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 clear_fragment_layout_cache(&self) {
251 match self {
252 InlineItem::StartInlineBox(inline_box) => {
253 inline_box.borrow().base.clear_fragment_layout_cache()
254 },
255 InlineItem::EndInlineBox | InlineItem::TextRun(..) => {},
256 InlineItem::OutOfFlowAbsolutelyPositionedBox(positioned_box, ..) => {
257 positioned_box
258 .borrow()
259 .context
260 .base
261 .clear_fragment_layout_cache();
262 },
263 InlineItem::OutOfFlowFloatBox(float_box) => float_box
264 .borrow()
265 .contents
266 .base
267 .clear_fragment_layout_cache(),
268 InlineItem::Atomic(independent_formatting_context, ..) => {
269 independent_formatting_context
270 .borrow()
271 .base
272 .clear_fragment_layout_cache()
273 },
274 }
275 }
276
277 pub(crate) fn with_base<T>(&self, callback: impl FnOnce(&LayoutBoxBase) -> T) -> T {
278 match self {
279 InlineItem::StartInlineBox(inline_box) => callback(&inline_box.borrow().base),
280 InlineItem::EndInlineBox | InlineItem::TextRun(..) => {
281 unreachable!("Should never have these kind of fragments attached to a DOM node")
282 },
283 InlineItem::OutOfFlowAbsolutelyPositionedBox(positioned_box, ..) => {
284 callback(&positioned_box.borrow().context.base)
285 },
286 InlineItem::OutOfFlowFloatBox(float_box) => callback(&float_box.borrow().contents.base),
287 InlineItem::Atomic(independent_formatting_context, ..) => {
288 callback(&independent_formatting_context.borrow().base)
289 },
290 }
291 }
292
293 pub(crate) fn with_base_mut(&mut self, callback: impl Fn(&mut LayoutBoxBase)) {
294 match self {
295 InlineItem::StartInlineBox(inline_box) => {
296 callback(&mut inline_box.borrow_mut().base);
297 },
298 InlineItem::EndInlineBox | InlineItem::TextRun(..) => {
299 unreachable!("Should never have these kind of fragments attached to a DOM node")
300 },
301 InlineItem::OutOfFlowAbsolutelyPositionedBox(positioned_box, ..) => {
302 callback(&mut positioned_box.borrow_mut().context.base)
303 },
304 InlineItem::OutOfFlowFloatBox(float_box) => {
305 callback(&mut float_box.borrow_mut().contents.base)
306 },
307 InlineItem::Atomic(independent_formatting_context, ..) => {
308 callback(&mut independent_formatting_context.borrow_mut().base)
309 },
310 }
311 }
312}
313
314struct LineUnderConstruction {
321 start_position: LogicalVec2<Au>,
324
325 inline_position: Au,
328
329 max_block_size: LineBlockSizes,
333
334 has_content: bool,
337
338 has_floats_waiting_to_be_placed: bool,
342
343 placement_among_floats: OnceCell<LogicalRect<Au>>,
348
349 line_items: Vec<LineItem>,
352}
353
354impl LineUnderConstruction {
355 fn new(start_position: LogicalVec2<Au>) -> Self {
356 Self {
357 inline_position: start_position.inline,
358 start_position,
359 max_block_size: LineBlockSizes::zero(),
360 has_content: false,
361 has_floats_waiting_to_be_placed: false,
362 placement_among_floats: OnceCell::new(),
363 line_items: Vec::new(),
364 }
365 }
366
367 fn line_block_start_considering_placement_among_floats(&self) -> Au {
368 match self.placement_among_floats.get() {
369 Some(placement_among_floats) => placement_among_floats.start_corner.block,
370 None => self.start_position.block,
371 }
372 }
373
374 fn replace_placement_among_floats(&mut self, new_placement: LogicalRect<Au>) {
375 self.placement_among_floats.take();
376 let _ = self.placement_among_floats.set(new_placement);
377 }
378
379 fn trim_trailing_whitespace(&mut self) -> Au {
381 let mut whitespace_trimmed = Au::zero();
386 for item in self.line_items.iter_mut().rev() {
387 if !item.trim_whitespace_at_end(&mut whitespace_trimmed) {
388 break;
389 }
390 }
391
392 whitespace_trimmed
393 }
394
395 fn count_justification_opportunities(&self) -> usize {
397 self.line_items
398 .iter()
399 .filter_map(|item| match item {
400 LineItem::TextRun(_, text_run) => Some(
401 text_run
402 .text
403 .iter()
404 .map(|glyph_store| glyph_store.total_word_separators())
405 .sum::<usize>(),
406 ),
407 _ => None,
408 })
409 .sum()
410 }
411}
412
413#[derive(Clone, Debug)]
419struct BaselineRelativeSize {
420 ascent: Au,
424
425 descent: Au,
429}
430
431impl BaselineRelativeSize {
432 fn zero() -> Self {
433 Self {
434 ascent: Au::zero(),
435 descent: Au::zero(),
436 }
437 }
438
439 fn max(&self, other: &Self) -> Self {
440 BaselineRelativeSize {
441 ascent: self.ascent.max(other.ascent),
442 descent: self.descent.max(other.descent),
443 }
444 }
445
446 fn adjust_for_nested_baseline_offset(&mut self, baseline_offset: Au) {
460 self.ascent -= baseline_offset;
461 self.descent += baseline_offset;
462 }
463}
464
465#[derive(Clone, Debug)]
466struct LineBlockSizes {
467 line_height: Au,
468 baseline_relative_size_for_line_height: Option<BaselineRelativeSize>,
469 size_for_baseline_positioning: BaselineRelativeSize,
470}
471
472impl LineBlockSizes {
473 fn zero() -> Self {
474 LineBlockSizes {
475 line_height: Au::zero(),
476 baseline_relative_size_for_line_height: None,
477 size_for_baseline_positioning: BaselineRelativeSize::zero(),
478 }
479 }
480
481 fn resolve(&self) -> Au {
482 let height_from_ascent_and_descent = self
483 .baseline_relative_size_for_line_height
484 .as_ref()
485 .map(|size| (size.ascent + size.descent).abs())
486 .unwrap_or_else(Au::zero);
487 self.line_height.max(height_from_ascent_and_descent)
488 }
489
490 fn max(&self, other: &LineBlockSizes) -> LineBlockSizes {
491 let baseline_relative_size = match (
492 self.baseline_relative_size_for_line_height.as_ref(),
493 other.baseline_relative_size_for_line_height.as_ref(),
494 ) {
495 (Some(our_size), Some(other_size)) => Some(our_size.max(other_size)),
496 (our_size, other_size) => our_size.or(other_size).cloned(),
497 };
498 Self {
499 line_height: self.line_height.max(other.line_height),
500 baseline_relative_size_for_line_height: baseline_relative_size,
501 size_for_baseline_positioning: self
502 .size_for_baseline_positioning
503 .max(&other.size_for_baseline_positioning),
504 }
505 }
506
507 fn max_assign(&mut self, other: &LineBlockSizes) {
508 *self = self.max(other);
509 }
510
511 fn adjust_for_baseline_offset(&mut self, baseline_offset: Au) {
512 if let Some(size) = self.baseline_relative_size_for_line_height.as_mut() {
513 size.adjust_for_nested_baseline_offset(baseline_offset)
514 }
515 self.size_for_baseline_positioning
516 .adjust_for_nested_baseline_offset(baseline_offset);
517 }
518
519 fn find_baseline_offset(&self) -> Au {
526 match self.baseline_relative_size_for_line_height.as_ref() {
527 Some(size) => size.ascent,
528 None => {
529 let leading = self.resolve() -
532 (self.size_for_baseline_positioning.ascent +
533 self.size_for_baseline_positioning.descent);
534 leading.scale_by(0.5) + self.size_for_baseline_positioning.ascent
535 },
536 }
537 }
538}
539
540struct UnbreakableSegmentUnderConstruction {
544 inline_size: Au,
546
547 max_block_size: LineBlockSizes,
550
551 line_items: Vec<LineItem>,
553
554 inline_box_hierarchy_depth: Option<usize>,
557
558 has_content: bool,
562
563 trailing_whitespace_size: Au,
565}
566
567impl UnbreakableSegmentUnderConstruction {
568 fn new() -> Self {
569 Self {
570 inline_size: Au::zero(),
571 max_block_size: LineBlockSizes {
572 line_height: Au::zero(),
573 baseline_relative_size_for_line_height: None,
574 size_for_baseline_positioning: BaselineRelativeSize::zero(),
575 },
576 line_items: Vec::new(),
577 inline_box_hierarchy_depth: None,
578 has_content: false,
579 trailing_whitespace_size: Au::zero(),
580 }
581 }
582
583 fn reset(&mut self) {
585 assert!(self.line_items.is_empty()); self.inline_size = Au::zero();
587 self.max_block_size = LineBlockSizes::zero();
588 self.inline_box_hierarchy_depth = None;
589 self.has_content = false;
590 self.trailing_whitespace_size = Au::zero();
591 }
592
593 fn push_line_item(&mut self, line_item: LineItem, inline_box_hierarchy_depth: usize) {
598 if self.line_items.is_empty() {
599 self.inline_box_hierarchy_depth = Some(inline_box_hierarchy_depth);
600 }
601 self.line_items.push(line_item);
602 }
603
604 fn trim_leading_whitespace(&mut self) {
615 let mut whitespace_trimmed = Au::zero();
616 for item in self.line_items.iter_mut() {
617 if !item.trim_whitespace_at_start(&mut whitespace_trimmed) {
618 break;
619 }
620 }
621 self.inline_size -= whitespace_trimmed;
622 }
623}
624
625bitflags! {
626 pub struct InlineContainerStateFlags: u8 {
627 const CREATE_STRUT = 0b0001;
628 const IS_SINGLE_LINE_TEXT_INPUT = 0b0010;
629 }
630}
631
632pub(super) struct InlineContainerState {
633 style: Arc<ComputedValues>,
635
636 flags: InlineContainerStateFlags,
638
639 has_content: RefCell<bool>,
642
643 strut_block_sizes: LineBlockSizes,
648
649 nested_strut_block_sizes: LineBlockSizes,
653
654 pub baseline_offset: Au,
660
661 font_metrics: FontMetrics,
663}
664
665pub(super) struct InlineFormattingContextLayout<'layout_data> {
666 positioning_context: &'layout_data mut PositioningContext,
667 containing_block: &'layout_data ContainingBlock<'layout_data>,
668 sequential_layout_state: Option<&'layout_data mut SequentialLayoutState>,
669 layout_context: &'layout_data LayoutContext<'layout_data>,
670
671 ifc: &'layout_data InlineFormattingContext,
673
674 root_nesting_level: InlineContainerState,
684
685 inline_box_state_stack: Vec<Rc<InlineBoxContainerState>>,
689
690 inline_box_states: Vec<Rc<InlineBoxContainerState>>,
695
696 fragments: Vec<Fragment>,
700
701 current_line: LineUnderConstruction,
703
704 current_line_segment: UnbreakableSegmentUnderConstruction,
706
707 linebreak_before_new_content: bool,
726
727 deferred_br_clear: Clear,
731
732 pub have_deferred_soft_wrap_opportunity: bool,
736
737 had_inflow_content: bool,
739
740 depends_on_block_constraints: bool,
743
744 white_space_collapse: WhiteSpaceCollapse,
749
750 text_wrap_mode: TextWrapMode,
755
756 baselines: Baselines,
760}
761
762impl InlineFormattingContextLayout<'_> {
763 fn current_inline_container_state(&self) -> &InlineContainerState {
764 match self.inline_box_state_stack.last() {
765 Some(inline_box_state) => &inline_box_state.base,
766 None => &self.root_nesting_level,
767 }
768 }
769
770 fn current_inline_box_identifier(&self) -> Option<InlineBoxIdentifier> {
771 self.inline_box_state_stack
772 .last()
773 .map(|state| state.identifier)
774 }
775
776 fn current_line_max_block_size_including_nested_containers(&self) -> LineBlockSizes {
777 self.current_inline_container_state()
778 .nested_strut_block_sizes
779 .max(&self.current_line.max_block_size)
780 }
781
782 fn propagate_current_nesting_level_white_space_style(&mut self) {
783 let style = match self.inline_box_state_stack.last() {
784 Some(inline_box_state) => &inline_box_state.base.style,
785 None => self.containing_block.style,
786 };
787 let style_text = style.get_inherited_text();
788 self.white_space_collapse = style_text.white_space_collapse;
789 self.text_wrap_mode = style_text.text_wrap_mode;
790 }
791
792 fn processing_br_element(&self) -> bool {
793 self.inline_box_state_stack
794 .last()
795 .map(|state| {
796 state
797 .base_fragment_info
798 .flags
799 .contains(FragmentFlags::IS_BR_ELEMENT)
800 })
801 .unwrap_or(false)
802 }
803
804 fn start_inline_box(&mut self, inline_box: &InlineBox) {
807 let inline_box_state = InlineBoxContainerState::new(
808 inline_box,
809 self.containing_block,
810 self.layout_context,
811 self.current_inline_container_state(),
812 inline_box.is_last_split,
813 inline_box
814 .default_font_index
815 .map(|index| &self.ifc.font_metrics[index].metrics),
816 );
817
818 self.depends_on_block_constraints |= inline_box
819 .base
820 .style
821 .depends_on_block_constraints_due_to_relative_positioning(
822 self.containing_block.style.writing_mode,
823 );
824
825 if inline_box_state
830 .base_fragment_info
831 .flags
832 .contains(FragmentFlags::IS_BR_ELEMENT) &&
833 self.deferred_br_clear == Clear::None
834 {
835 self.deferred_br_clear = Clear::from_style_and_container_writing_mode(
836 &inline_box_state.base.style,
837 self.containing_block.style.writing_mode,
838 );
839 }
840
841 if inline_box.is_first_split {
842 self.current_line_segment.inline_size += inline_box_state.pbm.padding.inline_start +
843 inline_box_state.pbm.border.inline_start +
844 inline_box_state.pbm.margin.inline_start.auto_is(Au::zero);
845 self.current_line_segment
846 .line_items
847 .push(LineItem::InlineStartBoxPaddingBorderMargin(
848 inline_box.identifier,
849 ));
850 }
851
852 let inline_box_state = Rc::new(inline_box_state);
853
854 assert_eq!(
858 self.inline_box_states.len(),
859 inline_box.identifier.index_in_inline_boxes as usize
860 );
861 self.inline_box_states.push(inline_box_state.clone());
862 self.inline_box_state_stack.push(inline_box_state);
863 }
864
865 fn finish_inline_box(&mut self) {
868 let inline_box_state = match self.inline_box_state_stack.pop() {
869 Some(inline_box_state) => inline_box_state,
870 None => return, };
872
873 self.current_line_segment
874 .max_block_size
875 .max_assign(&inline_box_state.base.nested_strut_block_sizes);
876
877 if *inline_box_state.base.has_content.borrow() {
882 self.propagate_current_nesting_level_white_space_style();
883 }
884
885 if inline_box_state.is_last_fragment {
886 let pbm_end = inline_box_state.pbm.padding.inline_end +
887 inline_box_state.pbm.border.inline_end +
888 inline_box_state.pbm.margin.inline_end.auto_is(Au::zero);
889 self.current_line_segment.inline_size += pbm_end;
890 self.current_line_segment
891 .line_items
892 .push(LineItem::InlineEndBoxPaddingBorderMargin(
893 inline_box_state.identifier,
894 ))
895 }
896 }
897
898 fn finish_last_line(&mut self) {
899 self.process_soft_wrap_opportunity();
905
906 self.commit_current_segment_to_line();
909
910 self.finish_current_line_and_reset(true );
913 }
914
915 fn finish_current_line_and_reset(&mut self, last_line_or_forced_line_break: bool) {
919 let whitespace_trimmed = self.current_line.trim_trailing_whitespace();
920 let (inline_start_position, justification_adjustment) = self
921 .calculate_current_line_inline_start_and_justification_adjustment(
922 whitespace_trimmed,
923 last_line_or_forced_line_break,
924 );
925
926 let block_start_position = self
927 .current_line
928 .line_block_start_considering_placement_among_floats();
929 let had_inline_advance =
930 self.current_line.inline_position != self.current_line.start_position.inline;
931
932 let effective_block_advance = if self.current_line.has_content ||
933 had_inline_advance ||
934 self.linebreak_before_new_content
935 {
936 self.current_line_max_block_size_including_nested_containers()
937 } else {
938 LineBlockSizes::zero()
939 };
940
941 let resolved_block_advance = effective_block_advance.resolve();
942 let mut block_end_position = block_start_position + resolved_block_advance;
943 if let Some(sequential_layout_state) = self.sequential_layout_state.as_mut() {
944 let increment = block_end_position - self.current_line.start_position.block;
947 sequential_layout_state.advance_block_position(increment);
948
949 if let Some(clearance) = sequential_layout_state
953 .calculate_clearance(self.deferred_br_clear, &CollapsedMargin::zero())
954 {
955 sequential_layout_state.advance_block_position(clearance);
956 block_end_position += clearance;
957 };
958 self.deferred_br_clear = Clear::None;
959 }
960
961 let mut line_to_layout = std::mem::replace(
963 &mut self.current_line,
964 LineUnderConstruction::new(LogicalVec2 {
965 inline: Au::zero(),
966 block: block_end_position,
967 }),
968 );
969
970 if line_to_layout.has_floats_waiting_to_be_placed {
971 place_pending_floats(self, &mut line_to_layout.line_items);
972 }
973
974 let start_position = LogicalVec2 {
975 block: block_start_position,
976 inline: inline_start_position,
977 };
978
979 let baseline_offset = effective_block_advance.find_baseline_offset();
980 let start_positioning_context_length = self.positioning_context.len();
981 let fragments = LineItemLayout::layout_line_items(
982 self,
983 line_to_layout.line_items,
984 start_position,
985 &effective_block_advance,
986 justification_adjustment,
987 );
988
989 if fragments.is_empty() &&
991 self.positioning_context.len() == start_positioning_context_length
992 {
993 return;
994 }
995
996 if line_to_layout.has_content {
997 let baseline = baseline_offset + block_start_position;
998 self.baselines.first.get_or_insert(baseline);
999 self.baselines.last = Some(baseline);
1000 }
1001
1002 let start_corner = LogicalVec2 {
1006 inline: Au::zero(),
1007 block: block_start_position,
1008 };
1009
1010 let logical_origin_in_physical_coordinates =
1011 start_corner.to_physical_vector(self.containing_block.style.writing_mode);
1012 self.positioning_context
1013 .adjust_static_position_of_hoisted_fragments_with_offset(
1014 &logical_origin_in_physical_coordinates,
1015 start_positioning_context_length,
1016 );
1017
1018 let physical_line_rect = LogicalRect {
1019 start_corner,
1020 size: LogicalVec2 {
1021 inline: self.containing_block.size.inline,
1022 block: effective_block_advance.resolve(),
1023 },
1024 }
1025 .as_physical(Some(self.containing_block));
1026 self.fragments
1027 .push(Fragment::Positioning(PositioningFragment::new_anonymous(
1028 self.root_nesting_level.style.clone(),
1029 physical_line_rect,
1030 fragments,
1031 )));
1032 }
1033
1034 fn calculate_current_line_inline_start_and_justification_adjustment(
1039 &self,
1040 whitespace_trimmed: Au,
1041 last_line_or_forced_line_break: bool,
1042 ) -> (Au, Au) {
1043 enum TextAlign {
1044 Start,
1045 Center,
1046 End,
1047 }
1048 let style = self.containing_block.style;
1049 let mut text_align_keyword = style.clone_text_align();
1050
1051 if last_line_or_forced_line_break {
1052 text_align_keyword = match style.clone_text_align_last() {
1053 TextAlignLast::Auto if text_align_keyword == TextAlignKeyword::Justify => {
1054 TextAlignKeyword::Start
1055 },
1056 TextAlignLast::Auto => text_align_keyword,
1057 TextAlignLast::Start => TextAlignKeyword::Start,
1058 TextAlignLast::End => TextAlignKeyword::End,
1059 TextAlignLast::Left => TextAlignKeyword::Left,
1060 TextAlignLast::Right => TextAlignKeyword::Right,
1061 TextAlignLast::Center => TextAlignKeyword::Center,
1062 TextAlignLast::Justify => TextAlignKeyword::Justify,
1063 };
1064 }
1065
1066 let text_align = match text_align_keyword {
1067 TextAlignKeyword::Start => TextAlign::Start,
1068 TextAlignKeyword::Center | TextAlignKeyword::MozCenter => TextAlign::Center,
1069 TextAlignKeyword::End => TextAlign::End,
1070 TextAlignKeyword::Left | TextAlignKeyword::MozLeft => {
1071 if style.writing_mode.line_left_is_inline_start() {
1072 TextAlign::Start
1073 } else {
1074 TextAlign::End
1075 }
1076 },
1077 TextAlignKeyword::Right | TextAlignKeyword::MozRight => {
1078 if style.writing_mode.line_left_is_inline_start() {
1079 TextAlign::End
1080 } else {
1081 TextAlign::Start
1082 }
1083 },
1084 TextAlignKeyword::Justify => TextAlign::Start,
1085 };
1086
1087 let (line_start, available_space) = match self.current_line.placement_among_floats.get() {
1088 Some(placement_among_floats) => (
1089 placement_among_floats.start_corner.inline,
1090 placement_among_floats.size.inline,
1091 ),
1092 None => (Au::zero(), self.containing_block.size.inline),
1093 };
1094
1095 let text_indent = self.current_line.start_position.inline;
1102 let line_length = self.current_line.inline_position - whitespace_trimmed - text_indent;
1103 let adjusted_line_start = line_start +
1104 match text_align {
1105 TextAlign::Start => text_indent,
1106 TextAlign::End => (available_space - line_length).max(text_indent),
1107 TextAlign::Center => (available_space - line_length + text_indent)
1108 .scale_by(0.5)
1109 .max(text_indent),
1110 };
1111
1112 let text_justify = self.containing_block.style.clone_text_justify();
1116 let justification_adjustment = match (text_align_keyword, text_justify) {
1117 (TextAlignKeyword::Justify, TextJustify::None) => Au::zero(),
1120 (TextAlignKeyword::Justify, _) => {
1121 match self.current_line.count_justification_opportunities() {
1122 0 => Au::zero(),
1123 num_justification_opportunities => {
1124 (available_space - text_indent - line_length)
1125 .scale_by(1. / num_justification_opportunities as f32)
1126 },
1127 }
1128 },
1129 _ => Au::zero(),
1130 };
1131
1132 let justification_adjustment = justification_adjustment.max(Au::zero());
1135
1136 (adjusted_line_start, justification_adjustment)
1137 }
1138
1139 fn place_float_fragment(&mut self, fragment: &mut BoxFragment) {
1140 let state = self
1141 .sequential_layout_state
1142 .as_mut()
1143 .expect("Tried to lay out a float with no sequential placement state!");
1144
1145 let block_offset_from_containining_block_top = state
1146 .current_block_position_including_margins() -
1147 state.current_containing_block_offset();
1148 state.place_float_fragment(
1149 fragment,
1150 self.containing_block,
1151 CollapsedMargin::zero(),
1152 block_offset_from_containining_block_top,
1153 );
1154 }
1155
1156 fn place_float_line_item_for_commit_to_line(
1165 &mut self,
1166 float_item: &mut FloatLineItem,
1167 line_inline_size_without_trailing_whitespace: Au,
1168 ) {
1169 let mut float_fragment = float_item.fragment.borrow_mut();
1170 let logical_margin_rect_size = float_fragment
1171 .margin_rect()
1172 .size
1173 .to_logical(self.containing_block.style.writing_mode);
1174 let inline_size = logical_margin_rect_size.inline.max(Au::zero());
1175
1176 let available_inline_size = match self.current_line.placement_among_floats.get() {
1177 Some(placement_among_floats) => placement_among_floats.size.inline,
1178 None => self.containing_block.size.inline,
1179 } - line_inline_size_without_trailing_whitespace;
1180
1181 let has_content = self.current_line.has_content || self.current_line_segment.has_content;
1187 let fits_on_line = !has_content || inline_size <= available_inline_size;
1188 let needs_placement_later =
1189 self.current_line.has_floats_waiting_to_be_placed || !fits_on_line;
1190
1191 if needs_placement_later {
1192 self.current_line.has_floats_waiting_to_be_placed = true;
1193 } else {
1194 self.place_float_fragment(&mut float_fragment);
1195 float_item.needs_placement = false;
1196 }
1197
1198 let new_placement = self.place_line_among_floats(&LogicalVec2 {
1203 inline: line_inline_size_without_trailing_whitespace,
1204 block: self.current_line.max_block_size.resolve(),
1205 });
1206 self.current_line
1207 .replace_placement_among_floats(new_placement);
1208 }
1209
1210 fn place_line_among_floats(&self, potential_line_size: &LogicalVec2<Au>) -> LogicalRect<Au> {
1215 let sequential_layout_state = self
1216 .sequential_layout_state
1217 .as_ref()
1218 .expect("Should not have called this function without having floats.");
1219
1220 let ifc_offset_in_float_container = LogicalVec2 {
1221 inline: sequential_layout_state
1222 .floats
1223 .containing_block_info
1224 .inline_start,
1225 block: sequential_layout_state.current_containing_block_offset(),
1226 };
1227
1228 let ceiling = self
1229 .current_line
1230 .line_block_start_considering_placement_among_floats();
1231 let mut placement = PlacementAmongFloats::new(
1232 &sequential_layout_state.floats,
1233 ceiling + ifc_offset_in_float_container.block,
1234 LogicalVec2 {
1235 inline: potential_line_size.inline,
1236 block: potential_line_size.block,
1237 },
1238 &PaddingBorderMargin::zero(),
1239 );
1240
1241 let mut placement_rect = placement.place();
1242 placement_rect.start_corner -= ifc_offset_in_float_container;
1243 placement_rect
1244 }
1245
1246 fn new_potential_line_size_causes_line_break(
1253 &mut self,
1254 potential_line_size: &LogicalVec2<Au>,
1255 ) -> bool {
1256 let available_line_space = if self.sequential_layout_state.is_some() {
1257 self.current_line
1258 .placement_among_floats
1259 .get_or_init(|| self.place_line_among_floats(potential_line_size))
1260 .size
1261 } else {
1262 LogicalVec2 {
1263 inline: self.containing_block.size.inline,
1264 block: MAX_AU,
1265 }
1266 };
1267
1268 let inline_would_overflow = potential_line_size.inline > available_line_space.inline;
1269 let block_would_overflow = potential_line_size.block > available_line_space.block;
1270
1271 let can_break = self.current_line.has_content;
1274
1275 if !can_break {
1281 if self.sequential_layout_state.is_some() &&
1284 (inline_would_overflow || block_would_overflow)
1285 {
1286 let new_placement = self.place_line_among_floats(potential_line_size);
1287 self.current_line
1288 .replace_placement_among_floats(new_placement);
1289 }
1290
1291 return false;
1292 }
1293
1294 if potential_line_size.inline > self.containing_block.size.inline {
1297 return true;
1298 }
1299
1300 if block_would_overflow {
1304 assert!(self.sequential_layout_state.is_some());
1306 let new_placement = self.place_line_among_floats(potential_line_size);
1307 if new_placement.start_corner.block !=
1308 self.current_line
1309 .line_block_start_considering_placement_among_floats()
1310 {
1311 return true;
1312 } else {
1313 self.current_line
1314 .replace_placement_among_floats(new_placement);
1315 return false;
1316 }
1317 }
1318
1319 inline_would_overflow
1323 }
1324
1325 pub(super) fn defer_forced_line_break(&mut self) {
1326 if !self.unbreakable_segment_fits_on_line() {
1329 self.process_line_break(false );
1330 }
1331
1332 self.linebreak_before_new_content = true;
1334
1335 let line_is_empty =
1343 !self.current_line_segment.has_content && !self.current_line.has_content;
1344 if !self.processing_br_element() || line_is_empty {
1345 let strut_size = self
1346 .current_inline_container_state()
1347 .strut_block_sizes
1348 .clone();
1349 self.update_unbreakable_segment_for_new_content(
1350 &strut_size,
1351 Au::zero(),
1352 SegmentContentFlags::empty(),
1353 );
1354 }
1355
1356 self.had_inflow_content = true;
1357 }
1358
1359 pub(super) fn possibly_flush_deferred_forced_line_break(&mut self) {
1360 if !self.linebreak_before_new_content {
1361 return;
1362 }
1363
1364 self.commit_current_segment_to_line();
1365 self.process_line_break(true );
1366 self.linebreak_before_new_content = false;
1367 }
1368
1369 fn push_line_item_to_unbreakable_segment(&mut self, line_item: LineItem) {
1370 self.current_line_segment
1371 .push_line_item(line_item, self.inline_box_state_stack.len());
1372 }
1373
1374 pub(super) fn push_glyph_store_to_unbreakable_segment(
1375 &mut self,
1376 glyph_store: std::sync::Arc<GlyphStore>,
1377 text_run: &TextRun,
1378 font_index: usize,
1379 bidi_level: Level,
1380 range: range::Range<ByteIndex>,
1381 ) {
1382 let inline_advance = glyph_store.total_advance();
1383 let flags = if glyph_store.is_whitespace() {
1384 SegmentContentFlags::from(text_run.inline_styles.style.borrow().get_inherited_text())
1385 } else {
1386 SegmentContentFlags::empty()
1387 };
1388
1389 let ifc_font_info = &self.ifc.font_metrics[font_index];
1393 let font_metrics = ifc_font_info.metrics.clone();
1394 let using_fallback_font =
1395 self.current_inline_container_state().font_metrics != font_metrics;
1396
1397 let quirks_mode = self.layout_context.style_context.quirks_mode() != QuirksMode::NoQuirks;
1398 let strut_size = if using_fallback_font {
1399 let container_state = self.current_inline_container_state();
1401 let vertical_align = effective_vertical_align(
1402 &container_state.style,
1403 self.inline_box_state_stack.last().map(|c| &c.base),
1404 );
1405 let mut block_size = container_state.get_block_size_contribution(
1406 vertical_align,
1407 &font_metrics,
1408 &container_state.font_metrics,
1409 );
1410 block_size.adjust_for_baseline_offset(container_state.baseline_offset);
1411 block_size
1412 } else if quirks_mode && !flags.is_collapsible_whitespace() {
1413 self.current_inline_container_state()
1418 .strut_block_sizes
1419 .clone()
1420 } else {
1421 LineBlockSizes::zero()
1422 };
1423 self.update_unbreakable_segment_for_new_content(&strut_size, inline_advance, flags);
1424
1425 let current_inline_box_identifier = self.current_inline_box_identifier();
1426 match self.current_line_segment.line_items.last_mut() {
1427 Some(LineItem::TextRun(inline_box_identifier, line_item))
1428 if *inline_box_identifier == current_inline_box_identifier &&
1429 line_item.can_merge(ifc_font_info.key, bidi_level) =>
1430 {
1431 line_item.text.push(glyph_store);
1432 return;
1433 },
1434 _ => {},
1435 }
1436
1437 let selection_range = if let Some(selection) = &text_run.selection_range {
1438 let intersection = selection.intersect(&range);
1439 if intersection.is_empty() {
1440 let insertion_point_index = selection.begin();
1441 if insertion_point_index >= range.begin() &&
1444 insertion_point_index <= range.end() &&
1445 (range.begin() != insertion_point_index || range.begin().0 == 0)
1446 {
1447 Some(Range::new(
1448 insertion_point_index - range.begin(),
1449 ByteIndex(0),
1450 ))
1451 } else {
1452 None
1453 }
1454 } else {
1455 Some(Range::new(
1456 intersection.begin() - range.begin(),
1457 intersection.length(),
1458 ))
1459 }
1460 } else {
1461 None
1462 };
1463
1464 self.push_line_item_to_unbreakable_segment(LineItem::TextRun(
1465 current_inline_box_identifier,
1466 TextRunLineItem {
1467 text: vec![glyph_store],
1468 base_fragment_info: text_run.base_fragment_info,
1469 inline_styles: text_run.inline_styles.clone(),
1470 font_metrics,
1471 font_key: ifc_font_info.key,
1472 bidi_level,
1473 selection_range,
1474 },
1475 ));
1476 }
1477
1478 fn update_unbreakable_segment_for_new_content(
1479 &mut self,
1480 block_sizes_of_content: &LineBlockSizes,
1481 inline_size: Au,
1482 flags: SegmentContentFlags,
1483 ) {
1484 if flags.is_collapsible_whitespace() || flags.is_wrappable_and_hangable() {
1485 self.current_line_segment.trailing_whitespace_size = inline_size;
1486 } else {
1487 self.current_line_segment.trailing_whitespace_size = Au::zero();
1488 }
1489 if !flags.is_collapsible_whitespace() {
1490 self.current_line_segment.has_content = true;
1491 self.had_inflow_content = true;
1492 }
1493
1494 let container_max_block_size = &self
1496 .current_inline_container_state()
1497 .nested_strut_block_sizes
1498 .clone();
1499 self.current_line_segment
1500 .max_block_size
1501 .max_assign(container_max_block_size);
1502 self.current_line_segment
1503 .max_block_size
1504 .max_assign(block_sizes_of_content);
1505
1506 self.current_line_segment.inline_size += inline_size;
1507
1508 *self
1510 .current_inline_container_state()
1511 .has_content
1512 .borrow_mut() = true;
1513 self.propagate_current_nesting_level_white_space_style();
1514 }
1515
1516 fn process_line_break(&mut self, forced_line_break: bool) {
1517 self.current_line_segment.trim_leading_whitespace();
1518 self.finish_current_line_and_reset(forced_line_break);
1519 }
1520
1521 pub(super) fn unbreakable_segment_fits_on_line(&mut self) -> bool {
1522 let potential_line_size = LogicalVec2 {
1523 inline: self.current_line.inline_position + self.current_line_segment.inline_size -
1524 self.current_line_segment.trailing_whitespace_size,
1525 block: self
1526 .current_line_max_block_size_including_nested_containers()
1527 .max(&self.current_line_segment.max_block_size)
1528 .resolve(),
1529 };
1530
1531 !self.new_potential_line_size_causes_line_break(&potential_line_size)
1532 }
1533
1534 pub(super) fn process_soft_wrap_opportunity(&mut self) {
1538 if self.current_line_segment.line_items.is_empty() {
1539 return;
1540 }
1541 if self.text_wrap_mode == TextWrapMode::Nowrap {
1542 return;
1543 }
1544
1545 let potential_line_size = LogicalVec2 {
1546 inline: self.current_line.inline_position + self.current_line_segment.inline_size -
1547 self.current_line_segment.trailing_whitespace_size,
1548 block: self
1549 .current_line_max_block_size_including_nested_containers()
1550 .max(&self.current_line_segment.max_block_size)
1551 .resolve(),
1552 };
1553
1554 if self.new_potential_line_size_causes_line_break(&potential_line_size) {
1555 self.process_line_break(false );
1556 }
1557 self.commit_current_segment_to_line();
1558 }
1559
1560 fn commit_current_segment_to_line(&mut self) {
1563 if self.current_line_segment.line_items.is_empty() && !self.current_line_segment.has_content
1566 {
1567 return;
1568 }
1569
1570 if !self.current_line.has_content {
1571 self.current_line_segment.trim_leading_whitespace();
1572 }
1573
1574 self.current_line.inline_position += self.current_line_segment.inline_size;
1575 self.current_line.max_block_size = self
1576 .current_line_max_block_size_including_nested_containers()
1577 .max(&self.current_line_segment.max_block_size);
1578 let line_inline_size_without_trailing_whitespace =
1579 self.current_line.inline_position - self.current_line_segment.trailing_whitespace_size;
1580
1581 let mut segment_items = mem::take(&mut self.current_line_segment.line_items);
1583 for item in segment_items.iter_mut() {
1584 if let LineItem::Float(_, float_item) = item {
1585 self.place_float_line_item_for_commit_to_line(
1586 float_item,
1587 line_inline_size_without_trailing_whitespace,
1588 );
1589 }
1590 }
1591
1592 if self.current_line.line_items.is_empty() {
1597 let will_break = self.new_potential_line_size_causes_line_break(&LogicalVec2 {
1598 inline: line_inline_size_without_trailing_whitespace,
1599 block: self.current_line_segment.max_block_size.resolve(),
1600 });
1601 assert!(!will_break);
1602 }
1603
1604 self.current_line.line_items.extend(segment_items);
1605 self.current_line.has_content |= self.current_line_segment.has_content;
1606
1607 self.current_line_segment.reset();
1608 }
1609}
1610
1611bitflags! {
1612 pub struct SegmentContentFlags: u8 {
1613 const COLLAPSIBLE_WHITESPACE = 0b00000001;
1614 const WRAPPABLE_AND_HANGABLE_WHITESPACE = 0b00000010;
1615 }
1616}
1617
1618impl SegmentContentFlags {
1619 fn is_collapsible_whitespace(&self) -> bool {
1620 self.contains(Self::COLLAPSIBLE_WHITESPACE)
1621 }
1622
1623 fn is_wrappable_and_hangable(&self) -> bool {
1624 self.contains(Self::WRAPPABLE_AND_HANGABLE_WHITESPACE)
1625 }
1626}
1627
1628impl From<&InheritedText> for SegmentContentFlags {
1629 fn from(style_text: &InheritedText) -> Self {
1630 let mut flags = Self::empty();
1631
1632 if !matches!(
1635 style_text.white_space_collapse,
1636 WhiteSpaceCollapse::Preserve | WhiteSpaceCollapse::BreakSpaces
1637 ) {
1638 flags.insert(Self::COLLAPSIBLE_WHITESPACE);
1639 }
1640
1641 if style_text.text_wrap_mode == TextWrapMode::Wrap &&
1644 style_text.white_space_collapse != WhiteSpaceCollapse::BreakSpaces
1645 {
1646 flags.insert(Self::WRAPPABLE_AND_HANGABLE_WHITESPACE);
1647 }
1648 flags
1649 }
1650}
1651
1652impl InlineFormattingContext {
1653 #[servo_tracing::instrument(name = "InlineFormattingContext::new_with_builder", skip_all)]
1654 pub(super) fn new_with_builder(
1655 builder: InlineFormattingContextBuilder,
1656 layout_context: &LayoutContext,
1657 has_first_formatted_line: bool,
1658 is_single_line_text_input: bool,
1659 starting_bidi_level: Level,
1660 ) -> Self {
1661 let text_content: String = builder.text_segments.into_iter().collect();
1663 let mut font_metrics = Vec::new();
1664
1665 let bidi_info = BidiInfo::new(&text_content, Some(starting_bidi_level));
1666 let has_right_to_left_content = bidi_info.has_rtl();
1667
1668 let mut new_linebreaker = LineBreaker::new(text_content.as_str());
1669 for item in builder.inline_items.iter() {
1670 match &mut *item.borrow_mut() {
1671 InlineItem::TextRun(text_run) => {
1672 text_run.borrow_mut().segment_and_shape(
1673 &text_content,
1674 &layout_context.font_context,
1675 &mut new_linebreaker,
1676 &mut font_metrics,
1677 &bidi_info,
1678 );
1679 },
1680 InlineItem::StartInlineBox(inline_box) => {
1681 let inline_box = &mut *inline_box.borrow_mut();
1682 if let Some(font) = get_font_for_first_font_for_style(
1683 &inline_box.base.style,
1684 &layout_context.font_context,
1685 ) {
1686 inline_box.default_font_index = Some(add_or_get_font(
1687 &font,
1688 &mut font_metrics,
1689 &layout_context.font_context,
1690 ));
1691 }
1692 },
1693 InlineItem::Atomic(_, index_in_text, bidi_level) => {
1694 *bidi_level = bidi_info.levels[*index_in_text];
1695 },
1696 InlineItem::OutOfFlowAbsolutelyPositionedBox(..) |
1697 InlineItem::OutOfFlowFloatBox(_) |
1698 InlineItem::EndInlineBox => {},
1699 }
1700 }
1701
1702 InlineFormattingContext {
1703 text_content,
1704 inline_items: builder.inline_items,
1705 inline_boxes: builder.inline_boxes,
1706 font_metrics,
1707 shared_inline_styles: builder
1708 .shared_inline_styles_stack
1709 .last()
1710 .expect("Should have at least one SharedInlineStyle for the root of an IFC")
1711 .clone(),
1712 has_first_formatted_line,
1713 contains_floats: builder.contains_floats,
1714 is_single_line_text_input,
1715 has_right_to_left_content,
1716 }
1717 }
1718
1719 pub(crate) fn repair_style(
1720 &self,
1721 node: &ServoThreadSafeLayoutNode,
1722 new_style: &Arc<ComputedValues>,
1723 ) {
1724 *self.shared_inline_styles.style.borrow_mut() = new_style.clone();
1725 *self.shared_inline_styles.selected.borrow_mut() = node.selected_style();
1726 }
1727
1728 pub(super) fn layout(
1729 &self,
1730 layout_context: &LayoutContext,
1731 positioning_context: &mut PositioningContext,
1732 containing_block: &ContainingBlock,
1733 sequential_layout_state: Option<&mut SequentialLayoutState>,
1734 collapsible_with_parent_start_margin: CollapsibleWithParentStartMargin,
1735 ) -> CacheableLayoutResult {
1736 let first_line_inline_start = if self.has_first_formatted_line {
1737 containing_block
1738 .style
1739 .get_inherited_text()
1740 .text_indent
1741 .length
1742 .to_used_value(containing_block.size.inline)
1743 } else {
1744 Au::zero()
1745 };
1746
1747 for inline_box in self.inline_boxes.iter() {
1749 inline_box.borrow().base.clear_fragments();
1750 }
1751
1752 let style = containing_block.style;
1753
1754 let default_font_metrics =
1757 get_font_for_first_font_for_style(style, &layout_context.font_context)
1758 .map(|font| font.metrics.clone());
1759
1760 let style_text = containing_block.style.get_inherited_text();
1761 let mut inline_container_state_flags = InlineContainerStateFlags::empty();
1762 if inline_container_needs_strut(style, layout_context, None) {
1763 inline_container_state_flags.insert(InlineContainerStateFlags::CREATE_STRUT);
1764 }
1765 if self.is_single_line_text_input {
1766 inline_container_state_flags
1767 .insert(InlineContainerStateFlags::IS_SINGLE_LINE_TEXT_INPUT);
1768 }
1769
1770 let mut layout = InlineFormattingContextLayout {
1771 positioning_context,
1772 containing_block,
1773 sequential_layout_state,
1774 layout_context,
1775 ifc: self,
1776 fragments: Vec::new(),
1777 current_line: LineUnderConstruction::new(LogicalVec2 {
1778 inline: first_line_inline_start,
1779 block: Au::zero(),
1780 }),
1781 root_nesting_level: InlineContainerState::new(
1782 style.to_arc(),
1783 inline_container_state_flags,
1784 None, default_font_metrics.as_ref(),
1786 ),
1787 inline_box_state_stack: Vec::new(),
1788 inline_box_states: Vec::with_capacity(self.inline_boxes.len()),
1789 current_line_segment: UnbreakableSegmentUnderConstruction::new(),
1790 linebreak_before_new_content: false,
1791 deferred_br_clear: Clear::None,
1792 have_deferred_soft_wrap_opportunity: false,
1793 had_inflow_content: false,
1794 depends_on_block_constraints: false,
1795 white_space_collapse: style_text.white_space_collapse,
1796 text_wrap_mode: style_text.text_wrap_mode,
1797 baselines: Baselines::default(),
1798 };
1799
1800 if let Some(ref mut sequential_layout_state) = layout.sequential_layout_state {
1804 sequential_layout_state.collapse_margins();
1805 }
1807
1808 for item in self.inline_items.iter() {
1809 let item = &*item.borrow();
1810
1811 if !matches!(item, InlineItem::EndInlineBox) {
1813 layout.possibly_flush_deferred_forced_line_break();
1814 }
1815
1816 match item {
1817 InlineItem::StartInlineBox(inline_box) => {
1818 layout.start_inline_box(&inline_box.borrow());
1819 },
1820 InlineItem::EndInlineBox => layout.finish_inline_box(),
1821 InlineItem::TextRun(run) => run.borrow().layout_into_line_items(&mut layout),
1822 InlineItem::Atomic(atomic_formatting_context, offset_in_text, bidi_level) => {
1823 atomic_formatting_context.borrow().layout_into_line_items(
1824 &mut layout,
1825 *offset_in_text,
1826 *bidi_level,
1827 );
1828 },
1829 InlineItem::OutOfFlowAbsolutelyPositionedBox(positioned_box, _) => {
1830 layout.push_line_item_to_unbreakable_segment(LineItem::AbsolutelyPositioned(
1831 layout.current_inline_box_identifier(),
1832 AbsolutelyPositionedLineItem {
1833 absolutely_positioned_box: positioned_box.clone(),
1834 },
1835 ));
1836 },
1837 InlineItem::OutOfFlowFloatBox(float_box) => {
1838 float_box.borrow().layout_into_line_items(&mut layout);
1839 },
1840 }
1841 }
1842
1843 layout.finish_last_line();
1844
1845 let mut collapsible_margins_in_children = CollapsedBlockMargins::zero();
1846 let content_block_size = layout.current_line.start_position.block;
1847 collapsible_margins_in_children.collapsed_through = !layout.had_inflow_content &&
1848 content_block_size.is_zero() &&
1849 collapsible_with_parent_start_margin.0;
1850
1851 CacheableLayoutResult {
1852 fragments: layout.fragments,
1853 content_block_size,
1854 collapsible_margins_in_children,
1855 baselines: layout.baselines,
1856 depends_on_block_constraints: layout.depends_on_block_constraints,
1857 content_inline_size_for_table: None,
1858 specific_layout_info: None,
1859 }
1860 }
1861
1862 fn next_character_prevents_soft_wrap_opportunity(&self, index: usize) -> bool {
1863 let Some(character) = self.text_content[index..].chars().nth(1) else {
1864 return false;
1865 };
1866 char_prevents_soft_wrap_opportunity_when_before_or_after_atomic(character)
1867 }
1868
1869 fn previous_character_prevents_soft_wrap_opportunity(&self, index: usize) -> bool {
1870 let Some(character) = self.text_content[0..index].chars().next_back() else {
1871 return false;
1872 };
1873 char_prevents_soft_wrap_opportunity_when_before_or_after_atomic(character)
1874 }
1875}
1876
1877impl InlineContainerState {
1878 fn new(
1879 style: Arc<ComputedValues>,
1880 flags: InlineContainerStateFlags,
1881 parent_container: Option<&InlineContainerState>,
1882 font_metrics: Option<&FontMetrics>,
1883 ) -> Self {
1884 let font_metrics = font_metrics.cloned().unwrap_or_else(FontMetrics::empty);
1885 let line_height = line_height(
1886 &style,
1887 &font_metrics,
1888 flags.contains(InlineContainerStateFlags::IS_SINGLE_LINE_TEXT_INPUT),
1889 );
1890
1891 let mut baseline_offset = Au::zero();
1892 let mut strut_block_sizes = Self::get_block_sizes_with_style(
1893 effective_vertical_align(&style, parent_container),
1894 &style,
1895 &font_metrics,
1896 &font_metrics,
1897 line_height,
1898 );
1899 if let Some(parent_container) = parent_container {
1900 baseline_offset = parent_container.get_cumulative_baseline_offset_for_child(
1903 style.clone_vertical_align(),
1904 &strut_block_sizes,
1905 );
1906 strut_block_sizes.adjust_for_baseline_offset(baseline_offset);
1907 }
1908
1909 let mut nested_block_sizes = parent_container
1910 .map(|container| container.nested_strut_block_sizes.clone())
1911 .unwrap_or_else(LineBlockSizes::zero);
1912 if flags.contains(InlineContainerStateFlags::CREATE_STRUT) {
1913 nested_block_sizes.max_assign(&strut_block_sizes);
1914 }
1915
1916 Self {
1917 style,
1918 flags,
1919 has_content: RefCell::new(false),
1920 nested_strut_block_sizes: nested_block_sizes,
1921 strut_block_sizes,
1922 baseline_offset,
1923 font_metrics,
1924 }
1925 }
1926
1927 fn get_block_sizes_with_style(
1928 vertical_align: VerticalAlign,
1929 style: &ComputedValues,
1930 font_metrics: &FontMetrics,
1931 font_metrics_of_first_font: &FontMetrics,
1932 line_height: Au,
1933 ) -> LineBlockSizes {
1934 if !is_baseline_relative(vertical_align) {
1935 return LineBlockSizes {
1936 line_height,
1937 baseline_relative_size_for_line_height: None,
1938 size_for_baseline_positioning: BaselineRelativeSize::zero(),
1939 };
1940 }
1941
1942 let mut ascent = font_metrics.ascent;
1951 let mut descent = font_metrics.descent;
1952 if style.get_font().line_height == LineHeight::Normal {
1953 let half_leading_from_line_gap =
1954 (font_metrics.line_gap - descent - ascent).scale_by(0.5);
1955 ascent += half_leading_from_line_gap;
1956 descent += half_leading_from_line_gap;
1957 }
1958
1959 let size_for_baseline_positioning = BaselineRelativeSize { ascent, descent };
1963
1964 if style.get_font().line_height != LineHeight::Normal {
1980 ascent = font_metrics_of_first_font.ascent;
1981 descent = font_metrics_of_first_font.descent;
1982 let half_leading = (line_height - (ascent + descent)).scale_by(0.5);
1983 ascent += half_leading;
1988 descent = line_height - ascent;
1989 }
1990
1991 LineBlockSizes {
1992 line_height,
1993 baseline_relative_size_for_line_height: Some(BaselineRelativeSize { ascent, descent }),
1994 size_for_baseline_positioning,
1995 }
1996 }
1997
1998 fn get_block_size_contribution(
1999 &self,
2000 vertical_align: VerticalAlign,
2001 font_metrics: &FontMetrics,
2002 font_metrics_of_first_font: &FontMetrics,
2003 ) -> LineBlockSizes {
2004 Self::get_block_sizes_with_style(
2005 vertical_align,
2006 &self.style,
2007 font_metrics,
2008 font_metrics_of_first_font,
2009 line_height(
2010 &self.style,
2011 font_metrics,
2012 self.flags
2013 .contains(InlineContainerStateFlags::IS_SINGLE_LINE_TEXT_INPUT),
2014 ),
2015 )
2016 }
2017
2018 fn get_cumulative_baseline_offset_for_child(
2019 &self,
2020 child_vertical_align: VerticalAlign,
2021 child_block_size: &LineBlockSizes,
2022 ) -> Au {
2023 let block_size = self.get_block_size_contribution(
2024 child_vertical_align.clone(),
2025 &self.font_metrics,
2026 &self.font_metrics,
2027 );
2028 self.baseline_offset +
2029 match child_vertical_align {
2030 VerticalAlign::Keyword(VerticalAlignKeyword::Baseline) |
2035 VerticalAlign::Keyword(VerticalAlignKeyword::Top) |
2036 VerticalAlign::Keyword(VerticalAlignKeyword::Bottom) => Au::zero(),
2037 VerticalAlign::Keyword(VerticalAlignKeyword::Sub) => {
2038 block_size.resolve().scale_by(FONT_SUBSCRIPT_OFFSET_RATIO)
2039 },
2040 VerticalAlign::Keyword(VerticalAlignKeyword::Super) => {
2041 -block_size.resolve().scale_by(FONT_SUPERSCRIPT_OFFSET_RATIO)
2042 },
2043 VerticalAlign::Keyword(VerticalAlignKeyword::TextTop) => {
2044 child_block_size.size_for_baseline_positioning.ascent - self.font_metrics.ascent
2045 },
2046 VerticalAlign::Keyword(VerticalAlignKeyword::Middle) => {
2047 (child_block_size.size_for_baseline_positioning.ascent -
2050 child_block_size.size_for_baseline_positioning.descent -
2051 self.font_metrics.x_height)
2052 .scale_by(0.5)
2053 },
2054 VerticalAlign::Keyword(VerticalAlignKeyword::TextBottom) => {
2055 self.font_metrics.descent -
2056 child_block_size.size_for_baseline_positioning.descent
2057 },
2058 VerticalAlign::Length(length_percentage) => {
2059 -length_percentage.to_used_value(child_block_size.line_height)
2060 },
2061 }
2062 }
2063}
2064
2065impl IndependentFormattingContext {
2066 fn layout_into_line_items(
2067 &self,
2068 layout: &mut InlineFormattingContextLayout,
2069 offset_in_text: usize,
2070 bidi_level: Level,
2071 ) {
2072 let mut child_positioning_context = PositioningContext::default();
2074 let IndependentFloatOrAtomicLayoutResult {
2075 mut fragment,
2076 baselines,
2077 pbm_sums,
2078 } = self.layout_float_or_atomic_inline(
2079 layout.layout_context,
2080 &mut child_positioning_context,
2081 layout.containing_block,
2082 );
2083
2084 layout.depends_on_block_constraints |= fragment.base.flags.contains(
2087 FragmentFlags::SIZE_DEPENDS_ON_BLOCK_CONSTRAINTS_AND_CAN_BE_CHILD_OF_FLEX_ITEM,
2088 );
2089
2090 let container_writing_mode = layout.containing_block.style.writing_mode;
2092 let pbm_physical_offset = pbm_sums
2093 .start_offset()
2094 .to_physical_size(container_writing_mode);
2095 fragment.content_rect = fragment
2096 .content_rect
2097 .translate(pbm_physical_offset.to_vector());
2098
2099 fragment = fragment.with_baselines(baselines);
2101
2102 let positioning_context = if self.is_replaced() {
2105 None
2106 } else {
2107 if fragment
2108 .style
2109 .establishes_containing_block_for_absolute_descendants(fragment.base.flags)
2110 {
2111 child_positioning_context
2112 .layout_collected_children(layout.layout_context, &mut fragment);
2113 }
2114 Some(child_positioning_context)
2115 };
2116
2117 if layout.text_wrap_mode == TextWrapMode::Wrap &&
2118 !layout
2119 .ifc
2120 .previous_character_prevents_soft_wrap_opportunity(offset_in_text)
2121 {
2122 layout.process_soft_wrap_opportunity();
2123 }
2124
2125 let size = pbm_sums.sum() +
2126 fragment
2127 .content_rect
2128 .size
2129 .to_logical(container_writing_mode);
2130 let baseline_offset = self
2131 .pick_baseline(&fragment.baselines(container_writing_mode))
2132 .map(|baseline| pbm_sums.block_start + baseline)
2133 .unwrap_or(size.block);
2134
2135 let (block_sizes, baseline_offset_in_parent) =
2136 self.get_block_sizes_and_baseline_offset(layout, size.block, baseline_offset);
2137 layout.update_unbreakable_segment_for_new_content(
2138 &block_sizes,
2139 size.inline,
2140 SegmentContentFlags::empty(),
2141 );
2142
2143 let fragment = ArcRefCell::new(fragment);
2144 self.base.set_fragment(Fragment::Box(fragment.clone()));
2145
2146 layout.push_line_item_to_unbreakable_segment(LineItem::Atomic(
2147 layout.current_inline_box_identifier(),
2148 AtomicLineItem {
2149 fragment,
2150 size,
2151 positioning_context,
2152 baseline_offset_in_parent,
2153 baseline_offset_in_item: baseline_offset,
2154 bidi_level,
2155 },
2156 ));
2157
2158 if !layout
2161 .ifc
2162 .next_character_prevents_soft_wrap_opportunity(offset_in_text)
2163 {
2164 layout.have_deferred_soft_wrap_opportunity = true;
2165 }
2166 }
2167
2168 fn pick_baseline(&self, baselines: &Baselines) -> Option<Au> {
2172 match self.style().clone_baseline_source() {
2173 BaselineSource::First => baselines.first,
2174 BaselineSource::Last => baselines.last,
2175 BaselineSource::Auto if self.is_block_container() => baselines.last,
2176 BaselineSource::Auto => baselines.first,
2177 }
2178 }
2179
2180 fn get_block_sizes_and_baseline_offset(
2181 &self,
2182 ifc: &InlineFormattingContextLayout,
2183 block_size: Au,
2184 baseline_offset_in_content_area: Au,
2185 ) -> (LineBlockSizes, Au) {
2186 let mut contribution = if !is_baseline_relative(self.style().clone_vertical_align()) {
2187 LineBlockSizes {
2188 line_height: block_size,
2189 baseline_relative_size_for_line_height: None,
2190 size_for_baseline_positioning: BaselineRelativeSize::zero(),
2191 }
2192 } else {
2193 let baseline_relative_size = BaselineRelativeSize {
2194 ascent: baseline_offset_in_content_area,
2195 descent: block_size - baseline_offset_in_content_area,
2196 };
2197 LineBlockSizes {
2198 line_height: block_size,
2199 baseline_relative_size_for_line_height: Some(baseline_relative_size.clone()),
2200 size_for_baseline_positioning: baseline_relative_size,
2201 }
2202 };
2203
2204 let baseline_offset = ifc
2205 .current_inline_container_state()
2206 .get_cumulative_baseline_offset_for_child(
2207 self.style().clone_vertical_align(),
2208 &contribution,
2209 );
2210 contribution.adjust_for_baseline_offset(baseline_offset);
2211
2212 (contribution, baseline_offset)
2213 }
2214}
2215
2216impl FloatBox {
2217 fn layout_into_line_items(&self, layout: &mut InlineFormattingContextLayout) {
2218 let fragment = ArcRefCell::new(self.layout(
2219 layout.layout_context,
2220 layout.positioning_context,
2221 layout.containing_block,
2222 ));
2223
2224 self.contents
2225 .base
2226 .set_fragment(Fragment::Box(fragment.clone()));
2227 layout.push_line_item_to_unbreakable_segment(LineItem::Float(
2228 layout.current_inline_box_identifier(),
2229 FloatLineItem {
2230 fragment,
2231 needs_placement: true,
2232 },
2233 ));
2234 }
2235}
2236
2237fn place_pending_floats(ifc: &mut InlineFormattingContextLayout, line_items: &mut [LineItem]) {
2238 for item in line_items.iter_mut() {
2239 if let LineItem::Float(_, float_line_item) = item {
2240 if float_line_item.needs_placement {
2241 ifc.place_float_fragment(&mut float_line_item.fragment.borrow_mut());
2242 }
2243 }
2244 }
2245}
2246
2247fn line_height(
2248 parent_style: &ComputedValues,
2249 font_metrics: &FontMetrics,
2250 is_single_line_text_input: bool,
2251) -> Au {
2252 let font = parent_style.get_font();
2253 let font_size = font.font_size.computed_size();
2254 let mut line_height = match font.line_height {
2255 LineHeight::Normal => font_metrics.line_gap,
2256 LineHeight::Number(number) => (font_size * number.0).into(),
2257 LineHeight::Length(length) => length.0.into(),
2258 };
2259
2260 if is_single_line_text_input {
2264 line_height.max_assign(font_metrics.line_gap);
2265 }
2266
2267 line_height
2268}
2269
2270fn effective_vertical_align(
2271 style: &ComputedValues,
2272 container: Option<&InlineContainerState>,
2273) -> VerticalAlign {
2274 if container.is_none() {
2275 VerticalAlign::Keyword(VerticalAlignKeyword::Baseline)
2279 } else {
2280 style.clone_vertical_align()
2281 }
2282}
2283
2284fn is_baseline_relative(vertical_align: VerticalAlign) -> bool {
2285 !matches!(
2286 vertical_align,
2287 VerticalAlign::Keyword(VerticalAlignKeyword::Top) |
2288 VerticalAlign::Keyword(VerticalAlignKeyword::Bottom)
2289 )
2290}
2291
2292fn inline_container_needs_strut(
2318 style: &ComputedValues,
2319 layout_context: &LayoutContext,
2320 pbm: Option<&PaddingBorderMargin>,
2321) -> bool {
2322 if layout_context.style_context.quirks_mode() == QuirksMode::NoQuirks {
2323 return true;
2324 }
2325
2326 if style.get_box().display.is_list_item() {
2329 return true;
2330 }
2331
2332 pbm.map(|pbm| !pbm.padding_border_sums.inline.is_zero())
2333 .unwrap_or(false)
2334}
2335
2336impl ComputeInlineContentSizes for InlineFormattingContext {
2337 fn compute_inline_content_sizes(
2341 &self,
2342 layout_context: &LayoutContext,
2343 constraint_space: &ConstraintSpace,
2344 ) -> InlineContentSizesResult {
2345 ContentSizesComputation::compute(self, layout_context, constraint_space)
2346 }
2347}
2348
2349struct ContentSizesComputation<'layout_data> {
2351 layout_context: &'layout_data LayoutContext<'layout_data>,
2352 constraint_space: &'layout_data ConstraintSpace,
2353 paragraph: ContentSizes,
2354 current_line: ContentSizes,
2355 pending_whitespace: ContentSizes,
2357 had_content_yet_for_min_content: bool,
2360 had_content_yet_for_max_content: bool,
2363 ending_inline_pbm_stack: Vec<Au>,
2366 depends_on_block_constraints: bool,
2367}
2368
2369impl<'layout_data> ContentSizesComputation<'layout_data> {
2370 fn traverse(
2371 mut self,
2372 inline_formatting_context: &InlineFormattingContext,
2373 ) -> InlineContentSizesResult {
2374 for inline_item in inline_formatting_context.inline_items.iter() {
2375 self.process_item(&inline_item.borrow(), inline_formatting_context);
2376 }
2377 self.forced_line_break();
2378
2379 InlineContentSizesResult {
2380 sizes: self.paragraph,
2381 depends_on_block_constraints: self.depends_on_block_constraints,
2382 }
2383 }
2384
2385 fn process_item(
2386 &mut self,
2387 inline_item: &InlineItem,
2388 inline_formatting_context: &InlineFormattingContext,
2389 ) {
2390 match inline_item {
2391 InlineItem::StartInlineBox(inline_box) => {
2392 let inline_box = inline_box.borrow();
2396 let zero = Au::zero();
2397 let writing_mode = self.constraint_space.writing_mode;
2398 let layout_style = inline_box.layout_style();
2399 let padding = layout_style
2400 .padding(writing_mode)
2401 .percentages_relative_to(zero);
2402 let border = layout_style.border_width(writing_mode);
2403 let margin = inline_box
2404 .base
2405 .style
2406 .margin(writing_mode)
2407 .percentages_relative_to(zero)
2408 .auto_is(Au::zero);
2409
2410 let pbm = margin + padding + border;
2411 if inline_box.is_first_split {
2412 self.add_inline_size(pbm.inline_start);
2413 }
2414 if inline_box.is_last_split {
2415 self.ending_inline_pbm_stack.push(pbm.inline_end);
2416 } else {
2417 self.ending_inline_pbm_stack.push(Au::zero());
2418 }
2419 },
2420 InlineItem::EndInlineBox => {
2421 let length = self.ending_inline_pbm_stack.pop().unwrap_or_else(Au::zero);
2422 self.add_inline_size(length);
2423 },
2424 InlineItem::TextRun(text_run) => {
2425 let text_run = &*text_run.borrow();
2426 let parent_style = text_run.inline_styles.style.borrow();
2427 for segment in text_run.shaped_text.iter() {
2428 let style_text = parent_style.get_inherited_text();
2429 let can_wrap = style_text.text_wrap_mode == TextWrapMode::Wrap;
2430
2431 if can_wrap && segment.break_at_start {
2434 self.line_break_opportunity()
2435 }
2436
2437 for run in segment.runs.iter() {
2438 let advance = run.glyph_store.total_advance();
2439 if run.glyph_store.is_whitespace() {
2440 if run.is_single_preserved_newline() {
2443 self.forced_line_break();
2444 continue;
2445 }
2446 if !matches!(
2447 style_text.white_space_collapse,
2448 WhiteSpaceCollapse::Preserve | WhiteSpaceCollapse::BreakSpaces
2449 ) {
2450 if can_wrap {
2451 self.line_break_opportunity();
2452 } else if self.had_content_yet_for_min_content {
2453 self.pending_whitespace.min_content += advance;
2454 }
2455 if self.had_content_yet_for_max_content {
2456 self.pending_whitespace.max_content += advance;
2457 }
2458 continue;
2459 }
2460 if can_wrap {
2461 self.pending_whitespace.max_content += advance;
2462 self.commit_pending_whitespace();
2463 self.line_break_opportunity();
2464 continue;
2465 }
2466 }
2467
2468 self.commit_pending_whitespace();
2469 self.add_inline_size(advance);
2470
2471 if can_wrap && run.glyph_store.ends_with_whitespace() {
2476 self.line_break_opportunity();
2477 }
2478 }
2479 }
2480 },
2481 InlineItem::Atomic(atomic, offset_in_text, _level) => {
2482 if !inline_formatting_context
2484 .previous_character_prevents_soft_wrap_opportunity(*offset_in_text)
2485 {
2486 self.line_break_opportunity();
2487 }
2488
2489 let InlineContentSizesResult {
2490 sizes: outer,
2491 depends_on_block_constraints,
2492 } = atomic.borrow().outer_inline_content_sizes(
2493 self.layout_context,
2494 &self.constraint_space.into(),
2495 &LogicalVec2::zero(),
2496 false, );
2498 self.depends_on_block_constraints |= depends_on_block_constraints;
2499
2500 if !inline_formatting_context
2501 .next_character_prevents_soft_wrap_opportunity(*offset_in_text)
2502 {
2503 self.line_break_opportunity();
2504 }
2505
2506 self.commit_pending_whitespace();
2507 self.current_line += outer;
2508 },
2509 _ => {},
2510 }
2511 }
2512
2513 fn add_inline_size(&mut self, l: Au) {
2514 self.current_line.min_content += l;
2515 self.current_line.max_content += l;
2516 }
2517
2518 fn line_break_opportunity(&mut self) {
2519 self.pending_whitespace.min_content = Au::zero();
2523 let current_min_content = mem::take(&mut self.current_line.min_content);
2524 self.paragraph.min_content.max_assign(current_min_content);
2525 self.had_content_yet_for_min_content = false;
2526 }
2527
2528 fn forced_line_break(&mut self) {
2529 self.line_break_opportunity();
2531
2532 self.pending_whitespace.max_content = Au::zero();
2534 let current_max_content = mem::take(&mut self.current_line.max_content);
2535 self.paragraph.max_content.max_assign(current_max_content);
2536 self.had_content_yet_for_max_content = false;
2537 }
2538
2539 fn commit_pending_whitespace(&mut self) {
2540 self.current_line += mem::take(&mut self.pending_whitespace);
2541 self.had_content_yet_for_min_content = true;
2542 self.had_content_yet_for_max_content = true;
2543 }
2544
2545 fn compute(
2547 inline_formatting_context: &InlineFormattingContext,
2548 layout_context: &'layout_data LayoutContext,
2549 constraint_space: &'layout_data ConstraintSpace,
2550 ) -> InlineContentSizesResult {
2551 Self {
2552 layout_context,
2553 constraint_space,
2554 paragraph: ContentSizes::zero(),
2555 current_line: ContentSizes::zero(),
2556 pending_whitespace: ContentSizes::zero(),
2557 had_content_yet_for_min_content: false,
2558 had_content_yet_for_max_content: false,
2559 ending_inline_pbm_stack: Vec::new(),
2560 depends_on_block_constraints: false,
2561 }
2562 .traverse(inline_formatting_context)
2563 }
2564}
2565
2566fn char_prevents_soft_wrap_opportunity_when_before_or_after_atomic(character: char) -> bool {
2578 if character == '\u{00A0}' {
2579 return false;
2580 }
2581 let class = linebreak_property(character);
2582 class == XI_LINE_BREAKING_CLASS_GL ||
2583 class == XI_LINE_BREAKING_CLASS_WJ ||
2584 class == XI_LINE_BREAKING_CLASS_ZWJ
2585}