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 use api::{AlphaType, BorderRadius, BoxShadowClipMode, BuiltDisplayList, ClipMode, ColorF, ComplexClipRegion};
6 use api::{DeviceIntRect, DeviceIntSize, DevicePixelScale, Epoch, ExtendMode, FontRenderMode};
7 use api::{GlyphInstance, GlyphKey, GradientStop, ImageKey, ImageRendering, ItemRange, ItemTag};
8 use api::{LayerPoint, LayerRect, LayerSize, LayerToWorldTransform, LayerVector2D, LineOrientation};
9 use api::{LineStyle, PremultipliedColorF, YuvColorSpace, YuvFormat};
10 use border::{BorderCornerInstance, BorderEdgeKind};
11 use clip_scroll_tree::{ClipChainIndex, ClipScrollNodeIndex, CoordinateSystemId};
12 use clip_scroll_node::ClipScrollNode;
13 use clip::{ClipChain, ClipChainNode, ClipChainNodeIter, ClipChainNodeRef, ClipSource};
14 use clip::{ClipSourcesHandle, ClipWorkItem};
15 use frame_builder::{FrameBuildingContext, FrameBuildingState, PictureContext, PictureState};
16 use frame_builder::PrimitiveRunContext;
17 use glyph_rasterizer::{FontInstance, FontTransform};
18 use gpu_cache::{GpuBlockData, GpuCache, GpuCacheAddress, GpuCacheHandle, GpuDataRequest,
19                 ToGpuBlocks};
20 use gpu_types::{ClipChainRectIndex};
21 use picture::{PictureKind, PicturePrimitive};
22 use render_task::{BlitSource, RenderTask, RenderTaskCacheKey, RenderTaskCacheKeyKind};
23 use render_task::RenderTaskId;
24 use renderer::{MAX_VERTEX_TEXTURE_WIDTH};
25 use resource_cache::{CacheItem, ImageProperties, ImageRequest, ResourceCache};
26 use segment::SegmentBuilder;
27 use std::{mem, usize};
28 use std::sync::Arc;
29 use util::{MatrixHelpers, WorldToLayerFastTransform, calculate_screen_bounding_rect};
30 use util::{pack_as_float, recycle_vec};
31 
32 
33 const MIN_BRUSH_SPLIT_AREA: f32 = 256.0 * 256.0;
34 
35 #[derive(Clone, Copy, Debug, Eq, PartialEq)]
36 pub struct ScrollNodeAndClipChain {
37     pub scroll_node_id: ClipScrollNodeIndex,
38     pub clip_chain_index: ClipChainIndex,
39 }
40 
41 impl ScrollNodeAndClipChain {
new( scroll_node_id: ClipScrollNodeIndex, clip_chain_index: ClipChainIndex ) -> ScrollNodeAndClipChain42     pub fn new(
43         scroll_node_id: ClipScrollNodeIndex,
44         clip_chain_index: ClipChainIndex
45     ) -> ScrollNodeAndClipChain {
46         ScrollNodeAndClipChain { scroll_node_id, clip_chain_index }
47     }
48 }
49 
50 #[derive(Debug)]
51 pub struct PrimitiveRun {
52     pub base_prim_index: PrimitiveIndex,
53     pub count: usize,
54     pub clip_and_scroll: ScrollNodeAndClipChain,
55 }
56 
57 #[derive(Debug, Copy, Clone)]
58 pub struct PrimitiveOpacity {
59     pub is_opaque: bool,
60 }
61 
62 impl PrimitiveOpacity {
opaque() -> PrimitiveOpacity63     pub fn opaque() -> PrimitiveOpacity {
64         PrimitiveOpacity { is_opaque: true }
65     }
66 
translucent() -> PrimitiveOpacity67     pub fn translucent() -> PrimitiveOpacity {
68         PrimitiveOpacity { is_opaque: false }
69     }
70 
from_alpha(alpha: f32) -> PrimitiveOpacity71     pub fn from_alpha(alpha: f32) -> PrimitiveOpacity {
72         PrimitiveOpacity {
73             is_opaque: alpha == 1.0,
74         }
75     }
76 }
77 
78 #[derive(Debug, Copy, Clone)]
79 pub struct CachedGradientIndex(pub usize);
80 
81 pub struct CachedGradient {
82     pub handle: GpuCacheHandle,
83 }
84 
85 impl CachedGradient {
new() -> CachedGradient86     pub fn new() -> CachedGradient {
87         CachedGradient {
88             handle: GpuCacheHandle::new(),
89         }
90     }
91 }
92 
93 // Represents the local space rect of a list of
94 // primitive runs. For most primitive runs, the
95 // primitive runs are attached to the parent they
96 // are declared in. However, when a primitive run
97 // is part of a 3d rendering context, it may get
98 // hoisted to a higher level in the picture tree.
99 // When this happens, we need to also calculate the
100 // local space rects in the original space. This
101 // allows constructing the true world space polygons
102 // for the primitive, to enable the plane splitting
103 // logic to work correctly.
104 // TODO(gw) In the future, we can probably simplify
105 //          this - perhaps calculate the world space
106 //          polygons directly and store internally
107 //          in the picture structure.
108 #[derive(Debug)]
109 pub struct PrimitiveRunLocalRect {
110     pub local_rect_in_actual_parent_space: LayerRect,
111     pub local_rect_in_original_parent_space: LayerRect,
112 }
113 
114 /// For external images, it's not possible to know the
115 /// UV coords of the image (or the image data itself)
116 /// until the render thread receives the frame and issues
117 /// callbacks to the client application. For external
118 /// images that are visible, a DeferredResolve is created
119 /// that is stored in the frame. This allows the render
120 /// thread to iterate this list and update any changed
121 /// texture data and update the UV rect.
122 #[cfg_attr(feature = "capture", derive(Serialize))]
123 #[cfg_attr(feature = "replay", derive(Deserialize))]
124 pub struct DeferredResolve {
125     pub address: GpuCacheAddress,
126     pub image_properties: ImageProperties,
127 }
128 
129 #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash, Ord, PartialOrd)]
130 pub struct SpecificPrimitiveIndex(pub usize);
131 
132 #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash, Ord, PartialOrd)]
133 #[cfg_attr(feature = "capture", derive(Serialize))]
134 #[cfg_attr(feature = "replay", derive(Deserialize))]
135 pub struct PrimitiveIndex(pub usize);
136 
137 #[derive(Debug, Copy, Clone, Eq, PartialEq)]
138 pub enum PrimitiveKind {
139     TextRun,
140     Image,
141     Border,
142     Picture,
143     Brush,
144 }
145 
146 impl GpuCacheHandle {
as_int(&self, gpu_cache: &GpuCache) -> i32147     pub fn as_int(&self, gpu_cache: &GpuCache) -> i32 {
148         gpu_cache.get_address(self).as_int()
149     }
150 }
151 
152 impl GpuCacheAddress {
as_int(&self) -> i32153     pub fn as_int(&self) -> i32 {
154         // TODO(gw): Temporarily encode GPU Cache addresses as a single int.
155         //           In the future, we can change the PrimitiveInstance struct
156         //           to use 2x u16 for the vertex attribute instead of an i32.
157         self.v as i32 * MAX_VERTEX_TEXTURE_WIDTH as i32 + self.u as i32
158     }
159 }
160 
161 #[derive(Debug, Copy, Clone)]
162 pub struct ScreenRect {
163     pub clipped: DeviceIntRect,
164     pub unclipped: DeviceIntRect,
165 }
166 
167 // TODO(gw): Pack the fields here better!
168 #[derive(Debug)]
169 pub struct PrimitiveMetadata {
170     pub opacity: PrimitiveOpacity,
171     pub clip_sources: Option<ClipSourcesHandle>,
172     pub prim_kind: PrimitiveKind,
173     pub cpu_prim_index: SpecificPrimitiveIndex,
174     pub gpu_location: GpuCacheHandle,
175     pub clip_task_id: Option<RenderTaskId>,
176 
177     // TODO(gw): In the future, we should just pull these
178     //           directly from the DL item, instead of
179     //           storing them here.
180     pub local_rect: LayerRect,
181     pub local_clip_rect: LayerRect,
182     pub clip_chain_rect_index: ClipChainRectIndex,
183     pub is_backface_visible: bool,
184     pub screen_rect: Option<ScreenRect>,
185 
186     /// A tag used to identify this primitive outside of WebRender. This is
187     /// used for returning useful data during hit testing.
188     pub tag: Option<ItemTag>,
189 }
190 
191 #[derive(Debug)]
192 pub enum BrushKind {
193     Solid {
194         color: ColorF,
195     },
196     Clear,
197     Line {
198         color: PremultipliedColorF,
199         wavy_line_thickness: f32,
200         style: LineStyle,
201         orientation: LineOrientation,
202     },
203     Picture,
204     Image {
205         request: ImageRequest,
206         current_epoch: Epoch,
207         alpha_type: AlphaType,
208     },
209     YuvImage {
210         yuv_key: [ImageKey; 3],
211         format: YuvFormat,
212         color_space: YuvColorSpace,
213         image_rendering: ImageRendering,
214     },
215     RadialGradient {
216         gradient_index: CachedGradientIndex,
217         stops_range: ItemRange<GradientStop>,
218         extend_mode: ExtendMode,
219         start_center: LayerPoint,
220         end_center: LayerPoint,
221         start_radius: f32,
222         end_radius: f32,
223         ratio_xy: f32,
224     },
225     LinearGradient {
226         gradient_index: CachedGradientIndex,
227         stops_range: ItemRange<GradientStop>,
228         stops_count: usize,
229         extend_mode: ExtendMode,
230         reverse_stops: bool,
231         start_point: LayerPoint,
232         end_point: LayerPoint,
233     }
234 }
235 
236 impl BrushKind {
supports_segments(&self) -> bool237     fn supports_segments(&self) -> bool {
238         match *self {
239             BrushKind::Solid { .. } |
240             BrushKind::Picture |
241             BrushKind::Image { .. } |
242             BrushKind::YuvImage { .. } |
243             BrushKind::RadialGradient { .. } |
244             BrushKind::LinearGradient { .. } => true,
245 
246             BrushKind::Clear |
247             BrushKind::Line { .. } => false,
248         }
249     }
250 }
251 
252 bitflags! {
253     /// Each bit of the edge AA mask is:
254     /// 0, when the edge of the primitive needs to be considered for AA
255     /// 1, when the edge of the segment needs to be considered for AA
256     ///
257     /// *Note*: the bit values have to match the shader logic in
258     /// `write_transform_vertex()` function.
259     pub struct EdgeAaSegmentMask: u8 {
260         const LEFT = 0x1;
261         const TOP = 0x2;
262         const RIGHT = 0x4;
263         const BOTTOM = 0x8;
264     }
265 }
266 
267 #[derive(Debug)]
268 pub struct BrushSegment {
269     pub local_rect: LayerRect,
270     pub clip_task_id: Option<RenderTaskId>,
271     pub may_need_clip_mask: bool,
272     pub edge_flags: EdgeAaSegmentMask,
273 }
274 
275 impl BrushSegment {
new( origin: LayerPoint, size: LayerSize, may_need_clip_mask: bool, edge_flags: EdgeAaSegmentMask, ) -> BrushSegment276     pub fn new(
277         origin: LayerPoint,
278         size: LayerSize,
279         may_need_clip_mask: bool,
280         edge_flags: EdgeAaSegmentMask,
281     ) -> BrushSegment {
282         BrushSegment {
283             local_rect: LayerRect::new(origin, size),
284             clip_task_id: None,
285             may_need_clip_mask,
286             edge_flags,
287         }
288     }
289 }
290 
291 #[derive(Copy, Clone, Debug, PartialEq)]
292 pub enum BrushClipMaskKind {
293     Unknown,
294     Individual,
295     Global,
296 }
297 
298 #[derive(Debug)]
299 pub struct BrushSegmentDescriptor {
300     pub segments: Vec<BrushSegment>,
301     pub clip_mask_kind: BrushClipMaskKind,
302 }
303 
304 #[derive(Debug)]
305 pub struct BrushPrimitive {
306     pub kind: BrushKind,
307     pub segment_desc: Option<BrushSegmentDescriptor>,
308 }
309 
310 impl BrushPrimitive {
new( kind: BrushKind, segment_desc: Option<BrushSegmentDescriptor>, ) -> BrushPrimitive311     pub fn new(
312         kind: BrushKind,
313         segment_desc: Option<BrushSegmentDescriptor>,
314     ) -> BrushPrimitive {
315         BrushPrimitive {
316             kind,
317             segment_desc,
318         }
319     }
320 
write_gpu_blocks(&self, request: &mut GpuDataRequest)321     fn write_gpu_blocks(&self, request: &mut GpuDataRequest) {
322         // has to match VECS_PER_SPECIFIC_BRUSH
323         match self.kind {
324             BrushKind::Picture |
325             BrushKind::YuvImage { .. } => {
326             }
327             BrushKind::Image { .. } => {
328                 request.push([0.0; 4]);
329             }
330             BrushKind::Solid { color } => {
331                 request.push(color.premultiplied());
332             }
333             BrushKind::Clear => {
334                 // Opaque black with operator dest out
335                 request.push(PremultipliedColorF::BLACK);
336             }
337             BrushKind::Line { color, wavy_line_thickness, style, orientation } => {
338                 request.push(color);
339                 request.push([
340                     wavy_line_thickness,
341                     pack_as_float(style as u32),
342                     pack_as_float(orientation as u32),
343                     0.0,
344                 ]);
345             }
346             BrushKind::LinearGradient { start_point, end_point, extend_mode, .. } => {
347                 request.push([
348                     start_point.x,
349                     start_point.y,
350                     end_point.x,
351                     end_point.y,
352                 ]);
353                 request.push([
354                     pack_as_float(extend_mode as u32),
355                     0.0,
356                     0.0,
357                     0.0,
358                 ]);
359             }
360             BrushKind::RadialGradient { start_center, end_center, start_radius, end_radius, ratio_xy, extend_mode, .. } => {
361                 request.push([
362                     start_center.x,
363                     start_center.y,
364                     end_center.x,
365                     end_center.y,
366                 ]);
367                 request.push([
368                     start_radius,
369                     end_radius,
370                     ratio_xy,
371                     pack_as_float(extend_mode as u32),
372                 ]);
373             }
374         }
375     }
376 }
377 
378 // Key that identifies a unique (partial) image that is being
379 // stored in the render task cache.
380 #[derive(Debug, Copy, Clone, Eq, Hash, PartialEq)]
381 #[cfg_attr(feature = "capture", derive(Serialize))]
382 #[cfg_attr(feature = "replay", derive(Deserialize))]
383 pub struct ImageCacheKey {
384     pub request: ImageRequest,
385     pub texel_rect: Option<DeviceIntRect>,
386 }
387 
388 // Where to find the texture data for an image primitive.
389 #[derive(Debug)]
390 pub enum ImageSource {
391     // A normal image - just reference the texture cache.
392     Default,
393     // An image that is pre-rendered into the texture cache
394     // via a render task.
395     Cache {
396         size: DeviceIntSize,
397         item: CacheItem,
398     },
399 }
400 
401 #[derive(Debug)]
402 pub struct ImagePrimitiveCpu {
403     pub tile_spacing: LayerSize,
404     pub alpha_type: AlphaType,
405     pub stretch_size: LayerSize,
406     pub current_epoch: Epoch,
407     pub source: ImageSource,
408     pub key: ImageCacheKey,
409 }
410 
411 impl ToGpuBlocks for ImagePrimitiveCpu {
write_gpu_blocks(&self, mut request: GpuDataRequest)412     fn write_gpu_blocks(&self, mut request: GpuDataRequest) {
413         request.push([
414             self.stretch_size.width, self.stretch_size.height,
415             self.tile_spacing.width, self.tile_spacing.height,
416         ]);
417     }
418 }
419 
420 #[derive(Debug)]
421 pub struct BorderPrimitiveCpu {
422     pub corner_instances: [BorderCornerInstance; 4],
423     pub edges: [BorderEdgeKind; 4],
424     pub gpu_blocks: [GpuBlockData; 8],
425 }
426 
427 impl ToGpuBlocks for BorderPrimitiveCpu {
write_gpu_blocks(&self, mut request: GpuDataRequest)428     fn write_gpu_blocks(&self, mut request: GpuDataRequest) {
429         request.extend_from_slice(&self.gpu_blocks);
430     }
431 }
432 
433 // The gradient entry index for the first color stop
434 pub const GRADIENT_DATA_FIRST_STOP: usize = 0;
435 // The gradient entry index for the last color stop
436 pub const GRADIENT_DATA_LAST_STOP: usize = GRADIENT_DATA_SIZE - 1;
437 
438 // The start of the gradient data table
439 pub const GRADIENT_DATA_TABLE_BEGIN: usize = GRADIENT_DATA_FIRST_STOP + 1;
440 // The exclusive bound of the gradient data table
441 pub const GRADIENT_DATA_TABLE_END: usize = GRADIENT_DATA_LAST_STOP;
442 // The number of entries in the gradient data table.
443 pub const GRADIENT_DATA_TABLE_SIZE: usize = 128;
444 
445 // The number of entries in a gradient data: GRADIENT_DATA_TABLE_SIZE + first stop entry + last stop entry
446 pub const GRADIENT_DATA_SIZE: usize = GRADIENT_DATA_TABLE_SIZE + 2;
447 
448 #[derive(Debug)]
449 #[repr(C)]
450 // An entry in a gradient data table representing a segment of the gradient color space.
451 pub struct GradientDataEntry {
452     pub start_color: PremultipliedColorF,
453     pub end_color: PremultipliedColorF,
454 }
455 
456 struct GradientGpuBlockBuilder<'a> {
457     stops_range: ItemRange<GradientStop>,
458     display_list: &'a BuiltDisplayList,
459 }
460 
461 impl<'a> GradientGpuBlockBuilder<'a> {
new( stops_range: ItemRange<GradientStop>, display_list: &'a BuiltDisplayList, ) -> Self462     fn new(
463         stops_range: ItemRange<GradientStop>,
464         display_list: &'a BuiltDisplayList,
465     ) -> Self {
466         GradientGpuBlockBuilder {
467             stops_range,
468             display_list,
469         }
470     }
471 
472     /// Generate a color ramp filling the indices in [start_idx, end_idx) and interpolating
473     /// from start_color to end_color.
fill_colors( &self, start_idx: usize, end_idx: usize, start_color: &PremultipliedColorF, end_color: &PremultipliedColorF, entries: &mut [GradientDataEntry; GRADIENT_DATA_SIZE], )474     fn fill_colors(
475         &self,
476         start_idx: usize,
477         end_idx: usize,
478         start_color: &PremultipliedColorF,
479         end_color: &PremultipliedColorF,
480         entries: &mut [GradientDataEntry; GRADIENT_DATA_SIZE],
481     ) {
482         // Calculate the color difference for individual steps in the ramp.
483         let inv_steps = 1.0 / (end_idx - start_idx) as f32;
484         let step_r = (end_color.r - start_color.r) * inv_steps;
485         let step_g = (end_color.g - start_color.g) * inv_steps;
486         let step_b = (end_color.b - start_color.b) * inv_steps;
487         let step_a = (end_color.a - start_color.a) * inv_steps;
488 
489         let mut cur_color = *start_color;
490 
491         // Walk the ramp writing start and end colors for each entry.
492         for index in start_idx .. end_idx {
493             let entry = &mut entries[index];
494             entry.start_color = cur_color;
495             cur_color.r += step_r;
496             cur_color.g += step_g;
497             cur_color.b += step_b;
498             cur_color.a += step_a;
499             entry.end_color = cur_color;
500         }
501     }
502 
503     /// Compute an index into the gradient entry table based on a gradient stop offset. This
504     /// function maps offsets from [0, 1] to indices in [GRADIENT_DATA_TABLE_BEGIN, GRADIENT_DATA_TABLE_END].
505     #[inline]
get_index(offset: f32) -> usize506     fn get_index(offset: f32) -> usize {
507         (offset.max(0.0).min(1.0) * GRADIENT_DATA_TABLE_SIZE as f32 +
508             GRADIENT_DATA_TABLE_BEGIN as f32)
509             .round() as usize
510     }
511 
512     // Build the gradient data from the supplied stops, reversing them if necessary.
build(&self, reverse_stops: bool, request: &mut GpuDataRequest)513     fn build(&self, reverse_stops: bool, request: &mut GpuDataRequest) {
514         let src_stops = self.display_list.get(self.stops_range);
515 
516         // Preconditions (should be ensured by DisplayListBuilder):
517         // * we have at least two stops
518         // * first stop has offset 0.0
519         // * last stop has offset 1.0
520 
521         let mut src_stops = src_stops.into_iter();
522         let first = src_stops.next().unwrap();
523         let mut cur_color = first.color.premultiplied();
524         debug_assert_eq!(first.offset, 0.0);
525 
526         // A table of gradient entries, with two colors per entry, that specify the start and end color
527         // within the segment of the gradient space represented by that entry. To lookup a gradient result,
528         // first the entry index is calculated to determine which two colors to interpolate between, then
529         // the offset within that entry bucket is used to interpolate between the two colors in that entry.
530         // This layout preserves hard stops, as the end color for a given entry can differ from the start
531         // color for the following entry, despite them being adjacent. Colors are stored within in BGRA8
532         // format for texture upload. This table requires the gradient color stops to be normalized to the
533         // range [0, 1]. The first and last entries hold the first and last color stop colors respectively,
534         // while the entries in between hold the interpolated color stop values for the range [0, 1].
535         let mut entries: [GradientDataEntry; GRADIENT_DATA_SIZE] = unsafe { mem::uninitialized() };
536 
537         if reverse_stops {
538             // Fill in the first entry (for reversed stops) with the first color stop
539             self.fill_colors(
540                 GRADIENT_DATA_LAST_STOP,
541                 GRADIENT_DATA_LAST_STOP + 1,
542                 &cur_color,
543                 &cur_color,
544                 &mut entries,
545             );
546 
547             // Fill in the center of the gradient table, generating a color ramp between each consecutive pair
548             // of gradient stops. Each iteration of a loop will fill the indices in [next_idx, cur_idx). The
549             // loop will then fill indices in [GRADIENT_DATA_TABLE_BEGIN, GRADIENT_DATA_TABLE_END).
550             let mut cur_idx = GRADIENT_DATA_TABLE_END;
551             for next in src_stops {
552                 let next_color = next.color.premultiplied();
553                 let next_idx = Self::get_index(1.0 - next.offset);
554 
555                 if next_idx < cur_idx {
556                     self.fill_colors(next_idx, cur_idx, &next_color, &cur_color, &mut entries);
557                     cur_idx = next_idx;
558                 }
559 
560                 cur_color = next_color;
561             }
562             debug_assert_eq!(cur_idx, GRADIENT_DATA_TABLE_BEGIN);
563 
564             // Fill in the last entry (for reversed stops) with the last color stop
565             self.fill_colors(
566                 GRADIENT_DATA_FIRST_STOP,
567                 GRADIENT_DATA_FIRST_STOP + 1,
568                 &cur_color,
569                 &cur_color,
570                 &mut entries,
571             );
572         } else {
573             // Fill in the first entry with the first color stop
574             self.fill_colors(
575                 GRADIENT_DATA_FIRST_STOP,
576                 GRADIENT_DATA_FIRST_STOP + 1,
577                 &cur_color,
578                 &cur_color,
579                 &mut entries,
580             );
581 
582             // Fill in the center of the gradient table, generating a color ramp between each consecutive pair
583             // of gradient stops. Each iteration of a loop will fill the indices in [cur_idx, next_idx). The
584             // loop will then fill indices in [GRADIENT_DATA_TABLE_BEGIN, GRADIENT_DATA_TABLE_END).
585             let mut cur_idx = GRADIENT_DATA_TABLE_BEGIN;
586             for next in src_stops {
587                 let next_color = next.color.premultiplied();
588                 let next_idx = Self::get_index(next.offset);
589 
590                 if next_idx > cur_idx {
591                     self.fill_colors(cur_idx, next_idx, &cur_color, &next_color, &mut entries);
592                     cur_idx = next_idx;
593                 }
594 
595                 cur_color = next_color;
596             }
597             debug_assert_eq!(cur_idx, GRADIENT_DATA_TABLE_END);
598 
599             // Fill in the last entry with the last color stop
600             self.fill_colors(
601                 GRADIENT_DATA_LAST_STOP,
602                 GRADIENT_DATA_LAST_STOP + 1,
603                 &cur_color,
604                 &cur_color,
605                 &mut entries,
606             );
607         }
608 
609         for entry in entries.iter() {
610             request.push(entry.start_color);
611             request.push(entry.end_color);
612         }
613     }
614 }
615 
616 #[derive(Debug, Clone)]
617 pub struct TextRunPrimitiveCpu {
618     pub font: FontInstance,
619     pub offset: LayerVector2D,
620     pub glyph_range: ItemRange<GlyphInstance>,
621     pub glyph_count: usize,
622     pub glyph_keys: Vec<GlyphKey>,
623     pub glyph_gpu_blocks: Vec<GpuBlockData>,
624     pub shadow: bool,
625 }
626 
627 impl TextRunPrimitiveCpu {
get_font( &self, device_pixel_scale: DevicePixelScale, transform: Option<LayerToWorldTransform>, ) -> FontInstance628     pub fn get_font(
629         &self,
630         device_pixel_scale: DevicePixelScale,
631         transform: Option<LayerToWorldTransform>,
632     ) -> FontInstance {
633         let mut font = self.font.clone();
634         font.size = font.size.scale_by(device_pixel_scale.0);
635         if let Some(transform) = transform {
636             if transform.has_perspective_component() || !transform.has_2d_inverse() {
637                 font.render_mode = font.render_mode.limit_by(FontRenderMode::Alpha);
638             } else {
639                 font.transform = FontTransform::from(&transform).quantize();
640             }
641         }
642         font
643     }
644 
prepare_for_render( &mut self, resource_cache: &mut ResourceCache, device_pixel_scale: DevicePixelScale, transform: Option<LayerToWorldTransform>, display_list: &BuiltDisplayList, gpu_cache: &mut GpuCache, )645     fn prepare_for_render(
646         &mut self,
647         resource_cache: &mut ResourceCache,
648         device_pixel_scale: DevicePixelScale,
649         transform: Option<LayerToWorldTransform>,
650         display_list: &BuiltDisplayList,
651         gpu_cache: &mut GpuCache,
652     ) {
653         let font = self.get_font(device_pixel_scale, transform);
654 
655         // Cache the glyph positions, if not in the cache already.
656         // TODO(gw): In the future, remove `glyph_instances`
657         //           completely, and just reference the glyphs
658         //           directly from the display list.
659         if self.glyph_keys.is_empty() {
660             let subpx_dir = font.subpx_dir.limit_by(font.render_mode);
661             let src_glyphs = display_list.get(self.glyph_range);
662 
663             // TODO(gw): If we support chunks() on AuxIter
664             //           in the future, this code below could
665             //           be much simpler...
666             let mut gpu_block = [0.0; 4];
667             for (i, src) in src_glyphs.enumerate() {
668                 let key = GlyphKey::new(src.index, src.point, font.render_mode, subpx_dir);
669                 self.glyph_keys.push(key);
670 
671                 // Two glyphs are packed per GPU block.
672 
673                 if (i & 1) == 0 {
674                     gpu_block[0] = src.point.x;
675                     gpu_block[1] = src.point.y;
676                 } else {
677                     gpu_block[2] = src.point.x;
678                     gpu_block[3] = src.point.y;
679                     self.glyph_gpu_blocks.push(gpu_block.into());
680                 }
681             }
682 
683             // Ensure the last block is added in the case
684             // of an odd number of glyphs.
685             if (self.glyph_keys.len() & 1) != 0 {
686                 self.glyph_gpu_blocks.push(gpu_block.into());
687             }
688         }
689 
690         resource_cache.request_glyphs(font, &self.glyph_keys, gpu_cache);
691     }
692 
write_gpu_blocks(&self, request: &mut GpuDataRequest)693     fn write_gpu_blocks(&self, request: &mut GpuDataRequest) {
694         request.push(ColorF::from(self.font.color).premultiplied());
695         // this is the only case where we need to provide plain color to GPU
696         let bg_color = ColorF::from(self.font.bg_color);
697         request.push([bg_color.r, bg_color.g, bg_color.b, 1.0]);
698         request.push([
699             self.offset.x,
700             self.offset.y,
701             0.0,
702             0.0,
703         ]);
704         request.extend_from_slice(&self.glyph_gpu_blocks);
705 
706         assert!(request.current_used_block_num() <= MAX_VERTEX_TEXTURE_WIDTH);
707     }
708 }
709 
710 #[derive(Debug)]
711 #[repr(C)]
712 struct ClipRect {
713     rect: LayerRect,
714     mode: f32,
715 }
716 
717 #[derive(Debug)]
718 #[repr(C)]
719 struct ClipCorner {
720     rect: LayerRect,
721     outer_radius_x: f32,
722     outer_radius_y: f32,
723     inner_radius_x: f32,
724     inner_radius_y: f32,
725 }
726 
727 impl ToGpuBlocks for ClipCorner {
write_gpu_blocks(&self, mut request: GpuDataRequest)728     fn write_gpu_blocks(&self, mut request: GpuDataRequest) {
729         self.write(&mut request)
730     }
731 }
732 
733 impl ClipCorner {
write(&self, request: &mut GpuDataRequest)734     fn write(&self, request: &mut GpuDataRequest) {
735         request.push(self.rect);
736         request.push([
737             self.outer_radius_x,
738             self.outer_radius_y,
739             self.inner_radius_x,
740             self.inner_radius_y,
741         ]);
742     }
743 
uniform(rect: LayerRect, outer_radius: f32, inner_radius: f32) -> ClipCorner744     fn uniform(rect: LayerRect, outer_radius: f32, inner_radius: f32) -> ClipCorner {
745         ClipCorner {
746             rect,
747             outer_radius_x: outer_radius,
748             outer_radius_y: outer_radius,
749             inner_radius_x: inner_radius,
750             inner_radius_y: inner_radius,
751         }
752     }
753 }
754 
755 #[derive(Debug)]
756 #[repr(C)]
757 pub struct ImageMaskData {
758     pub local_rect: LayerRect,
759 }
760 
761 impl ToGpuBlocks for ImageMaskData {
write_gpu_blocks(&self, mut request: GpuDataRequest)762     fn write_gpu_blocks(&self, mut request: GpuDataRequest) {
763         request.push(self.local_rect);
764     }
765 }
766 
767 #[derive(Debug)]
768 pub struct ClipData {
769     rect: ClipRect,
770     top_left: ClipCorner,
771     top_right: ClipCorner,
772     bottom_left: ClipCorner,
773     bottom_right: ClipCorner,
774 }
775 
776 impl ClipData {
rounded_rect(rect: &LayerRect, radii: &BorderRadius, mode: ClipMode) -> ClipData777     pub fn rounded_rect(rect: &LayerRect, radii: &BorderRadius, mode: ClipMode) -> ClipData {
778         ClipData {
779             rect: ClipRect {
780                 rect: *rect,
781                 mode: mode as u32 as f32,
782             },
783             top_left: ClipCorner {
784                 rect: LayerRect::new(
785                     LayerPoint::new(rect.origin.x, rect.origin.y),
786                     LayerSize::new(radii.top_left.width, radii.top_left.height),
787                 ),
788                 outer_radius_x: radii.top_left.width,
789                 outer_radius_y: radii.top_left.height,
790                 inner_radius_x: 0.0,
791                 inner_radius_y: 0.0,
792             },
793             top_right: ClipCorner {
794                 rect: LayerRect::new(
795                     LayerPoint::new(
796                         rect.origin.x + rect.size.width - radii.top_right.width,
797                         rect.origin.y,
798                     ),
799                     LayerSize::new(radii.top_right.width, radii.top_right.height),
800                 ),
801                 outer_radius_x: radii.top_right.width,
802                 outer_radius_y: radii.top_right.height,
803                 inner_radius_x: 0.0,
804                 inner_radius_y: 0.0,
805             },
806             bottom_left: ClipCorner {
807                 rect: LayerRect::new(
808                     LayerPoint::new(
809                         rect.origin.x,
810                         rect.origin.y + rect.size.height - radii.bottom_left.height,
811                     ),
812                     LayerSize::new(radii.bottom_left.width, radii.bottom_left.height),
813                 ),
814                 outer_radius_x: radii.bottom_left.width,
815                 outer_radius_y: radii.bottom_left.height,
816                 inner_radius_x: 0.0,
817                 inner_radius_y: 0.0,
818             },
819             bottom_right: ClipCorner {
820                 rect: LayerRect::new(
821                     LayerPoint::new(
822                         rect.origin.x + rect.size.width - radii.bottom_right.width,
823                         rect.origin.y + rect.size.height - radii.bottom_right.height,
824                     ),
825                     LayerSize::new(radii.bottom_right.width, radii.bottom_right.height),
826                 ),
827                 outer_radius_x: radii.bottom_right.width,
828                 outer_radius_y: radii.bottom_right.height,
829                 inner_radius_x: 0.0,
830                 inner_radius_y: 0.0,
831             },
832         }
833     }
834 
uniform(rect: LayerRect, radius: f32, mode: ClipMode) -> ClipData835     pub fn uniform(rect: LayerRect, radius: f32, mode: ClipMode) -> ClipData {
836         ClipData {
837             rect: ClipRect {
838                 rect,
839                 mode: mode as u32 as f32,
840             },
841             top_left: ClipCorner::uniform(
842                 LayerRect::new(
843                     LayerPoint::new(rect.origin.x, rect.origin.y),
844                     LayerSize::new(radius, radius),
845                 ),
846                 radius,
847                 0.0,
848             ),
849             top_right: ClipCorner::uniform(
850                 LayerRect::new(
851                     LayerPoint::new(rect.origin.x + rect.size.width - radius, rect.origin.y),
852                     LayerSize::new(radius, radius),
853                 ),
854                 radius,
855                 0.0,
856             ),
857             bottom_left: ClipCorner::uniform(
858                 LayerRect::new(
859                     LayerPoint::new(rect.origin.x, rect.origin.y + rect.size.height - radius),
860                     LayerSize::new(radius, radius),
861                 ),
862                 radius,
863                 0.0,
864             ),
865             bottom_right: ClipCorner::uniform(
866                 LayerRect::new(
867                     LayerPoint::new(
868                         rect.origin.x + rect.size.width - radius,
869                         rect.origin.y + rect.size.height - radius,
870                     ),
871                     LayerSize::new(radius, radius),
872                 ),
873                 radius,
874                 0.0,
875             ),
876         }
877     }
878 
write(&self, request: &mut GpuDataRequest)879     pub fn write(&self, request: &mut GpuDataRequest) {
880         request.push(self.rect.rect);
881         request.push([self.rect.mode, 0.0, 0.0, 0.0]);
882         for corner in &[
883             &self.top_left,
884             &self.top_right,
885             &self.bottom_left,
886             &self.bottom_right,
887         ] {
888             corner.write(request);
889         }
890     }
891 }
892 
893 #[derive(Debug)]
894 pub enum PrimitiveContainer {
895     TextRun(TextRunPrimitiveCpu),
896     Image(ImagePrimitiveCpu),
897     Border(BorderPrimitiveCpu),
898     Picture(PicturePrimitive),
899     Brush(BrushPrimitive),
900 }
901 
902 pub struct PrimitiveStore {
903     /// CPU side information only.
904     pub cpu_brushes: Vec<BrushPrimitive>,
905     pub cpu_text_runs: Vec<TextRunPrimitiveCpu>,
906     pub cpu_pictures: Vec<PicturePrimitive>,
907     pub cpu_images: Vec<ImagePrimitiveCpu>,
908     pub cpu_metadata: Vec<PrimitiveMetadata>,
909     pub cpu_borders: Vec<BorderPrimitiveCpu>,
910 }
911 
912 impl PrimitiveStore {
new() -> PrimitiveStore913     pub fn new() -> PrimitiveStore {
914         PrimitiveStore {
915             cpu_metadata: Vec::new(),
916             cpu_brushes: Vec::new(),
917             cpu_text_runs: Vec::new(),
918             cpu_pictures: Vec::new(),
919             cpu_images: Vec::new(),
920             cpu_borders: Vec::new(),
921         }
922     }
923 
recycle(self) -> Self924     pub fn recycle(self) -> Self {
925         PrimitiveStore {
926             cpu_metadata: recycle_vec(self.cpu_metadata),
927             cpu_brushes: recycle_vec(self.cpu_brushes),
928             cpu_text_runs: recycle_vec(self.cpu_text_runs),
929             cpu_pictures: recycle_vec(self.cpu_pictures),
930             cpu_images: recycle_vec(self.cpu_images),
931             cpu_borders: recycle_vec(self.cpu_borders),
932         }
933     }
934 
add_primitive( &mut self, local_rect: &LayerRect, local_clip_rect: &LayerRect, is_backface_visible: bool, clip_sources: Option<ClipSourcesHandle>, tag: Option<ItemTag>, container: PrimitiveContainer, ) -> PrimitiveIndex935     pub fn add_primitive(
936         &mut self,
937         local_rect: &LayerRect,
938         local_clip_rect: &LayerRect,
939         is_backface_visible: bool,
940         clip_sources: Option<ClipSourcesHandle>,
941         tag: Option<ItemTag>,
942         container: PrimitiveContainer,
943     ) -> PrimitiveIndex {
944         let prim_index = self.cpu_metadata.len();
945 
946         let base_metadata = PrimitiveMetadata {
947             clip_sources,
948             gpu_location: GpuCacheHandle::new(),
949             clip_task_id: None,
950             local_rect: *local_rect,
951             local_clip_rect: *local_clip_rect,
952             clip_chain_rect_index: ClipChainRectIndex(0),
953             is_backface_visible: is_backface_visible,
954             screen_rect: None,
955             tag,
956             opacity: PrimitiveOpacity::translucent(),
957             prim_kind: PrimitiveKind::Brush,
958             cpu_prim_index: SpecificPrimitiveIndex(0),
959         };
960 
961         let metadata = match container {
962             PrimitiveContainer::Brush(brush) => {
963                 let opacity = match brush.kind {
964                     BrushKind::Clear => PrimitiveOpacity::translucent(),
965                     BrushKind::Solid { ref color } => PrimitiveOpacity::from_alpha(color.a),
966                     BrushKind::Line { .. } => PrimitiveOpacity::translucent(),
967                     BrushKind::Image { .. } => PrimitiveOpacity::translucent(),
968                     BrushKind::YuvImage { .. } => PrimitiveOpacity::opaque(),
969                     BrushKind::RadialGradient { .. } => PrimitiveOpacity::translucent(),
970                     BrushKind::LinearGradient { .. } => PrimitiveOpacity::translucent(),
971                     BrushKind::Picture => {
972                         // TODO(gw): This is not currently used. In the future
973                         //           we should detect opaque pictures.
974                         unreachable!();
975                     }
976                 };
977 
978                 let metadata = PrimitiveMetadata {
979                     opacity,
980                     prim_kind: PrimitiveKind::Brush,
981                     cpu_prim_index: SpecificPrimitiveIndex(self.cpu_brushes.len()),
982                     ..base_metadata
983                 };
984 
985                 self.cpu_brushes.push(brush);
986 
987                 metadata
988             }
989             PrimitiveContainer::TextRun(text_cpu) => {
990                 let metadata = PrimitiveMetadata {
991                     opacity: PrimitiveOpacity::translucent(),
992                     prim_kind: PrimitiveKind::TextRun,
993                     cpu_prim_index: SpecificPrimitiveIndex(self.cpu_text_runs.len()),
994                     ..base_metadata
995                 };
996 
997                 self.cpu_text_runs.push(text_cpu);
998                 metadata
999             }
1000             PrimitiveContainer::Picture(picture) => {
1001                 let metadata = PrimitiveMetadata {
1002                     opacity: PrimitiveOpacity::translucent(),
1003                     prim_kind: PrimitiveKind::Picture,
1004                     cpu_prim_index: SpecificPrimitiveIndex(self.cpu_pictures.len()),
1005                     ..base_metadata
1006                 };
1007 
1008                 self.cpu_pictures.push(picture);
1009                 metadata
1010             }
1011             PrimitiveContainer::Image(image_cpu) => {
1012                 let metadata = PrimitiveMetadata {
1013                     opacity: PrimitiveOpacity::translucent(),
1014                     prim_kind: PrimitiveKind::Image,
1015                     cpu_prim_index: SpecificPrimitiveIndex(self.cpu_images.len()),
1016                     ..base_metadata
1017                 };
1018 
1019                 self.cpu_images.push(image_cpu);
1020                 metadata
1021             }
1022             PrimitiveContainer::Border(border_cpu) => {
1023                 let metadata = PrimitiveMetadata {
1024                     opacity: PrimitiveOpacity::translucent(),
1025                     prim_kind: PrimitiveKind::Border,
1026                     cpu_prim_index: SpecificPrimitiveIndex(self.cpu_borders.len()),
1027                     ..base_metadata
1028                 };
1029 
1030                 self.cpu_borders.push(border_cpu);
1031                 metadata
1032             }
1033         };
1034 
1035         self.cpu_metadata.push(metadata);
1036 
1037         PrimitiveIndex(prim_index)
1038     }
1039 
get_metadata(&self, index: PrimitiveIndex) -> &PrimitiveMetadata1040     pub fn get_metadata(&self, index: PrimitiveIndex) -> &PrimitiveMetadata {
1041         &self.cpu_metadata[index.0]
1042     }
1043 
prim_count(&self) -> usize1044     pub fn prim_count(&self) -> usize {
1045         self.cpu_metadata.len()
1046     }
1047 
prepare_prim_for_render_inner( &mut self, prim_index: PrimitiveIndex, prim_run_context: &PrimitiveRunContext, pic_state_for_children: PictureState, pic_context: &PictureContext, pic_state: &mut PictureState, frame_context: &FrameBuildingContext, frame_state: &mut FrameBuildingState, )1048     fn prepare_prim_for_render_inner(
1049         &mut self,
1050         prim_index: PrimitiveIndex,
1051         prim_run_context: &PrimitiveRunContext,
1052         pic_state_for_children: PictureState,
1053         pic_context: &PictureContext,
1054         pic_state: &mut PictureState,
1055         frame_context: &FrameBuildingContext,
1056         frame_state: &mut FrameBuildingState,
1057     ) {
1058         let metadata = &mut self.cpu_metadata[prim_index.0];
1059         match metadata.prim_kind {
1060             PrimitiveKind::Border => {}
1061             PrimitiveKind::Picture => {
1062                 self.cpu_pictures[metadata.cpu_prim_index.0]
1063                     .prepare_for_render(
1064                         prim_index,
1065                         &metadata.screen_rect
1066                             .expect("bug: trying to draw an off-screen picture!?")
1067                             .clipped,
1068                         &metadata.local_rect,
1069                         pic_state_for_children,
1070                         pic_state,
1071                         frame_context,
1072                         frame_state,
1073                     );
1074             }
1075             PrimitiveKind::TextRun => {
1076                 let text = &mut self.cpu_text_runs[metadata.cpu_prim_index.0];
1077                 // The transform only makes sense for screen space rasterization
1078                 let transform = if pic_context.draw_text_transformed {
1079                     Some(prim_run_context.scroll_node.world_content_transform.into())
1080                 } else {
1081                     None
1082                 };
1083                 text.prepare_for_render(
1084                     frame_state.resource_cache,
1085                     frame_context.device_pixel_scale,
1086                     transform,
1087                     pic_context.display_list,
1088                     frame_state.gpu_cache,
1089                 );
1090             }
1091             PrimitiveKind::Image => {
1092                 let image_cpu = &mut self.cpu_images[metadata.cpu_prim_index.0];
1093                 let image_properties = frame_state
1094                     .resource_cache
1095                     .get_image_properties(image_cpu.key.request.key);
1096 
1097                 // TODO(gw): Add image.rs and move this code out to a separate
1098                 //           source file as it gets more complicated, and we
1099                 //           start pre-rendering images for other reasons.
1100 
1101                 if let Some(image_properties) = image_properties {
1102                     // See if this image has been updated since we last hit this code path.
1103                     // If so, we need to (at least) update the opacity, and also rebuild
1104                     // and render task cached portions of this image.
1105                     if image_properties.epoch != image_cpu.current_epoch {
1106                         image_cpu.current_epoch = image_properties.epoch;
1107 
1108                         // Update the opacity.
1109                         metadata.opacity.is_opaque = image_properties.descriptor.is_opaque &&
1110                             image_cpu.tile_spacing.width == 0.0 &&
1111                             image_cpu.tile_spacing.height == 0.0;
1112 
1113                         // Work out whether this image is a normal / simple type, or if
1114                         // we need to pre-render it to the render task cache.
1115                         image_cpu.source = match image_cpu.key.texel_rect {
1116                             Some(texel_rect) => {
1117                                 ImageSource::Cache {
1118                                     // Size in device-pixels we need to allocate in render task cache.
1119                                     size: texel_rect.size,
1120                                     item: CacheItem::invalid(),
1121                                 }
1122                             }
1123                             None => {
1124                                 // Simple image - just use a normal texture cache entry.
1125                                 ImageSource::Default
1126                             }
1127                         };
1128                     }
1129 
1130                     // Set if we need to request the source image from the cache this frame.
1131                     let mut request_source_image = false;
1132 
1133                     // Every frame, for cached items, we need to request the render
1134                     // task cache item. The closure will be invoked on the first
1135                     // time through, and any time the render task output has been
1136                     // evicted from the texture cache.
1137                     match image_cpu.source {
1138                         ImageSource::Cache { size, ref mut item } => {
1139                             let key = image_cpu.key;
1140 
1141                             // Request a pre-rendered image task.
1142                             *item = frame_state.resource_cache.request_render_task(
1143                                 RenderTaskCacheKey {
1144                                     size,
1145                                     kind: RenderTaskCacheKeyKind::Image(key),
1146                                 },
1147                                 frame_state.gpu_cache,
1148                                 frame_state.render_tasks,
1149                                 |render_tasks| {
1150                                     // We need to render the image cache this frame,
1151                                     // so will need access to the source texture.
1152                                     request_source_image = true;
1153 
1154                                     // Create a task to blit from the texture cache to
1155                                     // a normal transient render task surface. This will
1156                                     // copy only the sub-rect, if specified.
1157                                     let cache_to_target_task = RenderTask::new_blit(
1158                                         size,
1159                                         BlitSource::Image {
1160                                             key,
1161                                         },
1162                                     );
1163                                     let cache_to_target_task_id = render_tasks.add(cache_to_target_task);
1164 
1165                                     // Create a task to blit the rect from the child render
1166                                     // task above back into the right spot in the persistent
1167                                     // render target cache.
1168                                     let target_to_cache_task = RenderTask::new_blit(
1169                                         size,
1170                                         BlitSource::RenderTask {
1171                                             task_id: cache_to_target_task_id,
1172                                         },
1173                                     );
1174                                     let target_to_cache_task_id = render_tasks.add(target_to_cache_task);
1175 
1176                                     // Hook this into the render task tree at the right spot.
1177                                     pic_state.tasks.push(target_to_cache_task_id);
1178 
1179                                     // Pass the image opacity, so that the cached render task
1180                                     // item inherits the same opacity properties.
1181                                     (target_to_cache_task_id, image_properties.descriptor.is_opaque)
1182                                 }
1183                             );
1184                         }
1185                         ImageSource::Default => {
1186                             // Normal images just reference the source texture each frame.
1187                             request_source_image = true;
1188                         }
1189                     }
1190 
1191                     // Request source image from the texture cache, if required.
1192                     if request_source_image {
1193                         frame_state.resource_cache.request_image(
1194                             image_cpu.key.request,
1195                             frame_state.gpu_cache,
1196                         );
1197                     }
1198                 }
1199             }
1200             PrimitiveKind::Brush => {
1201                 let brush = &mut self.cpu_brushes[metadata.cpu_prim_index.0];
1202 
1203                 match brush.kind {
1204                     BrushKind::Image { request, ref mut current_epoch, .. } => {
1205                         let image_properties = frame_state
1206                             .resource_cache
1207                             .get_image_properties(request.key);
1208 
1209                         if let Some(image_properties) = image_properties {
1210                             // See if this image has been updated since we last hit this code path.
1211                             // If so, we need to update the opacity.
1212                             if image_properties.epoch != *current_epoch {
1213                                 *current_epoch = image_properties.epoch;
1214                                 metadata.opacity.is_opaque = image_properties.descriptor.is_opaque;
1215                             }
1216                         }
1217 
1218                         frame_state.resource_cache.request_image(
1219                             request,
1220                             frame_state.gpu_cache,
1221                         );
1222                     }
1223                     BrushKind::YuvImage { format, yuv_key, image_rendering, .. } => {
1224                         let channel_num = format.get_plane_num();
1225                         debug_assert!(channel_num <= 3);
1226                         for channel in 0 .. channel_num {
1227                             frame_state.resource_cache.request_image(
1228                                 ImageRequest {
1229                                     key: yuv_key[channel],
1230                                     rendering: image_rendering,
1231                                     tile: None,
1232                                 },
1233                                 frame_state.gpu_cache,
1234                             );
1235                         }
1236                     }
1237                     BrushKind::RadialGradient { gradient_index, stops_range, .. } => {
1238                         let stops_handle = &mut frame_state.cached_gradients[gradient_index.0].handle;
1239                         if let Some(mut request) = frame_state.gpu_cache.request(stops_handle) {
1240                             let gradient_builder = GradientGpuBlockBuilder::new(
1241                                 stops_range,
1242                                 pic_context.display_list,
1243                             );
1244                             gradient_builder.build(
1245                                 false,
1246                                 &mut request,
1247                             );
1248                         }
1249                     }
1250                     BrushKind::LinearGradient { gradient_index, stops_range, reverse_stops, .. } => {
1251                         let stops_handle = &mut frame_state.cached_gradients[gradient_index.0].handle;
1252                         if let Some(mut request) = frame_state.gpu_cache.request(stops_handle) {
1253                             let gradient_builder = GradientGpuBlockBuilder::new(
1254                                 stops_range,
1255                                 pic_context.display_list,
1256                             );
1257                             gradient_builder.build(
1258                                 reverse_stops,
1259                                 &mut request,
1260                             );
1261                         }
1262                     }
1263                     BrushKind::Solid { .. } |
1264                     BrushKind::Clear |
1265                     BrushKind::Line { .. } |
1266                     BrushKind::Picture { .. } => {}
1267                 }
1268             }
1269         }
1270 
1271         // Mark this GPU resource as required for this frame.
1272         if let Some(mut request) = frame_state.gpu_cache.request(&mut metadata.gpu_location) {
1273             // has to match VECS_PER_BRUSH_PRIM
1274             request.push(metadata.local_rect);
1275             request.push(metadata.local_clip_rect);
1276 
1277             match metadata.prim_kind {
1278                 PrimitiveKind::Border => {
1279                     let border = &self.cpu_borders[metadata.cpu_prim_index.0];
1280                     border.write_gpu_blocks(request);
1281                 }
1282                 PrimitiveKind::Image => {
1283                     let image = &self.cpu_images[metadata.cpu_prim_index.0];
1284                     image.write_gpu_blocks(request);
1285                 }
1286                 PrimitiveKind::TextRun => {
1287                     let text = &self.cpu_text_runs[metadata.cpu_prim_index.0];
1288                     text.write_gpu_blocks(&mut request);
1289                 }
1290                 PrimitiveKind::Picture => {
1291                     let pic = &self.cpu_pictures[metadata.cpu_prim_index.0];
1292                     pic.write_gpu_blocks(&mut request);
1293 
1294                     let brush = &pic.brush;
1295                     brush.write_gpu_blocks(&mut request);
1296                     match brush.segment_desc {
1297                         Some(ref segment_desc) => {
1298                             for segment in &segment_desc.segments {
1299                                 // has to match VECS_PER_SEGMENT
1300                                 request.write_segment(segment.local_rect);
1301                             }
1302                         }
1303                         None => {
1304                             request.write_segment(metadata.local_rect);
1305                         }
1306                     }
1307                 }
1308                 PrimitiveKind::Brush => {
1309                     let brush = &self.cpu_brushes[metadata.cpu_prim_index.0];
1310                     brush.write_gpu_blocks(&mut request);
1311                     match brush.segment_desc {
1312                         Some(ref segment_desc) => {
1313                             for segment in &segment_desc.segments {
1314                                 // has to match VECS_PER_SEGMENT
1315                                 request.write_segment(segment.local_rect);
1316                             }
1317                         }
1318                         None => {
1319                             request.write_segment(metadata.local_rect);
1320                         }
1321                     }
1322                 }
1323             }
1324         }
1325     }
1326 
write_brush_segment_description( brush: &mut BrushPrimitive, metadata: &PrimitiveMetadata, prim_run_context: &PrimitiveRunContext, clips: &Vec<ClipWorkItem>, has_clips_from_other_coordinate_systems: bool, frame_context: &FrameBuildingContext, frame_state: &mut FrameBuildingState, )1327     fn write_brush_segment_description(
1328         brush: &mut BrushPrimitive,
1329         metadata: &PrimitiveMetadata,
1330         prim_run_context: &PrimitiveRunContext,
1331         clips: &Vec<ClipWorkItem>,
1332         has_clips_from_other_coordinate_systems: bool,
1333         frame_context: &FrameBuildingContext,
1334         frame_state: &mut FrameBuildingState,
1335     ) {
1336         match brush.segment_desc {
1337             Some(ref segment_desc) => {
1338                 // If we already have a segment descriptor, only run through the
1339                 // clips list if we haven't already determined the mask kind.
1340                 if segment_desc.clip_mask_kind != BrushClipMaskKind::Unknown {
1341                     return;
1342                 }
1343             }
1344             None => {
1345                 // If no segment descriptor built yet, see if it is a brush
1346                 // type that wants to be segmented.
1347                 if !brush.kind.supports_segments() {
1348                     return;
1349                 }
1350                 if metadata.local_rect.size.area() <= MIN_BRUSH_SPLIT_AREA {
1351                     return;
1352                 }
1353             }
1354         }
1355 
1356         let mut segment_builder = SegmentBuilder::new(
1357             metadata.local_rect,
1358             None,
1359             metadata.local_clip_rect
1360         );
1361 
1362         // If this primitive is clipped by clips from a different coordinate system, then we
1363         // need to apply a clip mask for the entire primitive.
1364         let mut clip_mask_kind = match has_clips_from_other_coordinate_systems {
1365             true => BrushClipMaskKind::Global,
1366             false => BrushClipMaskKind::Individual,
1367         };
1368 
1369         // Segment the primitive on all the local-space clip sources that we can.
1370         for clip_item in clips {
1371             if clip_item.coordinate_system_id != prim_run_context.scroll_node.coordinate_system_id {
1372                 continue;
1373             }
1374 
1375             let local_clips = frame_state.clip_store.get_opt(&clip_item.clip_sources).expect("bug");
1376             for &(ref clip, _) in &local_clips.clips {
1377                 let (local_clip_rect, radius, mode) = match *clip {
1378                     ClipSource::RoundedRectangle(rect, radii, clip_mode) => {
1379                         (rect, Some(radii), clip_mode)
1380                     }
1381                     ClipSource::Rectangle(rect) => {
1382                         (rect, None, ClipMode::Clip)
1383                     }
1384                     ClipSource::BoxShadow(ref info) => {
1385                         // For inset box shadows, we can clip out any
1386                         // pixels that are inside the shadow region
1387                         // and are beyond the inner rect, as they can't
1388                         // be affected by the blur radius.
1389                         let inner_clip_mode = match info.clip_mode {
1390                             BoxShadowClipMode::Outset => None,
1391                             BoxShadowClipMode::Inset => Some(ClipMode::ClipOut),
1392                         };
1393 
1394                         // Push a region into the segment builder where the
1395                         // box-shadow can have an effect on the result. This
1396                         // ensures clip-mask tasks get allocated for these
1397                         // pixel regions, even if no other clips affect them.
1398                         segment_builder.push_mask_region(
1399                             info.prim_shadow_rect,
1400                             info.prim_shadow_rect.inflate(
1401                                 -0.5 * info.shadow_rect_alloc_size.width,
1402                                 -0.5 * info.shadow_rect_alloc_size.height,
1403                             ),
1404                             inner_clip_mode,
1405                         );
1406 
1407                         continue;
1408                     }
1409                     ClipSource::BorderCorner(..) |
1410                     ClipSource::Image(..) => {
1411                         // TODO(gw): We can easily extend the segment builder
1412                         //           to support these clip sources in the
1413                         //           future, but they are rarely used.
1414                         clip_mask_kind = BrushClipMaskKind::Global;
1415                         continue;
1416                     }
1417                 };
1418 
1419                 // If the scroll node transforms are different between the clip
1420                 // node and the primitive, we need to get the clip rect in the
1421                 // local space of the primitive, in order to generate correct
1422                 // local segments.
1423                 let local_clip_rect = if clip_item.scroll_node_data_index == prim_run_context.scroll_node.node_data_index {
1424                     local_clip_rect
1425                 } else {
1426                     let clip_transform = frame_context
1427                         .node_data[clip_item.scroll_node_data_index.0 as usize]
1428                         .transform;
1429                     let prim_transform = &prim_run_context.scroll_node.world_content_transform;
1430                     let relative_transform = prim_transform
1431                         .inverse()
1432                         .unwrap_or(WorldToLayerFastTransform::identity())
1433                         .pre_mul(&clip_transform.into());
1434 
1435                     relative_transform.transform_rect(&local_clip_rect)
1436                 };
1437 
1438                 segment_builder.push_clip_rect(local_clip_rect, radius, mode);
1439             }
1440         }
1441 
1442         match brush.segment_desc {
1443             Some(ref mut segment_desc) => {
1444                 segment_desc.clip_mask_kind = clip_mask_kind;
1445             }
1446             None => {
1447                 // TODO(gw): We can probably make the allocation
1448                 //           patterns of this and the segment
1449                 //           builder significantly better, by
1450                 //           retaining it across primitives.
1451                 let mut segments = Vec::new();
1452 
1453                 segment_builder.build(|segment| {
1454                     segments.push(
1455                         BrushSegment::new(
1456                             segment.rect.origin,
1457                             segment.rect.size,
1458                             segment.has_mask,
1459                             segment.edge_flags,
1460                         ),
1461                     );
1462                 });
1463 
1464                 brush.segment_desc = Some(BrushSegmentDescriptor {
1465                     segments,
1466                     clip_mask_kind,
1467                 });
1468             }
1469         }
1470     }
1471 
update_clip_task_for_brush( &mut self, prim_run_context: &PrimitiveRunContext, prim_index: PrimitiveIndex, clips: &Vec<ClipWorkItem>, combined_outer_rect: &DeviceIntRect, has_clips_from_other_coordinate_systems: bool, pic_state: &mut PictureState, frame_context: &FrameBuildingContext, frame_state: &mut FrameBuildingState, ) -> bool1472     fn update_clip_task_for_brush(
1473         &mut self,
1474         prim_run_context: &PrimitiveRunContext,
1475         prim_index: PrimitiveIndex,
1476         clips: &Vec<ClipWorkItem>,
1477         combined_outer_rect: &DeviceIntRect,
1478         has_clips_from_other_coordinate_systems: bool,
1479         pic_state: &mut PictureState,
1480         frame_context: &FrameBuildingContext,
1481         frame_state: &mut FrameBuildingState,
1482     ) -> bool {
1483         let metadata = &self.cpu_metadata[prim_index.0];
1484         let brush = match metadata.prim_kind {
1485             PrimitiveKind::Brush => {
1486                 &mut self.cpu_brushes[metadata.cpu_prim_index.0]
1487             }
1488             PrimitiveKind::Picture => {
1489                 &mut self.cpu_pictures[metadata.cpu_prim_index.0].brush
1490             }
1491             _ => {
1492                 return false;
1493             }
1494         };
1495 
1496         PrimitiveStore::write_brush_segment_description(
1497             brush,
1498             metadata,
1499             prim_run_context,
1500             clips,
1501             has_clips_from_other_coordinate_systems,
1502             frame_context,
1503             frame_state,
1504         );
1505 
1506         let segment_desc = match brush.segment_desc {
1507             Some(ref mut description) => description,
1508             None => return false,
1509         };
1510         let clip_mask_kind = segment_desc.clip_mask_kind;
1511 
1512         for segment in &mut segment_desc.segments {
1513             if !segment.may_need_clip_mask && clip_mask_kind != BrushClipMaskKind::Global {
1514                 segment.clip_task_id = None;
1515                 continue;
1516             }
1517 
1518             let segment_screen_rect = calculate_screen_bounding_rect(
1519                 &prim_run_context.scroll_node.world_content_transform,
1520                 &segment.local_rect,
1521                 frame_context.device_pixel_scale,
1522             );
1523 
1524             let intersected_rect = combined_outer_rect.intersection(&segment_screen_rect);
1525             segment.clip_task_id = intersected_rect.map(|bounds| {
1526                 let clip_task = RenderTask::new_mask(
1527                     bounds,
1528                     clips.clone(),
1529                     prim_run_context.scroll_node.coordinate_system_id,
1530                     frame_state.clip_store,
1531                     frame_state.gpu_cache,
1532                     frame_state.resource_cache,
1533                     frame_state.render_tasks,
1534                 );
1535 
1536                 let clip_task_id = frame_state.render_tasks.add(clip_task);
1537                 pic_state.tasks.push(clip_task_id);
1538 
1539                 clip_task_id
1540             })
1541         }
1542 
1543         true
1544     }
1545 
update_clip_task( &mut self, prim_index: PrimitiveIndex, prim_run_context: &PrimitiveRunContext, prim_screen_rect: &DeviceIntRect, pic_state: &mut PictureState, frame_context: &FrameBuildingContext, frame_state: &mut FrameBuildingState, ) -> bool1546     fn update_clip_task(
1547         &mut self,
1548         prim_index: PrimitiveIndex,
1549         prim_run_context: &PrimitiveRunContext,
1550         prim_screen_rect: &DeviceIntRect,
1551         pic_state: &mut PictureState,
1552         frame_context: &FrameBuildingContext,
1553         frame_state: &mut FrameBuildingState,
1554     ) -> bool {
1555         self.cpu_metadata[prim_index.0].clip_task_id = None;
1556 
1557         let prim_screen_rect = match prim_screen_rect.intersection(&frame_context.screen_rect) {
1558             Some(rect) => rect,
1559             None => {
1560                 self.cpu_metadata[prim_index.0].screen_rect = None;
1561                 return false;
1562             }
1563         };
1564 
1565         let mut combined_outer_rect =
1566             prim_screen_rect.intersection(&prim_run_context.clip_chain.combined_outer_screen_rect);
1567         let clip_chain = prim_run_context.clip_chain.nodes.clone();
1568 
1569         let prim_coordinate_system_id = prim_run_context.scroll_node.coordinate_system_id;
1570         let transform = &prim_run_context.scroll_node.world_content_transform;
1571         let extra_clip =  {
1572             let metadata = &self.cpu_metadata[prim_index.0];
1573             metadata.clip_sources.as_ref().map(|ref clip_sources| {
1574                 let prim_clips = frame_state.clip_store.get_mut(clip_sources);
1575                 prim_clips.update(
1576                     frame_state.gpu_cache,
1577                     frame_state.resource_cache,
1578                     frame_context.device_pixel_scale,
1579                 );
1580                 let (screen_inner_rect, screen_outer_rect) =
1581                     prim_clips.get_screen_bounds(transform, frame_context.device_pixel_scale);
1582 
1583                 if let Some(outer) = screen_outer_rect {
1584                     combined_outer_rect = combined_outer_rect.and_then(|r| r.intersection(&outer));
1585                 }
1586 
1587                 Arc::new(ClipChainNode {
1588                     work_item: ClipWorkItem {
1589                         scroll_node_data_index: prim_run_context.scroll_node.node_data_index,
1590                         clip_sources: clip_sources.weak(),
1591                         coordinate_system_id: prim_coordinate_system_id,
1592                     },
1593                     // The local_clip_rect a property of ClipChain nodes that are ClipScrollNodes.
1594                     // It's used to calculate a local clipping rectangle before we reach this
1595                     // point, so we can set it to zero here. It should be unused from this point
1596                     // on.
1597                     local_clip_rect: LayerRect::zero(),
1598                     screen_inner_rect,
1599                     screen_outer_rect: screen_outer_rect.unwrap_or(prim_screen_rect),
1600                     prev: None,
1601                 })
1602             })
1603         };
1604 
1605         // If everything is clipped out, then we don't need to render this primitive.
1606         let combined_outer_rect = match combined_outer_rect {
1607             Some(rect) if !rect.is_empty() => rect,
1608             _ => {
1609                 self.cpu_metadata[prim_index.0].screen_rect = None;
1610                 return false;
1611             }
1612         };
1613 
1614         let mut has_clips_from_other_coordinate_systems = false;
1615         let mut combined_inner_rect = frame_context.screen_rect;
1616         let clips = convert_clip_chain_to_clip_vector(
1617             clip_chain,
1618             extra_clip,
1619             &combined_outer_rect,
1620             &mut combined_inner_rect,
1621             prim_run_context.scroll_node.coordinate_system_id,
1622             &mut has_clips_from_other_coordinate_systems
1623         );
1624 
1625         // This can happen if we had no clips or if all the clips were optimized away. In
1626         // some cases we still need to create a clip mask in order to create a rectangular
1627         // clip in screen space coordinates.
1628         if clips.is_empty() {
1629             // If we don't have any clips from other coordinate systems, the local clip
1630             // calculated from the clip chain should be sufficient to ensure proper clipping.
1631             if !has_clips_from_other_coordinate_systems {
1632                 return true;
1633             }
1634 
1635             // If we have filtered all clips and the screen rect isn't any smaller, we can just
1636             // skip masking entirely.
1637             if combined_outer_rect == prim_screen_rect {
1638                 return true;
1639             }
1640             // Otherwise we create an empty mask, but with an empty inner rect to avoid further
1641             // optimization of the empty mask.
1642             combined_inner_rect = DeviceIntRect::zero();
1643         }
1644 
1645         if combined_inner_rect.contains_rect(&prim_screen_rect) {
1646            return true;
1647         }
1648 
1649         // First try to  render this primitive's mask using optimized brush rendering.
1650         if self.update_clip_task_for_brush(
1651             prim_run_context,
1652             prim_index,
1653             &clips,
1654             &combined_outer_rect,
1655             has_clips_from_other_coordinate_systems,
1656             pic_state,
1657             frame_context,
1658             frame_state,
1659         ) {
1660             return true;
1661         }
1662 
1663         let clip_task = RenderTask::new_mask(
1664             combined_outer_rect,
1665             clips,
1666             prim_coordinate_system_id,
1667             frame_state.clip_store,
1668             frame_state.gpu_cache,
1669             frame_state.resource_cache,
1670             frame_state.render_tasks,
1671         );
1672 
1673         let clip_task_id = frame_state.render_tasks.add(clip_task);
1674         self.cpu_metadata[prim_index.0].clip_task_id = Some(clip_task_id);
1675         pic_state.tasks.push(clip_task_id);
1676 
1677         true
1678     }
1679 
prepare_prim_for_render( &mut self, prim_index: PrimitiveIndex, prim_run_context: &PrimitiveRunContext, pic_context: &PictureContext, pic_state: &mut PictureState, frame_context: &FrameBuildingContext, frame_state: &mut FrameBuildingState, ) -> Option<LayerRect>1680     pub fn prepare_prim_for_render(
1681         &mut self,
1682         prim_index: PrimitiveIndex,
1683         prim_run_context: &PrimitiveRunContext,
1684         pic_context: &PictureContext,
1685         pic_state: &mut PictureState,
1686         frame_context: &FrameBuildingContext,
1687         frame_state: &mut FrameBuildingState,
1688     ) -> Option<LayerRect> {
1689         let mut may_need_clip_mask = true;
1690         let mut pic_state_for_children = PictureState::new();
1691 
1692         // Do some basic checks first, that can early out
1693         // without even knowing the local rect.
1694         let (prim_kind, cpu_prim_index) = {
1695             let metadata = &self.cpu_metadata[prim_index.0];
1696 
1697             if pic_context.perform_culling &&
1698                !metadata.is_backface_visible &&
1699                prim_run_context.scroll_node.world_content_transform.is_backface_visible() {
1700                 return None;
1701             }
1702 
1703             (metadata.prim_kind, metadata.cpu_prim_index)
1704         };
1705 
1706         // If we have dependencies, we need to prepare them first, in order
1707         // to know the actual rect of this primitive.
1708         // For example, scrolling may affect the location of an item in
1709         // local space, which may force us to render this item on a larger
1710         // picture target, if being composited.
1711         if let PrimitiveKind::Picture = prim_kind {
1712             let pic_context_for_children = {
1713                 let pic = &mut self.cpu_pictures[cpu_prim_index.0];
1714 
1715                 if !pic.resolve_scene_properties(frame_context.scene_properties) {
1716                     return None;
1717                 }
1718 
1719                 let (draw_text_transformed, original_reference_frame_index) = match pic.kind {
1720                     PictureKind::Image { reference_frame_index, composite_mode, .. } => {
1721                         may_need_clip_mask = composite_mode.is_some();
1722                         (true, Some(reference_frame_index))
1723                     }
1724                     PictureKind::TextShadow { .. } => {
1725                         (false, None)
1726                     }
1727                 };
1728 
1729                 let display_list = &frame_context
1730                     .pipelines
1731                     .get(&pic.pipeline_id)
1732                     .expect("No display list?")
1733                     .display_list;
1734 
1735                 let inv_world_transform = prim_run_context
1736                     .scroll_node
1737                     .world_content_transform
1738                     .inverse();
1739 
1740                 PictureContext {
1741                     pipeline_id: pic.pipeline_id,
1742                     perform_culling: pic.cull_children,
1743                     prim_runs: mem::replace(&mut pic.runs, Vec::new()),
1744                     original_reference_frame_index,
1745                     display_list,
1746                     draw_text_transformed,
1747                     inv_world_transform,
1748                 }
1749             };
1750 
1751             let result = self.prepare_prim_runs(
1752                 &pic_context_for_children,
1753                 &mut pic_state_for_children,
1754                 frame_context,
1755                 frame_state,
1756             );
1757 
1758             // Restore the dependencies (borrow check dance)
1759             let pic = &mut self.cpu_pictures[cpu_prim_index.0];
1760             pic.runs = pic_context_for_children.prim_runs;
1761 
1762             let metadata = &mut self.cpu_metadata[prim_index.0];
1763             metadata.local_rect = pic.update_local_rect(result);
1764         }
1765 
1766         let (local_rect, unclipped_device_rect) = {
1767             let metadata = &mut self.cpu_metadata[prim_index.0];
1768             if metadata.local_rect.size.width <= 0.0 ||
1769                metadata.local_rect.size.height <= 0.0 {
1770                 //warn!("invalid primitive rect {:?}", metadata.local_rect);
1771                 return None;
1772             }
1773 
1774             let local_rect = metadata.local_clip_rect.intersection(&metadata.local_rect);
1775             let local_rect = match local_rect {
1776                 Some(local_rect) => local_rect,
1777                 None if pic_context.perform_culling => return None,
1778                 None => LayerRect::zero(),
1779             };
1780 
1781             let screen_bounding_rect = calculate_screen_bounding_rect(
1782                 &prim_run_context.scroll_node.world_content_transform,
1783                 &local_rect,
1784                 frame_context.device_pixel_scale,
1785             );
1786 
1787             metadata.screen_rect = screen_bounding_rect
1788                 .intersection(&prim_run_context.clip_chain.combined_outer_screen_rect)
1789                 .map(|clipped| {
1790                     ScreenRect {
1791                         clipped,
1792                         unclipped: screen_bounding_rect,
1793                     }
1794                 });
1795 
1796             if metadata.screen_rect.is_none() && pic_context.perform_culling {
1797                 return None;
1798             }
1799 
1800             metadata.clip_chain_rect_index = prim_run_context.clip_chain_rect_index;
1801 
1802             (local_rect, screen_bounding_rect)
1803         };
1804 
1805         if pic_context.perform_culling && may_need_clip_mask && !self.update_clip_task(
1806             prim_index,
1807             prim_run_context,
1808             &unclipped_device_rect,
1809             pic_state,
1810             frame_context,
1811             frame_state,
1812         ) {
1813             return None;
1814         }
1815 
1816         self.prepare_prim_for_render_inner(
1817             prim_index,
1818             prim_run_context,
1819             pic_state_for_children,
1820             pic_context,
1821             pic_state,
1822             frame_context,
1823             frame_state,
1824         );
1825 
1826         Some(local_rect)
1827     }
1828 
1829     // TODO(gw): Make this simpler / more efficient by tidying
1830     //           up the logic that early outs from prepare_prim_for_render.
reset_prim_visibility(&mut self)1831     pub fn reset_prim_visibility(&mut self) {
1832         for md in &mut self.cpu_metadata {
1833             md.screen_rect = None;
1834         }
1835     }
1836 
prepare_prim_runs( &mut self, pic_context: &PictureContext, pic_state: &mut PictureState, frame_context: &FrameBuildingContext, frame_state: &mut FrameBuildingState, ) -> PrimitiveRunLocalRect1837     pub fn prepare_prim_runs(
1838         &mut self,
1839         pic_context: &PictureContext,
1840         pic_state: &mut PictureState,
1841         frame_context: &FrameBuildingContext,
1842         frame_state: &mut FrameBuildingState,
1843     ) -> PrimitiveRunLocalRect {
1844         let mut result = PrimitiveRunLocalRect {
1845             local_rect_in_actual_parent_space: LayerRect::zero(),
1846             local_rect_in_original_parent_space: LayerRect::zero(),
1847         };
1848 
1849         for run in &pic_context.prim_runs {
1850             // TODO(gw): Perhaps we can restructure this to not need to create
1851             //           a new primitive context for every run (if the hash
1852             //           lookups ever show up in a profile).
1853             let scroll_node = &frame_context
1854                 .clip_scroll_tree
1855                 .nodes[run.clip_and_scroll.scroll_node_id.0];
1856             let clip_chain = frame_context
1857                 .clip_scroll_tree
1858                 .get_clip_chain(run.clip_and_scroll.clip_chain_index);
1859 
1860             if pic_context.perform_culling {
1861                 if !scroll_node.invertible {
1862                     debug!("{:?} {:?}: position not invertible", run.base_prim_index, pic_context.pipeline_id);
1863                     continue;
1864                 }
1865 
1866                 if clip_chain.combined_outer_screen_rect.is_empty() {
1867                     debug!("{:?} {:?}: clipped out", run.base_prim_index, pic_context.pipeline_id);
1868                     continue;
1869                 }
1870             }
1871 
1872             let parent_relative_transform = pic_context
1873                 .inv_world_transform
1874                 .map(|inv_parent| {
1875                     inv_parent.pre_mul(&scroll_node.world_content_transform)
1876                 });
1877 
1878             let original_relative_transform = pic_context.original_reference_frame_index
1879                 .and_then(|original_reference_frame_index| {
1880                     let parent = frame_context
1881                         .clip_scroll_tree
1882                         .nodes[original_reference_frame_index.0]
1883                         .world_content_transform;
1884                     parent.inverse()
1885                         .map(|inv_parent| {
1886                             inv_parent.pre_mul(&scroll_node.world_content_transform)
1887                         })
1888                 });
1889 
1890             let clip_chain_rect = match pic_context.perform_culling {
1891                 true => get_local_clip_rect_for_nodes(scroll_node, clip_chain),
1892                 false => None,
1893             };
1894 
1895             let clip_chain_rect_index = match clip_chain_rect {
1896                 Some(rect) if rect.is_empty() => continue,
1897                 Some(rect) => {
1898                     frame_state.local_clip_rects.push(rect);
1899                     ClipChainRectIndex(frame_state.local_clip_rects.len() - 1)
1900                 }
1901                 None => ClipChainRectIndex(0), // This is no clipping.
1902             };
1903 
1904             let child_prim_run_context = PrimitiveRunContext::new(
1905                 clip_chain,
1906                 scroll_node,
1907                 clip_chain_rect_index,
1908             );
1909 
1910             for i in 0 .. run.count {
1911                 let prim_index = PrimitiveIndex(run.base_prim_index.0 + i);
1912 
1913                 if let Some(prim_local_rect) = self.prepare_prim_for_render(
1914                     prim_index,
1915                     &child_prim_run_context,
1916                     pic_context,
1917                     pic_state,
1918                     frame_context,
1919                     frame_state,
1920                 ) {
1921                     frame_state.profile_counters.visible_primitives.inc();
1922 
1923                     if let Some(ref matrix) = original_relative_transform {
1924                         let bounds = matrix.transform_rect(&prim_local_rect);
1925                         result.local_rect_in_original_parent_space =
1926                             result.local_rect_in_original_parent_space.union(&bounds);
1927                     }
1928 
1929                     if let Some(ref matrix) = parent_relative_transform {
1930                         let bounds = matrix.transform_rect(&prim_local_rect);
1931                         result.local_rect_in_actual_parent_space =
1932                             result.local_rect_in_actual_parent_space.union(&bounds);
1933                     }
1934                 }
1935             }
1936         }
1937 
1938         result
1939     }
1940 }
1941 
1942 //Test for one clip region contains another
1943 trait InsideTest<T> {
might_contain(&self, clip: &T) -> bool1944     fn might_contain(&self, clip: &T) -> bool;
1945 }
1946 
1947 impl InsideTest<ComplexClipRegion> for ComplexClipRegion {
1948     // Returns true if clip is inside self, can return false negative
might_contain(&self, clip: &ComplexClipRegion) -> bool1949     fn might_contain(&self, clip: &ComplexClipRegion) -> bool {
1950         let delta_left = clip.rect.origin.x - self.rect.origin.x;
1951         let delta_top = clip.rect.origin.y - self.rect.origin.y;
1952         let delta_right = self.rect.max_x() - clip.rect.max_x();
1953         let delta_bottom = self.rect.max_y() - clip.rect.max_y();
1954 
1955         delta_left >= 0f32 && delta_top >= 0f32 && delta_right >= 0f32 && delta_bottom >= 0f32 &&
1956             clip.radii.top_left.width >= self.radii.top_left.width - delta_left &&
1957             clip.radii.top_left.height >= self.radii.top_left.height - delta_top &&
1958             clip.radii.top_right.width >= self.radii.top_right.width - delta_right &&
1959             clip.radii.top_right.height >= self.radii.top_right.height - delta_top &&
1960             clip.radii.bottom_left.width >= self.radii.bottom_left.width - delta_left &&
1961             clip.radii.bottom_left.height >= self.radii.bottom_left.height - delta_bottom &&
1962             clip.radii.bottom_right.width >= self.radii.bottom_right.width - delta_right &&
1963             clip.radii.bottom_right.height >= self.radii.bottom_right.height - delta_bottom
1964     }
1965 }
1966 
convert_clip_chain_to_clip_vector( clip_chain_nodes: ClipChainNodeRef, extra_clip: ClipChainNodeRef, combined_outer_rect: &DeviceIntRect, combined_inner_rect: &mut DeviceIntRect, prim_coordinate_system: CoordinateSystemId, has_clips_from_other_coordinate_systems: &mut bool, ) -> Vec<ClipWorkItem>1967 fn convert_clip_chain_to_clip_vector(
1968     clip_chain_nodes: ClipChainNodeRef,
1969     extra_clip: ClipChainNodeRef,
1970     combined_outer_rect: &DeviceIntRect,
1971     combined_inner_rect: &mut DeviceIntRect,
1972     prim_coordinate_system: CoordinateSystemId,
1973     has_clips_from_other_coordinate_systems: &mut bool,
1974 ) -> Vec<ClipWorkItem> {
1975     // Filter out all the clip instances that don't contribute to the result.
1976     ClipChainNodeIter { current: extra_clip }
1977         .chain(ClipChainNodeIter { current: clip_chain_nodes })
1978         .filter_map(|node| {
1979             *has_clips_from_other_coordinate_systems |=
1980                 prim_coordinate_system != node.work_item.coordinate_system_id;
1981 
1982             *combined_inner_rect = if !node.screen_inner_rect.is_empty() {
1983                 // If this clip's inner area contains the area of the primitive clipped
1984                 // by previous clips, then it's not going to affect rendering in any way.
1985                 if node.screen_inner_rect.contains_rect(&combined_outer_rect) {
1986                     return None;
1987                 }
1988                 combined_inner_rect.intersection(&node.screen_inner_rect)
1989                     .unwrap_or_else(DeviceIntRect::zero)
1990             } else {
1991                 DeviceIntRect::zero()
1992             };
1993 
1994             Some(node.work_item.clone())
1995         })
1996         .collect()
1997 }
1998 
get_local_clip_rect_for_nodes( scroll_node: &ClipScrollNode, clip_chain: &ClipChain, ) -> Option<LayerRect>1999 fn get_local_clip_rect_for_nodes(
2000     scroll_node: &ClipScrollNode,
2001     clip_chain: &ClipChain,
2002 ) -> Option<LayerRect> {
2003     let local_rect = ClipChainNodeIter { current: clip_chain.nodes.clone() }.fold(
2004         None,
2005         |combined_local_clip_rect: Option<LayerRect>, node| {
2006             if node.work_item.coordinate_system_id != scroll_node.coordinate_system_id {
2007                 return combined_local_clip_rect;
2008             }
2009 
2010             Some(match combined_local_clip_rect {
2011                 Some(combined_rect) =>
2012                     combined_rect.intersection(&node.local_clip_rect).unwrap_or_else(LayerRect::zero),
2013                 None => node.local_clip_rect,
2014             })
2015         }
2016     );
2017 
2018     match local_rect {
2019         Some(local_rect) => scroll_node.coordinate_system_relative_transform.unapply(&local_rect),
2020         None => None,
2021     }
2022 }
2023 
2024 impl<'a> GpuDataRequest<'a> {
2025     // Write the GPU cache data for an individual segment.
2026     // TODO(gw): The second block is currently unused. In
2027     //           the future, it will be used to store a
2028     //           UV rect, allowing segments to reference
2029     //           part of an image.
write_segment( &mut self, local_rect: LayerRect, )2030     fn write_segment(
2031         &mut self,
2032         local_rect: LayerRect,
2033     ) {
2034         self.push(local_rect);
2035         self.push([
2036             0.0,
2037             0.0,
2038             0.0,
2039             0.0
2040         ]);
2041     }
2042 }
2043