1 /* This Source Code Form is subject to the terms of the Mozilla Public
2  * License, v. 2.0. If a copy of the MPL was not distributed with this
3  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4 
5 //! Builds display lists from flows and fragments.
6 //!
7 //! Other browser engines sometimes call this "painting", but it is more accurately called display
8 //! list building, as the actual painting does not happen here—only deciding *what* we're going to
9 //! paint.
10 
11 #![deny(unsafe_code)]
12 
13 use app_units::{Au, AU_PER_PX};
14 use block::BlockFlow;
15 use canvas_traits::canvas::{CanvasMsg, FromLayoutMsg};
16 use context::LayoutContext;
17 use display_list::ToLayout;
18 use display_list::background::{build_border_radius, build_image_border_details};
19 use display_list::background::{calculate_inner_border_radii, compute_background_placement};
20 use display_list::background::{convert_linear_gradient, convert_radial_gradient};
21 use display_list::background::{get_cyclic, simple_normal_border};
22 use euclid::{rect, Point2D, Rect, SideOffsets2D, Size2D, TypedSize2D, Vector2D};
23 use flex::FlexFlow;
24 use flow::{BaseFlow, Flow, FlowFlags};
25 use flow_ref::FlowRef;
26 use fnv::FnvHashMap;
27 use fragment::{CanvasFragmentSource, CoordinateSystem, Fragment, ScannedTextFragmentInfo};
28 use fragment::SpecificFragmentInfo;
29 use gfx::display_list;
30 use gfx::display_list::{BaseDisplayItem, BorderDetails, BorderDisplayItem, BLUR_INFLATION_FACTOR};
31 use gfx::display_list::{BoxShadowDisplayItem, ClipScrollNode};
32 use gfx::display_list::{ClipScrollNodeIndex, ClipScrollNodeType, ClippingAndScrolling};
33 use gfx::display_list::{ClippingRegion, DisplayItem, DisplayItemMetadata, DisplayList};
34 use gfx::display_list::{DisplayListSection, GradientDisplayItem, IframeDisplayItem};
35 use gfx::display_list::{ImageDisplayItem, LineDisplayItem, OpaqueNode};
36 use gfx::display_list::{PopAllTextShadowsDisplayItem, PushTextShadowDisplayItem};
37 use gfx::display_list::{RadialGradientDisplayItem, SolidColorDisplayItem, StackingContext};
38 use gfx::display_list::{StackingContextType, StickyFrameData, TextDisplayItem, TextOrientation};
39 use gfx::display_list::WebRenderImageInfo;
40 use gfx::text::TextRun;
41 use gfx::text::glyph::ByteIndex;
42 use gfx_traits::{combine_id_with_fragment_type, FragmentType, StackingContextId};
43 use inline::{InlineFlow, InlineFragmentNodeFlags};
44 use ipc_channel::ipc;
45 use list_item::ListItemFlow;
46 use model::MaybeAuto;
47 use msg::constellation_msg::{BrowsingContextId, PipelineId};
48 use net_traits::image::base::PixelFormat;
49 use net_traits::image_cache::UsePlaceholder;
50 use range::Range;
51 use servo_config::opts;
52 use servo_geometry::MaxRect;
53 use std::default::Default;
54 use std::f32;
55 use std::mem;
56 use std::sync::Arc;
57 use style::computed_values::background_clip::single_value::T as BackgroundClip;
58 use style::computed_values::border_style::T as BorderStyle;
59 use style::computed_values::overflow_x::T as StyleOverflow;
60 use style::computed_values::pointer_events::T as PointerEvents;
61 use style::computed_values::position::T as StylePosition;
62 use style::computed_values::visibility::T as Visibility;
63 use style::logical_geometry::{LogicalMargin, LogicalPoint, LogicalRect};
64 use style::properties::{ComputedValues, style_structs};
65 use style::servo::restyle_damage::ServoRestyleDamage;
66 use style::values::{Either, RGBA};
67 use style::values::computed::Gradient;
68 use style::values::computed::effects::SimpleShadow;
69 use style::values::computed::pointing::Cursor;
70 use style::values::generics::background::BackgroundSize;
71 use style::values::generics::image::{GradientKind, Image, PaintWorklet};
72 use style_traits::CSSPixel;
73 use style_traits::ToCss;
74 use style_traits::cursor::CursorKind;
75 use table_cell::CollapsedBordersForCell;
76 use webrender_api::{self, BorderRadius, BorderSide, BoxShadowClipMode, ColorF, ExternalScrollId};
77 use webrender_api::{FilterOp, GlyphInstance, ImageRendering, LayoutRect, LayoutSize};
78 use webrender_api::{LayoutTransform, LayoutVector2D, LineStyle, LocalClip, NormalBorder};
79 use webrender_api::{ScrollPolicy, ScrollSensitivity, StickyOffsetBounds};
80 
establishes_containing_block_for_absolute( flags: StackingContextCollectionFlags, positioning: StylePosition, ) -> bool81 fn establishes_containing_block_for_absolute(
82     flags: StackingContextCollectionFlags,
83     positioning: StylePosition,
84 ) -> bool {
85     !flags.contains(StackingContextCollectionFlags::NEVER_CREATES_CONTAINING_BLOCK) &&
86         StylePosition::Static != positioning
87 }
88 
89 trait RgbColor {
rgb(r: u8, g: u8, b: u8) -> Self90     fn rgb(r: u8, g: u8, b: u8) -> Self;
91 }
92 
93 impl RgbColor for ColorF {
rgb(r: u8, g: u8, b: u8) -> Self94     fn rgb(r: u8, g: u8, b: u8) -> Self {
95         ColorF {
96             r: (r as f32) / (255.0 as f32),
97             g: (g as f32) / (255.0 as f32),
98             b: (b as f32) / (255.0 as f32),
99             a: 1.0 as f32,
100         }
101     }
102 }
103 
104 static THREAD_TINT_COLORS: [ColorF; 8] = [
105     ColorF {
106         r: 6.0 / 255.0,
107         g: 153.0 / 255.0,
108         b: 198.0 / 255.0,
109         a: 0.7,
110     },
111     ColorF {
112         r: 255.0 / 255.0,
113         g: 212.0 / 255.0,
114         b: 83.0 / 255.0,
115         a: 0.7,
116     },
117     ColorF {
118         r: 116.0 / 255.0,
119         g: 29.0 / 255.0,
120         b: 109.0 / 255.0,
121         a: 0.7,
122     },
123     ColorF {
124         r: 204.0 / 255.0,
125         g: 158.0 / 255.0,
126         b: 199.0 / 255.0,
127         a: 0.7,
128     },
129     ColorF {
130         r: 242.0 / 255.0,
131         g: 46.0 / 255.0,
132         b: 121.0 / 255.0,
133         a: 0.7,
134     },
135     ColorF {
136         r: 116.0 / 255.0,
137         g: 203.0 / 255.0,
138         b: 196.0 / 255.0,
139         a: 0.7,
140     },
141     ColorF {
142         r: 255.0 / 255.0,
143         g: 249.0 / 255.0,
144         b: 201.0 / 255.0,
145         a: 0.7,
146     },
147     ColorF {
148         r: 137.0 / 255.0,
149         g: 196.0 / 255.0,
150         b: 78.0 / 255.0,
151         a: 0.7,
152     },
153 ];
154 
155 pub struct InlineNodeBorderInfo {
156     is_first_fragment_of_element: bool,
157     is_last_fragment_of_element: bool,
158 }
159 
160 #[derive(Debug)]
161 struct StackingContextInfo {
162     children: Vec<StackingContext>,
163     clip_scroll_nodes: Vec<ClipScrollNodeIndex>,
164     real_stacking_context_id: StackingContextId,
165 }
166 
167 impl StackingContextInfo {
new(real_stacking_context_id: StackingContextId) -> StackingContextInfo168     fn new(real_stacking_context_id: StackingContextId) -> StackingContextInfo {
169         StackingContextInfo {
170             children: Vec::new(),
171             clip_scroll_nodes: Vec::new(),
172             real_stacking_context_id,
173         }
174     }
175 
take_children(&mut self) -> Vec<StackingContext>176     fn take_children(&mut self) -> Vec<StackingContext> {
177         mem::replace(&mut self.children, Vec::new())
178     }
179 }
180 
181 pub struct StackingContextCollectionState {
182     /// The PipelineId of this stacking context collection.
183     pub pipeline_id: PipelineId,
184 
185     /// The root of the StackingContext tree.
186     pub root_stacking_context: StackingContext,
187 
188     /// StackingContext and ClipScrollNode children for each StackingContext.
189     stacking_context_info: FnvHashMap<StackingContextId, StackingContextInfo>,
190 
191     pub clip_scroll_nodes: Vec<ClipScrollNode>,
192 
193     /// The current stacking context id, used to keep track of state when building.
194     /// recursively building and processing the display list.
195     pub current_stacking_context_id: StackingContextId,
196 
197     /// The current stacking real context id, which doesn't include pseudo-stacking contexts.
198     pub current_real_stacking_context_id: StackingContextId,
199 
200     /// The next stacking context id that we will assign to a stacking context.
201     pub next_stacking_context_id: StackingContextId,
202 
203     /// The current clip and scroll info, used to keep track of state when
204     /// recursively building and processing the display list.
205     pub current_clipping_and_scrolling: ClippingAndScrolling,
206 
207     /// The clip and scroll info  of the first ancestor which defines a containing block.
208     /// This is necessary because absolutely positioned items should be clipped
209     /// by their containing block's scroll root.
210     pub containing_block_clipping_and_scrolling: ClippingAndScrolling,
211 
212     /// A stack of clips used to cull display list entries that are outside the
213     /// rendered region.
214     pub clip_stack: Vec<Rect<Au>>,
215 
216     /// A stack of clips used to cull display list entries that are outside the
217     /// rendered region, but only collected at containing block boundaries.
218     pub containing_block_clip_stack: Vec<Rect<Au>>,
219 
220     /// The flow parent's content box, used to calculate sticky constraints.
221     parent_stacking_relative_content_box: Rect<Au>,
222 }
223 
224 impl StackingContextCollectionState {
new(pipeline_id: PipelineId) -> StackingContextCollectionState225     pub fn new(pipeline_id: PipelineId) -> StackingContextCollectionState {
226         let root_clip_indices = ClippingAndScrolling::simple(ClipScrollNodeIndex(0));
227 
228         // This is just a dummy node to take up a slot in the array. WebRender
229         // takes care of adding this root node and it can be ignored during DL conversion.
230         let root_node = ClipScrollNode {
231             parent_index: ClipScrollNodeIndex(0),
232             clip: ClippingRegion::from_rect(LayoutRect::zero()),
233             content_rect: LayoutRect::zero(),
234             node_type: ClipScrollNodeType::ScrollFrame(
235                 ScrollSensitivity::ScriptAndInputEvents,
236                 pipeline_id.root_scroll_id(),
237             ),
238         };
239 
240         let mut stacking_context_info = FnvHashMap::default();
241         stacking_context_info.insert(
242             StackingContextId::root(),
243             StackingContextInfo::new(StackingContextId::root())
244         );
245 
246         StackingContextCollectionState {
247             pipeline_id: pipeline_id,
248             root_stacking_context: StackingContext::root(),
249             stacking_context_info,
250             clip_scroll_nodes: vec![root_node],
251             current_stacking_context_id: StackingContextId::root(),
252             current_real_stacking_context_id: StackingContextId::root(),
253             next_stacking_context_id: StackingContextId::root().next(),
254             current_clipping_and_scrolling: root_clip_indices,
255             containing_block_clipping_and_scrolling: root_clip_indices,
256             clip_stack: Vec::new(),
257             containing_block_clip_stack: Vec::new(),
258             parent_stacking_relative_content_box: Rect::zero(),
259         }
260     }
261 
allocate_stacking_context_info( &mut self, stacking_context_type: StackingContextType ) -> StackingContextId262     fn allocate_stacking_context_info(
263         &mut self,
264         stacking_context_type: StackingContextType
265     ) -> StackingContextId {
266         let next_stacking_context_id = self.next_stacking_context_id.next();
267         let allocated_id =
268             mem::replace(&mut self.next_stacking_context_id, next_stacking_context_id);
269 
270         let real_stacking_context_id = match stacking_context_type {
271             StackingContextType::Real => allocated_id,
272             _ => self.current_real_stacking_context_id,
273         };
274 
275         self.stacking_context_info.insert(
276             allocated_id,
277             StackingContextInfo::new(real_stacking_context_id)
278         );
279 
280         allocated_id
281     }
282 
add_stacking_context( &mut self, parent_id: StackingContextId, stacking_context: StackingContext, )283     fn add_stacking_context(
284         &mut self,
285         parent_id: StackingContextId,
286         stacking_context: StackingContext,
287     ) {
288         self.stacking_context_info.get_mut(&parent_id).unwrap().children.push(stacking_context);
289     }
290 
add_clip_scroll_node(&mut self, clip_scroll_node: ClipScrollNode) -> ClipScrollNodeIndex291     fn add_clip_scroll_node(&mut self, clip_scroll_node: ClipScrollNode) -> ClipScrollNodeIndex {
292         // We want the scroll root to be defined before any possible item that could use it,
293         // so we make sure that it is added to the beginning of the parent "real" (non-pseudo)
294         // stacking context. This ensures that item reordering will not result in an item using
295         // the scroll root before it is defined.
296         self.clip_scroll_nodes.push(clip_scroll_node);
297         let index = ClipScrollNodeIndex(self.clip_scroll_nodes.len() - 1);
298         self.stacking_context_info
299             .get_mut(&self.current_real_stacking_context_id)
300             .unwrap()
301             .clip_scroll_nodes
302             .push(index);
303         index
304     }
305 }
306 
307 pub struct DisplayListBuildState<'a> {
308     /// A LayoutContext reference important for creating WebRender images.
309     pub layout_context: &'a LayoutContext<'a>,
310 
311     /// The root of the StackingContext tree.
312     pub root_stacking_context: StackingContext,
313 
314     /// StackingContext and ClipScrollNode children for each StackingContext.
315     stacking_context_info: FnvHashMap<StackingContextId, StackingContextInfo>,
316 
317     /// A vector of ClipScrollNodes which will be given ids during WebRender DL conversion.
318     pub clip_scroll_nodes: Vec<ClipScrollNode>,
319 
320     /// The items in this display list.
321     pub items: FnvHashMap<StackingContextId, Vec<DisplayItem>>,
322 
323     /// Whether or not we are processing an element that establishes scrolling overflow. Used
324     /// to determine what ClipScrollNode to place backgrounds and borders into.
325     pub processing_scrolling_overflow_element: bool,
326 
327     /// The current stacking context id, used to keep track of state when building.
328     /// recursively building and processing the display list.
329     pub current_stacking_context_id: StackingContextId,
330 
331     /// The current clip and scroll info, used to keep track of state when
332     /// recursively building and processing the display list.
333     pub current_clipping_and_scrolling: ClippingAndScrolling,
334 
335     /// Vector containing iframe sizes, used to inform the constellation about
336     /// new iframe sizes
337     pub iframe_sizes: Vec<(BrowsingContextId, TypedSize2D<f32, CSSPixel>)>,
338 
339     /// Stores text runs to answer text queries used to place a cursor inside text.
340     pub indexable_text: IndexableText,
341 }
342 
343 impl<'a> DisplayListBuildState<'a> {
new( layout_context: &'a LayoutContext, state: StackingContextCollectionState, ) -> DisplayListBuildState<'a>344     pub fn new(
345         layout_context: &'a LayoutContext,
346         state: StackingContextCollectionState,
347     ) -> DisplayListBuildState<'a> {
348         let root_clip_indices = ClippingAndScrolling::simple(ClipScrollNodeIndex(0));
349         DisplayListBuildState {
350             layout_context: layout_context,
351             root_stacking_context: state.root_stacking_context,
352             items: FnvHashMap::default(),
353             stacking_context_info: state.stacking_context_info,
354             clip_scroll_nodes: state.clip_scroll_nodes,
355             processing_scrolling_overflow_element: false,
356             current_stacking_context_id: StackingContextId::root(),
357             current_clipping_and_scrolling: root_clip_indices,
358             iframe_sizes: Vec::new(),
359             indexable_text: IndexableText::default(),
360         }
361     }
362 
add_display_item(&mut self, display_item: DisplayItem)363     fn add_display_item(&mut self, display_item: DisplayItem) {
364         let items = self.items
365             .entry(display_item.stacking_context_id())
366             .or_insert(Vec::new());
367         items.push(display_item);
368     }
369 
parent_clip_scroll_node_index(&self, index: ClipScrollNodeIndex) -> ClipScrollNodeIndex370     fn parent_clip_scroll_node_index(&self, index: ClipScrollNodeIndex) -> ClipScrollNodeIndex {
371         if index.is_root_scroll_node() {
372             return index;
373         }
374 
375         self.clip_scroll_nodes[index.0].parent_index
376     }
377 
is_background_or_border_of_clip_scroll_node(&self, section: DisplayListSection) -> bool378     fn is_background_or_border_of_clip_scroll_node(&self, section: DisplayListSection) -> bool {
379         (section == DisplayListSection::BackgroundAndBorders ||
380             section == DisplayListSection::BlockBackgroundsAndBorders) &&
381             self.processing_scrolling_overflow_element
382     }
383 
create_base_display_item( &self, bounds: &Rect<Au>, clip: LocalClip, node: OpaqueNode, cursor: Option<CursorKind>, section: DisplayListSection, ) -> BaseDisplayItem384     fn create_base_display_item(
385         &self,
386         bounds: &Rect<Au>,
387         clip: LocalClip,
388         node: OpaqueNode,
389         cursor: Option<CursorKind>,
390         section: DisplayListSection,
391     ) -> BaseDisplayItem {
392         let clipping_and_scrolling = if self.is_background_or_border_of_clip_scroll_node(section) {
393             ClippingAndScrolling::simple(self.parent_clip_scroll_node_index(
394                 self.current_clipping_and_scrolling.scrolling,
395             ))
396         } else {
397             self.current_clipping_and_scrolling
398         };
399 
400         BaseDisplayItem::new(
401             bounds.to_layout(),
402             DisplayItemMetadata {
403                 node,
404                 // Store cursor id in display list.
405                 pointing: cursor.map(|x| x as u16),
406             },
407             clip,
408             section,
409             self.current_stacking_context_id,
410             clipping_and_scrolling,
411         )
412     }
413 
add_late_clip_node(&mut self, rect: LayoutRect, radii: BorderRadius) -> ClipScrollNodeIndex414     fn add_late_clip_node(&mut self, rect: LayoutRect, radii: BorderRadius) -> ClipScrollNodeIndex {
415         let mut clip = ClippingRegion::from_rect(rect);
416         clip.intersect_with_rounded_rect(rect, radii);
417 
418         let node = ClipScrollNode {
419             parent_index: self.current_clipping_and_scrolling.scrolling,
420             clip,
421             content_rect: LayoutRect::zero(), // content_rect isn't important for clips.
422             node_type: ClipScrollNodeType::Clip,
423         };
424 
425         // We want the scroll root to be defined before any possible item that could use it,
426         // so we make sure that it is added to the beginning of the parent "real" (non-pseudo)
427         // stacking context. This ensures that item reordering will not result in an item using
428         // the scroll root before it is defined.
429         self.clip_scroll_nodes.push(node);
430         let index = ClipScrollNodeIndex(self.clip_scroll_nodes.len() - 1);
431         let real_stacking_context_id =
432             self.stacking_context_info[&self.current_stacking_context_id].real_stacking_context_id;
433         self.stacking_context_info
434             .get_mut(&real_stacking_context_id)
435             .unwrap()
436             .clip_scroll_nodes
437             .push(index);
438 
439         index
440     }
441 
to_display_list(mut self) -> DisplayList442     pub fn to_display_list(mut self) -> DisplayList {
443         let mut list = Vec::new();
444         let root_context = mem::replace(&mut self.root_stacking_context, StackingContext::root());
445 
446         self.to_display_list_for_stacking_context(&mut list, root_context);
447 
448         DisplayList {
449             list: list,
450             clip_scroll_nodes: self.clip_scroll_nodes,
451         }
452     }
453 
to_display_list_for_stacking_context( &mut self, list: &mut Vec<DisplayItem>, stacking_context: StackingContext, )454     fn to_display_list_for_stacking_context(
455         &mut self,
456         list: &mut Vec<DisplayItem>,
457         stacking_context: StackingContext,
458     ) {
459         let mut child_items = self.items
460             .remove(&stacking_context.id)
461             .unwrap_or(Vec::new());
462         child_items.sort_by(|a, b| a.base().section.cmp(&b.base().section));
463         child_items.reverse();
464 
465         let mut info = self.stacking_context_info.remove(&stacking_context.id).unwrap();
466 
467         info.children.sort();
468 
469         if stacking_context.context_type != StackingContextType::Real {
470             list.extend(
471                 info.clip_scroll_nodes
472                     .into_iter()
473                     .map(|index| index.to_define_item()),
474             );
475             self.to_display_list_for_items(list, child_items, info.children);
476         } else {
477             let (push_item, pop_item) = stacking_context.to_display_list_items();
478             list.push(push_item);
479             list.extend(
480                 info.clip_scroll_nodes
481                     .into_iter()
482                     .map(|index| index.to_define_item()),
483             );
484             self.to_display_list_for_items(list, child_items, info.children);
485             list.push(pop_item);
486         }
487     }
488 
to_display_list_for_items( &mut self, list: &mut Vec<DisplayItem>, mut child_items: Vec<DisplayItem>, child_stacking_contexts: Vec<StackingContext>, )489     fn to_display_list_for_items(
490         &mut self,
491         list: &mut Vec<DisplayItem>,
492         mut child_items: Vec<DisplayItem>,
493         child_stacking_contexts: Vec<StackingContext>,
494     ) {
495         // Properly order display items that make up a stacking context. "Steps" here
496         // refer to the steps in CSS 2.1 Appendix E.
497         // Steps 1 and 2: Borders and background for the root.
498         while child_items.last().map_or(false, |child| {
499             child.section() == DisplayListSection::BackgroundAndBorders
500         }) {
501             list.push(child_items.pop().unwrap());
502         }
503 
504         // Step 3: Positioned descendants with negative z-indices.
505         let mut child_stacking_contexts = child_stacking_contexts.into_iter().peekable();
506         while child_stacking_contexts
507             .peek()
508             .map_or(false, |child| child.z_index < 0)
509         {
510             let context = child_stacking_contexts.next().unwrap();
511             self.to_display_list_for_stacking_context(list, context);
512         }
513 
514         // Step 4: Block backgrounds and borders.
515         while child_items.last().map_or(false, |child| {
516             child.section() == DisplayListSection::BlockBackgroundsAndBorders
517         }) {
518             list.push(child_items.pop().unwrap());
519         }
520 
521         // Step 5: Floats.
522         while child_stacking_contexts.peek().map_or(false, |child| {
523             child.context_type == StackingContextType::PseudoFloat
524         }) {
525             let context = child_stacking_contexts.next().unwrap();
526             self.to_display_list_for_stacking_context(list, context);
527         }
528 
529         // Step 6 & 7: Content and inlines that generate stacking contexts.
530         while child_items.last().map_or(false, |child| {
531             child.section() == DisplayListSection::Content
532         }) {
533             list.push(child_items.pop().unwrap());
534         }
535 
536         // Step 8 & 9: Positioned descendants with nonnegative, numeric z-indices.
537         for child in child_stacking_contexts {
538             self.to_display_list_for_stacking_context(list, child);
539         }
540 
541         // Step 10: Outlines.
542         for item in child_items.drain(..) {
543             list.push(item);
544         }
545     }
546 }
547 
548 /// The logical width of an insertion point: at the moment, a one-pixel-wide line.
549 const INSERTION_POINT_LOGICAL_WIDTH: Au = Au(1 * AU_PER_PX);
550 
551 pub trait FragmentDisplayListBuilding {
collect_stacking_contexts_for_blocklike_fragment( &mut self, state: &mut StackingContextCollectionState, ) -> bool552     fn collect_stacking_contexts_for_blocklike_fragment(
553         &mut self,
554         state: &mut StackingContextCollectionState,
555     ) -> bool;
556 
557     /// Adds the display items necessary to paint the background of this fragment to the display
558     /// list if necessary.
build_display_list_for_background_if_applicable( &self, state: &mut DisplayListBuildState, style: &ComputedValues, display_list_section: DisplayListSection, absolute_bounds: &Rect<Au>, )559     fn build_display_list_for_background_if_applicable(
560         &self,
561         state: &mut DisplayListBuildState,
562         style: &ComputedValues,
563         display_list_section: DisplayListSection,
564         absolute_bounds: &Rect<Au>,
565     );
566 
567     /// Same as build_display_list_for_background_if_applicable, but lets you
568     /// override the actual background used
build_display_list_for_background_if_applicable_with_background( &self, state: &mut DisplayListBuildState, style: &ComputedValues, background: &style_structs::Background, background_color: RGBA, display_list_section: DisplayListSection, absolute_bounds: &Rect<Au>, )569     fn build_display_list_for_background_if_applicable_with_background(
570         &self,
571         state: &mut DisplayListBuildState,
572         style: &ComputedValues,
573         background: &style_structs::Background,
574         background_color: RGBA,
575         display_list_section: DisplayListSection,
576         absolute_bounds: &Rect<Au>,
577     );
578 
579     /// Adds the display items necessary to paint a webrender image of this fragment to the
580     /// appropriate section of the display list.
build_display_list_for_webrender_image( &self, state: &mut DisplayListBuildState, style: &ComputedValues, display_list_section: DisplayListSection, absolute_bounds: Rect<Au>, webrender_image: WebRenderImageInfo, index: usize, )581     fn build_display_list_for_webrender_image(
582         &self,
583         state: &mut DisplayListBuildState,
584         style: &ComputedValues,
585         display_list_section: DisplayListSection,
586         absolute_bounds: Rect<Au>,
587         webrender_image: WebRenderImageInfo,
588         index: usize,
589     );
590 
591     /// Calculates the webrender image for a paint worklet.
592     /// Returns None if the worklet is not registered.
593     /// If the worklet has missing image URLs, it passes them to the image cache for loading.
get_webrender_image_for_paint_worklet( &self, state: &mut DisplayListBuildState, style: &ComputedValues, paint_worklet: &PaintWorklet, size: Size2D<Au>, ) -> Option<WebRenderImageInfo>594     fn get_webrender_image_for_paint_worklet(
595         &self,
596         state: &mut DisplayListBuildState,
597         style: &ComputedValues,
598         paint_worklet: &PaintWorklet,
599         size: Size2D<Au>,
600     ) -> Option<WebRenderImageInfo>;
601 
602     /// Adds the display items necessary to paint the background linear gradient of this fragment
603     /// to the appropriate section of the display list.
build_display_list_for_background_gradient( &self, state: &mut DisplayListBuildState, display_list_section: DisplayListSection, absolute_bounds: Rect<Au>, gradient: &Gradient, style: &ComputedValues, index: usize, )604     fn build_display_list_for_background_gradient(
605         &self,
606         state: &mut DisplayListBuildState,
607         display_list_section: DisplayListSection,
608         absolute_bounds: Rect<Au>,
609         gradient: &Gradient,
610         style: &ComputedValues,
611         index: usize,
612     );
613 
614     /// Adds the display items necessary to paint the borders of this fragment to a display list if
615     /// necessary.
build_display_list_for_borders_if_applicable( &self, state: &mut DisplayListBuildState, style: &ComputedValues, inline_node_info: Option<InlineNodeBorderInfo>, border_painting_mode: BorderPaintingMode, bounds: &Rect<Au>, display_list_section: DisplayListSection, clip: &Rect<Au>, )616     fn build_display_list_for_borders_if_applicable(
617         &self,
618         state: &mut DisplayListBuildState,
619         style: &ComputedValues,
620         inline_node_info: Option<InlineNodeBorderInfo>,
621         border_painting_mode: BorderPaintingMode,
622         bounds: &Rect<Au>,
623         display_list_section: DisplayListSection,
624         clip: &Rect<Au>,
625     );
626 
627     /// Adds the display items necessary to paint the outline of this fragment to the display list
628     /// if necessary.
build_display_list_for_outline_if_applicable( &self, state: &mut DisplayListBuildState, style: &ComputedValues, bounds: &Rect<Au>, clip: &Rect<Au>, )629     fn build_display_list_for_outline_if_applicable(
630         &self,
631         state: &mut DisplayListBuildState,
632         style: &ComputedValues,
633         bounds: &Rect<Au>,
634         clip: &Rect<Au>,
635     );
636 
637     /// Adds the display items necessary to paint the box shadow of this fragment to the display
638     /// list if necessary.
build_display_list_for_box_shadow_if_applicable( &self, state: &mut DisplayListBuildState, style: &ComputedValues, display_list_section: DisplayListSection, absolute_bounds: &Rect<Au>, clip: &Rect<Au>, )639     fn build_display_list_for_box_shadow_if_applicable(
640         &self,
641         state: &mut DisplayListBuildState,
642         style: &ComputedValues,
643         display_list_section: DisplayListSection,
644         absolute_bounds: &Rect<Au>,
645         clip: &Rect<Au>,
646     );
647 
648     /// Adds display items necessary to draw debug boxes around a scanned text fragment.
build_debug_borders_around_text_fragments( &self, state: &mut DisplayListBuildState, style: &ComputedValues, stacking_relative_border_box: &Rect<Au>, stacking_relative_content_box: &Rect<Au>, text_fragment: &ScannedTextFragmentInfo, clip: &Rect<Au>, )649     fn build_debug_borders_around_text_fragments(
650         &self,
651         state: &mut DisplayListBuildState,
652         style: &ComputedValues,
653         stacking_relative_border_box: &Rect<Au>,
654         stacking_relative_content_box: &Rect<Au>,
655         text_fragment: &ScannedTextFragmentInfo,
656         clip: &Rect<Au>,
657     );
658 
659     /// Adds display items necessary to draw debug boxes around this fragment.
build_debug_borders_around_fragment( &self, state: &mut DisplayListBuildState, stacking_relative_border_box: &Rect<Au>, clip: &Rect<Au>, )660     fn build_debug_borders_around_fragment(
661         &self,
662         state: &mut DisplayListBuildState,
663         stacking_relative_border_box: &Rect<Au>,
664         clip: &Rect<Au>,
665     );
666 
667     /// Adds the display items for this fragment to the given display list.
668     ///
669     /// Arguments:
670     ///
671     /// * `state`: The display building state, including the display list currently
672     ///   under construction and other metadata useful for constructing it.
673     /// * `dirty`: The dirty rectangle in the coordinate system of the owning flow.
674     /// * `clip`: The region to clip the display items to.
build_display_list( &mut self, state: &mut DisplayListBuildState, stacking_relative_border_box: Rect<Au>, border_painting_mode: BorderPaintingMode, display_list_section: DisplayListSection, clip: &Rect<Au>, )675     fn build_display_list(
676         &mut self,
677         state: &mut DisplayListBuildState,
678         stacking_relative_border_box: Rect<Au>,
679         border_painting_mode: BorderPaintingMode,
680         display_list_section: DisplayListSection,
681         clip: &Rect<Au>,
682     );
683 
684     /// build_display_list, but don't update the restyle damage
685     ///
686     /// Must be paired with a self.restyle_damage.remove(REPAINT) somewhere
build_display_list_no_damage( &self, state: &mut DisplayListBuildState, stacking_relative_border_box: Rect<Au>, border_painting_mode: BorderPaintingMode, display_list_section: DisplayListSection, clip: &Rect<Au>, )687     fn build_display_list_no_damage(
688         &self,
689         state: &mut DisplayListBuildState,
690         stacking_relative_border_box: Rect<Au>,
691         border_painting_mode: BorderPaintingMode,
692         display_list_section: DisplayListSection,
693         clip: &Rect<Au>,
694     );
695 
696     /// Builds the display items necessary to paint the selection and/or caret for this fragment,
697     /// if any.
build_display_items_for_selection_if_necessary( &self, state: &mut DisplayListBuildState, stacking_relative_border_box: &Rect<Au>, display_list_section: DisplayListSection, clip: &Rect<Au>, )698     fn build_display_items_for_selection_if_necessary(
699         &self,
700         state: &mut DisplayListBuildState,
701         stacking_relative_border_box: &Rect<Au>,
702         display_list_section: DisplayListSection,
703         clip: &Rect<Au>,
704     );
705 
706     /// Creates the text display item for one text fragment. This can be called multiple times for
707     /// one fragment if there are text shadows.
708     ///
709     /// `text_shadow` will be `Some` if this is rendering a shadow.
build_display_list_for_text_fragment( &self, state: &mut DisplayListBuildState, text_fragment: &ScannedTextFragmentInfo, stacking_relative_content_box: &Rect<Au>, text_shadows: &[SimpleShadow], clip: &Rect<Au>, )710     fn build_display_list_for_text_fragment(
711         &self,
712         state: &mut DisplayListBuildState,
713         text_fragment: &ScannedTextFragmentInfo,
714         stacking_relative_content_box: &Rect<Au>,
715         text_shadows: &[SimpleShadow],
716         clip: &Rect<Au>,
717     );
718 
719     /// Creates the display item for a text decoration: underline, overline, or line-through.
build_display_list_for_text_decoration( &self, state: &mut DisplayListBuildState, color: &RGBA, stacking_relative_box: &LogicalRect<Au>, clip: &Rect<Au>, )720     fn build_display_list_for_text_decoration(
721         &self,
722         state: &mut DisplayListBuildState,
723         color: &RGBA,
724         stacking_relative_box: &LogicalRect<Au>,
725         clip: &Rect<Au>,
726     );
727 
728     /// A helper method that `build_display_list` calls to create per-fragment-type display items.
build_fragment_type_specific_display_items( &self, state: &mut DisplayListBuildState, stacking_relative_border_box: &Rect<Au>, clip: &Rect<Au>, )729     fn build_fragment_type_specific_display_items(
730         &self,
731         state: &mut DisplayListBuildState,
732         stacking_relative_border_box: &Rect<Au>,
733         clip: &Rect<Au>,
734     );
735 
736     /// Creates a stacking context for associated fragment.
create_stacking_context( &self, id: StackingContextId, base_flow: &BaseFlow, scroll_policy: ScrollPolicy, context_type: StackingContextType, parent_clipping_and_scrolling: ClippingAndScrolling, ) -> StackingContext737     fn create_stacking_context(
738         &self,
739         id: StackingContextId,
740         base_flow: &BaseFlow,
741         scroll_policy: ScrollPolicy,
742         context_type: StackingContextType,
743         parent_clipping_and_scrolling: ClippingAndScrolling,
744     ) -> StackingContext;
745 
unique_id(&self) -> u64746     fn unique_id(&self) -> u64;
747 
fragment_type(&self) -> FragmentType748     fn fragment_type(&self) -> FragmentType;
749 }
750 
751 /// Get the border radius for the rectangle inside of a rounded border. This is useful
752 /// for building the clip for the content inside the border.
build_border_radius_for_inner_rect( outer_rect: &Rect<Au>, style: &ComputedValues, ) -> BorderRadius753 fn build_border_radius_for_inner_rect(
754     outer_rect: &Rect<Au>,
755     style: &ComputedValues,
756 ) -> BorderRadius {
757     let radii = build_border_radius(&outer_rect, style.get_border());
758     if radii.is_zero() {
759         return radii;
760     }
761 
762     // Since we are going to using the inner rectangle (outer rectangle minus
763     // border width), we need to adjust to border radius so that we are smaller
764     // rectangle with the same border curve.
765     let border_widths = style.logical_border_width().to_physical(style.writing_mode);
766     calculate_inner_border_radii(radii, border_widths)
767 }
768 
769 impl FragmentDisplayListBuilding for Fragment {
collect_stacking_contexts_for_blocklike_fragment( &mut self, state: &mut StackingContextCollectionState, ) -> bool770     fn collect_stacking_contexts_for_blocklike_fragment(
771         &mut self,
772         state: &mut StackingContextCollectionState,
773     ) -> bool {
774         match self.specific {
775             SpecificFragmentInfo::InlineBlock(ref mut block_flow) => {
776                 let block_flow = FlowRef::deref_mut(&mut block_flow.flow_ref);
777                 block_flow.collect_stacking_contexts(state);
778                 true
779             },
780             SpecificFragmentInfo::InlineAbsoluteHypothetical(ref mut block_flow) => {
781                 let block_flow = FlowRef::deref_mut(&mut block_flow.flow_ref);
782                 block_flow.collect_stacking_contexts(state);
783                 true
784             },
785             SpecificFragmentInfo::InlineAbsolute(ref mut block_flow) => {
786                 let block_flow = FlowRef::deref_mut(&mut block_flow.flow_ref);
787                 block_flow.collect_stacking_contexts(state);
788                 true
789             },
790             // FIXME: In the future, if #15144 is fixed we can remove this case. See #18510.
791             SpecificFragmentInfo::TruncatedFragment(ref mut info) => info.full
792                 .collect_stacking_contexts_for_blocklike_fragment(state),
793             _ => false,
794         }
795     }
796 
build_display_list_for_background_if_applicable( &self, state: &mut DisplayListBuildState, style: &ComputedValues, display_list_section: DisplayListSection, absolute_bounds: &Rect<Au>, )797     fn build_display_list_for_background_if_applicable(
798         &self,
799         state: &mut DisplayListBuildState,
800         style: &ComputedValues,
801         display_list_section: DisplayListSection,
802         absolute_bounds: &Rect<Au>,
803     ) {
804         let background = style.get_background();
805         let background_color = style.resolve_color(background.background_color);
806         // XXXManishearth the below method should ideally use an iterator over
807         // backgrounds
808         self.build_display_list_for_background_if_applicable_with_background(
809             state, style, background, background_color, display_list_section, absolute_bounds)
810     }
811 
build_display_list_for_background_if_applicable_with_background( &self, state: &mut DisplayListBuildState, style: &ComputedValues, background: &style_structs::Background, background_color: RGBA, display_list_section: DisplayListSection, absolute_bounds: &Rect<Au>, )812     fn build_display_list_for_background_if_applicable_with_background(
813         &self,
814         state: &mut DisplayListBuildState,
815         style: &ComputedValues,
816         background: &style_structs::Background,
817         background_color: RGBA,
818         display_list_section: DisplayListSection,
819         absolute_bounds: &Rect<Au>,
820     ) {
821         // FIXME: This causes a lot of background colors to be displayed when they are clearly not
822         // needed. We could use display list optimization to clean this up, but it still seems
823         // inefficient. What we really want is something like "nearest ancestor element that
824         // doesn't have a fragment".
825 
826         // 'background-clip' determines the area within which the background is painted.
827         // http://dev.w3.org/csswg/css-backgrounds-3/#the-background-clip
828         let mut bounds = *absolute_bounds;
829 
830         // This is the clip for the color (which is the last element in the bg array)
831         // Background clips are never empty.
832         let color_clip = &background.background_clip.0.last().unwrap();
833 
834         // Adjust the clipping region as necessary to account for `border-radius`.
835         let mut border_radii = build_border_radius(absolute_bounds, style.get_border());
836 
837         match **color_clip {
838             BackgroundClip::BorderBox => {},
839             BackgroundClip::PaddingBox => {
840                 let border = style.logical_border_width().to_physical(style.writing_mode);
841                 bounds = bounds.inner_rect(border);
842                 border_radii = calculate_inner_border_radii(border_radii, border);
843             },
844             BackgroundClip::ContentBox => {
845                 let border_padding = self.border_padding.to_physical(style.writing_mode);
846                 bounds = bounds.inner_rect(border_padding);
847                 border_radii = calculate_inner_border_radii(border_radii, border_padding);
848             },
849         }
850 
851         let previous_clipping_and_scrolling = state.current_clipping_and_scrolling;
852         if !border_radii.is_zero() {
853             let clip_id = state.add_late_clip_node(bounds.to_layout(), border_radii);
854             state.current_clipping_and_scrolling = ClippingAndScrolling::simple(clip_id);
855         }
856 
857         let base = state.create_base_display_item(
858             &bounds,
859             LocalClip::Rect(bounds.to_layout()),
860             self.node,
861             style.get_cursor(CursorKind::Default),
862             display_list_section,
863         );
864         state.add_display_item(DisplayItem::SolidColor(Box::new(SolidColorDisplayItem {
865             base: base,
866             color: background_color.to_layout(),
867         })));
868 
869         state.current_clipping_and_scrolling = previous_clipping_and_scrolling;
870 
871         // The background image is painted on top of the background color.
872         // Implements background image, per spec:
873         // http://www.w3.org/TR/CSS21/colors.html#background
874         let background = style.get_background();
875         for (i, background_image) in background.background_image.0.iter().enumerate().rev() {
876             match *background_image {
877                 Either::First(_) => {},
878                 Either::Second(Image::Gradient(ref gradient)) => {
879                     self.build_display_list_for_background_gradient(
880                         state,
881                         display_list_section,
882                         *absolute_bounds,
883                         gradient,
884                         style,
885                         i,
886                     );
887                 },
888                 Either::Second(Image::Url(ref image_url)) => {
889                     if let Some(url) = image_url.url() {
890                         let webrender_image = state.layout_context.get_webrender_image_for_url(
891                             self.node,
892                             url.clone(),
893                             UsePlaceholder::No,
894                         );
895                         if let Some(webrender_image) = webrender_image {
896                             self.build_display_list_for_webrender_image(
897                                 state,
898                                 style,
899                                 display_list_section,
900                                 *absolute_bounds,
901                                 webrender_image,
902                                 i,
903                             );
904                         }
905                     }
906                 },
907                 Either::Second(Image::PaintWorklet(ref paint_worklet)) => {
908                     let bounding_box = self.border_box - style.logical_border_width();
909                     let bounding_box_size = bounding_box.size.to_physical(style.writing_mode);
910                     let background_size =
911                         get_cyclic(&style.get_background().background_size.0, i).clone();
912                     let size = match background_size {
913                         BackgroundSize::Explicit { width, height } => Size2D::new(
914                             MaybeAuto::from_style(width, bounding_box_size.width)
915                                 .specified_or_default(bounding_box_size.width),
916                             MaybeAuto::from_style(height, bounding_box_size.height)
917                                 .specified_or_default(bounding_box_size.height),
918                         ),
919                         _ => bounding_box_size,
920                     };
921                     let webrender_image = self.get_webrender_image_for_paint_worklet(
922                         state,
923                         style,
924                         paint_worklet,
925                         size,
926                     );
927                     if let Some(webrender_image) = webrender_image {
928                         self.build_display_list_for_webrender_image(
929                             state,
930                             style,
931                             display_list_section,
932                             *absolute_bounds,
933                             webrender_image,
934                             i,
935                         );
936                     }
937                 },
938                 Either::Second(Image::Rect(_)) => {
939                     // TODO: Implement `-moz-image-rect`
940                 },
941                 Either::Second(Image::Element(_)) => {
942                     // TODO: Implement `-moz-element`
943                 },
944             }
945         }
946     }
947 
build_display_list_for_webrender_image( &self, state: &mut DisplayListBuildState, style: &ComputedValues, display_list_section: DisplayListSection, absolute_bounds: Rect<Au>, webrender_image: WebRenderImageInfo, index: usize, )948     fn build_display_list_for_webrender_image(
949         &self,
950         state: &mut DisplayListBuildState,
951         style: &ComputedValues,
952         display_list_section: DisplayListSection,
953         absolute_bounds: Rect<Au>,
954         webrender_image: WebRenderImageInfo,
955         index: usize,
956     ) {
957         debug!("(building display list) building background image");
958 
959         let image = Size2D::new(
960             Au::from_px(webrender_image.width as i32),
961             Au::from_px(webrender_image.height as i32),
962         );
963         let placement = compute_background_placement(
964             style.get_background(),
965             state.layout_context.shared_context().viewport_size(),
966             absolute_bounds,
967             Some(image),
968             style.logical_border_width().to_physical(style.writing_mode),
969             self.border_padding.to_physical(style.writing_mode),
970             index,
971         );
972 
973         // Create the image display item.
974         let base = state.create_base_display_item(
975             &placement.bounds,
976             LocalClip::Rect(placement.css_clip.to_layout()),
977             self.node,
978             style.get_cursor(CursorKind::Default),
979             display_list_section,
980         );
981 
982         debug!("(building display list) adding background image.");
983         state.add_display_item(DisplayItem::Image(Box::new(ImageDisplayItem {
984             base: base,
985             webrender_image: webrender_image,
986             stretch_size: placement.tile_size.to_layout(),
987             tile_spacing: placement.tile_spacing.to_layout(),
988             image_rendering: style.get_inheritedbox().image_rendering.to_layout(),
989         })));
990     }
991 
get_webrender_image_for_paint_worklet( &self, state: &mut DisplayListBuildState, style: &ComputedValues, paint_worklet: &PaintWorklet, size_in_au: Size2D<Au>, ) -> Option<WebRenderImageInfo>992     fn get_webrender_image_for_paint_worklet(
993         &self,
994         state: &mut DisplayListBuildState,
995         style: &ComputedValues,
996         paint_worklet: &PaintWorklet,
997         size_in_au: Size2D<Au>,
998     ) -> Option<WebRenderImageInfo> {
999         let device_pixel_ratio = state.layout_context.style_context.device_pixel_ratio();
1000         let size_in_px =
1001             TypedSize2D::new(size_in_au.width.to_f32_px(), size_in_au.height.to_f32_px());
1002 
1003         // TODO: less copying.
1004         let name = paint_worklet.name.clone();
1005         let arguments = paint_worklet
1006             .arguments
1007             .iter()
1008             .map(|argument| argument.to_css_string())
1009             .collect();
1010 
1011         let draw_result = match state.layout_context.registered_painters.get(&name) {
1012             Some(painter) => {
1013                 debug!(
1014                     "Drawing a paint image {}({},{}).",
1015                     name, size_in_px.width, size_in_px.height
1016                 );
1017                 let properties = painter
1018                     .properties()
1019                     .iter()
1020                     .filter_map(|(name, id)| id.as_shorthand().err().map(|id| (name, id)))
1021                     .map(|(name, id)| (name.clone(), style.computed_value_to_string(id)))
1022                     .collect();
1023                 painter.draw_a_paint_image(size_in_px, device_pixel_ratio, properties, arguments)
1024             },
1025             None => {
1026                 debug!("Worklet {} called before registration.", name);
1027                 return None;
1028             },
1029         };
1030 
1031         if let Ok(draw_result) = draw_result {
1032             let webrender_image = WebRenderImageInfo {
1033                 width: draw_result.width,
1034                 height: draw_result.height,
1035                 format: draw_result.format,
1036                 key: draw_result.image_key,
1037             };
1038 
1039             for url in draw_result.missing_image_urls.into_iter() {
1040                 debug!("Requesting missing image URL {}.", url);
1041                 state.layout_context.get_webrender_image_for_url(
1042                     self.node,
1043                     url,
1044                     UsePlaceholder::No,
1045                 );
1046             }
1047             Some(webrender_image)
1048         } else {
1049             None
1050         }
1051     }
1052 
build_display_list_for_background_gradient( &self, state: &mut DisplayListBuildState, display_list_section: DisplayListSection, absolute_bounds: Rect<Au>, gradient: &Gradient, style: &ComputedValues, index: usize, )1053     fn build_display_list_for_background_gradient(
1054         &self,
1055         state: &mut DisplayListBuildState,
1056         display_list_section: DisplayListSection,
1057         absolute_bounds: Rect<Au>,
1058         gradient: &Gradient,
1059         style: &ComputedValues,
1060         index: usize,
1061     ) {
1062         let placement = compute_background_placement(
1063             style.get_background(),
1064             state.layout_context.shared_context().viewport_size(),
1065             absolute_bounds,
1066             None,
1067             style.logical_border_width().to_physical(style.writing_mode),
1068             self.border_padding.to_physical(style.writing_mode),
1069             index,
1070         );
1071 
1072         let base = state.create_base_display_item(
1073             &placement.bounds,
1074             LocalClip::Rect(placement.css_clip.to_layout()),
1075             self.node,
1076             style.get_cursor(CursorKind::Default),
1077             display_list_section,
1078         );
1079 
1080         let display_item = match gradient.kind {
1081             GradientKind::Linear(angle_or_corner) => {
1082                 let gradient = convert_linear_gradient(
1083                     placement.tile_size,
1084                     &gradient.items[..],
1085                     angle_or_corner,
1086                     gradient.repeating,
1087                 );
1088                 DisplayItem::Gradient(Box::new(GradientDisplayItem {
1089                     base: base,
1090                     gradient: gradient,
1091                     tile: placement.tile_size.to_layout(),
1092                     tile_spacing: placement.tile_spacing.to_layout(),
1093                 }))
1094             },
1095             GradientKind::Radial(shape, center, _angle) => {
1096                 let gradient = convert_radial_gradient(
1097                     placement.tile_size,
1098                     &gradient.items[..],
1099                     shape,
1100                     center,
1101                     gradient.repeating,
1102                 );
1103                 DisplayItem::RadialGradient(Box::new(RadialGradientDisplayItem {
1104                     base: base,
1105                     gradient: gradient,
1106                     tile: placement.tile_size.to_layout(),
1107                     tile_spacing: placement.tile_spacing.to_layout(),
1108                 }))
1109             },
1110         };
1111         state.add_display_item(display_item);
1112     }
1113 
build_display_list_for_box_shadow_if_applicable( &self, state: &mut DisplayListBuildState, style: &ComputedValues, display_list_section: DisplayListSection, absolute_bounds: &Rect<Au>, clip: &Rect<Au>, )1114     fn build_display_list_for_box_shadow_if_applicable(
1115         &self,
1116         state: &mut DisplayListBuildState,
1117         style: &ComputedValues,
1118         display_list_section: DisplayListSection,
1119         absolute_bounds: &Rect<Au>,
1120         clip: &Rect<Au>,
1121     ) {
1122         // NB: According to CSS-BACKGROUNDS, box shadows render in *reverse* order (front to back).
1123         for box_shadow in style.get_effects().box_shadow.0.iter().rev() {
1124             let bounds = shadow_bounds(
1125                 &absolute_bounds.translate(&Vector2D::new(
1126                     Au::from(box_shadow.base.horizontal),
1127                     Au::from(box_shadow.base.vertical),
1128                 )),
1129                 Au::from(box_shadow.base.blur),
1130                 Au::from(box_shadow.spread),
1131             );
1132 
1133             let base = state.create_base_display_item(
1134                 &bounds,
1135                 LocalClip::from(clip.to_layout()),
1136                 self.node,
1137                 style.get_cursor(CursorKind::Default),
1138                 display_list_section,
1139             );
1140             let border_radius = build_border_radius(absolute_bounds, style.get_border());
1141             state.add_display_item(DisplayItem::BoxShadow(Box::new(BoxShadowDisplayItem {
1142                 base: base,
1143                 box_bounds: absolute_bounds.to_layout(),
1144                 color: box_shadow
1145                     .base
1146                     .color
1147                     .unwrap_or(style.get_color().color)
1148                     .to_layout(),
1149                 offset: LayoutVector2D::new(
1150                     box_shadow.base.horizontal.px(),
1151                     box_shadow.base.vertical.px(),
1152                 ),
1153                 blur_radius: box_shadow.base.blur.px(),
1154                 spread_radius: box_shadow.spread.px(),
1155                 border_radius: border_radius,
1156                 clip_mode: if box_shadow.inset {
1157                     BoxShadowClipMode::Inset
1158                 } else {
1159                     BoxShadowClipMode::Outset
1160                 },
1161             })));
1162         }
1163     }
1164 
build_display_list_for_borders_if_applicable( &self, state: &mut DisplayListBuildState, style: &ComputedValues, inline_info: Option<InlineNodeBorderInfo>, border_painting_mode: BorderPaintingMode, bounds: &Rect<Au>, display_list_section: DisplayListSection, clip: &Rect<Au>, )1165     fn build_display_list_for_borders_if_applicable(
1166         &self,
1167         state: &mut DisplayListBuildState,
1168         style: &ComputedValues,
1169         inline_info: Option<InlineNodeBorderInfo>,
1170         border_painting_mode: BorderPaintingMode,
1171         bounds: &Rect<Au>,
1172         display_list_section: DisplayListSection,
1173         clip: &Rect<Au>,
1174     ) {
1175         let mut border = style.logical_border_width();
1176 
1177         if let Some(inline_info) = inline_info {
1178             modify_border_width_for_inline_sides(&mut border, inline_info);
1179         }
1180 
1181         match border_painting_mode {
1182             BorderPaintingMode::Separate => {},
1183             BorderPaintingMode::Collapse(collapsed_borders) => {
1184                 collapsed_borders.adjust_border_widths_for_painting(&mut border)
1185             },
1186             BorderPaintingMode::Hidden => return,
1187         }
1188         if border.is_zero() {
1189             // TODO: check if image-border-outset is zero
1190             return;
1191         }
1192 
1193         let border_style_struct = style.get_border();
1194         let mut colors = SideOffsets2D::new(
1195             border_style_struct.border_top_color,
1196             border_style_struct.border_right_color,
1197             border_style_struct.border_bottom_color,
1198             border_style_struct.border_left_color,
1199         );
1200         let mut border_style = SideOffsets2D::new(
1201             border_style_struct.border_top_style,
1202             border_style_struct.border_right_style,
1203             border_style_struct.border_bottom_style,
1204             border_style_struct.border_left_style,
1205         );
1206 
1207         if let BorderPaintingMode::Collapse(collapsed_borders) = border_painting_mode {
1208             collapsed_borders.adjust_border_colors_and_styles_for_painting(
1209                 &mut colors,
1210                 &mut border_style,
1211                 style.writing_mode,
1212             );
1213         }
1214 
1215         // If this border collapses, then we draw outside the boundaries we were given.
1216         let mut bounds = *bounds;
1217         if let BorderPaintingMode::Collapse(collapsed_borders) = border_painting_mode {
1218             collapsed_borders.adjust_border_bounds_for_painting(&mut bounds, style.writing_mode)
1219         }
1220 
1221         // Append the border to the display list.
1222         let base = state.create_base_display_item(
1223             &bounds,
1224             LocalClip::from(clip.to_layout()),
1225             self.node,
1226             style.get_cursor(CursorKind::Default),
1227             display_list_section,
1228         );
1229 
1230         let border_radius = build_border_radius(&bounds, border_style_struct);
1231 
1232         let details = match border_style_struct.border_image_source {
1233             Either::First(_) => Some(BorderDetails::Normal(NormalBorder {
1234                 left: BorderSide {
1235                     color: style.resolve_color(colors.left).to_layout(),
1236                     style: border_style.left.to_layout(),
1237                 },
1238                 right: BorderSide {
1239                     color: style.resolve_color(colors.right).to_layout(),
1240                     style: border_style.right.to_layout(),
1241                 },
1242                 top: BorderSide {
1243                     color: style.resolve_color(colors.top).to_layout(),
1244                     style: border_style.top.to_layout(),
1245                 },
1246                 bottom: BorderSide {
1247                     color: style.resolve_color(colors.bottom).to_layout(),
1248                     style: border_style.bottom.to_layout(),
1249                 },
1250                 radius: border_radius,
1251             })),
1252             Either::Second(Image::Gradient(ref gradient)) => {
1253                 Some(match gradient.kind {
1254                     GradientKind::Linear(angle_or_corner) => {
1255                         BorderDetails::Gradient(display_list::GradientBorder {
1256                             gradient: convert_linear_gradient(
1257                                 bounds.size,
1258                                 &gradient.items[..],
1259                                 angle_or_corner,
1260                                 gradient.repeating,
1261                             ),
1262                             // TODO(gw): Support border-image-outset
1263                             outset: SideOffsets2D::zero(),
1264                         })
1265                     },
1266                     GradientKind::Radial(shape, center, _angle) => {
1267                         BorderDetails::RadialGradient(display_list::RadialGradientBorder {
1268                             gradient: convert_radial_gradient(
1269                                 bounds.size,
1270                                 &gradient.items[..],
1271                                 shape,
1272                                 center,
1273                                 gradient.repeating,
1274                             ),
1275                             // TODO(gw): Support border-image-outset
1276                             outset: SideOffsets2D::zero(),
1277                         })
1278                     },
1279                 })
1280             },
1281             Either::Second(Image::PaintWorklet(ref paint_worklet)) => {
1282                 // TODO: this size should be increased by border-image-outset
1283                 let size = self.border_box.size.to_physical(style.writing_mode);
1284                 self.get_webrender_image_for_paint_worklet(state, style, paint_worklet, size)
1285                     .and_then(|image| build_image_border_details(image, border_style_struct))
1286             },
1287             Either::Second(Image::Rect(..)) => {
1288                 // TODO: Handle border-image with `-moz-image-rect`.
1289                 None
1290             },
1291             Either::Second(Image::Element(..)) => {
1292                 // TODO: Handle border-image with `-moz-element`.
1293                 None
1294             },
1295             Either::Second(Image::Url(ref image_url)) => image_url
1296                 .url()
1297                 .and_then(|url| {
1298                     state.layout_context.get_webrender_image_for_url(
1299                         self.node,
1300                         url.clone(),
1301                         UsePlaceholder::No,
1302                     )
1303                 })
1304                 .and_then(|image| build_image_border_details(image, border_style_struct)),
1305         };
1306         if let Some(details) = details {
1307             state.add_display_item(DisplayItem::Border(Box::new(BorderDisplayItem {
1308                 base,
1309                 border_widths: border.to_physical(style.writing_mode).to_layout(),
1310                 details,
1311             })));
1312         }
1313     }
1314 
build_display_list_for_outline_if_applicable( &self, state: &mut DisplayListBuildState, style: &ComputedValues, bounds: &Rect<Au>, clip: &Rect<Au>, )1315     fn build_display_list_for_outline_if_applicable(
1316         &self,
1317         state: &mut DisplayListBuildState,
1318         style: &ComputedValues,
1319         bounds: &Rect<Au>,
1320         clip: &Rect<Au>,
1321     ) {
1322         use style::values::specified::outline::OutlineStyle;
1323 
1324         let width = Au::from(style.get_outline().outline_width);
1325         if width == Au(0) {
1326             return;
1327         }
1328 
1329         let outline_style = match style.get_outline().outline_style {
1330             OutlineStyle::Auto => BorderStyle::Solid,
1331             OutlineStyle::Other(BorderStyle::None) => return,
1332             OutlineStyle::Other(border_style) => border_style,
1333         };
1334 
1335         // Outlines are not accounted for in the dimensions of the border box, so adjust the
1336         // absolute bounds.
1337         let mut bounds = *bounds;
1338         let offset = width + Au::from(style.get_outline().outline_offset);
1339         bounds = bounds.inflate(offset, offset);
1340 
1341         // Append the outline to the display list.
1342         let color = style
1343             .resolve_color(style.get_outline().outline_color)
1344             .to_layout();
1345         let base = state.create_base_display_item(
1346             &bounds,
1347             LocalClip::from(clip.to_layout()),
1348             self.node,
1349             style.get_cursor(CursorKind::Default),
1350             DisplayListSection::Outlines,
1351         );
1352         state.add_display_item(DisplayItem::Border(Box::new(BorderDisplayItem {
1353             base: base,
1354             border_widths: SideOffsets2D::new_all_same(width).to_layout(),
1355             details: BorderDetails::Normal(simple_normal_border(color, outline_style.to_layout())),
1356         })));
1357     }
1358 
build_debug_borders_around_text_fragments( &self, state: &mut DisplayListBuildState, style: &ComputedValues, stacking_relative_border_box: &Rect<Au>, stacking_relative_content_box: &Rect<Au>, text_fragment: &ScannedTextFragmentInfo, clip: &Rect<Au>, )1359     fn build_debug_borders_around_text_fragments(
1360         &self,
1361         state: &mut DisplayListBuildState,
1362         style: &ComputedValues,
1363         stacking_relative_border_box: &Rect<Au>,
1364         stacking_relative_content_box: &Rect<Au>,
1365         text_fragment: &ScannedTextFragmentInfo,
1366         clip: &Rect<Au>,
1367     ) {
1368         // FIXME(pcwalton, #2795): Get the real container size.
1369         let container_size = Size2D::zero();
1370 
1371         // Compute the text fragment bounds and draw a border surrounding them.
1372         let base = state.create_base_display_item(
1373             stacking_relative_border_box,
1374             LocalClip::from(clip.to_layout()),
1375             self.node,
1376             style.get_cursor(CursorKind::Default),
1377             DisplayListSection::Content,
1378         );
1379         state.add_display_item(DisplayItem::Border(Box::new(BorderDisplayItem {
1380             base: base,
1381             border_widths: SideOffsets2D::new_all_same(Au::from_px(1)).to_layout(),
1382             details: BorderDetails::Normal(simple_normal_border(
1383                 ColorF::rgb(0, 0, 200),
1384                 webrender_api::BorderStyle::Solid,
1385             )),
1386         })));
1387 
1388         // Draw a rectangle representing the baselines.
1389         let mut baseline = LogicalRect::from_physical(
1390             self.style.writing_mode,
1391             *stacking_relative_content_box,
1392             container_size,
1393         );
1394         baseline.start.b = baseline.start.b + text_fragment.run.ascent();
1395         baseline.size.block = Au(0);
1396         let baseline = baseline.to_physical(self.style.writing_mode, container_size);
1397 
1398         let base = state.create_base_display_item(
1399             &baseline,
1400             LocalClip::from(clip.to_layout()),
1401             self.node,
1402             style.get_cursor(CursorKind::Default),
1403             DisplayListSection::Content,
1404         );
1405         state.add_display_item(DisplayItem::Line(Box::new(LineDisplayItem {
1406             base: base,
1407             color: ColorF::rgb(0, 200, 0),
1408             style: LineStyle::Dashed,
1409         })));
1410     }
1411 
build_debug_borders_around_fragment( &self, state: &mut DisplayListBuildState, stacking_relative_border_box: &Rect<Au>, clip: &Rect<Au>, )1412     fn build_debug_borders_around_fragment(
1413         &self,
1414         state: &mut DisplayListBuildState,
1415         stacking_relative_border_box: &Rect<Au>,
1416         clip: &Rect<Au>,
1417     ) {
1418         // This prints a debug border around the border of this fragment.
1419         let base = state.create_base_display_item(
1420             stacking_relative_border_box,
1421             LocalClip::from(clip.to_layout()),
1422             self.node,
1423             self.style.get_cursor(CursorKind::Default),
1424             DisplayListSection::Content,
1425         );
1426         state.add_display_item(DisplayItem::Border(Box::new(BorderDisplayItem {
1427             base: base,
1428             border_widths: SideOffsets2D::new_all_same(Au::from_px(1)).to_layout(),
1429             details: BorderDetails::Normal(simple_normal_border(
1430                 ColorF::rgb(0, 0, 200),
1431                 webrender_api::BorderStyle::Solid,
1432             )),
1433         })));
1434     }
1435 
build_display_items_for_selection_if_necessary( &self, state: &mut DisplayListBuildState, stacking_relative_border_box: &Rect<Au>, display_list_section: DisplayListSection, clip: &Rect<Au>, )1436     fn build_display_items_for_selection_if_necessary(
1437         &self,
1438         state: &mut DisplayListBuildState,
1439         stacking_relative_border_box: &Rect<Au>,
1440         display_list_section: DisplayListSection,
1441         clip: &Rect<Au>,
1442     ) {
1443         let scanned_text_fragment_info = match self.specific {
1444             SpecificFragmentInfo::ScannedText(ref scanned_text_fragment_info) => {
1445                 scanned_text_fragment_info
1446             },
1447             _ => return,
1448         };
1449 
1450         // Draw a highlighted background if the text is selected.
1451         //
1452         // TODO: Allow non-text fragments to be selected too.
1453         if scanned_text_fragment_info.selected() {
1454             let style = self.selected_style();
1455             let background_color = style.resolve_color(style.get_background().background_color);
1456             let base = state.create_base_display_item(
1457                 stacking_relative_border_box,
1458                 LocalClip::from(clip.to_layout()),
1459                 self.node,
1460                 self.style.get_cursor(CursorKind::Default),
1461                 display_list_section,
1462             );
1463             state.add_display_item(DisplayItem::SolidColor(Box::new(SolidColorDisplayItem {
1464                 base: base,
1465                 color: background_color.to_layout(),
1466             })));
1467         }
1468 
1469         // Draw a caret at the insertion point.
1470         let insertion_point_index = match scanned_text_fragment_info.insertion_point {
1471             Some(insertion_point_index) => insertion_point_index,
1472             None => return,
1473         };
1474         let range = Range::new(
1475             scanned_text_fragment_info.range.begin(),
1476             insertion_point_index - scanned_text_fragment_info.range.begin(),
1477         );
1478         let advance = scanned_text_fragment_info.run.advance_for_range(&range);
1479 
1480         let insertion_point_bounds;
1481         let cursor;
1482         if !self.style.writing_mode.is_vertical() {
1483             insertion_point_bounds = rect(
1484                 stacking_relative_border_box.origin.x + advance,
1485                 stacking_relative_border_box.origin.y,
1486                 INSERTION_POINT_LOGICAL_WIDTH,
1487                 stacking_relative_border_box.size.height,
1488             );
1489             cursor = CursorKind::Text;
1490         } else {
1491             insertion_point_bounds = rect(
1492                 stacking_relative_border_box.origin.x,
1493                 stacking_relative_border_box.origin.y + advance,
1494                 stacking_relative_border_box.size.width,
1495                 INSERTION_POINT_LOGICAL_WIDTH,
1496             );
1497             cursor = CursorKind::VerticalText;
1498         };
1499 
1500         let base = state.create_base_display_item(
1501             &insertion_point_bounds,
1502             LocalClip::from(clip.to_layout()),
1503             self.node,
1504             self.style.get_cursor(cursor),
1505             display_list_section,
1506         );
1507         state.add_display_item(DisplayItem::SolidColor(Box::new(SolidColorDisplayItem {
1508             base: base,
1509             color: self.style().get_color().color.to_layout(),
1510         })));
1511     }
1512 
build_display_list( &mut self, state: &mut DisplayListBuildState, stacking_relative_border_box: Rect<Au>, border_painting_mode: BorderPaintingMode, display_list_section: DisplayListSection, clip: &Rect<Au>, )1513     fn build_display_list(
1514         &mut self,
1515         state: &mut DisplayListBuildState,
1516         stacking_relative_border_box: Rect<Au>,
1517         border_painting_mode: BorderPaintingMode,
1518         display_list_section: DisplayListSection,
1519         clip: &Rect<Au>,
1520     ) {
1521         self.restyle_damage.remove(ServoRestyleDamage::REPAINT);
1522         self.build_display_list_no_damage(state, stacking_relative_border_box,
1523                                 border_painting_mode, display_list_section, clip)
1524     }
1525 
build_display_list_no_damage( &self, state: &mut DisplayListBuildState, stacking_relative_border_box: Rect<Au>, border_painting_mode: BorderPaintingMode, display_list_section: DisplayListSection, clip: &Rect<Au>, )1526     fn build_display_list_no_damage(
1527         &self,
1528         state: &mut DisplayListBuildState,
1529         stacking_relative_border_box: Rect<Au>,
1530         border_painting_mode: BorderPaintingMode,
1531         display_list_section: DisplayListSection,
1532         clip: &Rect<Au>,
1533     ) {
1534         if self.style().get_inheritedbox().visibility != Visibility::Visible {
1535             return;
1536         }
1537 
1538         debug!(
1539             "Fragment::build_display_list at rel={:?}, abs={:?}: {:?}",
1540             self.border_box, stacking_relative_border_box, self
1541         );
1542 
1543         // Check the clip rect. If there's nothing to render at all, don't even construct display
1544         // list items.
1545         let empty_rect = !clip.intersects(&stacking_relative_border_box);
1546         if self.is_primary_fragment() && !empty_rect {
1547             // Add shadows, background, borders, and outlines, if applicable.
1548             if let Some(ref inline_context) = self.inline_context {
1549                 for node in inline_context.nodes.iter().rev() {
1550                     self.build_display_list_for_background_if_applicable(
1551                         state,
1552                         &*node.style,
1553                         display_list_section,
1554                         &stacking_relative_border_box,
1555                     );
1556 
1557                     self.build_display_list_for_box_shadow_if_applicable(
1558                         state,
1559                         &*node.style,
1560                         display_list_section,
1561                         &stacking_relative_border_box,
1562                         clip,
1563                     );
1564 
1565                     self.build_display_list_for_borders_if_applicable(
1566                         state,
1567                         &*node.style,
1568                         Some(InlineNodeBorderInfo {
1569                             is_first_fragment_of_element: node.flags
1570                                 .contains(InlineFragmentNodeFlags::FIRST_FRAGMENT_OF_ELEMENT),
1571                             is_last_fragment_of_element: node.flags
1572                                 .contains(InlineFragmentNodeFlags::LAST_FRAGMENT_OF_ELEMENT),
1573                         }),
1574                         border_painting_mode,
1575                         &stacking_relative_border_box,
1576                         display_list_section,
1577                         clip,
1578                     );
1579 
1580                     // FIXME(emilio): Why does outline not do the same width
1581                     // fixup as border?
1582                     self.build_display_list_for_outline_if_applicable(
1583                         state,
1584                         &*node.style,
1585                         &stacking_relative_border_box,
1586                         clip,
1587                     );
1588                 }
1589             }
1590 
1591             if !self.is_scanned_text_fragment() {
1592                 self.build_display_list_for_background_if_applicable(
1593                     state,
1594                     &*self.style,
1595                     display_list_section,
1596                     &stacking_relative_border_box,
1597                 );
1598 
1599                 self.build_display_list_for_box_shadow_if_applicable(
1600                     state,
1601                     &*self.style,
1602                     display_list_section,
1603                     &stacking_relative_border_box,
1604                     clip,
1605                 );
1606 
1607                 self.build_display_list_for_borders_if_applicable(
1608                     state,
1609                     &*self.style,
1610                     /* inline_node_info = */ None,
1611                     border_painting_mode,
1612                     &stacking_relative_border_box,
1613                     display_list_section,
1614                     clip,
1615                 );
1616 
1617                 self.build_display_list_for_outline_if_applicable(
1618                     state,
1619                     &*self.style,
1620                     &stacking_relative_border_box,
1621                     clip,
1622                 );
1623             }
1624         }
1625 
1626         if self.is_primary_fragment() {
1627             // Paint the selection point if necessary.  Even an empty text fragment may have an
1628             // insertion point, so we do this even if `empty_rect` is true.
1629             self.build_display_items_for_selection_if_necessary(
1630                 state,
1631                 &stacking_relative_border_box,
1632                 display_list_section,
1633                 clip,
1634             );
1635         }
1636 
1637         if empty_rect {
1638             return;
1639         }
1640 
1641         debug!("Fragment::build_display_list: intersected. Adding display item...");
1642 
1643         // Create special per-fragment-type display items.
1644         self.build_fragment_type_specific_display_items(state, &stacking_relative_border_box, clip);
1645 
1646         if opts::get().show_debug_fragment_borders {
1647             self.build_debug_borders_around_fragment(state, &stacking_relative_border_box, clip)
1648         }
1649     }
1650 
build_fragment_type_specific_display_items( &self, state: &mut DisplayListBuildState, stacking_relative_border_box: &Rect<Au>, clip: &Rect<Au>, )1651     fn build_fragment_type_specific_display_items(
1652         &self,
1653         state: &mut DisplayListBuildState,
1654         stacking_relative_border_box: &Rect<Au>,
1655         clip: &Rect<Au>,
1656     ) {
1657         let previous_clipping_and_scrolling = state.current_clipping_and_scrolling;
1658 
1659         // Compute the context box position relative to the parent stacking context.
1660         let stacking_relative_content_box =
1661             self.stacking_relative_content_box(stacking_relative_border_box);
1662 
1663         let create_base_display_item = |state: &mut DisplayListBuildState| {
1664             let layout_rect = stacking_relative_border_box.to_layout();
1665 
1666             // Adjust the clipping region as necessary to account for `border-radius`.
1667             let radii =
1668                 build_border_radius_for_inner_rect(&stacking_relative_border_box, &self.style);
1669 
1670             if !radii.is_zero() {
1671                 let clip_id = state.add_late_clip_node(layout_rect, radii);
1672                 state.current_clipping_and_scrolling = ClippingAndScrolling::simple(clip_id);
1673             }
1674 
1675             state.create_base_display_item(
1676                 &stacking_relative_content_box,
1677                 LocalClip::Rect(layout_rect),
1678                 self.node,
1679                 self.style.get_cursor(CursorKind::Default),
1680                 DisplayListSection::Content,
1681             )
1682         };
1683 
1684         match self.specific {
1685             SpecificFragmentInfo::TruncatedFragment(ref truncated_fragment)
1686                 if truncated_fragment.text_info.is_some() =>
1687             {
1688                 let text_fragment = truncated_fragment.text_info.as_ref().unwrap();
1689                 // Create the main text display item.
1690                 self.build_display_list_for_text_fragment(
1691                     state,
1692                     &text_fragment,
1693                     &stacking_relative_content_box,
1694                     &self.style.get_inheritedtext().text_shadow.0,
1695                     clip,
1696                 );
1697 
1698                 if opts::get().show_debug_fragment_borders {
1699                     self.build_debug_borders_around_text_fragments(
1700                         state,
1701                         self.style(),
1702                         stacking_relative_border_box,
1703                         &stacking_relative_content_box,
1704                         &text_fragment,
1705                         clip,
1706                     );
1707                 }
1708             }
1709             SpecificFragmentInfo::ScannedText(ref text_fragment) => {
1710                 // Create the main text display item.
1711                 self.build_display_list_for_text_fragment(
1712                     state,
1713                     &text_fragment,
1714                     &stacking_relative_content_box,
1715                     &self.style.get_inheritedtext().text_shadow.0,
1716                     clip,
1717                 );
1718 
1719                 if opts::get().show_debug_fragment_borders {
1720                     self.build_debug_borders_around_text_fragments(
1721                         state,
1722                         self.style(),
1723                         stacking_relative_border_box,
1724                         &stacking_relative_content_box,
1725                         &text_fragment,
1726                         clip,
1727                     );
1728                 }
1729             },
1730             SpecificFragmentInfo::Generic |
1731             SpecificFragmentInfo::GeneratedContent(..) |
1732             SpecificFragmentInfo::Table |
1733             SpecificFragmentInfo::TableCell |
1734             SpecificFragmentInfo::TableRow |
1735             SpecificFragmentInfo::TableWrapper |
1736             SpecificFragmentInfo::Multicol |
1737             SpecificFragmentInfo::MulticolColumn |
1738             SpecificFragmentInfo::InlineBlock(_) |
1739             SpecificFragmentInfo::InlineAbsoluteHypothetical(_) |
1740             SpecificFragmentInfo::InlineAbsolute(_) |
1741             SpecificFragmentInfo::TruncatedFragment(_) |
1742             SpecificFragmentInfo::Svg(_) => {
1743                 if opts::get().show_debug_fragment_borders {
1744                     self.build_debug_borders_around_fragment(
1745                         state,
1746                         stacking_relative_border_box,
1747                         clip,
1748                     );
1749                 }
1750             },
1751             SpecificFragmentInfo::Iframe(ref fragment_info) => {
1752                 if !stacking_relative_content_box.is_empty() {
1753                     let browsing_context_id = match fragment_info.browsing_context_id {
1754                         Some(browsing_context_id) => browsing_context_id,
1755                         None => return warn!("No browsing context id for iframe."),
1756                     };
1757                     let pipeline_id = match fragment_info.pipeline_id {
1758                         Some(pipeline_id) => pipeline_id,
1759                         None => return warn!("No pipeline id for iframe {}.", browsing_context_id),
1760                     };
1761 
1762                     let base = create_base_display_item(state);
1763                     let item = DisplayItem::Iframe(Box::new(IframeDisplayItem {
1764                         base,
1765                         iframe: pipeline_id,
1766                     }));
1767 
1768                     let size = Size2D::new(item.bounds().size.width, item.bounds().size.height);
1769                     state
1770                         .iframe_sizes
1771                         .push((browsing_context_id, TypedSize2D::from_untyped(&size)));
1772 
1773                     state.add_display_item(item);
1774                 }
1775             },
1776             SpecificFragmentInfo::Image(ref image_fragment) => {
1777                 // Place the image into the display list.
1778                 if let Some(ref image) = image_fragment.image {
1779                     let base = create_base_display_item(state);
1780                     state.add_display_item(DisplayItem::Image(Box::new(ImageDisplayItem {
1781                         base,
1782                         webrender_image: WebRenderImageInfo::from_image(image),
1783                         stretch_size: stacking_relative_content_box.size.to_layout(),
1784                         tile_spacing: LayoutSize::zero(),
1785                         image_rendering: self.style.get_inheritedbox().image_rendering.to_layout(),
1786                     })));
1787                 }
1788             },
1789             SpecificFragmentInfo::Canvas(ref canvas_fragment_info) => {
1790                 let computed_width = canvas_fragment_info.dom_width.to_px();
1791                 let computed_height = canvas_fragment_info.dom_height.to_px();
1792 
1793                 let (image_key, format) = match canvas_fragment_info.source {
1794                     CanvasFragmentSource::WebGL(image_key) => (image_key, PixelFormat::BGRA8),
1795                     CanvasFragmentSource::Image(ref ipc_renderer) => match *ipc_renderer {
1796                         Some(ref ipc_renderer) => {
1797                             let ipc_renderer = ipc_renderer.lock().unwrap();
1798                             let (sender, receiver) = ipc::channel().unwrap();
1799                             ipc_renderer
1800                                 .send(CanvasMsg::FromLayout(FromLayoutMsg::SendData(sender)))
1801                                 .unwrap();
1802                             (receiver.recv().unwrap().image_key, PixelFormat::BGRA8)
1803                         },
1804                         None => return,
1805                     },
1806                 };
1807 
1808                 let base = create_base_display_item(state);
1809                 let display_item = DisplayItem::Image(Box::new(ImageDisplayItem {
1810                     base,
1811                     webrender_image: WebRenderImageInfo {
1812                         width: computed_width as u32,
1813                         height: computed_height as u32,
1814                         format: format,
1815                         key: Some(image_key),
1816                     },
1817                     stretch_size: stacking_relative_content_box.size.to_layout(),
1818                     tile_spacing: LayoutSize::zero(),
1819                     image_rendering: ImageRendering::Auto,
1820                 }));
1821 
1822                 state.add_display_item(display_item);
1823             },
1824             SpecificFragmentInfo::UnscannedText(_) => {
1825                 panic!("Shouldn't see unscanned fragments here.")
1826             },
1827             SpecificFragmentInfo::TableColumn(_) => {
1828                 panic!("Shouldn't see table column fragments here.")
1829             },
1830         }
1831 
1832         state.current_clipping_and_scrolling = previous_clipping_and_scrolling;
1833     }
1834 
create_stacking_context( &self, id: StackingContextId, base_flow: &BaseFlow, scroll_policy: ScrollPolicy, context_type: StackingContextType, parent_clipping_and_scrolling: ClippingAndScrolling, ) -> StackingContext1835     fn create_stacking_context(
1836         &self,
1837         id: StackingContextId,
1838         base_flow: &BaseFlow,
1839         scroll_policy: ScrollPolicy,
1840         context_type: StackingContextType,
1841         parent_clipping_and_scrolling: ClippingAndScrolling,
1842     ) -> StackingContext {
1843         let border_box = self.stacking_relative_border_box(
1844             &base_flow.stacking_relative_position,
1845             &base_flow
1846                 .early_absolute_position_info
1847                 .relative_containing_block_size,
1848             base_flow
1849                 .early_absolute_position_info
1850                 .relative_containing_block_mode,
1851             CoordinateSystem::Parent,
1852         );
1853         // First, compute the offset of our border box (including relative positioning)
1854         // from our flow origin, since that is what `BaseFlow::overflow` is relative to.
1855         let border_box_offset = border_box
1856             .translate(&-base_flow.stacking_relative_position)
1857             .origin;
1858         // Then, using that, compute our overflow region relative to our border box.
1859         let overflow = base_flow
1860             .overflow
1861             .paint
1862             .translate(&-border_box_offset.to_vector());
1863 
1864         // Create the filter pipeline.
1865         let effects = self.style().get_effects();
1866         let mut filters: Vec<FilterOp> = effects.filter.0.iter().map(ToLayout::to_layout).collect();
1867         if effects.opacity != 1.0 {
1868             filters.push(FilterOp::Opacity(effects.opacity.into(), effects.opacity));
1869         }
1870 
1871         StackingContext::new(
1872             id,
1873             context_type,
1874             border_box.to_layout(),
1875             overflow.to_layout(),
1876             self.effective_z_index(),
1877             filters,
1878             self.style().get_effects().mix_blend_mode.to_layout(),
1879             self.transform_matrix(&border_box),
1880             self.style().get_used_transform_style().to_layout(),
1881             self.perspective_matrix(&border_box),
1882             scroll_policy,
1883             parent_clipping_and_scrolling,
1884         )
1885     }
1886 
build_display_list_for_text_fragment( &self, state: &mut DisplayListBuildState, text_fragment: &ScannedTextFragmentInfo, stacking_relative_content_box: &Rect<Au>, text_shadows: &[SimpleShadow], clip: &Rect<Au>, )1887     fn build_display_list_for_text_fragment(
1888         &self,
1889         state: &mut DisplayListBuildState,
1890         text_fragment: &ScannedTextFragmentInfo,
1891         stacking_relative_content_box: &Rect<Au>,
1892         text_shadows: &[SimpleShadow],
1893         clip: &Rect<Au>,
1894     ) {
1895         // NB: The order for painting text components (CSS Text Decoration Module Level 3) is:
1896         // shadows, underline, overline, text, text-emphasis, and then line-through.
1897 
1898         // TODO(emilio): Allow changing more properties by ::selection
1899         // Paint the text with the color as described in its styling.
1900         let text_color = if text_fragment.selected() {
1901             self.selected_style().get_color().color
1902         } else {
1903             self.style().get_color().color
1904         };
1905 
1906         // Determine the orientation and cursor to use.
1907         let (_orientation, cursor) = if self.style.writing_mode.is_vertical() {
1908             // TODO: Distinguish between 'sideways-lr' and 'sideways-rl' writing modes in CSS
1909             // Writing Modes Level 4.
1910             (TextOrientation::SidewaysRight, CursorKind::VerticalText)
1911         } else {
1912             (TextOrientation::Upright, CursorKind::Text)
1913         };
1914 
1915         // Compute location of the baseline.
1916         //
1917         // FIXME(pcwalton): Get the real container size.
1918         let container_size = Size2D::zero();
1919         let metrics = &text_fragment.run.font_metrics;
1920         let baseline_origin = stacking_relative_content_box.origin +
1921             LogicalPoint::new(self.style.writing_mode, Au(0), metrics.ascent)
1922                 .to_physical(self.style.writing_mode, container_size)
1923                 .to_vector();
1924 
1925         // Base item for all text/shadows
1926         let base = state.create_base_display_item(
1927             &stacking_relative_content_box,
1928             LocalClip::from(clip.to_layout()),
1929             self.node,
1930             self.style().get_cursor(cursor),
1931             DisplayListSection::Content,
1932         );
1933 
1934         // NB: According to CSS-BACKGROUNDS, text shadows render in *reverse* order (front
1935         // to back).
1936 
1937         // Shadows
1938         for shadow in text_shadows.iter().rev() {
1939             state.add_display_item(DisplayItem::PushTextShadow(Box::new(
1940                 PushTextShadowDisplayItem {
1941                     base: base.clone(),
1942                     blur_radius: shadow.blur.px(),
1943                     offset: LayoutVector2D::new(shadow.horizontal.px(), shadow.vertical.px()),
1944                     color: shadow
1945                         .color
1946                         .unwrap_or(self.style().get_color().color)
1947                         .to_layout(),
1948                 },
1949             )));
1950         }
1951 
1952         // Create display items for text decorations.
1953         let text_decorations = self.style().get_inheritedtext().text_decorations_in_effect;
1954 
1955         let logical_stacking_relative_content_box = LogicalRect::from_physical(
1956             self.style.writing_mode,
1957             *stacking_relative_content_box,
1958             container_size,
1959         );
1960 
1961         // Underline
1962         if text_decorations.underline {
1963             let mut stacking_relative_box = logical_stacking_relative_content_box;
1964             stacking_relative_box.start.b = logical_stacking_relative_content_box.start.b +
1965                 metrics.ascent -
1966                 metrics.underline_offset;
1967             stacking_relative_box.size.block = metrics.underline_size;
1968             self.build_display_list_for_text_decoration(
1969                 state,
1970                 &text_color,
1971                 &stacking_relative_box,
1972                 clip,
1973             );
1974         }
1975 
1976         // Overline
1977         if text_decorations.overline {
1978             let mut stacking_relative_box = logical_stacking_relative_content_box;
1979             stacking_relative_box.size.block = metrics.underline_size;
1980             self.build_display_list_for_text_decoration(
1981                 state,
1982                 &text_color,
1983                 &stacking_relative_box,
1984                 clip,
1985             );
1986         }
1987 
1988         // Text
1989         let glyphs = convert_text_run_to_glyphs(
1990             text_fragment.run.clone(),
1991             text_fragment.range,
1992             baseline_origin,
1993         );
1994         if !glyphs.is_empty() {
1995             let indexable_text = IndexableTextItem {
1996                 origin: stacking_relative_content_box.origin,
1997                 text_run: text_fragment.run.clone(),
1998                 range: text_fragment.range,
1999                 baseline_origin,
2000             };
2001             state.indexable_text.insert(self.node, indexable_text);
2002 
2003             state.add_display_item(DisplayItem::Text(Box::new(TextDisplayItem {
2004                 base: base.clone(),
2005                 glyphs: glyphs,
2006                 font_key: text_fragment.run.font_key,
2007                 text_color: text_color.to_layout(),
2008             })));
2009         }
2010 
2011         // TODO(#17715): emit text-emphasis marks here.
2012         // (just push another TextDisplayItem?)
2013 
2014         // Line-Through
2015         if text_decorations.line_through {
2016             let mut stacking_relative_box = logical_stacking_relative_content_box;
2017             stacking_relative_box.start.b =
2018                 stacking_relative_box.start.b + metrics.ascent - metrics.strikeout_offset;
2019             stacking_relative_box.size.block = metrics.strikeout_size;
2020             self.build_display_list_for_text_decoration(
2021                 state,
2022                 &text_color,
2023                 &stacking_relative_box,
2024                 clip,
2025             );
2026         }
2027 
2028         // Pop all the PushTextShadows
2029         if !text_shadows.is_empty() {
2030             state.add_display_item(DisplayItem::PopAllTextShadows(Box::new(
2031                 PopAllTextShadowsDisplayItem { base: base.clone() },
2032             )));
2033         }
2034     }
2035 
build_display_list_for_text_decoration( &self, state: &mut DisplayListBuildState, color: &RGBA, stacking_relative_box: &LogicalRect<Au>, clip: &Rect<Au>, )2036     fn build_display_list_for_text_decoration(
2037         &self,
2038         state: &mut DisplayListBuildState,
2039         color: &RGBA,
2040         stacking_relative_box: &LogicalRect<Au>,
2041         clip: &Rect<Au>,
2042     ) {
2043         // FIXME(pcwalton, #2795): Get the real container size.
2044         let container_size = Size2D::zero();
2045         let stacking_relative_box =
2046             stacking_relative_box.to_physical(self.style.writing_mode, container_size);
2047         let base = state.create_base_display_item(
2048             &stacking_relative_box,
2049             LocalClip::from(clip.to_layout()),
2050             self.node,
2051             self.style.get_cursor(CursorKind::Default),
2052             DisplayListSection::Content,
2053         );
2054 
2055         state.add_display_item(DisplayItem::Line(Box::new(LineDisplayItem {
2056             base: base,
2057             color: color.to_layout(),
2058             style: LineStyle::Solid,
2059         })));
2060     }
2061 
unique_id(&self) -> u642062     fn unique_id(&self) -> u64 {
2063         let fragment_type = self.fragment_type();
2064         let id = self.node.id() as usize;
2065         combine_id_with_fragment_type(id, fragment_type) as u64
2066     }
2067 
fragment_type(&self) -> FragmentType2068     fn fragment_type(&self) -> FragmentType {
2069         self.pseudo.fragment_type()
2070     }
2071 }
2072 
2073 bitflags! {
2074     pub struct StackingContextCollectionFlags: u8 {
2075         /// This flow never establishes a containing block.
2076         const NEVER_CREATES_CONTAINING_BLOCK = 0b001;
2077         /// This flow never creates a ClipScrollNode.
2078         const NEVER_CREATES_CLIP_SCROLL_NODE = 0b010;
2079         /// This flow never creates a stacking context.
2080         const NEVER_CREATES_STACKING_CONTEXT = 0b100;
2081     }
2082 }
2083 
2084 pub trait BlockFlowDisplayListBuilding {
collect_stacking_contexts_for_block( &mut self, state: &mut StackingContextCollectionState, flags: StackingContextCollectionFlags, )2085     fn collect_stacking_contexts_for_block(
2086         &mut self,
2087         state: &mut StackingContextCollectionState,
2088         flags: StackingContextCollectionFlags,
2089     );
2090 
transform_clip_to_coordinate_space( &mut self, state: &mut StackingContextCollectionState, preserved_state: &mut SavedStackingContextCollectionState, )2091     fn transform_clip_to_coordinate_space(
2092         &mut self,
2093         state: &mut StackingContextCollectionState,
2094         preserved_state: &mut SavedStackingContextCollectionState,
2095     );
setup_clipping_for_block( &mut self, state: &mut StackingContextCollectionState, preserved_state: &mut SavedStackingContextCollectionState, stacking_context_type: Option<StackingContextType>, flags: StackingContextCollectionFlags, ) -> ClippingAndScrolling2096     fn setup_clipping_for_block(
2097         &mut self,
2098         state: &mut StackingContextCollectionState,
2099         preserved_state: &mut SavedStackingContextCollectionState,
2100         stacking_context_type: Option<StackingContextType>,
2101         flags: StackingContextCollectionFlags,
2102     ) -> ClippingAndScrolling;
setup_clip_scroll_node_for_position( &mut self, state: &mut StackingContextCollectionState, border_box: &Rect<Au>, )2103     fn setup_clip_scroll_node_for_position(
2104         &mut self,
2105         state: &mut StackingContextCollectionState,
2106         border_box: &Rect<Au>,
2107     );
setup_clip_scroll_node_for_overflow( &mut self, state: &mut StackingContextCollectionState, border_box: &Rect<Au>, )2108     fn setup_clip_scroll_node_for_overflow(
2109         &mut self,
2110         state: &mut StackingContextCollectionState,
2111         border_box: &Rect<Au>,
2112     );
setup_clip_scroll_node_for_css_clip( &mut self, state: &mut StackingContextCollectionState, preserved_state: &mut SavedStackingContextCollectionState, stacking_relative_border_box: &Rect<Au>, )2113     fn setup_clip_scroll_node_for_css_clip(
2114         &mut self,
2115         state: &mut StackingContextCollectionState,
2116         preserved_state: &mut SavedStackingContextCollectionState,
2117         stacking_relative_border_box: &Rect<Au>,
2118     );
create_pseudo_stacking_context_for_block( &mut self, stacking_context_type: StackingContextType, parent_stacking_context_id: StackingContextId, parent_clip_and_scroll_info: ClippingAndScrolling, state: &mut StackingContextCollectionState, )2119     fn create_pseudo_stacking_context_for_block(
2120         &mut self,
2121         stacking_context_type: StackingContextType,
2122         parent_stacking_context_id: StackingContextId,
2123         parent_clip_and_scroll_info: ClippingAndScrolling,
2124         state: &mut StackingContextCollectionState,
2125     );
create_real_stacking_context_for_block( &mut self, parent_stacking_context_id: StackingContextId, parent_clipping_and_scrolling: ClippingAndScrolling, state: &mut StackingContextCollectionState, )2126     fn create_real_stacking_context_for_block(
2127         &mut self,
2128         parent_stacking_context_id: StackingContextId,
2129         parent_clipping_and_scrolling: ClippingAndScrolling,
2130         state: &mut StackingContextCollectionState,
2131     );
build_display_list_for_block( &mut self, state: &mut DisplayListBuildState, border_painting_mode: BorderPaintingMode, )2132     fn build_display_list_for_block(
2133         &mut self,
2134         state: &mut DisplayListBuildState,
2135         border_painting_mode: BorderPaintingMode,
2136     );
build_display_list_for_block_no_damage( &self, state: &mut DisplayListBuildState, border_painting_mode: BorderPaintingMode, )2137     fn build_display_list_for_block_no_damage(
2138         &self,
2139         state: &mut DisplayListBuildState,
2140         border_painting_mode: BorderPaintingMode,
2141     );
build_display_list_for_background_if_applicable_with_background( &self, state: &mut DisplayListBuildState, background: &style_structs::Background, background_color: RGBA)2142     fn build_display_list_for_background_if_applicable_with_background(
2143         &self,
2144         state: &mut DisplayListBuildState,
2145         background: &style_structs::Background,
2146         background_color: RGBA);
2147 
stacking_context_type( &self, flags: StackingContextCollectionFlags, ) -> Option<StackingContextType>2148     fn stacking_context_type(
2149         &self,
2150         flags: StackingContextCollectionFlags,
2151     ) -> Option<StackingContextType>;
2152 }
2153 
2154 /// This structure manages ensuring that modification to StackingContextCollectionState is
2155 /// only temporary. It's useful for moving recursively down the flow tree and ensuring
2156 /// that the state is restored for siblings. To use this structure, we must call
2157 /// SavedStackingContextCollectionState::restore in order to restore the state.
2158 /// TODO(mrobinson): It would be nice to use RAII here to avoid having to call restore.
2159 pub struct SavedStackingContextCollectionState {
2160     stacking_context_id: StackingContextId,
2161     real_stacking_context_id: StackingContextId,
2162     clipping_and_scrolling: ClippingAndScrolling,
2163     containing_block_clipping_and_scrolling: ClippingAndScrolling,
2164     clips_pushed: usize,
2165     containing_block_clips_pushed: usize,
2166     stacking_relative_content_box: Rect<Au>,
2167 }
2168 
2169 impl SavedStackingContextCollectionState {
new(state: &mut StackingContextCollectionState) -> SavedStackingContextCollectionState2170     fn new(state: &mut StackingContextCollectionState) -> SavedStackingContextCollectionState {
2171         SavedStackingContextCollectionState {
2172             stacking_context_id: state.current_stacking_context_id,
2173             real_stacking_context_id: state.current_real_stacking_context_id,
2174             clipping_and_scrolling: state.current_clipping_and_scrolling,
2175             containing_block_clipping_and_scrolling: state.containing_block_clipping_and_scrolling,
2176             clips_pushed: 0,
2177             containing_block_clips_pushed: 0,
2178             stacking_relative_content_box: state.parent_stacking_relative_content_box,
2179         }
2180     }
2181 
switch_to_containing_block_clip(&mut self, state: &mut StackingContextCollectionState)2182     fn switch_to_containing_block_clip(&mut self, state: &mut StackingContextCollectionState) {
2183         let clip = state
2184             .containing_block_clip_stack
2185             .last()
2186             .cloned()
2187             .unwrap_or_else(MaxRect::max_rect);
2188         state.clip_stack.push(clip);
2189         self.clips_pushed += 1;
2190     }
2191 
restore(self, state: &mut StackingContextCollectionState)2192     fn restore(self, state: &mut StackingContextCollectionState) {
2193         state.current_stacking_context_id = self.stacking_context_id;
2194         state.current_real_stacking_context_id = self.real_stacking_context_id;
2195         state.current_clipping_and_scrolling = self.clipping_and_scrolling;
2196         state.containing_block_clipping_and_scrolling =
2197             self.containing_block_clipping_and_scrolling;
2198         state.parent_stacking_relative_content_box = self.stacking_relative_content_box;
2199 
2200         let truncate_length = state.clip_stack.len() - self.clips_pushed;
2201         state.clip_stack.truncate(truncate_length);
2202 
2203         let truncate_length =
2204             state.containing_block_clip_stack.len() - self.containing_block_clips_pushed;
2205         state.containing_block_clip_stack.truncate(truncate_length);
2206     }
2207 
push_clip( &mut self, state: &mut StackingContextCollectionState, clip: &Rect<Au>, positioning: StylePosition, )2208     fn push_clip(
2209         &mut self,
2210         state: &mut StackingContextCollectionState,
2211         clip: &Rect<Au>,
2212         positioning: StylePosition,
2213     ) {
2214         let mut clip = *clip;
2215         if positioning != StylePosition::Fixed {
2216             if let Some(old_clip) = state.clip_stack.last() {
2217                 clip = old_clip.intersection(&clip).unwrap_or_else(Rect::zero);
2218             }
2219         }
2220 
2221         state.clip_stack.push(clip);
2222         self.clips_pushed += 1;
2223 
2224         if StylePosition::Absolute == positioning {
2225             state.containing_block_clip_stack.push(clip);
2226             self.containing_block_clips_pushed += 1;
2227         }
2228     }
2229 }
2230 
2231 impl BlockFlowDisplayListBuilding for BlockFlow {
transform_clip_to_coordinate_space( &mut self, state: &mut StackingContextCollectionState, preserved_state: &mut SavedStackingContextCollectionState, )2232     fn transform_clip_to_coordinate_space(
2233         &mut self,
2234         state: &mut StackingContextCollectionState,
2235         preserved_state: &mut SavedStackingContextCollectionState,
2236     ) {
2237         if state.clip_stack.is_empty() {
2238             return;
2239         }
2240         let border_box = self.stacking_relative_border_box(CoordinateSystem::Parent);
2241         let transform = match self.fragment.transform_matrix(&border_box) {
2242             Some(transform) => transform,
2243             None => return,
2244         };
2245 
2246         let perspective = self.fragment
2247             .perspective_matrix(&border_box)
2248             .unwrap_or(LayoutTransform::identity());
2249         let transform = transform.pre_mul(&perspective).inverse();
2250 
2251         let origin = &border_box.origin;
2252         let transform_clip = |clip: &Rect<Au>| {
2253             if *clip == Rect::max_rect() {
2254                 return *clip;
2255             }
2256 
2257             match transform {
2258                 Some(transform) if transform.m13 != 0.0 || transform.m23 != 0.0 => {
2259                     // We cannot properly handle perspective transforms, because there may be a
2260                     // situation where an element is transformed from outside the clip into the
2261                     // clip region. Here we don't have enough information to detect when that is
2262                     // happening. For the moment we just punt on trying to optimize the display
2263                     // list for those cases.
2264                     Rect::max_rect()
2265                 },
2266                 Some(transform) => {
2267                     let clip = rect(
2268                         (clip.origin.x - origin.x).to_f32_px(),
2269                         (clip.origin.y - origin.y).to_f32_px(),
2270                         clip.size.width.to_f32_px(),
2271                         clip.size.height.to_f32_px(),
2272                     );
2273 
2274                     let clip = transform.transform_rect(&clip);
2275 
2276                     rect(
2277                         Au::from_f32_px(clip.origin.x),
2278                         Au::from_f32_px(clip.origin.y),
2279                         Au::from_f32_px(clip.size.width),
2280                         Au::from_f32_px(clip.size.height),
2281                     )
2282                 },
2283                 None => Rect::zero(),
2284             }
2285         };
2286 
2287         if let Some(clip) = state.clip_stack.last().cloned() {
2288             state.clip_stack.push(transform_clip(&clip));
2289             preserved_state.clips_pushed += 1;
2290         }
2291 
2292         if let Some(clip) = state.containing_block_clip_stack.last().cloned() {
2293             state
2294                 .containing_block_clip_stack
2295                 .push(transform_clip(&clip));
2296             preserved_state.containing_block_clips_pushed += 1;
2297         }
2298     }
2299 
collect_stacking_contexts_for_block( &mut self, state: &mut StackingContextCollectionState, flags: StackingContextCollectionFlags, )2300     fn collect_stacking_contexts_for_block(
2301         &mut self,
2302         state: &mut StackingContextCollectionState,
2303         flags: StackingContextCollectionFlags,
2304     ) {
2305         let mut preserved_state = SavedStackingContextCollectionState::new(state);
2306 
2307         let stacking_context_type = self.stacking_context_type(flags);
2308         self.base.stacking_context_id = match stacking_context_type {
2309             None => state.current_stacking_context_id,
2310             Some(sc_type) => state.allocate_stacking_context_info(sc_type),
2311         };
2312         state.current_stacking_context_id = self.base.stacking_context_id;
2313 
2314         if stacking_context_type == Some(StackingContextType::Real) {
2315             state.current_real_stacking_context_id = self.base.stacking_context_id;
2316         }
2317 
2318         // We are getting the id of the scroll root that contains us here, not the id of
2319         // any scroll root that we create. If we create a scroll root, its index will be
2320         // stored in state.current_clipping_and_scrolling. If we create a stacking context,
2321         // we don't want it to be contained by its own scroll root.
2322         let containing_clipping_and_scrolling = self.setup_clipping_for_block(
2323             state,
2324             &mut preserved_state,
2325             stacking_context_type,
2326             flags,
2327         );
2328 
2329         if establishes_containing_block_for_absolute(flags, self.positioning()) {
2330             state.containing_block_clipping_and_scrolling = state.current_clipping_and_scrolling;
2331         }
2332 
2333         match stacking_context_type {
2334             None => self.base.collect_stacking_contexts_for_children(state),
2335             Some(StackingContextType::Real) => {
2336                 self.create_real_stacking_context_for_block(
2337                     preserved_state.stacking_context_id,
2338                     containing_clipping_and_scrolling,
2339                     state,
2340                 );
2341             },
2342             Some(stacking_context_type) => {
2343                 self.create_pseudo_stacking_context_for_block(
2344                     stacking_context_type,
2345                     preserved_state.stacking_context_id,
2346                     containing_clipping_and_scrolling,
2347                     state,
2348                 );
2349             },
2350         }
2351 
2352         preserved_state.restore(state);
2353     }
2354 
setup_clipping_for_block( &mut self, state: &mut StackingContextCollectionState, preserved_state: &mut SavedStackingContextCollectionState, stacking_context_type: Option<StackingContextType>, flags: StackingContextCollectionFlags, ) -> ClippingAndScrolling2355     fn setup_clipping_for_block(
2356         &mut self,
2357         state: &mut StackingContextCollectionState,
2358         preserved_state: &mut SavedStackingContextCollectionState,
2359         stacking_context_type: Option<StackingContextType>,
2360         flags: StackingContextCollectionFlags,
2361     ) -> ClippingAndScrolling {
2362         // If this block is absolutely positioned, we should be clipped and positioned by
2363         // the scroll root of our nearest ancestor that establishes a containing block.
2364         let containing_clipping_and_scrolling = match self.positioning() {
2365             StylePosition::Absolute => {
2366                 preserved_state.switch_to_containing_block_clip(state);
2367                 state.current_clipping_and_scrolling =
2368                     state.containing_block_clipping_and_scrolling;
2369                 state.containing_block_clipping_and_scrolling
2370             },
2371             StylePosition::Fixed => {
2372                 preserved_state.push_clip(state, &Rect::max_rect(), StylePosition::Fixed);
2373                 state.current_clipping_and_scrolling
2374             },
2375             _ => state.current_clipping_and_scrolling,
2376         };
2377         self.base.clipping_and_scrolling = Some(containing_clipping_and_scrolling);
2378 
2379         let stacking_relative_border_box = if self.fragment.establishes_stacking_context() {
2380             self.stacking_relative_border_box(CoordinateSystem::Own)
2381         } else {
2382             self.stacking_relative_border_box(CoordinateSystem::Parent)
2383         };
2384 
2385         if stacking_context_type == Some(StackingContextType::Real) {
2386             self.transform_clip_to_coordinate_space(state, preserved_state);
2387         }
2388 
2389         if !flags.contains(StackingContextCollectionFlags::NEVER_CREATES_CLIP_SCROLL_NODE) {
2390             self.setup_clip_scroll_node_for_position(state, &stacking_relative_border_box);
2391             self.setup_clip_scroll_node_for_overflow(state, &stacking_relative_border_box);
2392             self.setup_clip_scroll_node_for_css_clip(
2393                 state,
2394                 preserved_state,
2395                 &stacking_relative_border_box,
2396             );
2397         }
2398         self.base.clip = state
2399             .clip_stack
2400             .last()
2401             .cloned()
2402             .unwrap_or_else(Rect::max_rect);
2403 
2404         // We keep track of our position so that any stickily positioned elements can
2405         // properly determine the extent of their movement relative to scrolling containers.
2406         if !flags.contains(StackingContextCollectionFlags::NEVER_CREATES_CONTAINING_BLOCK) {
2407             let border_box = if self.fragment.establishes_stacking_context() {
2408                 stacking_relative_border_box
2409             } else {
2410                 self.stacking_relative_border_box(CoordinateSystem::Own)
2411             };
2412             state.parent_stacking_relative_content_box =
2413                 self.fragment.stacking_relative_content_box(&border_box)
2414         }
2415 
2416         match self.positioning() {
2417             StylePosition::Absolute | StylePosition::Relative | StylePosition::Fixed => {
2418                 state.containing_block_clipping_and_scrolling = state.current_clipping_and_scrolling
2419             },
2420             _ => {},
2421         }
2422 
2423         containing_clipping_and_scrolling
2424     }
2425 
setup_clip_scroll_node_for_position( &mut self, state: &mut StackingContextCollectionState, border_box: &Rect<Au>, )2426     fn setup_clip_scroll_node_for_position(
2427         &mut self,
2428         state: &mut StackingContextCollectionState,
2429         border_box: &Rect<Au>,
2430     ) {
2431         if self.positioning() != StylePosition::Sticky {
2432             return;
2433         }
2434 
2435         let sticky_position = self.sticky_position();
2436         if sticky_position.left == MaybeAuto::Auto && sticky_position.right == MaybeAuto::Auto &&
2437             sticky_position.top == MaybeAuto::Auto &&
2438             sticky_position.bottom == MaybeAuto::Auto
2439         {
2440             return;
2441         }
2442 
2443         // Since position: sticky elements always establish a stacking context, we will
2444         // have previously calculated our border box in our own coordinate system. In
2445         // order to properly calculate max offsets we need to compare our size and
2446         // position in our parent's coordinate system.
2447         let border_box_in_parent = self.stacking_relative_border_box(CoordinateSystem::Parent);
2448         let margins = self.fragment.margin.to_physical(
2449             self.base
2450                 .early_absolute_position_info
2451                 .relative_containing_block_mode,
2452         );
2453 
2454         // Position:sticky elements are always restricted based on the size and position of
2455         // their containing block, which for sticky items is like relative and statically
2456         // positioned items: just the parent block.
2457         let constraint_rect = state.parent_stacking_relative_content_box;
2458 
2459         let to_offset_bound = |constraint_edge: Au, moving_edge: Au| -> f32 {
2460             (constraint_edge - moving_edge).to_f32_px()
2461         };
2462 
2463         // This is the minimum negative offset and then the maximum positive offset. We just
2464         // specify every edge, but if the corresponding margin is None, that offset has no effect.
2465         let vertical_offset_bounds = StickyOffsetBounds::new(
2466             to_offset_bound(
2467                 constraint_rect.min_y(),
2468                 border_box_in_parent.min_y() - margins.top,
2469             ),
2470             to_offset_bound(constraint_rect.max_y(), border_box_in_parent.max_y()),
2471         );
2472         let horizontal_offset_bounds = StickyOffsetBounds::new(
2473             to_offset_bound(
2474                 constraint_rect.min_x(),
2475                 border_box_in_parent.min_x() - margins.left,
2476             ),
2477             to_offset_bound(constraint_rect.max_x(), border_box_in_parent.max_x()),
2478         );
2479 
2480         // The margins control which edges have sticky behavior.
2481         let sticky_frame_data = StickyFrameData {
2482             margins: SideOffsets2D::new(
2483                 sticky_position.top.to_option().map(|v| v.to_f32_px()),
2484                 sticky_position.right.to_option().map(|v| v.to_f32_px()),
2485                 sticky_position.bottom.to_option().map(|v| v.to_f32_px()),
2486                 sticky_position.left.to_option().map(|v| v.to_f32_px()),
2487             ),
2488             vertical_offset_bounds,
2489             horizontal_offset_bounds,
2490         };
2491 
2492         let new_clip_scroll_index = state.add_clip_scroll_node(ClipScrollNode {
2493             parent_index: self.clipping_and_scrolling().scrolling,
2494             clip: ClippingRegion::from_rect(border_box.to_layout()),
2495             content_rect: LayoutRect::zero(),
2496             node_type: ClipScrollNodeType::StickyFrame(sticky_frame_data),
2497         });
2498 
2499         let new_clipping_and_scrolling = ClippingAndScrolling::simple(new_clip_scroll_index);
2500         self.base.clipping_and_scrolling = Some(new_clipping_and_scrolling);
2501         state.current_clipping_and_scrolling = new_clipping_and_scrolling;
2502     }
2503 
setup_clip_scroll_node_for_overflow( &mut self, state: &mut StackingContextCollectionState, border_box: &Rect<Au>, )2504     fn setup_clip_scroll_node_for_overflow(
2505         &mut self,
2506         state: &mut StackingContextCollectionState,
2507         border_box: &Rect<Au>,
2508     ) {
2509         if !self.overflow_style_may_require_clip_scroll_node() {
2510             return;
2511         }
2512 
2513         let content_box = self.fragment.stacking_relative_content_box(&border_box);
2514         let has_scrolling_overflow = self.base.overflow.scroll.origin != Point2D::zero() ||
2515             self.base.overflow.scroll.size.width > content_box.size.width ||
2516             self.base.overflow.scroll.size.height > content_box.size.height ||
2517             StyleOverflow::Hidden == self.fragment.style.get_box().overflow_x ||
2518             StyleOverflow::Hidden == self.fragment.style.get_box().overflow_y;
2519 
2520         self.mark_scrolling_overflow(has_scrolling_overflow);
2521         if !has_scrolling_overflow {
2522             return;
2523         }
2524 
2525         let sensitivity = if StyleOverflow::Hidden == self.fragment.style.get_box().overflow_x &&
2526             StyleOverflow::Hidden == self.fragment.style.get_box().overflow_y
2527         {
2528             ScrollSensitivity::Script
2529         } else {
2530             ScrollSensitivity::ScriptAndInputEvents
2531         };
2532 
2533         let border_widths = self.fragment
2534             .style
2535             .logical_border_width()
2536             .to_physical(self.fragment.style.writing_mode);
2537         let clip_rect = border_box.inner_rect(border_widths);
2538 
2539         let mut clip = ClippingRegion::from_rect(clip_rect.to_layout());
2540         let radii = build_border_radius_for_inner_rect(&border_box, &self.fragment.style);
2541         if !radii.is_zero() {
2542             clip.intersect_with_rounded_rect(clip_rect.to_layout(), radii)
2543         }
2544 
2545         let content_size = self.base.overflow.scroll.origin + self.base.overflow.scroll.size;
2546         let content_size = Size2D::new(content_size.x, content_size.y);
2547 
2548         let external_id =
2549             ExternalScrollId(self.fragment.unique_id(), state.pipeline_id.to_webrender());
2550         let new_clip_scroll_index = state.add_clip_scroll_node(ClipScrollNode {
2551             parent_index: self.clipping_and_scrolling().scrolling,
2552             clip: clip,
2553             content_rect: Rect::new(content_box.origin, content_size).to_layout(),
2554             node_type: ClipScrollNodeType::ScrollFrame(sensitivity, external_id),
2555         });
2556 
2557         let new_clipping_and_scrolling = ClippingAndScrolling::simple(new_clip_scroll_index);
2558         self.base.clipping_and_scrolling = Some(new_clipping_and_scrolling);
2559         state.current_clipping_and_scrolling = new_clipping_and_scrolling;
2560     }
2561 
2562     /// Adds a scroll root for a block to take the `clip` property into account
2563     /// per CSS 2.1 § 11.1.2.
setup_clip_scroll_node_for_css_clip( &mut self, state: &mut StackingContextCollectionState, preserved_state: &mut SavedStackingContextCollectionState, stacking_relative_border_box: &Rect<Au>, )2564     fn setup_clip_scroll_node_for_css_clip(
2565         &mut self,
2566         state: &mut StackingContextCollectionState,
2567         preserved_state: &mut SavedStackingContextCollectionState,
2568         stacking_relative_border_box: &Rect<Au>,
2569     ) {
2570         // Account for `clip` per CSS 2.1 § 11.1.2.
2571         let style_clip_rect = match self.fragment.style().get_effects().clip {
2572             Either::First(style_clip_rect) => style_clip_rect,
2573             _ => return,
2574         };
2575 
2576         // CSS `clip` should only apply to position:absolute or positione:fixed elements.
2577         // CSS Masking Appendix A: "Applies to: Absolutely positioned elements."
2578         match self.positioning() {
2579             StylePosition::Absolute | StylePosition::Fixed => {},
2580             _ => return,
2581         }
2582 
2583         let clip_origin = Point2D::new(
2584             stacking_relative_border_box.origin.x +
2585                 style_clip_rect.left.map(Au::from).unwrap_or(Au(0)),
2586             stacking_relative_border_box.origin.y +
2587                 style_clip_rect.top.map(Au::from).unwrap_or(Au(0)),
2588         );
2589         let right = style_clip_rect
2590             .right
2591             .map(Au::from)
2592             .unwrap_or(stacking_relative_border_box.size.width);
2593         let bottom = style_clip_rect
2594             .bottom
2595             .map(Au::from)
2596             .unwrap_or(stacking_relative_border_box.size.height);
2597         let clip_size = Size2D::new(right - clip_origin.x, bottom - clip_origin.y);
2598 
2599         let clip_rect = Rect::new(clip_origin, clip_size);
2600         preserved_state.push_clip(state, &clip_rect, self.positioning());
2601 
2602         let new_index = state.add_clip_scroll_node(ClipScrollNode {
2603             parent_index: self.clipping_and_scrolling().scrolling,
2604             clip: ClippingRegion::from_rect(clip_rect.to_layout()),
2605             content_rect: LayoutRect::zero(), // content_rect isn't important for clips.
2606             node_type: ClipScrollNodeType::Clip,
2607         });
2608 
2609         let new_indices = ClippingAndScrolling::new(new_index, new_index);
2610         self.base.clipping_and_scrolling = Some(new_indices);
2611         state.current_clipping_and_scrolling = new_indices;
2612     }
2613 
create_pseudo_stacking_context_for_block( &mut self, stacking_context_type: StackingContextType, parent_stacking_context_id: StackingContextId, parent_clipping_and_scrolling: ClippingAndScrolling, state: &mut StackingContextCollectionState, )2614     fn create_pseudo_stacking_context_for_block(
2615         &mut self,
2616         stacking_context_type: StackingContextType,
2617         parent_stacking_context_id: StackingContextId,
2618         parent_clipping_and_scrolling: ClippingAndScrolling,
2619         state: &mut StackingContextCollectionState,
2620     ) {
2621         let new_context = self.fragment.create_stacking_context(
2622             self.base.stacking_context_id,
2623             &self.base,
2624             ScrollPolicy::Scrollable,
2625             stacking_context_type,
2626             parent_clipping_and_scrolling,
2627         );
2628         state.add_stacking_context(parent_stacking_context_id, new_context);
2629 
2630         self.base.collect_stacking_contexts_for_children(state);
2631 
2632         let children = state
2633             .stacking_context_info
2634             .get_mut(&self.base.stacking_context_id)
2635             .map(|info| info.take_children());
2636         if let Some(children) = children {
2637             for child in children {
2638                 if child.context_type == StackingContextType::PseudoFloat {
2639                     state.add_stacking_context(self.base.stacking_context_id, child);
2640                 } else {
2641                     state.add_stacking_context(parent_stacking_context_id, child);
2642                 }
2643             }
2644         }
2645     }
2646 
create_real_stacking_context_for_block( &mut self, parent_stacking_context_id: StackingContextId, parent_clipping_and_scrolling: ClippingAndScrolling, state: &mut StackingContextCollectionState, )2647     fn create_real_stacking_context_for_block(
2648         &mut self,
2649         parent_stacking_context_id: StackingContextId,
2650         parent_clipping_and_scrolling: ClippingAndScrolling,
2651         state: &mut StackingContextCollectionState,
2652     ) {
2653         let scroll_policy = if self.is_fixed() {
2654             ScrollPolicy::Fixed
2655         } else {
2656             ScrollPolicy::Scrollable
2657         };
2658 
2659         let stacking_context = self.fragment.create_stacking_context(
2660             self.base.stacking_context_id,
2661             &self.base,
2662             scroll_policy,
2663             StackingContextType::Real,
2664             parent_clipping_and_scrolling,
2665         );
2666 
2667         state.add_stacking_context(parent_stacking_context_id, stacking_context);
2668         self.base.collect_stacking_contexts_for_children(state);
2669     }
2670 
build_display_list_for_block_no_damage( &self, state: &mut DisplayListBuildState, border_painting_mode: BorderPaintingMode, )2671     fn build_display_list_for_block_no_damage(
2672         &self,
2673         state: &mut DisplayListBuildState,
2674         border_painting_mode: BorderPaintingMode,
2675     ) {
2676         let background_border_section = self.background_border_section();
2677 
2678         state.processing_scrolling_overflow_element = self.has_scrolling_overflow();
2679         let stacking_relative_border_box =
2680             self.base.stacking_relative_border_box_for_display_list(&self.fragment);
2681         // Add the box that starts the block context.
2682         self.fragment.build_display_list_no_damage(
2683             state,
2684             stacking_relative_border_box,
2685             border_painting_mode,
2686             background_border_section,
2687             &self.base.clip,
2688         );
2689 
2690         self.base
2691             .build_display_items_for_debugging_tint(state, self.fragment.node);
2692 
2693         state.processing_scrolling_overflow_element = false;
2694     }
2695 
build_display_list_for_block( &mut self, state: &mut DisplayListBuildState, border_painting_mode: BorderPaintingMode, )2696     fn build_display_list_for_block(
2697         &mut self,
2698         state: &mut DisplayListBuildState,
2699         border_painting_mode: BorderPaintingMode,
2700     ) {
2701         self.fragment.restyle_damage.remove(ServoRestyleDamage::REPAINT);
2702         self.build_display_list_for_block_no_damage(state, border_painting_mode);
2703     }
2704 
build_display_list_for_background_if_applicable_with_background( &self, state: &mut DisplayListBuildState, background: &style_structs::Background, background_color: RGBA)2705     fn build_display_list_for_background_if_applicable_with_background(
2706         &self,
2707         state: &mut DisplayListBuildState,
2708         background: &style_structs::Background,
2709         background_color: RGBA) {
2710         let stacking_relative_border_box =
2711             self.base.stacking_relative_border_box_for_display_list(&self.fragment);
2712         let background_border_section = self.background_border_section();
2713 
2714         self.fragment.build_display_list_for_background_if_applicable_with_background(
2715             state, self.fragment.style(), background, background_color,
2716             background_border_section, &stacking_relative_border_box
2717         )
2718 
2719     }
2720 
2721     #[inline]
stacking_context_type( &self, flags: StackingContextCollectionFlags, ) -> Option<StackingContextType>2722     fn stacking_context_type(
2723         &self,
2724         flags: StackingContextCollectionFlags,
2725     ) -> Option<StackingContextType>{
2726         if flags.contains(StackingContextCollectionFlags::NEVER_CREATES_STACKING_CONTEXT) {
2727             return None;
2728         }
2729 
2730         if self.fragment.establishes_stacking_context() {
2731             return Some(StackingContextType::Real);
2732         }
2733 
2734         if self.base.flags.contains(FlowFlags::IS_ABSOLUTELY_POSITIONED) {
2735             return Some(StackingContextType::PseudoPositioned);
2736         }
2737 
2738         if self.fragment.style.get_box().position != StylePosition::Static {
2739             return Some(StackingContextType::PseudoPositioned);
2740         }
2741 
2742         if self.base.flags.is_float() {
2743             return Some(StackingContextType::PseudoFloat);
2744         }
2745 
2746         None
2747     }
2748 }
2749 
2750 pub trait InlineFlowDisplayListBuilding {
collect_stacking_contexts_for_inline(&mut self, state: &mut StackingContextCollectionState)2751     fn collect_stacking_contexts_for_inline(&mut self, state: &mut StackingContextCollectionState);
build_display_list_for_inline_fragment_at_index( &mut self, state: &mut DisplayListBuildState, index: usize, )2752     fn build_display_list_for_inline_fragment_at_index(
2753         &mut self,
2754         state: &mut DisplayListBuildState,
2755         index: usize,
2756     );
build_display_list_for_inline(&mut self, state: &mut DisplayListBuildState)2757     fn build_display_list_for_inline(&mut self, state: &mut DisplayListBuildState);
2758 }
2759 
2760 impl InlineFlowDisplayListBuilding for InlineFlow {
collect_stacking_contexts_for_inline(&mut self, state: &mut StackingContextCollectionState)2761     fn collect_stacking_contexts_for_inline(&mut self, state: &mut StackingContextCollectionState) {
2762         self.base.stacking_context_id = state.current_stacking_context_id;
2763         self.base.clipping_and_scrolling = Some(state.current_clipping_and_scrolling);
2764         self.base.clip = state
2765             .clip_stack
2766             .last()
2767             .cloned()
2768             .unwrap_or_else(Rect::max_rect);
2769 
2770         for fragment in self.fragments.fragments.iter_mut() {
2771             let previous_cb_clipping_and_scrolling = state.containing_block_clipping_and_scrolling;
2772             if establishes_containing_block_for_absolute(
2773                 StackingContextCollectionFlags::empty(),
2774                 fragment.style.get_box().position,
2775             ) {
2776                 state.containing_block_clipping_and_scrolling =
2777                     state.current_clipping_and_scrolling;
2778             }
2779 
2780             if !fragment.collect_stacking_contexts_for_blocklike_fragment(state) {
2781                 if fragment.establishes_stacking_context() {
2782                     fragment.stacking_context_id =
2783                         state.allocate_stacking_context_info(StackingContextType::Real);
2784 
2785                     let current_stacking_context_id = state.current_stacking_context_id;
2786                     let stacking_context = fragment.create_stacking_context(
2787                         fragment.stacking_context_id,
2788                         &self.base,
2789                         ScrollPolicy::Scrollable,
2790                         StackingContextType::Real,
2791                         state.current_clipping_and_scrolling,
2792                     );
2793 
2794                     state.add_stacking_context(current_stacking_context_id, stacking_context);
2795                 } else {
2796                     fragment.stacking_context_id = state.current_stacking_context_id;
2797                 }
2798             }
2799 
2800             state.containing_block_clipping_and_scrolling = previous_cb_clipping_and_scrolling;
2801         }
2802     }
2803 
build_display_list_for_inline_fragment_at_index( &mut self, state: &mut DisplayListBuildState, index: usize, )2804     fn build_display_list_for_inline_fragment_at_index(
2805         &mut self,
2806         state: &mut DisplayListBuildState,
2807         index: usize,
2808     ) {
2809         let fragment = self.fragments.fragments.get_mut(index).unwrap();
2810         let stacking_relative_border_box =
2811             self.base.stacking_relative_border_box_for_display_list(fragment);
2812         fragment.build_display_list(
2813             state,
2814             stacking_relative_border_box,
2815             BorderPaintingMode::Separate,
2816             DisplayListSection::Content,
2817             &self.base.clip,
2818         );
2819     }
2820 
build_display_list_for_inline(&mut self, state: &mut DisplayListBuildState)2821     fn build_display_list_for_inline(&mut self, state: &mut DisplayListBuildState) {
2822         debug!(
2823             "Flow: building display list for {} inline fragments",
2824             self.fragments.len()
2825         );
2826 
2827         // We iterate using an index here, because we want to avoid doing a doing
2828         // a double-borrow of self (one mutable for the method call and one immutable
2829         // for the self.fragments.fragment iterator itself).
2830         for index in 0..self.fragments.fragments.len() {
2831             let (establishes_stacking_context, stacking_context_id) = {
2832                 let fragment = self.fragments.fragments.get(index).unwrap();
2833                 (
2834                     self.base.stacking_context_id != fragment.stacking_context_id,
2835                     fragment.stacking_context_id,
2836                 )
2837             };
2838 
2839             let parent_stacking_context_id = state.current_stacking_context_id;
2840             if establishes_stacking_context {
2841                 state.current_stacking_context_id = stacking_context_id;
2842             }
2843 
2844             self.build_display_list_for_inline_fragment_at_index(state, index);
2845 
2846             if establishes_stacking_context {
2847                 state.current_stacking_context_id = parent_stacking_context_id
2848             }
2849         }
2850 
2851         if !self.fragments.fragments.is_empty() {
2852             self.base
2853                 .build_display_items_for_debugging_tint(state, self.fragments.fragments[0].node);
2854         }
2855     }
2856 }
2857 
2858 pub trait ListItemFlowDisplayListBuilding {
build_display_list_for_list_item(&mut self, state: &mut DisplayListBuildState)2859     fn build_display_list_for_list_item(&mut self, state: &mut DisplayListBuildState);
2860 }
2861 
2862 impl ListItemFlowDisplayListBuilding for ListItemFlow {
build_display_list_for_list_item(&mut self, state: &mut DisplayListBuildState)2863     fn build_display_list_for_list_item(&mut self, state: &mut DisplayListBuildState) {
2864         // Draw the marker, if applicable.
2865         for marker in &mut self.marker_fragments {
2866             let stacking_relative_border_box =
2867                 self.block_flow.base.stacking_relative_border_box_for_display_list(marker);
2868             marker.build_display_list(
2869                 state,
2870                 stacking_relative_border_box,
2871                 BorderPaintingMode::Separate,
2872                 DisplayListSection::Content,
2873                 &self.block_flow.base.clip,
2874             );
2875         }
2876 
2877         // Draw the rest of the block.
2878         self.block_flow
2879             .build_display_list_for_block(state, BorderPaintingMode::Separate)
2880     }
2881 }
2882 
2883 pub trait FlexFlowDisplayListBuilding {
build_display_list_for_flex(&mut self, state: &mut DisplayListBuildState)2884     fn build_display_list_for_flex(&mut self, state: &mut DisplayListBuildState);
2885 }
2886 
2887 impl FlexFlowDisplayListBuilding for FlexFlow {
build_display_list_for_flex(&mut self, state: &mut DisplayListBuildState)2888     fn build_display_list_for_flex(&mut self, state: &mut DisplayListBuildState) {
2889         // Draw the rest of the block.
2890         self.as_mut_block()
2891             .build_display_list_for_block(state, BorderPaintingMode::Separate)
2892     }
2893 }
2894 
2895 trait BaseFlowDisplayListBuilding {
build_display_items_for_debugging_tint( &self, state: &mut DisplayListBuildState, node: OpaqueNode, )2896     fn build_display_items_for_debugging_tint(
2897         &self,
2898         state: &mut DisplayListBuildState,
2899         node: OpaqueNode,
2900     );
2901 }
2902 
2903 impl BaseFlowDisplayListBuilding for BaseFlow {
build_display_items_for_debugging_tint( &self, state: &mut DisplayListBuildState, node: OpaqueNode, )2904     fn build_display_items_for_debugging_tint(
2905         &self,
2906         state: &mut DisplayListBuildState,
2907         node: OpaqueNode,
2908     ) {
2909         if !opts::get().show_debug_parallel_layout {
2910             return;
2911         }
2912 
2913         let thread_id = self.thread_id;
2914         let stacking_context_relative_bounds = Rect::new(
2915             self.stacking_relative_position.to_point(),
2916             self.position.size.to_physical(self.writing_mode),
2917         );
2918 
2919         let mut color = THREAD_TINT_COLORS[thread_id as usize % THREAD_TINT_COLORS.len()];
2920         color.a = 1.0;
2921         let base = state.create_base_display_item(
2922             &stacking_context_relative_bounds.inflate(Au::from_px(2), Au::from_px(2)),
2923             LocalClip::from(self.clip.to_layout()),
2924             node,
2925             None,
2926             DisplayListSection::Content,
2927         );
2928         state.add_display_item(DisplayItem::Border(Box::new(BorderDisplayItem {
2929             base: base,
2930             border_widths: SideOffsets2D::new_all_same(Au::from_px(2)).to_layout(),
2931             details: BorderDetails::Normal(simple_normal_border(
2932                 color,
2933                 webrender_api::BorderStyle::Solid,
2934             )),
2935         })));
2936     }
2937 }
2938 
2939 trait ComputedValuesCursorUtility {
get_cursor(&self, default_cursor: CursorKind) -> Option<CursorKind>2940     fn get_cursor(&self, default_cursor: CursorKind) -> Option<CursorKind>;
2941 }
2942 
2943 impl ComputedValuesCursorUtility for ComputedValues {
2944     /// Gets the cursor to use given the specific ComputedValues.  `default_cursor` specifies
2945     /// the cursor to use if `cursor` is `auto`. Typically, this will be `PointerCursor`, but for
2946     /// text display items it may be `TextCursor` or `VerticalTextCursor`.
2947     #[inline]
get_cursor(&self, default_cursor: CursorKind) -> Option<CursorKind>2948     fn get_cursor(&self, default_cursor: CursorKind) -> Option<CursorKind> {
2949         match (
2950             self.get_pointing().pointer_events,
2951             self.get_pointing().cursor,
2952         ) {
2953             (PointerEvents::None, _) => None,
2954             (PointerEvents::Auto, Cursor(CursorKind::Auto)) => Some(default_cursor),
2955             (PointerEvents::Auto, Cursor(cursor)) => Some(cursor),
2956         }
2957     }
2958 }
2959 
2960 /// Adjusts `content_rect` as necessary for the given spread, and blur so that the resulting
2961 /// bounding rect contains all of a shadow's ink.
shadow_bounds(content_rect: &Rect<Au>, blur: Au, spread: Au) -> Rect<Au>2962 fn shadow_bounds(content_rect: &Rect<Au>, blur: Au, spread: Au) -> Rect<Au> {
2963     let inflation = spread + blur * BLUR_INFLATION_FACTOR;
2964     content_rect.inflate(inflation, inflation)
2965 }
2966 
2967 /// Adjusts borders as appropriate to account for a fragment's status as the
2968 /// first or last fragment within the range of an element.
2969 ///
2970 /// Specifically, this function sets border widths to zero on the sides for
2971 /// which the fragment is not outermost.
modify_border_width_for_inline_sides( border_width: &mut LogicalMargin<Au>, inline_border_info: InlineNodeBorderInfo, )2972 fn modify_border_width_for_inline_sides(
2973     border_width: &mut LogicalMargin<Au>,
2974     inline_border_info: InlineNodeBorderInfo,
2975 ) {
2976     if !inline_border_info.is_first_fragment_of_element {
2977         border_width.inline_start = Au(0);
2978     }
2979 
2980     if !inline_border_info.is_last_fragment_of_element {
2981         border_width.inline_end = Au(0);
2982     }
2983 }
2984 
2985 /// Describes how to paint the borders.
2986 #[derive(Clone, Copy)]
2987 pub enum BorderPaintingMode<'a> {
2988     /// Paint borders separately (`border-collapse: separate`).
2989     Separate,
2990     /// Paint collapsed borders.
2991     Collapse(&'a CollapsedBordersForCell),
2992     /// Paint no borders.
2993     Hidden,
2994 }
2995 
convert_text_run_to_glyphs( text_run: Arc<TextRun>, range: Range<ByteIndex>, mut origin: Point2D<Au>, ) -> Vec<GlyphInstance>2996 fn convert_text_run_to_glyphs(
2997     text_run: Arc<TextRun>,
2998     range: Range<ByteIndex>,
2999     mut origin: Point2D<Au>,
3000 ) -> Vec<GlyphInstance> {
3001     let mut glyphs = vec![];
3002 
3003     for slice in text_run.natural_word_slices_in_visual_order(&range) {
3004         for glyph in slice.glyphs.iter_glyphs_for_byte_range(&slice.range) {
3005             let glyph_advance = if glyph.char_is_space() {
3006                 glyph.advance() + text_run.extra_word_spacing
3007             } else {
3008                 glyph.advance()
3009             };
3010             if !slice.glyphs.is_whitespace() {
3011                 let glyph_offset = glyph.offset().unwrap_or(Point2D::zero());
3012                 let point = origin + glyph_offset.to_vector();
3013                 let glyph = GlyphInstance {
3014                     index: glyph.id(),
3015                     point: point.to_layout(),
3016                 };
3017                 glyphs.push(glyph);
3018             }
3019             origin.x += glyph_advance;
3020         }
3021     }
3022     return glyphs;
3023 }
3024 
3025 pub struct IndexableTextItem {
3026     /// The placement of the text item on the plane.
3027     pub origin: Point2D<Au>,
3028     /// The text run.
3029     pub text_run: Arc<TextRun>,
3030     /// The range of text within the text run.
3031     pub range: Range<ByteIndex>,
3032     /// The position of the start of the baseline of this text.
3033     pub baseline_origin: Point2D<Au>,
3034 }
3035 
3036 #[derive(Default)]
3037 pub struct IndexableText {
3038     inner: FnvHashMap<OpaqueNode, Vec<IndexableTextItem>>,
3039 }
3040 
3041 impl IndexableText {
insert(&mut self, node: OpaqueNode, item: IndexableTextItem)3042     fn insert(&mut self, node: OpaqueNode, item: IndexableTextItem) {
3043         let entries = self.inner.entry(node).or_insert(Vec::new());
3044         entries.push(item);
3045     }
3046 
get(&self, node: OpaqueNode) -> Option<&[IndexableTextItem]>3047     pub fn get(&self, node: OpaqueNode) -> Option<&[IndexableTextItem]> {
3048         self.inner.get(&node).map(|x| x.as_slice())
3049     }
3050 
3051     // Returns the text index within a node for the point of interest.
text_index(&self, node: OpaqueNode, point_in_item: Point2D<Au>) -> Option<usize>3052     pub fn text_index(&self, node: OpaqueNode, point_in_item: Point2D<Au>) -> Option<usize> {
3053         let item = self.inner.get(&node)?;
3054         // TODO(#20020): access all elements
3055         let point = point_in_item + item[0].origin.to_vector();
3056         let offset = point - item[0].baseline_origin;
3057         Some(item[0].text_run.range_index_of_advance(&item[0].range, offset.x))
3058     }
3059 }
3060