1use std::vec::IntoIter;
6
7use app_units::Au;
8use fonts::FontMetrics;
9use malloc_size_of_derive::MallocSizeOf;
10use script::layout_dom::ServoThreadSafeLayoutNode;
11use servo_arc::Arc as ServoArc;
12use style::properties::ComputedValues;
13
14use super::{
15 InlineContainerState, InlineContainerStateFlags, SharedInlineStyles,
16 inline_container_needs_strut,
17};
18use crate::ContainingBlock;
19use crate::cell::ArcRefCell;
20use crate::context::LayoutContext;
21use crate::dom_traversal::NodeAndStyleInfo;
22use crate::fragment_tree::BaseFragmentInfo;
23use crate::layout_box_base::LayoutBoxBase;
24use crate::style_ext::{LayoutStyle, PaddingBorderMargin};
25
26#[derive(Debug, MallocSizeOf)]
27pub(crate) struct InlineBox {
28 pub base: LayoutBoxBase,
29 pub(super) shared_inline_styles: SharedInlineStyles,
32 pub(super) identifier: InlineBoxIdentifier,
34 pub is_first_split: bool,
37 pub is_last_split: bool,
40 pub default_font_index: Option<usize>,
43}
44
45impl InlineBox {
46 pub(crate) fn new(info: &NodeAndStyleInfo) -> Self {
47 Self {
48 base: LayoutBoxBase::new(info.into(), info.style.clone()),
49 shared_inline_styles: info.into(),
50 identifier: InlineBoxIdentifier::default(),
52 is_first_split: true,
53 is_last_split: false,
54 default_font_index: None,
55 }
56 }
57
58 pub(crate) fn split_around_block(&self) -> Self {
59 Self {
60 base: LayoutBoxBase::new(self.base.base_fragment_info, self.base.style.clone()),
61 shared_inline_styles: self.shared_inline_styles.clone(),
62 is_first_split: false,
63 is_last_split: false,
64 ..*self
65 }
66 }
67
68 #[inline]
69 pub(crate) fn layout_style(&self) -> LayoutStyle<'_> {
70 LayoutStyle::Default(&self.base.style)
71 }
72
73 pub(crate) fn repair_style(
74 &mut self,
75 node: &ServoThreadSafeLayoutNode,
76 new_style: &ServoArc<ComputedValues>,
77 ) {
78 self.base.repair_style(new_style);
79 *self.shared_inline_styles.style.borrow_mut() = new_style.clone();
80 *self.shared_inline_styles.selected.borrow_mut() = node.selected_style();
81 }
82}
83
84#[derive(Debug, Default, MallocSizeOf)]
85pub(crate) struct InlineBoxes {
86 inline_boxes: Vec<ArcRefCell<InlineBox>>,
88
89 inline_box_tree: Vec<InlineBoxTreePathToken>,
94}
95
96impl InlineBoxes {
97 pub(super) fn len(&self) -> usize {
98 self.inline_boxes.len()
99 }
100
101 pub(super) fn iter(&self) -> impl Iterator<Item = &ArcRefCell<InlineBox>> {
102 self.inline_boxes.iter()
103 }
104
105 pub(super) fn get(&self, identifier: &InlineBoxIdentifier) -> ArcRefCell<InlineBox> {
106 self.inline_boxes[identifier.index_in_inline_boxes as usize].clone()
107 }
108
109 pub(super) fn end_inline_box(&mut self, identifier: InlineBoxIdentifier) {
110 self.inline_box_tree
111 .push(InlineBoxTreePathToken::End(identifier));
112 }
113
114 pub(super) fn start_inline_box(
115 &mut self,
116 inline_box: ArcRefCell<InlineBox>,
117 ) -> InlineBoxIdentifier {
118 assert!(self.inline_boxes.len() <= u32::MAX as usize);
119 assert!(self.inline_box_tree.len() <= u32::MAX as usize);
120
121 let index_in_inline_boxes = self.inline_boxes.len() as u32;
122 let index_of_start_in_tree = self.inline_box_tree.len() as u32;
123
124 let identifier = InlineBoxIdentifier {
125 index_of_start_in_tree,
126 index_in_inline_boxes,
127 };
128 inline_box.borrow_mut().identifier = identifier;
129
130 self.inline_boxes.push(inline_box);
131 self.inline_box_tree
132 .push(InlineBoxTreePathToken::Start(identifier));
133
134 identifier
135 }
136
137 pub(super) fn get_path(
138 &self,
139 from: Option<InlineBoxIdentifier>,
140 to: InlineBoxIdentifier,
141 ) -> IntoIter<InlineBoxTreePathToken> {
142 if from == Some(to) {
143 return Vec::new().into_iter();
144 }
145
146 let mut from_index = match from {
147 Some(InlineBoxIdentifier {
148 index_of_start_in_tree,
149 ..
150 }) => index_of_start_in_tree as usize,
151 None => 0,
152 };
153 let mut to_index = to.index_of_start_in_tree as usize;
154 let is_reversed = to_index < from_index;
155
156 if to_index > from_index && from.is_some() {
160 from_index += 1;
161 } else if to_index < from_index {
162 to_index += 1;
163 }
164
165 let mut path = Vec::with_capacity(from_index.abs_diff(to_index));
166 let min = from_index.min(to_index);
167 let max = from_index.max(to_index);
168
169 for token in &self.inline_box_tree[min..=max] {
170 if Some(&token.reverse()) == path.last() {
172 path.pop();
173 } else {
174 path.push(*token);
175 }
176 }
177
178 if is_reversed {
179 path.reverse();
180 for token in path.iter_mut() {
181 *token = token.reverse();
182 }
183 }
184
185 path.into_iter()
186 }
187}
188
189#[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq)]
190pub(super) enum InlineBoxTreePathToken {
191 Start(InlineBoxIdentifier),
192 End(InlineBoxIdentifier),
193}
194
195impl InlineBoxTreePathToken {
196 fn reverse(&self) -> Self {
197 match self {
198 Self::Start(index) => Self::End(*index),
199 Self::End(index) => Self::Start(*index),
200 }
201 }
202}
203
204#[derive(Clone, Copy, Debug, Default, Eq, Hash, MallocSizeOf, PartialEq)]
211pub(crate) struct InlineBoxIdentifier {
212 pub index_of_start_in_tree: u32,
213 pub index_in_inline_boxes: u32,
214}
215
216pub(super) struct InlineBoxContainerState {
217 pub base: InlineContainerState,
220
221 pub identifier: InlineBoxIdentifier,
224
225 pub base_fragment_info: BaseFragmentInfo,
227
228 pub pbm: PaddingBorderMargin,
230
231 pub is_last_fragment: bool,
235}
236
237impl InlineBoxContainerState {
238 pub(super) fn new(
239 inline_box: &InlineBox,
240 containing_block: &ContainingBlock,
241 layout_context: &LayoutContext,
242 parent_container: &InlineContainerState,
243 is_last_fragment: bool,
244 font_metrics: Option<&FontMetrics>,
245 ) -> Self {
246 let style = inline_box.base.style.clone();
247 let pbm = inline_box
248 .layout_style()
249 .padding_border_margin(containing_block);
250
251 let mut flags = InlineContainerStateFlags::empty();
252 if inline_container_needs_strut(&style, layout_context, Some(&pbm)) {
253 flags.insert(InlineContainerStateFlags::CREATE_STRUT);
254 }
255
256 Self {
257 base: InlineContainerState::new(style, flags, Some(parent_container), font_metrics),
258 identifier: inline_box.identifier,
259 base_fragment_info: inline_box.base.base_fragment_info,
260 pbm,
261 is_last_fragment,
262 }
263 }
264
265 pub(super) fn calculate_space_above_baseline(&self) -> Au {
266 let (ascent, descent, line_gap) = (
267 self.base.font_metrics.ascent,
268 self.base.font_metrics.descent,
269 self.base.font_metrics.line_gap,
270 );
271 let leading = line_gap - (ascent + descent);
272 leading.scale_by(0.5) + ascent
273 }
274}