layout/flow/inline/
inline_box.rs1use std::sync::Arc;
6use std::vec::IntoIter;
7
8use app_units::Au;
9use fonts::{FontMetrics, FontRef};
10use malloc_size_of_derive::MallocSizeOf;
11use script::layout_dom::ServoThreadSafeLayoutNode;
12use servo_arc::Arc as ServoArc;
13use style::context::SharedStyleContext;
14use style::properties::ComputedValues;
15
16use super::{
17 InlineContainerState, InlineContainerStateFlags, SharedInlineStyles,
18 inline_container_needs_strut,
19};
20use crate::ContainingBlock;
21use crate::cell::ArcRefCell;
22use crate::context::LayoutContext;
23use crate::dom_traversal::NodeAndStyleInfo;
24use crate::fragment_tree::BaseFragmentInfo;
25use crate::layout_box_base::LayoutBoxBase;
26use crate::style_ext::{LayoutStyle, PaddingBorderMargin};
27
28#[derive(Debug, MallocSizeOf)]
29pub(crate) struct InlineBox {
30 pub base: LayoutBoxBase,
31 pub(super) shared_inline_styles: SharedInlineStyles,
34 pub(super) identifier: InlineBoxIdentifier,
36 pub default_font: Option<FontRef>,
39}
40
41impl InlineBox {
42 pub(crate) fn new(info: &NodeAndStyleInfo, context: &LayoutContext) -> Self {
43 Self {
44 base: LayoutBoxBase::new(info.into(), info.style.clone()),
45 shared_inline_styles: SharedInlineStyles::from_info_and_context(info, context),
46 identifier: InlineBoxIdentifier::default(),
48 default_font: None,
49 }
50 }
51
52 #[inline]
53 pub(crate) fn layout_style(&self) -> LayoutStyle<'_> {
54 LayoutStyle::Default(&self.base.style)
55 }
56
57 pub(crate) fn repair_style(
58 &mut self,
59 context: &SharedStyleContext,
60 node: &ServoThreadSafeLayoutNode,
61 new_style: &ServoArc<ComputedValues>,
62 ) {
63 self.base.repair_style(new_style);
64 *self.shared_inline_styles.style.borrow_mut() = new_style.clone();
65 *self.shared_inline_styles.selected.borrow_mut() = node.selected_style(context);
66 }
67}
68
69#[derive(Debug, Default, MallocSizeOf)]
70pub(crate) struct InlineBoxes {
71 inline_boxes: Vec<ArcRefCell<InlineBox>>,
73
74 inline_box_tree: Vec<InlineBoxTreePathToken>,
79}
80
81impl InlineBoxes {
82 pub(super) fn len(&self) -> usize {
83 self.inline_boxes.len()
84 }
85
86 pub(super) fn iter(&self) -> impl Iterator<Item = &ArcRefCell<InlineBox>> {
87 self.inline_boxes.iter()
88 }
89
90 pub(super) fn get(&self, identifier: &InlineBoxIdentifier) -> ArcRefCell<InlineBox> {
91 self.inline_boxes[identifier.index_in_inline_boxes as usize].clone()
92 }
93
94 pub(super) fn end_inline_box(&mut self, identifier: InlineBoxIdentifier) {
95 self.inline_box_tree
96 .push(InlineBoxTreePathToken::End(identifier));
97 }
98
99 pub(super) fn start_inline_box(
100 &mut self,
101 inline_box: ArcRefCell<InlineBox>,
102 ) -> InlineBoxIdentifier {
103 assert!(self.inline_boxes.len() <= u32::MAX as usize);
104 assert!(self.inline_box_tree.len() <= u32::MAX as usize);
105
106 let index_in_inline_boxes = self.inline_boxes.len() as u32;
107 let index_of_start_in_tree = self.inline_box_tree.len() as u32;
108
109 let identifier = InlineBoxIdentifier {
110 index_of_start_in_tree,
111 index_in_inline_boxes,
112 };
113 inline_box.borrow_mut().identifier = identifier;
114
115 self.inline_boxes.push(inline_box);
116 self.inline_box_tree
117 .push(InlineBoxTreePathToken::Start(identifier));
118
119 identifier
120 }
121
122 pub(super) fn get_path(
123 &self,
124 from: Option<InlineBoxIdentifier>,
125 to: InlineBoxIdentifier,
126 ) -> IntoIter<InlineBoxTreePathToken> {
127 if from == Some(to) {
128 return Vec::new().into_iter();
129 }
130
131 let mut from_index = match from {
132 Some(InlineBoxIdentifier {
133 index_of_start_in_tree,
134 ..
135 }) => index_of_start_in_tree as usize,
136 None => 0,
137 };
138 let mut to_index = to.index_of_start_in_tree as usize;
139 let is_reversed = to_index < from_index;
140
141 if to_index > from_index && from.is_some() {
145 from_index += 1;
146 } else if to_index < from_index {
147 to_index += 1;
148 }
149
150 let mut path = Vec::with_capacity(from_index.abs_diff(to_index));
151 let min = from_index.min(to_index);
152 let max = from_index.max(to_index);
153
154 for token in &self.inline_box_tree[min..=max] {
155 if Some(&token.reverse()) == path.last() {
157 path.pop();
158 } else {
159 path.push(*token);
160 }
161 }
162
163 if is_reversed {
164 path.reverse();
165 for token in path.iter_mut() {
166 *token = token.reverse();
167 }
168 }
169
170 path.into_iter()
171 }
172}
173
174#[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq)]
175pub(super) enum InlineBoxTreePathToken {
176 Start(InlineBoxIdentifier),
177 End(InlineBoxIdentifier),
178}
179
180impl InlineBoxTreePathToken {
181 fn reverse(&self) -> Self {
182 match self {
183 Self::Start(index) => Self::End(*index),
184 Self::End(index) => Self::Start(*index),
185 }
186 }
187}
188
189#[derive(Clone, Copy, Debug, Default, Eq, Hash, MallocSizeOf, PartialEq)]
196pub(crate) struct InlineBoxIdentifier {
197 pub index_of_start_in_tree: u32,
198 pub index_in_inline_boxes: u32,
199}
200
201pub(super) struct InlineBoxContainerState {
202 pub base: InlineContainerState,
205
206 pub identifier: InlineBoxIdentifier,
209
210 pub base_fragment_info: BaseFragmentInfo,
212
213 pub pbm: PaddingBorderMargin,
215}
216
217impl InlineBoxContainerState {
218 pub(super) fn new(
219 inline_box: &InlineBox,
220 containing_block: &ContainingBlock,
221 layout_context: &LayoutContext,
222 parent_container: &InlineContainerState,
223 font_metrics: Option<Arc<FontMetrics>>,
224 ) -> Self {
225 let style = inline_box.base.style.clone();
226 let pbm = inline_box
227 .layout_style()
228 .padding_border_margin(containing_block);
229
230 let mut flags = InlineContainerStateFlags::empty();
231 if inline_container_needs_strut(&style, layout_context, Some(&pbm)) {
232 flags.insert(InlineContainerStateFlags::CREATE_STRUT);
233 }
234
235 Self {
236 base: InlineContainerState::new(style, flags, Some(parent_container), font_metrics),
237 identifier: inline_box.identifier,
238 base_fragment_info: inline_box.base.base_fragment_info,
239 pbm,
240 }
241 }
242
243 pub(super) fn calculate_space_above_baseline(&self) -> Au {
244 let (ascent, descent, line_gap) = (
245 self.base.font_metrics.ascent,
246 self.base.font_metrics.descent,
247 self.base.font_metrics.line_gap,
248 );
249 let leading = line_gap - (ascent + descent);
250 leading.scale_by(0.5) + ascent
251 }
252}