Merge autoland to mozilla-central. a=merge
authorNoemi Erli <nerli@mozilla.com>
Sun, 21 Oct 2018 12:46:47 +0300
changeset 490595 ab280e276dcec0ed5aec2a61753722929d25b86c
parent 490591 3872ebc4799bf8e606006f36444e021dddad0825 (current diff)
parent 490594 2d8a1d405333036b4adce643e4893f2da29957be (diff)
child 490596 62e384532eeb60f5c61383ca8b16d614c49e1838
push id247
push userfmarier@mozilla.com
push dateSat, 27 Oct 2018 01:06:44 +0000
reviewersmerge
milestone64.0a1
Merge autoland to mozilla-central. a=merge
--- a/gfx/webrender/src/batch.rs
+++ b/gfx/webrender/src/batch.rs
@@ -502,41 +502,52 @@ impl AlphaBatchBuilder {
             );
         }
 
         // Flush the accumulated plane splits onto the task tree.
         // Z axis is directed at the screen, `sort` is ascending, and we need back-to-front order.
         for poly in splitter.sort(vec3(0.0, 0.0, 1.0)) {
             let prim_instance = &pic.prim_instances[poly.anchor];
             let prim_index = prim_instance.prim_index;
-            let pic_metadata = &ctx.prim_store.primitives[prim_index.0].metadata;
+            let prim = &ctx.prim_store.primitives[prim_index.0];
             if cfg!(debug_assertions) && ctx.prim_store.chase_id == Some(prim_index) {
                 println!("\t\tsplit polygon {:?}", poly.points);
             }
             let transform = transforms.get_world_transform(prim_instance.spatial_node_index).inverse().unwrap();
             let transform_id = transforms.get_id(
                 prim_instance.spatial_node_index,
                 ROOT_SPATIAL_NODE_INDEX,
                 ctx.clip_scroll_tree,
             );
 
             let clip_task_address = prim_instance
                 .clip_task_id
                 .map_or(OPAQUE_TASK_ADDRESS, |id| render_tasks.get_task_address(id));
 
             let prim_header = PrimitiveHeader {
-                local_rect: pic_metadata.local_rect,
+                local_rect: prim.local_rect,
                 local_clip_rect: prim_instance.combined_local_clip_rect,
                 task_address,
                 specific_prim_address: GpuCacheAddress::invalid(),
                 clip_task_address,
                 transform_id,
             };
 
-            let pic = ctx.prim_store.get_pic(prim_index);
+            let pic_index = match prim.details {
+                PrimitiveDetails::Brush(ref brush) => {
+                    match brush.kind {
+                        BrushKind::Picture { pic_index, .. } => pic_index,
+                        _ => unreachable!(),
+                    }
+                }
+                PrimitiveDetails::TextRun(..) => {
+                    unreachable!();
+                }
+            };
+            let pic = &ctx.prim_store.pictures[pic_index.0];
 
             let (uv_rect_address, _) = pic
                 .raster_config
                 .as_ref()
                 .expect("BUG: no raster config")
                 .surface
                 .as_ref()
                 .expect("BUG: no surface")
@@ -602,17 +613,16 @@ impl AlphaBatchBuilder {
         deferred_resolves: &mut Vec<DeferredResolve>,
         splitter: &mut BspSplitter<f64, WorldPixel>,
         prim_headers: &mut PrimitiveHeaders,
         transforms: &mut TransformPalette,
         root_spatial_node_index: SpatialNodeIndex,
         plane_split_anchor: usize,
     ) {
         let prim = &ctx.prim_store.primitives[prim_instance.prim_index.0];
-        let prim_metadata = &prim.metadata;
 
         if prim_instance.clipped_world_rect.is_none() {
             return;
         }
 
         #[cfg(debug_assertions)] //TODO: why is this needed?
         debug_assert_eq!(prim_instance.prepared_frame_id, render_tasks.frame_id());
 
@@ -627,18 +637,17 @@ impl AlphaBatchBuilder {
         //           wasteful. We should probably cache this in
         //           the scroll node...
         let transform_kind = transform_id.transform_kind();
         let bounding_rect = prim_instance.clipped_world_rect
                                          .as_ref()
                                          .expect("bug");
 
         // If the primitive is internally decomposed into multiple sub-primitives we may not
-        // use some of the per-primitive data typically stored in PrimitiveMetadata and get
-        // it from each sub-primitive instead.
+        // use some of the per-primitive data and get it from each sub-primitive instead.
         let is_multiple_primitives = match prim.details {
             PrimitiveDetails::Brush(ref brush) => {
                 match brush.kind {
                     BrushKind::Image { ref visible_tiles, .. } => !visible_tiles.is_empty(),
                     BrushKind::LinearGradient { ref visible_tiles, .. } => !visible_tiles.is_empty(),
                     BrushKind::RadialGradient { ref visible_tiles, .. } => !visible_tiles.is_empty(),
                     _ => false,
                 }
@@ -662,49 +671,52 @@ impl AlphaBatchBuilder {
             prim_instance.clip_task_id.is_some() ||
             transform_kind == TransformedRectKind::Complex {
             specified_blend_mode
         } else {
             BlendMode::None
         };
 
         let prim_header = PrimitiveHeader {
-            local_rect: prim_metadata.local_rect,
+            local_rect: prim.local_rect,
             local_clip_rect: prim_instance.combined_local_clip_rect,
             task_address,
             specific_prim_address: prim_cache_address,
             clip_task_address,
             transform_id,
         };
 
         if cfg!(debug_assertions) && ctx.prim_store.chase_id == Some(prim_instance.prim_index) {
             println!("\ttask target {:?}", self.target_rect);
             println!("\t{:?}", prim_header);
         }
 
         match prim.details {
             PrimitiveDetails::Brush(ref brush) => {
                 match brush.kind {
-                    BrushKind::Picture(ref picture) => {
+                    BrushKind::Picture { pic_index, .. } => {
+                        let picture = &ctx.prim_store.pictures[pic_index.0];
+
                         // If this picture is participating in a 3D rendering context,
                         // then don't add it to any batches here. Instead, create a polygon
                         // for it and add it to the current plane splitter.
                         if picture.is_in_3d_context {
                             // Push into parent plane splitter.
                             debug_assert!(picture.raster_config.is_some());
                             let transform = transforms.get_world_transform(prim_instance.spatial_node_index);
 
                             // Apply the local clip rect here, before splitting. This is
                             // because the local clip rect can't be applied in the vertex
                             // shader for split composites, since we are drawing polygons
                             // rather that rectangles. The interpolation still works correctly
                             // since we determine the UVs by doing a bilerp with a factor
                             // from the original local rect.
-                            let local_rect = prim_metadata.local_rect
-                                                          .intersection(&prim_instance.combined_local_clip_rect);
+                            let local_rect = prim
+                                .local_rect
+                                .intersection(&prim_instance.combined_local_clip_rect);
 
                             if let Some(local_rect) = local_rect {
                                 match transform.transform_kind() {
                                     TransformedRectKind::AxisAligned => {
                                         let inv_transform = transforms.get_world_inv_transform(prim_instance.spatial_node_index);
                                         let polygon = Polygon::from_transformed_rect_with_inverse(
                                             local_rect.cast(),
                                             &transform.cast(),
@@ -823,18 +835,18 @@ impl AlphaBatchBuilder {
                                                 let shadow_prim_address = gpu_cache.get_address(&picture.extra_gpu_data_handle);
 
                                                 let content_prim_header_index = prim_headers.push(&prim_header, [
                                                     ShaderColorMode::Image as i32,
                                                     RasterizationSpace::Screen as i32,
                                                     0,
                                                 ]);
 
-                                                let shadow_rect = prim_metadata.local_rect.translate(&offset);
-                                                let shadow_clip_rect = prim_metadata.local_clip_rect.translate(&offset);
+                                                let shadow_rect = prim.local_rect.translate(&offset);
+                                                let shadow_clip_rect = prim.local_clip_rect.translate(&offset);
 
                                                 let shadow_prim_header = PrimitiveHeader {
                                                     local_rect: shadow_rect,
                                                     local_clip_rect: shadow_clip_rect,
                                                     specific_prim_address: shadow_prim_address,
                                                     ..prim_header
                                                 };
 
--- a/gfx/webrender/src/display_list_flattener.rs
+++ b/gfx/webrender/src/display_list_flattener.rs
@@ -21,18 +21,18 @@ use glyph_rasterizer::FontInstance;
 use gpu_cache::GpuCacheHandle;
 use gpu_types::BrushFlags;
 use hit_test::{HitTestingItem, HitTestingRun};
 use image::simplify_repeated_primitive;
 use internal_types::{FastHashMap, FastHashSet};
 use picture::{PictureCompositeMode, PictureIdGenerator, PicturePrimitive};
 use prim_store::{BrushKind, BrushPrimitive, BrushSegmentDescriptor, PrimitiveInstance};
 use prim_store::{EdgeAaSegmentMask, ImageSource, PrimitiveOpacity, PrimitiveKey};
-use prim_store::{BorderSource, BrushSegment, BrushSegmentVec, PrimitiveContainer, PrimitiveIndex, PrimitiveStore};
-use prim_store::{OpacityBinding, ScrollNodeAndClipChain, TextRunPrimitive};
+use prim_store::{BorderSource, BrushSegment, BrushSegmentVec, PrimitiveContainer, PrimitiveStore};
+use prim_store::{OpacityBinding, ScrollNodeAndClipChain, TextRunPrimitive, PictureIndex};
 use render_backend::{DocumentView};
 use resource_cache::{FontInstanceMap, ImageRequest};
 use scene::{Scene, ScenePipeline, StackingContextHelpers};
 use scene_builder::DocumentResources;
 use spatial_node::{StickyFrameInfo};
 use std::{f32, mem};
 use std::collections::vec_deque::VecDeque;
 use tiling::{CompositeOps};
@@ -154,19 +154,19 @@ pub struct DisplayListFlattener<'a> {
 
     /// Reference to the document resources, which contains
     /// shared (interned) data between display lists.
     resources: &'a mut DocumentResources,
 
     /// The estimated count of primtives we expect to encounter during flattening.
     prim_count_estimate: usize,
 
-    /// The root primitive index for this flattener. This is the primitive
+    /// The root picture index for this flattener. This is the picture
     /// to start the culling phase from.
-    pub root_prim_index: PrimitiveIndex,
+    pub root_pic_index: PictureIndex,
 }
 
 impl<'a> DisplayListFlattener<'a> {
     pub fn create_frame_builder(
         scene: &Scene,
         clip_scroll_tree: &mut ClipScrollTree,
         font_instances: FontInstanceMap,
         view: &DocumentView,
@@ -196,17 +196,17 @@ impl<'a> DisplayListFlattener<'a> {
             pending_shadow_items: VecDeque::new(),
             sc_stack: Vec::new(),
             pipeline_clip_chain_stack: vec![ClipChainId::NONE],
             prim_store: PrimitiveStore::new(),
             clip_store: ClipStore::new(),
             picture_id_generator,
             resources,
             prim_count_estimate: 0,
-            root_prim_index: PrimitiveIndex(0),
+            root_pic_index: PictureIndex(0),
         };
 
         flattener.push_root(
             root_pipeline_id,
             &root_pipeline.viewport_size,
             &root_pipeline.content_size,
         );
         flattener.flatten_root(root_pipeline, &root_pipeline.viewport_size);
@@ -1059,30 +1059,32 @@ impl<'a> DisplayListFlattener<'a> {
             composite_mode,
             stacking_context.participating_in_3d_context,
             stacking_context.pipeline_id,
             stacking_context.frame_output_pipeline_id,
             true,
             stacking_context.requested_raster_space,
             stacking_context.normal_primitives,
         );
+        let leaf_pic_index = self.prim_store.create_picture(leaf_picture);
 
         // Create a brush primitive that draws this picture.
-        let leaf_prim = BrushPrimitive::new_picture(leaf_picture);
+        let leaf_prim = BrushPrimitive::new_picture(leaf_pic_index);
 
         // Add the brush to the parent picture.
         let leaf_prim_index = self.prim_store.add_primitive(
             &LayoutRect::zero(),
             &max_clip,
             PrimitiveContainer::Brush(leaf_prim),
         );
 
         // Create a chain of pictures based on presence of filters,
         // mix-blend-mode and/or 3d rendering context containers.
         let mut current_prim_index = leaf_prim_index;
+        let mut current_pic_index = leaf_pic_index;
 
         // For each filter, create a new image with that composite mode.
         for filter in &stacking_context.composite_ops.filters {
             let filter = filter.sanitize();
 
             let filter_picture = PicturePrimitive::new_image(
                 self.picture_id_generator.next(),
                 Some(PictureCompositeMode::Filter(filter)),
@@ -1095,28 +1097,30 @@ impl<'a> DisplayListFlattener<'a> {
                     PrimitiveInstance::new(
                         current_prim_index,
                         prim_data_handle,
                         stacking_context.clip_chain_id,
                         stacking_context.spatial_node_index,
                     ),
                 ],
             );
+            let filter_pic_index = self.prim_store.create_picture(filter_picture);
+            current_pic_index = filter_pic_index;
 
-            let filter_prim = BrushPrimitive::new_picture(filter_picture);
+            let filter_prim = BrushPrimitive::new_picture(filter_pic_index);
 
             current_prim_index = self.prim_store.add_primitive(
                 &LayoutRect::zero(),
                 &max_clip,
                 PrimitiveContainer::Brush(filter_prim),
             );
 
             // Run the optimize pass on this picture, to see if we can
             // collapse opacity and avoid drawing to an off-screen surface.
-            self.prim_store.optimize_picture_if_possible(current_prim_index);
+            self.prim_store.optimize_picture_if_possible(current_pic_index);
         }
 
         // Same for mix-blend-mode.
         if let Some(mix_blend_mode) = stacking_context.composite_ops.mix_blend_mode {
             let blend_picture = PicturePrimitive::new_image(
                 self.picture_id_generator.next(),
                 Some(PictureCompositeMode::MixBlend(mix_blend_mode)),
                 false,
@@ -1128,18 +1132,20 @@ impl<'a> DisplayListFlattener<'a> {
                     PrimitiveInstance::new(
                         current_prim_index,
                         prim_data_handle,
                         stacking_context.clip_chain_id,
                         stacking_context.spatial_node_index,
                     ),
                 ],
             );
+            let blend_pic_index = self.prim_store.create_picture(blend_picture);
+            current_pic_index = blend_pic_index;
 
-            let blend_prim = BrushPrimitive::new_picture(blend_picture);
+            let blend_prim = BrushPrimitive::new_picture(blend_pic_index);
 
             current_prim_index = self.prim_store.add_primitive(
                 &LayoutRect::zero(),
                 &max_clip,
                 PrimitiveContainer::Brush(blend_prim),
             );
         }
 
@@ -1162,31 +1168,33 @@ impl<'a> DisplayListFlattener<'a> {
                 None,
                 false,
                 stacking_context.pipeline_id,
                 None,
                 true,
                 stacking_context.requested_raster_space,
                 prims,
             );
+            let container_pic_index = self.prim_store.create_picture(container_picture);
+            current_pic_index = container_pic_index;
 
-            let container_prim = BrushPrimitive::new_picture(container_picture);
+            let container_prim = BrushPrimitive::new_picture(container_pic_index);
 
             current_prim_index = self.prim_store.add_primitive(
                 &LayoutRect::zero(),
                 &max_clip,
                 PrimitiveContainer::Brush(container_prim),
             );
         } else {
             debug_assert!(stacking_context.preserve3d_primitives.is_empty());
         }
 
         if self.sc_stack.is_empty() {
             // This must be the root stacking context
-            self.root_prim_index = current_prim_index;
+            self.root_pic_index = current_pic_index;
             return;
         }
 
         let sc_count = self.sc_stack.len();
         let prim_instance = PrimitiveInstance::new(
             current_prim_index,
             prim_data_handle,
             stacking_context.clip_chain_id,
@@ -1495,17 +1503,18 @@ impl<'a> DisplayListFlattener<'a> {
                             pipeline_id,
                             None,
                             is_passthrough,
                             raster_space,
                             prims,
                         );
 
                         // Create the primitive to draw the shadow picture into the scene.
-                        let shadow_prim = BrushPrimitive::new_picture(shadow_pic);
+                        let shadow_pic_index = self.prim_store.create_picture(shadow_pic);
+                        let shadow_prim = BrushPrimitive::new_picture(shadow_pic_index);
                         let shadow_prim_index = self.prim_store.add_primitive(
                             &LayoutRect::zero(),
                             &max_clip,
                             PrimitiveContainer::Brush(shadow_prim),
                         );
 
                         let shadow_prim_key = PrimitiveKey::new(true);
                         let shadow_prim_data_handle = self.resources.prim_interner.intern(&shadow_prim_key);
--- a/gfx/webrender/src/frame_builder.rs
+++ b/gfx/webrender/src/frame_builder.rs
@@ -8,17 +8,17 @@ use api::{LayoutPoint, LayoutRect, Layou
 use clip::{ClipDataStore, ClipStore};
 use clip_scroll_tree::{ClipScrollTree, ROOT_SPATIAL_NODE_INDEX, SpatialNodeIndex};
 use display_list_flattener::{DisplayListFlattener};
 use gpu_cache::GpuCache;
 use gpu_types::{PrimitiveHeaders, TransformPalette, UvRectKind};
 use hit_test::{HitTester, HitTestingRun};
 use internal_types::{FastHashMap};
 use picture::{PictureCompositeMode, PictureSurface, RasterConfig};
-use prim_store::{PrimitiveIndex, PrimitiveStore, SpaceMapper};
+use prim_store::{PrimitiveIndex, PrimitiveStore, SpaceMapper, PictureIndex};
 use profiler::{FrameProfileCounters, GpuCacheProfileCounters, TextureCacheProfileCounters};
 use render_backend::{FrameResources, FrameId};
 use render_task::{RenderTask, RenderTaskId, RenderTaskLocation, RenderTaskTree};
 use resource_cache::{ResourceCache};
 use scene::{ScenePipeline, SceneProperties};
 use segment::SegmentBuilder;
 use spatial_node::SpatialNode;
 use std::f32;
@@ -53,17 +53,17 @@ pub struct FrameBuilderConfig {
 }
 
 /// A builder structure for `tiling::Frame`
 pub struct FrameBuilder {
     screen_rect: DeviceUintRect,
     background_color: Option<ColorF>,
     window_size: DeviceUintSize,
     scene_id: u64,
-    root_prim_index: PrimitiveIndex,
+    root_pic_index: PictureIndex,
     pub prim_store: PrimitiveStore,
     pub clip_store: ClipStore,
     pub hit_testing_runs: Vec<HitTestingRun>,
     pub config: FrameBuilderConfig,
 }
 
 pub struct FrameBuildingContext<'a> {
     pub scene_id: u64,
@@ -83,16 +83,17 @@ pub struct FrameBuildingState<'a> {
     pub gpu_cache: &'a mut GpuCache,
     pub special_render_passes: &'a mut SpecialRenderPasses,
     pub transforms: &'a mut TransformPalette,
     pub resources: &'a mut FrameResources,
     pub segment_builder: SegmentBuilder,
 }
 
 pub struct PictureContext {
+    pub pic_index: PictureIndex,
     pub pipeline_id: PipelineId,
     pub apply_local_clip_rect: bool,
     pub inflation_factor: f32,
     pub allow_subpixel_aa: bool,
     pub is_passthrough: bool,
     pub raster_space: RasterSpace,
 }
 
@@ -133,17 +134,17 @@ impl FrameBuilder {
         FrameBuilder {
             hit_testing_runs: Vec::new(),
             prim_store: PrimitiveStore::new(),
             clip_store: ClipStore::new(),
             screen_rect: DeviceUintRect::zero(),
             window_size: DeviceUintSize::zero(),
             background_color: None,
             scene_id: 0,
-            root_prim_index: PrimitiveIndex(0),
+            root_pic_index: PictureIndex(0),
             config: FrameBuilderConfig {
                 default_font_render_mode: FontRenderMode::Mono,
                 dual_source_blending_is_enabled: true,
                 dual_source_blending_is_supported: false,
                 chase_primitive: ChasePrimitive::Nothing,
             },
         }
     }
@@ -154,17 +155,17 @@ impl FrameBuilder {
         window_size: DeviceUintSize,
         scene_id: u64,
         flattener: DisplayListFlattener,
     ) -> Self {
         FrameBuilder {
             hit_testing_runs: flattener.hit_testing_runs,
             prim_store: flattener.prim_store,
             clip_store: flattener.clip_store,
-            root_prim_index: flattener.root_prim_index,
+            root_pic_index: flattener.root_pic_index,
             screen_rect,
             background_color,
             window_size,
             scene_id,
             config: flattener.config,
         }
     }
 
@@ -223,18 +224,19 @@ impl FrameBuilder {
 
         let prim_context = PrimitiveContext::new(
             &clip_scroll_tree.spatial_nodes[root_spatial_node_index.0],
             root_spatial_node_index,
         );
 
         let (pic_context, mut pic_state, mut instances) = self
             .prim_store
-            .get_pic_mut(self.root_prim_index)
+            .pictures[self.root_pic_index.0]
             .take_context(
+                self.root_pic_index,
                 &prim_context,
                 root_spatial_node_index,
                 root_spatial_node_index,
                 true,
                 &mut frame_state,
                 &frame_context,
                 false,
             )
@@ -246,33 +248,31 @@ impl FrameBuilder {
             &mut instances,
             &pic_context,
             &mut pic_state,
             &frame_context,
             &mut frame_state,
             &mut pic_rect,
         );
 
-        let pic = self
-            .prim_store
-            .get_pic_mut(self.root_prim_index);
+        let pic = &mut self.prim_store.pictures[self.root_pic_index.0];
         pic.restore_context(
             instances,
             pic_context,
             pic_state,
             Some(pic_rect),
             &mut frame_state,
         );
 
         let pic_state = pic.take_state();
 
         let root_render_task = RenderTask::new_picture(
             RenderTaskLocation::Fixed(self.screen_rect.to_i32()),
             self.screen_rect.size.to_f32(),
-            self.root_prim_index,
+            self.root_pic_index,
             DeviceIntPoint::zero(),
             pic_state.tasks,
             UvRectKind::Rect,
             root_spatial_node_index,
         );
 
         let render_task_id = frame_state.render_tasks.add(root_render_task);
         pic.raster_config = Some(RasterConfig {
--- a/gfx/webrender/src/picture.rs
+++ b/gfx/webrender/src/picture.rs
@@ -9,18 +9,17 @@ use api::{PicturePixel, RasterPixel, Wor
 use box_shadow::{BLUR_SAMPLE_SCALE};
 use clip::ClipNodeCollector;
 use clip_scroll_tree::{ROOT_SPATIAL_NODE_INDEX, SpatialNodeIndex};
 use euclid::TypedScale;
 use frame_builder::{FrameBuildingContext, FrameBuildingState, PictureState};
 use frame_builder::{PictureContext, PrimitiveContext};
 use gpu_cache::{GpuCacheHandle};
 use gpu_types::UvRectKind;
-use prim_store::{PrimitiveInstance, SpaceMapper};
-use prim_store::{PrimitiveMetadata, get_raster_rects};
+use prim_store::{PictureIndex, PrimitiveInstance, SpaceMapper, get_raster_rects};
 use render_task::{ClearMode, RenderTask, RenderTaskCacheEntryHandle};
 use render_task::{RenderTaskCacheKey, RenderTaskCacheKeyKind, RenderTaskId, RenderTaskLocation};
 use scene::{FilterOpHelpers, SceneProperties};
 use std::mem;
 use tiling::RenderTargetKind;
 use util::{TransformedRectKind, MatrixHelpers, MaxRect};
 
 /*
@@ -237,16 +236,17 @@ impl PicturePrimitive {
             pipeline_id,
             id,
             requested_raster_space,
         }
     }
 
     pub fn take_context(
         &mut self,
+        pic_index: PictureIndex,
         prim_context: &PrimitiveContext,
         surface_spatial_node_index: SpatialNodeIndex,
         raster_spatial_node_index: SpatialNodeIndex,
         parent_allows_subpixel_aa: bool,
         frame_state: &mut FrameBuildingState,
         frame_context: &FrameBuildingContext,
         is_chased: bool,
     ) -> Option<(PictureContext, PictureState, Vec<PrimitiveInstance>)> {
@@ -361,16 +361,17 @@ impl PicturePrimitive {
                 BLUR_SAMPLE_SCALE * blur_radius
             }
             _ => {
                 0.0
             }
         };
 
         let context = PictureContext {
+            pic_index,
             pipeline_id: self.pipeline_id,
             apply_local_clip_rect: self.apply_local_clip_rect,
             inflation_factor,
             allow_subpixel_aa,
             is_passthrough: self.raster_config.is_none(),
             raster_space,
         };
 
@@ -434,33 +435,34 @@ impl PicturePrimitive {
     }
 
     pub fn take_state(&mut self) -> PictureState {
         self.state.take().expect("bug: no state present!")
     }
 
     pub fn prepare_for_render(
         &mut self,
+        pic_index: PictureIndex,
         prim_instance: &PrimitiveInstance,
-        prim_metadata: &PrimitiveMetadata,
+        prim_local_rect: &LayoutRect,
         pic_state: &mut PictureState,
         frame_context: &FrameBuildingContext,
         frame_state: &mut FrameBuildingState,
     ) -> bool {
         let mut pic_state_for_children = self.take_state();
 
         match self.raster_config {
             Some(ref mut raster_config) => {
                 let (map_raster_to_world, map_pic_to_raster) = create_raster_mappers(
                     prim_instance.spatial_node_index,
                     raster_config.raster_spatial_node_index,
                     frame_context,
                 );
 
-                let pic_rect = PictureRect::from_untyped(&prim_metadata.local_rect.to_untyped());
+                let pic_rect = PictureRect::from_untyped(&prim_local_rect.to_untyped());
 
                 let (clipped, unclipped, transform) = match get_raster_rects(
                     pic_rect,
                     &map_pic_to_raster,
                     &map_raster_to_world,
                     prim_instance.clipped_world_rect.expect("bug1"),
                     frame_context.device_pixel_scale,
                 ) {
@@ -506,17 +508,17 @@ impl PicturePrimitive {
                         // anyway. In the future we should relax this a bit, so that we can
                         // cache tasks with complex coordinate systems if we detect the
                         // relevant transforms haven't changed from frame to frame.
                         let surface = if pic_state_for_children.has_non_root_coord_system ||
                                          !pic_state_for_children.is_cacheable {
                             let picture_task = RenderTask::new_picture(
                                 RenderTaskLocation::Dynamic(None, device_rect.size),
                                 unclipped.size,
-                                prim_instance.prim_index,
+                                pic_index,
                                 device_rect.origin,
                                 pic_state_for_children.tasks,
                                 uv_rect_kind,
                                 pic_state_for_children.raster_spatial_node_index,
                             );
 
                             let picture_task_id = frame_state.render_tasks.add(picture_task);
 
@@ -564,17 +566,17 @@ impl PicturePrimitive {
                                 None,
                                 false,
                                 |render_tasks| {
                                     let child_tasks = mem::replace(&mut pic_state_for_children.tasks, Vec::new());
 
                                     let picture_task = RenderTask::new_picture(
                                         RenderTaskLocation::Dynamic(None, device_rect.size),
                                         unclipped.size,
-                                        prim_instance.prim_index,
+                                        pic_index,
                                         device_rect.origin,
                                         child_tasks,
                                         uv_rect_kind,
                                         pic_state_for_children.raster_spatial_node_index,
                                     );
 
                                     let picture_task_id = render_tasks.add(picture_task);
 
@@ -621,17 +623,17 @@ impl PicturePrimitive {
                             &transform,
                             &device_rect,
                             frame_context.device_pixel_scale,
                         );
 
                         let mut picture_task = RenderTask::new_picture(
                             RenderTaskLocation::Dynamic(None, device_rect.size),
                             unclipped.size,
-                            prim_instance.prim_index,
+                            pic_index,
                             device_rect.origin,
                             pic_state_for_children.tasks,
                             uv_rect_kind,
                             pic_state_for_children.raster_spatial_node_index,
                         );
                         picture_task.mark_for_saving();
 
                         let picture_task_id = frame_state.render_tasks.add(picture_task);
@@ -664,24 +666,24 @@ impl PicturePrimitive {
                             //           drop-shadow where we need a different local
                             //           rect for the shadow. To tidy this up in future,
                             //           we could consider abstracting the code in prim_store.rs
                             //           that writes a brush primitive header.
 
                             // Basic brush primitive header is (see end of prepare_prim_for_render_inner in prim_store.rs)
                             //  [brush specific data]
                             //  [segment_rect, segment data]
-                            let shadow_rect = prim_metadata.local_rect.translate(&offset);
+                            let shadow_rect = prim_local_rect.translate(&offset);
 
                             // ImageBrush colors
                             request.push(color.premultiplied());
                             request.push(PremultipliedColorF::WHITE);
                             request.push([
-                                prim_metadata.local_rect.size.width,
-                                prim_metadata.local_rect.size.height,
+                                prim_local_rect.size.width,
+                                prim_local_rect.size.height,
                                 0.0,
                                 0.0,
                             ]);
 
                             // segment rect / extra data
                             request.push(shadow_rect);
                             request.push([0.0, 0.0, 0.0, 0.0]);
                         }
@@ -692,17 +694,17 @@ impl PicturePrimitive {
                             &transform,
                             &clipped,
                             frame_context.device_pixel_scale,
                         );
 
                         let picture_task = RenderTask::new_picture(
                             RenderTaskLocation::Dynamic(None, clipped.size),
                             unclipped.size,
-                            prim_instance.prim_index,
+                            pic_index,
                             clipped.origin,
                             pic_state_for_children.tasks,
                             uv_rect_kind,
                             pic_state_for_children.raster_spatial_node_index,
                         );
 
                         let readback_task_id = frame_state.render_tasks.add(
                             RenderTask::new_readback(clipped)
@@ -729,17 +731,17 @@ impl PicturePrimitive {
                             &transform,
                             &clipped,
                             frame_context.device_pixel_scale,
                         );
 
                         let picture_task = RenderTask::new_picture(
                             RenderTaskLocation::Dynamic(None, clipped.size),
                             unclipped.size,
-                            prim_instance.prim_index,
+                            pic_index,
                             clipped.origin,
                             pic_state_for_children.tasks,
                             uv_rect_kind,
                             pic_state_for_children.raster_spatial_node_index,
                         );
 
                         let render_task_id = frame_state.render_tasks.add(picture_task);
                         pic_state.tasks.push(render_task_id);
@@ -751,17 +753,17 @@ impl PicturePrimitive {
                             &transform,
                             &clipped,
                             frame_context.device_pixel_scale,
                         );
 
                         let picture_task = RenderTask::new_picture(
                             RenderTaskLocation::Dynamic(None, clipped.size),
                             unclipped.size,
-                            prim_instance.prim_index,
+                            pic_index,
                             clipped.origin,
                             pic_state_for_children.tasks,
                             uv_rect_kind,
                             pic_state_for_children.raster_spatial_node_index,
                         );
 
                         let render_task_id = frame_state.render_tasks.add(picture_task);
                         pic_state.tasks.push(render_task_id);
--- a/gfx/webrender/src/prim_store.rs
+++ b/gfx/webrender/src/prim_store.rs
@@ -219,16 +219,21 @@ pub struct DeferredResolve {
     pub rendering: ImageRendering,
 }
 
 #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash, Ord, PartialOrd)]
 #[cfg_attr(feature = "capture", derive(Serialize))]
 #[cfg_attr(feature = "replay", derive(Deserialize))]
 pub struct PrimitiveIndex(pub usize);
 
+#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash, Ord, PartialOrd)]
+#[cfg_attr(feature = "capture", derive(Serialize))]
+#[cfg_attr(feature = "replay", derive(Deserialize))]
+pub struct PictureIndex(pub usize);
+
 impl GpuCacheHandle {
     pub fn as_int(&self, gpu_cache: &GpuCache) -> i32 {
         gpu_cache.get_address(self).as_int()
     }
 }
 
 impl GpuCacheAddress {
     pub fn as_int(&self) -> i32 {
@@ -276,23 +281,16 @@ impl From<PrimitiveKey> for PrimitiveTem
 #[derive(Clone, Copy, Debug)]
 pub struct PrimitiveDataMarker;
 
 pub type PrimitiveDataStore = intern::DataStore<PrimitiveKey, PrimitiveTemplate, PrimitiveDataMarker>;
 pub type PrimitiveDataHandle = intern::Handle<PrimitiveDataMarker>;
 pub type PrimitiveDataUpdateList = intern::UpdateList<PrimitiveKey>;
 pub type PrimitiveDataInterner = intern::Interner<PrimitiveKey, PrimitiveDataMarker>;
 
-// TODO(gw): Pack the fields here better!
-#[derive(Debug)]
-pub struct PrimitiveMetadata {
-    pub local_rect: LayoutRect,
-    pub local_clip_rect: LayoutRect,
-}
-
 // Maintains a list of opacity bindings that have been collapsed into
 // the color of a single primitive. This is an important optimization
 // that avoids allocating an intermediate surface for most common
 // uses of opacity filters.
 #[derive(Debug)]
 pub struct OpacityBinding {
     bindings: Vec<PropertyBinding<f32>>,
     current: f32,
@@ -367,17 +365,19 @@ pub enum BorderSource {
 
 #[derive(Debug)]
 pub enum BrushKind {
     Solid {
         color: ColorF,
         opacity_binding: OpacityBinding,
     },
     Clear,
-    Picture(PicturePrimitive),
+    Picture {
+        pic_index: PictureIndex,
+    },
     Image {
         request: ImageRequest,
         alpha_type: AlphaType,
         stretch_size: LayoutSize,
         tile_spacing: LayoutSize,
         color: ColorF,
         source: ImageSource,
         sub_rect: Option<DeviceIntRect>,
@@ -633,30 +633,21 @@ impl BrushPrimitive {
         segment_desc: Option<BrushSegmentDescriptor>,
     ) -> Self {
         BrushPrimitive {
             kind,
             segment_desc,
         }
     }
 
-    pub fn may_need_clip_mask(&self) -> bool {
-        match self.kind {
-            BrushKind::Picture(ref pic) => {
-                pic.raster_config.is_some()
-            }
-            _ => {
-                true
-            }
-        }
-    }
-
-    pub fn new_picture(prim: PicturePrimitive) -> Self {
+    pub fn new_picture(pic_index: PictureIndex) -> Self {
         BrushPrimitive {
-            kind: BrushKind::Picture(prim),
+            kind: BrushKind::Picture {
+                pic_index,
+            },
             segment_desc: None,
         }
     }
 
     pub fn new_line_decoration(
         color: ColorF,
         style: LineStyle,
         orientation: LineOrientation,
@@ -1503,40 +1494,21 @@ impl PrimitiveContainer {
 }
 
 pub enum PrimitiveDetails {
     Brush(BrushPrimitive),
     TextRun(TextRunPrimitive),
 }
 
 pub struct Primitive {
-    pub metadata: PrimitiveMetadata,
+    pub local_rect: LayoutRect,
+    pub local_clip_rect: LayoutRect,
     pub details: PrimitiveDetails,
 }
 
-impl Primitive {
-    pub fn as_pic(&self) -> &PicturePrimitive {
-        match self.details {
-            PrimitiveDetails::Brush(BrushPrimitive { kind: BrushKind::Picture(ref pic), .. }) => pic,
-            _ => {
-                panic!("bug: not a picture!");
-            }
-        }
-    }
-
-    pub fn as_pic_mut(&mut self) -> &mut PicturePrimitive {
-        match self.details {
-            PrimitiveDetails::Brush(BrushPrimitive { kind: BrushKind::Picture(ref mut pic), .. }) => pic,
-            _ => {
-                panic!("bug: not a picture!");
-            }
-        }
-    }
-}
-
 #[derive(Debug)]
 pub struct PrimitiveInstance {
     /// Index into the prim store containing information about
     /// the specific primitive. This will be removed once all
     /// primitive data is interned.
     pub prim_index: PrimitiveIndex,
 
     /// Handle to the common interned data for this primitive.
@@ -1597,85 +1569,75 @@ impl PrimitiveInstance {
             clip_chain_id,
             spatial_node_index,
         }
     }
 }
 
 pub struct PrimitiveStore {
     pub primitives: Vec<Primitive>,
+    pub pictures: Vec<PicturePrimitive>,
 
     /// A primitive index to chase through debugging.
     pub chase_id: Option<PrimitiveIndex>,
 }
 
 impl PrimitiveStore {
     pub fn new() -> PrimitiveStore {
         PrimitiveStore {
             primitives: Vec::new(),
+            pictures: Vec::new(),
             chase_id: None,
         }
     }
 
-    pub fn get_pic(&self, index: PrimitiveIndex) -> &PicturePrimitive {
-        self.primitives[index.0].as_pic()
-    }
-
-    pub fn get_pic_mut(&mut self, index: PrimitiveIndex) -> &mut PicturePrimitive {
-        self.primitives[index.0].as_pic_mut()
+    pub fn create_picture(
+        &mut self,
+        prim: PicturePrimitive,
+    ) -> PictureIndex {
+        let index = PictureIndex(self.pictures.len());
+        self.pictures.push(prim);
+        index
     }
 
     pub fn add_primitive(
         &mut self,
         local_rect: &LayoutRect,
         local_clip_rect: &LayoutRect,
         container: PrimitiveContainer,
     ) -> PrimitiveIndex {
         let prim_index = self.primitives.len();
 
-        let base_metadata = PrimitiveMetadata {
+        let details = match container {
+            PrimitiveContainer::Brush(brush) => {
+                PrimitiveDetails::Brush(brush)
+            }
+            PrimitiveContainer::TextRun(text_cpu) => {
+                PrimitiveDetails::TextRun(text_cpu)
+            }
+        };
+
+        let prim = Primitive {
             local_rect: *local_rect,
             local_clip_rect: *local_clip_rect,
-        };
-
-        let prim = match container {
-            PrimitiveContainer::Brush(brush) => {
-                let metadata = PrimitiveMetadata {
-                    ..base_metadata
-                };
-
-                Primitive {
-                    metadata,
-                    details: PrimitiveDetails::Brush(brush),
-                }
-            }
-            PrimitiveContainer::TextRun(text_cpu) => {
-                let metadata = PrimitiveMetadata {
-                    ..base_metadata
-                };
-
-                Primitive {
-                    metadata,
-                    details: PrimitiveDetails::TextRun(text_cpu),
-                }
-            }
+            details,
         };
 
         self.primitives.push(prim);
 
         PrimitiveIndex(prim_index)
     }
 
     // Internal method that retrieves the primitive index of a primitive
     // that can be the target for collapsing parent opacity filters into.
     fn get_opacity_collapse_prim(
         &self,
-        pic_prim_index: PrimitiveIndex,
+        pic_index: PictureIndex,
     ) -> Option<PrimitiveIndex> {
-        let pic = self.get_pic(pic_prim_index);
+        let pic = &self.pictures[pic_index.0];
 
         // We can only collapse opacity if there is a single primitive, otherwise
         // the opacity needs to be applied to the primitives as a group.
         if pic.prim_instances.len() != 1 {
             return None;
         }
 
         let prim_instance = &pic.prim_instances[0];
@@ -1683,22 +1645,24 @@ impl PrimitiveStore {
 
         // For now, we only support opacity collapse on solid rects and images.
         // This covers the most common types of opacity filters that can be
         // handled by this optimization. In the future, we can easily extend
         // this to other primitives, such as text runs and gradients.
         match prim.details {
             PrimitiveDetails::Brush(ref brush) => {
                 match brush.kind {
-                    BrushKind::Picture(ref pic) => {
+                    BrushKind::Picture { pic_index, .. } => {
+                        let pic = &self.pictures[pic_index.0];
+
                         // If we encounter a picture that is a pass-through
                         // (i.e. no composite mode), then we can recurse into
                         // that to try and find a primitive to collapse to.
                         if pic.requested_composite_mode.is_none() {
-                            return self.get_opacity_collapse_prim(prim_instance.prim_index);
+                            return self.get_opacity_collapse_prim(pic_index);
                         }
                     }
                     // If we find a single rect or image, we can use that
                     // as the primitive to collapse the opacity into.
                     BrushKind::Solid { .. } | BrushKind::Image { .. } => {
                         return Some(prim_instance.prim_index)
                     }
                     BrushKind::Border { .. } |
@@ -1716,31 +1680,31 @@ impl PrimitiveStore {
     }
 
     // Apply any optimizations to drawing this picture. Currently,
     // we just support collapsing pictures with an opacity filter
     // by pushing that opacity value into the color of a primitive
     // if that picture contains one compatible primitive.
     pub fn optimize_picture_if_possible(
         &mut self,
-        pic_prim_index: PrimitiveIndex,
+        pic_index: PictureIndex,
     ) {
         // Only handle opacity filters for now.
-        let binding = match self.get_pic(pic_prim_index).requested_composite_mode {
+        let binding = match self.pictures[pic_index.0].requested_composite_mode {
             Some(PictureCompositeMode::Filter(FilterOp::Opacity(binding, _))) => {
                 binding
             }
             _ => {
                 return;
             }
         };
 
         // See if this picture contains a single primitive that supports
         // opacity collapse.
-        match self.get_opacity_collapse_prim(pic_prim_index) {
+        match self.get_opacity_collapse_prim(pic_index) {
             Some(prim_index) => {
                 let prim = &mut self.primitives[prim_index.0];
                 match prim.details {
                     PrimitiveDetails::Brush(ref mut brush) => {
                         // By this point, we know we should only have found a primitive
                         // that supports opacity collapse.
                         match brush.kind {
                             BrushKind::Solid { ref mut opacity_binding, .. } |
@@ -1768,17 +1732,17 @@ impl PrimitiveStore {
             }
         }
 
         // The opacity filter has been collapsed, so mark this picture
         // as a pass though. This means it will no longer allocate an
         // intermediate surface or incur an extra blend / blit. Instead,
         // the collapsed primitive will be drawn directly into the
         // parent picture.
-        self.get_pic_mut(pic_prim_index).requested_composite_mode = None;
+        self.pictures[pic_index.0].requested_composite_mode = None;
     }
 
     pub fn prim_count(&self) -> usize {
         self.primitives.len()
     }
 
     pub fn prepare_prim_for_render(
         &mut self,
@@ -1794,18 +1758,21 @@ impl PrimitiveStore {
     ) -> bool {
         // If we have dependencies, we need to prepare them first, in order
         // to know the actual rect of this primitive.
         // For example, scrolling may affect the location of an item in
         // local space, which may force us to render this item on a larger
         // picture target, if being composited.
         let pic_info = {
             match self.primitives[prim_instance.prim_index.0].details {
-                PrimitiveDetails::Brush(BrushPrimitive { kind: BrushKind::Picture(ref mut pic), .. }) => {
+                PrimitiveDetails::Brush(BrushPrimitive { kind: BrushKind::Picture { pic_index, .. }, .. }) => {
+                    let pic = &mut self.pictures[pic_index.0];
+
                     match pic.take_context(
+                        pic_index,
                         prim_context,
                         pic_state.surface_spatial_node_index,
                         pic_state.raster_spatial_node_index,
                         pic_context.allow_subpixel_aa,
                         frame_state,
                         frame_context,
                         is_chased,
                     ) {
@@ -1840,33 +1807,33 @@ impl PrimitiveStore {
                 let pic_rect = if is_passthrough {
                     *current_pic_rect = current_pic_rect.union(&pic_rect);
                     None
                 } else {
                     Some(pic_rect)
                 };
 
                 if !pic_state_for_children.is_cacheable {
-                  pic_state.is_cacheable = false;
+                    pic_state.is_cacheable = false;
                 }
 
                 // Restore the dependencies (borrow check dance)
-                let prim = &mut self.primitives[prim_instance.prim_index.0];
-                let (new_local_rect, clip_node_collector) = prim
-                    .as_pic_mut()
+                let (new_local_rect, clip_node_collector) = self
+                    .pictures[pic_context_for_children.pic_index.0]
                     .restore_context(
                         prim_instances,
                         pic_context_for_children,
                         pic_state_for_children,
                         pic_rect,
                         frame_state,
                     );
 
-                if new_local_rect != prim.metadata.local_rect {
-                    prim.metadata.local_rect = new_local_rect;
+                let prim = &mut self.primitives[prim_instance.prim_index.0];
+                if new_local_rect != prim.local_rect {
+                    prim.local_rect = new_local_rect;
                     frame_state.gpu_cache.invalidate(&mut prim_instance.gpu_location);
                     pic_state.local_rect_changed = true;
                 }
 
                 (is_passthrough, clip_node_collector)
             }
             None => {
                 (false, None)
@@ -1877,50 +1844,49 @@ impl PrimitiveStore {
 
         if !prim.is_cacheable(frame_state.resource_cache) {
             pic_state.is_cacheable = false;
         }
 
         if is_passthrough {
             prim_instance.clipped_world_rect = Some(pic_state.map_pic_to_world.bounds);
         } else {
-            if prim.metadata.local_rect.size.width <= 0.0 ||
-               prim.metadata.local_rect.size.height <= 0.0 {
+            if prim.local_rect.size.width <= 0.0 ||
+               prim.local_rect.size.height <= 0.0 {
                 if cfg!(debug_assertions) && is_chased {
                     println!("\tculled for zero local rectangle");
                 }
                 return false;
             }
 
             // Inflate the local rect for this primitive by the inflation factor of
             // the picture context. This ensures that even if the primitive itself
             // is not visible, any effects from the blur radius will be correctly
             // taken into account.
             let local_rect = prim
-                .metadata
                 .local_rect
                 .inflate(pic_context.inflation_factor, pic_context.inflation_factor)
-                .intersection(&prim.metadata.local_clip_rect);
+                .intersection(&prim.local_clip_rect);
             let local_rect = match local_rect {
                 Some(local_rect) => local_rect,
                 None => {
                     if cfg!(debug_assertions) && is_chased {
                         println!("\tculled for being out of the local clip rectangle: {:?}",
-                            prim.metadata.local_clip_rect);
+                            prim.local_clip_rect);
                     }
                     return false;
                 }
             };
 
             let clip_chain = frame_state
                 .clip_store
                 .build_clip_chain_instance(
                     prim_instance.clip_chain_id,
                     local_rect,
-                    prim.metadata.local_clip_rect,
+                    prim.local_clip_rect,
                     prim_context.spatial_node_index,
                     &pic_state.map_local_to_pic,
                     &pic_state.map_pic_to_world,
                     &frame_context.clip_scroll_tree,
                     frame_state.gpu_cache,
                     frame_state.resource_cache,
                     frame_context.device_pixel_scale,
                     &frame_context.world_rect,
@@ -1943,21 +1909,21 @@ impl PrimitiveStore {
                 );
             }
 
             pic_state.has_non_root_coord_system |= clip_chain.has_non_root_coord_system;
 
             prim_instance.combined_local_clip_rect = if pic_context.apply_local_clip_rect {
                 clip_chain.local_clip_rect
             } else {
-                prim.metadata.local_clip_rect
+                prim.local_clip_rect
             };
 
             let pic_rect = match pic_state.map_local_to_pic
-                                          .map(&prim.metadata.local_rect) {
+                                          .map(&prim.local_rect) {
                 Some(pic_rect) => pic_rect,
                 None => return false,
             };
 
             // Check if the clip bounding rect (in pic space) is visible on screen
             // This includes both the prim bounding rect + local prim clip rect!
             let world_rect = match pic_state.map_pic_to_world
                                             .map(&clip_chain.pic_clip_rect) {
@@ -1996,16 +1962,17 @@ impl PrimitiveStore {
             *current_pic_rect = current_pic_rect.union(&pic_rect);
         }
 
         prim.prepare_prim_for_render_inner(
             prim_instance,
             prim_context,
             pic_context,
             pic_state,
+            &mut self.pictures,
             frame_context,
             frame_state,
             display_list,
             is_chased,
         );
 
         true
     }
@@ -2113,45 +2080,45 @@ fn build_gradient_stops_request(
             &mut request,
         );
     }
 }
 
 fn decompose_repeated_primitive(
     visible_tiles: &mut Vec<VisibleGradientTile>,
     instance: &mut PrimitiveInstance,
-    metadata: &mut PrimitiveMetadata,
+    prim_local_rect: &LayoutRect,
     stretch_size: &LayoutSize,
     tile_spacing: &LayoutSize,
     prim_context: &PrimitiveContext,
     frame_state: &mut FrameBuildingState,
     callback: &mut FnMut(&LayoutRect, GpuDataRequest),
 ) {
     visible_tiles.clear();
 
     // Tighten the clip rect because decomposing the repeated image can
     // produce primitives that are partially covering the original image
     // rect and we want to clip these extra parts out.
     let tight_clip_rect = instance
         .combined_local_clip_rect
-        .intersection(&metadata.local_rect).unwrap();
+        .intersection(prim_local_rect).unwrap();
 
     let clipped_world_rect = &instance
         .clipped_world_rect
         .unwrap();
 
     let visible_rect = compute_conservative_visible_rect(
         prim_context,
         clipped_world_rect,
         &tight_clip_rect
     );
     let stride = *stretch_size + *tile_spacing;
 
     for_each_repetition(
-        &metadata.local_rect,
+        prim_local_rect,
         &visible_rect,
         &stride,
         &mut |origin, _| {
 
             let mut handle = GpuCacheHandle::new();
             let rect = LayoutRect {
                 origin: *origin,
                 size: *stretch_size,
@@ -2215,175 +2182,178 @@ impl<'a> GpuDataRequest<'a> {
         extra_data: [f32; 4],
     ) {
         let _ = VECS_PER_SEGMENT;
         self.push(local_rect);
         self.push(extra_data);
     }
 }
 
-fn write_brush_segment_description(
-    brush: &mut BrushPrimitive,
-    metadata: &PrimitiveMetadata,
-    clip_chain: &ClipChainInstance,
-    frame_state: &mut FrameBuildingState,
-) {
-    match brush.segment_desc {
-        Some(..) => {
-            // If we already have a segment descriptor, skip segment build.
-            return;
-        }
-        None => {
-            // If no segment descriptor built yet, see if it is a brush
-            // type that wants to be segmented.
-            if !brush.kind.supports_segments(frame_state.resource_cache) {
+impl BrushPrimitive {
+    fn write_brush_segment_description(
+        &mut self,
+        prim_local_rect: LayoutRect,
+        prim_local_clip_rect: LayoutRect,
+        clip_chain: &ClipChainInstance,
+        frame_state: &mut FrameBuildingState,
+    ) {
+        match self.segment_desc {
+            Some(..) => {
+                // If we already have a segment descriptor, skip segment build.
                 return;
             }
-        }
-    }
-
-    // If the brush is small, we generally want to skip building segments
-    // and just draw it as a single primitive with clip mask. However,
-    // if the clips are purely rectangles that have no per-fragment
-    // clip masks, we will segment anyway. This allows us to completely
-    // skip allocating a clip mask in these cases.
-    let is_large = metadata.local_rect.size.area() > MIN_BRUSH_SPLIT_AREA;
-
-    // TODO(gw): We should probably detect and store this on each
-    //           ClipSources instance, to avoid having to iterate
-    //           the clip sources here.
-    let mut rect_clips_only = true;
-
-    let segment_builder = &mut frame_state.segment_builder;
-    segment_builder.initialize(
-        metadata.local_rect,
-        None,
-        metadata.local_clip_rect
-    );
-
-    // Segment the primitive on all the local-space clip sources that we can.
-    let mut local_clip_count = 0;
-    for i in 0 .. clip_chain.clips_range.count {
-        let clip_instance = frame_state
-            .clip_store
-            .get_instance_from_range(&clip_chain.clips_range, i);
-        let clip_node = &frame_state.resources.clip_data_store[clip_instance.handle];
-
-        // If this clip item is positioned by another positioning node, its relative position
-        // could change during scrolling. This means that we would need to resegment. Instead
-        // of doing that, only segment with clips that have the same positioning node.
-        // TODO(mrobinson, #2858): It may make sense to include these nodes, resegmenting only
-        // when necessary while scrolling.
-        if !clip_instance.flags.contains(ClipNodeFlags::SAME_SPATIAL_NODE) {
-            continue;
-        }
-
-        local_clip_count += 1;
-
-        let (local_clip_rect, radius, mode) = match clip_node.item {
-            ClipItem::RoundedRectangle(rect, radii, clip_mode) => {
-                rect_clips_only = false;
-                (rect, Some(radii), clip_mode)
-            }
-            ClipItem::Rectangle(rect, mode) => {
-                (rect, None, mode)
-            }
-            ClipItem::BoxShadow(ref info) => {
-                rect_clips_only = false;
-
-                // For inset box shadows, we can clip out any
-                // pixels that are inside the shadow region
-                // and are beyond the inner rect, as they can't
-                // be affected by the blur radius.
-                let inner_clip_mode = match info.clip_mode {
-                    BoxShadowClipMode::Outset => None,
-                    BoxShadowClipMode::Inset => Some(ClipMode::ClipOut),
-                };
-
-                // Push a region into the segment builder where the
-                // box-shadow can have an effect on the result. This
-                // ensures clip-mask tasks get allocated for these
-                // pixel regions, even if no other clips affect them.
-                segment_builder.push_mask_region(
-                    info.prim_shadow_rect,
-                    info.prim_shadow_rect.inflate(
-                        -0.5 * info.shadow_rect_alloc_size.width,
-                        -0.5 * info.shadow_rect_alloc_size.height,
-                    ),
-                    inner_clip_mode,
-                );
-
-                continue;
-            }
-            ClipItem::Image(..) => {
-                rect_clips_only = false;
-                continue;
-            }
-        };
-
-        segment_builder.push_clip_rect(local_clip_rect, radius, mode);
-    }
-
-    if is_large || rect_clips_only {
-        // If there were no local clips, then we will subdivide the primitive into
-        // a uniform grid (up to 8x8 segments). This will typically result in
-        // a significant number of those segments either being completely clipped,
-        // or determined to not need a clip mask for that segment.
-        if local_clip_count == 0 && clip_chain.clips_range.count > 0 {
-            let x_clip_count = cmp::min(8, (metadata.local_rect.size.width / 128.0).ceil() as i32);
-            let y_clip_count = cmp::min(8, (metadata.local_rect.size.height / 128.0).ceil() as i32);
-
-            for y in 0 .. y_clip_count {
-                let y0 = metadata.local_rect.size.height * y as f32 / y_clip_count as f32;
-                let y1 = metadata.local_rect.size.height * (y+1) as f32 / y_clip_count as f32;
-
-                for x in 0 .. x_clip_count {
-                    let x0 = metadata.local_rect.size.width * x as f32 / x_clip_count as f32;
-                    let x1 = metadata.local_rect.size.width * (x+1) as f32 / x_clip_count as f32;
-
-                    let rect = LayoutRect::new(
-                        LayoutPoint::new(
-                            x0 + metadata.local_rect.origin.x,
-                            y0 + metadata.local_rect.origin.y,
-                        ),
-                        LayoutSize::new(
-                            x1 - x0,
-                            y1 - y0,
-                        ),
-                    );
-
-                    segment_builder.push_mask_region(rect, LayoutRect::zero(), None);
+            None => {
+                // If no segment descriptor built yet, see if it is a brush
+                // type that wants to be segmented.
+                if !self.kind.supports_segments(frame_state.resource_cache) {
+                    return;
                 }
             }
         }
 
-        match brush.segment_desc {
-            Some(..) => panic!("bug: should not already have descriptor"),
-            None => {
-                // TODO(gw): We can probably make the allocation
-                //           patterns of this and the segment
-                //           builder significantly better, by
-                //           retaining it across primitives.
-                let mut segments = BrushSegmentVec::new();
-
-                segment_builder.build(|segment| {
-                    segments.push(
-                        BrushSegment::new(
-                            segment.rect,
-                            segment.has_mask,
-                            segment.edge_flags,
-                            [0.0; 4],
-                            BrushFlags::empty(),
+        // If the brush is small, we generally want to skip building segments
+        // and just draw it as a single primitive with clip mask. However,
+        // if the clips are purely rectangles that have no per-fragment
+        // clip masks, we will segment anyway. This allows us to completely
+        // skip allocating a clip mask in these cases.
+        let is_large = prim_local_rect.size.area() > MIN_BRUSH_SPLIT_AREA;
+
+        // TODO(gw): We should probably detect and store this on each
+        //           ClipSources instance, to avoid having to iterate
+        //           the clip sources here.
+        let mut rect_clips_only = true;
+
+        let segment_builder = &mut frame_state.segment_builder;
+        segment_builder.initialize(
+            prim_local_rect,
+            None,
+            prim_local_clip_rect
+        );
+
+        // Segment the primitive on all the local-space clip sources that we can.
+        let mut local_clip_count = 0;
+        for i in 0 .. clip_chain.clips_range.count {
+            let clip_instance = frame_state
+                .clip_store
+                .get_instance_from_range(&clip_chain.clips_range, i);
+            let clip_node = &frame_state.resources.clip_data_store[clip_instance.handle];
+
+            // If this clip item is positioned by another positioning node, its relative position
+            // could change during scrolling. This means that we would need to resegment. Instead
+            // of doing that, only segment with clips that have the same positioning node.
+            // TODO(mrobinson, #2858): It may make sense to include these nodes, resegmenting only
+            // when necessary while scrolling.
+            if !clip_instance.flags.contains(ClipNodeFlags::SAME_SPATIAL_NODE) {
+                continue;
+            }
+
+            local_clip_count += 1;
+
+            let (local_clip_rect, radius, mode) = match clip_node.item {
+                ClipItem::RoundedRectangle(rect, radii, clip_mode) => {
+                    rect_clips_only = false;
+                    (rect, Some(radii), clip_mode)
+                }
+                ClipItem::Rectangle(rect, mode) => {
+                    (rect, None, mode)
+                }
+                ClipItem::BoxShadow(ref info) => {
+                    rect_clips_only = false;
+
+                    // For inset box shadows, we can clip out any
+                    // pixels that are inside the shadow region
+                    // and are beyond the inner rect, as they can't
+                    // be affected by the blur radius.
+                    let inner_clip_mode = match info.clip_mode {
+                        BoxShadowClipMode::Outset => None,
+                        BoxShadowClipMode::Inset => Some(ClipMode::ClipOut),
+                    };
+
+                    // Push a region into the segment builder where the
+                    // box-shadow can have an effect on the result. This
+                    // ensures clip-mask tasks get allocated for these
+                    // pixel regions, even if no other clips affect them.
+                    segment_builder.push_mask_region(
+                        info.prim_shadow_rect,
+                        info.prim_shadow_rect.inflate(
+                            -0.5 * info.shadow_rect_alloc_size.width,
+                            -0.5 * info.shadow_rect_alloc_size.height,
                         ),
+                        inner_clip_mode,
                     );
-                });
-
-                brush.segment_desc = Some(BrushSegmentDescriptor {
-                    segments,
-                });
+
+                    continue;
+                }
+                ClipItem::Image(..) => {
+                    rect_clips_only = false;
+                    continue;
+                }
+            };
+
+            segment_builder.push_clip_rect(local_clip_rect, radius, mode);
+        }
+
+        if is_large || rect_clips_only {
+            // If there were no local clips, then we will subdivide the primitive into
+            // a uniform grid (up to 8x8 segments). This will typically result in
+            // a significant number of those segments either being completely clipped,
+            // or determined to not need a clip mask for that segment.
+            if local_clip_count == 0 && clip_chain.clips_range.count > 0 {
+                let x_clip_count = cmp::min(8, (prim_local_rect.size.width / 128.0).ceil() as i32);
+                let y_clip_count = cmp::min(8, (prim_local_rect.size.height / 128.0).ceil() as i32);
+
+                for y in 0 .. y_clip_count {
+                    let y0 = prim_local_rect.size.height * y as f32 / y_clip_count as f32;
+                    let y1 = prim_local_rect.size.height * (y+1) as f32 / y_clip_count as f32;
+
+                    for x in 0 .. x_clip_count {
+                        let x0 = prim_local_rect.size.width * x as f32 / x_clip_count as f32;
+                        let x1 = prim_local_rect.size.width * (x+1) as f32 / x_clip_count as f32;
+
+                        let rect = LayoutRect::new(
+                            LayoutPoint::new(
+                                x0 + prim_local_rect.origin.x,
+                                y0 + prim_local_rect.origin.y,
+                            ),
+                            LayoutSize::new(
+                                x1 - x0,
+                                y1 - y0,
+                            ),
+                        );
+
+                        segment_builder.push_mask_region(rect, LayoutRect::zero(), None);
+                    }
+                }
+            }
+
+            match self.segment_desc {
+                Some(..) => panic!("bug: should not already have descriptor"),
+                None => {
+                    // TODO(gw): We can probably make the allocation
+                    //           patterns of this and the segment
+                    //           builder significantly better, by
+                    //           retaining it across primitives.
+                    let mut segments = BrushSegmentVec::new();
+
+                    segment_builder.build(|segment| {
+                        segments.push(
+                            BrushSegment::new(
+                                segment.rect,
+                                segment.has_mask,
+                                segment.edge_flags,
+                                [0.0; 4],
+                                BrushFlags::empty(),
+                            ),
+                        );
+                    });
+
+                    self.segment_desc = Some(BrushSegmentDescriptor {
+                        segments,
+                    });
+                }
             }
         }
     }
 }
 
 impl Primitive {
     fn update_clip_task_for_brush(
         &mut self,
@@ -2397,19 +2367,19 @@ impl Primitive {
         frame_state: &mut FrameBuildingState,
         clip_node_collector: &Option<ClipNodeCollector>,
     ) -> bool {
         let brush = match self.details {
             PrimitiveDetails::Brush(ref mut brush) => brush,
             PrimitiveDetails::TextRun(..) => return false,
         };
 
-        write_brush_segment_description(
-            brush,
-            &self.metadata,
+        brush.write_brush_segment_description(
+            self.local_rect,
+            self.local_clip_rect,
             prim_clip_chain,
             frame_state,
         );
 
         let segment_desc = match brush.segment_desc {
             Some(ref mut description) => description,
             None => return false,
         };
@@ -2432,17 +2402,17 @@ impl Primitive {
                 // Build a clip chain for the smaller segment rect. This will
                 // often manage to eliminate most/all clips, and sometimes
                 // clip the segment completely.
                 let segment_clip_chain = frame_state
                     .clip_store
                     .build_clip_chain_instance(
                         prim_instance.clip_chain_id,
                         segment.local_rect,
-                        self.metadata.local_clip_rect,
+                        self.local_clip_rect,
                         prim_context.spatial_node_index,
                         &pic_state.map_local_to_pic,
                         &pic_state.map_pic_to_world,
                         &frame_context.clip_scroll_tree,
                         frame_state.gpu_cache,
                         frame_state.resource_cache,
                         frame_context.device_pixel_scale,
                         &frame_context.world_rect,
@@ -2462,49 +2432,43 @@ impl Primitive {
         }
 
         true
     }
 
     // Returns true if the primitive *might* need a clip mask. If
     // false, there is no need to even check for clip masks for
     // this primitive.
-    fn reset_clip_task(
-        &mut self,
-        prim_instance: &mut PrimitiveInstance,
-    ) -> bool {
+    fn reset_clip_task(&mut self, prim_instance: &mut PrimitiveInstance) {
         prim_instance.clip_task_id = None;
         match self.details {
             PrimitiveDetails::Brush(ref mut brush) => {
                 if let Some(ref mut desc) = brush.segment_desc {
                     for segment in &mut desc.segments {
                         segment.clip_task_id = BrushSegmentTaskId::Opaque;
                     }
                 }
-                brush.may_need_clip_mask()
             }
-            PrimitiveDetails::TextRun(..) => {
-                true
-            }
+            PrimitiveDetails::TextRun(..) => {}
         }
     }
 
     fn prepare_prim_for_render_inner(
         &mut self,
         prim_instance: &mut PrimitiveInstance,
         prim_context: &PrimitiveContext,
         pic_context: &PictureContext,
         pic_state: &mut PictureState,
+        pictures: &mut [PicturePrimitive],
         frame_context: &FrameBuildingContext,
         frame_state: &mut FrameBuildingState,
         display_list: &BuiltDisplayList,
         is_chased: bool,
     ) {
         let mut is_tiled = false;
-        let metadata = &mut self.metadata;
         #[cfg(debug_assertions)]
         {
             prim_instance.prepared_frame_id = frame_state.render_tasks.frame_id();
         }
 
         match self.details {
             PrimitiveDetails::TextRun(ref mut text) => {
                 // The transform only makes sense for screen space rasterization
@@ -2655,32 +2619,32 @@ impl Primitive {
                             if let Some(tile_size) = image_properties.tiling {
                                 let device_image_size = image_properties.descriptor.size;
 
                                 // Tighten the clip rect because decomposing the repeated image can
                                 // produce primitives that are partially covering the original image
                                 // rect and we want to clip these extra parts out.
                                 let tight_clip_rect = prim_instance
                                     .combined_local_clip_rect
-                                    .intersection(&metadata.local_rect).unwrap();
+                                    .intersection(&self.local_rect).unwrap();
 
                                 let visible_rect = compute_conservative_visible_rect(
                                     prim_context,
                                     &prim_instance.clipped_world_rect.unwrap(),
                                     &tight_clip_rect
                                 );
 
                                 let base_edge_flags = edge_flags_for_tile_spacing(tile_spacing);
 
                                 let stride = stretch_size + *tile_spacing;
 
                                 visible_tiles.clear();
 
                                 for_each_repetition(
-                                    &metadata.local_rect,
+                                    &self.local_rect,
                                     &visible_rect,
                                     &stride,
                                     &mut |origin, edge_flags| {
                                         let edge_flags = base_edge_flags | edge_flags;
 
                                         let image_rect = LayoutRect {
                                             origin: *origin,
                                             size: stretch_size,
@@ -2733,17 +2697,17 @@ impl Primitive {
                                 );
                             }
                         }
                     }
                     BrushKind::LineDecoration { ref mut handle, style, orientation, wavy_line_thickness, .. } => {
                         // Work out the device pixel size to be used to cache this line decoration.
 
                         let size = get_line_decoration_sizes(
-                            &metadata.local_rect.size,
+                            &self.local_rect.size,
                             orientation,
                             style,
                             wavy_line_thickness,
                         );
 
                         if let Some((inline_size, block_size)) = size {
                             let size = match orientation {
                                 LineOrientation::Horizontal => LayoutSize::new(inline_size, block_size),
@@ -2751,29 +2715,29 @@ impl Primitive {
                             };
 
                             // If dotted, adjust the clip rect to ensure we don't draw a final
                             // partial dot.
                             if style == LineStyle::Dotted {
                                 let clip_size = match orientation {
                                     LineOrientation::Horizontal => {
                                         LayoutSize::new(
-                                            inline_size * (metadata.local_rect.size.width / inline_size).floor(),
-                                            metadata.local_rect.size.height,
+                                            inline_size * (self.local_rect.size.width / inline_size).floor(),
+                                            self.local_rect.size.height,
                                         )
                                     }
                                     LineOrientation::Vertical => {
                                         LayoutSize::new(
-                                            metadata.local_rect.size.width,
-                                            inline_size * (metadata.local_rect.size.height / inline_size).floor(),
+                                            self.local_rect.size.width,
+                                            inline_size * (self.local_rect.size.height / inline_size).floor(),
                                         )
                                     }
                                 };
                                 let clip_rect = LayoutRect::new(
-                                    metadata.local_rect.origin,
+                                    self.local_rect.origin,
                                     clip_size,
                                 );
                                 prim_instance.combined_local_clip_rect = clip_rect
                                     .intersection(&prim_instance.combined_local_clip_rect)
                                     .unwrap_or(LayoutRect::zero());
                             }
 
                             // TODO(gw): Do we ever need / want to support scales for text decorations
@@ -2913,17 +2877,17 @@ impl Primitive {
                         );
 
                         if tile_spacing != LayoutSize::zero() {
                             is_tiled = true;
 
                             decompose_repeated_primitive(
                                 visible_tiles,
                                 prim_instance,
-                                metadata,
+                                &self.local_rect,
                                 &stretch_size,
                                 &tile_spacing,
                                 prim_context,
                                 frame_state,
                                 &mut |rect, mut request| {
                                     request.push([
                                         center.x,
                                         center.y,
@@ -2955,18 +2919,18 @@ impl Primitive {
                         ..
                     } => {
                         // If the coverage of the gradient extends to or beyond
                         // the primitive rect, then the opacity can be determined
                         // by the colors of the stops. If we have tiling / spacing
                         // then we just assume the gradient is translucent for now.
                         // (In the future we could consider segmenting in some cases).
                         let stride = stretch_size + tile_spacing;
-                        prim_instance.opacity = if stride.width >= metadata.local_rect.size.width &&
-                           stride.height >= metadata.local_rect.size.height {
+                        prim_instance.opacity = if stride.width >= self.local_rect.size.width &&
+                           stride.height >= self.local_rect.size.height {
                             stops_opacity
                         } else {
                             PrimitiveOpacity::translucent()
                         };
 
                         build_gradient_stops_request(
                             stops_handle,
                             stops_range,
@@ -2976,17 +2940,17 @@ impl Primitive {
                         );
 
                         if tile_spacing != LayoutSize::zero() {
                             is_tiled = true;
 
                             decompose_repeated_primitive(
                                 visible_tiles,
                                 prim_instance,
-                                metadata,
+                                &self.local_rect,
                                 &stretch_size,
                                 &tile_spacing,
                                 prim_context,
                                 frame_state,
                                 &mut |rect, mut request| {
                                     request.push([
                                         start_point.x,
                                         start_point.y,
@@ -2999,20 +2963,22 @@ impl Primitive {
                                         stretch_size.height,
                                         0.0,
                                     ]);
                                     request.write_segment(*rect, [0.0; 4]);
                                 }
                             );
                         }
                     }
-                    BrushKind::Picture(ref mut pic) => {
+                    BrushKind::Picture { pic_index, .. } => {
+                        let pic = &mut pictures[pic_index.0];
                         if !pic.prepare_for_render(
+                            pic_index,
                             prim_instance,
-                            metadata,
+                            &self.local_rect,
                             pic_state,
                             frame_context,
                             frame_state,
                         ) {
                             prim_instance.clipped_world_rect = None;
                         }
                     }
                     BrushKind::Solid { ref color, ref mut opacity_binding, .. } => {
@@ -3037,34 +3003,34 @@ impl Primitive {
 
         // Mark this GPU resource as required for this frame.
         if let Some(mut request) = frame_state.gpu_cache.request(&mut prim_instance.gpu_location) {
             match self.details {
                 PrimitiveDetails::TextRun(ref mut text) => {
                     text.write_gpu_blocks(&mut request);
                 }
                 PrimitiveDetails::Brush(ref mut brush) => {
-                    brush.write_gpu_blocks(&mut request, metadata.local_rect);
+                    brush.write_gpu_blocks(&mut request, self.local_rect);
 
                     match brush.segment_desc {
                         Some(ref segment_desc) => {
                             for segment in &segment_desc.segments {
                                 if cfg!(debug_assertions) && is_chased {
                                     println!("\t\t{:?}", segment);
                                 }
                                 // has to match VECS_PER_SEGMENT
                                 request.write_segment(
                                     segment.local_rect,
                                     segment.extra_data,
                                 );
                             }
                         }
                         None => {
                             request.write_segment(
-                                metadata.local_rect,
+                                self.local_rect,
                                 [0.0; 4],
                             );
                         }
                     }
                 }
             }
         }
     }
@@ -3081,20 +3047,17 @@ impl Primitive {
         frame_state: &mut FrameBuildingState,
         is_chased: bool,
         clip_node_collector: &Option<ClipNodeCollector>,
     ) {
         if cfg!(debug_assertions) && is_chased {
             println!("\tupdating clip task with pic rect {:?}", clip_chain.pic_clip_rect);
         }
         // Reset clips from previous frames since we may clip differently each frame.
-        // If this primitive never needs clip masks, just return straight away.
-        if !self.reset_clip_task(prim_instance) {
-            return;
-        }
+        self.reset_clip_task(prim_instance);
 
         // First try to  render this primitive's mask using optimized brush rendering.
         if self.update_clip_task_for_brush(
             prim_instance,
             root_spatial_node_index,
             prim_bounding_rect,
             prim_context,
             &clip_chain,
--- a/gfx/webrender/src/render_task.rs
+++ b/gfx/webrender/src/render_task.rs
@@ -17,17 +17,17 @@ use euclid::{TypedPoint2D, TypedVector2D
 use freelist::{FreeList, FreeListHandle, WeakFreeListHandle};
 use glyph_rasterizer::GpuGlyphCacheKey;
 use gpu_cache::{GpuCache, GpuCacheAddress, GpuCacheHandle};
 use gpu_types::{BorderInstance, ImageSource, UvRectKind};
 use internal_types::{CacheTextureId, FastHashMap, LayerIndex, SavedTargetIndex};
 #[cfg(feature = "pathfinder")]
 use pathfinder_partitioner::mesh::Mesh;
 use picture::PictureCacheKey;
-use prim_store::{PrimitiveIndex, ImageCacheKey, LineDecorationCacheKey};
+use prim_store::{PictureIndex, ImageCacheKey, LineDecorationCacheKey};
 #[cfg(feature = "debugger")]
 use print_tree::{PrintTreePrinter};
 use render_backend::FrameId;
 use resource_cache::{CacheItem, ResourceCache};
 use std::{cmp, ops, usize, f32, i32};
 use texture_cache::{TextureCache, TextureCacheHandle, Eviction};
 use tiling::{RenderPass, RenderTargetIndex};
 use tiling::{RenderTargetKind};
@@ -217,17 +217,17 @@ pub struct CacheMaskTask {
 pub struct ClipRegionTask {
     pub clip_data_address: GpuCacheAddress,
 }
 
 #[derive(Debug)]
 #[cfg_attr(feature = "capture", derive(Serialize))]
 #[cfg_attr(feature = "replay", derive(Deserialize))]
 pub struct PictureTask {
-    pub prim_index: PrimitiveIndex,
+    pub pic_index: PictureIndex,
     pub can_merge: bool,
     pub content_origin: DeviceIntPoint,
     pub uv_rect_handle: GpuCacheHandle,
     pub root_spatial_node_index: SpatialNodeIndex,
     uv_rect_kind: UvRectKind,
 }
 
 #[derive(Debug)]
@@ -379,17 +379,17 @@ impl RenderTask {
             clear_mode,
             saved_index: None,
         }
     }
 
     pub fn new_picture(
         location: RenderTaskLocation,
         unclipped_size: DeviceSize,
-        prim_index: PrimitiveIndex,
+        pic_index: PictureIndex,
         content_origin: DeviceIntPoint,
         children: Vec<RenderTaskId>,
         uv_rect_kind: UvRectKind,
         root_spatial_node_index: SpatialNodeIndex,
     ) -> Self {
         let size = match location {
             RenderTaskLocation::Dynamic(_, size) => size,
             RenderTaskLocation::Fixed(rect) => rect.size,
@@ -400,17 +400,17 @@ impl RenderTask {
 
         let can_merge = size.width as f32 >= unclipped_size.width &&
                         size.height as f32 >= unclipped_size.height;
 
         RenderTask {
             location,
             children,
             kind: RenderTaskKind::Picture(PictureTask {
-                prim_index,
+                pic_index,
                 content_origin,
                 can_merge,
                 uv_rect_handle: GpuCacheHandle::new(),
                 uv_rect_kind,
                 root_spatial_node_index,
             }),
             clear_mode: ClearMode::Transparent,
             saved_index: None,
@@ -987,17 +987,17 @@ impl RenderTask {
             image_source.write_gpu_blocks(&mut request);
         }
     }
 
     #[cfg(feature = "debugger")]
     pub fn print_with<T: PrintTreePrinter>(&self, pt: &mut T, tree: &RenderTaskTree) -> bool {
         match self.kind {
             RenderTaskKind::Picture(ref task) => {
-                pt.new_level(format!("Picture of {:?}", task.prim_index));
+                pt.new_level(format!("Picture of {:?}", task.pic_index));
             }
             RenderTaskKind::CacheMask(ref task) => {
                 pt.new_level(format!("CacheMask with {} clips", task.clip_node_range.count));
                 pt.add_item(format!("rect: {:?}", task.actual_rect));
             }
             RenderTaskKind::LineDecoration(..) => {
                 pt.new_level("LineDecoration".to_owned());
             }
--- a/gfx/webrender/src/tiling.rs
+++ b/gfx/webrender/src/tiling.rs
@@ -402,17 +402,17 @@ impl RenderTarget for ColorRenderTarget 
     ) {
         let mut merged_batches = AlphaBatchContainer::new(None);
 
         for task_id in &self.alpha_tasks {
             let task = &render_tasks[*task_id];
 
             match task.kind {
                 RenderTaskKind::Picture(ref pic_task) => {
-                    let pic = ctx.prim_store.get_pic(pic_task.prim_index);
+                    let pic = &ctx.prim_store.pictures[pic_task.pic_index.0];
 
                     let (target_rect, _) = task.get_target_rect();
 
                     let mut batch_builder = AlphaBatchBuilder::new(
                         self.screen_size,
                         target_rect,
                         pic_task.can_merge,
                     );
@@ -467,17 +467,17 @@ impl RenderTarget for ColorRenderTarget 
                 info.add_instances(
                     &mut self.horizontal_blurs,
                     BlurDirection::Horizontal,
                     render_tasks.get_task_address(task_id),
                     render_tasks.get_task_address(task.children[0]),
                 );
             }
             RenderTaskKind::Picture(ref task_info) => {
-                let pic = ctx.prim_store.get_pic(task_info.prim_index);
+                let pic = &ctx.prim_store.pictures[task_info.pic_index.0];
                 self.alpha_tasks.push(task_id);
 
                 // If this pipeline is registered as a frame output
                 // store the information necessary to do the copy.
                 if let Some(pipeline_id) = pic.frame_output_pipeline_id {
                     self.outputs.push(FrameOutput {
                         pipeline_id,
                         task_id,
--- a/gfx/webrender_bindings/revision.txt
+++ b/gfx/webrender_bindings/revision.txt
@@ -1,1 +1,1 @@
-c72754d72ddd0e9e198bb1edefe13f77d9a38f07
+15656cb497303703b4d541d3e14292259e4c5343