Bug 1361751 - Update webrender to 964df2f. r=jrmuizel
authorKartikaya Gupta <kgupta@mozilla.com>
Wed, 10 May 2017 10:28:39 -0400
changeset 359297 9d9046d172d6204b2e7b0c3453ba6c045dd4c9fd
parent 359296 c509185bf7e5f29f4685b4f3d8d4467581b49cfa
child 359298 b84bdb44e96b3eec386ff5a0d2699f9698ca4dc1
push id31852
push userkwierso@gmail.com
push dateFri, 19 May 2017 21:47:27 +0000
treeherdermozilla-central@979f11deabd0 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjrmuizel
bugs1361751
milestone55.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 1361751 - Update webrender to 964df2f. r=jrmuizel This includes the Cargo.lock file changes and regenerated bindings.
gfx/doc/README.webrender
gfx/webrender/doc/CLIPPING.md
gfx/webrender/examples/basic.rs
gfx/webrender/examples/blob.rs
gfx/webrender/examples/scrolling.rs
gfx/webrender/examples/yuv.rs
gfx/webrender/src/frame.rs
gfx/webrender/src/frame_builder.rs
gfx/webrender/src/mask_cache.rs
gfx/webrender/src/prim_store.rs
gfx/webrender/src/render_backend.rs
gfx/webrender/src/scene.rs
gfx/webrender/src/tiling.rs
gfx/webrender_bindings/webrender_ffi_generated.h
gfx/webrender_traits/Cargo.toml
gfx/webrender_traits/src/api.rs
gfx/webrender_traits/src/channel.rs
gfx/webrender_traits/src/display_item.rs
gfx/webrender_traits/src/display_list.rs
gfx/webrender_traits/src/lib.rs
toolkit/library/gtest/rust/Cargo.lock
toolkit/library/rust/Cargo.lock
--- a/gfx/doc/README.webrender
+++ b/gfx/doc/README.webrender
@@ -74,9 +74,9 @@ there is another crate in m-c called moz
 the same folder to store its rust dependencies. If one of the libraries that is
 required by both mozjs_sys and webrender is updated without updating the other
 project's Cargo.lock file, that results in build bustage.
 This means that any time you do this sort of manual update of packages, you need
 to make sure that mozjs_sys also has its Cargo.lock file updated if needed, hence
 the need to run the cargo update command in js/src as well. Hopefully this will
 be resolved soon.
 
-Latest Commit: 8516d6c04235e684d9bf9c783ba4fc99dab3bf02
+Latest Commit: 964df2fa00f330daf4f233669e37133f93113792
--- a/gfx/webrender/doc/CLIPPING.md
+++ b/gfx/webrender/doc/CLIPPING.md
@@ -7,17 +7,17 @@ and can be reused between items as well 
 
 ## Clips
 
 Clips are defined using the ClipRegion in both cases.
 
 ```rust
 pub struct ClipRegion {
     pub main: LayoutRect,
-    pub complex: ItemRange,
+    pub complex: ItemRange<ComplexClip>,
     pub image_mask: Option<ImageMask>,
 }
 ```
 
 `main` defines a rectangular clip, while the other members make that rectangle
 smaller. `complex`, if it is not empty, defines the boundaries of a rounded
 rectangle. While `image_mask` defines the positioning, repetition, and data of
 a masking image.
--- a/gfx/webrender/examples/basic.rs
+++ b/gfx/webrender/examples/basic.rs
@@ -12,20 +12,20 @@ extern crate webrender_traits;
 use app_units::Au;
 use gleam::gl;
 use glutin::TouchPhase;
 use std::collections::HashMap;
 use std::env;
 use std::fs::File;
 use std::io::Read;
 use std::path::PathBuf;
-use webrender_traits::{ColorF, Epoch, GlyphInstance};
+use webrender_traits::{ClipRegionToken, ColorF, DisplayListBuilder, Epoch, GlyphInstance};
 use webrender_traits::{DeviceIntPoint, DeviceUintSize, LayoutPoint, LayoutRect, LayoutSize};
 use webrender_traits::{ImageData, ImageDescriptor, ImageFormat};
-use webrender_traits::{PipelineId, TransformStyle, BoxShadowClipMode};
+use webrender_traits::{PipelineId, RenderApi, TransformStyle, BoxShadowClipMode};
 
 #[derive(Debug)]
 enum Gesture {
     None,
     Pan,
     Zoom,
 }
 
@@ -186,16 +186,36 @@ impl webrender_traits::RenderNotifier fo
     }
 
     fn new_scroll_frame_ready(&mut self, _composite_needed: bool) {
         #[cfg(not(target_os = "android"))]
         self.window_proxy.wakeup_event_loop();
     }
 }
 
