1use std::vec::IntoIter;
6
7use app_units::Au;
8use fonts::FontRef;
9use layout_api::LayoutNode;
10use malloc_size_of_derive::MallocSizeOf;
11use script::layout_dom::ServoLayoutNode;
12use servo_arc::Arc as ServoArc;
13use style::Zero;
14use style::computed_values::alignment_baseline::T as AlignmentBaseline;
15use style::computed_values::baseline_source::T as BaselineSource;
16use style::computed_values::box_decoration_break::T as BoxDecorationBreak;
17use style::context::SharedStyleContext;
18use style::properties::ComputedValues;
19use style::values::computed::{BaselineShift, LengthPercentage};
20
21use super::{
22 InlineContainerState, InlineContainerStateFlags, SharedInlineStyles,
23 inline_container_needs_strut,
24};
25use crate::ContainingBlock;
26use crate::cell::ArcRefCell;
27use crate::context::LayoutContext;
28use crate::dom_traversal::NodeAndStyleInfo;
29use crate::fragment_tree::BaseFragmentInfo;
30use crate::layout_box_base::LayoutBoxBase;
31use crate::style_ext::{ComputedValuesExt, LayoutStyle, PaddingBorderMargin};
32
33#[derive(Debug, MallocSizeOf)]
34pub(crate) struct InlineBox {
35 pub base: LayoutBoxBase,
36 pub(super) shared_inline_styles: SharedInlineStyles,
39 pub(super) identifier: InlineBoxIdentifier,
41 pub default_font: Option<FontRef>,
44 pub breaks_shaping_at_start: bool,
46 pub breaks_shaping_at_end: bool,
48}
49
50impl InlineBox {
51 pub(crate) fn new(info: &NodeAndStyleInfo, context: &LayoutContext) -> Self {
52 let (breaks_shaping_at_start, breaks_shaping_at_end) =
53 inline_box_style_breaks_shaping(&info.style);
54 Self {
55 base: LayoutBoxBase::new(info.into(), info.style.clone()),
56 shared_inline_styles: SharedInlineStyles::from_info_and_context(info, context),
57 identifier: InlineBoxIdentifier::default(),
59 default_font: None,
60 breaks_shaping_at_start,
61 breaks_shaping_at_end,
62 }
63 }
64
65 #[inline]
66 pub(crate) fn layout_style(&self) -> LayoutStyle<'_> {
67 LayoutStyle::Default(&self.base.style)
68 }
69
70 pub(crate) fn repair_style(
71 &mut self,
72 context: &SharedStyleContext,
73 node: &ServoLayoutNode,
74 new_style: &ServoArc<ComputedValues>,
75 ) {
76 (self.breaks_shaping_at_start, self.breaks_shaping_at_end) =
77 inline_box_style_breaks_shaping(new_style);
78
79 self.base.repair_style(new_style);
80 *self.shared_inline_styles.style.borrow_mut() = new_style.clone();
81 *self.shared_inline_styles.selected.borrow_mut() = node.selected_style(context);
82 }
83}
84
85#[derive(Debug, Default, MallocSizeOf)]
86pub(crate) struct InlineBoxes {
87 inline_boxes: Vec<ArcRefCell<InlineBox>>,
89
90 inline_box_tree: Vec<InlineBoxTreePathToken>,
95}
96
97impl InlineBoxes {
98 pub(super) fn len(&self) -> usize {
99 self.inline_boxes.len()
100 }
101
102 pub(super) fn iter(&self) -> impl Iterator<Item = &ArcRefCell<InlineBox>> {
103 self.inline_boxes.iter()
104 }
105
106 pub(super) fn get(&self, identifier: &InlineBoxIdentifier) -> ArcRefCell<InlineBox> {
107 self.inline_boxes[identifier.index_in_inline_boxes as usize].clone()
108 }
109
110 pub(super) fn end_inline_box(&mut self, identifier: InlineBoxIdentifier) {
111 self.inline_box_tree
112 .push(InlineBoxTreePathToken::End(identifier));
113 }
114
115 pub(super) fn start_inline_box(
116 &mut self,
117 inline_box: ArcRefCell<InlineBox>,
118 ) -> InlineBoxIdentifier {
119 assert!(self.inline_boxes.len() <= u32::MAX as usize);
120 assert!(self.inline_box_tree.len() <= u32::MAX as usize);
121
122 let index_in_inline_boxes = self.inline_boxes.len() as u32;
123 let index_of_start_in_tree = self.inline_box_tree.len() as u32;
124
125 let identifier = InlineBoxIdentifier {
126 index_of_start_in_tree,
127 index_in_inline_boxes,
128 };
129 inline_box.borrow_mut().identifier = identifier;
130
131 self.inline_boxes.push(inline_box);
132 self.inline_box_tree
133 .push(InlineBoxTreePathToken::Start(identifier));
134
135 identifier
136 }
137
138 pub(super) fn get_path(
139 &self,
140 from: Option<InlineBoxIdentifier>,
141 to: InlineBoxIdentifier,
142 ) -> IntoIter<InlineBoxTreePathToken> {
143 if from == Some(to) {
144 return Vec::new().into_iter();
145 }
146
147 let mut from_index = match from {
148 Some(InlineBoxIdentifier {
149 index_of_start_in_tree,
150 ..
151 }) => index_of_start_in_tree as usize,
152 None => 0,
153 };
154 let mut to_index = to.index_of_start_in_tree as usize;
155 let is_reversed = to_index < from_index;
156
157 if to_index > from_index && from.is_some() {
161 from_index += 1;
162 } else if to_index < from_index {
163 to_index += 1;
164 }
165
166 let mut path = Vec::with_capacity(from_index.abs_diff(to_index));
167 let min = from_index.min(to_index);
168 let max = from_index.max(to_index);
169
170 for token in &self.inline_box_tree[min..=max] {
171 if Some(&token.reverse()) == path.last() {
173 path.pop();
174 } else {
175 path.push(*token);
176 }
177 }
178
179 if is_reversed {
180 path.reverse();
181 for token in path.iter_mut() {
182 *token = token.reverse();
183 }
184 }
185
186 path.into_iter()
187 }
188}
189
190#[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq)]
191pub(super) enum InlineBoxTreePathToken {
192 Start(InlineBoxIdentifier),
193 End(InlineBoxIdentifier),
194}
195
196impl InlineBoxTreePathToken {
197 fn reverse(&self) -> Self {
198 match self {
199 Self::Start(index) => Self::End(*index),
200 Self::End(index) => Self::Start(*index),
201 }
202 }
203}
204
205#[derive(Clone, Copy, Debug, Default, Eq, Hash, MallocSizeOf, PartialEq)]
212pub(crate) struct InlineBoxIdentifier {
213 pub index_of_start_in_tree: u32,
214 pub index_in_inline_boxes: u32,
215}
216
217pub(super) struct InlineBoxContainerState {
218 pub base: InlineContainerState,
221
222 pub identifier: InlineBoxIdentifier,
225
226 pub base_fragment_info: BaseFragmentInfo,
228
229 pub pbm: PaddingBorderMargin,
231}
232
233impl InlineBoxContainerState {
234 pub(super) fn new(
235 inline_box: &InlineBox,
236 containing_block: &ContainingBlock,
237 layout_context: &LayoutContext,
238 parent_container: &InlineContainerState,
239 default_font: Option<FontRef>,
240 ) -> Self {
241 let style = inline_box.base.style.clone();
242 let pbm = inline_box
243 .layout_style()
244 .padding_border_margin(containing_block);
245
246 let mut flags = InlineContainerStateFlags::empty();
247 if inline_container_needs_strut(&style, layout_context, Some(&pbm)) {
248 flags.insert(InlineContainerStateFlags::CREATE_STRUT);
249 }
250
251 Self {
252 base: InlineContainerState::new(style, flags, Some(parent_container), default_font),
253 identifier: inline_box.identifier,
254 base_fragment_info: inline_box.base.base_fragment_info,
255 pbm,
256 }
257 }
258
259 pub(super) fn calculate_space_above_baseline(&self) -> Au {
260 let font_metrics = &self.base.font_metrics;
261 let (ascent, descent, line_gap) = (
262 font_metrics.ascent,
263 font_metrics.descent,
264 font_metrics.line_gap,
265 );
266 let leading = line_gap - (ascent + descent);
267 leading.scale_by(0.5) + ascent
268 }
269
270 pub(super) fn should_clone_pbm(&self) -> bool {
271 self.base.style.get_border().box_decoration_break == BoxDecorationBreak::Clone
272 }
273}
274
275fn inline_box_style_breaks_shaping(style: &ComputedValues) -> (bool, bool) {
287 if style.clone_baseline_shift() != BaselineShift::zero() ||
292 style.clone_baseline_source() != BaselineSource::Auto ||
293 style.clone_alignment_baseline() != AlignmentBaseline::Baseline
294 {
295 return (true, true);
296 }
297
298 let layout_style = LayoutStyle::Default(style);
299 let border_widths = layout_style.border_width(style.writing_mode);
300 let padding = layout_style.padding(style.writing_mode);
301 let margin = style.margin(style.writing_mode);
302
303 (
304 !border_widths.inline_start.is_zero() ||
305 !padding.inline_start.is_zero() ||
306 !margin
307 .inline_start
308 .non_auto()
309 .is_none_or(LengthPercentage::is_zero),
310 !border_widths.inline_end.is_zero() ||
311 !padding.inline_end.is_zero() ||
312 !margin
313 .inline_end
314 .non_auto()
315 .is_none_or(LengthPercentage::is_zero),
316 )
317}