1use std::sync::Arc;
6
7use app_units::Au;
8use base::id::PipelineId;
9use base::print_tree::PrintTree;
10use euclid::{Point2D, Rect, Size2D, UnknownUnit};
11use fonts::{ByteIndex, FontMetrics, GlyphStore};
12use layout_api::BoxAreaType;
13use malloc_size_of_derive::MallocSizeOf;
14use range::Range as ServoRange;
15use servo_arc::Arc as ServoArc;
16use style::Zero;
17use style::properties::ComputedValues;
18use webrender_api::{FontInstanceKey, ImageKey};
19
20use super::{
21 BaseFragment, BoxFragment, ContainingBlockManager, HoistedSharedFragment, PositioningFragment,
22 Tag,
23};
24use crate::cell::ArcRefCell;
25use crate::flow::inline::SharedInlineStyles;
26use crate::geom::{LogicalSides, PhysicalPoint, PhysicalRect};
27use crate::style_ext::ComputedValuesExt;
28
29#[derive(Clone, MallocSizeOf)]
30pub(crate) enum Fragment {
31 Box(ArcRefCell<BoxFragment>),
32 Float(ArcRefCell<BoxFragment>),
38 Positioning(ArcRefCell<PositioningFragment>),
39 AbsoluteOrFixedPositioned(ArcRefCell<HoistedSharedFragment>),
47 Text(ArcRefCell<TextFragment>),
48 Image(ArcRefCell<ImageFragment>),
49 IFrame(ArcRefCell<IFrameFragment>),
50}
51
52#[derive(Clone, MallocSizeOf)]
53pub(crate) struct CollapsedBlockMargins {
54 pub collapsed_through: bool,
55 pub start: CollapsedMargin,
56 pub end: CollapsedMargin,
57}
58
59#[derive(Clone, Copy, Debug, MallocSizeOf)]
60pub(crate) struct CollapsedMargin {
61 max_positive: Au,
62 min_negative: Au,
63}
64
65#[derive(MallocSizeOf)]
66pub(crate) struct TextFragment {
67 pub base: BaseFragment,
68 pub inline_styles: SharedInlineStyles,
69 pub rect: PhysicalRect<Au>,
70 pub font_metrics: FontMetrics,
71 pub font_key: FontInstanceKey,
72 #[conditional_malloc_size_of]
73 pub glyphs: Vec<Arc<GlyphStore>>,
74
75 pub justification_adjustment: Au,
77 pub selection_range: Option<ServoRange<ByteIndex>>,
78}
79
80#[derive(MallocSizeOf)]
81pub(crate) struct ImageFragment {
82 pub base: BaseFragment,
83 pub style: ServoArc<ComputedValues>,
84 pub rect: PhysicalRect<Au>,
85 pub clip: PhysicalRect<Au>,
86 pub image_key: Option<ImageKey>,
87}
88
89#[derive(MallocSizeOf)]
90pub(crate) struct IFrameFragment {
91 pub base: BaseFragment,
92 pub pipeline_id: PipelineId,
93 pub rect: PhysicalRect<Au>,
94 pub style: ServoArc<ComputedValues>,
95}
96
97impl Fragment {
98 pub fn base(&self) -> Option<BaseFragment> {
99 Some(match self {
100 Fragment::Box(fragment) => fragment.borrow().base.clone(),
101 Fragment::Text(fragment) => fragment.borrow().base.clone(),
102 Fragment::AbsoluteOrFixedPositioned(_) => return None,
103 Fragment::Positioning(fragment) => fragment.borrow().base.clone(),
104 Fragment::Image(fragment) => fragment.borrow().base.clone(),
105 Fragment::IFrame(fragment) => fragment.borrow().base.clone(),
106 Fragment::Float(fragment) => fragment.borrow().base.clone(),
107 })
108 }
109
110 pub(crate) fn mutate_content_rect(&mut self, callback: impl FnOnce(&mut PhysicalRect<Au>)) {
111 match self {
112 Fragment::Box(box_fragment) | Fragment::Float(box_fragment) => {
113 callback(&mut box_fragment.borrow_mut().content_rect)
114 },
115 Fragment::Positioning(_) | Fragment::AbsoluteOrFixedPositioned(_) => {},
116 Fragment::Text(text_fragment) => callback(&mut text_fragment.borrow_mut().rect),
117 Fragment::Image(image_fragment) => callback(&mut image_fragment.borrow_mut().rect),
118 Fragment::IFrame(iframe_fragment) => callback(&mut iframe_fragment.borrow_mut().rect),
119 }
120 }
121
122 pub(crate) fn set_containing_block(&self, containing_block: &PhysicalRect<Au>) {
123 match self {
124 Fragment::Box(box_fragment) => box_fragment
125 .borrow_mut()
126 .set_containing_block(containing_block),
127 Fragment::Float(float_fragment) => float_fragment
128 .borrow_mut()
129 .set_containing_block(containing_block),
130 Fragment::Positioning(positioning_fragment) => positioning_fragment
131 .borrow_mut()
132 .set_containing_block(containing_block),
133 Fragment::AbsoluteOrFixedPositioned(hoisted_shared_fragment) => {
134 if let Some(ref fragment) = hoisted_shared_fragment.borrow().fragment {
135 fragment.set_containing_block(containing_block);
136 }
137 },
138 Fragment::Text(_) => {},
139 Fragment::Image(_) => {},
140 Fragment::IFrame(_) => {},
141 }
142 }
143
144 pub fn tag(&self) -> Option<Tag> {
145 self.base().and_then(|base| base.tag)
146 }
147
148 pub fn print(&self, tree: &mut PrintTree) {
149 match self {
150 Fragment::Box(fragment) => fragment.borrow().print(tree),
151 Fragment::Float(fragment) => {
152 tree.new_level("Float".to_string());
153 fragment.borrow().print(tree);
154 tree.end_level();
155 },
156 Fragment::AbsoluteOrFixedPositioned(_) => {
157 tree.add_item("AbsoluteOrFixedPositioned".to_string());
158 },
159 Fragment::Positioning(fragment) => fragment.borrow().print(tree),
160 Fragment::Text(fragment) => fragment.borrow().print(tree),
161 Fragment::Image(fragment) => fragment.borrow().print(tree),
162 Fragment::IFrame(fragment) => fragment.borrow().print(tree),
163 }
164 }
165
166 pub(crate) fn scrolling_area(&self) -> PhysicalRect<Au> {
167 match self {
168 Fragment::Box(fragment) | Fragment::Float(fragment) => {
169 let fragment = fragment.borrow();
170 fragment.offset_by_containing_block(&fragment.scrollable_overflow())
171 },
172 _ => self.scrollable_overflow_for_parent(),
173 }
174 }
175
176 pub(crate) fn scrollable_overflow_for_parent(&self) -> PhysicalRect<Au> {
177 match self {
178 Fragment::Box(fragment) | Fragment::Float(fragment) => {
179 return fragment.borrow().scrollable_overflow_for_parent();
180 },
181 Fragment::AbsoluteOrFixedPositioned(_) => PhysicalRect::zero(),
182 Fragment::Positioning(fragment) => fragment.borrow().scrollable_overflow_for_parent(),
183 Fragment::Text(fragment) => fragment.borrow().rect,
184 Fragment::Image(fragment) => fragment.borrow().rect,
185 Fragment::IFrame(fragment) => fragment.borrow().rect,
186 }
187 }
188
189 pub(crate) fn calculate_scrollable_overflow_for_parent(&self) -> PhysicalRect<Au> {
190 self.calculate_scrollable_overflow();
191 self.scrollable_overflow_for_parent()
192 }
193
194 pub(crate) fn calculate_scrollable_overflow(&self) {
195 match self {
196 Fragment::Box(fragment) | Fragment::Float(fragment) => {
197 fragment.borrow_mut().calculate_scrollable_overflow()
198 },
199 Fragment::Positioning(fragment) => {
200 fragment.borrow_mut().calculate_scrollable_overflow()
201 },
202 _ => {},
203 }
204 }
205
206 pub(crate) fn cumulative_box_area_rect(&self, area: BoxAreaType) -> Option<PhysicalRect<Au>> {
207 match self {
208 Fragment::Box(fragment) | Fragment::Float(fragment) => Some(match area {
209 BoxAreaType::Content => fragment.borrow().cumulative_content_box_rect(),
210 BoxAreaType::Padding => fragment.borrow().cumulative_padding_box_rect(),
211 BoxAreaType::Border => fragment.borrow().cumulative_border_box_rect(),
212 }),
213 Fragment::Positioning(fragment) => {
214 let fragment = fragment.borrow();
215 Some(fragment.offset_by_containing_block(&fragment.rect))
216 },
217 Fragment::Text(_) |
218 Fragment::AbsoluteOrFixedPositioned(_) |
219 Fragment::Image(_) |
220 Fragment::IFrame(_) => None,
221 }
222 }
223
224 pub(crate) fn client_rect(&self) -> Rect<i32, UnknownUnit> {
225 let rect = match self {
226 Fragment::Box(fragment) | Fragment::Float(fragment) => {
227 let fragment = fragment.borrow();
233 if fragment.is_inline_box() {
234 return Rect::zero();
235 }
236
237 if fragment.is_table_wrapper() {
238 let mut rect = fragment.border_rect();
241 rect.origin = PhysicalPoint::zero();
242 rect
243 } else {
244 let mut rect = fragment.padding_rect();
245 rect.origin = PhysicalPoint::new(fragment.border.left, fragment.border.top);
246 rect
247 }
248 },
249 _ => return Rect::zero(),
250 }
251 .to_untyped();
252
253 let rect = Rect::new(
254 Point2D::new(rect.origin.x.to_f32_px(), rect.origin.y.to_f32_px()),
255 Size2D::new(rect.size.width.to_f32_px(), rect.size.height.to_f32_px()),
256 );
257 rect.round().to_i32()
258 }
259
260 pub(crate) fn find<T>(
261 &self,
262 manager: &ContainingBlockManager<PhysicalRect<Au>>,
263 level: usize,
264 process_func: &mut impl FnMut(&Fragment, usize, &PhysicalRect<Au>) -> Option<T>,
265 ) -> Option<T> {
266 let containing_block = manager.get_containing_block_for_fragment(self);
267 if let Some(result) = process_func(self, level, containing_block) {
268 return Some(result);
269 }
270
271 match self {
272 Fragment::Box(fragment) | Fragment::Float(fragment) => {
273 let fragment = fragment.borrow();
274 let content_rect = fragment
275 .content_rect
276 .translate(containing_block.origin.to_vector());
277 let padding_rect = fragment
278 .padding_rect()
279 .translate(containing_block.origin.to_vector());
280 let new_manager = if fragment
281 .style
282 .establishes_containing_block_for_all_descendants(fragment.base.flags)
283 {
284 manager.new_for_absolute_and_fixed_descendants(&content_rect, &padding_rect)
285 } else if fragment
286 .style
287 .establishes_containing_block_for_absolute_descendants(fragment.base.flags)
288 {
289 manager.new_for_absolute_descendants(&content_rect, &padding_rect)
290 } else {
291 manager.new_for_non_absolute_descendants(&content_rect)
292 };
293
294 fragment
295 .children
296 .iter()
297 .find_map(|child| child.find(&new_manager, level + 1, process_func))
298 },
299 Fragment::Positioning(fragment) => {
300 let fragment = fragment.borrow();
301 let content_rect = fragment.rect.translate(containing_block.origin.to_vector());
302 let new_manager = manager.new_for_non_absolute_descendants(&content_rect);
303 fragment
304 .children
305 .iter()
306 .find_map(|child| child.find(&new_manager, level + 1, process_func))
307 },
308 _ => None,
309 }
310 }
311
312 pub(crate) fn repair_style(&self, style: &ServoArc<ComputedValues>) {
313 match self {
314 Fragment::Box(box_fragment) | Fragment::Float(box_fragment) => {
315 box_fragment.borrow_mut().style = style.clone()
316 },
317 Fragment::Positioning(positioning_fragment) => {
318 positioning_fragment.borrow_mut().style = style.clone();
319 },
320 Fragment::AbsoluteOrFixedPositioned(positioned_fragment) => {
321 if let Some(ref fragment) = positioned_fragment.borrow().fragment {
322 fragment.repair_style(style);
323 }
324 },
325 Fragment::Text(..) => unreachable!("Should never try to repair style of TextFragment"),
326 Fragment::Image(image_fragment) => image_fragment.borrow_mut().style = style.clone(),
327 Fragment::IFrame(iframe_fragment) => iframe_fragment.borrow_mut().style = style.clone(),
328 }
329 }
330
331 pub(crate) fn retrieve_box_fragment(&self) -> Option<&ArcRefCell<BoxFragment>> {
332 match self {
333 Fragment::Box(box_fragment) | Fragment::Float(box_fragment) => Some(box_fragment),
334 _ => None,
335 }
336 }
337}
338
339impl TextFragment {
340 pub fn print(&self, tree: &mut PrintTree) {
341 tree.add_item(format!(
342 "Text num_glyphs={} box={:?}",
343 self.glyphs
344 .iter()
345 .map(|glyph_store| glyph_store.len().0)
346 .sum::<isize>(),
347 self.rect,
348 ));
349 }
350
351 pub fn has_selection(&self) -> bool {
352 self.selection_range.is_some()
353 }
354}
355
356impl ImageFragment {
357 pub fn print(&self, tree: &mut PrintTree) {
358 tree.add_item(format!(
359 "Image\
360 \nrect={:?}",
361 self.rect
362 ));
363 }
364}
365
366impl IFrameFragment {
367 pub fn print(&self, tree: &mut PrintTree) {
368 tree.add_item(format!(
369 "IFrame\
370 \npipeline={:?} rect={:?}",
371 self.pipeline_id, self.rect
372 ));
373 }
374}
375
376impl CollapsedBlockMargins {
377 pub fn from_margin(margin: &LogicalSides<Au>) -> Self {
378 Self {
379 collapsed_through: false,
380 start: CollapsedMargin::new(margin.block_start),
381 end: CollapsedMargin::new(margin.block_end),
382 }
383 }
384
385 pub fn zero() -> Self {
386 Self {
387 collapsed_through: false,
388 start: CollapsedMargin::zero(),
389 end: CollapsedMargin::zero(),
390 }
391 }
392}
393
394impl CollapsedMargin {
395 pub fn zero() -> Self {
396 Self {
397 max_positive: Au::zero(),
398 min_negative: Au::zero(),
399 }
400 }
401
402 pub fn new(margin: Au) -> Self {
403 Self {
404 max_positive: margin.max(Au::zero()),
405 min_negative: margin.min(Au::zero()),
406 }
407 }
408
409 pub fn adjoin(&self, other: &Self) -> Self {
410 Self {
411 max_positive: self.max_positive.max(other.max_positive),
412 min_negative: self.min_negative.min(other.min_negative),
413 }
414 }
415
416 pub fn adjoin_assign(&mut self, other: &Self) {
417 *self = self.adjoin(other);
418 }
419
420 pub fn solve(&self) -> Au {
421 self.max_positive + self.min_negative
422 }
423}