+fn push_sub_clip(api: &RenderApi, builder: &mut DisplayListBuilder, bounds: &LayoutRect)
+                 -> ClipRegionToken {
+    let mask_image = api.generate_image_key();
+    api.add_image(mask_image,
+                  ImageDescriptor::new(2, 2, ImageFormat::A8, true),
+                  ImageData::new(vec![0, 80, 180, 255]),
+                  None);
+    let mask = webrender_traits::ImageMask {
+        image: mask_image,
+        rect: LayoutRect::new(LayoutPoint::new(75.0, 75.0), LayoutSize::new(100.0, 100.0)),
+        repeat: false,
+    };
+    let complex = webrender_traits::ComplexClipRegion::new(
+        LayoutRect::new(LayoutPoint::new(50.0, 50.0), LayoutSize::new(100.0, 100.0)),
+        webrender_traits::BorderRadius::uniform(20.0));
+
+    builder.push_clip_region(bounds, vec![complex], Some(mask))
+}
+
+
 fn main() {
     let args: Vec<String> = env::args().collect();
     let res_path = if args.len() > 1 {
         Some(PathBuf::from(&args[1]))
     } else {
         None
     };
 
@@ -247,41 +267,25 @@ fn main() {
     let bounds = LayoutRect::new(LayoutPoint::zero(), LayoutSize::new(width as f32, height as f32));
     builder.push_stacking_context(webrender_traits::ScrollPolicy::Scrollable,
                                   bounds,
                                   None,
                                   TransformStyle::Flat,
                                   None,
                                   webrender_traits::MixBlendMode::Normal,
                                   Vec::new());
-    let sub_clip = {
-        let mask_image = api.generate_image_key();
-        api.add_image(
-            mask_image,
-            ImageDescriptor::new(2, 2, ImageFormat::A8, true),
-            ImageData::new(vec![0, 80, 180, 255]),
-            None,
-        );
-        let mask = webrender_traits::ImageMask {
-            image: mask_image,
-            rect: LayoutRect::new(LayoutPoint::new(75.0, 75.0), LayoutSize::new(100.0, 100.0)),
-            repeat: false,
-        };
-        let complex = webrender_traits::ComplexClipRegion::new(
-            LayoutRect::new(LayoutPoint::new(50.0, 50.0), LayoutSize::new(100.0, 100.0)),
-            webrender_traits::BorderRadius::uniform(20.0));
 
-        builder.new_clip_region(&bounds, vec![complex], Some(mask))
-    };
-
+    let clip = push_sub_clip(&api, &mut builder, &bounds);
     builder.push_rect(LayoutRect::new(LayoutPoint::new(100.0, 100.0), LayoutSize::new(100.0, 100.0)),
-                      sub_clip,
+                      clip,
                       ColorF::new(0.0, 1.0, 0.0, 1.0));
+
+    let clip = push_sub_clip(&api, &mut builder, &bounds);
     builder.push_rect(LayoutRect::new(LayoutPoint::new(250.0, 100.0), LayoutSize::new(100.0, 100.0)),
-                      sub_clip,
+                      clip,
                       ColorF::new(0.0, 1.0, 0.0, 1.0));
     let border_side = webrender_traits::BorderSide {
         color: ColorF::new(0.0, 0.0, 1.0, 1.0),
         style: webrender_traits::BorderStyle::Groove,
     };
     let border_widths = webrender_traits::BorderWidths {
         top: 10.0,
         left: 10.0,
@@ -290,18 +294,20 @@ fn main() {
     };
     let border_details = webrender_traits::BorderDetails::Normal(webrender_traits::NormalBorder {
         top: border_side,
         right: border_side,
         bottom: border_side,
         left: border_side,
         radius: webrender_traits::BorderRadius::uniform(20.0),
     });
+
+    let clip = push_sub_clip(&api, &mut builder, &bounds);
     builder.push_border(LayoutRect::new(LayoutPoint::new(100.0, 100.0), LayoutSize::new(100.0, 100.0)),
-                        sub_clip,
+                        clip,
                         border_widths,
                         border_details);
 
 
     if false { // draw text?
         let font_key = api.generate_font_key();
         let font_bytes = load_file("res/FreeSans.ttf");
         api.add_raw_font(font_key, font_bytes, 0);
@@ -354,18 +360,19 @@ fn main() {
                 point: LayoutPoint::new(600.0, 100.0),
             },
             GlyphInstance {
                 index: 17,
                 point: LayoutPoint::new(650.0, 100.0),
             },
         ];
 
+        let clip = builder.push_clip_region(&bounds, Vec::new(), None);
         builder.push_text(text_bounds,
-                          webrender_traits::ClipRegion::simple(&bounds),
+                          clip,
                           &glyphs,
                           font_key,
                           ColorF::new(1.0, 1.0, 0.0, 1.0),
                           Au::from_px(32),
                           Au::from_px(0),
                           None);
     }
 
@@ -374,17 +381,17 @@ fn main() {
         let simple_box_bounds = LayoutRect::new(LayoutPoint::new(20.0, 200.0),
                                                 LayoutSize::new(50.0, 50.0));
         let offset = LayoutPoint::new(10.0, 10.0);
         let color = ColorF::new(1.0, 1.0, 1.0, 1.0);
         let blur_radius = 0.0;
         let spread_radius = 0.0;
         let simple_border_radius = 8.0;
         let box_shadow_type = BoxShadowClipMode::Inset;
-        let full_screen_clip = builder.new_clip_region(&bounds, Vec::new(), None);
+        let full_screen_clip = builder.push_clip_region(&bounds, Vec::new(), None);
 
         builder.push_box_shadow(rect,
                                 full_screen_clip,
                                 simple_box_bounds,
                                 offset,
                                 color,
                                 blur_radius,
                                 spread_radius,
--- a/gfx/webrender/examples/blob.rs
+++ b/gfx/webrender/examples/blob.rs
@@ -7,17 +7,17 @@ extern crate euclid;
 extern crate gleam;
 extern crate glutin;
 extern crate webrender;
 extern crate webrender_traits;
 
 use gleam::gl;
 use std::collections::HashMap;
 use webrender_traits::{BlobImageData, BlobImageDescriptor, BlobImageError, BlobImageRenderer, BlobImageRequest};
-use webrender_traits::{BlobImageResult, ImageStore, ClipRegion, ColorF, ColorU, Epoch};
+use webrender_traits::{BlobImageResult, ImageStore, ColorF, ColorU, Epoch};
 use webrender_traits::{DeviceUintSize, DeviceUintRect, LayoutPoint, LayoutRect, LayoutSize};
 use webrender_traits::{ImageData, ImageDescriptor, ImageFormat, ImageRendering, ImageKey, TileSize};
 use webrender_traits::{PipelineId, RasterizedBlobImage, TransformStyle};
 
 // This example shows how to implement a very basic BlobImageRenderer that can only render
 // a checkerboard pattern.
 
 // The deserialized command list internally used by this example is just a color.
@@ -199,28 +199,31 @@ fn main() {
     let bounds = LayoutRect::new(LayoutPoint::zero(), LayoutSize::new(width as f32, height as f32));
     builder.push_stacking_context(webrender_traits::ScrollPolicy::Scrollable,
                                   bounds,
                                   None,
                                   TransformStyle::Flat,
                                   None,
                                   webrender_traits::MixBlendMode::Normal,
                                   Vec::new());
+
+    let clip = builder.push_clip_region(&bounds, vec![], None);
     builder.push_image(
         LayoutRect::new(LayoutPoint::new(30.0, 30.0), LayoutSize::new(500.0, 500.0)),
-        ClipRegion::simple(&bounds),
+        clip,
         LayoutSize::new(500.0, 500.0),
         LayoutSize::new(0.0, 0.0),
         ImageRendering::Auto,
         blob_img1,
     );
 
+    let clip = builder.push_clip_region(&bounds, vec![], None);
     builder.push_image(
         LayoutRect::new(LayoutPoint::new(600.0, 60.0), LayoutSize::new(200.0, 200.0)),
-        ClipRegion::simple(&bounds),
+        clip,
         LayoutSize::new(200.0, 200.0),
         LayoutSize::new(0.0, 0.0),
         ImageRendering::Auto,
         blob_img2,
     );
 
     builder.pop_stacking_context();
 
--- a/gfx/webrender/examples/scrolling.rs
+++ b/gfx/webrender/examples/scrolling.rs
@@ -5,17 +5,17 @@
 extern crate gleam;
 extern crate glutin;
 extern crate webrender;
 extern crate webrender_traits;
 
 use gleam::gl;
 use std::env;
 use std::path::PathBuf;
-use webrender_traits::{ClipId, ClipRegion, ColorF, DeviceUintSize, Epoch, LayoutPoint, LayoutRect};
+use webrender_traits::{ClipId, ColorF, DeviceUintSize, Epoch, LayoutPoint, LayoutRect};
 use webrender_traits::{LayoutSize, PipelineId, ScrollEventPhase, ScrollLocation, TransformStyle};
 use webrender_traits::WorldPoint;
 
 struct Notifier {
     window_proxy: glutin::WindowProxy,
 }
 
 impl Notifier {
@@ -118,57 +118,65 @@ fn main() {
                                       LayoutRect::new(LayoutPoint::new(10.0, 10.0),
                                                       LayoutSize::zero()),
                                       None,
                                       TransformStyle::Flat,
                                       None,
                                       webrender_traits::MixBlendMode::Normal,
                                       Vec::new());
         // set the scrolling clip
+        let clip = builder.push_clip_region(&scrollbox, vec![], None);
         let clip_id = builder.define_clip((0, 0).to(1000, 1000),
-                                          ClipRegion::simple(&scrollbox),
+                                          clip,
                                           Some(ClipId::new(42, pipeline_id)));
         builder.push_clip_id(clip_id);
         // now put some content into it.
         // start with a white background
+        let clip = builder.push_clip_region(&(0, 0).to(1000, 1000), vec![], None);
         builder.push_rect((0, 0).to(500, 500),
-                          ClipRegion::simple(&(0, 0).to(1000, 1000)),
+                          clip,
                           ColorF::new(1.0, 1.0, 1.0, 1.0));
         // let's make a 50x50 blue square as a visual reference
+        let clip = builder.push_clip_region(&(0, 0).to(50, 50), vec![], None);
         builder.push_rect((0, 0).to(50, 50),
-                          ClipRegion::simple(&(0, 0).to(50, 50)),
+                          clip,
                           ColorF::new(0.0, 0.0, 1.0, 1.0));
         // and a 50x50 green square next to it with an offset clip
         // to see what that looks like
+        let clip = builder.push_clip_region(&(60, 10).to(110, 60), vec![], None);
         builder.push_rect((50, 0).to(100, 50),
-                          ClipRegion::simple(&(60, 10).to(110, 60)),
+                          clip,
                           ColorF::new(0.0, 1.0, 0.0, 1.0));
 
         // Below the above rectangles, set up a nested scrollbox. It's still in
         // the same stacking context, so note that the rects passed in need to
         // be relative to the stacking context.
+        let clip = builder.push_clip_region(&(0, 100).to(200, 300), vec![], None);
         let nested_clip_id = builder.define_clip((0, 100).to(300, 400),
-                                                 ClipRegion::simple(&(0, 100).to(200, 300)),
+                                                 clip,
                                                  Some(ClipId::new(43, pipeline_id)));
         builder.push_clip_id(nested_clip_id);
         // give it a giant gray background just to distinguish it and to easily
         // visually identify the nested scrollbox
+        let clip = builder.push_clip_region(&(-1000, -1000).to(5000, 5000), vec![], None);
         builder.push_rect((-1000, -1000).to(5000, 5000),
-                          ClipRegion::simple(&(-1000, -1000).to(5000, 5000)),
+                          clip,
                           ColorF::new(0.5, 0.5, 0.5, 1.0));
         // add a teal square to visualize the scrolling/clipping behaviour
         // as you scroll the nested scrollbox with WASD keys
+        let clip = builder.push_clip_region(&(0, 100).to(50, 150), vec![], None);
         builder.push_rect((0, 100).to(50, 150),
-                          ClipRegion::simple(&(0, 100).to(50, 150)),
+                          clip,
                           ColorF::new(0.0, 1.0, 1.0, 1.0));
         // just for good measure add another teal square in the bottom-right
         // corner of the nested scrollframe content, which can be scrolled into
         // view by the user
+        let clip = builder.push_clip_region(&(250, 350).to(300, 400), vec![], None);
         builder.push_rect((250, 350).to(300, 400),
-                          ClipRegion::simple(&(250, 350).to(300, 400)),
+                          clip,
                           ColorF::new(0.0, 1.0, 1.0, 1.0));
         builder.pop_clip_id(); // nested_clip_id
 
         builder.pop_clip_id(); // clip_id
         builder.pop_stacking_context();
     }
 
     builder.pop_stacking_context();
--- a/gfx/webrender/examples/yuv.rs
+++ b/gfx/webrender/examples/yuv.rs
@@ -9,17 +9,17 @@ extern crate glutin;
 extern crate webrender;
 extern crate webrender_traits;
 
 use gleam::gl;
 use glutin::TouchPhase;
 use std::collections::HashMap;
 use std::env;
 use std::path::PathBuf;
-use webrender_traits::{ClipRegion, ColorF, Epoch};
+use webrender_traits::{ColorF, Epoch};
 use webrender_traits::{DeviceIntPoint, DeviceUintSize, LayoutPoint, LayoutRect, LayoutSize};
 use webrender_traits::{ImageData, ImageDescriptor, ImageFormat};
 use webrender_traits::{PipelineId, TransformStyle};
 use webrender_traits::{YuvColorSpace, YuvData};
 
 #[derive(Debug)]
 enum Gesture {
     None,
@@ -270,26 +270,28 @@ fn main() {
     );
     api.add_image(
         yuv_chanel3,
         ImageDescriptor::new(100, 100, ImageFormat::A8, true),
         ImageData::new(vec![127; 100 * 100]),
         None,
     );
 
+    let clip = builder.push_clip_region(&bounds, vec![], None);
     builder.push_yuv_image(
         LayoutRect::new(LayoutPoint::new(100.0, 0.0), LayoutSize::new(100.0, 100.0)),
-        ClipRegion::simple(&bounds),
+        clip,
         YuvData::NV12(yuv_chanel1, yuv_chanel2),
         YuvColorSpace::Rec601,
     );
 
+    let clip = builder.push_clip_region(&bounds, vec![], None);
     builder.push_yuv_image(
         LayoutRect::new(LayoutPoint::new(300.0, 0.0), LayoutSize::new(100.0, 100.0)),
-        ClipRegion::simple(&bounds),
+        clip,
         YuvData::PlanarYCbCr(yuv_chanel1, yuv_chanel2_1, yuv_chanel3),
         YuvColorSpace::Rec601,
     );
 
     builder.pop_stacking_context();
 
     api.set_display_list(
         Some(root_background_color),
--- a/gfx/webrender/src/frame.rs
+++ b/gfx/webrender/src/frame.rs
@@ -10,22 +10,22 @@ use internal_types::{LowLevelFilterOp};
 use internal_types::{RendererFrame};
 use frame_builder::{FrameBuilder, FrameBuilderConfig};
 use clip_scroll_tree::{ClipScrollTree, ScrollStates};
 use profiler::TextureCacheProfileCounters;
 use resource_cache::ResourceCache;
 use scene::{Scene, SceneProperties};
 use std::collections::HashMap;
 use std::hash::BuildHasherDefault;
-use tiling::{AuxiliaryListsMap, CompositeOps, PrimitiveFlags};
+use tiling::{CompositeOps, DisplayListMap, PrimitiveFlags};
 use util::{ComplexClipRegionHelpers, subtract_rect};
-use webrender_traits::{AuxiliaryLists, ClipAndScrollInfo, ClipDisplayItem, ClipId, ClipRegion};
-use webrender_traits::{ColorF, DeviceUintRect, DeviceUintSize, DisplayItem, Epoch, FilterOp};
-use webrender_traits::{ImageDisplayItem, LayerPoint, LayerRect, LayerSize, LayerToScrollTransform};
-use webrender_traits::{LayoutRect, LayoutTransform, MixBlendMode, PipelineId, ScrollEventPhase};
+use webrender_traits::{BuiltDisplayList, BuiltDisplayListIter, ClipAndScrollInfo, ClipDisplayItem};
+use webrender_traits::{ClipId, ClipRegion, ColorF, DeviceUintRect, DeviceUintSize, Epoch, FilterOp};
+use webrender_traits::{ImageDisplayItem, ItemRange, LayerPoint, LayerRect, LayerSize, LayerToScrollTransform};
+use webrender_traits::{LayoutTransform, MixBlendMode, PipelineId, ScrollEventPhase};
 use webrender_traits::{ScrollLayerState, ScrollLocation, ScrollPolicy, SpecificDisplayItem};
 use webrender_traits::{StackingContext, TileOffset, WorldPoint};
 
 #[derive(Copy, Clone, PartialEq, PartialOrd, Debug)]
 pub struct FrameId(pub u32);
 
 static DEFAULT_SCROLLBAR_COLOR: ColorF = ColorF { r: 0.3, g: 0.3, b: 0.3, a: 0.6 };
 
@@ -61,52 +61,39 @@ impl<'a> FlattenContext<'a> {
 pub struct Frame {
     pub clip_scroll_tree: ClipScrollTree,
     pub pipeline_epoch_map: HashMap<PipelineId, Epoch, BuildHasherDefault<FnvHasher>>,
     id: FrameId,
     frame_builder_config: FrameBuilderConfig,
     frame_builder: Option<FrameBuilder>,
 }
 
-trait DisplayListHelpers {
-    fn starting_stacking_context<'a>(&'a self) -> Option<(&'a StackingContext, &'a LayoutRect)>;
-}
-
-impl DisplayListHelpers for Vec<DisplayItem> {
-    fn starting_stacking_context<'a>(&'a self) -> Option<(&'a StackingContext, &'a LayoutRect)> {
-        self.first().and_then(|item| match item.item {
-            SpecificDisplayItem::PushStackingContext(ref specific_item) => {
-                Some((&specific_item.stacking_context, &item.rect))
-            },
-            _ => None,
-        })
-    }
-}
-
 trait StackingContextHelpers {
     fn mix_blend_mode_for_compositing(&self) -> Option<MixBlendMode>;
     fn filter_ops_for_compositing(&self,
-                                  auxiliary_lists: &AuxiliaryLists,
+                                  display_list: &BuiltDisplayList,
+                                  input_filters: ItemRange<FilterOp>,
                                   properties: &SceneProperties) -> Vec<LowLevelFilterOp>;
 }
 
 impl StackingContextHelpers for StackingContext {
     fn mix_blend_mode_for_compositing(&self) -> Option<MixBlendMode> {
         match self.mix_blend_mode {
             MixBlendMode::Normal => None,
             _ => Some(self.mix_blend_mode),
         }
     }
 
     fn filter_ops_for_compositing(&self,
-                                  auxiliary_lists: &AuxiliaryLists,
+                                  display_list: &BuiltDisplayList,
+                                  input_filters: ItemRange<FilterOp>,
                                   properties: &SceneProperties) -> Vec<LowLevelFilterOp> {
         let mut filters = vec![];
-        for filter in auxiliary_lists.filters(&self.filters) {
-            match *filter {
+        for filter in display_list.get(input_filters) {
+            match filter {
                 FilterOp::Blur(radius) => {
                     filters.push(LowLevelFilterOp::Blur(
                         radius,
                         AxisDirection::Horizontal));
                     filters.push(LowLevelFilterOp::Blur(
                         radius,
                         AxisDirection::Vertical));
                 }
@@ -145,81 +132,26 @@ impl StackingContextHelpers for Stacking
                             LowLevelFilterOp::Sepia(Au::from_f32_px(amount)));
                 }
             }
         }
         filters
     }
 }
 
-struct DisplayListTraversal<'a> {
-    pub display_list: &'a [DisplayItem],
-    pub next_item_index: usize,
-}
-
-impl<'a> DisplayListTraversal<'a> {
-    pub fn new_skipping_first(display_list: &'a Vec<DisplayItem>) -> DisplayListTraversal {
-        DisplayListTraversal {
-            display_list: display_list,
-            next_item_index: 1,
-        }
-    }
-
-    pub fn skip_current_stacking_context(&mut self) {
-        let mut depth = 0;
-        for item in self {
-            match item.item {
-                SpecificDisplayItem::PushStackingContext(..) => depth += 1,
-                SpecificDisplayItem::PopStackingContext if depth == 0 => return,
-                SpecificDisplayItem::PopStackingContext => depth -= 1,
-                _ => {}
-            }
-            debug_assert!(depth >= 0);
-        }
-    }
-
-    pub fn current_stacking_context_empty(&self) -> bool {
-        match self.peek() {
-            Some(item) => item.item == SpecificDisplayItem::PopStackingContext,
-            None => true,
-        }
-    }
-
-    fn peek(&self) -> Option<&'a DisplayItem> {
-        if self.next_item_index >= self.display_list.len() {
-            return None
-        }
-        Some(&self.display_list[self.next_item_index])
-    }
-}
-
-impl<'a> Iterator for DisplayListTraversal<'a> {
-    type Item = &'a DisplayItem;
-
-    fn next(&mut self) -> Option<&'a DisplayItem> {
-        if self.next_item_index >= self.display_list.len() {
-            return None
-        }
-
-        let item = &self.display_list[self.next_item_index];
-        self.next_item_index += 1;
-        Some(item)
-    }
-}
-
 fn clip_intersection(original_rect: &LayerRect,
                      region: &ClipRegion,
-                     aux_lists: &AuxiliaryLists)
+                     display_list: &BuiltDisplayList)
                      -> Option<LayerRect> {
     if region.image_mask.is_some() {
         return None;
     }
-    let clips = aux_lists.complex_clip_regions(&region.complex);
+    let clips = display_list.get(region.complex_clips);
     let base_rect = region.main.intersection(original_rect);
-    clips.iter().fold(base_rect, |inner_combined, ccr| {
+    clips.fold(base_rect, |inner_combined, ccr| {
         inner_combined.and_then(|combined| {
             ccr.get_inner_rect_full().and_then(|ir| ir.intersection(&combined))
         })
     })
 }
 
 impl Frame {
     pub fn new(config: FrameBuilderConfig) -> Frame {
@@ -292,23 +224,26 @@ impl Frame {
         if window_size.width == 0 || window_size.height == 0 {
             error!("ERROR: Invalid window dimensions! Please call api.set_window_size()");
         }
 
         let old_scrolling_states = self.reset();
 
         self.pipeline_epoch_map.insert(root_pipeline_id, root_pipeline.epoch);
 
-        let (root_stacking_context, root_bounds) = match display_list.starting_stacking_context() {
-            Some(some) => some,
-            None => {
-                warn!("Pipeline display list does not start with a stacking context.");
-                return;
-            }
-        };
+        let mut traversal = display_list.iter();
+
+        let (root_stacking_context, root_bounds, root_filters) =
+          match traversal.starting_stacking_context() {
+              Some(some) => some,
+              None => {
+                  warn!("Pipeline display list does not start with a stacking context.");
+                  return;
+              }
+          };
 
         let background_color = root_pipeline.background_color.and_then(|color| {
             if color.a > 0.0 {
                 Some(color)
             } else {
                 None
             }
         });
@@ -326,25 +261,25 @@ impl Frame {
                                                     &root_bounds.size,
                                                     &mut self.clip_scroll_tree);
 
             context.builder.setup_viewport_offset(window_size,
                                                   inner_rect,
                                                   device_pixel_ratio,
                                                   &mut self.clip_scroll_tree);
 
-            let mut traversal = DisplayListTraversal::new_skipping_first(display_list);
             self.flatten_stacking_context(&mut traversal,
                                           root_pipeline_id,
                                           &mut context,
                                           clip_id,
                                           LayerPoint::zero(),
                                           0,
-                                          root_bounds,
-                                          root_stacking_context);
+                                          &root_bounds,
+                                          &root_stacking_context,
+                                          root_filters);
         }
 
         self.frame_builder = Some(frame_builder);
         self.clip_scroll_tree.finalize_and_apply_pending_scroll_offsets(old_scrolling_states);
     }
 
     fn flatten_clip<'a>(&mut self,
                         context: &mut FlattenContext,
@@ -358,36 +293,38 @@ impl Frame {
                                              pipeline_id,
                                              &content_rect,
                                              clip,
                                              &mut self.clip_scroll_tree);
 
     }
 
     fn flatten_stacking_context<'a>(&mut self,
-                                    traversal: &mut DisplayListTraversal<'a>,
+                                    traversal: &mut BuiltDisplayListIter<'a>,
                                     pipeline_id: PipelineId,
                                     context: &mut FlattenContext,
                                     context_scroll_node_id: ClipId,
                                     mut reference_frame_relative_offset: LayerPoint,
                                     level: i32,
                                     bounds: &LayerRect,
-                                    stacking_context: &StackingContext) {
+                                    stacking_context: &StackingContext,
+                                    filters: ItemRange<FilterOp>) {
         // Avoid doing unnecessary work for empty stacking contexts.
         if traversal.current_stacking_context_empty() {
             traversal.skip_current_stacking_context();
             return;
         }
 
         let composition_operations = {
-            let auxiliary_lists = context.scene.pipeline_auxiliary_lists
-                                               .get(&pipeline_id)
-                                               .expect("No auxiliary lists?!");
+            // TODO(optimization?): self.traversal.display_list()
+            let display_list = context.scene.display_lists
+                                      .get(&pipeline_id)
+                                      .expect("No display list?!");
             CompositeOps::new(
-                stacking_context.filter_ops_for_compositing(auxiliary_lists, &context.scene.properties),
+                stacking_context.filter_ops_for_compositing(display_list, filters, &context.scene.properties),
                 stacking_context.mix_blend_mode_for_compositing())
         };
 
         if composition_operations.will_make_invisible() {
             traversal.skip_current_stacking_context();
             return;
         }
 
@@ -494,18 +431,21 @@ impl Frame {
         };
 
         let display_list = context.scene.display_lists.get(&pipeline_id);
         let display_list = match display_list {
             Some(display_list) => display_list,
             None => return,
         };
 
+        let mut traversal = display_list.iter();
+
         let (iframe_stacking_context,
-             iframe_stacking_context_bounds) = match display_list.starting_stacking_context() {
+             iframe_stacking_context_bounds,
+             iframe_filters) = match traversal.starting_stacking_context() {
             Some(some) => some,
             None => {
                 warn!("Pipeline display list does not start with a stacking context.");
                 return;
             }
         };
 
         self.pipeline_epoch_map.insert(pipeline_id, pipeline.epoch);
@@ -527,189 +467,217 @@ impl Frame {
         context.builder.add_clip_scroll_node(
             iframe_clip_id,
             iframe_reference_frame_id,
             pipeline_id,
             &LayerRect::new(LayerPoint::zero(), iframe_stacking_context_bounds.size),
             &ClipRegion::simple(&iframe_rect),
             &mut self.clip_scroll_tree);
 
-        let mut traversal = DisplayListTraversal::new_skipping_first(display_list);
         self.flatten_stacking_context(&mut traversal,
                                       pipeline_id,
                                       context,
                                       iframe_clip_id,
                                       LayerPoint::zero(),
                                       0,
-                                      iframe_stacking_context_bounds,
-                                      iframe_stacking_context);
+                                      &iframe_stacking_context_bounds,
+                                      &iframe_stacking_context,
+                                      iframe_filters);
 
         context.builder.pop_reference_frame();
     }
 
     fn flatten_items<'a>(&mut self,
-                         traversal: &mut DisplayListTraversal<'a>,
+                         traversal: &mut BuiltDisplayListIter<'a>,
                          pipeline_id: PipelineId,
                          context: &mut FlattenContext,
                          reference_frame_relative_offset: LayerPoint,
                          level: i32) {
-        while let Some(item) = traversal.next() {
-            let mut clip_and_scroll = item.clip_and_scroll;
+
+        // All this continue_traversal stuff is a big borrowck hack ;_;
+        // Non-lexical lifetimes should fix it.
+        //
+        // Basic idea: when we recurse, we make an independent traversal, then assign
+        // it to this variable to be swapped in at the start of the loop. We can't
+        // while-let because we need a brief period where the item doesn't exist.
+        let mut continue_traversal: Option<BuiltDisplayListIter<'a>> = None;
+        loop {
+            if let Some(trav) = continue_traversal.take() {
+                *traversal = trav;
+            }
+            let item = match traversal.next() {
+                Some(item) => item,
+                None => break,
+            };
+
+            let mut clip_and_scroll = item.clip_and_scroll();
             clip_and_scroll.scroll_node_id =
                 context.clip_id_with_replacement(clip_and_scroll.scroll_node_id);
-
-            match item.item {
+            match *item.item() {
                 SpecificDisplayItem::WebGL(ref info) => {
                     context.builder.add_webgl_rectangle(clip_and_scroll,
-                                                        item.rect,
-                                                        &item.clip,
+                                                        item.rect(),
+                                                        item.clip_region(),
                                                         info.context_id);
                 }
                 SpecificDisplayItem::Image(ref info) => {
                     let image = context.resource_cache.get_image_properties(info.image_key);
                     if let Some(tile_size) = image.tiling {
                         // The image resource is tiled. We have to generate an image primitive
                         // for each tile.
                         let image_size = DeviceUintSize::new(image.descriptor.width, image.descriptor.height);
                         self.decompose_image(clip_and_scroll,
                                              context,
-                                             &item.rect,
-                                             &item.clip,
+                                             &item.rect(),
+                                             item.clip_region(),
                                              info,
                                              image_size,
                                              tile_size as u32);
                     } else {
                         context.builder.add_image(clip_and_scroll,
-                                                  item.rect,
-                                                  &item.clip,
+                                                  item.rect(),
+                                                  item.clip_region(),
                                                   &info.stretch_size,
                                                   &info.tile_spacing,
                                                   None,
                                                   info.image_key,
                                                   info.image_rendering,
                                                   None);
                     }
                 }
                 SpecificDisplayItem::YuvImage(ref info) => {
                     context.builder.add_yuv_image(clip_and_scroll,
-                                                  item.rect,
-                                                  &item.clip,
+                                                  item.rect(),
+                                                  item.clip_region(),
                                                   info.yuv_data,
                                                   info.color_space);
                 }
                 SpecificDisplayItem::Text(ref text_info) => {
                     context.builder.add_text(clip_and_scroll,
-                                             item.rect,
-                                             &item.clip,
+                                             item.rect(),
+                                             item.clip_region(),
                                              text_info.font_key,
                                              text_info.size,
                                              text_info.blur_radius,
                                              &text_info.color,
-                                             text_info.glyphs,
+                                             item.glyphs(),
+                                             item.display_list().get(item.glyphs()).count(),
                                              text_info.glyph_options);
                 }
                 SpecificDisplayItem::Rectangle(ref info) => {
-                    let auxiliary_lists = context.scene.pipeline_auxiliary_lists
-                                                       .get(&pipeline_id)
-                                                       .expect("No auxiliary lists?!");
+                    let display_list = context.scene.display_lists
+                                              .get(&pipeline_id)
+                                              .expect("No display list?!");
                     // Try to extract the opaque inner rectangle out of the clipped primitive.
-                    if let Some(opaque_rect) = clip_intersection(&item.rect, &item.clip, auxiliary_lists) {
+                    if let Some(opaque_rect) = clip_intersection(&item.rect(), item.clip_region(), display_list) {
                         let mut results = Vec::new();
-                        subtract_rect(&item.rect, &opaque_rect, &mut results);
+                        subtract_rect(&item.rect(), &opaque_rect, &mut results);
                         // The inner rectangle is considered opaque within this layer.
                         // It may still inherit some masking from the clip stack.
                         context.builder.add_solid_rectangle(clip_and_scroll,
                                                             &opaque_rect,
-                                                            &ClipRegion::simple(&item.clip.main),
+                                                            &ClipRegion::simple(&item.clip_region().main),
                                                             &info.color,
                                                             PrimitiveFlags::None);
                         for transparent_rect in &results {
                             context.builder.add_solid_rectangle(clip_and_scroll,
                                                                 transparent_rect,
-                                                                &item.clip,
+                                                                item.clip_region(),
                                                                 &info.color,
                                                                 PrimitiveFlags::None);
                         }
                     } else {
                         context.builder.add_solid_rectangle(clip_and_scroll,
-                                                            &item.rect,
-                                                            &item.clip,
+                                                            &item.rect(),
+                                                            item.clip_region(),
                                                             &info.color,
                                                             PrimitiveFlags::None);
                     }
                 }
                 SpecificDisplayItem::Gradient(ref info) => {
                     context.builder.add_gradient(clip_and_scroll,
-                                                 item.rect,
-                                                 &item.clip,
+                                                 item.rect(),
+                                                 item.clip_region(),
                                                  info.gradient.start_point,
                                                  info.gradient.end_point,
-                                                 info.gradient.stops,
+                                                 item.gradient_stops(),
+                                                 item.display_list()
+                                                     .get(item.gradient_stops()).count(),
                                                  info.gradient.extend_mode,
                                                  info.tile_size,
                                                  info.tile_spacing);
                 }
                 SpecificDisplayItem::RadialGradient(ref info) => {
                     context.builder.add_radial_gradient(clip_and_scroll,
-                                                        item.rect,
-                                                        &item.clip,
+                                                        item.rect(),
+                                                        item.clip_region(),
                                                         info.gradient.start_center,
                                                         info.gradient.start_radius,
                                                         info.gradient.end_center,
                                                         info.gradient.end_radius,
                                                         info.gradient.ratio_xy,
-                                                        info.gradient.stops,
+                                                        item.gradient_stops(),
                                                         info.gradient.extend_mode,
                                                         info.tile_size,
                                                         info.tile_spacing);
                 }
                 SpecificDisplayItem::BoxShadow(ref box_shadow_info) => {
                     context.builder.add_box_shadow(clip_and_scroll,
                                                    &box_shadow_info.box_bounds,
-                                                   &item.clip,
+                                                   item.clip_region(),
                                                    &box_shadow_info.offset,
                                                    &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) => {
+
                     context.builder.add_border(clip_and_scroll,
-                                               item.rect,
-                                               &item.clip,
-                                               info);
+                                               item.rect(),
+                                               item.clip_region(),
+                                               info,
+                                               item.gradient_stops(),
+                                               item.display_list()
+                                                   .get(item.gradient_stops()).count());
                 }
                 SpecificDisplayItem::PushStackingContext(ref info) => {
-                    self.flatten_stacking_context(traversal,
+                    let mut subtraversal = item.sub_iter();
+                    self.flatten_stacking_context(&mut subtraversal,
                                                   pipeline_id,
                                                   context,
-                                                  item.clip_and_scroll.scroll_node_id,
+                                                  item.clip_and_scroll().scroll_node_id,
                                                   reference_frame_relative_offset,
                                                   level + 1,
-                                                  &item.rect,
-                                                  &info.stacking_context);
+                                                  &item.rect(),
+                                                  &info.stacking_context,
+                                                  item.filters());
+                    continue_traversal = Some(subtraversal);
                 }
                 SpecificDisplayItem::Iframe(ref info) => {
                     self.flatten_iframe(info.pipeline_id,
                                         clip_and_scroll.scroll_node_id,
-                                        &item.rect,
+                                        &item.rect(),
                                         context,
                                         reference_frame_relative_offset);
                 }
                 SpecificDisplayItem::Clip(ref info) => {
-                    let content_rect = &item.rect.translate(&reference_frame_relative_offset);
+                    let content_rect = &item.rect().translate(&reference_frame_relative_offset);
                     self.flatten_clip(context,
                                       pipeline_id,
                                       clip_and_scroll.scroll_node_id,
                                       &info,
                                       &content_rect,
-                                      &item.clip);
+                                      item.clip_region());
                 }
                 SpecificDisplayItem::PopStackingContext => return,
+                SpecificDisplayItem::SetGradientStops | SpecificDisplayItem::SetClipRegion(_) => {
+                    // Do nothing; these are dummy items for the display list parser
+                }
             }
         }
     }
 
     /// Decomposes an image display item that is repeated into an image per individual repetition.
     /// We need to do this when we are unable to perform the repetition in the shader,
     /// for example if the image is tiled.
     ///
@@ -817,17 +785,17 @@ impl Frame {
         // We need to do this because the image is broken up into smaller tiles in the texture
         // cache and the image shader is not able to work with this type of sparse representation.
 
         // The tiling logic works as follows:
         //
         //  ###################-+  -+
         //  #    |    |    |//# |   | image size
         //  #    |    |    |//# |   |
-        //  #----+----+----+--#-+   |  -+ 
+        //  #----+----+----+--#-+   |  -+
         //  #    |    |    |//# |   |   | regular tile size
         //  #    |    |    |//# |   |   |
         //  #----+----+----+--#-+   |  -+-+
         //  #////|////|////|//# |   |     | "leftover" height
         //  ################### |  -+  ---+
         //  #----+----+----+----+
         //
         // In the ascii diagram above, a large image is plit into tiles of almost regular size.
@@ -997,42 +965,42 @@ impl Frame {
                                       info.image_key,
                                       info.image_rendering,
                                       Some(tile_offset));
         }
     }
 
     pub fn build(&mut self,
                  resource_cache: &mut ResourceCache,
-                 auxiliary_lists_map: &AuxiliaryListsMap,
+                 display_lists: &DisplayListMap,
                  device_pixel_ratio: f32,
                  pan: LayerPoint,
                  texture_cache_profile: &mut TextureCacheProfileCounters)
                  -> RendererFrame {
         self.clip_scroll_tree.update_all_node_transforms(pan);
         let frame = self.build_frame(resource_cache,
-                                     auxiliary_lists_map,
+                                     display_lists,
                                      device_pixel_ratio,
                                      texture_cache_profile);
         resource_cache.expire_old_resources(self.id);
         frame
     }
 
     fn build_frame(&mut self,
                    resource_cache: &mut ResourceCache,
-                   auxiliary_lists_map: &AuxiliaryListsMap,
+                   display_lists: &DisplayListMap,
                    device_pixel_ratio: f32,
                    texture_cache_profile: &mut TextureCacheProfileCounters)
                    -> RendererFrame {
         let mut frame_builder = self.frame_builder.take();
         let frame = frame_builder.as_mut().map(|builder|
             builder.build(resource_cache,
                           self.id,
                           &mut self.clip_scroll_tree,
-                          auxiliary_lists_map,
+                          display_lists,
                           device_pixel_ratio,
                           texture_cache_profile)
         );
         self.frame_builder = frame_builder;
 
         let nodes_bouncing_back = self.clip_scroll_tree.collect_nodes_bouncing_back();
         RendererFrame::new(self.pipeline_epoch_map.clone(), nodes_bouncing_back, frame)
     }
--- a/gfx/webrender/src/frame_builder.rs
+++ b/gfx/webrender/src/frame_builder.rs
@@ -17,27 +17,28 @@ use profiler::{FrameProfileCounters, Tex
 use render_task::{AlphaRenderItem, MaskCacheKey, MaskResult, RenderTask, RenderTaskIndex};
 use render_task::RenderTaskLocation;
 use resource_cache::ResourceCache;
 use clip_scroll_node::{ClipInfo, ClipScrollNode, NodeType};
 use clip_scroll_tree::ClipScrollTree;
 use std::{cmp, f32, i32, mem, usize};
 use euclid::{SideOffsets2D, TypedPoint3D};
 use tiling::{ContextIsolation, StackingContextIndex};
-use tiling::{AuxiliaryListsMap, ClipScrollGroup, ClipScrollGroupIndex, CompositeOps, Frame};
+use tiling::{ClipScrollGroup, ClipScrollGroupIndex, CompositeOps, DisplayListMap, Frame};
 use tiling::{PackedLayer, PackedLayerIndex, PrimitiveFlags, PrimitiveRunCmd, RenderPass};
 use tiling::{RenderTargetContext, RenderTaskCollection, ScrollbarPrimitive, StackingContext};
 use util::{self, pack_as_float, subtract_rect, recycle_vec};
 use util::RectHelpers;
 use webrender_traits::{BorderDetails, BorderDisplayItem, BoxShadowClipMode, ClipAndScrollInfo};
 use webrender_traits::{ClipId, ClipRegion, ColorF, DeviceIntPoint, DeviceIntRect, DeviceIntSize};
 use webrender_traits::{DeviceUintRect, DeviceUintSize, ExtendMode, FontKey, FontRenderMode};
-use webrender_traits::{GlyphOptions, ImageKey, ImageRendering, ItemRange, LayerPoint, LayerRect};
-use webrender_traits::{LayerSize, LayerToScrollTransform, PipelineId, RepeatMode, TileOffset};
-use webrender_traits::{TransformStyle, WebGLContextId, WorldPixel, YuvColorSpace, YuvData};
+use webrender_traits::{GlyphInstance, GlyphOptions, GradientStop, ImageKey, ImageRendering};
+use webrender_traits::{ItemRange, LayerPoint, LayerRect, LayerSize, LayerToScrollTransform};
+use webrender_traits::{PipelineId, RepeatMode, TileOffset, TransformStyle, WebGLContextId};
+use webrender_traits::{WorldPixel, YuvColorSpace, YuvData};
 
 #[derive(Debug, Clone)]
 struct ImageBorderSegment {
     geom_rect: LayerRect,
     sub_rect: TexelRect,
     stretch_size: LayerSize,
     tile_spacing: LayerSize,
 }
@@ -414,17 +415,19 @@ impl FrameBuilder {
             }
         }
     }
 
     pub fn add_border(&mut self,
                       clip_and_scroll: ClipAndScrollInfo,
                       rect: LayerRect,
                       clip_region: &ClipRegion,
-                      border_item: &BorderDisplayItem) {
+                      border_item: &BorderDisplayItem,
+                      gradient_stops: ItemRange<GradientStop>,
+                      gradient_stops_count: usize) {
         let create_segments = |outset: SideOffsets2D<f32>| {
             // Calculate the modified rect as specific by border-image-outset
             let origin = LayerPoint::new(rect.origin.x - outset.left,
                                          rect.origin.y - outset.top);
             let size = LayerSize::new(rect.size.width + outset.left + outset.right,
                                       rect.size.height + outset.top + outset.bottom);
             let rect = LayerRect::new(origin, size);
 
@@ -574,17 +577,18 @@ impl FrameBuilder {
                 for segment in create_segments(border.outset) {
                     let segment_rel = segment.origin - rect.origin;
 
                     self.add_gradient(clip_and_scroll,
                                       segment,
                                       clip_region,
                                       border.gradient.start_point - segment_rel,
                                       border.gradient.end_point - segment_rel,
-                                      border.gradient.stops,
+                                      gradient_stops,
+                                      gradient_stops_count,
                                       border.gradient.extend_mode,
                                       segment.size,
                                       LayerSize::zero());
                 }
             }
             BorderDetails::RadialGradient(ref border) => {
                 for segment in create_segments(border.outset) {
                     let segment_rel = segment.origin - rect.origin;
@@ -592,32 +596,33 @@ impl FrameBuilder {
                     self.add_radial_gradient(clip_and_scroll,
                                              segment,
                                              clip_region,
                                              border.gradient.start_center - segment_rel,
                                              border.gradient.start_radius,
                                              border.gradient.end_center - segment_rel,
                                              border.gradient.end_radius,
                                              border.gradient.ratio_xy,
-                                             border.gradient.stops,
+                                             gradient_stops,
                                              border.gradient.extend_mode,
                                              segment.size,
                                              LayerSize::zero());
                 }
             }
         }
     }
 
     pub fn add_gradient(&mut self,
                         clip_and_scroll: ClipAndScrollInfo,
                         rect: LayerRect,
                         clip_region: &ClipRegion,
                         start_point: LayerPoint,
                         end_point: LayerPoint,
-                        stops: ItemRange,
+                        stops: ItemRange<GradientStop>,
+                        stops_count: usize,
                         extend_mode: ExtendMode,
                         tile_size: LayerSize,
                         tile_spacing: LayerSize) {
         let tile_repeat = tile_size + tile_spacing;
         let is_not_tiled = tile_repeat.width >= rect.size.width &&
                            tile_repeat.height >= rect.size.height;
 
         let aligned_and_fills_rect = (start_point.x == end_point.x &&
@@ -638,16 +643,17 @@ impl FrameBuilder {
         // reversing in that case.
         let reverse_stops = !aligned &&
                             (start_point.x > end_point.x ||
                              (start_point.x == end_point.x &&
                               start_point.y > end_point.y));
 
         let gradient_cpu = GradientPrimitiveCpu {
             stops_range: stops,
+            stops_count: stops_count,
             extend_mode: extend_mode,
             reverse_stops: reverse_stops,
             cache_dirty: true,
         };
 
         // To get reftests exactly matching with reverse start/end
         // points, it's necessary to reverse the gradient
         // line in some cases.
@@ -679,17 +685,17 @@ impl FrameBuilder {
                                clip_and_scroll: ClipAndScrollInfo,
                                rect: LayerRect,
                                clip_region: &ClipRegion,
                                start_center: LayerPoint,
                                start_radius: f32,
                                end_center: LayerPoint,
                                end_radius: f32,
                                ratio_xy: f32,
-                               stops: ItemRange,
+                               stops: ItemRange<GradientStop>,
                                extend_mode: ExtendMode,
                                tile_size: LayerSize,
                                tile_spacing: LayerSize) {
         let radial_gradient_cpu = RadialGradientPrimitiveCpu {
             stops_range: stops,
             extend_mode: extend_mode,
             cache_dirty: true,
         };
@@ -716,17 +722,18 @@ impl FrameBuilder {
     pub fn add_text(&mut self,
                     clip_and_scroll: ClipAndScrollInfo,
                     rect: LayerRect,
                     clip_region: &ClipRegion,
                     font_key: FontKey,
                     size: Au,
                     blur_radius: Au,
                     color: &ColorF,
-                    glyph_range: ItemRange,
+                    glyph_range: ItemRange<GlyphInstance>,
+                    glyph_count: usize,
                     glyph_options: Option<GlyphOptions>) {
         if color.a == 0.0 {
             return
         }
 
         if size.0 <= 0 {
             return
         }
@@ -741,16 +748,17 @@ impl FrameBuilder {
             FontRenderMode::Alpha
         };
 
         let prim_cpu = TextRunPrimitiveCpu {
             font_key: font_key,
             logical_font_size: size,
             blur_radius: blur_radius,
             glyph_range: glyph_range,
+            glyph_count: glyph_count,
             cache_dirty: true,
             glyph_instances: Vec::new(),
             color_texture_id: SourceTexture::Invalid,
             color: *color,
             render_mode: render_mode,
             glyph_options: glyph_options,
             resource_address: GpuStoreAddress(0),
         };
@@ -1059,25 +1067,25 @@ impl FrameBuilder {
                            PrimitiveContainer::YuvImage(prim_cpu, prim_gpu));
     }
 
     /// Compute the contribution (bounding rectangles, and resources) of layers and their
     /// primitives in screen space.
     fn build_layer_screen_rects_and_cull_layers(&mut self,
                                                 screen_rect: &DeviceIntRect,
                                                 clip_scroll_tree: &mut ClipScrollTree,
-                                                auxiliary_lists_map: &AuxiliaryListsMap,
+                                                display_lists: &DisplayListMap,
                                                 resource_cache: &mut ResourceCache,
                                                 profile_counters: &mut FrameProfileCounters,
                                                 device_pixel_ratio: f32) {
         profile_scope!("cull");
         LayerRectCalculationAndCullingPass::create_and_run(self,
                                                            screen_rect,
                                                            clip_scroll_tree,
-                                                           auxiliary_lists_map,
+                                                           display_lists,
                                                            resource_cache,
                                                            profile_counters,
                                                            device_pixel_ratio);
     }
 
     fn update_scroll_bars(&mut self, clip_scroll_tree: &ClipScrollTree) {
         let distance_from_edge = 8.0;
 
@@ -1321,17 +1329,17 @@ impl FrameBuilder {
         debug_assert!(preserve_3d_stack.is_empty());
         (current_task, next_task_index.0)
     }
 
     pub fn build(&mut self,
                  resource_cache: &mut ResourceCache,
                  frame_id: FrameId,
                  clip_scroll_tree: &mut ClipScrollTree,
-                 auxiliary_lists_map: &AuxiliaryListsMap,
+                 display_lists: &DisplayListMap,
                  device_pixel_ratio: f32,
                  texture_cache_profile: &mut TextureCacheProfileCounters)
                  -> Frame {
         profile_scope!("build");
 
         let mut profile_counters = FrameProfileCounters::new();
         profile_counters.total_primitives.set(self.prim_store.prim_count());
 
@@ -1348,17 +1356,17 @@ impl FrameBuilder {
         // covers the entire screen).
         let cache_size = DeviceUintSize::new(cmp::max(1024, screen_rect.size.width as u32),
                                              cmp::max(1024, screen_rect.size.height as u32));
 
         self.update_scroll_bars(clip_scroll_tree);
 
         self.build_layer_screen_rects_and_cull_layers(&screen_rect,
                                                       clip_scroll_tree,
-                                                      auxiliary_lists_map,
+                                                      display_lists,
                                                       resource_cache,
                                                       &mut profile_counters,
                                                       device_pixel_ratio);
 
         let (main_render_task, static_render_task_count) = self.build_render_task(clip_scroll_tree);
         let mut render_tasks = RenderTaskCollection::new(static_render_task_count);
 
         let mut required_pass_count = 0;
@@ -1428,17 +1436,17 @@ impl FrameBuilder {
     }
 
 }
 
 struct LayerRectCalculationAndCullingPass<'a> {
     frame_builder: &'a mut FrameBuilder,
     screen_rect: &'a DeviceIntRect,
     clip_scroll_tree: &'a mut ClipScrollTree,
-    auxiliary_lists_map: &'a AuxiliaryListsMap,
+    display_lists: &'a DisplayListMap,
     resource_cache: &'a mut ResourceCache,
     profile_counters: &'a mut FrameProfileCounters,
     device_pixel_ratio: f32,
     stacking_context_stack: Vec<StackingContextIndex>,
 
     /// A cached clip info stack, which should handle the most common situation,
     /// which is that we are using the same clip info stack that we were using
     /// previously.
@@ -1448,26 +1456,26 @@ struct LayerRectCalculationAndCullingPas
     /// to recalculate it for every primitive.
     current_clip_info: Option<(ClipId, Option<DeviceIntRect>)>
 }
 
 impl<'a> LayerRectCalculationAndCullingPass<'a> {
     fn create_and_run(frame_builder: &'a mut FrameBuilder,
                       screen_rect: &'a DeviceIntRect,
                       clip_scroll_tree: &'a mut ClipScrollTree,
-                      auxiliary_lists_map: &'a AuxiliaryListsMap,
+                      display_lists: &'a DisplayListMap,
                       resource_cache: &'a mut ResourceCache,
                       profile_counters: &'a mut FrameProfileCounters,
                       device_pixel_ratio: f32) {
 
         let mut pass = LayerRectCalculationAndCullingPass {
             frame_builder: frame_builder,
             screen_rect: screen_rect,
             clip_scroll_tree: clip_scroll_tree,
-            auxiliary_lists_map: auxiliary_lists_map,
+            display_lists: display_lists,
             resource_cache: resource_cache,
             profile_counters: profile_counters,
             device_pixel_ratio: device_pixel_ratio,
             stacking_context_stack: Vec::new(),
             current_clip_stack: Vec::new(),
             current_clip_info: None,
         };
         pass.run();
@@ -1520,24 +1528,24 @@ impl<'a> LayerRectCalculationAndCullingP
                                                                         self.screen_rect,
                                                                         self.device_pixel_ratio);
 
             let mask_info = match node_clip_info.mask_cache_info {
                 Some(ref mut mask_info) => mask_info,
                 _ => continue,
             };
 
-            let auxiliary_lists = self.auxiliary_lists_map.get(&node.pipeline_id)
-                                                          .expect("No auxiliary lists?");
+            let display_list = self.display_lists.get(&node.pipeline_id)
+                                                 .expect("No display list?");
 
             mask_info.update(&node_clip_info.clip_sources,
                              &packed_layer.transform,
                              &mut self.frame_builder.prim_store.gpu_data32,
                              self.device_pixel_ratio,
-                             auxiliary_lists);
+                             display_list);
 
             for clip_source in &node_clip_info.clip_sources {
                 if let Some(mask) = clip_source.image_mask() {
                     // We don't add the image mask for resolution, because
                     // layer masks are resolved later.
                     self.resource_cache.request_image(mask.image, ImageRendering::Auto, None);
                 }
             }
@@ -1688,30 +1696,30 @@ impl<'a> LayerRectCalculationAndCullingP
             self.rebuild_clip_info_stack_if_necessary(clip_and_scroll.clip_node_id());
         if clip_bounds.map_or(false, |bounds| bounds.is_empty()) {
             return;
         }
 
         let stacking_context =
             &mut self.frame_builder.stacking_context_store[stacking_context_index.0];
         let packed_layer = &self.frame_builder.packed_layers[packed_layer_index.0];
-        let auxiliary_lists = self.auxiliary_lists_map.get(&pipeline_id)
-                                                      .expect("No auxiliary lists?");
+        let display_list = self.display_lists.get(&pipeline_id)
+                                             .expect("No display list?");
         for i in 0..prim_count {
             let prim_index = PrimitiveIndex(prim_index.0 + i);
             if self.frame_builder.prim_store.build_bounding_rect(prim_index,
                                                                  self.screen_rect,
                                                                  &packed_layer.transform,
                                                                  &packed_layer.local_clip_rect,
                                                                  self.device_pixel_ratio) {
                 if self.frame_builder.prim_store.prepare_prim_for_render(prim_index,
                                                                          self.resource_cache,
                                                                          &packed_layer.transform,
                                                                          self.device_pixel_ratio,
-                                                                         auxiliary_lists) {
+                                                                         display_list) {
                     self.frame_builder.prim_store.build_bounding_rect(prim_index,
                                                                       self.screen_rect,
                                                                       &packed_layer.transform,
                                                                       &packed_layer.local_clip_rect,
                                                                       self.device_pixel_ratio);
                 }
 
                 // If the primitive is visible, consider culling it via clip rect(s).
--- a/gfx/webrender/src/mask_cache.rs
+++ b/gfx/webrender/src/mask_cache.rs
@@ -3,17 +3,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 use border::BorderCornerClipSource;
 use gpu_store::GpuStoreAddress;
 use prim_store::{ClipData, GpuBlock32, PrimitiveStore};
 use prim_store::{CLIP_DATA_GPU_SIZE, MASK_DATA_GPU_SIZE};
 use renderer::VertexDataStore;
 use util::{ComplexClipRegionHelpers, MatrixHelpers, TransformedRect};
-use webrender_traits::{AuxiliaryLists, BorderRadius, ClipRegion, ComplexClipRegion, ImageMask};
+use webrender_traits::{BorderRadius, BuiltDisplayList, ClipRegion, ComplexClipRegion, ImageMask};
 use webrender_traits::{DeviceIntRect, LayerToWorldTransform};
 use webrender_traits::{LayerRect, LayerPoint, LayerSize};
 use std::ops::Not;
 
 const MAX_CLIP: f32 = 1000000.0;
 
 #[repr(C)]
 #[derive(Copy, Clone, Debug, PartialEq)]
@@ -149,18 +149,17 @@ impl MaskCacheInfo {
                 ClipSource::Complex(..) => {
                     complex_clip_count += 1;
                 }
                 ClipSource::Region(ref region, region_mode) => {
                     if let Some(info) = region.image_mask {
                         debug_assert!(image.is_none());     // TODO(gw): Support >1 image mask!
                         image = Some((info, clip_store.alloc(MASK_DATA_GPU_SIZE)));
                     }
-
-                    complex_clip_count += region.complex.length;
+                    complex_clip_count += region.complex_clip_count;
                     if region_mode == RegionMode::IncludeRect {
                         complex_clip_count += 1;
                     }
                 }
                 ClipSource::BorderCorner(ref source) => {
                     // One block for the corner header, plus one
                     // block per dash to clip out.
                     let gpu_address = clip_store.alloc(1 + source.dash_count);
@@ -188,17 +187,17 @@ impl MaskCacheInfo {
         })
     }
 
     pub fn update(&mut self,
                   sources: &[ClipSource],
                   transform: &LayerToWorldTransform,
                   clip_store: &mut VertexDataStore<GpuBlock32>,
                   device_pixel_ratio: f32,
-                  aux_lists: &AuxiliaryLists) {
+                  display_list: &BuiltDisplayList) {
         let is_aligned = transform.can_losslessly_transform_and_perspective_project_a_2d_rect();
 
         // If we haven't cached this info, or if the transform type has changed
         // we need to re-calculate the number of clips.
         if self.bounds.is_none() || self.is_aligned != is_aligned {
             let mut local_rect = Some(LayerRect::new(LayerPoint::new(-MAX_CLIP, -MAX_CLIP),
                                                      LayerSize::new(2.0 * MAX_CLIP, 2.0 * MAX_CLIP)));
             let mut local_inner: Option<LayerRect> = None;
@@ -233,34 +232,34 @@ impl MaskCacheInfo {
                             Some(ref mask) if !mask.repeat => {
                                 local_rect = local_rect.and_then(|r| r.intersection(&mask.rect));
                                 None
                             },
                             Some(_) => None,
                             None => local_rect,
                         };
 
-                        let clips = aux_lists.complex_clip_regions(&region.complex);
+                        let clips = display_list.get(region.complex_clips);
                         if !self.is_aligned && region_mode == RegionMode::IncludeRect {
                             // we have an extra clip rect coming from the transformed layer
                             debug_assert!(self.effective_complex_clip_count < self.complex_clip_range.item_count);
                             let address = self.complex_clip_range.start + self.effective_complex_clip_count * CLIP_DATA_GPU_SIZE;
                             self.effective_complex_clip_count += 1;
 
                             let slice = clip_store.get_slice_mut(address, CLIP_DATA_GPU_SIZE);
                             PrimitiveStore::populate_clip_data(slice, ClipData::uniform(region.main, 0.0, ClipMode::Clip));
                         }
 
                         debug_assert!(self.effective_complex_clip_count + clips.len() <= self.complex_clip_range.item_count);
                         let address = self.complex_clip_range.start + self.effective_complex_clip_count * CLIP_DATA_GPU_SIZE;
                         self.effective_complex_clip_count += clips.len();
 
                         let slice = clip_store.get_slice_mut(address, CLIP_DATA_GPU_SIZE * clips.len());
-                        for (clip, chunk) in clips.iter().zip(slice.chunks_mut(CLIP_DATA_GPU_SIZE)) {
-                            let data = ClipData::from_clip_region(clip);
+                        for (clip, chunk) in clips.zip(slice.chunks_mut(CLIP_DATA_GPU_SIZE)) {
+                            let data = ClipData::from_clip_region(&clip);
                             PrimitiveStore::populate_clip_data(chunk, data);
                             local_rect = local_rect.and_then(|r| r.intersection(&clip.rect));
                             local_inner = local_inner.and_then(|r| clip.get_inner_rect_safe()
                                                                        .and_then(|ref inner| r.intersection(inner)));
                         }
                     }
                     ClipSource::BorderCorner{..} => {}
                 }
--- a/gfx/webrender/src/prim_store.rs
+++ b/gfx/webrender/src/prim_store.rs
@@ -9,24 +9,24 @@ use gpu_store::GpuStoreAddress;
 use internal_types::{SourceTexture, PackedTexel};
 use mask_cache::{ClipMode, ClipSource, MaskCacheInfo};
 use renderer::{VertexDataStore, GradientDataStore, SplitGeometryStore};
 use render_task::{RenderTask, RenderTaskLocation};
 use resource_cache::{CacheItem, ImageProperties, ResourceCache};
 use std::mem;
 use std::usize;
 use util::{TransformedRect, recycle_vec};
-use webrender_traits::{AuxiliaryLists, ColorF, ImageKey, ImageRendering, YuvColorSpace, YuvFormat};
-use webrender_traits::{ClipRegion, ComplexClipRegion, ItemRange, GlyphKey};
+use webrender_traits::{BuiltDisplayList, ColorF, ImageKey, ImageRendering, YuvColorSpace};
+use webrender_traits::{YuvFormat, ClipRegion, ComplexClipRegion, ItemRange, GlyphKey};
 use webrender_traits::{FontKey, FontRenderMode, WebGLContextId};
 use webrender_traits::{device_length, DeviceIntRect, DeviceIntSize};
 use webrender_traits::{DeviceRect, DevicePoint, DeviceSize};
 use webrender_traits::{LayerRect, LayerSize, LayerPoint, LayoutPoint};
 use webrender_traits::{LayerToWorldTransform, GlyphInstance, GlyphOptions};
-use webrender_traits::{ExtendMode, GradientStop, TileOffset};
+use webrender_traits::{ExtendMode, GradientStop, AuxIter, TileOffset};
 
 pub const CLIP_DATA_GPU_SIZE: usize = 5;
 pub const MASK_DATA_GPU_SIZE: usize = 1;
 
 /// Stores two coordinates in texel space. The coordinates
 /// are stored in texel coordinates because the texture atlas
 /// may grow. Storing them as texel coords and normalizing
 /// the UVs in the vertex shader means nothing needs to be
@@ -266,17 +266,18 @@ pub struct GradientPrimitiveGpu {
     pub tile_size: LayerSize,
     pub tile_repeat: LayerSize,
     pub extend_mode: f32,
     pub padding: [f32; 7],
 }
 
 #[derive(Debug)]
 pub struct GradientPrimitiveCpu {
-    pub stops_range: ItemRange,
+    pub stops_range: ItemRange<GradientStop>,
+    pub stops_count: usize,
     pub extend_mode: ExtendMode,
     pub reverse_stops: bool,
     pub cache_dirty: bool,
 }
 
 #[derive(Debug, Clone)]
 #[repr(C)]
 pub struct RadialGradientPrimitiveGpu {
@@ -288,17 +289,17 @@ pub struct RadialGradientPrimitiveGpu {
     pub extend_mode: f32,
     pub tile_size: LayerSize,
     pub tile_repeat: LayerSize,
     pub padding: [f32; 4],
 }
 
 #[derive(Debug)]
 pub struct RadialGradientPrimitiveCpu {
-    pub stops_range: ItemRange,
+    pub stops_range: ItemRange<GradientStop>,
     pub extend_mode: ExtendMode,
     pub cache_dirty: bool,
 }
 
 // The number of entries in a gradient data table.
 pub const GRADIENT_DATA_RESOLUTION: usize = 128;
 
 #[derive(Debug, Clone, Copy)]
@@ -374,17 +375,17 @@ impl GradientData {
 
     // Compute an entry index based on a gradient stop offset.
     #[inline]
     fn get_index(offset: f32) -> usize {
         (offset.max(0.0).min(1.0) * GRADIENT_DATA_RESOLUTION as f32).round() as usize
     }
 
     // Build the gradient data from the supplied stops, reversing them if necessary.
-    fn build(&mut self, src_stops: &[GradientStop], reverse_stops: bool) {
+    fn build(&mut self, src_stops: AuxIter<GradientStop>, reverse_stops: bool) {
 
         const MAX_IDX: usize = GRADIENT_DATA_RESOLUTION;
         const MIN_IDX: usize = 0;
 
         // Preconditions (should be ensured by DisplayListBuilder):
         // * we have at least two stops
         // * first stop has offset 0.0
         // * last stop has offset 1.0
@@ -435,17 +436,18 @@ pub struct TextRunPrimitiveGpu {
     pub color: ColorF,
 }
 
 #[derive(Debug, Clone)]
 pub struct TextRunPrimitiveCpu {
     pub font_key: FontKey,
     pub logical_font_size: Au,
     pub blur_radius: Au,
-    pub glyph_range: ItemRange,
+    pub glyph_range: ItemRange<GlyphInstance>,
+    pub glyph_count: usize,
     pub cache_dirty: bool,
     // TODO(gw): Maybe make this an Arc for sharing with resource cache
     pub glyph_instances: Vec<GlyphInstance>,
     pub color_texture_id: SourceTexture,
     pub color: ColorF,
     pub render_mode: FontRenderMode,
     pub resource_address: GpuStoreAddress,
     pub glyph_options: Option<GlyphOptions>,
@@ -705,28 +707,28 @@ impl PrimitiveStore {
                     render_task: None,
                     clip_task: None,
                 };
 
                 metadata
             }
             PrimitiveContainer::TextRun(mut text_cpu, text_gpu) => {
                 let gpu_address = self.gpu_data16.push(text_gpu);
-                let gpu_glyphs_address = self.gpu_data16.alloc(text_cpu.glyph_range.length);
-                text_cpu.resource_address = self.gpu_resource_rects.alloc(text_cpu.glyph_range.length);
+                let gpu_glyphs_address = self.gpu_data16.alloc(text_cpu.glyph_count);
+                text_cpu.resource_address = self.gpu_resource_rects.alloc(text_cpu.glyph_count);
 
                 let metadata = PrimitiveMetadata {
                     is_opaque: false,
                     clips: clips,
                     clip_cache_info: clip_info,
                     prim_kind: PrimitiveKind::TextRun,
                     cpu_prim_index: SpecificPrimitiveIndex(self.cpu_text_runs.len()),
                     gpu_prim_index: gpu_address,
                     gpu_data_address: gpu_glyphs_address,
-                    gpu_data_count: text_cpu.glyph_range.length as i32,
+                    gpu_data_count: text_cpu.glyph_count as i32,
                     render_task: None,
                     clip_task: None,
                 };
 
                 self.cpu_text_runs.push(text_cpu);
                 metadata
             }
             PrimitiveContainer::Image(mut image_cpu, image_gpu) => {
@@ -787,28 +789,28 @@ impl PrimitiveStore {
                     clip_task: None,
                 };
 
                 self.cpu_borders.push(border_cpu);
                 metadata
             }
             PrimitiveContainer::AlignedGradient(gradient_cpu, gradient_gpu) => {
                 let gpu_address = self.gpu_data64.push(gradient_gpu);
-                let gpu_stops_address = self.gpu_data32.alloc(gradient_cpu.stops_range.length);
+                let gpu_stops_address = self.gpu_data32.alloc(gradient_cpu.stops_count);
 
                 let metadata = PrimitiveMetadata {
                     // TODO: calculate if the gradient is actually opaque
                     is_opaque: false,
                     clips: clips,
                     clip_cache_info: clip_info,
                     prim_kind: PrimitiveKind::AlignedGradient,
                     cpu_prim_index: SpecificPrimitiveIndex(self.cpu_gradients.len()),
                     gpu_prim_index: gpu_address,
                     gpu_data_address: gpu_stops_address,
-                    gpu_data_count: gradient_cpu.stops_range.length as i32,
+                    gpu_data_count: gradient_cpu.stops_count as i32,
                     render_task: None,
                     clip_task: None,
                 };
 
                 self.cpu_gradients.push(gradient_cpu);
                 metadata
             }
             PrimitiveContainer::AngleGradient(gradient_cpu, gradient_gpu) => {
@@ -980,17 +982,17 @@ impl PrimitiveStore {
                 PrimitiveKind::AngleGradient |
                 PrimitiveKind::RadialGradient=> {}
                 PrimitiveKind::TextRun => {
                     let text = &mut self.cpu_text_runs[metadata.cpu_prim_index.0];
 
                     let font_size_dp = text.logical_font_size.scale_by(device_pixel_ratio);
 
                     let dest_rects = self.gpu_resource_rects.get_slice_mut(text.resource_address,
-                                                                           text.glyph_range.length);
+                                                                           text.glyph_count);
 
                     let texture_id = resource_cache.get_glyphs(text.font_key,
                                                                font_size_dp,
                                                                text.color,
                                                                &text.glyph_instances,
                                                                text.render_mode,
                                                                text.glyph_options, |index, uv0, uv1| {
                         let dest_rect = &mut dest_rects[index];
@@ -1126,30 +1128,30 @@ impl PrimitiveStore {
     }
 
     /// Returns true if the bounding box needs to be updated.
     pub fn prepare_prim_for_render(&mut self,
                                    prim_index: PrimitiveIndex,
                                    resource_cache: &mut ResourceCache,
                                    layer_transform: &LayerToWorldTransform,
                                    device_pixel_ratio: f32,
-                                   auxiliary_lists: &AuxiliaryLists) -> bool {
+                                   display_list: &BuiltDisplayList) -> bool {
 
         let metadata = &mut self.cpu_metadata[prim_index.0];
         let mut prim_needs_resolve = false;
         let mut rebuild_bounding_rect = false;
 
         if let Some(ref mut clip_info) = metadata.clip_cache_info {
             clip_info.update(&metadata.clips,
                              layer_transform,
                              &mut self.gpu_data32,
                              device_pixel_ratio,
-                             auxiliary_lists);
+                             display_list);
             for clip in &metadata.clips {
-                if let ClipSource::Region(ClipRegion{ image_mask: Some(ref mask), .. }, _) = *clip {
+                if let ClipSource::Region(ClipRegion{ image_mask: Some(ref mask), .. }, ..) = *clip {
                     resource_cache.request_image(mask.image, ImageRendering::Auto, None);
                     prim_needs_resolve = true;
                 }
             }
         }
 
         match metadata.prim_kind {
             PrimitiveKind::Rectangle |
@@ -1170,33 +1172,34 @@ impl PrimitiveStore {
                 let cache_size = DeviceIntSize::new(edge_size, edge_size);
                 let location = RenderTaskLocation::Dynamic(None, cache_size);
                 metadata.render_task.as_mut().unwrap().location = location;
             }
             PrimitiveKind::TextRun => {
                 let text = &mut self.cpu_text_runs[metadata.cpu_prim_index.0];
 
                 let font_size_dp = text.logical_font_size.scale_by(device_pixel_ratio);
-                let src_glyphs = auxiliary_lists.glyph_instances(&text.glyph_range);
+                let src_glyphs = display_list.get(text.glyph_range);
                 prim_needs_resolve = true;
 
                 if text.cache_dirty {
                     rebuild_bounding_rect = true;
                     text.cache_dirty = false;
 
-                    debug_assert!(metadata.gpu_data_count == text.glyph_range.length as i32);
+                    debug_assert!(metadata.gpu_data_count == src_glyphs.len() as i32);
                     debug_assert!(text.glyph_instances.is_empty());
 
                     let dest_glyphs = self.gpu_data16.get_slice_mut(metadata.gpu_data_address,
-                                                                    text.glyph_range.length);
+                                                                    src_glyphs.len());
+
                     let mut glyph_key = GlyphKey::new(text.font_key,
                                                       font_size_dp,
                                                       text.color,
-                                                      src_glyphs[0].index,
-                                                      src_glyphs[0].point,
+                                                      0,
+                                                      LayoutPoint::new(0.0, 0.0),
                                                       text.render_mode);
                     let mut local_rect = LayerRect::zero();
                     let mut actual_glyph_count = 0;
 
                     for src in src_glyphs {
                         glyph_key.index = src.index;
                         glyph_key.subpixel_point.set_offset(src.point, text.render_mode);
 
@@ -1297,46 +1300,48 @@ impl PrimitiveStore {
                 }
 
                 // TODO(nical): Currently assuming no tile_spacing for yuv images.
                 metadata.is_opaque = true;
             }
             PrimitiveKind::AlignedGradient => {
                 let gradient = &mut self.cpu_gradients[metadata.cpu_prim_index.0];
                 if gradient.cache_dirty {
-                    let src_stops = auxiliary_lists.gradient_stops(&gradient.stops_range);
+                    let src_stops = display_list.get(gradient.stops_range);
 
-                    debug_assert!(metadata.gpu_data_count == gradient.stops_range.length as i32);
+                    debug_assert!(metadata.gpu_data_count == src_stops.len() as i32);
                     let dest_stops = self.gpu_data32.get_slice_mut(metadata.gpu_data_address,
-                                                                   gradient.stops_range.length);
+                                                                   src_stops.len());
 
-                    for (src, dest) in src_stops.iter().zip(dest_stops.iter_mut()) {
+                    for (src, dest) in src_stops.zip(dest_stops.iter_mut()) {
                         *dest = GpuBlock32::from(GradientStopGpu {
                             offset: src.offset,
                             color: src.color,
                             padding: [0.0; 3],
                         });
                     }
 
                     gradient.cache_dirty = false;
                 }
             }
             PrimitiveKind::AngleGradient => {
                 let gradient = &mut self.cpu_gradients[metadata.cpu_prim_index.0];
                 if gradient.cache_dirty {
-                    let src_stops = auxiliary_lists.gradient_stops(&gradient.stops_range);
+                    let src_stops = display_list.get(gradient.stops_range);
+
                     let dest_gradient = self.gpu_gradient_data.get_mut(metadata.gpu_data_address);
                     dest_gradient.build(src_stops, gradient.reverse_stops);
                     gradient.cache_dirty = false;
                 }
             }
             PrimitiveKind::RadialGradient => {
                 let gradient = &mut self.cpu_radial_gradients[metadata.cpu_prim_index.0];
                 if gradient.cache_dirty {
-                    let src_stops = auxiliary_lists.gradient_stops(&gradient.stops_range);
+                    let src_stops = display_list.get(gradient.stops_range);
+
                     let dest_gradient = self.gpu_gradient_data.get_mut(metadata.gpu_data_address);
                     dest_gradient.build(src_stops, false);
                     gradient.cache_dirty = false;
                 }
             }
         }
 
         if prim_needs_resolve {
--- a/gfx/webrender/src/render_backend.rs
+++ b/gfx/webrender/src/render_backend.rs
@@ -13,17 +13,17 @@ use std::collections::HashMap;
 use std::sync::{Arc, Mutex};
 use std::sync::mpsc::Sender;
 use texture_cache::TextureCache;
 use time::precise_time_ns;
 use thread_profiler::register_thread_with_profiler;
 use threadpool::ThreadPool;
 use webgl_types::{GLContextHandleWrapper, GLContextWrapper};
 use webrender_traits::{DeviceIntPoint, DeviceUintPoint, DeviceUintRect, DeviceUintSize, LayerPoint};
-use webrender_traits::{ApiMsg, AuxiliaryLists, BuiltDisplayList, IdNamespace, ImageData};
+use webrender_traits::{ApiMsg, BuiltDisplayList, IdNamespace, ImageData};
 use webrender_traits::{PipelineId, RenderNotifier, RenderDispatcher, WebGLCommand, WebGLContextId};
 use webrender_traits::channel::{PayloadSenderHelperMethods, PayloadReceiverHelperMethods, PayloadReceiver, PayloadSender, MsgReceiver};
 use webrender_traits::{BlobImageRenderer, VRCompositorCommand, VRCompositorHandler};
 #[cfg(feature = "webgl")]
 use offscreen_gl_context::GLContextDispatcher;
 #[cfg(not(feature = "webgl"))]
 use webgl_types::GLContextDispatcher;
 
@@ -176,73 +176,67 @@ impl RenderBackend {
 
                             sender.send(result).unwrap();
                         }
                         ApiMsg::SetDisplayList(background_color,
                                                epoch,
                                                pipeline_id,
                                                viewport_size,
                                                display_list_descriptor,
-                                               auxiliary_lists_descriptor,
                                                preserve_frame_state) => {
                             profile_scope!("SetDisplayList");
-                            let mut leftover_auxiliary_data = vec![];
-                            let mut auxiliary_data;
+                            let mut leftover_data = vec![];
+                            let mut data;
                             loop {
-                                auxiliary_data = self.payload_rx.recv_payload().unwrap();
+                                data = self.payload_rx.recv_payload().unwrap();
                                 {
-                                    if auxiliary_data.epoch == epoch &&
-                                       auxiliary_data.pipeline_id == pipeline_id {
+                                    if data.epoch == epoch &&
+                                       data.pipeline_id == pipeline_id {
                                         break
                                     }
                                 }
-                                leftover_auxiliary_data.push(auxiliary_data)
+                                leftover_data.push(data)
                             }
-                            for leftover_auxiliary_data in leftover_auxiliary_data {
-                                self.payload_tx.send_payload(leftover_auxiliary_data).unwrap()
+                            for leftover_data in leftover_data {
+                                self.payload_tx.send_payload(leftover_data).unwrap()
                             }
                             if let Some(ref mut r) = self.recorder {
-                                r.write_payload(frame_counter, &auxiliary_data.to_data());
+                                r.write_payload(frame_counter, &data.to_data());
                             }
 
                             let built_display_list =
-                                BuiltDisplayList::from_data(auxiliary_data.display_list_data,
+                                BuiltDisplayList::from_data(data.display_list_data,
                                                             display_list_descriptor);
-                            let auxiliary_lists =
-                                AuxiliaryLists::from_data(auxiliary_data.auxiliary_lists_data,
-                                                          auxiliary_lists_descriptor);
 
                             if !preserve_frame_state {
                                 self.discard_frame_state_for_pipeline(pipeline_id);
                             }
-                            
+
                             let display_list_len = built_display_list.data().len();
-                            let aux_list_len = auxiliary_lists.data().len();
                             let (builder_start_time, builder_finish_time) = built_display_list.times();
 
                             let display_list_received_time = precise_time_ns();
-                            
+
                             profile_counters.total_time.profile(|| {
                                 self.scene.set_display_list(pipeline_id,
                                                             epoch,
                                                             built_display_list,
                                                             background_color,
-                                                            viewport_size,
-                                                            auxiliary_lists);
+                                                            viewport_size);
                                 self.build_scene();
                             });
 
-                            // Note: this isn't quite right as auxiliary values will be 
+                            // Note: this isn't quite right as auxiliary values will be
                             // pulled out somewhere in the prim_store, but aux values are
                             // really simple and cheap to access, so it's not a big deal.
                             let display_list_consumed_time = precise_time_ns();
 
-                            profile_counters.ipc.set(builder_start_time, builder_finish_time, 
+                            profile_counters.ipc.set(builder_start_time, builder_finish_time,
                                                      display_list_received_time, display_list_consumed_time,
-                                                     display_list_len + aux_list_len);
+                                                     display_list_len);
                         }
                         ApiMsg::SetRootPipeline(pipeline_id) => {
                             profile_scope!("SetRootPipeline");
                             self.scene.set_root_pipeline_id(pipeline_id);
 
                             if self.scene.display_lists.get(&pipeline_id).is_none() {
                                 continue;
                             }
@@ -486,17 +480,17 @@ impl RenderBackend {
 
     fn render(&mut self,
               texture_cache_profile: &mut TextureCacheProfileCounters)
               -> RendererFrame {
         let accumulated_scale_factor = self.accumulated_scale_factor();
         let pan = LayerPoint::new(self.pan.x as f32 / accumulated_scale_factor,
                                   self.pan.y as f32 / accumulated_scale_factor);
         let frame = self.frame.build(&mut self.resource_cache,
-                                     &self.scene.pipeline_auxiliary_lists,
+                                     &self.scene.display_lists,
                                      accumulated_scale_factor,
                                      pan,
                                      texture_cache_profile);
         frame
     }
 
     fn publish_frame(&mut self,
                      frame: RendererFrame,
--- a/gfx/webrender/src/scene.rs
+++ b/gfx/webrender/src/scene.rs
@@ -1,18 +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 fnv::FnvHasher;
 use std::collections::HashMap;
 use std::hash::BuildHasherDefault;
-use tiling::AuxiliaryListsMap;
-use webrender_traits::{AuxiliaryLists, BuiltDisplayList, PipelineId, Epoch, ColorF};
-use webrender_traits::{DisplayItem, DynamicProperties, LayerSize, LayoutTransform};
+use webrender_traits::{BuiltDisplayList, PipelineId, Epoch, ColorF};
+use webrender_traits::{DynamicProperties, LayerSize, LayoutTransform};
 use webrender_traits::{PropertyBinding, PropertyBindingId};
 
 /// Stores a map of the animated property bindings for the current display list. These
 /// can be used to animate the transform and/or opacity of a display list without
 /// re-submitting the display list itself.
 pub struct SceneProperties {
     transform_properties: HashMap<PropertyBindingId, LayoutTransform>,
     float_properties: HashMap<PropertyBindingId, f32>,
@@ -88,46 +87,42 @@ pub struct ScenePipeline {
     pub viewport_size: LayerSize,
     pub background_color: Option<ColorF>,
 }
 
 /// A complete representation of the layout bundling visible pipelines together.
 pub struct Scene {
     pub root_pipeline_id: Option<PipelineId>,
     pub pipeline_map: HashMap<PipelineId, ScenePipeline, BuildHasherDefault<FnvHasher>>,
-    pub pipeline_auxiliary_lists: AuxiliaryListsMap,
-    pub display_lists: HashMap<PipelineId, Vec<DisplayItem>, BuildHasherDefault<FnvHasher>>,
+    pub display_lists: HashMap<PipelineId, BuiltDisplayList, BuildHasherDefault<FnvHasher>>,
     pub properties: SceneProperties,
 }
 
 impl Scene {
     pub fn new() -> Scene {
         Scene {
             root_pipeline_id: None,
             pipeline_map: HashMap::default(),
-            pipeline_auxiliary_lists: HashMap::default(),
             display_lists: HashMap::default(),
             properties: SceneProperties::new(),
         }
     }
 
     pub fn set_root_pipeline_id(&mut self, pipeline_id: PipelineId) {
         self.root_pipeline_id = Some(pipeline_id);
     }
 
     pub fn set_display_list(&mut self,
                             pipeline_id: PipelineId,
                             epoch: Epoch,
                             built_display_list: BuiltDisplayList,
                             background_color: Option<ColorF>,
-                            viewport_size: LayerSize,
-                            auxiliary_lists: AuxiliaryLists) {
+                            viewport_size: LayerSize) {
 
-        self.pipeline_auxiliary_lists.insert(pipeline_id, auxiliary_lists);
-        self.display_lists.insert(pipeline_id, built_display_list.into_display_items());
+        self.display_lists.insert(pipeline_id, built_display_list);
         
         let new_pipeline = ScenePipeline {
             pipeline_id: pipeline_id,
             epoch: epoch,
             viewport_size: viewport_size,
             background_color: background_color,
         };
 
--- a/gfx/webrender/src/tiling.rs
+++ b/gfx/webrender/src/tiling.rs
@@ -19,31 +19,31 @@ use render_task::RenderTaskLocation;
 use renderer::BlendMode;
 use renderer::ImageBufferKind;
 use resource_cache::ResourceCache;
 use std::{f32, i32, mem, usize};
 use std::collections::HashMap;
 use std::hash::BuildHasherDefault;
 use texture_cache::TexturePage;
 use util::{TransformedRect, TransformedRectKind};
-use webrender_traits::{AuxiliaryLists, ClipAndScrollInfo, ClipId, ColorF, DeviceIntPoint};
+use webrender_traits::{BuiltDisplayList, ClipAndScrollInfo, ClipId, ColorF, DeviceIntPoint};
 use webrender_traits::{DeviceIntRect, DeviceIntSize, DeviceUintPoint, DeviceUintSize};
 use webrender_traits::{ExternalImageType, FontRenderMode, ImageRendering, LayerPoint, LayerRect};
 use webrender_traits::{LayerToWorldTransform, MixBlendMode, PipelineId, TransformStyle};
 use webrender_traits::{WorldPoint4D, WorldToLayerTransform};
 use webrender_traits::{YuvColorSpace, YuvFormat};
 
 // Special sentinel value recognized by the shader. It is considered to be
 // a dummy task that doesn't mask out anything.
 const OPAQUE_TASK_INDEX: RenderTaskIndex = RenderTaskIndex(i32::MAX as usize);
 
 
-pub type AuxiliaryListsMap = HashMap<PipelineId,
-                                     AuxiliaryLists,
-                                     BuildHasherDefault<FnvHasher>>;
+pub type DisplayListMap = HashMap<PipelineId,
+                                  BuiltDisplayList,
+                                  BuildHasherDefault<FnvHasher>>;
 
 trait AlphaBatchHelpers {
     fn get_color_textures(&self, metadata: &PrimitiveMetadata) -> [SourceTexture; 3];
     fn get_blend_mode(&self,
                       needs_blending: bool,
                       metadata: &PrimitiveMetadata) -> BlendMode;
 }
 
--- a/gfx/webrender_bindings/webrender_ffi_generated.h
+++ b/gfx/webrender_bindings/webrender_ffi_generated.h
@@ -206,30 +206,16 @@ struct WrVecU8 {
 
   bool operator==(const WrVecU8& aOther) const {
     return data == aOther.data &&
            length == aOther.length &&
            capacity == aOther.capacity;
   }
 };
 
-struct WrAuxiliaryListsDescriptor {
-  size_t gradient_stops_size;
-  size_t complex_clip_regions_size;
-  size_t filters_size;
-  size_t glyph_instances_size;
-
-  bool operator==(const WrAuxiliaryListsDescriptor& aOther) const {
-    return gradient_stops_size == aOther.gradient_stops_size &&
-           complex_clip_regions_size == aOther.complex_clip_regions_size &&
-           filters_size == aOther.filters_size &&
-           glyph_instances_size == aOther.glyph_instances_size;
-  }
-};
-
 struct WrOpacityProperty {
   uint64_t id;
   float opacity;
 
   bool operator==(const WrOpacityProperty& aOther) const {
     return id == aOther.id &&
            opacity == aOther.opacity;
   }
--- a/gfx/webrender_traits/Cargo.toml
+++ b/gfx/webrender_traits/Cargo.toml
@@ -7,16 +7,17 @@ repository = "https://github.com/servo/w
 
 [features]
 nightly = ["euclid/unstable", "serde/unstable"]
 ipc = ["ipc-channel"]
 webgl = ["offscreen_gl_context"]
 
 [dependencies]
 app_units = "0.4"
+bincode = "1.0.0-alpha2"
 byteorder = "1.0"
 euclid = "0.11"
 gleam = "0.4"
 heapsize = "0.3.6"
 ipc-channel = {version = "0.7", optional = true}
 offscreen_gl_context = {version = "0.8", features = ["serde"], optional = true}
 serde = "0.9"
 serde_derive = "0.9"
--- a/gfx/webrender_traits/src/api.rs
+++ b/gfx/webrender_traits/src/api.rs
@@ -3,17 +3,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 use channel::{self, MsgSender, Payload, PayloadSenderHelperMethods, PayloadSender};
 #[cfg(feature = "webgl")]
 use offscreen_gl_context::{GLContextAttributes, GLLimits};
 use std::cell::Cell;
 use std::fmt;
 use std::marker::PhantomData;
-use {AuxiliaryLists, AuxiliaryListsDescriptor, BuiltDisplayList, BuiltDisplayListDescriptor};
+use {BuiltDisplayList, BuiltDisplayListDescriptor};
 use {ClipId, ColorF, DeviceIntPoint, DeviceIntSize, DeviceUintRect, DeviceUintSize, FontKey};
 use {GlyphDimensions, GlyphKey, ImageData, ImageDescriptor, ImageKey, LayoutPoint, LayoutSize};
 use {LayoutTransform, NativeFontHandle, WorldPoint};
 #[cfg(feature = "webgl")]
 use {WebGLCommand, WebGLContextId};
 
 pub type TileSize = u16;
 
@@ -28,24 +28,22 @@ pub enum ApiMsg {
     AddImage(ImageKey, ImageDescriptor, ImageData, Option<TileSize>),
     /// Updates the the resource cache with the new image data.
     UpdateImage(ImageKey, ImageDescriptor, ImageData, Option<DeviceUintRect>),
     /// Drops an image from the resource cache.
     DeleteImage(ImageKey),
     CloneApi(MsgSender<IdNamespace>),
     /// Supplies a new frame to WebRender.
     ///
-    /// After receiving this message, WebRender will read the display list, followed by the
-    /// auxiliary lists, from the payload channel.
+    /// After receiving this message, WebRender will read the display list from the payload channel.
     SetDisplayList(Option<ColorF>,
                    Epoch,
                    PipelineId,
                    LayoutSize,
                    BuiltDisplayListDescriptor,
-                   AuxiliaryListsDescriptor,
                    bool),
     SetPageZoom(ZoomFactor),
     SetPinchZoom(ZoomFactor),
     SetPan(DeviceIntPoint),
     SetRootPipeline(PipelineId),
     SetWindowParameters(DeviceUintSize, DeviceUintRect),
     Scroll(ScrollLocation, WorldPoint, ScrollEventPhase),
     ScrollNodeWithId(LayoutPoint, ClipId),
@@ -289,44 +287,40 @@ impl RenderApi {
     ///
     /// Arguments:
     ///
     /// * `background_color`: The background color of this pipeline.
     /// * `epoch`: The unique Frame ID, monotonically increasing.
     /// * `viewport_size`: The size of the viewport for this frame.
     /// * `pipeline_id`: The ID of the pipeline that is supplying this display list.
     /// * `display_list`: The root Display list used in this frame.
-    /// * `auxiliary_lists`: Various items that the display lists and stacking contexts reference.
     /// * `preserve_frame_state`: If a previous frame exists which matches this pipeline
     ///                           id, this setting determines if frame state (such as scrolling
     ///                           position) should be preserved for this new display list.
     ///
     /// [notifier]: trait.RenderNotifier.html#tymethod.new_frame_ready
     pub fn set_display_list(&self,
                             background_color: Option<ColorF>,
                             epoch: Epoch,
                             viewport_size: LayoutSize,
-                            (pipeline_id, display_list, auxiliary_lists): (PipelineId, BuiltDisplayList, AuxiliaryLists),
+                            (pipeline_id, display_list): (PipelineId, BuiltDisplayList),
                             preserve_frame_state: bool) {
         let (dl_data, dl_desc) = display_list.into_data();
-        let (aux_data, aux_desc) = auxiliary_lists.into_data();
         let msg = ApiMsg::SetDisplayList(background_color,
                                              epoch,
                                              pipeline_id,
                                              viewport_size,
                                              dl_desc,
-                                             aux_desc,
                                              preserve_frame_state);
         self.api_sender.send(msg).unwrap();
 
         self.payload_sender.send_payload(Payload {
             epoch: epoch,
             pipeline_id: pipeline_id,
             display_list_data: dl_data,
-            auxiliary_lists_data: aux_data
         }).unwrap();
     }
 
     /// Scrolls the scrolling layer under the `cursor`
     ///
     /// WebRender looks for the layer closest to the user
     /// which has `ScrollPolicy::Scrollable` set.
     pub fn scroll(&self, scroll_location: ScrollLocation, cursor: WorldPoint, phase: ScrollEventPhase) {
--- a/gfx/webrender_traits/src/channel.rs
+++ b/gfx/webrender_traits/src/channel.rs
@@ -13,64 +13,55 @@ pub struct Payload {
     ///
     /// TODO(emilio): Is this still relevant? We send the messages for the same
     /// pipeline in order, so we shouldn't need it. Seems like this was only
     /// wallpapering (in most cases) the underlying problem in #991.
     pub epoch: Epoch,
     /// A pipeline id to key the payload with, along with the epoch.
     pub pipeline_id: PipelineId,
     pub display_list_data: Vec<u8>,
-    pub auxiliary_lists_data: Vec<u8>
 }
 
 impl Payload {
     /// Convert the payload to a raw byte vector, in order for it to be
     /// efficiently shared via shmem, for example.
     ///
     /// TODO(emilio, #1049): Consider moving the IPC boundary to the
     /// constellation in Servo and remove this complexity from WR.
     pub fn to_data(&self) -> Vec<u8> {
         let mut data = Vec::with_capacity(mem::size_of::<u32>() +
                                           2 * mem::size_of::<u32>() +
                                           mem::size_of::<u64>() +
-                                          self.display_list_data.len() +
-                                          mem::size_of::<u64>() +
-                                          self.auxiliary_lists_data.len());
+                                          self.display_list_data.len());
         data.write_u32::<LittleEndian>(self.epoch.0).unwrap();
         data.write_u32::<LittleEndian>(self.pipeline_id.0).unwrap();
         data.write_u32::<LittleEndian>(self.pipeline_id.1).unwrap();
         data.write_u64::<LittleEndian>(self.display_list_data.len() as u64).unwrap();
         data.extend_from_slice(&self.display_list_data);
-        data.write_u64::<LittleEndian>(self.auxiliary_lists_data.len() as u64).unwrap();
-        data.extend_from_slice(&self.auxiliary_lists_data);
         data
     }
 
     /// Deserializes the given payload from a raw byte vector.
     pub fn from_data(data: &[u8]) -> Payload {
         let mut payload_reader = Cursor::new(data);
         let epoch = Epoch(payload_reader.read_u32::<LittleEndian>().unwrap());
         let pipeline_id = PipelineId(payload_reader.read_u32::<LittleEndian>().unwrap(),
                                      payload_reader.read_u32::<LittleEndian>().unwrap());
 
         let dl_size = payload_reader.read_u64::<LittleEndian>().unwrap() as usize;
         let mut built_display_list_data = vec![0; dl_size];
         payload_reader.read_exact(&mut built_display_list_data[..]).unwrap();
 
-        let aux_size = payload_reader.read_u64::<LittleEndian>().unwrap() as usize;
-        let mut auxiliary_lists_data = vec![0; aux_size];
-        payload_reader.read_exact(&mut auxiliary_lists_data[..]).unwrap();
+        // TODO(new-ipc): assert_eq!(payload_reader.position(), data.len() as u64);
 
-        assert_eq!(payload_reader.position(), data.len() as u64);
 
         Payload {
             epoch: epoch,
             pipeline_id: pipeline_id,
             display_list_data: built_display_list_data,
-            auxiliary_lists_data: auxiliary_lists_data,
         }
     }
 }
 
 
 /// A helper to handle the interface difference between `IpcBytesSender`
 /// and `Sender<Vec<u8>>`.
 pub trait PayloadSenderHelperMethods {
--- a/gfx/webrender_traits/src/display_item.rs
+++ b/gfx/webrender_traits/src/display_item.rs
@@ -1,19 +1,23 @@
 /* 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 app_units::Au;
 use euclid::SideOffsets2D;
-use display_list::AuxiliaryListsBuilder;
-use {ColorF, FontKey, ImageKey, PipelineId, WebGLContextId};
+use {ColorF, FontKey, ImageKey, ItemRange, PipelineId, WebGLContextId};
 use {LayoutPoint, LayoutRect, LayoutSize, LayoutTransform};
 use {PropertyBinding};
 
+// NOTE: some of these structs have an "IMPLICIT" comment.
+// This indicates that the BuiltDisplayList will have serialized
+// a list of values nearby that this item consumes. The traversal
+// iterator should handle finding these.
+
 #[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
 pub struct ClipAndScrollInfo {
     pub scroll_node_id: ClipId,
     pub clip_node_id: Option<ClipId>,
 }
 
 impl ClipAndScrollInfo {
     pub fn simple(node_id: ClipId) -> ClipAndScrollInfo {
@@ -34,17 +38,16 @@ impl ClipAndScrollInfo {
         self.clip_node_id.unwrap_or(self.scroll_node_id)
     }
 }
 
 #[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)]
 pub struct DisplayItem {
     pub item: SpecificDisplayItem,
     pub rect: LayoutRect,
-    pub clip: ClipRegion,
     pub clip_and_scroll: ClipAndScrollInfo,
 }
 
 #[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)]
 pub enum SpecificDisplayItem {
     Clip(ClipDisplayItem),
     Rectangle(RectangleDisplayItem),
     Text(TextDisplayItem),
@@ -53,45 +56,39 @@ pub enum SpecificDisplayItem {
     WebGL(WebGLDisplayItem),
     Border(BorderDisplayItem),
     BoxShadow(BoxShadowDisplayItem),
     Gradient(GradientDisplayItem),
     RadialGradient(RadialGradientDisplayItem),
     Iframe(IframeDisplayItem),
     PushStackingContext(PushStackingContextDisplayItem),
     PopStackingContext,
-}
-
-#[repr(C)]
-#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
-pub struct ItemRange {
-    pub start: usize,
-    pub length: usize,
+    SetGradientStops,
+    SetClipRegion(ClipRegion),
 }
 
 #[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)]
 pub struct ClipDisplayItem {
     pub id: ClipId,
     pub parent_id: ClipId,
 }
 
 #[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)]
 pub struct RectangleDisplayItem {
     pub color: ColorF,
 }
 
 #[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)]
 pub struct TextDisplayItem {
-    pub glyphs: ItemRange,
     pub font_key: FontKey,
     pub size: Au,
     pub color: ColorF,
     pub blur_radius: Au,
     pub glyph_options: Option<GlyphOptions>,
-}
+} // IMPLICIT: glyphs: Vec<GlyphInstance>
 
 #[derive(Clone, Copy, Debug, Deserialize, Hash, Eq, PartialEq, PartialOrd, Ord, Serialize)]
 pub struct GlyphOptions {
     // These are currently only used on windows for dwrite fonts.
     pub use_embedded_bitmap: bool,
     pub force_gdi_rendering: bool,
 }
 
@@ -224,19 +221,18 @@ pub enum ExtendMode {
     Clamp,
     Repeat,
 }
 
 #[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)]
 pub struct Gradient {
     pub start_point: LayoutPoint,
     pub end_point: LayoutPoint,
-    pub stops: ItemRange,
     pub extend_mode: ExtendMode,
-}
+} // IMPLICIT: stops: Vec<GradientStop>
 
 #[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)]
 pub struct GradientDisplayItem {
     pub gradient: Gradient,
     pub tile_size: LayoutSize,
     pub tile_spacing: LayoutSize,
 }
 
@@ -250,19 +246,18 @@ known_heap_size!(0, GradientStop);
 
 #[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)]
 pub struct RadialGradient {
     pub start_center: LayoutPoint,
     pub start_radius: f32,
     pub end_center: LayoutPoint,
     pub end_radius: f32,
     pub ratio_xy: f32,
-    pub stops: ItemRange,
     pub extend_mode: ExtendMode,
-}
+} // IMPLICIT stops: Vec<GradientStop>
 
 #[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)]
 pub struct RadialGradientDisplayItem {
     pub gradient: RadialGradient,
     pub tile_size: LayoutSize,
     pub tile_spacing: LayoutSize,
 }
 
@@ -273,18 +268,17 @@ pub struct PushStackingContextDisplayIte
 
 #[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)]
 pub struct StackingContext {
     pub scroll_policy: ScrollPolicy,
     pub transform: Option<PropertyBinding<LayoutTransform>>,
     pub transform_style: TransformStyle,
     pub perspective: Option<LayoutTransform>,
     pub mix_blend_mode: MixBlendMode,
-    pub filters: ItemRange,
-}
+} // IMPLICIT: filters: Vec<FilterOp>
 
 #[repr(u32)]
 #[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
 pub enum ScrollPolicy {
     Scrollable  = 0,
     Fixed       = 1,
 }
 
@@ -418,48 +412,31 @@ pub struct ImageMask {
     pub image: ImageKey,
     pub rect: LayoutRect,
     pub repeat: bool,
 }
 
 #[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)]
 pub struct ClipRegion {
     pub main: LayoutRect,
-    pub complex: ItemRange,
     pub image_mask: Option<ImageMask>,
-}
+    #[serde(default, skip_serializing, skip_deserializing)]
+    pub complex_clips: ItemRange<ComplexClipRegion>,
+    #[serde(default, skip_serializing, skip_deserializing)]
+    pub complex_clip_count: usize,
+} 
 
 #[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)]
 pub struct ComplexClipRegion {
     /// The boundaries of the rectangle.
     pub rect: LayoutRect,
     /// Border radii of this rectangle.
     pub radii: BorderRadius,
 }
 
-impl StackingContext {
-    pub fn new(scroll_policy: ScrollPolicy,
-               transform: Option<PropertyBinding<LayoutTransform>>,
-               transform_style: TransformStyle,
-               perspective: Option<LayoutTransform>,
-               mix_blend_mode: MixBlendMode,
-               filters: Vec<FilterOp>,
-               auxiliary_lists_builder: &mut AuxiliaryListsBuilder)
-               -> StackingContext {
-        StackingContext {
-            scroll_policy: scroll_policy,
-            transform: transform,
-            transform_style: transform_style,
-            perspective: perspective,
-            mix_blend_mode: mix_blend_mode,
-            filters: auxiliary_lists_builder.add_filters(&filters),
-        }
-    }
-}
-
 impl BorderRadius {
     pub fn zero() -> BorderRadius {
         BorderRadius {
             top_left: LayoutSize::new(0.0, 0.0),
             top_right: LayoutSize::new(0.0, 0.0),
             bottom_left: LayoutSize::new(0.0, 0.0),
             bottom_right: LayoutSize::new(0.0, 0.0),
         }
@@ -507,37 +484,46 @@ impl BorderRadius {
         } else {
             false
         }
     }
 }
 
 impl ClipRegion {
     pub fn new(rect: &LayoutRect,
-               complex: Vec<ComplexClipRegion>,
-               image_mask: Option<ImageMask>,
-               auxiliary_lists_builder: &mut AuxiliaryListsBuilder)
+               image_mask: Option<ImageMask>)
                -> ClipRegion {
         ClipRegion {
             main: *rect,
-            complex: auxiliary_lists_builder.add_complex_clip_regions(&complex),
             image_mask: image_mask,
+            complex_clips: ItemRange::default(),
+            complex_clip_count: 0,
         }
     }
 
     pub fn simple(rect: &LayoutRect) -> ClipRegion {
         ClipRegion {
             main: *rect,
-            complex: ItemRange::empty(),
             image_mask: None,
+            complex_clips: ItemRange::default(),
+            complex_clip_count: 0,
+        }
+    }
+
+    pub fn empty() -> ClipRegion {
+        ClipRegion {
+            main: LayoutRect::zero(),
+            image_mask: None,
+            complex_clips: ItemRange::default(),
+            complex_clip_count: 0,
         }
     }
 
     pub fn is_complex(&self) -> bool {
-        self.complex.length !=0 || self.image_mask.is_some()
+        self.complex_clip_count != 0 || self.image_mask.is_some()
     }
 }
 
 impl ColorF {
     pub fn new(r: f32, g: f32, b: f32, a: f32) -> ColorF {
         ColorF {
             r: r,
             g: g,
--- a/gfx/webrender_traits/src/display_list.rs
+++ b/gfx/webrender_traits/src/display_list.rs
@@ -1,69 +1,100 @@
 /* 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 app_units::Au;
-use std::mem;
-use std::slice;
+use bincode;
+use serde::{Deserialize, Serialize, Serializer};
+use serde::ser::{SerializeSeq, SerializeMap};
 use time::precise_time_ns;
 use {BorderDetails, BorderDisplayItem, BorderWidths, BoxShadowClipMode, BoxShadowDisplayItem};
-use {ClipAndScrollInfo, ClipDisplayItem, ClipId, ClipRegion, ColorF, ComplexClipRegion};
-use {DisplayItem, ExtendMode, FilterOp, FontKey, GlyphInstance, GlyphOptions, Gradient};
-use {GradientDisplayItem, GradientStop, IframeDisplayItem, ImageDisplayItem, ImageKey, ImageMask};
-use {ImageRendering, ItemRange, LayoutPoint, LayoutRect, LayoutSize, LayoutTransform};
-use {MixBlendMode, PipelineId, PropertyBinding, PushStackingContextDisplayItem, RadialGradient};
-use {RadialGradientDisplayItem, RectangleDisplayItem, ScrollPolicy, SpecificDisplayItem};
-use {StackingContext, TextDisplayItem, TransformStyle, WebGLContextId, WebGLDisplayItem};
-use {YuvColorSpace, YuvData, YuvImageDisplayItem};
+use {ClipAndScrollInfo, ClipDisplayItem, ClipId, ClipRegion, ColorF, ComplexClipRegion, DisplayItem};
+use {ExtendMode, FilterOp, FontKey, GlyphInstance, GlyphOptions, Gradient, GradientDisplayItem};
+use {GradientStop, IframeDisplayItem, ImageDisplayItem, ImageKey, ImageMask, ImageRendering};
+use {LayoutPoint, LayoutRect, LayoutSize, LayoutTransform, MixBlendMode, PipelineId};
+use {PropertyBinding, PushStackingContextDisplayItem, RadialGradient, RadialGradientDisplayItem};
+use {RectangleDisplayItem, ScrollPolicy, SpecificDisplayItem, StackingContext, TextDisplayItem};
+use {TransformStyle, WebGLContextId, WebGLDisplayItem, YuvColorSpace, YuvData, YuvImageDisplayItem};
+use std::marker::PhantomData;
 
-#[derive(Clone, Deserialize, Serialize)]
-pub struct AuxiliaryLists {
-    /// The concatenation of: gradient stops, complex clip regions, filters, and glyph instances,
-    /// in that order.
-    data: Vec<u8>,
-    descriptor: AuxiliaryListsDescriptor,
+#[repr(C)]
+#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
+pub struct ItemRange<T> {
+    start: usize,
+    length: usize,
+    _boo: PhantomData<T>,
 }
 
-/// Describes the memory layout of the auxiliary lists.
-///
-/// Auxiliary lists consist of some number of gradient stops, complex clip regions, filters, and
-/// glyph instances, in that order.
-#[repr(C)]
-#[derive(Clone, Copy, Debug, Deserialize, Serialize)]
-pub struct AuxiliaryListsDescriptor {
-    gradient_stops_size: usize,
-    complex_clip_regions_size: usize,
-    filters_size: usize,
-    glyph_instances_size: usize,
+impl<T> Default for ItemRange<T> {
+    fn default() -> Self {
+        ItemRange { start: 0, length: 0, _boo: PhantomData }
+    }
+}
+
+impl<T> ItemRange<T> {
+    pub fn is_empty(&self) -> bool {
+        // Nothing more than space for a length (0).
+        self.length <= ::std::mem::size_of::<u64>()
+    }
 }
 
 /// A display list.
-#[derive(Clone, Deserialize, Serialize)]
+#[derive(Clone, Default)]
 pub struct BuiltDisplayList {
+    /// Serde encoded bytes. Mostly DisplayItems, but some mixed in slices.
     data: Vec<u8>,
     descriptor: BuiltDisplayListDescriptor,
 }
 
 /// Describes the memory layout of a display list.
 ///
 /// A display list consists of some number of display list items, followed by a number of display
 /// items.
 #[repr(C)]
-#[derive(Copy, Clone, Deserialize, Serialize)]
+#[derive(Copy, Clone, Default, Deserialize, Serialize)]
 pub struct BuiltDisplayListDescriptor {
     /// The size in bytes of the display list items in this display list.
     display_list_items_size: usize,
     /// The first IPC time stamp: before any work has been done
     builder_start_time: u64,
     /// The second IPC time stamp: after serialization
     builder_finish_time: u64,
 }
 
+pub struct BuiltDisplayListIter<'a> {
+    list: &'a BuiltDisplayList,
+    data: &'a [u8],
+    cur_item: DisplayItem,
+    cur_stops: ItemRange<GradientStop>,
+    cur_glyphs: ItemRange<GlyphInstance>,
+    cur_filters: ItemRange<FilterOp>,
+    cur_clip: ClipRegion,
+    peeking: Peek,
+}
+
+pub struct DisplayItemRef<'a: 'b, 'b> {
+    iter: &'b BuiltDisplayListIter<'a>,
+}
+
+#[derive(PartialEq)]
+enum Peek {
+    StartPeeking,
+    IsPeeking,
+    NotPeeking,
+}
+
+#[derive(Clone)]
+pub struct AuxIter<'a, T> {
+    data: &'a [u8],
+    size: usize,
+    _boo: PhantomData<T>,
+}
+
 impl BuiltDisplayListDescriptor {
     pub fn size(&self) -> usize {
         self.display_list_items_size
     }
 }
 
 impl BuiltDisplayList {
     pub fn from_data(data: Vec<u8>, descriptor: BuiltDisplayListDescriptor) -> BuiltDisplayList {
@@ -80,159 +111,471 @@ impl BuiltDisplayList {
     pub fn data(&self) -> &[u8] {
         &self.data[..]
     }
 
     pub fn descriptor(&self) -> &BuiltDisplayListDescriptor {
         &self.descriptor
     }
 
-    pub fn all_display_items(&self) -> &[DisplayItem] {
-        unsafe {
-            convert_blob_to_pod(&self.data)
+    pub fn times(&self) -> (u64, u64) {
+      (self.descriptor.builder_start_time, self.descriptor.builder_finish_time)
+    }
+
+    pub fn iter(&self) -> BuiltDisplayListIter {
+        BuiltDisplayListIter::new(self)
+    }
+
+    pub fn get<T: Deserialize>(&self, range: ItemRange<T>) -> AuxIter<T> {
+        AuxIter::new(&self.data[range.start .. range.start + range.length])
+    }
+}
+
+impl<'a> BuiltDisplayListIter<'a> {
+    pub fn new(list: &'a BuiltDisplayList) -> Self {
+        BuiltDisplayListIter {
+            list: list,
+            data: &list.data,
+            // Dummy data, will be overwritten by `next`
+            cur_item: DisplayItem {
+                item: SpecificDisplayItem::PopStackingContext,
+                rect: LayoutRect::zero(),
+                clip_and_scroll: ClipAndScrollInfo::simple(ClipId::new(0, PipelineId(0, 0))),
+            },
+            cur_stops: ItemRange::default(),
+            cur_glyphs: ItemRange::default(),
+            cur_filters: ItemRange::default(),
+            cur_clip: ClipRegion::empty(),
+            peeking: Peek::NotPeeking,
+        }
+    }
+
+    pub fn display_list(&self) -> &'a BuiltDisplayList {
+        self.list
+    }
+
+    pub fn next<'b>(&'b mut self) -> Option<DisplayItemRef<'a, 'b>> {
+        use SpecificDisplayItem::*;
+
+        match self.peeking {
+            Peek::IsPeeking => {
+                self.peeking = Peek::NotPeeking;
+                return Some(self.as_ref())
+            }
+            Peek::StartPeeking => {
+                self.peeking = Peek::IsPeeking;
+            }
+            Peek::NotPeeking => { /* do nothing */ }
+        }
+
+        // Don't let these bleed into another item
+        self.cur_stops = ItemRange::default();
+        self.cur_clip = ClipRegion::empty();
+
+        loop {
+            if self.data.len() == 0 {
+                return None
+            }
+
+            self.cur_item = bincode::deserialize_from(&mut self.data, bincode::Infinite)
+                                    .expect("MEH: malicious process?");
+
+            match self.cur_item.item {
+                SetClipRegion(clip) => {
+                    self.cur_clip = clip;
+                    let (clip_range, clip_count) = self.skip_slice::<ComplexClipRegion>();
+                    self.cur_clip.complex_clip_count = clip_count;
+                    self.cur_clip.complex_clips = clip_range;
+
+                    // This is a dummy item, skip over it
+                    continue;
+                }
+                SetGradientStops => {
+                    self.cur_stops = self.skip_slice::<GradientStop>().0;
+
+                    // This is a dummy item, skip over it
+                    continue;
+                }
+                Text(_) => {
+                    self.cur_glyphs = self.skip_slice::<GlyphInstance>().0;
+                }
+                PushStackingContext(_) => {
+                    self.cur_filters = self.skip_slice::<FilterOp>().0;
+                }
+                _ => { /* do nothing */ }
+            }
+
+            break;
+        }
+
+        Some(self.as_ref())
+    }
+
+    /// Returns the byte-range the slice occupied, and the number of elements
+    /// in the slice.
+    fn skip_slice<T: Deserialize>(&mut self) -> (ItemRange<T>, usize) {
+        let base = self.list.data.as_ptr() as usize;
+        let start = self.data.as_ptr() as usize;
+
+        // Read through the values (this is a bit of a hack to reuse logic)
+        let mut iter = AuxIter::<T>::new(self.data);
+        let count = iter.len();
+        for _ in &mut iter {}
+        let end = iter.data.as_ptr() as usize;
+
+        let range = ItemRange { start: start - base, length: end - start, _boo: PhantomData };
+
+        // Adjust data pointer to skip read values
+        self.data = &self.data[range.length..];
+        (range, count)
+    }
+
+    pub fn as_ref<'b>(&'b self) -> DisplayItemRef<'a, 'b> {
+        DisplayItemRef { iter: self }
+    }
+
+    pub fn starting_stacking_context(&mut self)
+        -> Option<(StackingContext, LayoutRect, ItemRange<FilterOp>)> {
+
+        self.next().and_then(|item| match *item.item() {
+            SpecificDisplayItem::PushStackingContext(ref specific_item) => {
+                Some((specific_item.stacking_context, item.rect(), item.filters()))
+            },
+            _ => None,
+        })
+    }
+
+    pub fn skip_current_stacking_context(&mut self) {
+        let mut depth = 0;
+        while let Some(item) = self.next() {
+            match *item.item() {
+                SpecificDisplayItem::PushStackingContext(..) => depth += 1,
+                SpecificDisplayItem::PopStackingContext if depth == 0 => return,
+                SpecificDisplayItem::PopStackingContext => depth -= 1,
+                _ => {}
+            }
+            debug_assert!(depth >= 0);
+        }
+    }
+
+    pub fn current_stacking_context_empty(&mut self) -> bool {
+        match self.peek() {
+            Some(item) => *item.item() == SpecificDisplayItem::PopStackingContext,
+            None => true,
         }
     }
 
-    pub fn into_display_items(self) -> Vec<DisplayItem> {
-        unsafe {
-            convert_vec_blob_to_pod(self.data)
+    pub fn peek<'b>(&'b mut self) -> Option<DisplayItemRef<'a, 'b>> {
+        if self.peeking == Peek::NotPeeking {
+            self.peeking = Peek::StartPeeking;
+            self.next()
+        } else {
+            Some(self.as_ref())
+        }
+    }
+}
+
+// Some of these might just become ItemRanges
+impl<'a, 'b> DisplayItemRef<'a, 'b> {
+    pub fn display_item(&self) -> &DisplayItem {
+        &self.iter.cur_item
+    }
+
+    pub fn rect(&self) -> LayoutRect {
+        self.iter.cur_item.rect
+    }
+
+    pub fn clip_and_scroll(&self) -> ClipAndScrollInfo {
+        self.iter.cur_item.clip_and_scroll
+    }
+
+    pub fn item(&self) -> &SpecificDisplayItem {
+        &self.iter.cur_item.item
+    }
+
+    pub fn clip_region(&self) -> &ClipRegion {
+        &self.iter.cur_clip
+    }
+
+    pub fn gradient_stops(&self) -> ItemRange<GradientStop> {
+        self.iter.cur_stops
+    }
+
+    pub fn glyphs(&self) -> ItemRange<GlyphInstance> {
+        self.iter.cur_glyphs
+    }
+
+    pub fn filters(&self) -> ItemRange<FilterOp> {
+        self.iter.cur_filters
+    }
+
+    pub fn display_list(&self) -> &BuiltDisplayList {
+        self.iter.display_list()
+    }
+
+    // Creates a new iterator where this element's iterator
+    // is, to hack around borrowck.
+    pub fn sub_iter(&self) -> BuiltDisplayListIter<'a> {
+        BuiltDisplayListIter {
+            list: self.iter.list,
+            data: self.iter.data,
+            // Dummy data, will be overwritten by `next`
+            cur_item: DisplayItem {
+                item: SpecificDisplayItem::PopStackingContext,
+                rect: LayoutRect::zero(),
+                clip_and_scroll: ClipAndScrollInfo::simple(ClipId::new(0, PipelineId(0, 0))),
+            },
+            cur_stops: ItemRange::default(),
+            cur_glyphs: ItemRange::default(),
+            cur_filters: ItemRange::default(),
+            cur_clip: ClipRegion::empty(),
+            peeking: Peek::NotPeeking,
+        }
+    }
+}
+
+impl<'a, T: Deserialize> AuxIter<'a, T> {
+    pub fn new(mut data: &'a [u8]) -> Self {
+
+        let size: usize = if data.len() == 0 {
+            0   // Accept empty ItemRanges pointing anywhere
+        } else {
+            bincode::deserialize_from(&mut data, bincode::Infinite)
+                                  .expect("MEH: malicious input?")
+        };
+
+        AuxIter {
+            data: data,
+            size: size,
+            _boo: PhantomData,
+        }
+    }
+}
+
+impl<'a, T: Deserialize> Iterator for AuxIter<'a, T> {
+    type Item = T;
+
+    fn next(&mut self) -> Option<T> {
+        if self.size == 0 {
+            None
+        } else {
+            self.size -= 1;
+            Some(bincode::deserialize_from(&mut self.data, bincode::Infinite)
+                         .expect("MEH: malicious input?"))
         }
     }
 
-    pub fn times(&self) -> (u64, u64) {
-      (self.descriptor.builder_start_time, self.descriptor.builder_finish_time)
+    fn size_hint(&self) -> (usize, Option<usize>) {
+        (self.size, Some(self.size))
+    }
+}
+
+impl<'a, T: Deserialize> ::std::iter::ExactSizeIterator for AuxIter<'a, T> { }
+
+
+// This is purely for the JSON writer in wrench
+impl Serialize for BuiltDisplayList {
+    fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
+        let mut seq = serializer.serialize_seq(None)?;
+        let mut traversal = self.iter();
+        while let Some(item) = traversal.next() {
+            seq.serialize_element(&item)?
+        }
+        seq.end()
+    }
+}
+
+impl<'a, 'b> Serialize for DisplayItemRef<'a, 'b> {
+    fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
+        let mut map = serializer.serialize_map(None)?;
+
+        map.serialize_entry("item", self.display_item())?;
+
+        match *self.item() {
+            SpecificDisplayItem::Text(_) => {
+                map.serialize_entry("glyphs",
+                    &self.iter.list.get(self.glyphs()).collect::<Vec<_>>())?;
+            }
+            SpecificDisplayItem::PushStackingContext(_) => {
+                map.serialize_entry("filters",
+                    &self.iter.list.get(self.filters()).collect::<Vec<_>>())?;
+            }
+            _ => { }
+        }
+
+        let clip_region = self.clip_region();
+        let gradient_stops = self.gradient_stops();
+
+        map.serialize_entry("clip_region", &clip_region)?;
+        if !clip_region.complex_clips.is_empty() {
+            map.serialize_entry("complex_clips",
+                &self.iter.list.get(clip_region.complex_clips).collect::<Vec<_>>())?;
+        }
+
+        if !gradient_stops.is_empty() {
+            map.serialize_entry("gradient_stops",
+                &self.iter.list.get(gradient_stops).collect::<Vec<_>>())?;
+        }
+
+        map.end()
     }
 }
 
 #[derive(Clone)]
 pub struct DisplayListBuilder {
-    pub list: Vec<DisplayItem>,
-    auxiliary_lists_builder: AuxiliaryListsBuilder,
+    pub data: Vec<u8>,
     pub pipeline_id: PipelineId,
     clip_stack: Vec<ClipAndScrollInfo>,
     next_clip_id: u64,
     builder_start_time: u64,
 }
 
 impl DisplayListBuilder {
     pub fn new(pipeline_id: PipelineId) -> DisplayListBuilder {
         let start_time = precise_time_ns();
         DisplayListBuilder {
-            list: Vec::new(),
-            auxiliary_lists_builder: AuxiliaryListsBuilder::new(),
+            data: Vec::with_capacity(1024 * 1024),
             pipeline_id: pipeline_id,
             clip_stack: vec![ClipAndScrollInfo::simple(ClipId::root_scroll_node(pipeline_id))],
 
             // We start at 1 here, because the root scroll id is always 0.
             next_clip_id: 1,
             builder_start_time: start_time,
         }
     }
 
     pub fn print_display_list(&mut self) {
-        for item in &self.list {
-            println!("{:?}", item);
+        let mut temp = BuiltDisplayList::default();
+        ::std::mem::swap(&mut temp.data, &mut self.data);
+
+        {
+            let mut iter = BuiltDisplayListIter::new(&temp);
+            while let Some(item) = iter.next() {
+                println!("{:?}", item.display_item());
+            }
         }
+
+        self.data = temp.data;
     }
 
-    fn push_item(&mut self, item: SpecificDisplayItem, rect: LayoutRect, clip: ClipRegion) {
-        self.list.push(DisplayItem {
+    fn push_item(&mut self, item: SpecificDisplayItem, rect: LayoutRect) {
+        bincode::serialize_into(&mut self.data, &DisplayItem {
             item: item,
             rect: rect,
-            clip: clip,
             clip_and_scroll: *self.clip_stack.last().unwrap(),
-        });
+        }, bincode::Infinite).unwrap();
     }
 
     fn push_new_empty_item(&mut self, item: SpecificDisplayItem) {
-        self.list.push(DisplayItem {
+        bincode::serialize_into(&mut self.data, &DisplayItem {
             item: item,
             rect: LayoutRect::zero(),
-            clip: ClipRegion::simple(&LayoutRect::zero()),
             clip_and_scroll: *self.clip_stack.last().unwrap(),
-        });
+        }, bincode::Infinite).unwrap();
+    }
+
+    fn push_iter<I>(&mut self, iter: I)
+    where I: IntoIterator,
+          I::IntoIter: ExactSizeIterator,
+          I::Item: Serialize,
+    {
+        let iter = iter.into_iter();
+        let len = iter.len();
+        let mut count = 0;
+
+        bincode::serialize_into(&mut self.data, &len, bincode::Infinite).unwrap();
+        for elem in iter {
+            count += 1;
+            bincode::serialize_into(&mut self.data, &elem, bincode::Infinite).unwrap();
+        }
+
+        debug_assert_eq!(len, count);
+    }
+
+    fn push_range<T>(&mut self, range: ItemRange<T>, src: &BuiltDisplayList) {
+        self.data.extend_from_slice(&src.data[range.start..range.start+range.length]);
     }
 
     pub fn push_rect(&mut self,
                      rect: LayoutRect,
-                     clip: ClipRegion,
+                     _token: ClipRegionToken,
                      color: ColorF) {
         let item = SpecificDisplayItem::Rectangle(RectangleDisplayItem {
             color: color,
         });
 
-        self.push_item(item, rect, clip);
+        self.push_item(item, rect);
     }
 
     pub fn push_image(&mut self,
                       rect: LayoutRect,
-                      clip: ClipRegion,
+                      _token: ClipRegionToken,
                       stretch_size: LayoutSize,
                       tile_spacing: LayoutSize,
                       image_rendering: ImageRendering,
                       key: ImageKey) {
         let item = SpecificDisplayItem::Image(ImageDisplayItem {
             image_key: key,
             stretch_size: stretch_size,
             tile_spacing: tile_spacing,
             image_rendering: image_rendering,
         });
 
-        self.push_item(item, rect, clip);
+        self.push_item(item, rect);
     }
 
     /// Push a yuv image. All planar data in yuv image should use the same buffer type.
     pub fn push_yuv_image(&mut self,
                           rect: LayoutRect,
-                          clip: ClipRegion,
+                          _token: ClipRegionToken,
                           yuv_data: YuvData,
                           color_space: YuvColorSpace) {
         let item = SpecificDisplayItem::YuvImage(YuvImageDisplayItem {
             yuv_data: yuv_data,
             color_space: color_space,
         });
-        self.push_item(item, rect, clip);
+        self.push_item(item, rect);
     }
 
     pub fn push_webgl_canvas(&mut self,
                              rect: LayoutRect,
-                             clip: ClipRegion,
+                             _token: ClipRegionToken,
                              context_id: WebGLContextId) {
         let item = SpecificDisplayItem::WebGL(WebGLDisplayItem {
             context_id: context_id,
         });
-        self.push_item(item, rect, clip);
+        self.push_item(item, rect);
     }
 
     pub fn push_text(&mut self,
                      rect: LayoutRect,
-                     clip: ClipRegion,
+                     _token: ClipRegionToken,
                      glyphs: &[GlyphInstance],
                      font_key: FontKey,
                      color: ColorF,
                      size: Au,
                      blur_radius: Au,
                      glyph_options: Option<GlyphOptions>) {
         // Sanity check - anything with glyphs bigger than this
         // is probably going to consume too much memory to render
         // efficiently anyway. This is specifically to work around
         // the font_advance.html reftest, which creates a very large
         // font as a crash test - the rendering is also ignored
         // by the azure renderer.
         if size < Au::from_px(4096) {
             let item = SpecificDisplayItem::Text(TextDisplayItem {
                 color: color,
-                glyphs: self.auxiliary_lists_builder.add_glyph_instances(&glyphs),
                 font_key: font_key,
                 size: size,
                 blur_radius: blur_radius,
                 glyph_options: glyph_options,
             });
 
-            self.push_item(item, rect, clip);
+            self.push_item(item, rect);
+            self.push_iter(glyphs);
         }
     }
 
     // Gradients can be defined with stops outside the range of [0, 1]
     // when this happens the gradient needs to be normalized by adjusting
     // the gradient stops and gradient line into an equivalent gradient
     // with stops in the range [0, 1]. this is done by moving the beginning
     // of the gradient line to where stop[0] and the end of the gradient line
@@ -303,115 +646,127 @@ impl DisplayListBuilder {
                     });
 
                     (0.0, 1.0)
                 }
             }
         }
     }
 
+    // NOTE: gradients must be pushed in the order they're created
+    // because create_gradient stores the stops in anticipation
     pub fn create_gradient(&mut self,
                            start_point: LayoutPoint,
                            end_point: LayoutPoint,
                            mut stops: Vec<GradientStop>,
                            extend_mode: ExtendMode) -> Gradient {
         let (start_offset,
              end_offset) = DisplayListBuilder::normalize_stops(&mut stops, extend_mode);
 
         let start_to_end = end_point - start_point;
 
+        self.push_stops(&stops);
+
         Gradient {
             start_point: start_point + start_to_end * start_offset,
             end_point: start_point + start_to_end * end_offset,
-            stops: self.auxiliary_lists_builder.add_gradient_stops(&stops),
             extend_mode: extend_mode,
         }
     }
 
+    // NOTE: gradients must be pushed in the order they're created
+    // because create_gradient stores the stops in anticipation
     pub fn create_radial_gradient(&mut self,
                                   center: LayoutPoint,
                                   radius: LayoutSize,
                                   mut stops: Vec<GradientStop>,
                                   extend_mode: ExtendMode) -> RadialGradient {
         if radius.width <= 0.0 || radius.height <= 0.0 {
             // The shader cannot handle a non positive radius. So
             // reuse the stops vector and construct an equivalent
             // gradient.
             let last_color = stops.last().unwrap().color;
 
-            stops.clear();
-            stops.push(GradientStop {
-                offset: 0.0,
-                color: last_color,
-            });
-            stops.push(GradientStop {
-                offset: 1.0,
-                color: last_color,
-            });
+            let stops = [
+                GradientStop {
+                    offset: 0.0,
+                    color: last_color,
+                },
+                GradientStop {
+                    offset: 1.0,
+                    color: last_color,
+                },
+            ];
+
+            self.push_stops(&stops);
 
             return RadialGradient {
                 start_center: center,
                 start_radius: 0.0,
                 end_center: center,
                 end_radius: 1.0,
                 ratio_xy: 1.0,
-                stops: self.auxiliary_lists_builder.add_gradient_stops(&stops),
                 extend_mode: extend_mode,
             };
         }
 
         let (start_offset,
              end_offset) = DisplayListBuilder::normalize_stops(&mut stops, extend_mode);
 
+        self.push_stops(&stops);
+
         RadialGradient {
             start_center: center,
             start_radius: radius.width * start_offset,
             end_center: center,
             end_radius: radius.width * end_offset,
             ratio_xy: radius.width / radius.height,
-            stops: self.auxiliary_lists_builder.add_gradient_stops(&stops),
             extend_mode: extend_mode,
         }
     }
 
+    // NOTE: gradients must be pushed in the order they're created
+    // because create_gradient stores the stops in anticipation
     pub fn create_complex_radial_gradient(&mut self,
                                           start_center: LayoutPoint,
                                           start_radius: f32,
                                           end_center: LayoutPoint,
                                           end_radius: f32,
                                           ratio_xy: f32,
                                           stops: Vec<GradientStop>,
                                           extend_mode: ExtendMode) -> RadialGradient {
+
+        self.push_stops(&stops);
+
         RadialGradient {
             start_center: start_center,
             start_radius: start_radius,
             end_center: end_center,
             end_radius: end_radius,
             ratio_xy: ratio_xy,
-            stops: self.auxiliary_lists_builder.add_gradient_stops(&stops),
             extend_mode: extend_mode,
         }
     }
 
     pub fn push_border(&mut self,
                        rect: LayoutRect,
-                       clip: ClipRegion,
+                       _token: ClipRegionToken,
                        widths: BorderWidths,
                        details: BorderDetails) {
         let item = SpecificDisplayItem::Border(BorderDisplayItem {
             details: details,
             widths: widths,
         });
 
-        self.push_item(item, rect, clip);
+        self.push_item(item, rect);
     }
 
     pub fn push_box_shadow(&mut self,
                            rect: LayoutRect,
-                           clip: ClipRegion,
+                           _token: ClipRegionToken,
                            box_bounds: LayoutRect,
                            offset: LayoutPoint,
                            color: ColorF,
                            blur_radius: f32,
                            spread_radius: f32,
                            border_radius: f32,
                            clip_mode: BoxShadowClipMode) {
         let item = SpecificDisplayItem::BoxShadow(BoxShadowDisplayItem {
@@ -419,47 +774,47 @@ impl DisplayListBuilder {
             offset: offset,
             color: color,
             blur_radius: blur_radius,
             spread_radius: spread_radius,
             border_radius: border_radius,
             clip_mode: clip_mode,
         });
 
-        self.push_item(item, rect, clip);
+        self.push_item(item, rect);
     }
 
     pub fn push_gradient(&mut self,
                          rect: LayoutRect,
-                         clip: ClipRegion,
+                         _token: ClipRegionToken,
                          gradient: Gradient,
                          tile_size: LayoutSize,
                          tile_spacing: LayoutSize) {
         let item = SpecificDisplayItem::Gradient(GradientDisplayItem {
             gradient: gradient,
             tile_size: tile_size,
             tile_spacing: tile_spacing,
         });
 
-        self.push_item(item, rect, clip);
+        self.push_item(item, rect);
     }
 
     pub fn push_radial_gradient(&mut self,
                                 rect: LayoutRect,
-                                clip: ClipRegion,
+                                _token: ClipRegionToken,
                                 gradient: RadialGradient,
                                 tile_size: LayoutSize,
                                 tile_spacing: LayoutSize) {
         let item = SpecificDisplayItem::RadialGradient(RadialGradientDisplayItem {
             gradient: gradient,
             tile_size: tile_size,
             tile_spacing: tile_spacing,
         });
 
-        self.push_item(item, rect, clip);
+        self.push_item(item, rect);
     }
 
     pub fn push_stacking_context(&mut self,
                                  scroll_policy: ScrollPolicy,
                                  bounds: LayoutRect,
                                  transform: Option<PropertyBinding<LayoutTransform>>,
                                  transform_style: TransformStyle,
                                  perspective: Option<LayoutTransform>,
@@ -467,54 +822,62 @@ impl DisplayListBuilder {
                                  filters: Vec<FilterOp>) {
         let item = SpecificDisplayItem::PushStackingContext(PushStackingContextDisplayItem {
             stacking_context: StackingContext {
                 scroll_policy: scroll_policy,
                 transform: transform,
                 transform_style: transform_style,
                 perspective: perspective,
                 mix_blend_mode: mix_blend_mode,
-                filters: self.auxiliary_lists_builder.add_filters(&filters),
             }
         });
 
-        self.push_item(item, bounds, ClipRegion::simple(&LayoutRect::zero()));
+        self.push_item(item, bounds);
+        self.push_iter(&filters);
     }
 
     pub fn pop_stacking_context(&mut self) {
         self.push_new_empty_item(SpecificDisplayItem::PopStackingContext);
     }
 
+    pub fn push_stops(&mut self, stops: &[GradientStop]) {
+        if stops.is_empty() {
+            return
+        }
+        self.push_new_empty_item(SpecificDisplayItem::SetGradientStops);
+        self.push_iter(stops);
+    }
+
     pub fn define_clip(&mut self,
                        content_rect: LayoutRect,
-                       clip: ClipRegion,
+                       _token: ClipRegionToken,
                        id: Option<ClipId>)
                        -> ClipId {
         let id = match id {
             Some(id) => id,
             None => {
                 self.next_clip_id += 1;
                 ClipId::Clip(self.next_clip_id - 1, self.pipeline_id)
             }
         };
 
         let item = SpecificDisplayItem::Clip(ClipDisplayItem {
             id: id,
             parent_id: self.clip_stack.last().unwrap().scroll_node_id,
         });
 
-        self.push_item(item, content_rect, clip);
+        self.push_item(item, content_rect);
         id
     }
 
     pub fn push_clip_node(&mut self,
-                          clip: ClipRegion,
                           content_rect: LayoutRect,
-                          id: Option<ClipId>) {
-        let id = self.define_clip(content_rect, clip, id);
+                          token: ClipRegionToken,
+                          id: Option<ClipId>){
+        let id = self.define_clip(content_rect, token, id);
         self.clip_stack.push(ClipAndScrollInfo::simple(id));
     }
 
     pub fn push_clip_id(&mut self, id: ClipId) {
         self.clip_stack.push(ClipAndScrollInfo::simple(id));
     }
 
     pub fn push_clip_and_scroll_info(&mut self, info: ClipAndScrollInfo) {
@@ -525,264 +888,86 @@ impl DisplayListBuilder {
         self.clip_stack.pop();
         assert!(self.clip_stack.len() > 0);
     }
 
     pub fn pop_clip_node(&mut self) {
         self.pop_clip_id();
     }
 
-    pub fn push_iframe(&mut self, rect: LayoutRect, clip: ClipRegion, pipeline_id: PipelineId) {
+    pub fn push_iframe(&mut self, rect: LayoutRect, _token: ClipRegionToken, pipeline_id: PipelineId) {
         let item = SpecificDisplayItem::Iframe(IframeDisplayItem { pipeline_id: pipeline_id });
-        self.push_item(item, rect, clip);
+        self.push_item(item, rect);
     }
 
     // Don't use this function. It will go away.
     // We're using it as a hack in Gecko to retain parts sub-parts of display lists so that
-    // we can regenerate them without building Gecko display items. 
-    pub fn push_built_display_list(&mut self, dl: BuiltDisplayList, aux: AuxiliaryLists) {
-        use SpecificDisplayItem::*;
-        // It's important for us to make sure that all of ItemRange structures are relocated
-        // when copying from one list to another. To avoid this problem we could use a custom
-        // derive implementation that would let ItemRanges relocate themselves.
-        for i in dl.all_display_items() {
-            let mut i = *i;
-            match i.item {
-                Text(ref mut item) => {
-                    item.glyphs = self.auxiliary_lists_builder.add_glyph_instances(aux.glyph_instances(&item.glyphs));
-                }
-                Gradient(ref mut item) => {
-                    item.gradient.stops = self.auxiliary_lists_builder.add_gradient_stops(aux.gradient_stops(&item.gradient.stops));
-                }
-                RadialGradient(ref mut item) => {
-                    item.gradient.stops = self.auxiliary_lists_builder.add_gradient_stops(aux.gradient_stops(&item.gradient.stops));
-                }
-                PushStackingContext(ref mut item) => {
-                    item.stacking_context.filters = self.auxiliary_lists_builder.add_filters(aux.filters(&item.stacking_context.filters));
-                }
-                Iframe(_) | Clip(_) => {
-                    // We don't support relocating these
-                    panic!();
-                }
-                _ => {}
+    // we can regenerate them without building Gecko display items.
+    pub fn push_built_display_list(&mut self, dl: BuiltDisplayList) {
+        // NOTE: Iframe and Clips aren't supported.
+
+        // FIXME: what `iter` here is doing an expensive deserialization
+        // because we need to update clip_and_scroll info! If we didn't need to
+        // update that, this function could just be memcopy!
+
+        // This implementation is basically BuiltDisplayListIter::next in reverse.
+
+        let mut iter = dl.iter();
+        while let Some(item) = iter.next() {
+            // First handle explicit prefix dummy items
+            let clip_region = item.clip_region();
+            if *clip_region != ClipRegion::empty() {
+                self.push_new_empty_item(SpecificDisplayItem::SetClipRegion(*clip_region));
+                self.push_range(clip_region.complex_clips, &dl);
             }
-            i.clip.complex =
-                self.auxiliary_lists_builder
-                    .add_complex_clip_regions(aux.complex_clip_regions(&i.clip.complex));
-            i.clip_and_scroll = *self.clip_stack.last().unwrap();
-            self.list.push(i);
+
+            let stops = item.gradient_stops();
+            if stops != ItemRange::default() {
+                self.push_new_empty_item(SpecificDisplayItem::SetGradientStops);
+                self.push_range(stops, &dl);
+            }
+
+            // Then reinsert the actual item, updating its clip_and_scroll
+            self.push_item(*item.item(), item.rect());
+
+            // Then handle implicit suffix items
+            match *item.item() {
+                SpecificDisplayItem::Text(_)                => self.push_range(item.glyphs(), &dl),
+                SpecificDisplayItem::PushStackingContext(_) => self.push_range(item.filters(), &dl),
+                _ => { /* do nothing */ }
+            }
         }
     }
 
-    pub fn new_clip_region(&mut self,
-                           rect: &LayoutRect,
-                           complex: Vec<ComplexClipRegion>,
-                           image_mask: Option<ImageMask>)
-                           -> ClipRegion {
-        ClipRegion::new(rect, complex, image_mask, &mut self.auxiliary_lists_builder)
+    pub fn push_clip_region<I>(&mut self,
+                            rect: &LayoutRect,
+                            complex: I,
+                            image_mask: Option<ImageMask>)
+                            -> ClipRegionToken
+    where I: IntoIterator<Item = ComplexClipRegion>,
+          I::IntoIter: ExactSizeIterator,
+    {
+        self.push_new_empty_item(SpecificDisplayItem::SetClipRegion(
+            ClipRegion::new(rect, image_mask),
+        ));
+        self.push_iter(complex);
+
+        ClipRegionToken { _unforgeable: () }
     }
 
-    pub fn finalize(self) -> (PipelineId, BuiltDisplayList, AuxiliaryLists) {
-        unsafe {
-            let blob = convert_vec_pod_to_blob(self.list);
-            let aux_list = self.auxiliary_lists_builder.finalize();
-
-            let end_time = precise_time_ns();
-
-            (self.pipeline_id,
-             BuiltDisplayList {
-                 descriptor: BuiltDisplayListDescriptor {
-                    display_list_items_size: blob.len(),
-                    builder_start_time: self.builder_start_time,
-                    builder_finish_time: end_time,
-                 },
-                 data: blob,
-             },
-             aux_list)
-        }
-    }
-}
+    pub fn finalize(self) -> (PipelineId, BuiltDisplayList) {
+        let end_time = precise_time_ns();
 
-impl ItemRange {
-    pub fn new<T>(backing_list: &mut Vec<T>, items: &[T]) -> ItemRange where T: Copy + Clone {
-        let start = backing_list.len();
-        backing_list.extend_from_slice(items);
-        ItemRange {
-            start: start,
-            length: items.len(),
-        }
-    }
-
-    pub fn empty() -> ItemRange {
-        ItemRange {
-            start: 0,
-            length: 0,
-        }
-    }
-
-    pub fn get<'a, T>(&self, backing_list: &'a [T]) -> &'a [T] {
-        &backing_list[self.start..(self.start + self.length)]
-    }
-
-    pub fn get_mut<'a, T>(&self, backing_list: &'a mut [T]) -> &'a mut [T] {
-        &mut backing_list[self.start..(self.start + self.length)]
+        (self.pipeline_id,
+         BuiltDisplayList {
+            descriptor: BuiltDisplayListDescriptor {
+            display_list_items_size: self.data.len(),
+            builder_start_time: self.builder_start_time,
+            builder_finish_time: end_time,
+            },
+            data: self.data,
+         })
     }
 }
 
-#[derive(Clone, Default)]
-pub struct AuxiliaryListsBuilder {
-    gradient_stops: Vec<GradientStop>,
-    complex_clip_regions: Vec<ComplexClipRegion>,
-    filters: Vec<FilterOp>,
-    glyph_instances: Vec<GlyphInstance>,
-}
-
-impl AuxiliaryListsBuilder {
-    pub fn new() -> AuxiliaryListsBuilder {
-        AuxiliaryListsBuilder::default()
-    }
-
-    pub fn add_gradient_stops(&mut self, gradient_stops: &[GradientStop]) -> ItemRange {
-        ItemRange::new(&mut self.gradient_stops, gradient_stops)
-    }
-
-    pub fn gradient_stops(&self, gradient_stops_range: &ItemRange) -> &[GradientStop] {
-        gradient_stops_range.get(&self.gradient_stops[..])
-    }
-
-    pub fn add_complex_clip_regions(&mut self, complex_clip_regions: &[ComplexClipRegion])
-                                    -> ItemRange {
-        ItemRange::new(&mut self.complex_clip_regions, complex_clip_regions)
-    }
-
-    pub fn complex_clip_regions(&self, complex_clip_regions_range: &ItemRange)
-                                -> &[ComplexClipRegion] {
-        complex_clip_regions_range.get(&self.complex_clip_regions[..])
-    }
-
-    pub fn add_filters(&mut self, filters: &[FilterOp]) -> ItemRange {
-        ItemRange::new(&mut self.filters, filters)
-    }
-
-    pub fn filters(&self, filters_range: &ItemRange) -> &[FilterOp] {
-        filters_range.get(&self.filters[..])
-    }
-
-    pub fn add_glyph_instances(&mut self, glyph_instances: &[GlyphInstance]) -> ItemRange {
-        ItemRange::new(&mut self.glyph_instances, glyph_instances)
-    }
-
-    pub fn glyph_instances(&self, glyph_instances_range: &ItemRange) -> &[GlyphInstance] {
-        glyph_instances_range.get(&self.glyph_instances[..])
-    }
-
-    pub fn finalize(self) -> AuxiliaryLists {
-        unsafe {
-            let mut blob = convert_vec_pod_to_blob(self.gradient_stops);
-            let gradient_stops_size = blob.len();
-            blob.extend_from_slice(convert_pod_to_blob(&self.complex_clip_regions));
-            let complex_clip_regions_size = blob.len() - gradient_stops_size;
-            blob.extend_from_slice(convert_pod_to_blob(&self.filters));
-            let filters_size = blob.len() - (complex_clip_regions_size + gradient_stops_size);
-            blob.extend_from_slice(convert_pod_to_blob(&self.glyph_instances));
-            let glyph_instances_size = blob.len() -
-                (complex_clip_regions_size + gradient_stops_size + filters_size);
-
-            AuxiliaryLists {
-                data: blob,
-                descriptor: AuxiliaryListsDescriptor {
-                    gradient_stops_size: gradient_stops_size,
-                    complex_clip_regions_size: complex_clip_regions_size,
-                    filters_size: filters_size,
-                    glyph_instances_size: glyph_instances_size,
-                },
-            }
-        }
-    }
-}
-
-impl AuxiliaryListsDescriptor {
-    pub fn size(&self) -> usize {
-        self.gradient_stops_size + self.complex_clip_regions_size + self.filters_size +
-            self.glyph_instances_size
-    }
-}
-
-impl AuxiliaryLists {
-    /// Creates a new `AuxiliaryLists` instance from a descriptor and data received over a channel.
-    pub fn from_data(data: Vec<u8>, descriptor: AuxiliaryListsDescriptor) -> AuxiliaryLists {
-        AuxiliaryLists {
-            data: data,
-            descriptor: descriptor,
-        }
-    }
-
-    pub fn into_data(self) -> (Vec<u8>, AuxiliaryListsDescriptor) {
-        (self.data, self.descriptor)
-    }
-
-    pub fn data(&self) -> &[u8] {
-        &self.data[..]
-    }
-
-    pub fn descriptor(&self) -> &AuxiliaryListsDescriptor {
-        &self.descriptor
-    }
-
-    /// Returns the gradient stops described by `gradient_stops_range`.
-    pub fn gradient_stops(&self, gradient_stops_range: &ItemRange) -> &[GradientStop] {
-        unsafe {
-            let end = self.descriptor.gradient_stops_size;
-            gradient_stops_range.get(convert_blob_to_pod(&self.data[0..end]))
-        }
-    }
-
-    /// Returns the complex clipping regions described by `complex_clip_regions_range`.
-    pub fn complex_clip_regions(&self, complex_clip_regions_range: &ItemRange)
-                                -> &[ComplexClipRegion] {
-        let start = self.descriptor.gradient_stops_size;
-        let end = start + self.descriptor.complex_clip_regions_size;
-        unsafe {
-            complex_clip_regions_range.get(convert_blob_to_pod(&self.data[start..end]))
-        }
-    }
-
-    /// Returns the filters described by `filters_range`.
-    pub fn filters(&self, filters_range: &ItemRange) -> &[FilterOp] {
-        let start = self.descriptor.gradient_stops_size +
-            self.descriptor.complex_clip_regions_size;
-        let end = start + self.descriptor.filters_size;
-        unsafe {
-            filters_range.get(convert_blob_to_pod(&self.data[start..end]))
-        }
-    }
-
-    /// Returns the glyph instances described by `glyph_instances_range`.
-    pub fn glyph_instances(&self, glyph_instances_range: &ItemRange) -> &[GlyphInstance] {
-        let start = self.descriptor.gradient_stops_size +
-            self.descriptor.complex_clip_regions_size + self.descriptor.filters_size;
-        unsafe {
-            glyph_instances_range.get(convert_blob_to_pod(&self.data[start..]))
-        }
-    }
-}
-
-unsafe fn convert_pod_to_blob<T>(data: &[T]) -> &[u8] where T: Copy + 'static {
-    slice::from_raw_parts(data.as_ptr() as *const u8, data.len() * mem::size_of::<T>())
-}
-
-// this variant of the above lets us convert without needing to make a copy
-unsafe fn convert_vec_pod_to_blob<T>(mut data: Vec<T>) -> Vec<u8> where T: Copy + 'static {
-    let v = Vec::from_raw_parts(data.as_mut_ptr() as *mut u8, data.len() * mem::size_of::<T>(), data.capacity() * mem::size_of::<T>());
-    mem::forget(data);
-    v
-}
-
-unsafe fn convert_blob_to_pod<T>(blob: &[u8]) -> &[T] where T: Copy + 'static {
-    slice::from_raw_parts(blob.as_ptr() as *const T, blob.len() / mem::size_of::<T>())
-}
-
-// this variant of the above lets us convert without needing to make a copy
-unsafe fn convert_vec_blob_to_pod<T>(mut data: Vec<u8>) -> Vec<T> where T: Copy + 'static {
-    let v = Vec::from_raw_parts(data.as_mut_ptr() as *mut T, data.len() / mem::size_of::<T>(), data.capacity() / mem::size_of::<T>());
-    mem::forget(data);
-    v
-}
+/// Verification that push_clip_region was called before
+/// pushing an item that requires it.
+pub struct ClipRegionToken { _unforgeable: () }
--- a/gfx/webrender_traits/src/lib.rs
+++ b/gfx/webrender_traits/src/lib.rs
@@ -1,16 +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/. */
 
 #![cfg_attr(feature = "nightly", feature(nonzero))]
 #![cfg_attr(feature = "cargo-clippy", allow(too_many_arguments, float_cmp))]
 
 extern crate app_units;
+extern crate bincode;
 extern crate byteorder;
 #[cfg(feature = "nightly")]
 extern crate core;
 extern crate euclid;
 extern crate gleam;
 #[macro_use]
 extern crate heapsize;
 #[cfg(feature = "ipc")]
--- a/toolkit/library/gtest/rust/Cargo.lock
+++ b/toolkit/library/gtest/rust/Cargo.lock
@@ -1039,16 +1039,17 @@ dependencies = [
  "webrender_traits 0.36.0",
 ]
 
 [[package]]
 name = "webrender_traits"
 version = "0.36.0"
 dependencies = [
  "app_units 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "bincode 1.0.0-alpha6 (registry+https://github.com/rust-lang/crates.io-index)",
  "byteorder 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "core-foundation 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "core-graphics 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "dwrote 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "euclid 0.11.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "gleam 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "heapsize 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde 0.9.9 (registry+https://github.com/rust-lang/crates.io-index)",
--- a/toolkit/library/rust/Cargo.lock
+++ b/toolkit/library/rust/Cargo.lock
@@ -1026,16 +1026,17 @@ dependencies = [
  "webrender_traits 0.36.0",
 ]
 
 [[package]]
 name = "webrender_traits"
 version = "0.36.0"
 dependencies = [
  "app_units 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "bincode 1.0.0-alpha6 (registry+https://github.com/rust-lang/crates.io-index)",
  "byteorder 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "core-foundation 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "core-graphics 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "dwrote 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "euclid 0.11.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "gleam 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "heapsize 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde 0.9.9 (registry+https://github.com/rust-lang/crates.io-index)",