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