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 base::id::RenderingGroupId;
83use bitflags::bitflags;
84use construct::InlineFormattingContextBuilder;
85use fonts::{ByteIndex, FontMetrics, GlyphStore};
86use inline_box::{InlineBox, InlineBoxContainerState, InlineBoxIdentifier, InlineBoxes};
87use line::{
88 AbsolutelyPositionedLineItem, AtomicLineItem, FloatLineItem, LineItem, LineItemLayout,
89 TextRunLineItem,
90};
91use line_breaker::LineBreaker;
92use malloc_size_of_derive::MallocSizeOf;
93use range::Range;
94use script::layout_dom::ServoThreadSafeLayoutNode;
95use servo_arc::Arc;
96use style::Zero;
97use style::computed_values::text_wrap_mode::T as TextWrapMode;
98use style::computed_values::vertical_align::T as VerticalAlign;
99use style::computed_values::white_space_collapse::T as WhiteSpaceCollapse;
100use style::context::{QuirksMode, SharedStyleContext};
101use style::properties::ComputedValues;
102use style::properties::style_structs::InheritedText;
103use style::values::generics::box_::VerticalAlignKeyword;
104use style::values::generics::font::LineHeight;
105use style::values::specified::box_::BaselineSource;
106use style::values::specified::text::TextAlignKeyword;
107use style::values::specified::{TextAlignLast, TextJustify};
108use text_run::{
109 TextRun, XI_LINE_BREAKING_CLASS_GL, XI_LINE_BREAKING_CLASS_WJ, XI_LINE_BREAKING_CLASS_ZWJ,
110 add_or_get_font, get_font_for_first_font_for_style,
111};
112use unicode_bidi::{BidiInfo, Level};
113use webrender_api::FontInstanceKey;
114use xi_unicode::linebreak_property;
115
116use super::float::{Clear, PlacementAmongFloats};
117use super::{CacheableLayoutResult, IndependentFloatOrAtomicLayoutResult};
118use crate::cell::ArcRefCell;
119use crate::context::LayoutContext;
120use crate::dom_traversal::NodeAndStyleInfo;
121use crate::flow::CollapsibleWithParentStartMargin;
122use crate::flow::float::{FloatBox, SequentialLayoutState};
123use crate::formatting_contexts::{Baselines, IndependentFormattingContext};
124use crate::fragment_tree::{
125 BoxFragment, CollapsedBlockMargins, CollapsedMargin, Fragment, FragmentFlags,
126 PositioningFragment,
127};
128use crate::geom::{LogicalRect, LogicalVec2, ToLogical};
129use crate::layout_box_base::LayoutBoxBase;
130use crate::positioned::{AbsolutelyPositionedBox, PositioningContext};
131use crate::sizing::{ComputeInlineContentSizes, ContentSizes, InlineContentSizesResult};
132use crate::style_ext::{ComputedValuesExt, PaddingBorderMargin};
133use crate::{ConstraintSpace, ContainingBlock, IndefiniteContainingBlock, SharedStyle};
134
135static FONT_SUBSCRIPT_OFFSET_RATIO: f32 = 0.20;
137static FONT_SUPERSCRIPT_OFFSET_RATIO: f32 = 0.34;
138
139#[derive(Debug, MallocSizeOf)]
140pub(crate) struct InlineFormattingContext {
141 pub(super) inline_items: Vec<ArcRefCell<InlineItem>>,
146
147 pub(super) inline_boxes: InlineBoxes,
150
151 pub(super) text_content: String,
153
154 pub font_metrics: Vec<FontKeyAndMetrics>,
157
158 pub(super) shared_inline_styles: SharedInlineStyles,
161
162 pub(super) has_first_formatted_line: bool,
165
166 pub(super) contains_floats: bool,
168
169 pub(super) is_single_line_text_input: bool,
172
173 pub(super) has_right_to_left_content: bool,
176}
177
178#[derive(Clone, Debug, MallocSizeOf)]
183pub(crate) struct SharedInlineStyles {
184 pub style: SharedStyle,
185 pub selected: SharedStyle,
186}
187
188impl From<&NodeAndStyleInfo<'_>> for SharedInlineStyles {
189 fn from(info: &NodeAndStyleInfo) -> Self {
190 Self {
191 style: SharedStyle::new(info.style.clone()),
192 selected: SharedStyle::new(info.node.selected_style()),
193 }
194 }
195}
196
197#[derive(Debug, MallocSizeOf)]
199pub(crate) struct FontKeyAndMetrics {
200 pub key: FontInstanceKey,
201 pub pt_size: Au,
202 pub metrics: FontMetrics,
203}
204
205#[derive(Debug, MallocSizeOf)]
206pub(crate) enum InlineItem {
207 StartInlineBox(ArcRefCell<InlineBox>),
208 EndInlineBox,
209 TextRun(ArcRefCell<TextRun>),
210 OutOfFlowAbsolutelyPositionedBox(
211 ArcRefCell<AbsolutelyPositionedBox>,
212 usize, ),
214 OutOfFlowFloatBox(ArcRefCell<FloatBox>),
215 Atomic(
216 ArcRefCell<IndependentFormattingContext>,
217 usize, Level, ),
220}
221
222impl InlineItem {
223 pub(crate) fn repair_style(
224 &self,
225 context: &SharedStyleContext,
226 node: &ServoThreadSafeLayoutNode,
227 new_style: &Arc<ComputedValues>,
228 ) {
229 match self {
230 InlineItem::StartInlineBox(inline_box) => {
231 inline_box.borrow_mut().repair_style(node, new_style);
232 },
233 InlineItem::EndInlineBox => {},
234 InlineItem::TextRun(..) => {},
237 InlineItem::OutOfFlowAbsolutelyPositionedBox(positioned_box, ..) => positioned_box
238 .borrow_mut()
239 .context
240 .repair_style(context, node, new_style),
241 InlineItem::OutOfFlowFloatBox(float_box) => float_box
242 .borrow_mut()
243 .contents
244 .repair_style(context, node, new_style),
245 InlineItem::Atomic(atomic, ..) => {
246 atomic.borrow_mut().repair_style(context, node, new_style)
247 },
248 }
249 }
250
251 pub(crate) fn with_base<T>(&self, callback: impl FnOnce(&LayoutBoxBase) -> T) -> T {
252 match self {
253 InlineItem::StartInlineBox(inline_box) => callback(&inline_box.borrow().base),
254 InlineItem::EndInlineBox | InlineItem::TextRun(..) => {
255 unreachable!("Should never have these kind of fragments attached to a DOM node")
256 },
257 InlineItem::OutOfFlowAbsolutelyPositionedBox(positioned_box, ..) => {
258 callback(&positioned_box.borrow().context.base)
259 },
260 InlineItem::OutOfFlowFloatBox(float_box) => callback(&float_box.borrow().contents.base),
261 InlineItem::Atomic(independent_formatting_context, ..) => {
262 callback(&independent_formatting_context.borrow().base)
263 },
264 }
265 }
266
267 pub(crate) fn with_base_mut<T>(&mut self, callback: impl FnOnce(&mut LayoutBoxBase) -> T) -> T {
268 match self {
269 InlineItem::StartInlineBox(inline_box) => callback(&mut inline_box.borrow_mut().base),
270 InlineItem::EndInlineBox | InlineItem::TextRun(..) => {
271 unreachable!("Should never have these kind of fragments attached to a DOM node")
272 },
273 InlineItem::OutOfFlowAbsolutelyPositionedBox(positioned_box, ..) => {
274 callback(&mut positioned_box.borrow_mut().context.base)
275 },
276 InlineItem::OutOfFlowFloatBox(float_box) => {
277 callback(&mut float_box.borrow_mut().contents.base)
278 },
279 InlineItem::Atomic(independent_formatting_context, ..) => {
280 callback(&mut independent_formatting_context.borrow_mut().base)
281 },
282 }
283 }
284}
285
286struct LineUnderConstruction {
293 start_position: LogicalVec2<Au>,
296
297 inline_position: Au,
300
301 max_block_size: LineBlockSizes,
305
306 has_content: bool,
309
310 has_inline_pbm: bool,
313
314 has_floats_waiting_to_be_placed: bool,
318
319 placement_among_floats: OnceCell<LogicalRect<Au>>,
324
325 line_items: Vec<LineItem>,
328}
329
330impl LineUnderConstruction {
331 fn new(start_position: LogicalVec2<Au>) -> Self {
332 Self {
333 inline_position: start_position.inline,
334 start_position,
335 max_block_size: LineBlockSizes::zero(),
336 has_content: false,
337 has_inline_pbm: false,
338 has_floats_waiting_to_be_placed: false,
339 placement_among_floats: OnceCell::new(),
340 line_items: Vec::new(),
341 }
342 }
343
344 fn line_block_start_considering_placement_among_floats(&self) -> Au {
345 match self.placement_among_floats.get() {
346 Some(placement_among_floats) => placement_among_floats.start_corner.block,
347 None => self.start_position.block,
348 }
349 }
350
351 fn replace_placement_among_floats(&mut self, new_placement: LogicalRect<Au>) {
352 self.placement_among_floats.take();
353 let _ = self.placement_among_floats.set(new_placement);
354 }
355
356 fn trim_trailing_whitespace(&mut self) -> Au {
358 let mut whitespace_trimmed = Au::zero();
363 for item in self.line_items.iter_mut().rev() {
364 if !item.trim_whitespace_at_end(&mut whitespace_trimmed) {
365 break;
366 }
367 }
368
369 whitespace_trimmed
370 }
371
372 fn count_justification_opportunities(&self) -> usize {
374 self.line_items
375 .iter()
376 .filter_map(|item| match item {
377 LineItem::TextRun(_, text_run) => Some(
378 text_run
379 .text
380 .iter()
381 .map(|glyph_store| glyph_store.total_word_separators())
382 .sum::<usize>(),
383 ),
384 _ => None,
385 })
386 .sum()
387 }
388}
389
390#[derive(Clone, Debug)]
396struct BaselineRelativeSize {
397 ascent: Au,
401
402 descent: Au,
406}
407
408impl BaselineRelativeSize {
409 fn zero() -> Self {
410 Self {
411 ascent: Au::zero(),
412 descent: Au::zero(),
413 }
414 }
415
416 fn max(&self, other: &Self) -> Self {
417 BaselineRelativeSize {
418 ascent: self.ascent.max(other.ascent),
419 descent: self.descent.max(other.descent),
420 }
421 }
422
423 fn adjust_for_nested_baseline_offset(&mut self, baseline_offset: Au) {
437 self.ascent -= baseline_offset;
438 self.descent += baseline_offset;
439 }
440}
441
442#[derive(Clone, Debug)]
443struct LineBlockSizes {
444 line_height: Au,
445 baseline_relative_size_for_line_height: Option<BaselineRelativeSize>,
446 size_for_baseline_positioning: BaselineRelativeSize,
447}
448
449impl LineBlockSizes {
450 fn zero() -> Self {
451 LineBlockSizes {
452 line_height: Au::zero(),
453 baseline_relative_size_for_line_height: None,
454 size_for_baseline_positioning: BaselineRelativeSize::zero(),
455 }
456 }
457
458 fn resolve(&self) -> Au {
459 let height_from_ascent_and_descent = self
460 .baseline_relative_size_for_line_height
461 .as_ref()
462 .map(|size| (size.ascent + size.descent).abs())
463 .unwrap_or_else(Au::zero);
464 self.line_height.max(height_from_ascent_and_descent)
465 }
466
467 fn max(&self, other: &LineBlockSizes) -> LineBlockSizes {
468 let baseline_relative_size = match (
469 self.baseline_relative_size_for_line_height.as_ref(),
470 other.baseline_relative_size_for_line_height.as_ref(),
471 ) {
472 (Some(our_size), Some(other_size)) => Some(our_size.max(other_size)),
473 (our_size, other_size) => our_size.or(other_size).cloned(),
474 };
475 Self {
476 line_height: self.line_height.max(other.line_height),
477 baseline_relative_size_for_line_height: baseline_relative_size,
478 size_for_baseline_positioning: self
479 .size_for_baseline_positioning
480 .max(&other.size_for_baseline_positioning),
481 }
482 }
483
484 fn max_assign(&mut self, other: &LineBlockSizes) {
485 *self = self.max(other);
486 }
487
488 fn adjust_for_baseline_offset(&mut self, baseline_offset: Au) {
489 if let Some(size) = self.baseline_relative_size_for_line_height.as_mut() {
490 size.adjust_for_nested_baseline_offset(baseline_offset)
491 }
492 self.size_for_baseline_positioning
493 .adjust_for_nested_baseline_offset(baseline_offset);
494 }
495
496 fn find_baseline_offset(&self) -> Au {
503 match self.baseline_relative_size_for_line_height.as_ref() {
504 Some(size) => size.ascent,
505 None => {
506 let leading = self.resolve() -
509 (self.size_for_baseline_positioning.ascent +
510 self.size_for_baseline_positioning.descent);
511 leading.scale_by(0.5) + self.size_for_baseline_positioning.ascent
512 },
513 }
514 }
515}
516
517struct UnbreakableSegmentUnderConstruction {
521 inline_size: Au,
523
524 max_block_size: LineBlockSizes,
527
528 line_items: Vec<LineItem>,
530
531 inline_box_hierarchy_depth: Option<usize>,
534
535 has_content: bool,
539
540 has_inline_pbm: bool,
543
544 trailing_whitespace_size: Au,
546}
547
548impl UnbreakableSegmentUnderConstruction {
549 fn new() -> Self {
550 Self {
551 inline_size: Au::zero(),
552 max_block_size: LineBlockSizes {
553 line_height: Au::zero(),
554 baseline_relative_size_for_line_height: None,
555 size_for_baseline_positioning: BaselineRelativeSize::zero(),
556 },
557 line_items: Vec::new(),
558 inline_box_hierarchy_depth: None,
559 has_content: false,
560 has_inline_pbm: false,
561 trailing_whitespace_size: Au::zero(),
562 }
563 }
564
565 fn reset(&mut self) {
567 assert!(self.line_items.is_empty()); self.inline_size = Au::zero();
569 self.max_block_size = LineBlockSizes::zero();
570 self.inline_box_hierarchy_depth = None;
571 self.has_content = false;
572 self.has_inline_pbm = false;
573 self.trailing_whitespace_size = Au::zero();
574 }
575
576 fn push_line_item(&mut self, line_item: LineItem, inline_box_hierarchy_depth: usize) {
581 if self.line_items.is_empty() {
582 self.inline_box_hierarchy_depth = Some(inline_box_hierarchy_depth);
583 }
584 self.line_items.push(line_item);
585 }
586
587 fn trim_leading_whitespace(&mut self) {
598 let mut whitespace_trimmed = Au::zero();
599 for item in self.line_items.iter_mut() {
600 if !item.trim_whitespace_at_start(&mut whitespace_trimmed) {
601 break;
602 }
603 }
604 self.inline_size -= whitespace_trimmed;
605 }
606}
607
608bitflags! {
609 pub struct InlineContainerStateFlags: u8 {
610 const CREATE_STRUT = 0b0001;
611 const IS_SINGLE_LINE_TEXT_INPUT = 0b0010;
612 }
613}
614
615pub(super) struct InlineContainerState {
616 style: Arc<ComputedValues>,
618
619 flags: InlineContainerStateFlags,
621
622 has_content: RefCell<bool>,
625
626 strut_block_sizes: LineBlockSizes,
631
632 nested_strut_block_sizes: LineBlockSizes,
636
637 pub baseline_offset: Au,
643
644 font_metrics: FontMetrics,
646}
647
648pub(super) struct InlineFormattingContextLayout<'layout_data> {
649 positioning_context: &'layout_data mut PositioningContext,
650 containing_block: &'layout_data ContainingBlock<'layout_data>,
651 sequential_layout_state: Option<&'layout_data mut SequentialLayoutState>,
652 layout_context: &'layout_data LayoutContext<'layout_data>,
653
654 ifc: &'layout_data InlineFormattingContext,
656
657 root_nesting_level: InlineContainerState,
667
668 inline_box_state_stack: Vec<Rc<InlineBoxContainerState>>,
672
673 inline_box_states: Vec<Rc<InlineBoxContainerState>>,
678
679 fragments: Vec<Fragment>,
683
684 current_line: LineUnderConstruction,
686
687 current_line_segment: UnbreakableSegmentUnderConstruction,
689
690 linebreak_before_new_content: bool,
709
710 deferred_br_clear: Clear,
714
715 pub have_deferred_soft_wrap_opportunity: bool,
719
720 has_line_boxes: bool,
723
724 depends_on_block_constraints: bool,
727
728 white_space_collapse: WhiteSpaceCollapse,
733
734 text_wrap_mode: TextWrapMode,
739
740 baselines: Baselines,
744}
745
746impl InlineFormattingContextLayout<'_> {
747 fn current_inline_container_state(&self) -> &InlineContainerState {
748 match self.inline_box_state_stack.last() {
749 Some(inline_box_state) => &inline_box_state.base,
750 None => &self.root_nesting_level,
751 }
752 }
753
754 fn current_inline_box_identifier(&self) -> Option<InlineBoxIdentifier> {
755 self.inline_box_state_stack
756 .last()
757 .map(|state| state.identifier)
758 }
759
760 fn current_line_max_block_size_including_nested_containers(&self) -> LineBlockSizes {
761 self.current_inline_container_state()
762 .nested_strut_block_sizes
763 .max(&self.current_line.max_block_size)
764 }
765
766 fn propagate_current_nesting_level_white_space_style(&mut self) {
767 let style = match self.inline_box_state_stack.last() {
768 Some(inline_box_state) => &inline_box_state.base.style,
769 None => self.containing_block.style,
770 };
771 let style_text = style.get_inherited_text();
772 self.white_space_collapse = style_text.white_space_collapse;
773 self.text_wrap_mode = style_text.text_wrap_mode;
774 }
775
776 fn processing_br_element(&self) -> bool {
777 self.inline_box_state_stack
778 .last()
779 .map(|state| {
780 state
781 .base_fragment_info
782 .flags
783 .contains(FragmentFlags::IS_BR_ELEMENT)
784 })
785 .unwrap_or(false)
786 }
787
788 fn start_inline_box(&mut self, inline_box: &InlineBox) {
791 let inline_box_state = InlineBoxContainerState::new(
792 inline_box,
793 self.containing_block,
794 self.layout_context,
795 self.current_inline_container_state(),
796 inline_box.is_last_split,
797 inline_box
798 .default_font_index
799 .map(|index| &self.ifc.font_metrics[index].metrics),
800 );
801
802 self.depends_on_block_constraints |= inline_box
803 .base
804 .style
805 .depends_on_block_constraints_due_to_relative_positioning(
806 self.containing_block.style.writing_mode,
807 );
808
809 if inline_box_state
814 .base_fragment_info
815 .flags
816 .contains(FragmentFlags::IS_BR_ELEMENT) &&
817 self.deferred_br_clear == Clear::None
818 {
819 self.deferred_br_clear = Clear::from_style_and_container_writing_mode(
820 &inline_box_state.base.style,
821 self.containing_block.style.writing_mode,
822 );
823 }
824
825 if inline_box.is_first_split {
826 let padding = inline_box_state.pbm.padding.inline_start;
827 let border = inline_box_state.pbm.border.inline_start;
828 let margin = inline_box_state.pbm.margin.inline_start.auto_is(Au::zero);
829 if !padding.is_zero() || !border.is_zero() || !margin.is_zero() {
832 self.current_line_segment.has_inline_pbm = true;
833 }
834 self.current_line_segment.inline_size += padding + border + margin;
835 self.current_line_segment
836 .line_items
837 .push(LineItem::InlineStartBoxPaddingBorderMargin(
838 inline_box.identifier,
839 ));
840 }
841
842 let inline_box_state = Rc::new(inline_box_state);
843
844 assert_eq!(
848 self.inline_box_states.len(),
849 inline_box.identifier.index_in_inline_boxes as usize
850 );
851 self.inline_box_states.push(inline_box_state.clone());
852 self.inline_box_state_stack.push(inline_box_state);
853 }
854
855 fn finish_inline_box(&mut self) {
858 let inline_box_state = match self.inline_box_state_stack.pop() {
859 Some(inline_box_state) => inline_box_state,
860 None => return, };
862
863 self.current_line_segment
864 .max_block_size
865 .max_assign(&inline_box_state.base.nested_strut_block_sizes);
866
867 if *inline_box_state.base.has_content.borrow() {
872 self.propagate_current_nesting_level_white_space_style();
873 }
874
875 if inline_box_state.is_last_fragment {
876 let padding = inline_box_state.pbm.padding.inline_end;
877 let border = inline_box_state.pbm.border.inline_end;
878 let margin = inline_box_state.pbm.margin.inline_end.auto_is(Au::zero);
879 if !padding.is_zero() || !border.is_zero() || !margin.is_zero() {
882 self.current_line_segment.has_inline_pbm = true;
883 }
884 self.current_line_segment.inline_size += padding + border + margin;
885 self.current_line_segment
886 .line_items
887 .push(LineItem::InlineEndBoxPaddingBorderMargin(
888 inline_box_state.identifier,
889 ))
890 }
891 }
892
893 fn finish_last_line(&mut self) {
894 self.process_soft_wrap_opportunity();
900
901 self.commit_current_segment_to_line();
904
905 self.finish_current_line_and_reset(true );
908 }
909
910 fn finish_current_line_and_reset(&mut self, last_line_or_forced_line_break: bool) {
914 let whitespace_trimmed = self.current_line.trim_trailing_whitespace();
915 let (inline_start_position, justification_adjustment) = self
916 .calculate_current_line_inline_start_and_justification_adjustment(
917 whitespace_trimmed,
918 last_line_or_forced_line_break,
919 );
920
921 let block_start_position = self
922 .current_line
923 .line_block_start_considering_placement_among_floats();
924
925 let is_phantom_line = !self.current_line.has_content && !self.current_line.has_inline_pbm;
934 let effective_block_advance = if is_phantom_line {
935 LineBlockSizes::zero()
936 } else {
937 self.current_line_max_block_size_including_nested_containers()
938 };
939
940 let resolved_block_advance = effective_block_advance.resolve();
941 let mut block_end_position = block_start_position + resolved_block_advance;
942 if let Some(sequential_layout_state) = self.sequential_layout_state.as_mut() {
943 let increment = block_end_position - self.current_line.start_position.block;
946 sequential_layout_state.advance_block_position(increment);
947
948 if let Some(clearance) = sequential_layout_state
952 .calculate_clearance(self.deferred_br_clear, &CollapsedMargin::zero())
953 {
954 sequential_layout_state.advance_block_position(clearance);
955 block_end_position += clearance;
956 };
957 self.deferred_br_clear = Clear::None;
958 }
959
960 let mut line_to_layout = std::mem::replace(
962 &mut self.current_line,
963 LineUnderConstruction::new(LogicalVec2 {
964 inline: Au::zero(),
965 block: block_end_position,
966 }),
967 );
968
969 if line_to_layout.has_floats_waiting_to_be_placed {
970 place_pending_floats(self, &mut line_to_layout.line_items);
971 }
972
973 let start_position = LogicalVec2 {
974 block: block_start_position,
975 inline: inline_start_position,
976 };
977
978 let baseline_offset = effective_block_advance.find_baseline_offset();
979 let start_positioning_context_length = self.positioning_context.len();
980 let fragments = LineItemLayout::layout_line_items(
981 self,
982 line_to_layout.line_items,
983 start_position,
984 &effective_block_advance,
985 justification_adjustment,
986 is_phantom_line,
987 );
988
989 if !is_phantom_line {
990 let baseline = baseline_offset + block_start_position;
991 self.baselines.first.get_or_insert(baseline);
992 self.baselines.last = Some(baseline);
993 self.has_line_boxes = true;
994 }
995
996 if fragments.is_empty() &&
998 self.positioning_context.len() == start_positioning_context_length
999 {
1000 return;
1001 }
1002
1003 let start_corner = LogicalVec2 {
1007 inline: Au::zero(),
1008 block: block_start_position,
1009 };
1010
1011 let logical_origin_in_physical_coordinates =
1012 start_corner.to_physical_vector(self.containing_block.style.writing_mode);
1013 self.positioning_context
1014 .adjust_static_position_of_hoisted_fragments_with_offset(
1015 &logical_origin_in_physical_coordinates,
1016 start_positioning_context_length,
1017 );
1018
1019 let physical_line_rect = LogicalRect {
1020 start_corner,
1021 size: LogicalVec2 {
1022 inline: self.containing_block.size.inline,
1023 block: effective_block_advance.resolve(),
1024 },
1025 }
1026 .as_physical(Some(self.containing_block));
1027 self.fragments
1028 .push(Fragment::Positioning(PositioningFragment::new_anonymous(
1029 self.root_nesting_level.style.clone(),
1030 physical_line_rect,
1031 fragments,
1032 )));
1033 }
1034
1035 fn calculate_current_line_inline_start_and_justification_adjustment(
1040 &self,
1041 whitespace_trimmed: Au,
1042 last_line_or_forced_line_break: bool,
1043 ) -> (Au, Au) {
1044 enum TextAlign {
1045 Start,
1046 Center,
1047 End,
1048 }
1049 let style = self.containing_block.style;
1050 let mut text_align_keyword = style.clone_text_align();
1051
1052 if last_line_or_forced_line_break {
1053 text_align_keyword = match style.clone_text_align_last() {
1054 TextAlignLast::Auto if text_align_keyword == TextAlignKeyword::Justify => {
1055 TextAlignKeyword::Start
1056 },
1057 TextAlignLast::Auto => text_align_keyword,
1058 TextAlignLast::Start => TextAlignKeyword::Start,
1059 TextAlignLast::End => TextAlignKeyword::End,
1060 TextAlignLast::Left => TextAlignKeyword::Left,
1061 TextAlignLast::Right => TextAlignKeyword::Right,
1062 TextAlignLast::Center => TextAlignKeyword::Center,
1063 TextAlignLast::Justify => TextAlignKeyword::Justify,
1064 };
1065 }
1066
1067 let text_align = match text_align_keyword {
1068 TextAlignKeyword::Start => TextAlign::Start,
1069 TextAlignKeyword::Center | TextAlignKeyword::MozCenter => TextAlign::Center,
1070 TextAlignKeyword::End => TextAlign::End,
1071 TextAlignKeyword::Left | TextAlignKeyword::MozLeft => {
1072 if style.writing_mode.line_left_is_inline_start() {
1073 TextAlign::Start
1074 } else {
1075 TextAlign::End
1076 }
1077 },
1078 TextAlignKeyword::Right | TextAlignKeyword::MozRight => {
1079 if style.writing_mode.line_left_is_inline_start() {
1080 TextAlign::End
1081 } else {
1082 TextAlign::Start
1083 }
1084 },
1085 TextAlignKeyword::Justify => TextAlign::Start,
1086 };
1087
1088 let (line_start, available_space) = match self.current_line.placement_among_floats.get() {
1089 Some(placement_among_floats) => (
1090 placement_among_floats.start_corner.inline,
1091 placement_among_floats.size.inline,
1092 ),
1093 None => (Au::zero(), self.containing_block.size.inline),
1094 };
1095
1096 let text_indent = self.current_line.start_position.inline;
1103 let line_length = self.current_line.inline_position - whitespace_trimmed - text_indent;
1104 let adjusted_line_start = line_start +
1105 match text_align {
1106 TextAlign::Start => text_indent,
1107 TextAlign::End => (available_space - line_length).max(text_indent),
1108 TextAlign::Center => (available_space - line_length + text_indent)
1109 .scale_by(0.5)
1110 .max(text_indent),
1111 };
1112
1113 let text_justify = self.containing_block.style.clone_text_justify();
1117 let justification_adjustment = match (text_align_keyword, text_justify) {
1118 (TextAlignKeyword::Justify, TextJustify::None) => Au::zero(),
1121 (TextAlignKeyword::Justify, _) => {
1122 match self.current_line.count_justification_opportunities() {
1123 0 => Au::zero(),
1124 num_justification_opportunities => {
1125 (available_space - text_indent - line_length)
1126 .scale_by(1. / num_justification_opportunities as f32)
1127 },
1128 }
1129 },
1130 _ => Au::zero(),
1131 };
1132
1133 let justification_adjustment = justification_adjustment.max(Au::zero());
1136
1137 (adjusted_line_start, justification_adjustment)
1138 }
1139
1140 fn place_float_fragment(&mut self, fragment: &mut BoxFragment) {
1141 let state = self
1142 .sequential_layout_state
1143 .as_mut()
1144 .expect("Tried to lay out a float with no sequential placement state!");
1145
1146 let block_offset_from_containining_block_top = state
1147 .current_block_position_including_margins() -
1148 state.current_containing_block_offset();
1149 state.place_float_fragment(
1150 fragment,
1151 self.containing_block,
1152 CollapsedMargin::zero(),
1153 block_offset_from_containining_block_top,
1154 );
1155 }
1156
1157 fn place_float_line_item_for_commit_to_line(
1166 &mut self,
1167 float_item: &mut FloatLineItem,
1168 line_inline_size_without_trailing_whitespace: Au,
1169 ) {
1170 let mut float_fragment = float_item.fragment.borrow_mut();
1171 let logical_margin_rect_size = float_fragment
1172 .margin_rect()
1173 .size
1174 .to_logical(self.containing_block.style.writing_mode);
1175 let inline_size = logical_margin_rect_size.inline.max(Au::zero());
1176
1177 let available_inline_size = match self.current_line.placement_among_floats.get() {
1178 Some(placement_among_floats) => placement_among_floats.size.inline,
1179 None => self.containing_block.size.inline,
1180 } - line_inline_size_without_trailing_whitespace;
1181
1182 let has_content = self.current_line.has_content || self.current_line_segment.has_content;
1188 let fits_on_line = !has_content || inline_size <= available_inline_size;
1189 let needs_placement_later =
1190 self.current_line.has_floats_waiting_to_be_placed || !fits_on_line;
1191
1192 if needs_placement_later {
1193 self.current_line.has_floats_waiting_to_be_placed = true;
1194 } else {
1195 self.place_float_fragment(&mut float_fragment);
1196 float_item.needs_placement = false;
1197 }
1198
1199 let new_placement = self.place_line_among_floats(&LogicalVec2 {
1204 inline: line_inline_size_without_trailing_whitespace,
1205 block: self.current_line.max_block_size.resolve(),
1206 });
1207 self.current_line
1208 .replace_placement_among_floats(new_placement);
1209 }
1210
1211 fn place_line_among_floats(&self, potential_line_size: &LogicalVec2<Au>) -> LogicalRect<Au> {
1216 let sequential_layout_state = self
1217 .sequential_layout_state
1218 .as_ref()
1219 .expect("Should not have called this function without having floats.");
1220
1221 let ifc_offset_in_float_container = LogicalVec2 {
1222 inline: sequential_layout_state
1223 .floats
1224 .containing_block_info
1225 .inline_start,
1226 block: sequential_layout_state.current_containing_block_offset(),
1227 };
1228
1229 let ceiling = self
1230 .current_line
1231 .line_block_start_considering_placement_among_floats();
1232 let mut placement = PlacementAmongFloats::new(
1233 &sequential_layout_state.floats,
1234 ceiling + ifc_offset_in_float_container.block,
1235 LogicalVec2 {
1236 inline: potential_line_size.inline,
1237 block: potential_line_size.block,
1238 },
1239 &PaddingBorderMargin::zero(),
1240 );
1241
1242 let mut placement_rect = placement.place();
1243 placement_rect.start_corner -= ifc_offset_in_float_container;
1244 placement_rect
1245 }
1246
1247 fn new_potential_line_size_causes_line_break(
1254 &mut self,
1255 potential_line_size: &LogicalVec2<Au>,
1256 ) -> bool {
1257 let available_line_space = if self.sequential_layout_state.is_some() {
1258 self.current_line
1259 .placement_among_floats
1260 .get_or_init(|| self.place_line_among_floats(potential_line_size))
1261 .size
1262 } else {
1263 LogicalVec2 {
1264 inline: self.containing_block.size.inline,
1265 block: MAX_AU,
1266 }
1267 };
1268
1269 let inline_would_overflow = potential_line_size.inline > available_line_space.inline;
1270 let block_would_overflow = potential_line_size.block > available_line_space.block;
1271
1272 let can_break = self.current_line.has_content;
1275
1276 if !can_break {
1282 if self.sequential_layout_state.is_some() &&
1285 (inline_would_overflow || block_would_overflow)
1286 {
1287 let new_placement = self.place_line_among_floats(potential_line_size);
1288 self.current_line
1289 .replace_placement_among_floats(new_placement);
1290 }
1291
1292 return false;
1293 }
1294
1295 if potential_line_size.inline > self.containing_block.size.inline {
1298 return true;
1299 }
1300
1301 if block_would_overflow {
1305 assert!(self.sequential_layout_state.is_some());
1307 let new_placement = self.place_line_among_floats(potential_line_size);
1308 if new_placement.start_corner.block !=
1309 self.current_line
1310 .line_block_start_considering_placement_among_floats()
1311 {
1312 return true;
1313 } else {
1314 self.current_line
1315 .replace_placement_among_floats(new_placement);
1316 return false;
1317 }
1318 }
1319
1320 inline_would_overflow
1324 }
1325
1326 pub(super) fn defer_forced_line_break(&mut self) {
1327 if !self.unbreakable_segment_fits_on_line() {
1330 self.process_line_break(false );
1331 }
1332
1333 self.linebreak_before_new_content = true;
1335
1336 let line_is_empty =
1344 !self.current_line_segment.has_content && !self.current_line.has_content;
1345 if !self.processing_br_element() || line_is_empty {
1346 let strut_size = self
1347 .current_inline_container_state()
1348 .strut_block_sizes
1349 .clone();
1350 self.update_unbreakable_segment_for_new_content(
1351 &strut_size,
1352 Au::zero(),
1353 SegmentContentFlags::empty(),
1354 );
1355 }
1356 }
1357
1358 pub(super) fn possibly_flush_deferred_forced_line_break(&mut self) {
1359 if !self.linebreak_before_new_content {
1360 return;
1361 }
1362
1363 self.commit_current_segment_to_line();
1364 self.process_line_break(true );
1365 self.linebreak_before_new_content = false;
1366 }
1367
1368 fn push_line_item_to_unbreakable_segment(&mut self, line_item: LineItem) {
1369 self.current_line_segment
1370 .push_line_item(line_item, self.inline_box_state_stack.len());
1371 }
1372
1373 pub(super) fn push_glyph_store_to_unbreakable_segment(
1374 &mut self,
1375 glyph_store: std::sync::Arc<GlyphStore>,
1376 text_run: &TextRun,
1377 font_index: usize,
1378 bidi_level: Level,
1379 range: range::Range<ByteIndex>,
1380 ) {
1381 let inline_advance = glyph_store.total_advance();
1382 let flags = if glyph_store.is_whitespace() {
1383 SegmentContentFlags::from(text_run.inline_styles.style.borrow().get_inherited_text())
1384 } else {
1385 SegmentContentFlags::empty()
1386 };
1387
1388 let ifc_font_info = &self.ifc.font_metrics[font_index];
1392 let font_metrics = ifc_font_info.metrics.clone();
1393 let using_fallback_font =
1394 self.current_inline_container_state().font_metrics != font_metrics;
1395
1396 let quirks_mode = self.layout_context.style_context.quirks_mode() != QuirksMode::NoQuirks;
1397 let strut_size = if using_fallback_font {
1398 let container_state = self.current_inline_container_state();
1400 let vertical_align = effective_vertical_align(
1401 &container_state.style,
1402 self.inline_box_state_stack.last().map(|c| &c.base),
1403 );
1404 let mut block_size = container_state.get_block_size_contribution(
1405 vertical_align,
1406 &font_metrics,
1407 &container_state.font_metrics,
1408 );
1409 block_size.adjust_for_baseline_offset(container_state.baseline_offset);
1410 block_size
1411 } else if quirks_mode && !flags.is_collapsible_whitespace() {
1412 self.current_inline_container_state()
1417 .strut_block_sizes
1418 .clone()
1419 } else {
1420 LineBlockSizes::zero()
1421 };
1422 self.update_unbreakable_segment_for_new_content(&strut_size, inline_advance, flags);
1423
1424 let current_inline_box_identifier = self.current_inline_box_identifier();
1425 match self.current_line_segment.line_items.last_mut() {
1426 Some(LineItem::TextRun(inline_box_identifier, line_item))
1427 if *inline_box_identifier == current_inline_box_identifier &&
1428 line_item.can_merge(ifc_font_info.key, bidi_level) =>
1429 {
1430 line_item.text.push(glyph_store);
1431 return;
1432 },
1433 _ => {},
1434 }
1435
1436 let selection_range = if let Some(selection) = &text_run.selection_range {
1437 let intersection = selection.intersect(&range);
1438 if intersection.is_empty() {
1439 let insertion_point_index = selection.begin();
1440 if insertion_point_index >= range.begin() &&
1443 insertion_point_index <= range.end() &&
1444 (range.begin() != insertion_point_index || range.begin().0 == 0)
1445 {
1446 Some(Range::new(
1447 insertion_point_index - range.begin(),
1448 ByteIndex(0),
1449 ))
1450 } else {
1451 None
1452 }
1453 } else {
1454 Some(Range::new(
1455 intersection.begin() - range.begin(),
1456 intersection.length(),
1457 ))
1458 }
1459 } else {
1460 None
1461 };
1462
1463 self.push_line_item_to_unbreakable_segment(LineItem::TextRun(
1464 current_inline_box_identifier,
1465 TextRunLineItem {
1466 text: vec![glyph_store],
1467 base_fragment_info: text_run.base_fragment_info,
1468 inline_styles: text_run.inline_styles.clone(),
1469 font_metrics,
1470 font_key: ifc_font_info.key,
1471 bidi_level,
1472 selection_range,
1473 },
1474 ));
1475 }
1476
1477 fn update_unbreakable_segment_for_new_content(
1478 &mut self,
1479 block_sizes_of_content: &LineBlockSizes,
1480 inline_size: Au,
1481 flags: SegmentContentFlags,
1482 ) {
1483 if flags.is_collapsible_whitespace() || flags.is_wrappable_and_hangable() {
1484 self.current_line_segment.trailing_whitespace_size = inline_size;
1485 } else {
1486 self.current_line_segment.trailing_whitespace_size = Au::zero();
1487 }
1488 if !flags.is_collapsible_whitespace() {
1489 self.current_line_segment.has_content = true;
1490 }
1491
1492 let container_max_block_size = &self
1494 .current_inline_container_state()
1495 .nested_strut_block_sizes
1496 .clone();
1497 self.current_line_segment
1498 .max_block_size
1499 .max_assign(container_max_block_size);
1500 self.current_line_segment
1501 .max_block_size
1502 .max_assign(block_sizes_of_content);
1503
1504 self.current_line_segment.inline_size += inline_size;
1505
1506 *self
1508 .current_inline_container_state()
1509 .has_content
1510 .borrow_mut() = true;
1511 self.propagate_current_nesting_level_white_space_style();
1512 }
1513
1514 fn process_line_break(&mut self, forced_line_break: bool) {
1515 self.current_line_segment.trim_leading_whitespace();
1516 self.finish_current_line_and_reset(forced_line_break);
1517 }
1518
1519 pub(super) fn unbreakable_segment_fits_on_line(&mut self) -> bool {
1520 let potential_line_size = LogicalVec2 {
1521 inline: self.current_line.inline_position + self.current_line_segment.inline_size -
1522 self.current_line_segment.trailing_whitespace_size,
1523 block: self
1524 .current_line_max_block_size_including_nested_containers()
1525 .max(&self.current_line_segment.max_block_size)
1526 .resolve(),
1527 };
1528
1529 !self.new_potential_line_size_causes_line_break(&potential_line_size)
1530 }
1531
1532 pub(super) fn process_soft_wrap_opportunity(&mut self) {
1536 if self.current_line_segment.line_items.is_empty() {
1537 return;
1538 }
1539 if self.text_wrap_mode == TextWrapMode::Nowrap {
1540 return;
1541 }
1542
1543 let potential_line_size = LogicalVec2 {
1544 inline: self.current_line.inline_position + self.current_line_segment.inline_size -
1545 self.current_line_segment.trailing_whitespace_size,
1546 block: self
1547 .current_line_max_block_size_including_nested_containers()
1548 .max(&self.current_line_segment.max_block_size)
1549 .resolve(),
1550 };
1551
1552 if self.new_potential_line_size_causes_line_break(&potential_line_size) {
1553 self.process_line_break(false );
1554 }
1555 self.commit_current_segment_to_line();
1556 }
1557
1558 fn commit_current_segment_to_line(&mut self) {
1561 if self.current_line_segment.line_items.is_empty() && !self.current_line_segment.has_content
1564 {
1565 return;
1566 }
1567
1568 if !self.current_line.has_content {
1569 self.current_line_segment.trim_leading_whitespace();
1570 }
1571
1572 self.current_line.inline_position += self.current_line_segment.inline_size;
1573 self.current_line.max_block_size = self
1574 .current_line_max_block_size_including_nested_containers()
1575 .max(&self.current_line_segment.max_block_size);
1576 let line_inline_size_without_trailing_whitespace =
1577 self.current_line.inline_position - self.current_line_segment.trailing_whitespace_size;
1578
1579 let mut segment_items = mem::take(&mut self.current_line_segment.line_items);
1581 for item in segment_items.iter_mut() {
1582 if let LineItem::Float(_, float_item) = item {
1583 self.place_float_line_item_for_commit_to_line(
1584 float_item,
1585 line_inline_size_without_trailing_whitespace,
1586 );
1587 }
1588 }
1589
1590 if self.current_line.line_items.is_empty() {
1595 let will_break = self.new_potential_line_size_causes_line_break(&LogicalVec2 {
1596 inline: line_inline_size_without_trailing_whitespace,
1597 block: self.current_line_segment.max_block_size.resolve(),
1598 });
1599 assert!(!will_break);
1600 }
1601
1602 self.current_line.line_items.extend(segment_items);
1603 self.current_line.has_content |= self.current_line_segment.has_content;
1604 self.current_line.has_inline_pbm |= self.current_line_segment.has_inline_pbm;
1605
1606 self.current_line_segment.reset();
1607 }
1608}
1609
1610bitflags! {
1611 pub struct SegmentContentFlags: u8 {
1612 const COLLAPSIBLE_WHITESPACE = 0b00000001;
1613 const WRAPPABLE_AND_HANGABLE_WHITESPACE = 0b00000010;
1614 }
1615}
1616
1617impl SegmentContentFlags {
1618 fn is_collapsible_whitespace(&self) -> bool {
1619 self.contains(Self::COLLAPSIBLE_WHITESPACE)
1620 }
1621
1622 fn is_wrappable_and_hangable(&self) -> bool {
1623 self.contains(Self::WRAPPABLE_AND_HANGABLE_WHITESPACE)
1624 }
1625}
1626
1627impl From<&InheritedText> for SegmentContentFlags {
1628 fn from(style_text: &InheritedText) -> Self {
1629 let mut flags = Self::empty();
1630
1631 if !matches!(
1634 style_text.white_space_collapse,
1635 WhiteSpaceCollapse::Preserve | WhiteSpaceCollapse::BreakSpaces
1636 ) {
1637 flags.insert(Self::COLLAPSIBLE_WHITESPACE);
1638 }
1639
1640 if style_text.text_wrap_mode == TextWrapMode::Wrap &&
1643 style_text.white_space_collapse != WhiteSpaceCollapse::BreakSpaces
1644 {
1645 flags.insert(Self::WRAPPABLE_AND_HANGABLE_WHITESPACE);
1646 }
1647 flags
1648 }
1649}
1650
1651impl InlineFormattingContext {
1652 #[servo_tracing::instrument(name = "InlineFormattingContext::new_with_builder", skip_all)]
1653 pub(super) fn new_with_builder(
1654 builder: InlineFormattingContextBuilder,
1655 layout_context: &LayoutContext,
1656 has_first_formatted_line: bool,
1657 is_single_line_text_input: bool,
1658 starting_bidi_level: Level,
1659 rendering_group_id: RenderingGroupId,
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 rendering_group_id,
1679 );
1680 },
1681 InlineItem::StartInlineBox(inline_box) => {
1682 let inline_box = &mut *inline_box.borrow_mut();
1683 if let Some(font) = get_font_for_first_font_for_style(
1684 &inline_box.base.style,
1685 &layout_context.font_context,
1686 ) {
1687 inline_box.default_font_index = Some(add_or_get_font(
1688 &font,
1689 &mut font_metrics,
1690 &layout_context.font_context,
1691 rendering_group_id,
1692 ));
1693 }
1694 },
1695 InlineItem::Atomic(_, index_in_text, bidi_level) => {
1696 *bidi_level = bidi_info.levels[*index_in_text];
1697 },
1698 InlineItem::OutOfFlowAbsolutelyPositionedBox(..) |
1699 InlineItem::OutOfFlowFloatBox(_) |
1700 InlineItem::EndInlineBox => {},
1701 }
1702 }
1703
1704 InlineFormattingContext {
1705 text_content,
1706 inline_items: builder.inline_items,
1707 inline_boxes: builder.inline_boxes,
1708 font_metrics,
1709 shared_inline_styles: builder
1710 .shared_inline_styles_stack
1711 .last()
1712 .expect("Should have at least one SharedInlineStyle for the root of an IFC")
1713 .clone(),
1714 has_first_formatted_line,
1715 contains_floats: builder.contains_floats,
1716 is_single_line_text_input,
1717 has_right_to_left_content,
1718 }
1719 }
1720
1721 pub(crate) fn repair_style(
1722 &self,
1723 node: &ServoThreadSafeLayoutNode,
1724 new_style: &Arc<ComputedValues>,
1725 ) {
1726 *self.shared_inline_styles.style.borrow_mut() = new_style.clone();
1727 *self.shared_inline_styles.selected.borrow_mut() = node.selected_style();
1728 }
1729
1730 pub(crate) fn inline_start_for_first_line(
1731 &self,
1732 containing_block: IndefiniteContainingBlock,
1733 ) -> Au {
1734 if !self.has_first_formatted_line {
1735 return Au::zero();
1736 }
1737 containing_block
1738 .style
1739 .get_inherited_text()
1740 .text_indent
1741 .length
1742 .to_used_value(containing_block.size.inline.unwrap_or_default())
1743 }
1744
1745 pub(super) fn layout(
1746 &self,
1747 layout_context: &LayoutContext,
1748 positioning_context: &mut PositioningContext,
1749 containing_block: &ContainingBlock,
1750 sequential_layout_state: Option<&mut SequentialLayoutState>,
1751 collapsible_with_parent_start_margin: CollapsibleWithParentStartMargin,
1752 ) -> CacheableLayoutResult {
1753 for inline_box in self.inline_boxes.iter() {
1755 inline_box.borrow().base.clear_fragments();
1756 }
1757
1758 let style = containing_block.style;
1759
1760 let default_font_metrics =
1763 get_font_for_first_font_for_style(style, &layout_context.font_context)
1764 .map(|font| font.metrics.clone());
1765
1766 let style_text = containing_block.style.get_inherited_text();
1767 let mut inline_container_state_flags = InlineContainerStateFlags::empty();
1768 if inline_container_needs_strut(style, layout_context, None) {
1769 inline_container_state_flags.insert(InlineContainerStateFlags::CREATE_STRUT);
1770 }
1771 if self.is_single_line_text_input {
1772 inline_container_state_flags
1773 .insert(InlineContainerStateFlags::IS_SINGLE_LINE_TEXT_INPUT);
1774 }
1775
1776 let mut layout = InlineFormattingContextLayout {
1777 positioning_context,
1778 containing_block,
1779 sequential_layout_state,
1780 layout_context,
1781 ifc: self,
1782 fragments: Vec::new(),
1783 current_line: LineUnderConstruction::new(LogicalVec2 {
1784 inline: self.inline_start_for_first_line(containing_block.into()),
1785 block: Au::zero(),
1786 }),
1787 root_nesting_level: InlineContainerState::new(
1788 style.to_arc(),
1789 inline_container_state_flags,
1790 None, default_font_metrics.as_ref(),
1792 ),
1793 inline_box_state_stack: Vec::new(),
1794 inline_box_states: Vec::with_capacity(self.inline_boxes.len()),
1795 current_line_segment: UnbreakableSegmentUnderConstruction::new(),
1796 linebreak_before_new_content: false,
1797 deferred_br_clear: Clear::None,
1798 have_deferred_soft_wrap_opportunity: false,
1799 has_line_boxes: false,
1800 depends_on_block_constraints: false,
1801 white_space_collapse: style_text.white_space_collapse,
1802 text_wrap_mode: style_text.text_wrap_mode,
1803 baselines: Baselines::default(),
1804 };
1805
1806 if let Some(ref mut sequential_layout_state) = layout.sequential_layout_state {
1810 sequential_layout_state.collapse_margins();
1811 }
1813
1814 for item in self.inline_items.iter() {
1815 let item = &*item.borrow();
1816
1817 if !matches!(item, InlineItem::EndInlineBox) {
1819 layout.possibly_flush_deferred_forced_line_break();
1820 }
1821
1822 match item {
1823 InlineItem::StartInlineBox(inline_box) => {
1824 layout.start_inline_box(&inline_box.borrow());
1825 },
1826 InlineItem::EndInlineBox => layout.finish_inline_box(),
1827 InlineItem::TextRun(run) => run.borrow().layout_into_line_items(&mut layout),
1828 InlineItem::Atomic(atomic_formatting_context, offset_in_text, bidi_level) => {
1829 atomic_formatting_context.borrow().layout_into_line_items(
1830 &mut layout,
1831 *offset_in_text,
1832 *bidi_level,
1833 );
1834 },
1835 InlineItem::OutOfFlowAbsolutelyPositionedBox(positioned_box, _) => {
1836 layout.push_line_item_to_unbreakable_segment(LineItem::AbsolutelyPositioned(
1837 layout.current_inline_box_identifier(),
1838 AbsolutelyPositionedLineItem {
1839 absolutely_positioned_box: positioned_box.clone(),
1840 },
1841 ));
1842 },
1843 InlineItem::OutOfFlowFloatBox(float_box) => {
1844 float_box.borrow().layout_into_line_items(&mut layout);
1845 },
1846 }
1847 }
1848
1849 layout.finish_last_line();
1850
1851 let mut collapsible_margins_in_children = CollapsedBlockMargins::zero();
1852 let content_block_size = layout.current_line.start_position.block;
1853 collapsible_margins_in_children.collapsed_through = !layout.has_line_boxes &&
1854 content_block_size.is_zero() &&
1855 collapsible_with_parent_start_margin.0;
1856
1857 CacheableLayoutResult {
1858 fragments: layout.fragments,
1859 content_block_size,
1860 collapsible_margins_in_children,
1861 baselines: layout.baselines,
1862 depends_on_block_constraints: layout.depends_on_block_constraints,
1863 content_inline_size_for_table: None,
1864 specific_layout_info: None,
1865 }
1866 }
1867
1868 fn next_character_prevents_soft_wrap_opportunity(&self, index: usize) -> bool {
1869 let Some(character) = self.text_content[index..].chars().nth(1) else {
1870 return false;
1871 };
1872 char_prevents_soft_wrap_opportunity_when_before_or_after_atomic(character)
1873 }
1874
1875 fn previous_character_prevents_soft_wrap_opportunity(&self, index: usize) -> bool {
1876 let Some(character) = self.text_content[0..index].chars().next_back() else {
1877 return false;
1878 };
1879 char_prevents_soft_wrap_opportunity_when_before_or_after_atomic(character)
1880 }
1881}
1882
1883impl InlineContainerState {
1884 fn new(
1885 style: Arc<ComputedValues>,
1886 flags: InlineContainerStateFlags,
1887 parent_container: Option<&InlineContainerState>,
1888 font_metrics: Option<&FontMetrics>,
1889 ) -> Self {
1890 let font_metrics = font_metrics.cloned().unwrap_or_else(FontMetrics::empty);
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 &flags,
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 flags: &InlineContainerStateFlags,
1933 ) -> LineBlockSizes {
1934 let line_height = line_height(style, font_metrics, flags);
1935
1936 if !is_baseline_relative(vertical_align) {
1937 return LineBlockSizes {
1938 line_height,
1939 baseline_relative_size_for_line_height: None,
1940 size_for_baseline_positioning: BaselineRelativeSize::zero(),
1941 };
1942 }
1943
1944 let mut ascent = font_metrics.ascent;
1953 let mut descent = font_metrics.descent;
1954 if style.get_font().line_height == LineHeight::Normal {
1955 let half_leading_from_line_gap =
1956 (font_metrics.line_gap - descent - ascent).scale_by(0.5);
1957 ascent += half_leading_from_line_gap;
1958 descent += half_leading_from_line_gap;
1959 }
1960
1961 let size_for_baseline_positioning = BaselineRelativeSize { ascent, descent };
1965
1966 if style.get_font().line_height != LineHeight::Normal {
1982 ascent = font_metrics_of_first_font.ascent;
1983 descent = font_metrics_of_first_font.descent;
1984 let half_leading = (line_height - (ascent + descent)).scale_by(0.5);
1985 ascent += half_leading;
1990 descent = line_height - ascent;
1991 }
1992
1993 LineBlockSizes {
1994 line_height,
1995 baseline_relative_size_for_line_height: Some(BaselineRelativeSize { ascent, descent }),
1996 size_for_baseline_positioning,
1997 }
1998 }
1999
2000 fn get_block_size_contribution(
2001 &self,
2002 vertical_align: VerticalAlign,
2003 font_metrics: &FontMetrics,
2004 font_metrics_of_first_font: &FontMetrics,
2005 ) -> LineBlockSizes {
2006 Self::get_block_sizes_with_style(
2007 vertical_align,
2008 &self.style,
2009 font_metrics,
2010 font_metrics_of_first_font,
2011 &self.flags,
2012 )
2013 }
2014
2015 fn get_cumulative_baseline_offset_for_child(
2016 &self,
2017 child_vertical_align: VerticalAlign,
2018 child_block_size: &LineBlockSizes,
2019 ) -> Au {
2020 let block_size = self.get_block_size_contribution(
2021 child_vertical_align.clone(),
2022 &self.font_metrics,
2023 &self.font_metrics,
2024 );
2025 self.baseline_offset +
2026 match child_vertical_align {
2027 VerticalAlign::Keyword(VerticalAlignKeyword::Baseline) |
2032 VerticalAlign::Keyword(VerticalAlignKeyword::Top) |
2033 VerticalAlign::Keyword(VerticalAlignKeyword::Bottom) => Au::zero(),
2034 VerticalAlign::Keyword(VerticalAlignKeyword::Sub) => {
2035 block_size.resolve().scale_by(FONT_SUBSCRIPT_OFFSET_RATIO)
2036 },
2037 VerticalAlign::Keyword(VerticalAlignKeyword::Super) => {
2038 -block_size.resolve().scale_by(FONT_SUPERSCRIPT_OFFSET_RATIO)
2039 },
2040 VerticalAlign::Keyword(VerticalAlignKeyword::TextTop) => {
2041 child_block_size.size_for_baseline_positioning.ascent - self.font_metrics.ascent
2042 },
2043 VerticalAlign::Keyword(VerticalAlignKeyword::Middle) => {
2044 (child_block_size.size_for_baseline_positioning.ascent -
2047 child_block_size.size_for_baseline_positioning.descent -
2048 self.font_metrics.x_height)
2049 .scale_by(0.5)
2050 },
2051 VerticalAlign::Keyword(VerticalAlignKeyword::TextBottom) => {
2052 self.font_metrics.descent -
2053 child_block_size.size_for_baseline_positioning.descent
2054 },
2055 VerticalAlign::Length(length_percentage) => {
2056 -length_percentage.to_used_value(child_block_size.line_height)
2057 },
2058 }
2059 }
2060}
2061
2062impl IndependentFormattingContext {
2063 fn layout_into_line_items(
2064 &self,
2065 layout: &mut InlineFormattingContextLayout,
2066 offset_in_text: usize,
2067 bidi_level: Level,
2068 ) {
2069 let mut child_positioning_context = PositioningContext::default();
2071 let IndependentFloatOrAtomicLayoutResult {
2072 mut fragment,
2073 baselines,
2074 pbm_sums,
2075 } = self.layout_float_or_atomic_inline(
2076 layout.layout_context,
2077 &mut child_positioning_context,
2078 layout.containing_block,
2079 );
2080
2081 layout.depends_on_block_constraints |= fragment.base.flags.contains(
2084 FragmentFlags::SIZE_DEPENDS_ON_BLOCK_CONSTRAINTS_AND_CAN_BE_CHILD_OF_FLEX_ITEM,
2085 );
2086
2087 let container_writing_mode = layout.containing_block.style.writing_mode;
2089 let pbm_physical_offset = pbm_sums
2090 .start_offset()
2091 .to_physical_size(container_writing_mode);
2092 fragment.content_rect = fragment
2093 .content_rect
2094 .translate(pbm_physical_offset.to_vector());
2095
2096 fragment = fragment.with_baselines(baselines);
2098
2099 let positioning_context = if self.is_replaced() {
2102 None
2103 } else {
2104 if fragment
2105 .style
2106 .establishes_containing_block_for_absolute_descendants(fragment.base.flags)
2107 {
2108 child_positioning_context
2109 .layout_collected_children(layout.layout_context, &mut fragment);
2110 }
2111 Some(child_positioning_context)
2112 };
2113
2114 if layout.text_wrap_mode == TextWrapMode::Wrap &&
2115 !layout
2116 .ifc
2117 .previous_character_prevents_soft_wrap_opportunity(offset_in_text)
2118 {
2119 layout.process_soft_wrap_opportunity();
2120 }
2121
2122 let size = pbm_sums.sum() +
2123 fragment
2124 .content_rect
2125 .size
2126 .to_logical(container_writing_mode);
2127 let baseline_offset = self
2128 .pick_baseline(&fragment.baselines(container_writing_mode))
2129 .map(|baseline| pbm_sums.block_start + baseline)
2130 .unwrap_or(size.block);
2131
2132 let (block_sizes, baseline_offset_in_parent) =
2133 self.get_block_sizes_and_baseline_offset(layout, size.block, baseline_offset);
2134 layout.update_unbreakable_segment_for_new_content(
2135 &block_sizes,
2136 size.inline,
2137 SegmentContentFlags::empty(),
2138 );
2139
2140 let fragment = ArcRefCell::new(fragment);
2141 self.base.set_fragment(Fragment::Box(fragment.clone()));
2142
2143 layout.push_line_item_to_unbreakable_segment(LineItem::Atomic(
2144 layout.current_inline_box_identifier(),
2145 AtomicLineItem {
2146 fragment,
2147 size,
2148 positioning_context,
2149 baseline_offset_in_parent,
2150 baseline_offset_in_item: baseline_offset,
2151 bidi_level,
2152 },
2153 ));
2154
2155 if !layout
2158 .ifc
2159 .next_character_prevents_soft_wrap_opportunity(offset_in_text)
2160 {
2161 layout.have_deferred_soft_wrap_opportunity = true;
2162 }
2163 }
2164
2165 fn pick_baseline(&self, baselines: &Baselines) -> Option<Au> {
2169 match self.style().clone_baseline_source() {
2170 BaselineSource::First => baselines.first,
2171 BaselineSource::Last => baselines.last,
2172 BaselineSource::Auto if self.is_block_container() => baselines.last,
2173 BaselineSource::Auto => baselines.first,
2174 }
2175 }
2176
2177 fn get_block_sizes_and_baseline_offset(
2178 &self,
2179 ifc: &InlineFormattingContextLayout,
2180 block_size: Au,
2181 baseline_offset_in_content_area: Au,
2182 ) -> (LineBlockSizes, Au) {
2183 let mut contribution = if !is_baseline_relative(self.style().clone_vertical_align()) {
2184 LineBlockSizes {
2185 line_height: block_size,
2186 baseline_relative_size_for_line_height: None,
2187 size_for_baseline_positioning: BaselineRelativeSize::zero(),
2188 }
2189 } else {
2190 let baseline_relative_size = BaselineRelativeSize {
2191 ascent: baseline_offset_in_content_area,
2192 descent: block_size - baseline_offset_in_content_area,
2193 };
2194 LineBlockSizes {
2195 line_height: block_size,
2196 baseline_relative_size_for_line_height: Some(baseline_relative_size.clone()),
2197 size_for_baseline_positioning: baseline_relative_size,
2198 }
2199 };
2200
2201 let baseline_offset = ifc
2202 .current_inline_container_state()
2203 .get_cumulative_baseline_offset_for_child(
2204 self.style().clone_vertical_align(),
2205 &contribution,
2206 );
2207 contribution.adjust_for_baseline_offset(baseline_offset);
2208
2209 (contribution, baseline_offset)
2210 }
2211}
2212
2213impl FloatBox {
2214 fn layout_into_line_items(&self, layout: &mut InlineFormattingContextLayout) {
2215 let fragment = ArcRefCell::new(self.layout(
2216 layout.layout_context,
2217 layout.positioning_context,
2218 layout.containing_block,
2219 ));
2220
2221 self.contents
2222 .base
2223 .set_fragment(Fragment::Box(fragment.clone()));
2224 layout.push_line_item_to_unbreakable_segment(LineItem::Float(
2225 layout.current_inline_box_identifier(),
2226 FloatLineItem {
2227 fragment,
2228 needs_placement: true,
2229 },
2230 ));
2231 }
2232}
2233
2234fn place_pending_floats(ifc: &mut InlineFormattingContextLayout, line_items: &mut [LineItem]) {
2235 for item in line_items.iter_mut() {
2236 if let LineItem::Float(_, float_line_item) = item {
2237 if float_line_item.needs_placement {
2238 ifc.place_float_fragment(&mut float_line_item.fragment.borrow_mut());
2239 }
2240 }
2241 }
2242}
2243
2244fn line_height(
2245 parent_style: &ComputedValues,
2246 font_metrics: &FontMetrics,
2247 flags: &InlineContainerStateFlags,
2248) -> Au {
2249 let font = parent_style.get_font();
2250 let font_size = font.font_size.computed_size();
2251 let mut line_height = match font.line_height {
2252 LineHeight::Normal => font_metrics.line_gap,
2253 LineHeight::Number(number) => (font_size * number.0).into(),
2254 LineHeight::Length(length) => length.0.into(),
2255 };
2256
2257 if flags.contains(InlineContainerStateFlags::IS_SINGLE_LINE_TEXT_INPUT) {
2261 line_height.max_assign(font_metrics.line_gap);
2262 }
2263
2264 line_height
2265}
2266
2267fn effective_vertical_align(
2268 style: &ComputedValues,
2269 container: Option<&InlineContainerState>,
2270) -> VerticalAlign {
2271 if container.is_none() {
2272 VerticalAlign::Keyword(VerticalAlignKeyword::Baseline)
2276 } else {
2277 style.clone_vertical_align()
2278 }
2279}
2280
2281fn is_baseline_relative(vertical_align: VerticalAlign) -> bool {
2282 !matches!(
2283 vertical_align,
2284 VerticalAlign::Keyword(VerticalAlignKeyword::Top) |
2285 VerticalAlign::Keyword(VerticalAlignKeyword::Bottom)
2286 )
2287}
2288
2289fn inline_container_needs_strut(
2315 style: &ComputedValues,
2316 layout_context: &LayoutContext,
2317 pbm: Option<&PaddingBorderMargin>,
2318) -> bool {
2319 if layout_context.style_context.quirks_mode() == QuirksMode::NoQuirks {
2320 return true;
2321 }
2322
2323 if style.get_box().display.is_list_item() {
2326 return true;
2327 }
2328
2329 pbm.map(|pbm| !pbm.padding_border_sums.inline.is_zero())
2330 .unwrap_or(false)
2331}
2332
2333impl ComputeInlineContentSizes for InlineFormattingContext {
2334 fn compute_inline_content_sizes(
2338 &self,
2339 layout_context: &LayoutContext,
2340 constraint_space: &ConstraintSpace,
2341 ) -> InlineContentSizesResult {
2342 ContentSizesComputation::compute(self, layout_context, constraint_space)
2343 }
2344}
2345
2346struct ContentSizesComputation<'layout_data> {
2348 layout_context: &'layout_data LayoutContext<'layout_data>,
2349 constraint_space: &'layout_data ConstraintSpace<'layout_data>,
2350 paragraph: ContentSizes,
2351 current_line: ContentSizes,
2352 pending_whitespace: ContentSizes,
2354 had_content_yet_for_min_content: bool,
2357 had_content_yet_for_max_content: bool,
2360 ending_inline_pbm_stack: Vec<Au>,
2363 depends_on_block_constraints: bool,
2364}
2365
2366impl<'layout_data> ContentSizesComputation<'layout_data> {
2367 fn traverse(
2368 mut self,
2369 inline_formatting_context: &InlineFormattingContext,
2370 ) -> InlineContentSizesResult {
2371 self.add_inline_size(
2372 inline_formatting_context.inline_start_for_first_line(self.constraint_space.into()),
2373 );
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.style.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 let break_at_start =
2434 segment.break_at_start && self.had_content_yet_for_min_content;
2435
2436 for (run_index, run) in segment.runs.iter().enumerate() {
2437 if can_wrap && (run_index != 0 || break_at_start) {
2440 self.line_break_opportunity();
2441 }
2442
2443 let advance = run.glyph_store.total_advance();
2444 if run.glyph_store.is_whitespace() {
2445 if run.is_single_preserved_newline() {
2448 self.forced_line_break();
2449 continue;
2450 }
2451 if !matches!(
2452 style_text.white_space_collapse,
2453 WhiteSpaceCollapse::Preserve | WhiteSpaceCollapse::BreakSpaces
2454 ) {
2455 if self.had_content_yet_for_min_content {
2456 if can_wrap {
2457 self.line_break_opportunity();
2458 } else {
2459 self.pending_whitespace.min_content += advance;
2460 }
2461 }
2462 if self.had_content_yet_for_max_content {
2463 self.pending_whitespace.max_content += advance;
2464 }
2465 continue;
2466 }
2467 if can_wrap {
2468 self.pending_whitespace.max_content += advance;
2469 self.commit_pending_whitespace();
2470 self.line_break_opportunity();
2471 continue;
2472 }
2473 }
2474
2475 self.commit_pending_whitespace();
2476 self.add_inline_size(advance);
2477
2478 if can_wrap && run.glyph_store.ends_with_whitespace() {
2483 self.line_break_opportunity();
2484 }
2485 }
2486 }
2487 },
2488 InlineItem::Atomic(atomic, offset_in_text, _level) => {
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 self.had_content_yet_for_min_content &&
2502 !inline_formatting_context
2503 .previous_character_prevents_soft_wrap_opportunity(*offset_in_text)
2504 {
2505 self.line_break_opportunity();
2506 }
2507
2508 self.commit_pending_whitespace();
2509 self.current_line += outer;
2510
2511 if !inline_formatting_context
2513 .next_character_prevents_soft_wrap_opportunity(*offset_in_text)
2514 {
2515 self.line_break_opportunity();
2516 }
2517 },
2518 _ => {},
2519 }
2520 }
2521
2522 fn add_inline_size(&mut self, l: Au) {
2523 self.current_line.min_content += l;
2524 self.current_line.max_content += l;
2525 }
2526
2527 fn line_break_opportunity(&mut self) {
2528 self.pending_whitespace.min_content = Au::zero();
2532 let current_min_content = mem::take(&mut self.current_line.min_content);
2533 self.paragraph.min_content.max_assign(current_min_content);
2534 self.had_content_yet_for_min_content = false;
2535 }
2536
2537 fn forced_line_break(&mut self) {
2538 self.line_break_opportunity();
2540
2541 self.pending_whitespace.max_content = Au::zero();
2543 let current_max_content = mem::take(&mut self.current_line.max_content);
2544 self.paragraph.max_content.max_assign(current_max_content);
2545 self.had_content_yet_for_max_content = false;
2546 }
2547
2548 fn commit_pending_whitespace(&mut self) {
2549 self.current_line += mem::take(&mut self.pending_whitespace);
2550 self.had_content_yet_for_min_content = true;
2551 self.had_content_yet_for_max_content = true;
2552 }
2553
2554 fn compute(
2556 inline_formatting_context: &InlineFormattingContext,
2557 layout_context: &'layout_data LayoutContext,
2558 constraint_space: &'layout_data ConstraintSpace,
2559 ) -> InlineContentSizesResult {
2560 Self {
2561 layout_context,
2562 constraint_space,
2563 paragraph: ContentSizes::zero(),
2564 current_line: ContentSizes::zero(),
2565 pending_whitespace: ContentSizes::zero(),
2566 had_content_yet_for_min_content: false,
2567 had_content_yet_for_max_content: false,
2568 ending_inline_pbm_stack: Vec::new(),
2569 depends_on_block_constraints: false,
2570 }
2571 .traverse(inline_formatting_context)
2572 }
2573}
2574
2575fn char_prevents_soft_wrap_opportunity_when_before_or_after_atomic(character: char) -> bool {
2587 if character == '\u{00A0}' {
2588 return false;
2589 }
2590 let class = linebreak_property(character);
2591 class == XI_LINE_BREAKING_CLASS_GL ||
2592 class == XI_LINE_BREAKING_CLASS_WJ ||
2593 class == XI_LINE_BREAKING_CLASS_ZWJ
2594}