Bug 1531930 - Interneration refactoring r=gw
☠☠ backed out by 76475dd4031b ☠ ☠
authorDzmitry Malyshau <dmalyshau@mozilla.com>
Sun, 03 Mar 2019 21:14:49 +0000
changeset 462192 458edf3460d42b50405db25edded051f94532cb3
parent 462191 d75868102ceaeb949d2bbd50c3067acd97dae217
child 462193 76475dd4031be7f326f25d5bff12126365962002
push id35642
push userdvarga@mozilla.com
push dateMon, 04 Mar 2019 09:36:20 +0000
treeherdermozilla-central@8cdde0ff59a1 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersgw
bugs1531930
milestone67.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 1531930 - Interneration refactoring r=gw Remove the intern_types module in favor of the associated Internable types that we already have. The only bit of magic I had to do is around serialization bounds, and it's nicely isolated. Differential Revision: https://phabricator.services.mozilla.com/D21797
gfx/wr/webrender/src/batch.rs
gfx/wr/webrender/src/box_shadow.rs
gfx/wr/webrender/src/clip.rs
gfx/wr/webrender/src/display_list_flattener.rs
gfx/wr/webrender/src/filterdata.rs
gfx/wr/webrender/src/intern.rs
gfx/wr/webrender/src/intern_types.rs
gfx/wr/webrender/src/lib.rs
gfx/wr/webrender/src/picture.rs
gfx/wr/webrender/src/prim_store/borders.rs
gfx/wr/webrender/src/prim_store/gradient.rs
gfx/wr/webrender/src/prim_store/image.rs
gfx/wr/webrender/src/prim_store/interned.rs
gfx/wr/webrender/src/prim_store/line_dec.rs
gfx/wr/webrender/src/prim_store/mod.rs
gfx/wr/webrender/src/prim_store/picture.rs
gfx/wr/webrender/src/prim_store/text_run.rs
gfx/wr/webrender/src/profiler.rs
gfx/wr/webrender/src/render_backend.rs
gfx/wr/webrender/src/scene_builder.rs
gfx/wr/webrender_api/src/api.rs
--- a/gfx/wr/webrender/src/batch.rs
+++ b/gfx/wr/webrender/src/batch.rs
@@ -1459,17 +1459,17 @@ impl AlphaBatchBuilder {
                                 // except we store a little more data in the filter mode and
                                 // a gpu cache handle in the user data.
                                 let surface = ctx.surfaces[raster_config.surface_index.0]
                                     .surface
                                     .as_ref()
                                     .expect("bug: surface must be allocated by now");
 
 
-                                let filter_data = &ctx.data_stores.filterdata[handle];
+                                let filter_data = &ctx.data_stores.filter_data[handle];
                                 let filter_mode : i32 = 13 |
                                     ((filter_data.data.r_func.to_int() << 28 |
                                       filter_data.data.g_func.to_int() << 24 |
                                       filter_data.data.b_func.to_int() << 20 |
                                       filter_data.data.a_func.to_int() << 16) as i32);
 
                                 let user_data = filter_data.gpu_cache_handle.as_int(gpu_cache);
 
--- a/gfx/wr/webrender/src/box_shadow.rs
+++ b/gfx/wr/webrender/src/box_shadow.rs
@@ -1,19 +1,20 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-use api::{BorderRadius, BoxShadowClipMode, ClipMode, ColorF, DeviceIntSize, LayoutPrimitiveInfo};
-use api::{LayoutRect, LayoutSize, LayoutVector2D, MAX_BLUR_RADIUS};
+use api::{BorderRadius, BoxShadowClipMode, ClipMode, ColorF, LayoutPrimitiveInfo, PrimitiveKeyKind};
+use api::MAX_BLUR_RADIUS;
+use api::units::*;
 use clip::ClipItemKey;
 use display_list_flattener::DisplayListFlattener;
 use gpu_cache::GpuCacheHandle;
 use gpu_types::BoxShadowStretchMode;
-use prim_store::{ScrollNodeAndClipChain, PrimitiveKeyKind};
+use prim_store::ScrollNodeAndClipChain;
 use render_task::RenderTaskCacheEntryHandle;
 use util::RectHelpers;
 
 #[derive(Debug, Clone, MallocSizeOf)]
 #[cfg_attr(feature = "capture", derive(Serialize))]
 #[cfg_attr(feature = "replay", derive(Deserialize))]
 pub struct BoxShadowClipSource {
     // Parameters that define the shadow and are constant.
--- a/gfx/wr/webrender/src/clip.rs
+++ b/gfx/wr/webrender/src/clip.rs
@@ -1,17 +1,17 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 use api::{BorderRadius, ClipMode, ComplexClipRegion, DeviceIntRect, DevicePixelScale, ImageMask};
 use api::{ImageRendering, LayoutRect, LayoutSize, LayoutPoint, LayoutVector2D};
 use api::{BoxShadowClipMode, LayoutToWorldScale, PicturePixel, WorldPixel};
 use api::{PictureRect, LayoutPixel, WorldPoint, WorldSize, WorldRect, LayoutToWorldTransform};
-use api::{ImageKey};
+use api::{ClipIntern, ImageKey};
 use app_units::Au;
 use border::{ensure_no_corner_overlap, BorderRadiusAu};
 use box_shadow::{BLUR_SAMPLE_SCALE, BoxShadowClipSource, BoxShadowCacheKey};
 use clip_scroll_tree::{ClipScrollTree, ROOT_SPATIAL_NODE_INDEX, SpatialNodeIndex};
 use ellipse::Ellipse;
 use gpu_cache::{GpuCache, GpuCacheHandle, ToGpuBlocks};
 use gpu_types::{BoxShadowStretchMode};
 use image::{self, Repetition};
@@ -99,18 +99,18 @@ use util::{extract_inner_rect_safe, proj
     | flags            | flags            | flags            | flags            | flags            |
     | ...              | ...              | ...              | ...              | ...              |
     +------------------+------------------+------------------+------------------+------------------+
 
  */
 
 // Type definitions for interning clip nodes.
 
-pub use intern_types::clip::Store as ClipDataStore;
-use intern_types::clip::Handle as ClipDataHandle;
+pub type ClipDataStore = intern::DataStore<ClipIntern>;
+type ClipDataHandle = intern::Handle<ClipIntern>;
 
 // Result of comparing a clip node instance against a local rect.
 #[derive(Debug)]
 enum ClipResult {
     // The clip does not affect the region at all.
     Accept,
     // The clip prevents the region from being drawn.
     Reject,
@@ -842,16 +842,22 @@ impl ClipItemKey {
             Au::from_f32_px(blur_radius),
             clip_mode,
         )
     }
 }
 
 impl intern::InternDebug for ClipItemKey {}
 
+impl intern::Internable for ClipIntern {
+    type Key = ClipItemKey;
+    type StoreData = ClipNode;
+    type InternData = ();
+}
+
 #[derive(Debug, MallocSizeOf)]
 #[cfg_attr(feature = "capture", derive(Serialize))]
 #[cfg_attr(feature = "replay", derive(Deserialize))]
 pub enum ClipItem {
     Rectangle(LayoutSize, ClipMode),
     RoundedRectangle(LayoutSize, BorderRadius, ClipMode),
     Image {
         image: ImageKey,
--- a/gfx/wr/webrender/src/display_list_flattener.rs
+++ b/gfx/wr/webrender/src/display_list_flattener.rs
@@ -1,47 +1,48 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 use api::{AlphaType, BorderDetails, BorderDisplayItem, BuiltDisplayListIter};
-use api::{ClipId, ColorF, ComplexClipRegion, DeviceIntPoint, DeviceIntRect, DeviceIntSize};
-use api::{DisplayItemRef, ExtendMode, ExternalScrollId, AuHelpers};
-use api::{FilterOp, FontInstanceKey, GlyphInstance, GlyphOptions, RasterSpace, GradientStop};
-use api::{IframeDisplayItem, ImageKey, ImageRendering, ItemRange, LayoutPoint, ColorDepth};
-use api::{LayoutPrimitiveInfo, LayoutRect, LayoutSize, LayoutTransform, LayoutVector2D};
-use api::{LineOrientation, LineStyle, NinePatchBorderSource, PipelineId};
+use api::{ClipId, ColorF, ComplexClipRegion, RasterSpace};
+use api::{DisplayItemRef, ExtendMode, ExternalScrollId};
+use api::{FilterOp, FontInstanceKey, GlyphInstance, GlyphOptions, GradientStop};
+use api::{IframeDisplayItem, ImageKey, ImageRendering, ItemRange, ColorDepth};
+use api::{LayoutPrimitiveInfo, LineOrientation, LineStyle, NinePatchBorderSource, PipelineId};
 use api::{PropertyBinding, ReferenceFrame, ReferenceFrameKind, ScrollFrameDisplayItem, ScrollSensitivity};
-use api::{Shadow, SpaceAndClipInfo, SpatialId, SpecificDisplayItem, StackingContext, StickyFrameDisplayItem, TexelRect};
-use api::{ClipMode, TransformStyle, YuvColorSpace, YuvData, TempFilterData};
+use api::{Shadow, SpaceAndClipInfo, SpatialId, SpecificDisplayItem, StackingContext, StickyFrameDisplayItem};
+use api::{ClipMode, PrimitiveKeyKind, TransformStyle, YuvColorSpace, YuvData, TempFilterData};
+use api::units::*;
 use app_units::Au;
 use clip::{ClipChainId, ClipRegion, ClipItemKey, ClipStore};
 use clip_scroll_tree::{ROOT_SPATIAL_NODE_INDEX, ClipScrollTree, SpatialNodeIndex};
 use frame_builder::{ChasePrimitive, FrameBuilder, FrameBuilderConfig};
 use glyph_rasterizer::FontInstance;
 use hit_test::{HitTestingItem, HitTestingRun};
 use image::simplify_repeated_primitive;
-use intern::{Handle, Internable, InternDebug};
+use intern::Interner;
 use internal_types::{FastHashMap, FastHashSet};
 use picture::{Picture3DContext, PictureCompositeMode, PicturePrimitive, PictureOptions};
 use picture::{BlitReason, OrderedPictureChild, PrimitiveList, TileCache};
-use prim_store::{PrimitiveInstance, PrimitiveKeyKind, PrimitiveSceneData};
+use prim_store::{PrimitiveInstance, PrimitiveSceneData};
 use prim_store::{PrimitiveInstanceKind, NinePatchDescriptor, PrimitiveStore};
 use prim_store::{PrimitiveStoreStats, ScrollNodeAndClipChain, PictureIndex};
+use prim_store::InternablePrimitive;
 use prim_store::{register_prim_chase_id, get_line_decoration_sizes};
 use prim_store::borders::{ImageBorder, NormalBorderPrim};
 use prim_store::gradient::{GradientStopKey, LinearGradient, RadialGradient, RadialGradientParams};
 use prim_store::image::{Image, YuvImage};
 use prim_store::line_dec::{LineDecoration, LineDecorationCacheKey};
 use prim_store::picture::{Picture, PictureCompositeKey, PictureKey};
 use prim_store::text_run::TextRun;
 use render_backend::{DocumentView};
 use resource_cache::{FontInstanceMap, ImageRequest};
 use scene::{Scene, StackingContextHelpers};
-use scene_builder::{InternerMut, Interners};
+use scene_builder::Interners;
 use spatial_node::{StickyFrameInfo, ScrollFrameKind, SpatialNodeType};
 use std::{f32, mem, usize};
 use std::collections::vec_deque::VecDeque;
 use std::sync::Arc;
 use tiling::{CompositeOps};
 use util::{MaxRect, VecHelper};
 use ::filterdata::{SFilterDataComponent, SFilterData, SFilterDataKey};
 
@@ -1143,36 +1144,35 @@ impl<'a> DisplayListFlattener<'a> {
     fn create_primitive<P>(
         &mut self,
         info: &LayoutPrimitiveInfo,
         clip_chain_id: ClipChainId,
         spatial_node_index: SpatialNodeIndex,
         prim: P,
     ) -> PrimitiveInstance
     where
-        P: Internable<InternData=PrimitiveSceneData>,
-        P::Source: AsInstanceKind<Handle<P::Marker>> + InternDebug,
-        Interners: InternerMut<P>,
+        P: InternablePrimitive,
+        Interners: AsMut<Interner<P>>,
     {
         // Build a primitive key.
-        let prim_key = prim.build_key(info);
+        let prim_key = prim.into_key(info);
 
-        let interner = self.interners.interner_mut();
-        let prim_data_handle =
-            interner
+        let interner = self.interners.as_mut();
+        let prim_data_handle = interner
             .intern(&prim_key, || {
                 PrimitiveSceneData {
                     prim_size: info.rect.size,
                     is_backface_visible: info.is_backface_visible,
                 }
             });
 
         let current_offset = self.rf_mapper.current_offset();
 
-        let instance_kind = prim_key.as_instance_kind(
+        let instance_kind = P::make_instance_kind(
+            prim_key,
             prim_data_handle,
             &mut self.prim_store,
             current_offset,
         );
 
         PrimitiveInstance::new(
             info.rect.origin,
             info.clip_rect,
@@ -1223,19 +1223,18 @@ impl<'a> DisplayListFlattener<'a> {
     fn add_nonshadowable_primitive<P>(
         &mut self,
         clip_and_scroll: ScrollNodeAndClipChain,
         info: &LayoutPrimitiveInfo,
         clip_items: Vec<(LayoutPoint, ClipItemKey)>,
         prim: P,
     )
     where
-        P: Internable<InternData = PrimitiveSceneData> + IsVisible,
-        P::Source: AsInstanceKind<Handle<P::Marker>> + InternDebug,
-        Interners: InternerMut<P>,
+        P: InternablePrimitive + IsVisible,
+        Interners: AsMut<Interner<P>>,
     {
         if prim.is_visible() {
             let clip_chain_id = self.build_clip_chain(
                 clip_items,
                 clip_and_scroll.spatial_node_index,
                 clip_and_scroll.clip_chain_id,
             );
             self.add_prim_to_draw_list(
@@ -1250,19 +1249,18 @@ impl<'a> DisplayListFlattener<'a> {
     pub fn add_primitive<P>(
         &mut self,
         clip_and_scroll: ScrollNodeAndClipChain,
         info: &LayoutPrimitiveInfo,
         clip_items: Vec<(LayoutPoint, ClipItemKey)>,
         prim: P,
     )
     where
-        P: Internable<InternData = PrimitiveSceneData> + IsVisible,
-        P::Source: AsInstanceKind<Handle<P::Marker>> + InternDebug,
-        Interners: InternerMut<P>,
+        P: InternablePrimitive + IsVisible,
+        Interners: AsMut<Interner<P>>,
         ShadowItem: From<PendingPrimitive<P>>
     {
         // If a shadow context is not active, then add the primitive
         // directly to the parent picture.
         if self.pending_shadow_items.is_empty() {
             self.add_nonshadowable_primitive(
                 clip_and_scroll,
                 info,
@@ -1285,19 +1283,18 @@ impl<'a> DisplayListFlattener<'a> {
     fn add_prim_to_draw_list<P>(
         &mut self,
         info: &LayoutPrimitiveInfo,
         clip_chain_id: ClipChainId,
         clip_and_scroll: ScrollNodeAndClipChain,
         prim: P,
     )
     where
-        P: Internable<InternData = PrimitiveSceneData>,
-        P::Source: AsInstanceKind<Handle<P::Marker>> + InternDebug,
-        Interners: InternerMut<P>,
+        P: InternablePrimitive,
+        Interners: AsMut<Interner<P>>,
     {
         let prim_instance = self.create_primitive(
             info,
             clip_chain_id,
             clip_and_scroll.spatial_node_index,
             prim,
         );
         self.register_chase_primitive_by_rect(
@@ -1601,17 +1598,17 @@ impl<'a> DisplayListFlattener<'a> {
                                     b_func: SFilterDataComponent::from_functype_values(
                                         filter_data.func_b_type, &filter_data.b_values),
                                     a_func: SFilterDataComponent::from_functype_values(
                                         filter_data.func_a_type, &filter_data.a_values),
                                 },
                         };
 
                         let handle = self.interners
-                            .filterdata
+                            .filter_data
                             .intern(&filter_data_key, || ());
                         PictureCompositeMode::ComponentTransferFilter(handle)
                     }
                 }
                 _ => PictureCompositeMode::Filter(filter),
             });
 
             let filter_pic_index = PictureIndex(self.prim_store.pictures
@@ -2124,19 +2121,18 @@ impl<'a> DisplayListFlattener<'a> {
 
     fn add_shadow_prim<P>(
         &mut self,
         pending_shadow: &PendingShadow,
         pending_primitive: &PendingPrimitive<P>,
         prims: &mut Vec<PrimitiveInstance>,
     )
     where
-        P: Internable<InternData=PrimitiveSceneData> + CreateShadow,
-        P::Source: AsInstanceKind<Handle<P::Marker>> + InternDebug,
-        Interners: InternerMut<P>,
+        P: InternablePrimitive + CreateShadow,
+        Interners: AsMut<Interner<P>>,
     {
         // Offset the local rect and clip rect by the shadow offset.
         let mut info = pending_primitive.info.clone();
         info.rect = info.rect.translate(&pending_shadow.shadow.offset);
         info.clip_rect = info.clip_rect.translate(&pending_shadow.shadow.offset);
 
         // Construct and add a primitive for the given shadow.
         let shadow_prim_instance = self.create_primitive(
@@ -2151,19 +2147,18 @@ impl<'a> DisplayListFlattener<'a> {
         // Add the new primitive to the shadow picture.
         prims.push(shadow_prim_instance);
     }
 
     fn add_shadow_prim_to_draw_list<P>(
         &mut self,
         pending_primitive: PendingPrimitive<P>,
     ) where
-        P: Internable<InternData = PrimitiveSceneData> + IsVisible,
-        P::Source: AsInstanceKind<Handle<P::Marker>> + InternDebug,
-        Interners: InternerMut<P>,
+        P: InternablePrimitive + IsVisible,
+        Interners: AsMut<Interner<P>>,
     {
         // For a normal primitive, if it has alpha > 0, then we add this
         // as a normal primitive to the parent picture.
         if pending_primitive.prim.is_visible() {
             self.add_prim_to_draw_list(
                 &pending_primitive.info,
                 pending_primitive.clip_and_scroll.clip_chain_id,
                 pending_primitive.clip_and_scroll,
@@ -2676,24 +2671,16 @@ impl<'a> DisplayListFlattener<'a> {
                 }
                 Picture3DContext::In { .. } => {}
                 Picture3DContext::Out => panic!("Unable to find 3D root"),
             }
         }
     }
 }
 
-pub trait AsInstanceKind<H> {
-    fn as_instance_kind(
-        &self,
-        data_handle: H,
-        prim_store: &mut PrimitiveStore,
-        reference_frame_relative_offset: LayoutVector2D,
-    ) -> PrimitiveInstanceKind;
-}
 
 pub trait CreateShadow {
     fn create_shadow(&self, shadow: &Shadow) -> Self;
 }
 
 pub trait IsVisible {
     fn is_visible(&self) -> bool;
 }
--- a/gfx/wr/webrender/src/filterdata.rs
+++ b/gfx/wr/webrender/src/filterdata.rs
@@ -2,20 +2,20 @@
  * 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 std::{hash};
 use gpu_cache::{GpuCacheHandle};
 use frame_builder::FrameBuildingState;
 use gpu_cache::GpuDataRequest;
 use intern;
-use api::{ComponentTransferFuncType};
+use api::{FilterDataIntern, ComponentTransferFuncType};
 
 
-pub use intern_types::filterdata::Handle as FilterDataHandle;
+pub type FilterDataHandle = intern::Handle<FilterDataIntern>;
 
 #[derive(Debug, Clone, MallocSizeOf, PartialEq)]
 #[cfg_attr(feature = "capture", derive(Serialize))]
 #[cfg_attr(feature = "replay", derive(Deserialize))]
 pub enum SFilterDataComponent {
     Identity,
     Table(Vec<f32>),
     Discrete(Vec<f32>),
@@ -139,16 +139,22 @@ impl SFilterDataTemplate {
             assert!(self.data.r_func != SFilterDataComponent::Identity
                  || self.data.g_func != SFilterDataComponent::Identity
                  || self.data.b_func != SFilterDataComponent::Identity
                  || self.data.a_func != SFilterDataComponent::Identity);
         }
     }
 }
 
+impl intern::Internable for FilterDataIntern {
+    type Key = SFilterDataKey;
+    type StoreData = SFilterDataTemplate;
+    type InternData = ();
+}
+
 fn push_component_transfer_data(
     func_comp: &SFilterDataComponent,
     request: &mut GpuDataRequest,
 ) {
     match func_comp {
         SFilterDataComponent::Identity => { return; }
         SFilterDataComponent::Table(values) |
         SFilterDataComponent::Discrete(values) => {
--- a/gfx/wr/webrender/src/intern.rs
+++ b/gfx/wr/webrender/src/intern.rs
@@ -28,17 +28,16 @@
 //! free-list structure, for content access and memory
 //! usage efficiency.
 //!
 //! The epoch is incremented each time a scene is
 //! built. The most recently used scene epoch is
 //! stored inside each handle. This is then used for
 //! cache invalidation.
 
-use api::{LayoutPrimitiveInfo};
 use internal_types::FastHashMap;
 use malloc_size_of::MallocSizeOf;
 use profiler::ResourceProfileCounter;
 use std::fmt::Debug;
 use std::hash::Hash;
 use std::marker::PhantomData;
 use std::{mem, ops, u64};
 use std::sync::atomic::{AtomicUsize, Ordering};
@@ -74,25 +73,38 @@ impl ItemUid {
     pub fn next_uid() -> ItemUid {
         let uid = NEXT_UID.fetch_add(1, Ordering::Relaxed);
         ItemUid { uid }
     }
 }
 
 #[cfg_attr(feature = "capture", derive(Serialize))]
 #[cfg_attr(feature = "replay", derive(Deserialize))]
-#[derive(Debug, Copy, Clone, MallocSizeOf)]
-pub struct Handle<M: Copy> {
+#[derive(Debug, MallocSizeOf)]
+pub struct Handle<I> {
     index: u32,
     epoch: Epoch,
     uid: ItemUid,
-    _marker: PhantomData<M>,
+    _marker: PhantomData<I>,
 }
 
-impl <M> Handle<M> where M: Copy {
+impl<I> Clone for Handle<I> {
+    fn clone(&self) -> Self {
+        Handle {
+            index: self.index,
+            epoch: self.epoch,
+            uid: self.uid,
+            _marker: self._marker,
+        }
+    }
+}
+
+impl<I> Copy for Handle<I> {}
+
+impl<I> Handle<I> {
     pub fn uid(&self) -> ItemUid {
         self.uid
     }
 }
 
 #[cfg_attr(feature = "capture", derive(Serialize))]
 #[cfg_attr(feature = "replay", derive(Deserialize))]
 #[derive(MallocSizeOf)]
@@ -113,161 +125,124 @@ pub trait InternDebug {
     fn on_interned(&self, _uid: ItemUid) {}
 }
 
 /// The data store lives in the frame builder thread. It
 /// contains a free-list of items for fast access.
 #[cfg_attr(feature = "capture", derive(Serialize))]
 #[cfg_attr(feature = "replay", derive(Deserialize))]
 #[derive(MallocSizeOf)]
-pub struct DataStore<S, T: MallocSizeOf, M> {
-    items: Vec<Option<T>>,
-    _source: PhantomData<S>,
-    _marker: PhantomData<M>,
+pub struct DataStore<I: Internable> {
+    items: Vec<Option<I::StoreData>>,
 }
 
-impl<S, T, M> ::std::default::Default for DataStore<S, T, M>
-where
-    S: Debug + MallocSizeOf,
-    T: From<S> + MallocSizeOf,
-    M: Debug
-{
+impl<I: Internable> Default for DataStore<I> {
     fn default() -> Self {
         DataStore {
             items: Vec::new(),
-            _source: PhantomData,
-            _marker: PhantomData,
         }
     }
 }
 
-impl<S, T, M> DataStore<S, T, M>
-where
-    S: Debug + MallocSizeOf,
-    T: From<S> + MallocSizeOf,
-    M: Debug
-{
+impl<I: Internable> DataStore<I> {
     /// Apply any updates from the scene builder thread to
     /// this data store.
     pub fn apply_updates(
         &mut self,
-        update_list: UpdateList<S>,
+        update_list: UpdateList<I::Key>,
         profile_counter: &mut ResourceProfileCounter,
     ) {
         let mut data_iter = update_list.data.into_iter();
         for update in update_list.updates {
             match update.kind {
                 UpdateKind::Insert => {
-                    self.items.entry(update.index).
-                        set(Some(T::from(data_iter.next().unwrap())));
+                    let value = data_iter.next().unwrap().into();
+                    self.items
+                        .entry(update.index)
+                        .set(Some(value));
                 }
                 UpdateKind::Remove => {
                     self.items[update.index] = None;
                 }
             }
         }
 
-        let per_item_size = mem::size_of::<S>() + mem::size_of::<T>();
+        let per_item_size = mem::size_of::<I::Key>() + mem::size_of::<I::StoreData>();
         profile_counter.set(self.items.len(), per_item_size * self.items.len());
 
         debug_assert!(data_iter.next().is_none());
     }
 }
 
 /// Retrieve an item from the store via handle
-impl<S, T, M> ops::Index<Handle<M>> for DataStore<S, T, M>
-where
-    S: MallocSizeOf,
-    T: MallocSizeOf,
-    M: Copy
-{
-    type Output = T;
-    fn index(&self, handle: Handle<M>) -> &T {
+impl<I: Internable> ops::Index<Handle<I>> for DataStore<I> {
+    type Output = I::StoreData;
+    fn index(&self, handle: Handle<I>) -> &I::StoreData {
         self.items[handle.index as usize].as_ref().expect("Bad datastore lookup")
     }
 }
 
 /// Retrieve a mutable item from the store via handle
 /// Retrieve an item from the store via handle
-impl<S, T, M> ops::IndexMut<Handle<M>> for DataStore<S, T, M>
-where
-    S: MallocSizeOf,
-    T: MallocSizeOf,
-    M: Copy
-{
-    fn index_mut(&mut self, handle: Handle<M>) -> &mut T {
+impl<I: Internable> ops::IndexMut<Handle<I>> for DataStore<I> {
+    fn index_mut(&mut self, handle: Handle<I>) -> &mut I::StoreData {
         self.items[handle.index as usize].as_mut().expect("Bad datastore lookup")
     }
 }
 
 /// The main interning data structure. This lives in the
 /// scene builder thread, and handles hashing and interning
 /// unique data structures. It also manages a free-list for
 /// the items in the data store, which is synchronized via
 /// an update list of additions / removals.
 #[cfg_attr(feature = "capture", derive(Serialize))]
 #[cfg_attr(feature = "replay", derive(Deserialize))]
 #[derive(MallocSizeOf)]
-pub struct Interner<S, D, M>
-where
-    S: Eq + Hash + Clone + Debug + MallocSizeOf,
-    D: MallocSizeOf,
-    M: Copy + MallocSizeOf,
-{
+pub struct Interner<I: Internable> {
     /// Uniquely map an interning key to a handle
-    map: FastHashMap<S, Handle<M>>,
+    map: FastHashMap<I::Key, Handle<I>>,
     /// List of free slots in the data store for re-use.
     free_list: Vec<usize>,
     /// Pending list of updates that need to be applied.
     updates: Vec<Update>,
     /// Pending new data to insert.
-    update_data: Vec<S>,
+    update_data: Vec<I::Key>,
     /// The current epoch for the interner.
     current_epoch: Epoch,
     /// The information associated with each interned
     /// item that can be accessed by the interner.
-    local_data: Vec<D>,
+    local_data: Vec<I::InternData>,
 }
 
-impl<S, D, M> ::std::default::Default for Interner<S, D, M>
-where
-    S: Eq + Hash + Clone + Debug + MallocSizeOf,
-    D: MallocSizeOf,
-    M: Copy + Debug + MallocSizeOf,
-{
+impl<I: Internable> Default for Interner<I> {
     fn default() -> Self {
         Interner {
             map: FastHashMap::default(),
             free_list: Vec::new(),
             updates: Vec::new(),
             update_data: Vec::new(),
             current_epoch: Epoch(1),
             local_data: Vec::new(),
         }
     }
 }
 
-impl<S, D, M> Interner<S, D, M>
-where
-    S: Eq + Hash + Clone + Debug + InternDebug + MallocSizeOf,
-    D: MallocSizeOf,
-    M: Copy + Debug + MallocSizeOf
-{
+impl<I: Internable> Interner<I> {
     /// Intern a data structure, and return a handle to
     /// that data. The handle can then be stored in the
     /// frame builder, and safely accessed via the data
     /// store that lives in the frame builder thread.
     /// The provided closure is invoked to build the
     /// local data about an interned structure if the
     /// key isn't already interned.
     pub fn intern<F>(
         &mut self,
-        data: &S,
-        f: F,
-    ) -> Handle<M> where F: FnOnce() -> D {
+        data: &I::Key,
+        fun: F,
+    ) -> Handle<I> where F: FnOnce() -> I::InternData {
         // Use get_mut rather than entry here to avoid
         // cloning the (sometimes large) key in the common
         // case, where the data already exists in the interner.
         if let Some(handle) = self.map.get_mut(data) {
             handle.epoch = self.current_epoch;
             return *handle;
         }
 
@@ -298,25 +273,25 @@ where
         data.on_interned(handle.uid);
 
         // Store this handle so the next time it is
         // interned, it gets re-used.
         self.map.insert(data.clone(), handle);
 
         // Create the local data for this item that is
         // being interned.
-        self.local_data.entry(index).set(f());
+        self.local_data.entry(index).set(fun());
 
         handle
     }
 
     /// Retrieve the pending list of updates for an interner
     /// that need to be applied to the data store. Also run
     /// a GC step that removes old entries.
-    pub fn end_frame_and_get_pending_updates(&mut self) -> UpdateList<S> {
+    pub fn end_frame_and_get_pending_updates(&mut self) -> UpdateList<I::Key> {
         let mut updates = self.updates.take_and_preallocate();
         let data = self.update_data.take_and_preallocate();
 
         let free_list = &mut self.free_list;
         let current_epoch = self.current_epoch.0;
 
         // First, run a GC step. Walk through the handles, and
         // if we find any that haven't been used for some time,
@@ -349,35 +324,41 @@ where
         // Begin the next epoch
         self.current_epoch = Epoch(self.current_epoch.0 + 1);
 
         updates
     }
 }
 
 /// Retrieve the local data for an item from the interner via handle
-impl<S, D, M> ops::Index<Handle<M>> for Interner<S, D, M>
-where
-    S: Eq + Clone + Hash + Debug + MallocSizeOf,
-    D: MallocSizeOf,
-    M: Copy + Debug + MallocSizeOf
-{
-    type Output = D;
-    fn index(&self, handle: Handle<M>) -> &D {
+impl<I: Internable> ops::Index<Handle<I>> for Interner<I> {
+    type Output = I::InternData;
+    fn index(&self, handle: Handle<I>) -> &I::InternData {
         &self.local_data[handle.index as usize]
     }
 }
 
-/// Implement `Internable` for a type that wants participate in interning.
-///
-/// see DisplayListFlattener::add_interned_primitive<P>
-pub trait Internable {
-    type Marker: Copy + Debug + MallocSizeOf;
-    type Source: Eq + Hash + Clone + Debug + MallocSizeOf;
-    type StoreData: From<Self::Source> + MallocSizeOf;
-    type InternData: MallocSizeOf;
+// The trick to make trait bounds configurable by features.
+mod dummy {
+    #[cfg(not(feature = "capture"))]
+    pub trait Serialize {}
+    #[cfg(not(feature = "capture"))]
+    impl<T> Serialize for T {}
+    #[cfg(not(feature = "replay"))]
+    pub trait Deserialize<'a> {}
+    #[cfg(not(feature = "replay"))]
+    impl<'a, T> Deserialize<'a> for T {}
+}
+#[cfg(feature = "capture")]
+use serde::Serialize as InternSerialize;
+#[cfg(not(feature = "capture"))]
+use self::dummy::Serialize as InternSerialize;
+#[cfg(feature = "replay")]
+use serde::Deserialize as InternDeserialize;
+#[cfg(not(feature = "replay"))]
+use self::dummy::Deserialize as InternDeserialize;
 
-    /// Build a new key from self with `info`.
-    fn build_key(
-        self,
-        info: &LayoutPrimitiveInfo,
-    ) -> Self::Source;
+/// Implement `Internable` for a type that wants to participate in interning.
+pub trait Internable: MallocSizeOf {
+    type Key: Eq + Hash + Clone + Debug + MallocSizeOf + InternDebug + InternSerialize + for<'a> InternDeserialize<'a>;
+    type StoreData: From<Self::Key> + MallocSizeOf + InternSerialize + for<'a> InternDeserialize<'a>;
+    type InternData: MallocSizeOf + InternSerialize + for<'a> InternDeserialize<'a>;
 }
deleted file mode 100644
--- a/gfx/wr/webrender/src/intern_types.rs
+++ /dev/null
@@ -1,114 +0,0 @@
-/* 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/. */
-
-macro_rules! common {
-    () => (
-        use ::intern;
-        #[allow(unused_imports)]
-        use ::prim_store::PrimitiveSceneData;
-        #[cfg_attr(feature = "capture", derive(Serialize))]
-        #[cfg_attr(feature = "replay", derive(Deserialize))]
-        #[derive(Clone, Copy, Debug, Eq, Hash, MallocSizeOf, PartialEq)]
-        pub struct Marker;
-        pub type Handle = intern::Handle<Marker>;
-    )
-}
-
-pub mod clip {
-common!();
-use ::clip::{ClipItemKey, ClipNode};
-pub type Store = intern::DataStore<ClipItemKey, ClipNode, Marker>;
-pub type UpdateList = intern::UpdateList<ClipItemKey>;
-pub type Interner = intern::Interner<ClipItemKey, (), Marker>;
-}
-
-pub mod prim {
-common!();
-use ::prim_store::{PrimitiveKey, PrimitiveTemplate};
-pub type Store = intern::DataStore<PrimitiveKey, PrimitiveTemplate, Marker>;
-pub type UpdateList = intern::UpdateList<PrimitiveKey>;
-pub type Interner = intern::Interner<PrimitiveKey, PrimitiveSceneData, Marker>;
-}
-
-pub mod normal_border {
-common!();
-use ::prim_store::borders::{NormalBorderKey, NormalBorderTemplate};
-pub type Store = intern::DataStore<NormalBorderKey, NormalBorderTemplate, Marker>;
-pub type UpdateList = intern::UpdateList<NormalBorderKey>;
-pub type Interner = intern::Interner<NormalBorderKey, PrimitiveSceneData, Marker>;
-}
-
-pub mod image_border {
-common!();
-use ::prim_store::borders::{ImageBorderKey, ImageBorderTemplate};
-pub type Store = intern::DataStore<ImageBorderKey, ImageBorderTemplate, Marker>;
-pub type UpdateList = intern::UpdateList<ImageBorderKey>;
-pub type Interner = intern::Interner<ImageBorderKey, PrimitiveSceneData, Marker>;
-}
-
-pub mod image {
-common!();
-use ::prim_store::image::{ImageKey, ImageTemplate};
-pub type Store = intern::DataStore<ImageKey, ImageTemplate, Marker>;
-pub type UpdateList = intern::UpdateList<ImageKey>;
-pub type Interner = intern::Interner<ImageKey, PrimitiveSceneData, Marker>;
-}
-
-pub mod yuv_image {
-common!();
-use ::prim_store::image::{YuvImageKey, YuvImageTemplate};
-pub type Store = intern::DataStore<YuvImageKey, YuvImageTemplate, Marker>;
-pub type UpdateList = intern::UpdateList<YuvImageKey>;
-pub type Interner = intern::Interner<YuvImageKey, PrimitiveSceneData, Marker>;
-}
-
-pub mod line_decoration {
-use ::prim_store::line_dec::{LineDecorationKey, LineDecorationTemplate};
-common!();
-pub type Store = intern::DataStore<LineDecorationKey, LineDecorationTemplate, Marker>;
-pub type UpdateList = intern::UpdateList<LineDecorationKey>;
-pub type Interner = intern::Interner<LineDecorationKey, PrimitiveSceneData, Marker>;
-}
-
-pub mod linear_grad {
-common!();
-use ::prim_store::gradient::{LinearGradientKey, LinearGradientTemplate};
-pub type Store = intern::DataStore<LinearGradientKey, LinearGradientTemplate, Marker>;
-pub type UpdateList = intern::UpdateList<LinearGradientKey>;
-pub type Interner = intern::Interner<LinearGradientKey, PrimitiveSceneData, Marker>;
-}
-
-pub mod radial_grad {
-common!();
-use ::prim_store::gradient::{RadialGradientKey, RadialGradientTemplate};
-pub type Store = intern::DataStore<RadialGradientKey, RadialGradientTemplate, Marker>;
-pub type UpdateList = intern::UpdateList<RadialGradientKey>;
-pub type Interner = intern::Interner<RadialGradientKey, PrimitiveSceneData, Marker>;
-}
-
-pub mod picture {
-common!();
-use ::prim_store::picture::{PictureKey, PictureTemplate};
-pub type Store = intern::DataStore<PictureKey, PictureTemplate, Marker>;
-pub type UpdateList = intern::UpdateList<PictureKey>;
-pub type Interner = intern::Interner<PictureKey, PrimitiveSceneData, Marker>;
-}
-
-pub mod text_run {
-common!();
-use ::prim_store::text_run::{TextRunKey, TextRunTemplate};
-pub type Store = intern::DataStore<TextRunKey, TextRunTemplate, Marker>;
-pub type UpdateList = intern::UpdateList<TextRunKey>;
-pub type Interner = intern::Interner<TextRunKey, PrimitiveSceneData, Marker>;
-}
-
-pub mod filterdata {
-common!();
-use ::filterdata::{SFilterDataKey, SFilterDataTemplate};
-pub type Store = intern::DataStore<SFilterDataKey, SFilterDataTemplate, Marker>;
-pub type UpdateList = intern::UpdateList<SFilterDataKey>;
-pub type Interner = intern::Interner<SFilterDataKey, (), Marker>;
-}
-
-
--- a/gfx/wr/webrender/src/lib.rs
+++ b/gfx/wr/webrender/src/lib.rs
@@ -99,17 +99,16 @@ mod glyph_cache;
 mod glyph_rasterizer;
 mod gpu_cache;
 #[cfg(feature = "pathfinder")]
 mod gpu_glyph_renderer;
 mod gpu_types;
 mod hit_test;
 mod image;
 mod intern;
-mod intern_types;
 mod internal_types;
 mod picture;
 mod prim_store;
 mod print_tree;
 mod record;
 mod render_backend;
 mod render_task;
 mod renderer;
--- a/gfx/wr/webrender/src/picture.rs
+++ b/gfx/wr/webrender/src/picture.rs
@@ -3109,17 +3109,17 @@ impl PicturePrimitive {
                     device_pixel_scale,
                 );
 
                 let render_task_id = frame_state.render_tasks.add(picture_task);
                 frame_state.surfaces[surface_index.0].tasks.push(render_task_id);
                 PictureSurface::RenderTask(render_task_id)
             }
             PictureCompositeMode::ComponentTransferFilter(handle) => {
-                let filter_data = &mut data_stores.filterdata[handle];
+                let filter_data = &mut data_stores.filter_data[handle];
                 filter_data.update(frame_state);
 
                 let uv_rect_kind = calculate_uv_rect_kind(
                     &pic_rect,
                     &transform,
                     &clipped,
                     device_pixel_scale,
                     true,
--- a/gfx/wr/webrender/src/prim_store/borders.rs
+++ b/gfx/wr/webrender/src/prim_store/borders.rs
@@ -4,26 +4,25 @@
 
 use api::{
     AuHelpers, LayoutPrimitiveInfo, LayoutSideOffsets,
     LayoutSideOffsetsAu, LayoutSize, NormalBorder, PremultipliedColorF,
     Shadow, LayoutVector2D,
 };
 use border::create_border_segments;
 use border::NormalBorderAu;
-use display_list_flattener::{AsInstanceKind, CreateShadow, IsVisible};
+use display_list_flattener::{CreateShadow, IsVisible};
 use frame_builder::{FrameBuildingState};
 use gpu_cache::GpuDataRequest;
 use intern;
-use intern_types;
 use prim_store::{
     BorderSegmentInfo, BrushSegment, NinePatchDescriptor, PrimKey,
     PrimKeyCommonData, PrimTemplate, PrimTemplateCommonData,
     PrimitiveInstanceKind, PrimitiveOpacity, PrimitiveSceneData,
-    PrimitiveStore
+    PrimitiveStore, InternablePrimitive,
 };
 use resource_cache::ImageRequest;
 use storage;
 
 #[cfg_attr(feature = "capture", derive(Serialize))]
 #[cfg_attr(feature = "replay", derive(Deserialize))]
 #[derive(Debug, Clone, Eq, MallocSizeOf, PartialEq, Hash)]
 pub struct NormalBorderPrim {
@@ -44,32 +43,16 @@ impl NormalBorderKey {
             ),
             kind: normal_border,
         }
     }
 }
 
 impl intern::InternDebug for NormalBorderKey {}
 
-impl AsInstanceKind<NormalBorderDataHandle> for NormalBorderKey {
-    /// Construct a primitive instance that matches the type
-    /// of primitive key.
-    fn as_instance_kind(
-        &self,
-        data_handle: NormalBorderDataHandle,
-        _: &mut PrimitiveStore,
-        _reference_frame_relative_offset: LayoutVector2D,
-    ) -> PrimitiveInstanceKind {
-        PrimitiveInstanceKind::NormalBorder {
-            data_handle,
-            cache_handles: storage::Range::empty(),
-        }
-    }
-}
-
 #[cfg_attr(feature = "capture", derive(Serialize))]
 #[cfg_attr(feature = "replay", derive(Deserialize))]
 #[derive(MallocSizeOf)]
 pub struct NormalBorderData {
     pub brush_segments: Vec<BrushSegment>,
     pub border_segments: Vec<BorderSegmentInfo>,
     pub border: NormalBorder,
     pub widths: LayoutSideOffsets,
@@ -155,34 +138,46 @@ impl From<NormalBorderKey> for NormalBor
                 border_segments,
                 border,
                 widths,
             }
         }
     }
 }
 
-pub use intern_types::normal_border::Handle as NormalBorderDataHandle;
+pub type NormalBorderDataHandle = intern::Handle<NormalBorderPrim>;
 
 impl intern::Internable for NormalBorderPrim {
-    type Marker = intern_types::normal_border::Marker;
-    type Source = NormalBorderKey;
+    type Key = NormalBorderKey;
     type StoreData = NormalBorderTemplate;
     type InternData = PrimitiveSceneData;
+}
 
-    /// Build a new key from self with `info`.
-    fn build_key(
+impl InternablePrimitive for NormalBorderPrim {
+    fn into_key(
         self,
         info: &LayoutPrimitiveInfo,
     ) -> NormalBorderKey {
         NormalBorderKey::new(
             info,
             self,
         )
     }
+
+    fn make_instance_kind(
+        _key: NormalBorderKey,
+        data_handle: NormalBorderDataHandle,
+        _: &mut PrimitiveStore,
+        _reference_frame_relative_offset: LayoutVector2D,
+    ) -> PrimitiveInstanceKind {
+        PrimitiveInstanceKind::NormalBorder {
+            data_handle,
+            cache_handles: storage::Range::empty(),
+        }
+    }
 }
 
 impl CreateShadow for NormalBorderPrim {
     fn create_shadow(&self, shadow: &Shadow) -> Self {
         let border = self.border.with_color(shadow.color.into());
         NormalBorderPrim {
             border,
             widths: self.widths,
@@ -220,30 +215,16 @@ impl ImageBorderKey {
             ),
             kind: image_border,
         }
     }
 }
 
 impl intern::InternDebug for ImageBorderKey {}
 
-impl AsInstanceKind<ImageBorderDataHandle> for ImageBorderKey {
-    /// Construct a primitive instance that matches the type
-    /// of primitive key.
-    fn as_instance_kind(
-        &self,
-        data_handle: ImageBorderDataHandle,
-        _: &mut PrimitiveStore,
-        _reference_frame_relative_offset: LayoutVector2D,
-    ) -> PrimitiveInstanceKind {
-        PrimitiveInstanceKind::ImageBorder {
-            data_handle
-        }
-    }
-}
 
 #[cfg_attr(feature = "capture", derive(Serialize))]
 #[cfg_attr(feature = "replay", derive(Deserialize))]
 #[derive(MallocSizeOf)]
 pub struct ImageBorderData {
     #[ignore_malloc_size_of = "Arc"]
     pub request: ImageRequest,
     pub brush_segments: Vec<BrushSegment>,
@@ -325,34 +306,45 @@ impl From<ImageBorderKey> for ImageBorde
             kind: ImageBorderData {
                 request: key.kind.request,
                 brush_segments,
             }
         }
     }
 }
 
-pub use intern_types::image_border::Handle as ImageBorderDataHandle;
+pub type ImageBorderDataHandle = intern::Handle<ImageBorder>;
 
 impl intern::Internable for ImageBorder {
-    type Marker = intern_types::image_border::Marker;
-    type Source = ImageBorderKey;
+    type Key = ImageBorderKey;
     type StoreData = ImageBorderTemplate;
     type InternData = PrimitiveSceneData;
+}
 
-    /// Build a new key from self with `info`.
-    fn build_key(
+impl InternablePrimitive for ImageBorder {
+    fn into_key(
         self,
         info: &LayoutPrimitiveInfo,
     ) -> ImageBorderKey {
         ImageBorderKey::new(
             info,
             self,
         )
     }
+
+    fn make_instance_kind(
+        _key: ImageBorderKey,
+        data_handle: ImageBorderDataHandle,
+        _: &mut PrimitiveStore,
+        _reference_frame_relative_offset: LayoutVector2D,
+    ) -> PrimitiveInstanceKind {
+        PrimitiveInstanceKind::ImageBorder {
+            data_handle
+        }
+    }
 }
 
 impl IsVisible for ImageBorder {
     fn is_visible(&self) -> bool {
         true
     }
 }
 
--- a/gfx/wr/webrender/src/prim_store/gradient.rs
+++ b/gfx/wr/webrender/src/prim_store/gradient.rs
@@ -1,25 +1,24 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 use api::{
     ColorF, ColorU,ExtendMode, GradientStop, LayoutPoint, LayoutSize,
     LayoutPrimitiveInfo, PremultipliedColorF, LayoutVector2D,
 };
-use display_list_flattener::{AsInstanceKind, IsVisible};
+use display_list_flattener::IsVisible;
 use frame_builder::FrameBuildingState;
 use gpu_cache::{GpuCacheHandle, GpuDataRequest};
-use intern::{Internable, InternDebug};
-use intern_types;
+use intern::{Internable, InternDebug, Handle as InternHandle};
 use prim_store::{BrushSegment, GradientTileRange};
 use prim_store::{PrimitiveInstanceKind, PrimitiveOpacity, PrimitiveSceneData};
 use prim_store::{PrimKeyCommonData, PrimTemplateCommonData, PrimitiveStore};
-use prim_store::{NinePatchDescriptor, PointKey, SizeKey};
+use prim_store::{NinePatchDescriptor, PointKey, SizeKey, InternablePrimitive};
 use std::{hash, ops::{Deref, DerefMut}, mem};
 use util::pack_as_float;
 
 /// A hashable gradient stop that can be used in primitive keys.
 #[cfg_attr(feature = "capture", derive(Serialize))]
 #[cfg_attr(feature = "replay", derive(Deserialize))]
 #[derive(Debug, Clone, MallocSizeOf, PartialEq)]
 pub struct GradientStopKey {
@@ -72,32 +71,16 @@ impl LinearGradientKey {
             reverse_stops: linear_grad.reverse_stops,
             nine_patch: linear_grad.nine_patch,
         }
     }
 }
 
 impl InternDebug for LinearGradientKey {}
 
-impl AsInstanceKind<LinearGradientDataHandle> for LinearGradientKey {
-    /// Construct a primitive instance that matches the type
-    /// of primitive key.
-    fn as_instance_kind(
-        &self,
-        data_handle: LinearGradientDataHandle,
-        _prim_store: &mut PrimitiveStore,
-        _reference_frame_relative_offset: LayoutVector2D,
-    ) -> PrimitiveInstanceKind {
-        PrimitiveInstanceKind::LinearGradient {
-            data_handle,
-            visible_tiles_range: GradientTileRange::empty(),
-        }
-    }
-}
-
 #[cfg_attr(feature = "capture", derive(Serialize))]
 #[cfg_attr(feature = "replay", derive(Deserialize))]
 #[derive(MallocSizeOf)]
 pub struct LinearGradientTemplate {
     pub common: PrimTemplateCommonData,
     pub extend_mode: ExtendMode,
     pub start_point: LayoutPoint,
     pub end_point: LayoutPoint,
@@ -222,46 +205,61 @@ impl LinearGradientTemplate {
                 self.stops_opacity
             } else {
                PrimitiveOpacity::translucent()
             }
         }
     }
 }
 
-pub type LinearGradientDataHandle = intern_types::linear_grad::Handle;
+pub type LinearGradientDataHandle = InternHandle<LinearGradient>;
 
+#[derive(Debug, MallocSizeOf)]
+#[cfg_attr(feature = "capture", derive(Serialize))]
+#[cfg_attr(feature = "replay", derive(Deserialize))]
 pub struct LinearGradient {
     pub extend_mode: ExtendMode,
     pub start_point: PointKey,
     pub end_point: PointKey,
     pub stretch_size: SizeKey,
     pub tile_spacing: SizeKey,
     pub stops: Vec<GradientStopKey>,
     pub reverse_stops: bool,
     pub nine_patch: Option<Box<NinePatchDescriptor>>,
 }
 
 impl Internable for LinearGradient {
-    type Marker = intern_types::linear_grad::Marker;
-    type Source = LinearGradientKey;
+    type Key = LinearGradientKey;
     type StoreData = LinearGradientTemplate;
     type InternData = PrimitiveSceneData;
+}
 
-    /// Build a new key from self with `info`.
-    fn build_key(
+impl InternablePrimitive for LinearGradient {
+    fn into_key(
         self,
         info: &LayoutPrimitiveInfo,
     ) -> LinearGradientKey {
         LinearGradientKey::new(
             info.is_backface_visible,
             info.rect.size,
             self
         )
     }
+
+    fn make_instance_kind(
+        _key: LinearGradientKey,
+        data_handle: LinearGradientDataHandle,
+        _prim_store: &mut PrimitiveStore,
+        _reference_frame_relative_offset: LayoutVector2D,
+    ) -> PrimitiveInstanceKind {
+        PrimitiveInstanceKind::LinearGradient {
+            data_handle,
+            visible_tiles_range: GradientTileRange::empty(),
+        }
+    }
 }
 
 impl IsVisible for LinearGradient {
     fn is_visible(&self) -> bool {
         true
     }
 }
 
@@ -321,32 +319,16 @@ impl RadialGradientKey {
             tile_spacing: radial_grad.tile_spacing,
             nine_patch: radial_grad.nine_patch,
         }
     }
 }
 
 impl InternDebug for RadialGradientKey {}
 
-impl AsInstanceKind<RadialGradientDataHandle> for RadialGradientKey {
-    /// Construct a primitive instance that matches the type
-    /// of primitive key.
-    fn as_instance_kind(
-        &self,
-        data_handle: RadialGradientDataHandle,
-        _prim_store: &mut PrimitiveStore,
-        _reference_frame_relative_offset: LayoutVector2D,
-    ) -> PrimitiveInstanceKind {
-        PrimitiveInstanceKind::RadialGradient {
-            data_handle,
-            visible_tiles_range: GradientTileRange::empty(),
-        }
-    }
-}
-
 #[cfg_attr(feature = "capture", derive(Serialize))]
 #[cfg_attr(feature = "replay", derive(Deserialize))]
 #[derive(MallocSizeOf)]
 pub struct RadialGradientTemplate {
     pub common: PrimTemplateCommonData,
     pub extend_mode: ExtendMode,
     pub center: LayoutPoint,
     pub params: RadialGradientParams,
@@ -442,45 +424,60 @@ impl RadialGradientTemplate {
                 &self.stops,
             );
         }
 
         self.opacity = PrimitiveOpacity::translucent();
     }
 }
 
-pub type RadialGradientDataHandle = intern_types::radial_grad::Handle;
+pub type RadialGradientDataHandle = InternHandle<RadialGradient>;
 
+#[derive(Debug, MallocSizeOf)]
+#[cfg_attr(feature = "capture", derive(Serialize))]
+#[cfg_attr(feature = "replay", derive(Deserialize))]
 pub struct RadialGradient {
     pub extend_mode: ExtendMode,
     pub center: PointKey,
     pub params: RadialGradientParams,
     pub stretch_size: SizeKey,
     pub stops: Vec<GradientStopKey>,
     pub tile_spacing: SizeKey,
     pub nine_patch: Option<Box<NinePatchDescriptor>>,
 }
 
 impl Internable for RadialGradient {
-    type Marker = intern_types::radial_grad::Marker;
-    type Source = RadialGradientKey;
+    type Key = RadialGradientKey;
     type StoreData = RadialGradientTemplate;
     type InternData = PrimitiveSceneData;
+}
 
-    /// Build a new key from self with `info`.
-    fn build_key(
+impl InternablePrimitive for RadialGradient {
+    fn into_key(
         self,
         info: &LayoutPrimitiveInfo,
     ) -> RadialGradientKey {
         RadialGradientKey::new(
             info.is_backface_visible,
             info.rect.size,
             self,
         )
     }
+
+    fn make_instance_kind(
+        _key: RadialGradientKey,
+        data_handle: RadialGradientDataHandle,
+        _prim_store: &mut PrimitiveStore,
+        _reference_frame_relative_offset: LayoutVector2D,
+    ) -> PrimitiveInstanceKind {
+        PrimitiveInstanceKind::RadialGradient {
+            data_handle,
+            visible_tiles_range: GradientTileRange::empty(),
+        }
+    }
 }
 
 impl IsVisible for RadialGradient {
     fn is_visible(&self) -> bool {
         true
     }
 }
 
--- a/gfx/wr/webrender/src/prim_store/image.rs
+++ b/gfx/wr/webrender/src/prim_store/image.rs
@@ -3,26 +3,25 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 use api::{
     AlphaType, ColorDepth, ColorF, ColorU, DeviceIntRect, DeviceIntSideOffsets,
     DeviceIntSize, ImageRendering, LayoutRect, LayoutSize, LayoutPrimitiveInfo,
     PremultipliedColorF, Shadow, TileOffset, YuvColorSpace, YuvFormat, LayoutVector2D,
 };
 use api::ImageKey as ApiImageKey;
-use display_list_flattener::{AsInstanceKind, CreateShadow, IsVisible};
+use display_list_flattener::{CreateShadow, IsVisible};
 use frame_builder::FrameBuildingState;
 use gpu_cache::{GpuDataRequest};
-use intern::{Internable, InternDebug};
-use intern_types;
+use intern::{Internable, InternDebug, Handle as InternHandle};
 use prim_store::{
     EdgeAaSegmentMask, OpacityBindingIndex, PrimitiveInstanceKind,
     PrimitiveOpacity, PrimitiveSceneData, PrimKey, PrimKeyCommonData,
     PrimTemplate, PrimTemplateCommonData, PrimitiveStore, SegmentInstanceIndex,
-    SizeKey
+    SizeKey, InternablePrimitive,
 };
 use render_task::{
     BlitSource, RenderTask, RenderTaskCacheEntryHandle, RenderTaskCacheKey,
     RenderTaskCacheKeyKind
 };
 use resource_cache::ImageRequest;
 use util::pack_as_float;
 
@@ -96,41 +95,16 @@ impl ImageKey {
             },
             kind: image,
         }
     }
 }
 
 impl InternDebug for ImageKey {}
 
-impl AsInstanceKind<ImageDataHandle> for ImageKey {
-    /// Construct a primitive instance that matches the type
-    /// of primitive key.
-    fn as_instance_kind(
-        &self,
-        data_handle: ImageDataHandle,
-        prim_store: &mut PrimitiveStore,
-        _reference_frame_relative_offset: LayoutVector2D,
-    ) -> PrimitiveInstanceKind {
-        // TODO(gw): Refactor this to not need a separate image
-        //           instance (see ImageInstance struct).
-        let image_instance_index = prim_store.images.push(ImageInstance {
-            opacity_binding_index: OpacityBindingIndex::INVALID,
-            segment_instance_index: SegmentInstanceIndex::INVALID,
-            tight_local_clip_rect: LayoutRect::zero(),
-            visible_tiles: Vec::new(),
-        });
-
-        PrimitiveInstanceKind::Image {
-            data_handle,
-            image_instance_index,
-        }
-    }
-}
-
 // Where to find the texture data for an image primitive.
 #[cfg_attr(feature = "capture", derive(Serialize))]
 #[cfg_attr(feature = "replay", derive(Deserialize))]
 #[derive(Debug, MallocSizeOf)]
 pub enum ImageSource {
     // A normal image - just reference the texture cache.
     Default,
     // An image that is pre-rendered into the texture cache
@@ -333,35 +307,56 @@ impl From<ImageKey> for ImageTemplate {
 
         ImageTemplate {
             common,
             kind: image.kind.into(),
         }
     }
 }
 
-pub use intern_types::image::Handle as ImageDataHandle;
+pub type ImageDataHandle = InternHandle<Image>;
 
 impl Internable for Image {
-    type Marker = intern_types::image::Marker;
-    type Source = ImageKey;
+    type Key = ImageKey;
     type StoreData = ImageTemplate;
     type InternData = PrimitiveSceneData;
+}
 
-    /// Build a new key from self with `info`.
-    fn build_key(
+impl InternablePrimitive for Image {
+    fn into_key(
         self,
         info: &LayoutPrimitiveInfo,
     ) -> ImageKey {
         ImageKey::new(
             info.is_backface_visible,
             info.rect.size,
             self
         )
     }
+
+    fn make_instance_kind(
+        _key: ImageKey,
+        data_handle: ImageDataHandle,
+        prim_store: &mut PrimitiveStore,
+        _reference_frame_relative_offset: LayoutVector2D,
+    ) -> PrimitiveInstanceKind {
+        // TODO(gw): Refactor this to not need a separate image
+        //           instance (see ImageInstance struct).
+        let image_instance_index = prim_store.images.push(ImageInstance {
+            opacity_binding_index: OpacityBindingIndex::INVALID,
+            segment_instance_index: SegmentInstanceIndex::INVALID,
+            tight_local_clip_rect: LayoutRect::zero(),
+            visible_tiles: Vec::new(),
+        });
+
+        PrimitiveInstanceKind::Image {
+            data_handle,
+            image_instance_index,
+        }
+    }
 }
 
 impl CreateShadow for Image {
     fn create_shadow(&self, shadow: &Shadow) -> Self {
         Image {
             tile_spacing: self.tile_spacing,
             stretch_size: self.stretch_size,
             key: self.key,
@@ -408,32 +403,16 @@ impl YuvImageKey {
             },
             kind: yuv_image,
         }
     }
 }
 
 impl InternDebug for YuvImageKey {}
 
-impl AsInstanceKind<YuvImageDataHandle> for YuvImageKey {
-    /// Construct a primitive instance that matches the type
-    /// of primitive key.
-    fn as_instance_kind(
-        &self,
-        data_handle: YuvImageDataHandle,
-        _prim_store: &mut PrimitiveStore,
-        _reference_frame_relative_offset: LayoutVector2D,
-    ) -> PrimitiveInstanceKind {
-        PrimitiveInstanceKind::YuvImage {
-            data_handle,
-            segment_instance_index: SegmentInstanceIndex::INVALID
-        }
-    }
-}
-
 #[cfg_attr(feature = "capture", derive(Serialize))]
 #[cfg_attr(feature = "replay", derive(Deserialize))]
 #[derive(MallocSizeOf)]
 pub struct YuvImageData {
     pub color_depth: ColorDepth,
     pub yuv_key: [ApiImageKey; 3],
     pub format: YuvFormat,
     pub color_space: YuvColorSpace,
@@ -500,35 +479,47 @@ impl From<YuvImageKey> for YuvImageTempl
 
         YuvImageTemplate {
             common,
             kind: image.kind.into(),
         }
     }
 }
 
-pub use intern_types::yuv_image::Handle as YuvImageDataHandle;
+pub type YuvImageDataHandle = InternHandle<YuvImage>;
 
 impl Internable for YuvImage {
-    type Marker = intern_types::yuv_image::Marker;
-    type Source = YuvImageKey;
+    type Key = YuvImageKey;
     type StoreData = YuvImageTemplate;
     type InternData = PrimitiveSceneData;
+}
 
-    /// Build a new key from self with `info`.
-    fn build_key(
+impl InternablePrimitive for YuvImage {
+    fn into_key(
         self,
         info: &LayoutPrimitiveInfo,
     ) -> YuvImageKey {
         YuvImageKey::new(
             info.is_backface_visible,
             info.rect.size,
-            self
+            self,
         )
     }
+
+    fn make_instance_kind(
+        _key: YuvImageKey,
+        data_handle: YuvImageDataHandle,
+        _prim_store: &mut PrimitiveStore,
+        _reference_frame_relative_offset: LayoutVector2D,
+    ) -> PrimitiveInstanceKind {
+        PrimitiveInstanceKind::YuvImage {
+            data_handle,
+            segment_instance_index: SegmentInstanceIndex::INVALID
+        }
+    }
 }
 
 impl IsVisible for YuvImage {
     fn is_visible(&self) -> bool {
         true
     }
 }
 
new file mode 100644
--- /dev/null
+++ b/gfx/wr/webrender/src/prim_store/interned.rs
@@ -0,0 +1,12 @@
+/* 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/. */
+
+// list of all interned primitives to match enumerate_interners!
+
+pub use prim_store::borders::{ImageBorder, NormalBorderPrim};
+pub use prim_store::image::{Image, YuvImage};
+pub use prim_store::line_dec::{LineDecoration};
+pub use prim_store::gradient::{LinearGradient, RadialGradient};
+pub use prim_store::picture::Picture;
+pub use prim_store::text_run::TextRun;
--- a/gfx/wr/webrender/src/prim_store/line_dec.rs
+++ b/gfx/wr/webrender/src/prim_store/line_dec.rs
@@ -2,27 +2,27 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 use api::{
     ColorF, ColorU, LayoutPrimitiveInfo, LayoutSizeAu, LayoutVector2D,
     LineOrientation, LineStyle, PremultipliedColorF, Shadow,
 };
 use app_units::Au;
-use display_list_flattener::{AsInstanceKind, CreateShadow, IsVisible};
+use display_list_flattener::{CreateShadow, IsVisible};
 use frame_builder::{FrameBuildingState};
 use gpu_cache::GpuDataRequest;
 use intern;
-use intern_types;
 use prim_store::{
     PrimKey, PrimKeyCommonData, PrimTemplate, PrimTemplateCommonData,
-    PrimitiveSceneData, PrimitiveStore,
+    InternablePrimitive, PrimitiveSceneData, PrimitiveStore,
 };
 use prim_store::PrimitiveInstanceKind;
 
+
 #[derive(Clone, Debug, Hash, MallocSizeOf, PartialEq, Eq)]
 #[cfg_attr(feature = "capture", derive(Serialize))]
 #[cfg_attr(feature = "replay", derive(Deserialize))]
 pub struct LineDecorationCacheKey {
     pub style: LineStyle,
     pub orientation: LineOrientation,
     pub wavy_line_thickness: Au,
     pub size: LayoutSizeAu,
@@ -54,32 +54,16 @@ impl LineDecorationKey {
             ),
             kind: line_dec,
         }
     }
 }
 
 impl intern::InternDebug for LineDecorationKey {}
 
-impl AsInstanceKind<LineDecorationDataHandle> for LineDecorationKey {
-    /// Construct a primitive instance that matches the type
-    /// of primitive key.
-    fn as_instance_kind(
-        &self,
-        data_handle: LineDecorationDataHandle,
-        _: &mut PrimitiveStore,
-        _reference_frame_relative_offset: LayoutVector2D,
-    ) -> PrimitiveInstanceKind {
-        PrimitiveInstanceKind::LineDecoration {
-            data_handle,
-            cache_handle: None,
-        }
-    }
-}
-
 #[cfg_attr(feature = "capture", derive(Serialize))]
 #[cfg_attr(feature = "replay", derive(Deserialize))]
 #[derive(MallocSizeOf)]
 pub struct LineDecorationData {
     pub cache_key: Option<LineDecorationCacheKey>,
     pub color: ColorF,
 }
 
@@ -130,34 +114,46 @@ impl From<LineDecorationKey> for LineDec
             kind: LineDecorationData {
                 cache_key: line_dec.kind.cache_key,
                 color: line_dec.kind.color.into(),
             }
         }
     }
 }
 
-pub use intern_types::line_decoration::Handle as LineDecorationDataHandle;
+pub type LineDecorationDataHandle = intern::Handle<LineDecoration>;
 
 impl intern::Internable for LineDecoration {
-    type Marker = intern_types::line_decoration::Marker;
-    type Source = LineDecorationKey;
+    type Key = LineDecorationKey;
     type StoreData = LineDecorationTemplate;
     type InternData = PrimitiveSceneData;
+}
 
-    /// Build a new key from self with `info`.
-    fn build_key(
+impl InternablePrimitive for LineDecoration {
+    fn into_key(
         self,
         info: &LayoutPrimitiveInfo,
     ) -> LineDecorationKey {
         LineDecorationKey::new(
             info,
             self,
         )
     }
+
+    fn make_instance_kind(
+        _key: LineDecorationKey,
+        data_handle: LineDecorationDataHandle,
+        _: &mut PrimitiveStore,
+        _reference_frame_relative_offset: LayoutVector2D,
+    ) -> PrimitiveInstanceKind {
+        PrimitiveInstanceKind::LineDecoration {
+            data_handle,
+            cache_handle: None,
+        }
+    }
 }
 
 impl CreateShadow for LineDecoration {
     fn create_shadow(&self, shadow: &Shadow) -> Self {
         LineDecoration {
             color: shadow.color.into(),
             cache_key: self.cache_key.clone(),
         }
--- a/gfx/wr/webrender/src/prim_store/mod.rs
+++ b/gfx/wr/webrender/src/prim_store/mod.rs
@@ -1,29 +1,26 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-use api::{BorderRadius, ClipMode, ColorF, PictureRect, ColorU, LayoutVector2D};
-use api::{DeviceIntRect, DevicePixelScale, DeviceRect, WorldVector2D};
+use api::{BorderRadius, ClipMode, ColorF};
 use api::{FilterOp, ImageRendering, TileOffset, RepeatMode, WorldPoint, WorldSize};
-use api::{LayoutPoint, LayoutRect, LayoutSideOffsets, LayoutSize, PicturePoint};
-use api::{PremultipliedColorF, PropertyBinding, Shadow, DeviceVector2D};
-use api::{WorldPixel, BoxShadowClipMode, WorldRect, LayoutToWorldScale};
-use api::{PicturePixel, RasterPixel, LineStyle, LineOrientation, AuHelpers};
-use api::{LayoutPrimitiveInfo};
-use api::DevicePoint;
+use api::{PremultipliedColorF, PropertyBinding, Shadow};
+use api::{BoxShadowClipMode, LineStyle, LineOrientation, AuHelpers};
+use api::{LayoutPrimitiveInfo, PrimitiveKeyKind};
+use api::units::*;
 use border::{get_max_scale_for_border, build_border_instances};
 use border::BorderSegmentCacheKey;
 use clip::{ClipStore};
 use clip_scroll_tree::{ROOT_SPATIAL_NODE_INDEX, ClipScrollTree, SpatialNodeIndex, VisibleFace};
 use clip::{ClipDataStore, ClipNodeFlags, ClipChainId, ClipChainInstance, ClipItem};
 use debug_colors;
 use debug_render::DebugItem;
-use display_list_flattener::{AsInstanceKind, CreateShadow, IsVisible};
+use display_list_flattener::{CreateShadow, IsVisible};
 use euclid::{SideOffsets2D, TypedTransform3D, TypedRect, TypedScale, TypedSize2D};
 use frame_builder::{FrameBuildingContext, FrameBuildingState, PictureContext, PictureState};
 use frame_builder::{PrimitiveContext, FrameVisibilityContext, FrameVisibilityState};
 use glyph_rasterizer::GlyphKey;
 use gpu_cache::{GpuCache, GpuCacheAddress, GpuCacheHandle, GpuDataRequest, ToGpuBlocks};
 use gpu_types::{BrushFlags, SnapOffsets};
 use image::{Repetition};
 use intern;
@@ -55,16 +52,17 @@ use util::{scale_factors, clamp_to_scale
 use smallvec::SmallVec;
 
 pub mod borders;
 pub mod gradient;
 pub mod image;
 pub mod line_dec;
 pub mod picture;
 pub mod text_run;
+pub mod interned;
 
 /// Counter for unique primitive IDs for debug tracing.
 #[cfg(debug_assertions)]
 static NEXT_PRIM_ID: AtomicUsize = AtomicUsize::new(0);
 
 #[cfg(debug_assertions)]
 static PRIM_CHASE_ID: AtomicUsize = AtomicUsize::new(usize::MAX);
 
@@ -324,29 +322,16 @@ impl GpuCacheAddress {
 #[cfg_attr(feature = "capture", derive(Serialize))]
 #[cfg_attr(feature = "replay", derive(Deserialize))]
 #[derive(MallocSizeOf)]
 pub struct PrimitiveSceneData {
     pub prim_size: LayoutSize,
     pub is_backface_visible: bool,
 }
 
-/// Information specific to a primitive type that
-/// uniquely identifies a primitive template by key.
-#[cfg_attr(feature = "capture", derive(Serialize))]
-#[cfg_attr(feature = "replay", derive(Deserialize))]
-#[derive(Debug, Clone, Eq, MallocSizeOf, PartialEq, Hash)]
-pub enum PrimitiveKeyKind {
-    /// Clear an existing rect, used for special effects on some platforms.
-    Clear,
-    Rectangle {
-        color: ColorU,
-    },
-}
-
 #[cfg_attr(feature = "capture", derive(Serialize))]
 #[cfg_attr(feature = "replay", derive(Deserialize))]
 #[derive(Debug, Clone, MallocSizeOf, PartialEq)]
 pub struct RectangleKey {
     x: f32,
     y: f32,
     w: f32,
     h: f32,
@@ -629,60 +614,34 @@ impl PrimitiveKey {
             },
             kind,
         }
     }
 }
 
 impl intern::InternDebug for PrimitiveKey {}
 
-impl AsInstanceKind<PrimitiveDataHandle> for PrimitiveKey {
-    /// Construct a primitive instance that matches the type
-    /// of primitive key.
-    fn as_instance_kind(
-        &self,
-        data_handle: PrimitiveDataHandle,
-        _: &mut PrimitiveStore,
-        _reference_frame_relative_offset: LayoutVector2D,
-    ) -> PrimitiveInstanceKind {
-        match self.kind {
-            PrimitiveKeyKind::Clear => {
-                PrimitiveInstanceKind::Clear {
-                    data_handle
-                }
-            }
-            PrimitiveKeyKind::Rectangle { .. } => {
-                PrimitiveInstanceKind::Rectangle {
-                    data_handle,
-                    opacity_binding_index: OpacityBindingIndex::INVALID,
-                    segment_instance_index: SegmentInstanceIndex::INVALID,
-                }
-            }
-        }
-    }
-}
-
 /// The shared information for a given primitive. This is interned and retained
 /// both across frames and display lists, by comparing the matching PrimitiveKey.
 #[cfg_attr(feature = "capture", derive(Serialize))]
 #[cfg_attr(feature = "replay", derive(Deserialize))]
 #[derive(MallocSizeOf)]
 pub enum PrimitiveTemplateKind {
     Rectangle {
         color: ColorF,
     },
     Clear,
 }
 
 /// Construct the primitive template data from a primitive key. This
 /// is invoked when a primitive key is created and the interner
 /// doesn't currently contain a primitive with this key.
-impl PrimitiveKeyKind {
-    fn into_template(self) -> PrimitiveTemplateKind {
-        match self {
+impl From<PrimitiveKeyKind> for PrimitiveTemplateKind {
+    fn from(kind: PrimitiveKeyKind) -> Self {
+        match kind {
             PrimitiveKeyKind::Clear => {
                 PrimitiveTemplateKind::Clear
             }
             PrimitiveKeyKind::Rectangle { color, .. } => {
                 PrimitiveTemplateKind::Rectangle {
                     color: color.into(),
                 }
             }
@@ -741,20 +700,20 @@ impl ops::Deref for PrimitiveTemplate {
 impl ops::DerefMut for PrimitiveTemplate {
     fn deref_mut(&mut self) -> &mut Self::Target {
         &mut self.common
     }
 }
 
 impl From<PrimitiveKey> for PrimitiveTemplate {
     fn from(item: PrimitiveKey) -> Self {
-        let common = PrimTemplateCommonData::with_key_common(item.common);
-        let kind = item.kind.into_template();
-
-        PrimitiveTemplate { common, kind, }
+        PrimitiveTemplate {
+            common: PrimTemplateCommonData::with_key_common(item.common),
+            kind: item.kind.into(),
+        }
     }
 }
 
 impl PrimitiveTemplateKind {
     /// Write any GPU blocks for the primitive template to the given request object.
     fn write_prim_gpu_blocks(
         &self,
         request: &mut GpuDataRequest
@@ -790,36 +749,59 @@ impl PrimitiveTemplate {
             }
             PrimitiveTemplateKind::Rectangle { ref color, .. } => {
                 PrimitiveOpacity::from_alpha(color.a)
             }
         };
     }
 }
 
+type PrimitiveDataHandle = intern::Handle<PrimitiveKeyKind>;
+
 impl intern::Internable for PrimitiveKeyKind {
-    type Marker = ::intern_types::prim::Marker;
-    type Source = PrimitiveKey;
+    type Key = PrimitiveKey;
     type StoreData = PrimitiveTemplate;
     type InternData = PrimitiveSceneData;
-
-    fn build_key(
+}
+
+impl InternablePrimitive for PrimitiveKeyKind {
+    fn into_key(
         self,
         info: &LayoutPrimitiveInfo,
     ) -> PrimitiveKey {
         PrimitiveKey::new(
             info.is_backface_visible,
             info.rect.size,
             self,
         )
     }
+
+    fn make_instance_kind(
+        key: PrimitiveKey,
+        data_handle: PrimitiveDataHandle,
+        _: &mut PrimitiveStore,
+        _reference_frame_relative_offset: LayoutVector2D,
+    ) -> PrimitiveInstanceKind {
+        match key.kind {
+            PrimitiveKeyKind::Clear => {
+                PrimitiveInstanceKind::Clear {
+                    data_handle
+                }
+            }
+            PrimitiveKeyKind::Rectangle { .. } => {
+                PrimitiveInstanceKind::Rectangle {
+                    data_handle,
+                    opacity_binding_index: OpacityBindingIndex::INVALID,
+                    segment_instance_index: SegmentInstanceIndex::INVALID,
+                }
+            }
+        }
+    }
 }
 
-use intern_types::prim::Handle as PrimitiveDataHandle;
-
 // Maintains a list of opacity bindings that have been collapsed into
 // the color of a single primitive. This is an important optimization
 // that avoids allocating an intermediate surface for most common
 // uses of opacity filters.
 #[derive(Debug)]
 #[cfg_attr(feature = "capture", derive(Serialize))]
 pub struct OpacityBinding {
     pub bindings: Vec<PropertyBinding<f32>>,
@@ -3701,16 +3683,34 @@ fn update_opacity_binding(
         1.0
     } else {
         let binding = &mut opacity_bindings[opacity_binding_index];
         binding.update(scene_properties);
         binding.current
     }
 }
 
+/// Trait for primitives that are directly internable.
+/// see DisplayListFlattener::add_primitive<P>
+pub trait InternablePrimitive: intern::Internable<InternData = PrimitiveSceneData> + Sized {
+    /// Build a new key from self with `info`.
+    fn into_key(
+        self,
+        info: &LayoutPrimitiveInfo,
+    ) -> Self::Key;
+
+    fn make_instance_kind(
+        key: Self::Key,
+        data_handle: intern::Handle<Self>,
+        prim_store: &mut PrimitiveStore,
+        reference_frame_relative_offset: LayoutVector2D,
+    ) -> PrimitiveInstanceKind;
+}
+
+
 #[test]
 #[cfg(target_pointer_width = "64")]
 fn test_struct_sizes() {
     use std::mem;
     // The sizes of these structures are critical for performance on a number of
     // talos stress tests. If you get a failure here on CI, there's two possibilities:
     // (a) You made a structure smaller than it currently is. Great work! Update the
     //     test expectations and move on.
--- a/gfx/wr/webrender/src/prim_store/picture.rs
+++ b/gfx/wr/webrender/src/prim_store/picture.rs
@@ -3,23 +3,23 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 use api::{
     ColorU, FilterOp, LayoutSize, LayoutPrimitiveInfo, MixBlendMode,
     PropertyBinding, PropertyBindingId, LayoutVector2D,
 };
 use intern::ItemUid;
 use app_units::Au;
-use display_list_flattener::{AsInstanceKind, IsVisible};
-use intern::{Internable, InternDebug};
-use intern_types;
+use display_list_flattener::IsVisible;
+use intern::{Internable, InternDebug, Handle as InternHandle};
 use picture::PictureCompositeMode;
 use prim_store::{
     PrimKey, PrimKeyCommonData, PrimTemplate, PrimTemplateCommonData,
     PrimitiveInstanceKind, PrimitiveSceneData, PrimitiveStore, VectorKey,
+    InternablePrimitive,
 };
 
 /// Represents a hashable description of how a picture primitive
 /// will be composited into its parent.
 #[cfg_attr(feature = "capture", derive(Serialize))]
 #[cfg_attr(feature = "replay", derive(Deserialize))]
 #[derive(Debug, Clone, MallocSizeOf, PartialEq, Hash, Eq)]
 pub enum PictureCompositeKey {
@@ -156,31 +156,16 @@ impl PictureKey {
             },
             kind: pic,
         }
     }
 }
 
 impl InternDebug for PictureKey {}
 
-impl AsInstanceKind<PictureDataHandle> for PictureKey {
-    /// Construct a primitive instance that matches the type
-    /// of primitive key.
-    fn as_instance_kind(
-        &self,
-        _: PictureDataHandle,
-        _: &mut PrimitiveStore,
-        _reference_frame_relative_offset: LayoutVector2D,
-    ) -> PrimitiveInstanceKind {
-        // Should never be hit as this method should not be
-        // called for pictures.
-        unreachable!();
-    }
-}
-
 #[cfg_attr(feature = "capture", derive(Serialize))]
 #[cfg_attr(feature = "replay", derive(Deserialize))]
 #[derive(MallocSizeOf)]
 pub struct PictureData;
 
 pub type PictureTemplate = PrimTemplate<PictureData>;
 
 impl From<PictureKey> for PictureTemplate {
@@ -189,35 +174,46 @@ impl From<PictureKey> for PictureTemplat
 
         PictureTemplate {
             common,
             kind: PictureData,
         }
     }
 }
 
-pub use intern_types::picture::Handle as PictureDataHandle;
+pub type PictureDataHandle = InternHandle<Picture>;
 
 impl Internable for Picture {
-    type Marker = intern_types::picture::Marker;
-    type Source = PictureKey;
+    type Key = PictureKey;
     type StoreData = PictureTemplate;
     type InternData = PrimitiveSceneData;
+}
 
-    /// Build a new key from self with `info`.
-    fn build_key(
+impl InternablePrimitive for Picture {
+    fn into_key(
         self,
         info: &LayoutPrimitiveInfo,
     ) -> PictureKey {
         PictureKey::new(
             info.is_backface_visible,
             info.rect.size,
-            self
+            self,
         )
     }
+
+    fn make_instance_kind(
+        _key: PictureKey,
+        _: PictureDataHandle,
+        _: &mut PrimitiveStore,
+        _reference_frame_relative_offset: LayoutVector2D,
+    ) -> PrimitiveInstanceKind {
+        // Should never be hit as this method should not be
+        // called for pictures.
+        unreachable!();
+    }
 }
 
 impl IsVisible for Picture {
     fn is_visible(&self) -> bool {
         true
     }
 }
 
--- a/gfx/wr/webrender/src/prim_store/text_run.rs
+++ b/gfx/wr/webrender/src/prim_store/text_run.rs
@@ -1,29 +1,28 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 use api::{ColorF, DevicePixelScale, GlyphInstance, LayoutPrimitiveInfo};
 use api::{LayoutToWorldTransform, RasterSpace};
 use api::{LayoutVector2D, Shadow};
-use display_list_flattener::{AsInstanceKind, CreateShadow, IsVisible};
+use display_list_flattener::{CreateShadow, IsVisible};
 use frame_builder::{FrameBuildingState, PictureContext};
 use glyph_rasterizer::{FontInstance, FontTransform, GlyphKey, FONT_SIZE_LIMIT};
 use gpu_cache::GpuCache;
 use gpu_types::RasterizationSpace;
 use intern;
-use intern_types;
 use prim_store::{PrimitiveOpacity, PrimitiveSceneData,  PrimitiveScratchBuffer};
 use prim_store::{PrimitiveStore, PrimKeyCommonData, PrimTemplateCommonData};
 use render_task::{RenderTaskTree};
 use renderer::{MAX_VERTEX_TEXTURE_WIDTH};
 use resource_cache::{ResourceCache};
 use util::{MatrixHelpers};
-use prim_store::PrimitiveInstanceKind;
+use prim_store::{InternablePrimitive, PrimitiveInstanceKind};
 use std::ops;
 use std::sync::Arc;
 use storage;
 use util::PrimaryArc;
 
 /// A run of glyphs, with associated font information.
 #[cfg_attr(feature = "capture", derive(Serialize))]
 #[cfg_attr(feature = "replay", derive(Deserialize))]
@@ -48,38 +47,16 @@ impl TextRunKey {
             glyphs: PrimaryArc(text_run.glyphs),
             shadow: text_run.shadow,
         }
     }
 }
 
 impl intern::InternDebug for TextRunKey {}
 
-impl AsInstanceKind<TextRunDataHandle> for TextRunKey {
-    /// Construct a primitive instance that matches the type
-    /// of primitive key.
-    fn as_instance_kind(
-        &self,
-        data_handle: TextRunDataHandle,
-        prim_store: &mut PrimitiveStore,
-        reference_frame_relative_offset: LayoutVector2D,
-    ) -> PrimitiveInstanceKind {
-        let run_index = prim_store.text_runs.push(TextRunPrimitive {
-            used_font: self.font.clone(),
-            glyph_keys_range: storage::Range::empty(),
-            reference_frame_relative_offset,
-            shadow: self.shadow,
-            raster_space: RasterizationSpace::Screen,
-            inverse_raster_scale: 1.0,
-        });
-
-        PrimitiveInstanceKind::TextRun{ data_handle, run_index }
-    }
-}
-
 #[cfg_attr(feature = "capture", derive(Serialize))]
 #[cfg_attr(feature = "replay", derive(Deserialize))]
 #[derive(MallocSizeOf)]
 pub struct TextRunTemplate {
     pub common: PrimTemplateCommonData,
     pub font: FontInstance,
     #[ignore_malloc_size_of = "Measured via PrimaryArc"]
     pub glyphs: Arc<Vec<GlyphInstance>>,
@@ -152,40 +129,62 @@ impl TextRunTemplate {
                 request.push(gpu_block);
             }
 
             assert!(request.current_used_block_num() <= MAX_VERTEX_TEXTURE_WIDTH);
         }
     }
 }
 
-pub use intern_types::text_run::Handle as TextRunDataHandle;
+pub type TextRunDataHandle = intern::Handle<TextRun>;
 
+#[derive(Debug, MallocSizeOf)]
+#[cfg_attr(feature = "capture", derive(Serialize))]
+#[cfg_attr(feature = "replay", derive(Deserialize))]
 pub struct TextRun {
     pub font: FontInstance,
+    #[ignore_malloc_size_of = "Measured via PrimaryArc"]
     pub glyphs: Arc<Vec<GlyphInstance>>,
     pub shadow: bool,
 }
 
 impl intern::Internable for TextRun {
-    type Marker = intern_types::text_run::Marker;
-    type Source = TextRunKey;
+    type Key = TextRunKey;
     type StoreData = TextRunTemplate;
     type InternData = PrimitiveSceneData;
+}
 
-    /// Build a new key from self with `info`.
-    fn build_key(
+impl InternablePrimitive for TextRun {
+    fn into_key(
         self,
         info: &LayoutPrimitiveInfo,
     ) -> TextRunKey {
         TextRunKey::new(
             info,
             self,
         )
     }
+
+    fn make_instance_kind(
+        key: TextRunKey,
+        data_handle: TextRunDataHandle,
+        prim_store: &mut PrimitiveStore,
+        reference_frame_relative_offset: LayoutVector2D,
+    ) -> PrimitiveInstanceKind {
+        let run_index = prim_store.text_runs.push(TextRunPrimitive {
+            used_font: key.font.clone(),
+            glyph_keys_range: storage::Range::empty(),
+            reference_frame_relative_offset,
+            shadow: key.shadow,
+            raster_space: RasterizationSpace::Screen,
+            inverse_raster_scale: 1.0,
+        });
+
+        PrimitiveInstanceKind::TextRun{ data_handle, run_index }
+    }
 }
 
 impl CreateShadow for TextRun {
     fn create_shadow(&self, shadow: &Shadow) -> Self {
         let mut font = FontInstance {
             color: shadow.color.into(),
             ..self.font.clone()
         };
--- a/gfx/wr/webrender/src/profiler.rs
+++ b/gfx/wr/webrender/src/profiler.rs
@@ -448,17 +448,17 @@ pub struct IpcProfileCounters {
     pub build_time: TimeProfileCounter,
     pub consume_time: TimeProfileCounter,
     pub send_time: TimeProfileCounter,
     pub total_time: TimeProfileCounter,
     pub display_lists: ResourceProfileCounter,
 }
 
 macro_rules! declare_intern_profile_counters {
-    ( $( $name: ident, )+ ) => {
+    ( $( $name:ident : $ty:ty, )+ ) => {
         #[derive(Clone)]
         pub struct InternProfileCounters {
             $(
                 pub $name: ResourceProfileCounter,
             )+
         }
 
         impl InternProfileCounters {
@@ -517,29 +517,30 @@ impl BackendProfileCounters {
             },
             ipc: IpcProfileCounters {
                 build_time: TimeProfileCounter::new("Display List Build Time", false),
                 consume_time: TimeProfileCounter::new("Display List Consume Time", false),
                 send_time: TimeProfileCounter::new("Display List Send Time", false),
                 total_time: TimeProfileCounter::new("Total Display List Time", false),
                 display_lists: ResourceProfileCounter::new("Display Lists Sent"),
             },
+            //TODO: generate this by a macro
             intern: InternProfileCounters {
                 prim: ResourceProfileCounter::new("Interned primitives"),
                 image: ResourceProfileCounter::new("Interned images"),
                 image_border: ResourceProfileCounter::new("Interned image borders"),
                 line_decoration: ResourceProfileCounter::new("Interned line decorations"),
                 linear_grad: ResourceProfileCounter::new("Interned linear gradients"),
                 normal_border: ResourceProfileCounter::new("Interned normal borders"),
                 picture: ResourceProfileCounter::new("Interned pictures"),
                 radial_grad: ResourceProfileCounter::new("Interned radial gradients"),
                 text_run: ResourceProfileCounter::new("Interned text runs"),
                 yuv_image: ResourceProfileCounter::new("Interned YUV images"),
                 clip: ResourceProfileCounter::new("Interned clips"),
-                filterdata: ResourceProfileCounter::new("Interned filterdata"),
+                filter_data: ResourceProfileCounter::new("Interned filter data"),
             },
         }
     }
 
     pub fn reset(&mut self) {
         self.total_time.reset();
         self.ipc.total_time.reset();
         self.ipc.build_time.reset();
--- a/gfx/wr/webrender/src/render_backend.rs
+++ b/gfx/wr/webrender/src/render_backend.rs
@@ -10,35 +10,37 @@
 
 use api::{ApiMsg, BuiltDisplayList, ClearCache, DebugCommand, DebugFlags};
 #[cfg(feature = "debugger")]
 use api::{BuiltDisplayListIter, SpecificDisplayItem};
 use api::{DocumentId, DocumentLayer, ExternalScrollId, FrameMsg, HitTestFlags, HitTestResult};
 use api::{IdNamespace, MemoryReport, PipelineId, RenderNotifier, SceneMsg, ScrollClamping};
 use api::{ScrollLocation, ScrollNodeState, TransactionMsg, ResourceUpdate, BlobImageKey};
 use api::{NotificationRequest, Checkpoint};
+use api::{ClipIntern, FilterDataIntern, PrimitiveKeyKind};
 use api::units::*;
 use api::channel::{MsgReceiver, MsgSender, Payload};
 #[cfg(feature = "capture")]
 use api::CaptureBits;
 #[cfg(feature = "replay")]
 use api::CapturedDocument;
 use clip_scroll_tree::{SpatialNodeIndex, ClipScrollTree};
 #[cfg(feature = "debugger")]
 use debug_server;
 use frame_builder::{FrameBuilder, FrameBuilderConfig};
 use glyph_rasterizer::{FontInstance};
 use gpu_cache::GpuCache;
 use hit_test::{HitTest, HitTester};
-use intern_types;
+use intern::DataStore;
 use internal_types::{DebugOutput, FastHashMap, FastHashSet, RenderedDocument, ResultMsg};
 use malloc_size_of::{MallocSizeOf, MallocSizeOfOps};
 use picture::RetainedTiles;
 use prim_store::{PrimitiveScratchBuffer, PrimitiveInstance};
 use prim_store::{PrimitiveInstanceKind, PrimTemplateCommonData};
+use prim_store::interned::*;
 use profiler::{BackendProfileCounters, IpcProfileCounters, ResourceProfileCounters};
 use record::ApiRecordingReceiver;
 use render_task::RenderTaskTreeCounters;
 use renderer::{AsyncPropertySampler, PipelineInfo};
 use resource_cache::ResourceCache;
 #[cfg(feature = "replay")]
 use resource_cache::PlainCacheOwn;
 #[cfg(any(feature = "capture", feature = "replay"))]
@@ -205,25 +207,25 @@ impl FrameStamp {
     pub const INVALID: FrameStamp = FrameStamp {
         id: FrameId(0),
         time: UNIX_EPOCH,
         document_id: DocumentId::INVALID,
     };
 }
 
 macro_rules! declare_data_stores {
-    ( $( $name: ident, )+ ) => {
+    ( $( $name:ident : $ty:ty, )+ ) => {
         /// A collection of resources that are shared by clips, primitives
         /// between display lists.
         #[cfg_attr(feature = "capture", derive(Serialize))]
         #[cfg_attr(feature = "replay", derive(Deserialize))]
         #[derive(Default)]
         pub struct DataStores {
             $(
-                pub $name: intern_types::$name::Store,
+                pub $name: DataStore<$ty>,
             )+
         }
 
         impl DataStores {
             /// Reports CPU heap usage.
             fn report_memory(&self, ops: &mut MallocSizeOfOps, r: &mut MemoryReport) {
                 $(
                     r.interning.data_stores.$name += self.$name.size_of(ops);
--- a/gfx/wr/webrender/src/scene_builder.rs
+++ b/gfx/wr/webrender/src/scene_builder.rs
@@ -1,27 +1,25 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 use api::{AsyncBlobImageRasterizer, BlobImageRequest, BlobImageParams, BlobImageResult};
 use api::{DocumentId, PipelineId, ApiMsg, FrameMsg, ResourceUpdate, ExternalEvent, Epoch};
 use api::{BuiltDisplayList, ColorF, LayoutSize, NotificationRequest, Checkpoint, IdNamespace};
-use api::{MemoryReport};
+use api::{ClipIntern, FilterDataIntern, MemoryReport, PrimitiveKeyKind};
 use api::channel::MsgSender;
 #[cfg(feature = "capture")]
 use capture::CaptureConfig;
 use frame_builder::{FrameBuilderConfig, FrameBuilder};
 use clip_scroll_tree::ClipScrollTree;
 use display_list_flattener::DisplayListFlattener;
-use intern::{Internable, Interner};
-use intern_types;
+use intern::{Internable, Interner, UpdateList};
 use internal_types::{FastHashMap, FastHashSet};
 use malloc_size_of::{MallocSizeOf, MallocSizeOfOps};
-use prim_store::{PrimitiveKeyKind};
 use prim_store::PrimitiveStoreStats;
 use prim_store::borders::{ImageBorder, NormalBorderPrim};
 use prim_store::gradient::{LinearGradient, RadialGradient};
 use prim_store::image::{Image, YuvImage};
 use prim_store::line_dec::LineDecoration;
 use prim_store::picture::Picture;
 use prim_store::text_run::TextRun;
 use resource_cache::{AsyncBlobImageInfo, FontInstanceMap};
@@ -30,16 +28,17 @@ use renderer::{PipelineInfo, SceneBuilde
 use scene::Scene;
 use std::sync::mpsc::{channel, Receiver, Sender};
 use std::mem::replace;
 use time::precise_time_ns;
 use util::drain_filter;
 use std::thread;
 use std::time::Duration;
 
+
 /// Represents the work associated to a transaction before scene building.
 pub struct Transaction {
     pub document_id: DocumentId,
     pub display_list_updates: Vec<DisplayListUpdate>,
     pub removed_pipelines: Vec<PipelineId>,
     pub epoch_updates: Vec<(PipelineId, Epoch)>,
     pub request_scene_build: Option<SceneRequest>,
     pub blob_requests: Vec<BlobImageParams>,
@@ -165,35 +164,43 @@ pub enum SceneBuilderResult {
 // scene swap was completed. We need a separate channel for this
 // so that they don't get mixed with SceneBuilderRequest messages.
 pub enum SceneSwapResult {
     Complete(Sender<()>),
     Aborted,
 }
 
 macro_rules! declare_interners {
-    ( $( $name: ident, )+ ) => {
+    ( $( $name:ident : $ty:ident, )+ ) => {
         /// This struct contains all items that can be shared between
         /// display lists. We want to intern and share the same clips,
         /// primitives and other things between display lists so that:
         /// - GPU cache handles remain valid, reducing GPU cache updates.
         /// - Comparison of primitives and pictures between two
         ///   display lists is (a) fast (b) done during scene building.
         #[cfg_attr(feature = "capture", derive(Serialize))]
         #[cfg_attr(feature = "replay", derive(Deserialize))]
         #[derive(Default)]
         pub struct Interners {
             $(
-                pub $name: intern_types::$name::Interner,
+                pub $name: Interner<$ty>,
             )+
         }
 
+        $(
+            impl AsMut<Interner<$ty>> for Interners {
+                fn as_mut(&mut self) -> &mut Interner<$ty> {
+                    &mut self.$name
+                }
+            }
+        )+
+
         pub struct InternerUpdates {
             $(
-                pub $name: intern_types::$name::UpdateList,
+                pub $name: UpdateList<<$ty as Internable>::Key>,
             )+
         }
 
         impl Interners {
             /// Reports CPU heap memory used by the interners.
             fn report_memory(
                 &self,
                 ops: &mut MallocSizeOfOps,
@@ -212,49 +219,16 @@ macro_rules! declare_interners {
                 }
             }
         }
     }
 }
 
 enumerate_interners!(declare_interners);
 
-// Access to `Interners` interners by `Internable`
-pub trait InternerMut<I: Internable>
-{
-    fn interner_mut(&mut self) -> &mut Interner<I::Source, I::InternData, I::Marker>;
-}
-
-macro_rules! impl_interner_mut {
-    ($($ty:ident: $mem:ident,)*) => {
-        $(impl InternerMut<$ty> for Interners {
-            fn interner_mut(&mut self) -> &mut Interner<
-                <$ty as Internable>::Source,
-                <$ty as Internable>::InternData,
-                <$ty as Internable>::Marker
-            > {
-                &mut self.$mem
-            }
-        })*
-    }
-}
-
-impl_interner_mut! {
-    Image: image,
-    ImageBorder: image_border,
-    LineDecoration: line_decoration,
-    LinearGradient: linear_grad,
-    NormalBorderPrim: normal_border,
-    Picture: picture,
-    PrimitiveKeyKind: prim,
-    RadialGradient: radial_grad,
-    TextRun: text_run,
-    YuvImage: yuv_image,
-}
-
 // A document in the scene builder contains the current scene,
 // as well as a persistent clip interner. This allows clips
 // to be de-duplicated, and persisted in the GPU cache between
 // display lists.
 struct Document {
     scene: Scene,
     interners: Interners,
     prim_store_stats: PrimitiveStoreStats,
--- a/gfx/wr/webrender_api/src/api.rs
+++ b/gfx/wr/webrender_api/src/api.rs
@@ -10,17 +10,17 @@ use std::cell::Cell;
 use std::fmt;
 use std::marker::PhantomData;
 use std::os::raw::c_void;
 use std::path::PathBuf;
 use std::sync::Arc;
 use std::u32;
 // local imports
 use {display_item as di, font};
-use color::ColorF;
+use color::{ColorU, ColorF};
 use display_list::{BuiltDisplayList, BuiltDisplayListDescriptor};
 use image::{BlobImageData, BlobImageKey, ImageData, ImageDescriptor, ImageKey};
 use units::*;
 
 
 pub type TileSize = u16;
 /// Documents are rendered in the ascending order of their associated layer values.
 pub type DocumentLayer = i8;
@@ -808,44 +808,60 @@ pub type PipelineSourceId = u32;
 pub struct PipelineId(pub PipelineSourceId, pub u32);
 
 impl PipelineId {
     pub fn dummy() -> Self {
         PipelineId(0, 0)
     }
 }
 
+#[derive(Copy, Clone, Debug, MallocSizeOf, Serialize, Deserialize)]
+pub enum ClipIntern {}
+#[derive(Copy, Clone, Debug, MallocSizeOf, Serialize, Deserialize)]
+pub enum FilterDataIntern {}
+
+/// Information specific to a primitive type that
+/// uniquely identifies a primitive template by key.
+#[derive(Debug, Clone, Eq, MallocSizeOf, PartialEq, Hash, Serialize, Deserialize)]
+pub enum PrimitiveKeyKind {
+    /// Clear an existing rect, used for special effects on some platforms.
+    Clear,
+    Rectangle {
+        color: ColorU,
+    },
+}
+
 /// Meta-macro to enumerate the various interner identifiers and types.
 ///
 /// IMPORTANT: Keep this synchronized with the list in mozilla-central located at
 /// gfx/webrender_bindings/webrender_ffi.h
 ///
 /// Note that this could be a lot less verbose if concat_idents! were stable. :-(
 #[macro_export]
 macro_rules! enumerate_interners {
     ($macro_name: ident) => {
         $macro_name! {
-            clip,
-            prim,
-            normal_border,
-            image_border,
-            image,
-            yuv_image,
-            line_decoration,
-            linear_grad,
-            radial_grad,
-            picture,
-            text_run,
-            filterdata,
+            clip: ClipIntern,
+            prim: PrimitiveKeyKind,
+            normal_border: NormalBorderPrim,
+            image_border: ImageBorder,
+            image: Image,
+            yuv_image: YuvImage,
+            line_decoration: LineDecoration,
+            linear_grad: LinearGradient,
+            radial_grad: RadialGradient,
+            picture: Picture,
+            text_run: TextRun,
+            filter_data: FilterDataIntern,
         }
     }
 }
 
 macro_rules! declare_interning_memory_report {
-    ( $( $name: ident, )+ ) => {
+    ( $( $name:ident : $ty:ident, )+ ) => {
         #[repr(C)]
         #[derive(AddAssign, Clone, Debug, Default, Deserialize, Serialize)]
         pub struct InternerSubReport {
             $(
                 pub $name: usize,
             )+
         }
     }