Bug 1510222 - Update webrender to commit ea8f4a922b2aa38c40de137d7f0ab6598d53e29a (WR PR #3353). r=kats
authorWR Updater Bot <graphics-team@mozilla.staktrace.com>
Tue, 27 Nov 2018 12:15:46 +0000
changeset 507465 c779bf180e26500b0a907c55f992be2121fc4ee9
parent 507464 c19baae766e96ffbc7bf20534e1ba62b64871fe3
child 507466 2fd8827b99434692acfb05a0c5b82649936eb124
push id1905
push userffxbld-merge
push dateMon, 21 Jan 2019 12:33:13 +0000
treeherdermozilla-release@c2fca1944d8c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerskats
bugs1510222
milestone65.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1510222 - Update webrender to commit ea8f4a922b2aa38c40de137d7f0ab6598d53e29a (WR PR #3353). r=kats https://github.com/servo/webrender/pull/3353 Differential Revision: https://phabricator.services.mozilla.com/D13057
gfx/webrender_bindings/revision.txt
gfx/wr/webrender/src/batch.rs
gfx/wr/webrender/src/border.rs
gfx/wr/webrender/src/box_shadow.rs
gfx/wr/webrender/src/display_list_flattener.rs
gfx/wr/webrender/src/frame_builder.rs
gfx/wr/webrender/src/picture.rs
gfx/wr/webrender/src/prim_store.rs
gfx/wr/webrender/src/render_backend.rs
gfx/wr/webrender/src/surface.rs
gfx/wr/webrender_api/src/display_item.rs
gfx/wr/wrench/reftests/gradient/premultiplied-radial-2.png
--- a/gfx/webrender_bindings/revision.txt
+++ b/gfx/webrender_bindings/revision.txt
@@ -1,1 +1,1 @@
-604c69a40920e34bb1b8fa3f02bca6e5edfe73f4
+ea8f4a922b2aa38c40de137d7f0ab6598d53e29a
--- a/gfx/wr/webrender/src/batch.rs
+++ b/gfx/wr/webrender/src/batch.rs
@@ -10,20 +10,20 @@ use clip_scroll_tree::{ClipScrollTree, R
 use glyph_rasterizer::GlyphFormat;
 use gpu_cache::{GpuCache, GpuCacheHandle, GpuCacheAddress};
 use gpu_types::{BrushFlags, BrushInstance, PrimitiveHeaders, ZBufferId, ZBufferIdGenerator};
 use gpu_types::{ClipMaskInstance, SplitCompositeInstance};
 use gpu_types::{PrimitiveInstanceData, RasterizationSpace, GlyphInstance};
 use gpu_types::{PrimitiveHeader, PrimitiveHeaderIndex, TransformPaletteId, TransformPalette};
 use internal_types::{FastHashMap, SavedTargetIndex, TextureSource};
 use picture::{Picture3DContext, PictureCompositeMode, PicturePrimitive, PictureSurface};
-use prim_store::{BrushKind, BrushPrimitive, DeferredResolve, PrimitiveTemplateKind, PrimitiveDataStore};
+use prim_store::{DeferredResolve, PrimitiveTemplateKind, PrimitiveDataStore};
 use prim_store::{EdgeAaSegmentMask, ImageSource, PrimitiveInstanceKind};
 use prim_store::{VisibleGradientTile, PrimitiveInstance, PrimitiveOpacity, SegmentInstanceIndex};
-use prim_store::{BrushSegment, ClipMaskKind, ClipTaskIndex, PrimitiveDetails};
+use prim_store::{BrushSegment, ClipMaskKind, ClipTaskIndex};
 use render_task::{RenderTaskAddress, RenderTaskId, RenderTaskTree};
 use renderer::{BlendMode, ImageBufferKind, ShaderColorMode};
 use renderer::BLOCKS_PER_UV_RECT;
 use resource_cache::{CacheItem, GlyphFetchResult, ImageRequest, ResourceCache, ImageProperties};
 use scene::FilterOpHelpers;
 use smallvec::SmallVec;
 use std::{f32, i32, usize};
 use tiling::{RenderTargetContext};
@@ -897,23 +897,23 @@ impl AlphaBatchBuilder {
                     // Convert all children of the 3D hierarchy root into batches.
                     Picture3DContext::In { root_data: Some(ref list), .. } => {
                         for child in list {
                             let prim_instance = &picture.prim_list.prim_instances[child.anchor];
                             let pic_index = match prim_instance.kind {
                                 PrimitiveInstanceKind::Picture { pic_index } => pic_index,
                                 PrimitiveInstanceKind::LineDecoration { .. } |
                                 PrimitiveInstanceKind::TextRun { .. } |
-                                PrimitiveInstanceKind::LegacyPrimitive { .. } |
                                 PrimitiveInstanceKind::NormalBorder { .. } |
                                 PrimitiveInstanceKind::ImageBorder { .. } |
                                 PrimitiveInstanceKind::Rectangle { .. } |
                                 PrimitiveInstanceKind::YuvImage { .. } |
                                 PrimitiveInstanceKind::Image { .. } |
                                 PrimitiveInstanceKind::LinearGradient { .. } |
+                                PrimitiveInstanceKind::RadialGradient { .. } |
                                 PrimitiveInstanceKind::Clear => {
                                     unreachable!();
                                 }
                             };
                             let pic = &ctx.prim_store.pictures[pic_index.0];
 
                             // Get clip task, if set, for the picture primitive.
                             let clip_task_address = get_clip_task_address(
@@ -1396,114 +1396,16 @@ impl AlphaBatchBuilder {
                             transforms,
                             root_spatial_node_index,
                             z_generator,
                         );
                     }
                 }
             }
             (
-                PrimitiveInstanceKind::LegacyPrimitive { prim_index },
-                PrimitiveTemplateKind::Unused,
-            ) => {
-                let prim = &ctx.prim_store.primitives[prim_index.0];
-
-                // If the primitive is internally decomposed into multiple sub-primitives we may not
-                // 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::RadialGradient { visible_tiles_range, .. } => !visible_tiles_range.is_empty(),
-                        }
-                    }
-                };
-
-                let specified_blend_mode = BlendMode::PremultipliedAlpha;
-
-                match prim.details {
-                    PrimitiveDetails::Brush(ref brush) => {
-                        let non_segmented_blend_mode = if !brush.opacity.is_opaque ||
-                            prim_instance.clip_task_index != ClipTaskIndex::INVALID ||
-                            transform_kind == TransformedRectKind::Complex
-                        {
-                            specified_blend_mode
-                        } else {
-                            BlendMode::None
-                        };
-
-                        let prim_cache_address = if is_multiple_primitives {
-                            GpuCacheAddress::invalid()
-                        } else {
-                            gpu_cache.get_address(&brush.gpu_location)
-                        };
-
-                        let prim_header = PrimitiveHeader {
-                            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 prim_instance.is_chased() {
-                            println!("\ttask target {:?}", self.target_rect);
-                            println!("\t{:?}", prim_header);
-                        }
-
-                        match brush.kind {
-                            BrushKind::RadialGradient { ref stops_handle, visible_tiles_range, .. } if !visible_tiles_range.is_empty() => {
-                                let visible_tiles = &ctx.scratch.gradient_tiles[visible_tiles_range];
-
-                                add_gradient_tiles(
-                                    visible_tiles,
-                                    stops_handle,
-                                    BrushBatchKind::RadialGradient,
-                                    specified_blend_mode,
-                                    bounding_rect,
-                                    clip_task_address,
-                                    gpu_cache,
-                                    &mut self.batch_list,
-                                    &prim_header,
-                                    prim_headers,
-                                    z_id,
-                                );
-                            }
-                            _ => {
-                                if let Some(params) = brush.get_batch_params(
-                                    gpu_cache,
-                                ) {
-                                    let prim_header_index = prim_headers.push(&prim_header, z_id, params.prim_user_data);
-                                    if prim_instance.is_chased() {
-                                        println!("\t{:?} {:?}, task relative bounds {:?}",
-                                            params.batch_kind, prim_header_index, bounding_rect);
-                                    }
-
-                                    self.add_segmented_prim_to_batch(
-                                        brush.segment_desc.as_ref().map(|desc| desc.segments.as_slice()),
-                                        brush.opacity,
-                                        &params,
-                                        specified_blend_mode,
-                                        non_segmented_blend_mode,
-                                        prim_header_index,
-                                        clip_task_address,
-                                        bounding_rect,
-                                        transform_kind,
-                                        render_tasks,
-                                        z_id,
-                                        prim_instance.clip_task_index,
-                                        ctx,
-                                    );
-                                }
-                            }
-                        }
-                    }
-                }
-            }
-            (
                 PrimitiveInstanceKind::ImageBorder { .. },
                 PrimitiveTemplateKind::ImageBorder { request, brush_segments, .. }
             ) => {
                 let cache_item = resolve_image(
                     *request,
                     ctx.resource_cache,
                     gpu_cache,
                     deferred_resolves,
@@ -1959,16 +1861,99 @@ impl AlphaBatchBuilder {
                         gpu_cache,
                         &mut self.batch_list,
                         &prim_header,
                         prim_headers,
                         z_id,
                     );
                 }
             }
+            (
+                PrimitiveInstanceKind::RadialGradient { visible_tiles_range, .. },
+                PrimitiveTemplateKind::RadialGradient { stops_handle, ref brush_segments, .. }
+            ) => {
+                let specified_blend_mode = BlendMode::PremultipliedAlpha;
+
+                let mut prim_header = PrimitiveHeader {
+                    local_rect: prim_data.prim_rect,
+                    local_clip_rect: prim_instance.combined_local_clip_rect,
+                    task_address,
+                    specific_prim_address: GpuCacheAddress::invalid(),
+                    clip_task_address,
+                    transform_id,
+                };
+
+                if visible_tiles_range.is_empty() {
+                    let non_segmented_blend_mode = if !prim_data.opacity.is_opaque ||
+                        prim_instance.clip_task_index != ClipTaskIndex::INVALID ||
+                        transform_kind == TransformedRectKind::Complex
+                    {
+                        specified_blend_mode
+                    } else {
+                        BlendMode::None
+                    };
+
+                    let batch_params = BrushBatchParameters::shared(
+                        BrushBatchKind::RadialGradient,
+                        BatchTextures::no_texture(),
+                        [
+                            stops_handle.as_int(gpu_cache),
+                            0,
+                            0,
+                        ],
+                        0,
+                    );
+
+                    prim_header.specific_prim_address = gpu_cache.get_address(&prim_data.gpu_cache_handle);
+
+                    let prim_header_index = prim_headers.push(
+                        &prim_header,
+                        z_id,
+                        batch_params.prim_user_data,
+                    );
+
+                    let segments = if brush_segments.is_empty() {
+                        None
+                    } else {
+                        Some(brush_segments.as_slice())
+                    };
+
+                    self.add_segmented_prim_to_batch(
+                        segments,
+                        prim_data.opacity,
+                        &batch_params,
+                        specified_blend_mode,
+                        non_segmented_blend_mode,
+                        prim_header_index,
+                        clip_task_address,
+                        bounding_rect,
+                        transform_kind,
+                        render_tasks,
+                        z_id,
+                        prim_instance.clip_task_index,
+                        ctx,
+                    );
+                } else {
+                    let visible_tiles = &ctx.scratch.gradient_tiles[*visible_tiles_range];
+
+                    add_gradient_tiles(
+                        visible_tiles,
+                        stops_handle,
+                        BrushBatchKind::RadialGradient,
+                        specified_blend_mode,
+                        bounding_rect,
+                        clip_task_address,
+                        gpu_cache,
+                        &mut self.batch_list,
+                        &prim_header,
+                        prim_headers,
+                        z_id,
+                    );
+                }
+            }
             _ => {
                 unreachable!();
             }
         }
     }
 
     fn add_image_tile_to_batch(
         &mut self,
@@ -2290,38 +2275,16 @@ impl BrushBatchParameters {
                     textures,
                     user_data: segment_user_data,
                 }
             ),
         }
     }
 }
 
