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