-impl BrushPrimitive {
-    fn get_batch_params(
-        &self,
-        gpu_cache: &mut GpuCache,
-    ) -> Option<BrushBatchParameters> {
-        match self.kind {
-            BrushKind::RadialGradient { ref stops_handle, .. } => {
-                Some(BrushBatchParameters::shared(
-                    BrushBatchKind::RadialGradient,
-                    BatchTextures::no_texture(),
-                    [
-                        stops_handle.as_int(gpu_cache),
-                        0,
-                        0,
-                    ],
-                    0,
-                ))
-            }
-        }
-    }
-}
-
 impl PrimitiveInstance {
     pub fn is_cacheable(
         &self,
         prim_data_store: &PrimitiveDataStore,
         resource_cache: &ResourceCache,
     ) -> bool {
         let image_key = match self.kind {
             PrimitiveInstanceKind::Image { .. } |
@@ -2332,24 +2295,24 @@ impl PrimitiveInstance {
                         yuv_key[0]
                     }
                     PrimitiveTemplateKind::Image { key, .. } => {
                         key
                     }
                     _ => unreachable!(),
                 }
             }
-            PrimitiveInstanceKind::LegacyPrimitive { .. } |
             PrimitiveInstanceKind::Picture { .. } |
             PrimitiveInstanceKind::TextRun { .. } |
             PrimitiveInstanceKind::LineDecoration { .. } |
             PrimitiveInstanceKind::NormalBorder { .. } |
             PrimitiveInstanceKind::ImageBorder { .. } |
             PrimitiveInstanceKind::Rectangle { .. } |
             PrimitiveInstanceKind::LinearGradient { .. } |
+            PrimitiveInstanceKind::RadialGradient { .. } |
             PrimitiveInstanceKind::Clear => {
                 return true;
             }
         };
         match resource_cache.get_image_properties(image_key) {
             Some(ImageProperties { external_image: Some(_), .. }) => {
                 false
             }
--- a/gfx/wr/webrender/src/border.rs
+++ b/gfx/wr/webrender/src/border.rs
@@ -6,17 +6,17 @@ use api::{BorderRadius, BorderSide, Bord
 use api::{LayoutSideOffsets, LayoutSizeAu, LayoutPrimitiveInfo, LayoutToDeviceScale};
 use api::{DeviceVector2D, DevicePoint, LayoutRect, LayoutSize, NormalBorder, DeviceIntSize};
 use api::{AuHelpers, LayoutPoint, RepeatMode, TexelRect};
 use ellipse::Ellipse;
 use euclid::vec2;
 use display_list_flattener::DisplayListFlattener;
 use gpu_types::{BorderInstance, BorderSegment, BrushFlags};
 use prim_store::{BorderSegmentInfo, BrushSegment, NinePatchDescriptor};
-use prim_store::{EdgeAaSegmentMask, PrimitiveContainer, ScrollNodeAndClipChain};
+use prim_store::{EdgeAaSegmentMask, ScrollNodeAndClipChain, PrimitiveKeyKind};
 use util::{lerp, RectHelpers};
 
 // Using 2048 as the maximum radius in device space before which we
 // start stretching is up for debate.
 // the value must be chosen so that the corners will not use an
 // unreasonable amount of memory but should allow crisp corners in the
 // common cases.
 
@@ -112,16 +112,28 @@ pub struct NormalBorderAu {
     pub radius: BorderRadiusAu,
     /// Whether to apply anti-aliasing on the border corners.
     ///
     /// Note that for this to be `false` and work, this requires the borders to
     /// be solid, and no border-radius.
     pub do_aa: bool,
 }
 
+impl NormalBorderAu {
+    // Construct a border based upon self with color
+    pub fn with_color(&self, color: ColorU) -> Self {
+        let mut b = self.clone();
+        b.left.color = color;
+        b.right.color = color;
+        b.top.color = color;
+        b.bottom.color = color;
+        b
+    }
+}
+
 impl From<NormalBorder> for NormalBorderAu {
     fn from(border: NormalBorder) -> Self {
         NormalBorderAu {
             left: border.left.into(),
             right: border.right.into(),
             top: border.top.into(),
             bottom: border.bottom.into(),
             radius: border.radius.into(),
@@ -212,19 +224,19 @@ impl<'a> DisplayListFlattener<'a> {
     ) {
         let mut border = *border;
         ensure_no_corner_overlap(&mut border.radius, &info.rect);
 
         self.add_primitive(
             clip_and_scroll,
             info,
             Vec::new(),
-            PrimitiveContainer::NormalBorder {
-                border,
-                widths,
+            PrimitiveKeyKind::NormalBorder {
+                border: border.into(),
+                widths: widths.to_au(),
             },
         );
     }
 }
 
 pub trait BorderSideHelpers {
     fn border_color(&self, is_inner_border: bool) -> ColorF;
 }
--- a/gfx/wr/webrender/src/box_shadow.rs
+++ b/gfx/wr/webrender/src/box_shadow.rs
@@ -3,18 +3,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 use api::{BorderRadius, BoxShadowClipMode, ClipMode, ColorF, DeviceIntSize, LayoutPrimitiveInfo};
 use api::{LayoutRect, LayoutSize, LayoutVector2D, MAX_BLUR_RADIUS};
 use clip::ClipItemKey;
 use display_list_flattener::DisplayListFlattener;
 use gpu_cache::GpuCacheHandle;
 use gpu_types::BoxShadowStretchMode;
-use prim_store::PrimitiveContainer;
-use prim_store::ScrollNodeAndClipChain;
+use prim_store::{ScrollNodeAndClipChain, PrimitiveKeyKind};
 use render_task::RenderTaskCacheEntryHandle;
 use util::RectHelpers;
 
 #[derive(Debug, Clone)]
 #[cfg_attr(feature = "capture", derive(Serialize))]
 #[cfg_attr(feature = "replay", derive(Deserialize))]
 pub struct BoxShadowClipSource {
     // Parameters that define the shadow and are constant.
@@ -68,17 +67,17 @@ pub struct BoxShadowCacheKey {
 }
 
 impl<'a> DisplayListFlattener<'a> {
     pub fn add_box_shadow(
         &mut self,
         clip_and_scroll: ScrollNodeAndClipChain,
         prim_info: &LayoutPrimitiveInfo,
         box_offset: &LayoutVector2D,
-        color: &ColorF,
+        color: ColorF,
         mut blur_radius: f32,
         spread_radius: f32,
         border_radius: BorderRadius,
         clip_mode: BoxShadowClipMode,
     ) {
         if color.a == 0.0 {
             return;
         }
@@ -144,18 +143,18 @@ impl<'a> DisplayListFlattener<'a> {
                 clip_radius,
                 ClipMode::Clip,
             ));
 
             self.add_primitive(
                 clip_and_scroll,
                 &LayoutPrimitiveInfo::with_clip_rect(final_prim_rect, prim_info.clip_rect),
                 clips,
-                PrimitiveContainer::Rectangle {
-                    color: *color,
+                PrimitiveKeyKind::Rectangle {
+                    color: color.into(),
                 },
             );
         } else {
             // Normal path for box-shadows with a valid blur radius.
             let blur_offset = BLUR_SAMPLE_SCALE * blur_radius;
             let mut extra_clips = vec![];
 
             // Add a normal clip mask to clip out the contents
@@ -167,18 +166,18 @@ impl<'a> DisplayListFlattener<'a> {
             ));
 
             // Get the local rect of where the shadow will be drawn,
             // expanded to include room for the blurred region.
             let dest_rect = shadow_rect.inflate(blur_offset, blur_offset);
 
             // Draw the box-shadow as a solid rect, using a box-shadow
             // clip mask item.
-            let prim = PrimitiveContainer::Rectangle {
-                color: *color,
+            let prim = PrimitiveKeyKind::Rectangle {
+                color: color.into(),
             };
 
             // Create the box-shadow clip item.
             let shadow_clip_source = ClipItemKey::box_shadow(
                 shadow_rect,
                 shadow_radius,
                 dest_rect,
                 blur_radius,
--- a/gfx/wr/webrender/src/display_list_flattener.rs
+++ b/gfx/wr/webrender/src/display_list_flattener.rs
@@ -1,41 +1,40 @@
 
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 use api::{AlphaType, BorderDetails, BorderDisplayItem, BuiltDisplayListIter, ClipAndScrollInfo};
 use api::{ClipId, ColorF, ComplexClipRegion, DeviceIntPoint, DeviceIntRect, DeviceIntSize};
-use api::{DisplayItemRef, ExtendMode, ExternalScrollId};
+use api::{DisplayItemRef, ExtendMode, ExternalScrollId, AuHelpers};
 use api::{FilterOp, FontInstanceKey, GlyphInstance, GlyphOptions, RasterSpace, GradientStop};
 use api::{IframeDisplayItem, ImageKey, ImageRendering, ItemRange, LayoutPoint, ColorDepth};
 use api::{LayoutPrimitiveInfo, LayoutRect, LayoutSize, LayoutTransform, LayoutVector2D};
 use api::{LineOrientation, LineStyle, NinePatchBorderSource, PipelineId};
 use api::{PropertyBinding, ReferenceFrame, ScrollFrameDisplayItem, ScrollSensitivity};
 use api::{Shadow, SpecificDisplayItem, StackingContext, StickyFrameDisplayItem, TexelRect};
 use api::{ClipMode, TransformStyle, YuvColorSpace, YuvData};
+use app_units::Au;
 use clip::{ClipChainId, ClipRegion, ClipItemKey, ClipStore, ClipItemSceneData};
 use clip_scroll_tree::{ROOT_SPATIAL_NODE_INDEX, ClipScrollTree, SpatialNodeIndex};
 use frame_builder::{ChasePrimitive, FrameBuilder, FrameBuilderConfig};
 use glyph_rasterizer::FontInstance;
-use gpu_cache::GpuCacheHandle;
 use hit_test::{HitTestingItem, HitTestingRun};
 use image::simplify_repeated_primitive;
 use internal_types::{FastHashMap, FastHashSet};
 use picture::{Picture3DContext, PictureCompositeMode, PicturePrimitive, PrimitiveList};
-use prim_store::{BrushKind, BrushPrimitive, PrimitiveInstance, PrimitiveDataInterner, PrimitiveKeyKind};
+use prim_store::{PrimitiveInstance, PrimitiveDataInterner, PrimitiveKeyKind, RadialGradientParams};
 use prim_store::{PrimitiveKey, PrimitiveSceneData, PrimitiveInstanceKind, GradientStopKey, NinePatchDescriptor};
-use prim_store::{PrimitiveContainer, PrimitiveDataHandle, PrimitiveStore, PrimitiveStoreStats, BrushSegmentDescriptor};
-use prim_store::{ScrollNodeAndClipChain, PictureIndex, register_prim_chase_id, GradientTileRange};
+use prim_store::{PrimitiveDataHandle, PrimitiveStore, PrimitiveStoreStats, LineDecorationCacheKey};
+use prim_store::{ScrollNodeAndClipChain, PictureIndex, register_prim_chase_id, get_line_decoration_sizes};
 use render_backend::{DocumentView};
 use resource_cache::{FontInstanceMap, ImageRequest};
 use scene::{Scene, ScenePipeline, StackingContextHelpers};
 use scene_builder::DocumentResources;
-use smallvec::SmallVec;
 use spatial_node::{StickyFrameInfo};
 use std::{f32, mem};
 use std::collections::vec_deque::VecDeque;
 use tiling::{CompositeOps};
 use util::{MaxRect};
 
 #[derive(Debug, Copy, Clone)]
 struct ClipNode {
@@ -570,66 +569,72 @@ impl<'a> DisplayListFlattener<'a> {
                 );
             }
             SpecificDisplayItem::Line(ref info) => {
                 self.add_line(
                     clip_and_scroll,
                     &prim_info,
                     info.wavy_line_thickness,
                     info.orientation,
-                    &info.color,
+                    info.color,
                     info.style,
                 );
             }
             SpecificDisplayItem::Gradient(ref info) => {
-                if let Some(prim) = self.create_linear_gradient_prim(
+                if let Some(prim_key_kind) = self.create_linear_gradient_prim(
                     &prim_info,
                     info.gradient.start_point,
                     info.gradient.end_point,
                     item.gradient_stops(),
                     info.gradient.extend_mode,
                     info.tile_size,
                     info.tile_spacing,
                     pipeline_id,
                     None,
                 ) {
                     self.add_primitive(
                         clip_and_scroll,
                         &prim_info,
                         Vec::new(),
-                        prim,
+                        prim_key_kind,
                     );
                 }
             }
             SpecificDisplayItem::RadialGradient(ref info) => {
-                let brush_kind = self.create_brush_kind_for_radial_gradient(
+                let prim_key_kind = self.create_radial_gradient_prim(
                     &prim_info,
                     info.gradient.center,
                     info.gradient.start_offset * info.gradient.radius.width,
                     info.gradient.end_offset * info.gradient.radius.width,
                     info.gradient.radius.width / info.gradient.radius.height,
                     item.gradient_stops(),
                     info.gradient.extend_mode,
                     info.tile_size,
                     info.tile_spacing,
+                    pipeline_id,
+                    None,
                 );
-                let prim = PrimitiveContainer::Brush(BrushPrimitive::new(brush_kind, None));
-                self.add_primitive(clip_and_scroll, &prim_info, Vec::new(), prim);
+                self.add_primitive(
+                    clip_and_scroll,
+                    &prim_info,
+                    Vec::new(),
+                    prim_key_kind,
+                );
             }
             SpecificDisplayItem::BoxShadow(ref box_shadow_info) => {
                 let bounds = box_shadow_info
                     .box_bounds
                     .translate(&reference_frame_relative_offset);
                 let mut prim_info = prim_info.clone();
                 prim_info.rect = bounds;
                 self.add_box_shadow(
                     clip_and_scroll,
                     &prim_info,
                     &box_shadow_info.offset,
-                    &box_shadow_info.color,
+                    box_shadow_info.color,
                     box_shadow_info.blur_radius,
                     box_shadow_info.spread_radius,
                     box_shadow_info.border_radius,
                     box_shadow_info.clip_mode,
                 );
             }
             SpecificDisplayItem::Border(ref info) => {
                 self.add_border(
@@ -833,26 +838,19 @@ impl<'a> DisplayListFlattener<'a> {
     /// Create a primitive and add it to the prim store. This method doesn't
     /// add the primitive to the draw list, so can be used for creating
     /// sub-primitives.
     pub fn create_primitive(
         &mut self,
         info: &LayoutPrimitiveInfo,
         clip_chain_id: ClipChainId,
         spatial_node_index: SpatialNodeIndex,
-        container: PrimitiveContainer,
+        prim_key_kind: PrimitiveKeyKind,
     ) -> PrimitiveInstance {
-        // Build a primitive key, and optionally an old
-        // style PrimitiveDetails structure from the
-        // source primitive container.
-        let mut info = info.clone();
-        let (prim_key_kind, prim_details) = container.build(
-            &mut info,
-        );
-
+        // Build a primitive key.
         let prim_key = PrimitiveKey::new(
             info.is_backface_visible,
             info.rect,
             info.clip_rect,
             prim_key_kind,
         );
 
         // Get a tight bounding / culling rect for this primitive
@@ -866,34 +864,17 @@ impl<'a> DisplayListFlattener<'a> {
             .prim_interner
             .intern(&prim_key, || {
                 PrimitiveSceneData {
                     culling_rect,
                     is_backface_visible: info.is_backface_visible,
                 }
             });
 
-        // If we are building an old style primitive, add it to
-        // the prim store, and create a primitive index for it.
-        // For an interned primitive, use the primitive key to
-        // create a matching primitive instance kind.
-        let instance_kind = match prim_details {
-            Some(prim_details) => {
-                let prim_index = self.prim_store.add_primitive(
-                    &info.rect,
-                    &info.clip_rect,
-                    prim_details,
-                );
-
-                PrimitiveInstanceKind::LegacyPrimitive { prim_index }
-            }
-            None => {
-                prim_key.to_instance_kind(&mut self.prim_store)
-            }
-        };
+        let instance_kind = prim_key.to_instance_kind(&mut self.prim_store);
 
         PrimitiveInstance::new(
             instance_kind,
             prim_data_handle,
             clip_chain_id,
             spatial_node_index,
         )
     }
@@ -936,49 +917,49 @@ impl<'a> DisplayListFlattener<'a> {
 
     /// Convenience interface that creates a primitive entry and adds it
     /// to the draw list.
     pub fn add_primitive(
         &mut self,
         clip_and_scroll: ScrollNodeAndClipChain,
         info: &LayoutPrimitiveInfo,
         clip_items: Vec<ClipItemKey>,
-        container: PrimitiveContainer,
+        key_kind: PrimitiveKeyKind,
     ) {
         // If a shadow context is not active, then add the primitive
         // directly to the parent picture.
         if self.pending_shadow_items.is_empty() {
-            if container.is_visible() {
+            if key_kind.is_visible() {
                 let clip_chain_id = self.build_clip_chain(
                     clip_items,
                     clip_and_scroll.spatial_node_index,
                     clip_and_scroll.clip_chain_id,
                 );
                 let prim_instance = self.create_primitive(
                     info,
                     clip_chain_id,
                     clip_and_scroll.spatial_node_index,
-                    container,
+                    key_kind,
                 );
                 self.register_chase_primitive_by_rect(
                     &info.rect,
                     &prim_instance,
                 );
                 self.add_primitive_to_hit_testing_list(info, clip_and_scroll);
                 self.add_primitive_to_draw_list(prim_instance);
             }
         } else {
             debug_assert!(clip_items.is_empty(), "No per-prim clips expected for shadowed primitives");
 
             // There is an active shadow context. Store as a pending primitive
             // for processing during pop_all_shadows.
             self.pending_shadow_items.push_back(ShadowItem::Primitive(PendingPrimitive {
                 clip_and_scroll,
                 info: *info,
-                container,
+                key_kind,
             }));
         }
     }
 
     pub fn push_stacking_context(
         &mut self,
         pipeline_id: PipelineId,
         composite_ops: CompositeOps,
@@ -1554,17 +1535,17 @@ impl<'a> DisplayListFlattener<'a> {
                             info.rect = info.rect.translate(&pending_shadow.shadow.offset);
                             info.clip_rect = info.clip_rect.translate(&pending_shadow.shadow.offset);
 
                             // Construct and add a primitive for the given shadow.
                             let shadow_prim_instance = self.create_primitive(
                                 &info,
                                 pending_primitive.clip_and_scroll.clip_chain_id,
                                 pending_primitive.clip_and_scroll.spatial_node_index,
-                                pending_primitive.container.create_shadow(
+                                pending_primitive.key_kind.create_shadow(
                                     &pending_shadow.shadow,
                                 ),
                             );
 
                             // Add the new primitive to the shadow picture.
                             prims.push(shadow_prim_instance);
                         }
                     }
@@ -1625,22 +1606,22 @@ impl<'a> DisplayListFlattener<'a> {
                         // Add the shadow primitive. This must be done before pushing this
                         // picture on to the shadow stack, to avoid infinite recursion!
                         self.add_primitive_to_draw_list(shadow_prim_instance);
                     }
                 }
                 ShadowItem::Primitive(pending_primitive) => {
                     // For a normal primitive, if it has alpha > 0, then we add this
                     // as a normal primitive to the parent picture.
-                    if pending_primitive.container.is_visible() {
+                    if pending_primitive.key_kind.is_visible() {
                         let prim_instance = self.create_primitive(
                             &pending_primitive.info,
                             pending_primitive.clip_and_scroll.clip_chain_id,
                             pending_primitive.clip_and_scroll.spatial_node_index,
-                            pending_primitive.container,
+                            pending_primitive.key_kind,
                         );
                         self.register_chase_primitive_by_rect(
                             &pending_primitive.info.rect,
                             &prim_instance,
                         );
                         self.add_primitive_to_hit_testing_list(&pending_primitive.info, pending_primitive.clip_and_scroll);
                         self.add_primitive_to_draw_list(prim_instance);
                     }
@@ -1684,56 +1665,104 @@ impl<'a> DisplayListFlattener<'a> {
             self.add_primitive_to_hit_testing_list(info, clip_and_scroll);
             return;
         }
 
         self.add_primitive(
             clip_and_scroll,
             info,
             Vec::new(),
-            PrimitiveContainer::Rectangle {
-                color,
+            PrimitiveKeyKind::Rectangle {
+                color: color.into(),
             },
         );
     }
 
     pub fn add_clear_rectangle(
         &mut self,
         clip_and_scroll: ScrollNodeAndClipChain,
         info: &LayoutPrimitiveInfo,
     ) {
         self.add_primitive(
             clip_and_scroll,
             info,
             Vec::new(),
-            PrimitiveContainer::Clear,
+            PrimitiveKeyKind::Clear,
         );
     }
 
     pub fn add_line(
         &mut self,
         clip_and_scroll: ScrollNodeAndClipChain,
         info: &LayoutPrimitiveInfo,
         wavy_line_thickness: f32,
         orientation: LineOrientation,
-        color: &ColorF,
+        color: ColorF,
         style: LineStyle,
     ) {
-        let container = PrimitiveContainer::LineDecoration {
-            color: *color,
+        // For line decorations, we can construct the render task cache key
+        // here during scene building, since it doesn't depend on device
+        // pixel ratio or transform.
+        let mut info = info.clone();
+
+        let size = get_line_decoration_sizes(
+            &info.rect.size,
+            orientation,
             style,
-            orientation,
             wavy_line_thickness,
-        };
+        );
+
+        let cache_key = size.map(|(inline_size, block_size)| {
+            let size = match orientation {
+                LineOrientation::Horizontal => LayoutSize::new(inline_size, block_size),
+                LineOrientation::Vertical => LayoutSize::new(block_size, inline_size),
+            };
+
+            // 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 * (info.rect.size.width / inline_size).floor(),
+                            info.rect.size.height,
+                        )
+                    }
+                    LineOrientation::Vertical => {
+                        LayoutSize::new(
+                            info.rect.size.width,
+                            inline_size * (info.rect.size.height / inline_size).floor(),
+                        )
+                    }
+                };
+                let clip_rect = LayoutRect::new(
+                    info.rect.origin,
+                    clip_size,
+                );
+                info.clip_rect = clip_rect
+                    .intersection(&info.clip_rect)
+                    .unwrap_or(LayoutRect::zero());
+            }
+
+            LineDecorationCacheKey {
+                style,
+                orientation,
+                wavy_line_thickness: Au::from_f32_px(wavy_line_thickness),
+                size: size.to_au(),
+            }
+        });
 
         self.add_primitive(
             clip_and_scroll,
-            info,
+            &info,
             Vec::new(),
-            container,
+            PrimitiveKeyKind::LineDecoration {
+                cache_key,
+                color: color.into(),
+            },
         );
     }
 
     pub fn add_border(
         &mut self,
         clip_and_scroll: ScrollNodeAndClipChain,
         info: &LayoutPrimitiveInfo,
         border_item: &BorderDisplayItem,
@@ -1750,17 +1779,17 @@ impl<'a> DisplayListFlattener<'a> {
                     repeat_horizontal: border.repeat_horizontal,
                     repeat_vertical: border.repeat_vertical,
                     outset: border.outset.into(),
                     widths: border_item.widths.into(),
                 };
 
                 let prim = match border.source {
                     NinePatchBorderSource::Image(image_key) => {
-                        PrimitiveContainer::ImageBorder {
+                        PrimitiveKeyKind::ImageBorder {
                             request: ImageRequest {
                                 key: image_key,
                                 rendering: ImageRendering::Auto,
                                 tile: None,
                             },
                             nine_patch,
                         }
                     }
@@ -1776,36 +1805,28 @@ impl<'a> DisplayListFlattener<'a> {
                             pipeline_id,
                             Some(Box::new(nine_patch)),
                         ) {
                             Some(prim) => prim,
                             None => return,
                         }
                     }
                     NinePatchBorderSource::RadialGradient(gradient) => {
-                        let brush_kind = self.create_brush_kind_for_radial_gradient(
+                        self.create_radial_gradient_prim(
                             &info,
                             gradient.center,
                             gradient.start_offset * gradient.radius.width,
                             gradient.end_offset * gradient.radius.width,
                             gradient.radius.width / gradient.radius.height,
                             gradient_stops,
                             gradient.extend_mode,
                             LayoutSize::new(border.height as f32, border.width as f32),
                             LayoutSize::zero(),
-                        );
-
-                        let segments = nine_patch.create_segments(&info.rect);
-
-                        let descriptor = BrushSegmentDescriptor {
-                            segments: SmallVec::from_vec(segments),
-                        };
-
-                        PrimitiveContainer::Brush(
-                            BrushPrimitive::new(brush_kind, Some(descriptor))
+                            pipeline_id,
+                            Some(Box::new(nine_patch)),
                         )
                     }
                 };
 
                 self.add_primitive(
                     clip_and_scroll,
                     info,
                     Vec::new(),
@@ -1829,17 +1850,17 @@ impl<'a> DisplayListFlattener<'a> {
         start_point: LayoutPoint,
         end_point: LayoutPoint,
         stops: ItemRange<GradientStop>,
         extend_mode: ExtendMode,
         stretch_size: LayoutSize,
         mut tile_spacing: LayoutSize,
         pipeline_id: PipelineId,
         nine_patch: Option<Box<NinePatchDescriptor>>,
-    ) -> Option<PrimitiveContainer> {
+    ) -> Option<PrimitiveKeyKind> {
         let mut prim_rect = info.rect;
         simplify_repeated_primitive(&stretch_size, &mut tile_spacing, &mut prim_rect);
 
         // TODO(gw): It seems like we should be able to look this up once in
         //           flatten_root() and pass to all children here to avoid
         //           some hash lookups?
         let display_list = self.scene.get_display_list_for_pipeline(pipeline_id);
         let mut max_alpha: f32 = 0.0;
@@ -1871,54 +1892,71 @@ impl<'a> DisplayListFlattener<'a> {
         // points, it's necessary to reverse the gradient
         // line in some cases.
         let (sp, ep) = if reverse_stops {
             (end_point, start_point)
         } else {
             (start_point, end_point)
         };
 
-        Some(PrimitiveContainer::LinearGradient {
+        Some(PrimitiveKeyKind::LinearGradient {
             extend_mode,
-            start_point: sp,
-            end_point: ep,
-            stretch_size,
-            tile_spacing,
+            start_point: sp.into(),
+            end_point: ep.into(),
+            stretch_size: stretch_size.into(),
+            tile_spacing: tile_spacing.into(),
             stops,
             reverse_stops,
             nine_patch,
         })
     }
 
-    pub fn create_brush_kind_for_radial_gradient(
+    pub fn create_radial_gradient_prim(
         &mut self,
         info: &LayoutPrimitiveInfo,
         center: LayoutPoint,
         start_radius: f32,
         end_radius: f32,
         ratio_xy: f32,
         stops: ItemRange<GradientStop>,
         extend_mode: ExtendMode,
         stretch_size: LayoutSize,
         mut tile_spacing: LayoutSize,
-    ) -> BrushKind {
+        pipeline_id: PipelineId,
+        nine_patch: Option<Box<NinePatchDescriptor>>,
+    ) -> PrimitiveKeyKind {
         let mut prim_rect = info.rect;
         simplify_repeated_primitive(&stretch_size, &mut tile_spacing, &mut prim_rect);
 
-        BrushKind::RadialGradient {
-            stops_range: stops,
-            extend_mode,
-            center,
+        // TODO(gw): It seems like we should be able to look this up once in
+        //           flatten_root() and pass to all children here to avoid
+        //           some hash lookups?
+        let display_list = self.scene.get_display_list_for_pipeline(pipeline_id);
+
+        let params = RadialGradientParams {
             start_radius,
             end_radius,
             ratio_xy,
-            stops_handle: GpuCacheHandle::new(),
-            stretch_size,
-            tile_spacing,
-            visible_tiles_range: GradientTileRange::empty(),
+        };
+
+        let stops = display_list.get(stops).map(|stop| {
+            GradientStopKey {
+                offset: stop.offset,
+                color: stop.color.into(),
+            }
+        }).collect();
+
+        PrimitiveKeyKind::RadialGradient {
+            extend_mode,
+            center: center.into(),
+            params,
+            stretch_size: stretch_size.into(),
+            tile_spacing: tile_spacing.into(),
+            nine_patch,
+            stops,
         }
     }
 
     pub fn add_text(
         &mut self,
         clip_and_scroll: ScrollNodeAndClipChain,
         offset: LayoutVector2D,
         prim_info: &LayoutPrimitiveInfo,
@@ -1972,20 +2010,20 @@ impl<'a> DisplayListFlattener<'a> {
             let display_list = self.scene.get_display_list_for_pipeline(pipeline_id);
 
             // TODO(gw): It'd be nice not to have to allocate here for creating
             //           the primitive key, when the common case is that the
             //           hash will match and we won't end up creating a new
             //           primitive template.
             let glyphs = display_list.get(glyph_range).collect();
 
-            PrimitiveContainer::TextRun {
+            PrimitiveKeyKind::TextRun {
                 glyphs,
                 font,
-                offset,
+                offset: offset.to_au(),
                 shadow: false,
             }
         };
 
         self.add_primitive(
             clip_and_scroll,
             prim_info,
             Vec::new(),
@@ -2024,21 +2062,21 @@ impl<'a> DisplayListFlattener<'a> {
                 ),
             )
         });
 
         self.add_primitive(
             clip_and_scroll,
             &info,
             Vec::new(),
-            PrimitiveContainer::Image {
+            PrimitiveKeyKind::Image {
                 key: image_key,
-                tile_spacing,
-                stretch_size,
-                color,
+                tile_spacing: tile_spacing.into(),
+                stretch_size: stretch_size.into(),
+                color: color.into(),
                 sub_rect,
                 image_rendering,
                 alpha_type,
             },
         );
     }
 
     pub fn add_yuv_image(
@@ -2056,17 +2094,17 @@ impl<'a> DisplayListFlattener<'a> {
             YuvData::PlanarYCbCr(plane_0, plane_1, plane_2) => [plane_0, plane_1, plane_2],
             YuvData::InterleavedYCbCr(plane_0) => [plane_0, ImageKey::DUMMY, ImageKey::DUMMY],
         };
 
         self.add_primitive(
             clip_and_scroll,
             info,
             Vec::new(),
-            PrimitiveContainer::YuvImage {
+            PrimitiveKeyKind::YuvImage {
                 color_depth,
                 yuv_key,
                 format,
                 color_space,
                 image_rendering,
             },
         );
     }
@@ -2195,17 +2233,17 @@ impl FlattenedStackingContext {
 }
 
 /// A primitive that is added while a shadow context is
 /// active is stored as a pending primitive and only
 /// added to pictures during pop_all_shadows.
 struct PendingPrimitive {
     clip_and_scroll: ScrollNodeAndClipChain,
     info: LayoutPrimitiveInfo,
-    container: PrimitiveContainer,
+    key_kind: PrimitiveKeyKind,
 }
 
 /// As shadows are pushed, they are stored as pending
 /// shadows, and handled at once during pop_all_shadows.
 struct PendingShadow {
     shadow: Shadow,
     clip_and_scroll: ScrollNodeAndClipChain,
 }
--- a/gfx/wr/webrender/src/frame_builder.rs
+++ b/gfx/wr/webrender/src/frame_builder.rs
@@ -333,17 +333,17 @@ impl FrameBuilder {
         debug_assert!(
             DeviceIntRect::new(DeviceIntPoint::zero(), self.window_size)
                 .contains_rect(&self.screen_rect)
         );
 
         let mut profile_counters = FrameProfileCounters::new();
         profile_counters
             .total_primitives
-            .set(self.prim_store.prim_count());
+            .set(self.prim_store.prim_count);
 
         resource_cache.begin_frame(stamp);
         gpu_cache.begin_frame(stamp.frame_id());
 
         let mut transform_palette = TransformPalette::new();
         clip_scroll_tree.update_tree(
             pan,
             scene_properties,
--- a/gfx/wr/webrender/src/picture.rs
+++ b/gfx/wr/webrender/src/picture.rs
@@ -436,22 +436,22 @@ impl TileCache {
                     PrimitiveTemplateKind::YuvImage { ref yuv_key, .. } => {
                         image_keys.extend_from_slice(yuv_key);
                     }
                     _ => {
                         unreachable!();
                     }
                 }
             }
-            PrimitiveInstanceKind::LegacyPrimitive { .. } |
             PrimitiveInstanceKind::TextRun { .. } |
             PrimitiveInstanceKind::LineDecoration { .. } |
             PrimitiveInstanceKind::Clear |
             PrimitiveInstanceKind::NormalBorder { .. } |
             PrimitiveInstanceKind::LinearGradient { .. } |
+            PrimitiveInstanceKind::RadialGradient { .. } |
             PrimitiveInstanceKind::ImageBorder { .. } => {
                 // These don't contribute dependencies
             }
         }
 
         for (key, current) in &mut opacity_bindings {
             if let Some(value) = scene_properties.get_float_value(*key) {
                 *current = value;
--- a/gfx/wr/webrender/src/prim_store.rs
+++ b/gfx/wr/webrender/src/prim_store.rs
@@ -1,17 +1,17 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-use api::{AlphaType, BorderRadius, BuiltDisplayList, ClipMode, ColorF, PictureRect, ColorU, LayoutPrimitiveInfo};
+use api::{AlphaType, BorderRadius, ClipMode, ColorF, PictureRect, ColorU};
 use api::{DeviceIntRect, DeviceIntSize, DevicePixelScale, ExtendMode, DeviceRect, LayoutSideOffsetsAu};
-use api::{FilterOp, GlyphInstance, GradientStop, ImageKey, ImageRendering, ItemRange, TileOffset, RepeatMode};
+use api::{FilterOp, GlyphInstance, GradientStop, ImageKey, ImageRendering, TileOffset, RepeatMode};
 use api::{RasterSpace, LayoutPoint, LayoutRect, LayoutSideOffsets, LayoutSize, LayoutToWorldTransform};
-use api::{LayoutVector2D, PremultipliedColorF, PropertyBinding, Shadow, YuvColorSpace, YuvFormat};
+use api::{PremultipliedColorF, PropertyBinding, Shadow, YuvColorSpace, YuvFormat};
 use api::{DeviceIntSideOffsets, WorldPixel, BoxShadowClipMode, NormalBorder, WorldRect, LayoutToWorldScale};
 use api::{PicturePixel, RasterPixel, ColorDepth, LineStyle, LineOrientation, LayoutSizeAu, AuHelpers, LayoutVector2DAu};
 use app_units::Au;
 use border::{get_max_scale_for_border, build_border_instances, create_border_segments};
 use border::{BorderSegmentCacheKey, NormalBorderAu};
 use clip::{ClipStore};
 use clip_scroll_tree::{ClipScrollTree, SpatialNodeIndex};
 use clip::{ClipDataStore, ClipNodeFlags, ClipChainId, ClipChainInstance, ClipItem, ClipNodeCollector};
@@ -293,21 +293,16 @@ impl<F, T> SpaceMapper<F, T> where F: fm
 #[cfg_attr(feature = "capture", derive(Serialize))]
 #[cfg_attr(feature = "replay", derive(Deserialize))]
 pub struct DeferredResolve {
     pub address: GpuCacheAddress,
     pub image_properties: ImageProperties,
     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, PartialEq)]
 pub struct ClipTaskIndex(pub u32);
 
 impl ClipTaskIndex {
     pub const INVALID: ClipTaskIndex = ClipTaskIndex(0);
 }
 
 #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash, Ord, PartialOrd)]
@@ -401,16 +396,25 @@ pub enum PrimitiveKeyKind {
         start_point: PointKey,
         end_point: PointKey,
         stretch_size: SizeKey,
         tile_spacing: SizeKey,
         stops: Vec<GradientStopKey>,
         reverse_stops: bool,
         nine_patch: Option<Box<NinePatchDescriptor>>,
     },
+    RadialGradient {
+        extend_mode: ExtendMode,
+        center: PointKey,
+        params: RadialGradientParams,
+        stretch_size: SizeKey,
+        stops: Vec<GradientStopKey>,
+        tile_spacing: SizeKey,
+        nine_patch: Option<Box<NinePatchDescriptor>>,
+    },
 }
 
 /// A hashable gradient stop that can be used in primitive keys.
 #[cfg_attr(feature = "capture", derive(Serialize))]
 #[cfg_attr(feature = "replay", derive(Deserialize))]
 #[derive(Debug, Clone, PartialEq)]
 pub struct GradientStopKey {
     pub offset: f32,
@@ -520,17 +524,17 @@ impl From<SideOffsets2D<f32>> for SideOf
             left: offsets.left,
         }
     }
 }
 
 /// A hashable size for using as a key during primitive interning.
 #[cfg_attr(feature = "capture", derive(Serialize))]
 #[cfg_attr(feature = "replay", derive(Deserialize))]
-#[derive(Debug, Clone, PartialEq)]
+#[derive(Copy, Debug, Clone, PartialEq)]
 pub struct SizeKey {
     w: f32,
     h: f32,
 }
 
 impl Eq for SizeKey {}
 
 impl hash::Hash for SizeKey {
@@ -550,16 +554,36 @@ impl From<LayoutSize> for SizeKey {
     fn from(size: LayoutSize) -> SizeKey {
         SizeKey {
             w: size.width,
             h: size.height,
         }
     }
 }
 
+/// Hashable radial gradient parameters, for use during prim interning.
+#[cfg_attr(feature = "capture", derive(Serialize))]
+#[cfg_attr(feature = "replay", derive(Deserialize))]
+#[derive(Debug, Clone, PartialEq)]
+pub struct RadialGradientParams {
+    pub start_radius: f32,
+    pub end_radius: f32,
+    pub ratio_xy: f32,
+}
+
+impl Eq for RadialGradientParams {}
+
+impl hash::Hash for RadialGradientParams {
+    fn hash<H: hash::Hasher>(&self, state: &mut H) {
+        self.start_radius.to_bits().hash(state);
+        self.end_radius.to_bits().hash(state);
+        self.ratio_xy.to_bits().hash(state);
+    }
+}
+
 /// A hashable point for using as a key during primitive interning.
 #[cfg_attr(feature = "capture", derive(Serialize))]
 #[cfg_attr(feature = "replay", derive(Deserialize))]
 #[derive(Debug, Clone, PartialEq)]
 pub struct PointKey {
     x: f32,
     y: f32,
 }
@@ -672,16 +696,21 @@ impl PrimitiveKey {
                     image_instance_index,
                 }
             }
             PrimitiveKeyKind::LinearGradient { .. } => {
                 PrimitiveInstanceKind::LinearGradient {
                     visible_tiles_range: GradientTileRange::empty(),
                 }
             }
+            PrimitiveKeyKind::RadialGradient { .. } => {
+                PrimitiveInstanceKind::RadialGradient {
+                    visible_tiles_range: GradientTileRange::empty(),
+                }
+            }
             PrimitiveKeyKind::Unused => {
                 // Should never be hit as this method should not be
                 // called for old style primitives.
                 unreachable!();
             }
         }
     }
 }
@@ -743,16 +772,26 @@ pub enum PrimitiveTemplateKind {
         stretch_size: LayoutSize,
         tile_spacing: LayoutSize,
         stops_opacity: PrimitiveOpacity,
         stops: Vec<GradientStop>,
         brush_segments: Vec<BrushSegment>,
         reverse_stops: bool,
         stops_handle: GpuCacheHandle,
     },
+    RadialGradient {
+        extend_mode: ExtendMode,
+        center: LayoutPoint,
+        params: RadialGradientParams,
+        stretch_size: LayoutSize,
+        tile_spacing: LayoutSize,
+        brush_segments: Vec<BrushSegment>,
+        stops: Vec<GradientStop>,
+        stops_handle: GpuCacheHandle,
+    },
     Clear,
     Unused,
 }
 
 /// Construct the primitive template data from a primitive key. This
 /// is invoked when a primitive key is created and the interner
 /// doesn't currently contain a primitive with this key.
 impl PrimitiveKeyKind {
@@ -887,16 +926,50 @@ impl PrimitiveKeyKind {
                     tile_spacing: tile_spacing.into(),
                     stops_opacity,
                     stops,
                     brush_segments,
                     reverse_stops,
                     stops_handle: GpuCacheHandle::new(),
                 }
             }
+            PrimitiveKeyKind::RadialGradient {
+                extend_mode,
+                params,
+                stretch_size,
+                tile_spacing,
+                nine_patch,
+                center,
+                stops,
+                ..
+            } => {
+                let mut brush_segments = Vec::new();
+
+                if let Some(ref nine_patch) = nine_patch {
+                    brush_segments = nine_patch.create_segments(rect);
+                }
+
+                let stops = stops.iter().map(|stop| {
+                    GradientStop {
+                        offset: stop.offset,
+                        color: stop.color.into(),
+                    }
+                }).collect();
+
+                PrimitiveTemplateKind::RadialGradient {
+                    center: center.into(),
+                    extend_mode,
+                    params,
+                    stretch_size: stretch_size.into(),
+                    tile_spacing: tile_spacing.into(),
+                    brush_segments,
+                    stops_handle: GpuCacheHandle::new(),
+                    stops,
+                }
+            }
         }
     }
 }
 
 #[cfg_attr(feature = "capture", derive(Serialize))]
 #[cfg_attr(feature = "replay", derive(Deserialize))]
 pub struct PrimitiveTemplate {
     pub is_backface_visible: bool,
@@ -1049,16 +1122,36 @@ impl PrimitiveTemplateKind {
                 ]);
                 request.push([
                     pack_as_float(extend_mode as u32),
                     stretch_size.width,
                     stretch_size.height,
                     0.0,
                 ]);
             }
+            PrimitiveTemplateKind::RadialGradient {
+                center,
+                ref params,
+                extend_mode,
+                stretch_size,
+                ..
+            } => {
+                request.push([
+                    center.x,
+                    center.y,
+                    params.start_radius,
+                    params.end_radius,
+                ]);
+                request.push([
+                    params.ratio_xy,
+                    pack_as_float(extend_mode as u32),
+                    stretch_size.width,
+                    stretch_size.height,
+                ]);
+            }
             PrimitiveTemplateKind::Unused => {}
         }
     }
 
     fn write_segment_gpu_blocks(
         &self,
         request: &mut GpuDataRequest,
         prim_rect: LayoutRect,
@@ -1089,17 +1182,18 @@ impl PrimitiveTemplateKind {
                 }
             }
             PrimitiveTemplateKind::LineDecoration { .. } => {
                 request.write_segment(
                     prim_rect,
                     [0.0; 4],
                 );
             }
-            PrimitiveTemplateKind::LinearGradient { ref brush_segments, .. } => {
+            PrimitiveTemplateKind::LinearGradient { ref brush_segments, .. } |
+            PrimitiveTemplateKind::RadialGradient { ref brush_segments, .. } => {
                 for segment in brush_segments {
                     // has to match VECS_PER_SEGMENT
                     request.write_segment(
                         segment.local_rect,
                         segment.extra_data,
                     );
                 }
             }
@@ -1151,33 +1245,45 @@ impl PrimitiveTemplate {
                 reverse_stops,
                 ref stops,
                 ..
             } => {
                 if let Some(mut request) = frame_state.gpu_cache.request(stops_handle) {
                     GradientGpuBlockBuilder::build(
                         reverse_stops,
                         &mut request,
-                        stops.iter().cloned(),
+                        stops,
                     );
                 }
 
                 // 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;
                 if stride.width >= self.prim_rect.size.width &&
                    stride.height >= self.prim_rect.size.height {
                     stops_opacity
                 } else {
                     PrimitiveOpacity::translucent()
                 }
             }
+            PrimitiveTemplateKind::RadialGradient { ref mut stops_handle, ref stops, .. } => {
+                if let Some(mut request) = frame_state.gpu_cache.request(stops_handle) {
+                    GradientGpuBlockBuilder::build(
+                        false,
+                        &mut request,
+                        stops,
+                    );
+                }
+
+                //TODO: can we make it opaque in some cases?
+                PrimitiveOpacity::translucent()
+            }
             PrimitiveTemplateKind::ImageBorder { request, .. } => {
                 let image_properties = frame_state
                     .resource_cache
                     .get_image_properties(request.key);
 
                 if let Some(image_properties) = image_properties {
                     frame_state.resource_cache.request_image(
                         request,
@@ -1434,31 +1540,16 @@ pub struct VisibleGradientTile {
 #[cfg_attr(feature = "capture", derive(Serialize))]
 #[cfg_attr(feature = "replay", derive(Deserialize))]
 #[derive(Debug)]
 pub struct BorderSegmentInfo {
     pub local_task_size: LayoutSize,
     pub cache_key: BorderSegmentCacheKey,
 }
 
-pub enum BrushKind {
-    RadialGradient {
-        stops_handle: GpuCacheHandle,
-        stops_range: ItemRange<GradientStop>,
-        extend_mode: ExtendMode,
-        center: LayoutPoint,
-        start_radius: f32,
-        end_radius: f32,
-        ratio_xy: f32,
-        stretch_size: LayoutSize,
-        tile_spacing: LayoutSize,
-        visible_tiles_range: GradientTileRange,
-    },
-}
-
 bitflags! {
     /// Each bit of the edge AA mask is:
     /// 0, when the edge of the primitive needs to be considered for AA
     /// 1, when the edge of the segment needs to be considered for AA
     ///
     /// *Note*: the bit values have to match the shader logic in
     /// `write_transform_vertex()` function.
     #[cfg_attr(feature = "capture", derive(Serialize))]
@@ -1560,106 +1651,34 @@ impl BrushSegment {
             }
             None => {
                 ClipMaskKind::Clipped
             }
         }
     }
 }
 
-pub type BrushSegmentVec = SmallVec<[BrushSegment; 1]>;
-
-#[derive(Debug)]
-pub struct BrushSegmentDescriptor {
-    pub segments: BrushSegmentVec,
-}
-
-pub struct BrushPrimitive {
-    pub kind: BrushKind,
-    pub opacity: PrimitiveOpacity,
-    pub segment_desc: Option<BrushSegmentDescriptor>,
-    pub gpu_location: GpuCacheHandle,
-}
-
-impl BrushPrimitive {
-    pub fn new(
-        kind: BrushKind,
-        segment_desc: Option<BrushSegmentDescriptor>,
-    ) -> Self {
-        BrushPrimitive {
-            kind,
-            opacity: PrimitiveOpacity::translucent(),
-            segment_desc,
-            gpu_location: GpuCacheHandle::new(),
-        }
-    }
-
-    fn write_gpu_blocks_if_required(
-        &mut self,
-        local_rect: LayoutRect,
-        gpu_cache: &mut GpuCache,
-    ) {
-        if let Some(mut request) = gpu_cache.request(&mut self.gpu_location) {
-            // has to match VECS_PER_SPECIFIC_BRUSH
-            match self.kind {
-                BrushKind::RadialGradient { stretch_size, center, start_radius, end_radius, ratio_xy, extend_mode, .. } => {
-                    request.push([
-                        center.x,
-                        center.y,
-                        start_radius,
-                        end_radius,
-                    ]);
-                    request.push([
-                        ratio_xy,
-                        pack_as_float(extend_mode as u32),
-                        stretch_size.width,
-                        stretch_size.height,
-                    ]);
-                }
-            }
-
-            match self.segment_desc {
-                Some(ref segment_desc) => {
-                    for segment in &segment_desc.segments {
-                        // has to match VECS_PER_SEGMENT
-                        request.write_segment(
-                            segment.local_rect,
-                            segment.extra_data,
-                        );
-                    }
-                }
-                None => {
-                    request.write_segment(
-                        local_rect,
-                        [0.0; 4],
-                    );
-                }
-            }
-        }
-    }
-}
-
 // Key that identifies a unique (partial) image that is being
 // stored in the render task cache.
 #[derive(Debug, Copy, Clone, Eq, Hash, PartialEq)]
 #[cfg_attr(feature = "capture", derive(Serialize))]
 #[cfg_attr(feature = "replay", derive(Deserialize))]
 pub struct ImageCacheKey {
     pub request: ImageRequest,
     pub texel_rect: Option<DeviceIntRect>,
 }
 
 #[derive(Clone, Debug, Hash, PartialEq, Eq)]
 #[cfg_attr(feature = "capture", derive(Serialize))]
 #[cfg_attr(feature = "replay", derive(Deserialize))]
 pub struct LineDecorationCacheKey {
-    style: LineStyle,
-    orientation: LineOrientation,
-    wavy_line_thickness: Au,
-    size: LayoutSizeAu,
+    pub style: LineStyle,
+    pub orientation: LineOrientation,
+    pub wavy_line_thickness: Au,
+    pub size: LayoutSizeAu,
 }
 
 // Where to find the texture data for an image primitive.
 #[cfg_attr(feature = "capture", derive(Serialize))]
 #[cfg_attr(feature = "replay", derive(Deserialize))]
 #[derive(Debug)]
 pub enum ImageSource {
     // A normal image - just reference the texture cache.
@@ -1734,21 +1753,21 @@ impl GradientGpuBlockBuilder {
     #[inline]
     fn get_index(offset: f32) -> usize {
         (offset.max(0.0).min(1.0) * GRADIENT_DATA_TABLE_SIZE as f32 +
             GRADIENT_DATA_TABLE_BEGIN as f32)
             .round() as usize
     }
 
     // Build the gradient data from the supplied stops, reversing them if necessary.
-    fn build<I>(
+    fn build(
         reverse_stops: bool,
         request: &mut GpuDataRequest,
-        src_stops: I,
-    ) where I: IntoIterator<Item = GradientStop> {
+        src_stops: &[GradientStop],
+    ) {
         // Preconditions (should be ensured by DisplayListBuilder):
         // * we have at least two stops
         // * first stop has offset 0.0
         // * last stop has offset 1.0
         let mut src_stops = src_stops.into_iter();
         let mut cur_color = match src_stops.next() {
             Some(stop) => {
                 debug_assert_eq!(stop.offset, 0.0);
@@ -2185,337 +2204,111 @@ pub struct NinePatchDescriptor {
     pub slice: SideOffsets2D<i32>,
     pub fill: bool,
     pub repeat_horizontal: RepeatMode,
     pub repeat_vertical: RepeatMode,
     pub outset: SideOffsetsKey,
     pub widths: SideOffsetsKey,
 }
 
-pub enum PrimitiveContainer {
-    TextRun {
-        font: FontInstance,
-        offset: LayoutVector2D,
-        glyphs: Vec<GlyphInstance>,
-        shadow: bool,
-    },
-    Clear,
-    Brush(BrushPrimitive),
-    LineDecoration {
-        color: ColorF,
-        style: LineStyle,
-        orientation: LineOrientation,
-        wavy_line_thickness: f32,
-    },
-    NormalBorder {
-        border: NormalBorder,
-        widths: LayoutSideOffsets,
-    },
-    ImageBorder {
-        request: ImageRequest,
-        nine_patch: NinePatchDescriptor,
-    },
-    Rectangle {
-        color: ColorF,
-    },
-    YuvImage {
-        color_depth: ColorDepth,
-        yuv_key: [ImageKey; 3],
-        format: YuvFormat,
-        color_space: YuvColorSpace,
-        image_rendering: ImageRendering,
-    },
-    Image {
-        key: ImageKey,
-        color: ColorF,
-        tile_spacing: LayoutSize,
-        stretch_size: LayoutSize,
-        sub_rect: Option<DeviceIntRect>,
-        image_rendering: ImageRendering,
-        alpha_type: AlphaType,
-    },
-    LinearGradient {
-        extend_mode: ExtendMode,
-        start_point: LayoutPoint,
-        end_point: LayoutPoint,
-        stretch_size: LayoutSize,
-        tile_spacing: LayoutSize,
-        stops: Vec<GradientStopKey>,
-        reverse_stops: bool,
-        nine_patch: Option<Box<NinePatchDescriptor>>,
-    },
-}
-
-impl PrimitiveContainer {
+impl PrimitiveKeyKind {
     // Return true if the primary primitive is visible.
     // Used to trivially reject non-visible primitives.
     // TODO(gw): Currently, primitives other than those
     //           listed here are handled before the
     //           add_primitive() call. In the future
     //           we should move the logic for all other
     //           primitive types to use this.
     pub fn is_visible(&self) -> bool {
         match *self {
-            PrimitiveContainer::TextRun { ref font, .. } => {
+            PrimitiveKeyKind::TextRun { ref font, .. } => {
                 font.color.a > 0
             }
-            PrimitiveContainer::Brush(ref brush) => {
-                match brush.kind {
-                    BrushKind::RadialGradient { .. } => {
-                        true
-                    }
-                }
-            }
-            PrimitiveContainer::NormalBorder { .. } |
-            PrimitiveContainer::ImageBorder { .. } |
-            PrimitiveContainer::YuvImage { .. } |
-            PrimitiveContainer::Image { .. } |
-            PrimitiveContainer::LinearGradient { .. } |
-            PrimitiveContainer::Clear => {
+            PrimitiveKeyKind::NormalBorder { .. } |
+            PrimitiveKeyKind::ImageBorder { .. } |
+            PrimitiveKeyKind::YuvImage { .. } |
+            PrimitiveKeyKind::Image { .. } |
+            PrimitiveKeyKind::LinearGradient { .. } |
+            PrimitiveKeyKind::RadialGradient { .. } |
+            PrimitiveKeyKind::Clear |
+            PrimitiveKeyKind::Unused => {
                 true
             }
-            PrimitiveContainer::Rectangle { ref color, .. } |
-            PrimitiveContainer::LineDecoration { ref color, .. } => {
-                color.a > 0.0
-            }
-        }
-    }
-
-    /// Convert a source primitive container into a key, and optionally
-    /// an old style PrimitiveDetails structure.
-    pub fn build(
-        self,
-        info: &mut LayoutPrimitiveInfo,
-    ) -> (PrimitiveKeyKind, Option<PrimitiveDetails>) {
-        match self {
-            PrimitiveContainer::TextRun { font, offset, glyphs, shadow, .. } => {
-                let key = PrimitiveKeyKind::TextRun {
-                    font,
-                    offset: offset.to_au(),
-                    glyphs,
-                    shadow,
-                };
-
-                (key, None)
-            }
-            PrimitiveContainer::LinearGradient {
-                extend_mode,
-                start_point,
-                end_point,
-                stretch_size,
-                tile_spacing,
-                stops,
-                reverse_stops,
-                nine_patch,
-                ..
-            } => {
-                let key = PrimitiveKeyKind::LinearGradient {
-                    extend_mode,
-                    start_point: start_point.into(),
-                    end_point: end_point.into(),
-                    stretch_size: stretch_size.into(),
-                    tile_spacing: tile_spacing.into(),
-                    stops,
-                    reverse_stops,
-                    nine_patch,
-                };
-
-                (key, None)
-            }
-            PrimitiveContainer::Clear => {
-                (PrimitiveKeyKind::Clear, None)
-            }
-            PrimitiveContainer::Rectangle { color, .. } => {
-                let key = PrimitiveKeyKind::Rectangle {
-                    color: color.into(),
-                };
-
-                (key, None)
-            }
-            PrimitiveContainer::Image { alpha_type, key, stretch_size, color, tile_spacing, image_rendering, sub_rect, .. } => {
-                let key = PrimitiveKeyKind::Image {
-                    key,
-                    tile_spacing: tile_spacing.into(),
-                    stretch_size: stretch_size.into(),
-                    color: color.into(),
-                    sub_rect,
-                    image_rendering,
-                    alpha_type,
-                };
-
-                (key, None)
-            }
-            PrimitiveContainer::YuvImage { color_depth, yuv_key, format, color_space, image_rendering, .. } => {
-                let key = PrimitiveKeyKind::YuvImage {
-                    color_depth,
-                    yuv_key,
-                    format,
-                    color_space,
-                    image_rendering,
-                };
-
-                (key, None)
-            }
-            PrimitiveContainer::ImageBorder { request, nine_patch, .. } => {
-                let key = PrimitiveKeyKind::ImageBorder {
-                    request,
-                    nine_patch,
-                };
-
-                (key, None)
-            }
-            PrimitiveContainer::NormalBorder { border, widths, .. } => {
-                let key = PrimitiveKeyKind::NormalBorder {
-                    border: border.into(),
-                    widths: widths.to_au(),
-                };
-
-                (key, None)
-            }
-            PrimitiveContainer::LineDecoration { color, style, orientation, wavy_line_thickness } => {
-                // For line decorations, we can construct the render task cache key
-                // here during scene building, since it doesn't depend on device
-                // pixel ratio or transform.
-
-                let size = get_line_decoration_sizes(
-                    &info.rect.size,
-                    orientation,
-                    style,
-                    wavy_line_thickness,
-                );
-
-                let cache_key = size.map(|(inline_size, block_size)| {
-                    let size = match orientation {
-                        LineOrientation::Horizontal => LayoutSize::new(inline_size, block_size),
-                        LineOrientation::Vertical => LayoutSize::new(block_size, inline_size),
-                    };
-
-                    // 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 * (info.rect.size.width / inline_size).floor(),
-                                    info.rect.size.height,
-                                )
-                            }
-                            LineOrientation::Vertical => {
-                                LayoutSize::new(
-                                    info.rect.size.width,
-                                    inline_size * (info.rect.size.height / inline_size).floor(),
-                                )
-                            }
-                        };
-                        let clip_rect = LayoutRect::new(
-                            info.rect.origin,
-                            clip_size,
-                        );
-                        info.clip_rect = clip_rect
-                            .intersection(&info.clip_rect)
-                            .unwrap_or(LayoutRect::zero());
-                    }
-
-                    LineDecorationCacheKey {
-                        style,
-                        orientation,
-                        wavy_line_thickness: Au::from_f32_px(wavy_line_thickness),
-                        size: size.to_au(),
-                    }
-                });
-
-                let key = PrimitiveKeyKind::LineDecoration {
-                    cache_key,
-                    color: color.into(),
-                };
-
-                (key, None)
-            }
-            PrimitiveContainer::Brush(prim) => {
-                (PrimitiveKeyKind::Unused, Some(PrimitiveDetails::Brush(prim)))
+            PrimitiveKeyKind::Rectangle { ref color, .. } |
+            PrimitiveKeyKind::LineDecoration { ref color, .. } => {
+                color.a > 0
             }
         }
     }
 
     // Create a clone of this PrimitiveContainer, applying whatever
     // changes are necessary to the primitive to support rendering
     // it as part of the supplied shadow.
     pub fn create_shadow(
         &self,
         shadow: &Shadow,
-    ) -> PrimitiveContainer {
+    ) -> PrimitiveKeyKind {
         match *self {
-            PrimitiveContainer::TextRun { ref font, offset, ref glyphs, .. } => {
+            PrimitiveKeyKind::TextRun { ref font, offset, ref glyphs, .. } => {
                 let mut font = FontInstance {
                     color: shadow.color.into(),
                     ..font.clone()
                 };
                 if shadow.blur_radius > 0.0 {
                     font.disable_subpixel_aa();
                 }
 
-                PrimitiveContainer::TextRun {
+                PrimitiveKeyKind::TextRun {
                     font,
                     glyphs: glyphs.clone(),
-                    offset: offset + shadow.offset,
+                    offset: offset + shadow.offset.to_au(),
                     shadow: true,
                 }
             }
-            PrimitiveContainer::LineDecoration { style, orientation, wavy_line_thickness, .. } => {
-                PrimitiveContainer::LineDecoration {
-                    color: shadow.color,
-                    style,
-                    orientation,
-                    wavy_line_thickness,
+            PrimitiveKeyKind::LineDecoration { ref cache_key, .. } => {
+                PrimitiveKeyKind::LineDecoration {
+                    color: shadow.color.into(),
+                    cache_key: cache_key.clone(),
                 }
             }
-            PrimitiveContainer::Rectangle { .. } => {
-                PrimitiveContainer::Rectangle {
-                    color: shadow.color,
+            PrimitiveKeyKind::Rectangle { .. } => {
+                PrimitiveKeyKind::Rectangle {
+                    color: shadow.color.into(),
                 }
             }
-            PrimitiveContainer::NormalBorder { border, widths, .. } => {
-                let border = border.with_color(shadow.color);
-                PrimitiveContainer::NormalBorder {
+            PrimitiveKeyKind::NormalBorder { ref border, widths, .. } => {
+                let border = border.with_color(shadow.color.into());
+                PrimitiveKeyKind::NormalBorder {
                     border,
                     widths,
                 }
             }
-            PrimitiveContainer::Image { alpha_type, image_rendering, tile_spacing, stretch_size, key, sub_rect, .. } => {
-                PrimitiveContainer::Image {
+            PrimitiveKeyKind::Image { alpha_type, image_rendering, tile_spacing, stretch_size, key, sub_rect, .. } => {
+                PrimitiveKeyKind::Image {
                     tile_spacing,
                     stretch_size,
                     key,
                     sub_rect,
                     image_rendering,
                     alpha_type,
-                    color: shadow.color,
+                    color: shadow.color.into(),
                 }
             }
-            PrimitiveContainer::Brush(..) |
-            PrimitiveContainer::ImageBorder { .. } |
-            PrimitiveContainer::YuvImage { .. } |
-            PrimitiveContainer::LinearGradient { .. } |
-            PrimitiveContainer::Clear => {
+            PrimitiveKeyKind::ImageBorder { .. } |
+            PrimitiveKeyKind::YuvImage { .. } |
+            PrimitiveKeyKind::LinearGradient { .. } |
+            PrimitiveKeyKind::RadialGradient { .. } |
+            PrimitiveKeyKind::Unused |
+            PrimitiveKeyKind::Clear => {
                 panic!("bug: this prim is not supported in shadow contexts");
             }
         }
     }
 }
 
-pub enum PrimitiveDetails {
-    Brush(BrushPrimitive),
-}
-
-pub struct Primitive {
-    pub local_rect: LayoutRect,
-    pub local_clip_rect: LayoutRect,
-    pub details: PrimitiveDetails,
-}
-
 /// Instance specific fields for an image primitive. These are
 /// currently stored in a separate array to avoid bloating the
 /// size of PrimitiveInstance. In the future, we should be able
 /// to remove this and store the information inline, by:
 /// (a) Removing opacity collapse / binding support completely.
 ///     Once we have general picture caching, we don't need this.
 /// (b) Change visible_tiles to use Storage in the primitive
 ///     scratch buffer. This will reduce the size of the
@@ -2536,21 +2329,16 @@ pub struct ImageInstance {
 pub struct PrimitiveDebugId(pub usize);
 
 #[derive(Clone, Debug)]
 pub enum PrimitiveInstanceKind {
     /// Direct reference to a Picture
     Picture {
         pic_index: PictureIndex,
     },
-    /// An old style, non-interned primitive. Uses prim_index to
-    /// access the primitive details in the prim_store.
-    LegacyPrimitive {
-        prim_index: PrimitiveIndex,
-    },
     /// A run of glyphs, with associated font parameters.
     TextRun {
         run_index: TextRunIndex,
     },
     /// A line decoration. cache_handle refers to a cached render
     /// task handle, if this line decoration is not a simple solid.
     LineDecoration {
         // TODO(gw): For now, we need to store some information in
@@ -2576,16 +2364,19 @@ pub enum PrimitiveInstanceKind {
         segment_instance_index: SegmentInstanceIndex,
     },
     Image {
         image_instance_index: ImageInstanceIndex,
     },
     LinearGradient {
         visible_tiles_range: GradientTileRange,
     },
+    RadialGradient {
+        visible_tiles_range: GradientTileRange,
+    },
     /// Clear out a rect, used for special effects.
     Clear,
 }
 
 #[derive(Clone, Debug)]
 pub struct PrimitiveInstance {
     /// Identifies the kind of primitive this
     /// instance is, and references to where
@@ -2752,75 +2543,76 @@ impl PrimitiveScratchBuffer {
         self.gradient_tiles.clear();
     }
 }
 
 #[cfg_attr(feature = "capture", derive(Serialize))]
 #[cfg_attr(feature = "replay", derive(Deserialize))]
 #[derive(Clone, Debug)]
 pub struct PrimitiveStoreStats {
-    primitive_count: usize,
     picture_count: usize,
     text_run_count: usize,
     opacity_binding_count: usize,
     image_count: usize,
 }
 
 impl PrimitiveStoreStats {
     pub fn empty() -> Self {
         PrimitiveStoreStats {
-            primitive_count: 0,
             picture_count: 0,
             text_run_count: 0,
             opacity_binding_count: 0,
             image_count: 0,
         }
     }
 }
 
 pub struct PrimitiveStore {
-    pub primitives: Vec<Primitive>,
     pub pictures: Vec<PicturePrimitive>,
     pub text_runs: TextRunStorage,
 
     /// A list of image instances. These are stored separately as
     /// storing them inline in the instance makes the structure bigger
     /// for other types.
     pub images: ImageInstanceStorage,
 
     /// List of animated opacity bindings for a primitive.
     pub opacity_bindings: OpacityBindingStorage,
+
+    /// Total count of primitive instances contained in pictures.
+    /// This is used for profile counters only.
+    pub prim_count: usize,
 }
 
 impl PrimitiveStore {
     pub fn new(stats: &PrimitiveStoreStats) -> PrimitiveStore {
         PrimitiveStore {
-            primitives: Vec::with_capacity(stats.primitive_count),
             pictures: Vec::with_capacity(stats.picture_count),
             text_runs: TextRunStorage::new(stats.text_run_count),
             images: ImageInstanceStorage::new(stats.image_count),
             opacity_bindings: OpacityBindingStorage::new(stats.opacity_binding_count),
+            prim_count: 0,
         }
     }
 
     pub fn get_stats(&self) -> PrimitiveStoreStats {
         PrimitiveStoreStats {
-            primitive_count: self.primitives.len(),
             picture_count: self.pictures.len(),
             text_run_count: self.text_runs.len(),
             image_count: self.images.len(),
             opacity_binding_count: self.opacity_bindings.len(),
         }
     }
 
     pub fn create_picture(
         &mut self,
         prim: PicturePrimitive,
     ) -> PictureIndex {
         let index = PictureIndex(self.pictures.len());
+        self.prim_count += prim.prim_list.prim_instances.len();
         self.pictures.push(prim);
         index
     }
 
     /// Update a picture, determining surface configuration,
     /// rasterization roots, and (in future) whether there
     /// are cached surfaces that can be used by this picture.
     pub fn update_picture(
@@ -2862,35 +2654,16 @@ impl PrimitiveStore {
                 children,
                 state,
                 frame_context,
                 resource_cache,
             );
         }
     }
 
-    pub fn add_primitive(
-        &mut self,
-        local_rect: &LayoutRect,
-        local_clip_rect: &LayoutRect,
-        details: PrimitiveDetails,
-    ) -> PrimitiveIndex {
-        let prim_index = self.primitives.len();
-
-        let prim = Primitive {
-            local_rect: *local_rect,
-            local_clip_rect: *local_clip_rect,
-            details,
-        };
-
-        self.primitives.push(prim);
-
-        PrimitiveIndex(prim_index)
-    }
-
     pub fn get_opacity_binding(
         &self,
         opacity_binding_index: OpacityBindingIndex,
     ) -> f32 {
         if opacity_binding_index == OpacityBindingIndex::INVALID {
             1.0
         } else {
             self.opacity_bindings[opacity_binding_index].current
@@ -2924,18 +2697,18 @@ impl PrimitiveStore {
             PrimitiveInstanceKind::Image { .. } => {
                 return Some(pic_index);
             }
             PrimitiveInstanceKind::Clear |
             PrimitiveInstanceKind::TextRun { .. } |
             PrimitiveInstanceKind::NormalBorder { .. } |
             PrimitiveInstanceKind::ImageBorder { .. } |
             PrimitiveInstanceKind::YuvImage { .. } |
-            PrimitiveInstanceKind::LegacyPrimitive { .. } |
             PrimitiveInstanceKind::LinearGradient { .. } |
+            PrimitiveInstanceKind::RadialGradient { .. } |
             PrimitiveInstanceKind::LineDecoration { .. } => {
                 // These prims don't support opacity collapse
             }
             PrimitiveInstanceKind::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
@@ -3006,29 +2779,24 @@ 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.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,
         prim_instance: &mut PrimitiveInstance,
         prim_context: &PrimitiveContext,
         pic_context: &PictureContext,
         pic_state: &mut PictureState,
         frame_context: &FrameBuildingContext,
         frame_state: &mut FrameBuildingState,
-        display_list: &BuiltDisplayList,
         plane_split_anchor: usize,
         resources: &mut FrameResources,
         scratch: &mut PrimitiveScratchBuffer,
     ) -> 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
@@ -3055,22 +2823,22 @@ impl PrimitiveStore {
 
                             return false;
                         }
                     }
                 }
                 PrimitiveInstanceKind::TextRun { .. } |
                 PrimitiveInstanceKind::Rectangle { .. } |
                 PrimitiveInstanceKind::LineDecoration { .. } |
-                PrimitiveInstanceKind::LegacyPrimitive { .. } |
                 PrimitiveInstanceKind::NormalBorder { .. } |
                 PrimitiveInstanceKind::ImageBorder { .. } |
                 PrimitiveInstanceKind::YuvImage { .. } |
                 PrimitiveInstanceKind::Image { .. } |
                 PrimitiveInstanceKind::LinearGradient { .. } |
+                PrimitiveInstanceKind::RadialGradient { .. } |
                 PrimitiveInstanceKind::Clear => {
                     None
                 }
             }
         };
 
         let (is_passthrough, clip_node_collector) = match pic_info {
             Some((pic_context_for_children, mut pic_state_for_children, mut prim_list)) => {
@@ -3116,25 +2884,22 @@ impl PrimitiveStore {
             PrimitiveInstanceKind::TextRun { .. } |
             PrimitiveInstanceKind::Clear |
             PrimitiveInstanceKind::NormalBorder { .. } |
             PrimitiveInstanceKind::ImageBorder { .. } |
             PrimitiveInstanceKind::Rectangle { .. } |
             PrimitiveInstanceKind::YuvImage { .. } |
             PrimitiveInstanceKind::Image { .. } |
             PrimitiveInstanceKind::LinearGradient { .. } |
+            PrimitiveInstanceKind::RadialGradient { .. } |
             PrimitiveInstanceKind::LineDecoration { .. } => {
                 let prim_data = &resources
                     .prim_data_store[prim_instance.prim_data_handle];
                 (prim_data.prim_rect, prim_data.clip_rect)
             }
-            PrimitiveInstanceKind::LegacyPrimitive { prim_index } => {
-                let prim = &self.primitives[prim_index.0];
-                (prim.local_rect, prim.local_clip_rect)
-            }
         };
 
         // TODO(gw): Eventually we can move all the code handling below for
         //           visibility and clip chain building to be done during the
         //           update_prim_dependencies pass. That will mean that:
         //           (a) We only do the work if the relative transforms change.
         //           (b) Local clip rects can reduce the # of tile dependencies.
 
@@ -3318,61 +3083,43 @@ impl PrimitiveStore {
             PrimitiveInstanceKind::TextRun { .. } |
             PrimitiveInstanceKind::Clear |
             PrimitiveInstanceKind::Rectangle { .. } |
             PrimitiveInstanceKind::NormalBorder { .. } |
             PrimitiveInstanceKind::ImageBorder { .. } |
             PrimitiveInstanceKind::YuvImage { .. } |
             PrimitiveInstanceKind::Image { .. } |
             PrimitiveInstanceKind::LinearGradient { .. } |
+            PrimitiveInstanceKind::RadialGradient { .. } |
             PrimitiveInstanceKind::LineDecoration { .. } => {
                 self.prepare_interned_prim_for_render(
                     prim_instance,
                     prim_context,
                     pic_context,
                     frame_context,
                     frame_state,
                     resources,
                     scratch,
                 );
             }
-            PrimitiveInstanceKind::LegacyPrimitive { prim_index } => {
-                let prim_details = &mut self.primitives[prim_index.0].details;
-
-                prim_instance.prepare_prim_for_render_inner(
-                    prim_local_rect,
-                    prim_details,
-                    prim_context,
-                    pic_context,
-                    frame_state,
-                    display_list,
-                    scratch,
-                );
-            }
         }
 
         true
     }
 
     pub fn prepare_primitives(
         &mut self,
         prim_list: &mut PrimitiveList,
         pic_context: &PictureContext,
         pic_state: &mut PictureState,
         frame_context: &FrameBuildingContext,
         frame_state: &mut FrameBuildingState,
         resources: &mut FrameResources,
         scratch: &mut PrimitiveScratchBuffer,
     ) {
-        let display_list = &frame_context
-            .pipelines
-            .get(&pic_context.pipeline_id)
-            .expect("No display list?")
-            .display_list;
-
         for (plane_split_anchor, prim_instance) in prim_list.prim_instances.iter_mut().enumerate() {
             prim_instance.bounding_rect = None;
 
             if prim_instance.is_chased() {
                 #[cfg(debug_assertions)]
                 println!("\tpreparing {:?} in {:?}",
                     prim_instance.id, pic_context.pipeline_id);
             }
@@ -3433,17 +3180,16 @@ impl PrimitiveStore {
 
             if self.prepare_prim_for_render(
                 prim_instance,
                 &prim_context,
                 pic_context,
                 pic_state,
                 frame_context,
                 frame_state,
-                display_list,
                 plane_split_anchor,
                 resources,
                 scratch,
             ) {
                 frame_state.profile_counters.visible_primitives.inc();
             }
         }
     }
@@ -3778,16 +3524,56 @@ impl PrimitiveStore {
                         prim_instance.bounding_rect = None;
                     }
                 }
 
                 // TODO(gw): Consider whether it's worth doing segment building
                 //           for gradient primitives.
                 SegmentInstanceIndex::UNUSED
             }
+            (
+                PrimitiveInstanceKind::RadialGradient { ref mut visible_tiles_range, .. },
+                PrimitiveTemplateKind::RadialGradient { ref params, extend_mode, stretch_size, tile_spacing, center, .. }
+            ) => {
+                if *tile_spacing != LayoutSize::zero() {
+                    *visible_tiles_range = decompose_repeated_primitive(
+                        &prim_instance.combined_local_clip_rect,
+                        &prim_data.prim_rect,
+                        &stretch_size,
+                        &tile_spacing,
+                        prim_context,
+                        frame_state,
+                        &pic_context.dirty_world_rect,
+                        &mut scratch.gradient_tiles,
+                        &mut |rect, mut request| {
+                            request.push([
+                                center.x,
+                                center.y,
+                                params.start_radius,
+                                params.end_radius,
+                            ]);
+                            request.push([
+                                params.ratio_xy,
+                                pack_as_float(*extend_mode as u32),
+                                stretch_size.width,
+                                stretch_size.height,
+                            ]);
+                            request.write_segment(*rect, [0.0; 4]);
+                        },
+                    );
+
+                    if visible_tiles_range.is_empty() {
+                        prim_instance.bounding_rect = None;
+                    }
+                }
+
+                // TODO(gw): Consider whether it's worth doing segment building
+                //           for gradient primitives.
+                SegmentInstanceIndex::UNUSED
+            }
             _ => {
                 unreachable!();
             }
         };
 
         debug_assert!(segment_instance_index != SegmentInstanceIndex::INVALID);
         if segment_instance_index != SegmentInstanceIndex::UNUSED {
             let segment_instance = &mut scratch.segment_instances[segment_instance_index];
@@ -4070,67 +3856,21 @@ impl PrimitiveInstance {
                 &mut image_instance.segment_instance_index
             }
             PrimitiveInstanceKind::Picture { .. } |
             PrimitiveInstanceKind::TextRun { .. } |
             PrimitiveInstanceKind::NormalBorder { .. } |
             PrimitiveInstanceKind::ImageBorder { .. } |
             PrimitiveInstanceKind::Clear |
             PrimitiveInstanceKind::LinearGradient { .. } |
+            PrimitiveInstanceKind::RadialGradient { .. } |
             PrimitiveInstanceKind::LineDecoration { .. } => {
                 // These primitives don't support / need segments.
                 return;
             }
-            PrimitiveInstanceKind::LegacyPrimitive { prim_index } => {
-                let prim = &mut prim_store.primitives[prim_index.0];
-                match prim.details {
-                    PrimitiveDetails::Brush(ref mut brush) => {
-                        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.
-                                let mut segments = BrushSegmentVec::new();
-
-                                if write_brush_segment_description(
-                                    prim_local_rect,
-                                    prim_local_clip_rect,
-                                    prim_clip_chain,
-                                    &mut frame_state.segment_builder,
-                                    frame_state.clip_store,
-                                    resources,
-                                ) {
-                                    frame_state.segment_builder.build(|segment| {
-                                        segments.push(
-                                            BrushSegment::new(
-                                                segment.rect,
-                                                segment.has_mask,
-                                                segment.edge_flags,
-                                                [0.0; 4],
-                                                BrushFlags::empty(),
-                                            ),
-                                        );
-                                    });
-                                }
-
-                                if !segments.is_empty() {
-                                    brush.segment_desc = Some(BrushSegmentDescriptor {
-                                        segments,
-                                    });
-                                }
-                            }
-                        }
-                    }
-                }
-
-                return;
-            }
         };
 
         if *segment_instance_index == SegmentInstanceIndex::INVALID {
             let mut segments: SmallVec<[BrushSegment; 8]> = SmallVec::new();
 
             if write_brush_segment_description(
                 prim_local_rect,
                 prim_local_clip_rect,
@@ -4260,28 +4000,31 @@ impl PrimitiveInstance {
 
                         brush_segments.as_slice()
                     }
                     _ => {
                         unreachable!();
                     }
                 }
             }
-            PrimitiveInstanceKind::LegacyPrimitive { prim_index } => {
-                let prim = &prim_store.primitives[prim_index.0];
-                match prim.details {
-                    PrimitiveDetails::Brush(ref brush) => {
-                        match brush.segment_desc {
-                            Some(ref description) => {
-                                &description.segments
-                            }
-                            None => {
-                                return false;
-                            }
+            PrimitiveInstanceKind::RadialGradient { .. } => {
+                let prim_data = &resources.prim_data_store[self.prim_data_handle];
+
+                // TODO: This is quite messy - once we remove legacy primitives we
+                //       can change this to be a tuple match on (instance, template)
+                match prim_data.kind {
+                    PrimitiveTemplateKind::RadialGradient { ref brush_segments, .. } => {
+                        if brush_segments.is_empty() {
+                            return false;
                         }
+
+                        brush_segments.as_slice()
+                    }
+                    _ => {
+                        unreachable!();
                     }
                 }
             }
         };
 
         // If there are no segments, early out to avoid setting a valid
         // clip task instance location below.
         if segments.is_empty() {
@@ -4344,111 +4087,16 @@ impl PrimitiveInstance {
                 );
                 scratch.clip_mask_instances.push(clip_mask_kind);
             }
         }
 
         true
     }
 
-    fn prepare_prim_for_render_inner(
-        &mut self,
-        prim_local_rect: LayoutRect,
-        prim_details: &mut PrimitiveDetails,
-        prim_context: &PrimitiveContext,
-        pic_context: &PictureContext,
-        frame_state: &mut FrameBuildingState,
-        display_list: &BuiltDisplayList,
-        scratch: &mut PrimitiveScratchBuffer,
-    ) {
-        let mut is_tiled = false;
-
-        match *prim_details {
-            PrimitiveDetails::Brush(ref mut brush) => {
-                brush.opacity = match brush.kind {
-                    BrushKind::RadialGradient {
-                        stops_range,
-                        center,
-                        start_radius,
-                        end_radius,
-                        ratio_xy,
-                        extend_mode,
-                        stretch_size,
-                        tile_spacing,
-                        ref mut stops_handle,
-                        ref mut visible_tiles_range,
-                        ..
-                    } => {
-                        if let Some(mut request) = frame_state.gpu_cache.request(stops_handle) {
-                            let src_stops = display_list.get(stops_range);
-
-                            GradientGpuBlockBuilder::build(
-                                false,
-                                &mut request,
-                                src_stops,
-                            );
-                        }
-
-                        if tile_spacing != LayoutSize::zero() {
-                            is_tiled = true;
-
-                            *visible_tiles_range = decompose_repeated_primitive(
-                                &self.combined_local_clip_rect,
-                                &prim_local_rect,
-                                &stretch_size,
-                                &tile_spacing,
-                                prim_context,
-                                frame_state,
-                                &pic_context.dirty_world_rect,
-                                &mut scratch.gradient_tiles,
-                                &mut |rect, mut request| {
-                                    request.push([
-                                        center.x,
-                                        center.y,
-                                        start_radius,
-                                        end_radius,
-                                    ]);
-                                    request.push([
-                                        ratio_xy,
-                                        pack_as_float(extend_mode as u32),
-                                        stretch_size.width,
-                                        stretch_size.height,
-                                    ]);
-                                    request.write_segment(*rect, [0.0; 4]);
-                                },
-                            );
-
-                            if visible_tiles_range.is_empty() {
-                                self.bounding_rect = None;
-                            }
-                        }
-
-                        //TODO: can we make it opaque in some cases?
-                        PrimitiveOpacity::translucent()
-                    }
-                };
-            }
-        }
-
-        if is_tiled {
-            // we already requested each tile's gpu data.
-            return;
-        }
-
-        // Mark this GPU resource as required for this frame.
-        match *prim_details {
-            PrimitiveDetails::Brush(ref mut brush) => {
-                brush.write_gpu_blocks_if_required(
-                    prim_local_rect,
-                    frame_state.gpu_cache,
-                );
-            }
-        }
-    }
-
     fn update_clip_task(
         &mut self,
         prim_local_rect: LayoutRect,
         prim_local_clip_rect: LayoutRect,
         prim_context: &PrimitiveContext,
         prim_bounding_rect: WorldRect,
         root_spatial_node_index: SpatialNodeIndex,
         clip_chain: &ClipChainInstance,
@@ -4561,17 +4209,17 @@ pub fn get_raster_rects(
         device_pixel_scale,
     );
 
     Some((clipped.to_i32(), unclipped))
 }
 
 /// Get the inline (horizontal) and block (vertical) sizes
 /// for a given line decoration.
-fn get_line_decoration_sizes(
+pub fn get_line_decoration_sizes(
     rect_size: &LayoutSize,
     orientation: LineOrientation,
     style: LineStyle,
     wavy_line_thickness: f32,
 ) -> Option<(f32, f32)> {
     let h = match orientation {
         LineOrientation::Horizontal => rect_size.height,
         LineOrientation::Vertical => rect_size.width,
@@ -4627,17 +4275,15 @@ fn update_opacity_binding(
 #[cfg(target_os = "linux")]
 fn test_struct_sizes() {
     // The sizes of these structures are critical for performance on a number of
     // talos stress tests. If you get a failure here on CI, there's two possibilities:
     // (a) You made a structure smaller than it currently is. Great work! Update the
     //     test expectations and move on.
     // (b) You made a structure larger. This is not necessarily a problem, but should only
     //     be done with care, and after checking if talos performance regresses badly.
-    assert_eq!(mem::size_of::<PrimitiveContainer>(), 176, "PrimitiveContainer size changed");
     assert_eq!(mem::size_of::<PrimitiveInstance>(), 120, "PrimitiveInstance size changed");
     assert_eq!(mem::size_of::<PrimitiveInstanceKind>(), 16, "PrimitiveInstanceKind size changed");
     assert_eq!(mem::size_of::<PrimitiveTemplate>(), 176, "PrimitiveTemplate size changed");
     assert_eq!(mem::size_of::<PrimitiveTemplateKind>(), 112, "PrimitiveTemplateKind size changed");
     assert_eq!(mem::size_of::<PrimitiveKey>(), 152, "PrimitiveKey size changed");
     assert_eq!(mem::size_of::<PrimitiveKeyKind>(), 112, "PrimitiveKeyKind size changed");
-    assert_eq!(mem::size_of::<Primitive>(), 200, "Primitive size changed");
 }
--- a/gfx/wr/webrender/src/render_backend.rs
+++ b/gfx/wr/webrender/src/render_backend.rs
@@ -44,17 +44,16 @@ use scene_builder::*;
 #[cfg(feature = "serialize")]
 use serde::{Serialize, Deserialize};
 #[cfg(feature = "debugger")]
 use serde_json;
 #[cfg(any(feature = "capture", feature = "replay"))]
 use std::path::PathBuf;
 use std::sync::atomic::{AtomicUsize, Ordering};
 use std::mem::replace;
-use std::os::raw::c_void;
 use std::sync::mpsc::{channel, Sender, Receiver};
 use std::time::{UNIX_EPOCH, SystemTime};
 use std::u32;
 #[cfg(feature = "replay")]
 use tiling::Frame;
 use time::precise_time_ns;
 use util::drain_filter;
 
@@ -1364,28 +1363,22 @@ impl RenderBackend {
             doc.clip_scroll_tree.print_with(&mut builder);
 
             debug_root.add(builder.build());
         }
 
         serde_json::to_string(&debug_root).unwrap()
     }
 
-    fn size_of<T>(&self, ptr: *const T) -> usize {
-        let op = self.size_of_op.as_ref().unwrap();
-        unsafe { op(ptr as *const c_void) }
-    }
-
     fn report_memory(&self) -> MemoryReport {
         let mut report = MemoryReport::default();
         let op = self.size_of_op.unwrap();
         report.gpu_cache_metadata = self.gpu_cache.malloc_size_of(op);
         for (_id, doc) in &self.documents {
             if let Some(ref fb) = doc.frame_builder {
-                report.primitive_stores += self.size_of(fb.prim_store.primitives.as_ptr());
                 report.clip_stores += fb.clip_store.malloc_size_of(op);
             }
             report.hit_testers +=
                 doc.hit_tester.as_ref().map_or(0, |ht| ht.malloc_size_of(op));
         }
 
         report += self.resource_cache.report_memory(op);
 
--- a/gfx/wr/webrender/src/surface.rs
+++ b/gfx/wr/webrender/src/surface.rs
@@ -231,24 +231,24 @@ impl SurfaceDescriptor {
 
                 clip_chain_id = clip_chain_node.parent_clip_chain_id;
             }
 
             // For now, we only handle interned primitives. If we encounter
             // a legacy primitive or picture, then fail to create a cache
             // descriptor.
             match prim_instance.kind {
-                PrimitiveInstanceKind::Picture { .. } |
-                PrimitiveInstanceKind::LegacyPrimitive { .. } => {
+                PrimitiveInstanceKind::Picture { .. } => {
                     return None;
                 }
                 PrimitiveInstanceKind::Image { .. } |
                 PrimitiveInstanceKind::YuvImage { .. } |
                 PrimitiveInstanceKind::LineDecoration { .. } |
                 PrimitiveInstanceKind::LinearGradient { .. } |
+                PrimitiveInstanceKind::RadialGradient { .. } |
                 PrimitiveInstanceKind::TextRun { .. } |
                 PrimitiveInstanceKind::NormalBorder { .. } |
                 PrimitiveInstanceKind::Rectangle { .. } |
                 PrimitiveInstanceKind::ImageBorder { .. } |
                 PrimitiveInstanceKind::Clear => {}
             }
 
             // Record the unique identifier for the content represented
--- a/gfx/wr/webrender_api/src/display_item.rs
+++ b/gfx/wr/webrender_api/src/display_item.rs
@@ -269,26 +269,16 @@ pub struct NormalBorder {
     /// Whether to apply anti-aliasing on the border corners.
     ///
     /// Note that for this to be `false` and work, this requires the borders to
     /// be solid, and no border-radius.
     pub do_aa: bool,
 }
 
 impl NormalBorder {
-    // Construct a border based upon self with color
-    pub fn with_color(&self, color: ColorF) -> Self {
-        let mut b = *self;
-        b.left.color = color;
-        b.right.color = color;
-        b.top.color = color;
-        b.bottom.color = color;
-        b
-    }
-
     fn can_disable_antialiasing(&self) -> bool {
         fn is_valid(style: BorderStyle) -> bool {
             style == BorderStyle::Solid || style == BorderStyle::None
         }
 
         self.radius.is_zero() &&
             is_valid(self.top.style) &&
             is_valid(self.left.style) &&
@@ -458,17 +448,17 @@ pub struct BoxShadowDisplayItem {
 #[repr(C)]
 #[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)]
 pub struct Shadow {
     pub offset: LayoutVector2D,
     pub color: ColorF,
     pub blur_radius: f32,
 }
 
-#[repr(u32)]
+#[repr(u8)]
 #[derive(Debug, Copy, Clone, Hash, Eq, PartialEq, Serialize, Deserialize, Ord, PartialOrd)]
 pub enum ExtendMode {
     Clamp,
     Repeat,
 }
 
 #[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)]
 pub struct Gradient {
index 01a551e6ead1c5d43fa15fc08524eaf853976237..9a4462c7afaf9798ed624b49910ee37dfc2bbe3a
GIT binary patch
literal 27094
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