Bug 1456114 - Update webrender to commit 751236199b39bb8dac78522713133ca18c603fb3. r?jrmuizel draft
authorKartikaya Gupta <kgupta@mozilla.com>
Thu, 26 Apr 2018 14:14:24 -0400
changeset 788628 eff8c12faf5ee52843c4589f86326ed69f23259f
parent 788440 ccfd7b716a91241ddbc084cb7116ec561e56d5d1
child 788629 9176cdf8158fcb7b6141eeda9ab5e3955c6c76a1
push id108042
push userkgupta@mozilla.com
push dateThu, 26 Apr 2018 18:16:10 +0000
reviewersjrmuizel
bugs1456114
milestone61.0a1
Bug 1456114 - Update webrender to commit 751236199b39bb8dac78522713133ca18c603fb3. r?jrmuizel MozReview-Commit-ID: 5Zz7LwyLExN
gfx/webrender/examples/common/boilerplate.rs
gfx/webrender/examples/multiwindow.rs
gfx/webrender/res/brush.glsl
gfx/webrender/res/brush_blend.glsl
gfx/webrender/res/brush_image.glsl
gfx/webrender/res/brush_linear_gradient.glsl
gfx/webrender/res/brush_mix_blend.glsl
gfx/webrender/res/brush_radial_gradient.glsl
gfx/webrender/res/brush_solid.glsl
gfx/webrender/res/brush_yuv_image.glsl
gfx/webrender/res/cs_clip_border.glsl
gfx/webrender/res/prim_shared.glsl
gfx/webrender/res/ps_text_run.glsl
gfx/webrender/src/batch.rs
gfx/webrender/src/border.rs
gfx/webrender/src/box_shadow.rs
gfx/webrender/src/clip.rs
gfx/webrender/src/clip_scroll_node.rs
gfx/webrender/src/clip_scroll_tree.rs
gfx/webrender/src/display_list_flattener.rs
gfx/webrender/src/ellipse.rs
gfx/webrender/src/frame_builder.rs
gfx/webrender/src/glyph_rasterizer.rs
gfx/webrender/src/gpu_types.rs
gfx/webrender/src/hit_test.rs
gfx/webrender/src/image.rs
gfx/webrender/src/picture.rs
gfx/webrender/src/prim_store.rs
gfx/webrender/src/render_backend.rs
gfx/webrender/src/renderer.rs
gfx/webrender/src/scene.rs
gfx/webrender/src/scene_builder.rs
gfx/webrender/src/segment.rs
gfx/webrender/src/shade.rs
gfx/webrender/src/texture_cache.rs
gfx/webrender/src/tiling.rs
gfx/webrender/src/util.rs
gfx/webrender_api/src/api.rs
gfx/webrender_api/src/color.rs
gfx/webrender_api/src/display_item.rs
gfx/webrender_api/src/display_list.rs
gfx/webrender_api/src/image.rs
gfx/webrender_api/src/lib.rs
gfx/webrender_api/src/units.rs
gfx/webrender_bindings/revision.txt
gfx/wrench/src/main.rs
gfx/wrench/src/reftest.rs
gfx/wrench/src/scene.rs
gfx/wrench/src/wrench.rs
gfx/wrench/src/yaml_frame_reader.rs
gfx/wrench/src/yaml_frame_writer.rs
--- a/gfx/webrender/examples/common/boilerplate.rs
+++ b/gfx/webrender/examples/common/boilerplate.rs
@@ -29,17 +29,17 @@ impl RenderNotifier for Notifier {
         })
     }
 
     fn wake_up(&self) {
         #[cfg(not(target_os = "android"))]
         let _ = self.events_proxy.wakeup();
     }
 
-    fn new_document_ready(&self, _: DocumentId, _scrolled: bool, _composite_needed: bool) {
+    fn new_frame_ready(&self, _: DocumentId, _scrolled: bool, _composite_needed: bool) {
         self.wake_up();
     }
 }
 
 pub trait HandyDandyRectBuilder {
     fn to(&self, x2: i32, y2: i32) -> LayoutRect;
     fn by(&self, w: i32, h: i32) -> LayoutRect;
 }
--- a/gfx/webrender/examples/multiwindow.rs
+++ b/gfx/webrender/examples/multiwindow.rs
@@ -32,17 +32,17 @@ impl RenderNotifier for Notifier {
         })
     }
 
     fn wake_up(&self) {
         #[cfg(not(target_os = "android"))]
         let _ = self.events_proxy.wakeup();
     }
 
-    fn new_document_ready(&self, _: DocumentId, _scrolled: bool, _composite_needed: bool) {
+    fn new_frame_ready(&self, _: DocumentId, _scrolled: bool, _composite_needed: bool) {
         self.wake_up();
     }
 }
 
 struct Window {
     events_loop: glutin::EventsLoop, //TODO: share events loop?
     window: glutin::GlWindow,
     renderer: webrender::Renderer,
--- a/gfx/webrender/res/brush.glsl
+++ b/gfx/webrender/res/brush.glsl
@@ -152,23 +152,36 @@ void main(void) {
         pic_task,
         segment_data[1]
     );
 }
 #endif
 
 #ifdef WR_FRAGMENT_SHADER
 
-vec4 brush_fs();
+struct Fragment {
+    vec4 color;
+#ifdef WR_FEATURE_DUAL_SOURCE_BLENDING
+    vec4 blend;
+#endif
+};
+
+Fragment brush_fs();
 
 void main(void) {
     // Run the specific brush FS code to output the color.
-    vec4 color = brush_fs();
+    Fragment frag = brush_fs();
 
 #ifdef WR_FEATURE_ALPHA_PASS
     // Apply the clip mask
-    color *= do_clip();
+    float clip_alpha = do_clip();
+
+    frag.color *= clip_alpha;
+
+    #ifdef WR_FEATURE_DUAL_SOURCE_BLENDING
+        oFragBlend = frag.blend * clip_alpha;
+    #endif
 #endif
 
     // TODO(gw): Handle pre-multiply common code here as required.
-    oFragColor = color;
+    oFragColor = frag.color;
 }
 #endif
--- a/gfx/webrender/res/brush_blend.glsl
+++ b/gfx/webrender/res/brush_blend.glsl
@@ -117,21 +117,21 @@ vec3 Invert(vec3 Cs, float amount) {
 
 vec3 Brightness(vec3 Cs, float amount) {
     // Apply the brightness factor.
     // Resulting color needs to be clamped to output range
     // since we are pre-multiplying alpha in the shader.
     return clamp(Cs.rgb * amount, vec3(0.0), vec3(1.0));
 }
 
-vec4 brush_fs() {
+Fragment brush_fs() {
     vec4 Cs = texture(sColor0, vUv);
 
     if (Cs.a == 0.0) {
-        return vec4(0.0); // could also `discard`
+        return Fragment(vec4(0.0)); // could also `discard`
     }
 
     // Un-premultiply the input.
     float alpha = Cs.a;
     vec3 color = Cs.rgb / Cs.a;
 
     switch (vOp) {
         case 0:
@@ -152,11 +152,11 @@ vec4 brush_fs() {
             color = vColorMat * color + vColorOffset;
     }
 
     // Fail-safe to ensure that we don't sample outside the rendered
     // portion of a blend source.
     alpha *= point_inside_rect(vUv.xy, vUvClipBounds.xy, vUvClipBounds.zw);
 
     // Pre-multiply the alpha into the output value.
-    return alpha * vec4(color, 1.0);
+    return Fragment(alpha * vec4(color, 1.0));
 }
 #endif
--- a/gfx/webrender/res/brush_image.glsl
+++ b/gfx/webrender/res/brush_image.glsl
@@ -107,16 +107,20 @@ void brush_vs(
 
     vec2 f;
 
 #ifdef WR_FEATURE_ALPHA_PASS
     int color_mode = user_data.y >> 16;
     int raster_space = user_data.y & 0xffff;
     ImageBrushData image_data = fetch_image_data(prim_address);
 
+    if (color_mode == COLOR_MODE_FROM_PASS) {
+        color_mode = uMode;
+    }
+
     // Derive the texture coordinates for this image, based on
     // whether the source image is a local-space or screen-space
     // image.
     switch (raster_space) {
         case RASTER_SCREEN: {
             ImageBrushExtraData extra_data = fetch_image_extra_data(user_data.z);
 
             vec2 snapped_device_pos;
@@ -195,18 +199,18 @@ void brush_vs(
     }
 
     vLocalPos = vi.local_pos;
 #endif
 }
 #endif
 
 #ifdef WR_FRAGMENT_SHADER
-vec4 brush_fs() {
 
+Fragment brush_fs() {
     vec2 uv_size = vUvBounds.zw - vUvBounds.xy;
 
 #ifdef WR_FEATURE_ALPHA_PASS
     // This prevents the uv on the top and left parts of the primitive that was inflated
     // for anti-aliasing purposes from going beyound the range covered by the regular
     // (non-inflated) primitive.
     vec2 local_uv = max(vUv.xy, vec2(0.0));
 
@@ -227,19 +231,27 @@ vec4 brush_fs() {
     vec2 repeated_uv = mod(vUv.xy, uv_size) + vUvBounds.xy;
 #endif
 
     // Clamp the uvs to avoid sampling artifacts.
     vec2 uv = clamp(repeated_uv, vUvSampleBounds.xy, vUvSampleBounds.zw);
 
     vec4 texel = TEX_SAMPLE(sColor0, vec3(uv, vUv.z));
 
+    Fragment frag;
+
 #ifdef WR_FEATURE_ALPHA_PASS
     float alpha = init_transform_fs(vLocalPos);
     texel.rgb = texel.rgb * vMaskSwizzle.x + texel.aaa * vMaskSwizzle.y;
-    vec4 color = vColor * texel * alpha;
+
+    vec4 alpha_mask = texel * alpha;
+    frag.color = vColor * alpha_mask;
+
+    #ifdef WR_FEATURE_DUAL_SOURCE_BLENDING
+        frag.blend = alpha_mask * vColor.a;
+    #endif
 #else
-    vec4 color = texel;
+    frag.color = texel;
 #endif
 
-    return color;
+    return frag;
 }
 #endif
--- a/gfx/webrender/res/brush_linear_gradient.glsl
+++ b/gfx/webrender/res/brush_linear_gradient.glsl
@@ -65,17 +65,17 @@ void brush_vs(
 #ifdef WR_FEATURE_ALPHA_PASS
     vTileRepeat = tile_repeat.xy;
     vLocalPos = vi.local_pos;
 #endif
 }
 #endif
 
 #ifdef WR_FRAGMENT_SHADER
-vec4 brush_fs() {
+Fragment brush_fs() {
 
 #ifdef WR_FEATURE_ALPHA_PASS
     // Handle top and left inflated edges (see brush_image).
     vec2 local_pos = max(vPos, vec2(0.0));
 
     // Apply potential horizontal and vertical repetitions.
     vec2 pos = mod(local_pos, vRepeatedSize);
 
@@ -97,11 +97,11 @@ vec4 brush_fs() {
     vec4 color = sample_gradient(vGradientAddress,
                                  offset,
                                  vGradientRepeat);
 
 #ifdef WR_FEATURE_ALPHA_PASS
     color *= init_transform_fs(vLocalPos);
 #endif
 
-    return color;
+    return Fragment(color);
 }
 #endif
--- a/gfx/webrender/res/brush_mix_blend.glsl
+++ b/gfx/webrender/res/brush_mix_blend.glsl
@@ -191,25 +191,25 @@ const int MixBlendMode_HardLight   = 8;
 const int MixBlendMode_SoftLight   = 9;
 const int MixBlendMode_Difference  = 10;
 const int MixBlendMode_Exclusion   = 11;
 const int MixBlendMode_Hue         = 12;
 const int MixBlendMode_Saturation  = 13;
 const int MixBlendMode_Color       = 14;
 const int MixBlendMode_Luminosity  = 15;
 
-vec4 brush_fs() {
+Fragment brush_fs() {
     vec4 Cb = textureLod(sCacheRGBA8, vBackdropUv, 0.0);
     vec4 Cs = textureLod(sCacheRGBA8, vSrcUv, 0.0);
 
     if (Cb.a == 0.0) {
-        return Cs;
+        return Fragment(Cs);
     }
     if (Cs.a == 0.0) {
-        return vec4(0.0);
+        return Fragment(vec4(0.0));
     }
 
     // The mix-blend-mode functions assume no premultiplied alpha
     Cb.rgb /= Cb.a;
     Cs.rgb /= Cs.a;
 
     // Return yellow if none of the branches match (shouldn't happen).
     vec4 result = vec4(1.0, 1.0, 0.0, 1.0);
@@ -270,11 +270,11 @@ vec4 brush_fs() {
         default: break;
     }
 
     result.rgb = (1.0 - Cb.a) * Cs.rgb + Cb.a * result.rgb;
     result.a = Cs.a;
 
     result.rgb *= result.a;
 
-    return result;
+    return Fragment(result);
 }
 #endif
--- a/gfx/webrender/res/brush_radial_gradient.glsl
+++ b/gfx/webrender/res/brush_radial_gradient.glsl
@@ -68,17 +68,17 @@ void brush_vs(
 #ifdef WR_FEATURE_ALPHA_PASS
     vTileRepeat = tile_repeat.xy;
     vLocalPos = vi.local_pos;
 #endif
 }
 #endif
 
 #ifdef WR_FRAGMENT_SHADER
-vec4 brush_fs() {
+Fragment brush_fs() {
 
 #ifdef WR_FEATURE_ALPHA_PASS
     // Handle top and left inflated edges (see brush_image).
     vec2 local_pos = max(vPos, vec2(0.0));
 
     // Apply potential horizontal and vertical repetitions.
     vec2 pos = mod(local_pos, vRepeatedSize);
 
@@ -136,11 +136,11 @@ vec4 brush_fs() {
     vec4 color = sample_gradient(vGradientAddress,
                                  offset,
                                  vGradientRepeat);
 
 #ifdef WR_FEATURE_ALPHA_PASS
     color *= init_transform_fs(vLocalPos);
 #endif
 
-    return color;
+    return Fragment(color);
 }
 #endif
--- a/gfx/webrender/res/brush_solid.glsl
+++ b/gfx/webrender/res/brush_solid.glsl
@@ -37,16 +37,16 @@ void brush_vs(
 
 #ifdef WR_FEATURE_ALPHA_PASS
     vLocalPos = vi.local_pos;
 #endif
 }
 #endif
 
 #ifdef WR_FRAGMENT_SHADER
-vec4 brush_fs() {
+Fragment brush_fs() {
     vec4 color = vColor;
 #ifdef WR_FEATURE_ALPHA_PASS
     color *= init_transform_fs(vLocalPos);
 #endif
-    return color;
+    return Fragment(color);
 }
 #endif
--- a/gfx/webrender/res/brush_yuv_image.glsl
+++ b/gfx/webrender/res/brush_yuv_image.glsl
@@ -130,17 +130,17 @@ const mat3 YuvColorMatrix = mat3(
 // The matrix is stored in column-major.
 const mat3 YuvColorMatrix = mat3(
     1.16438,  1.16438,  1.16438,
     0.0    , -0.21325,  2.11240,
     1.79274, -0.53291,  0.0
 );
 #endif
 
-vec4 brush_fs() {
+Fragment brush_fs() {
     vec3 yuv_value;
 
 #if defined (WR_FEATURE_YUV_PLANAR)
     // The yuv_planar format should have this third texture coordinate.
     vec2 uv_y = clamp(vUv_Y.xy, vUvBounds_Y.xy, vUvBounds_Y.zw);
     vec2 uv_u = clamp(vUv_U.xy, vUvBounds_U.xy, vUvBounds_U.zw);
     vec2 uv_v = clamp(vUv_V.xy, vUvBounds_V.xy, vUvBounds_V.zw);
     yuv_value.x = TEX_SAMPLE(sColor0, vec3(uv_y, vUv_Y.z)).r;
@@ -164,11 +164,11 @@ vec4 brush_fs() {
     // See the YuvColorMatrix definition for an explanation of where the constants come from.
     vec3 rgb = YuvColorMatrix * (yuv_value - vec3(0.06275, 0.50196, 0.50196));
     vec4 color = vec4(rgb, 1.0);
 
 #ifdef WR_FEATURE_ALPHA_PASS
     color *= init_transform_fs(vLocalPos);
 #endif
 
-    return color;
+    return Fragment(color);
 }
 #endif
--- a/gfx/webrender/res/cs_clip_border.glsl
+++ b/gfx/webrender/res/cs_clip_border.glsl
@@ -1,14 +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/. */
 
 #include shared,clip_shared
 
+in vec4 aDashOrDot0;
+in vec4 aDashOrDot1;
+
 varying vec3 vPos;
 
 flat varying vec2 vClipCenter;
 
 flat varying vec4 vPoint_Tangent0;
 flat varying vec4 vPoint_Tangent1;
 flat varying vec3 vDotParams;
 flat varying vec2 vAlphaMask;
@@ -41,40 +44,43 @@ BorderCorner fetch_border_corner(ivec2 a
 }
 
 // Per-dash clip information.
 struct BorderClipDash {
     vec4 point_tangent_0;
     vec4 point_tangent_1;
 };
 
-BorderClipDash fetch_border_clip_dash(ivec2 address, int segment) {
-    vec4 data[2] = fetch_from_resource_cache_2_direct(address + ivec2(2 + 2 * (segment - 1), 0));
-    return BorderClipDash(data[0], data[1]);
+BorderClipDash fetch_border_clip_dash(ivec2 address) {
+    return BorderClipDash(aDashOrDot0, aDashOrDot1);
 }
 
 // Per-dot clip information.
 struct BorderClipDot {
     vec3 center_radius;
 };
 
-BorderClipDot fetch_border_clip_dot(ivec2 address, int segment) {
-    vec4 data = fetch_from_resource_cache_1_direct(address + ivec2(2 + (segment - 1), 0));
-    return BorderClipDot(data.xyz);
+BorderClipDot fetch_border_clip_dot(ivec2 address) {
+    return BorderClipDot(aDashOrDot0.xyz);
 }
 
 void main(void) {
     ClipMaskInstance cmi = fetch_clip_item();
     ClipArea area = fetch_clip_area(cmi.render_task_address);
     ClipScrollNode scroll_node = fetch_clip_scroll_node(cmi.scroll_node_id);
 
     // Fetch the header information for this corner clip.
     BorderCorner corner = fetch_border_corner(cmi.clip_data_address);
     vClipCenter = corner.clip_center;
 
+    // Get local vertex position for the corner rect.
+    // TODO(gw): We could reduce the number of pixels written here by calculating a tight
+    // fitting bounding box of the dash itself like we do for dots below.
+    vec2 pos = corner.rect.p0 + aPosition.xy * corner.rect.size;
+
     if (cmi.segment == 0) {
         // The first segment is used to zero out the border corner.
         vAlphaMask = vec2(0.0);
         vDotParams = vec3(0.0);
         vPoint_Tangent0 = vec4(1.0);
         vPoint_Tangent1 = vec4(1.0);
     } else {
         vec2 sign_modifier;
@@ -93,43 +99,49 @@ void main(void) {
                 break;
             default:
                 sign_modifier = vec2(0.0);
         };
 
         switch (corner.clip_mode) {
             case CLIP_MODE_DASH: {
                 // Fetch the information about this particular dash.
-                BorderClipDash dash = fetch_border_clip_dash(cmi.clip_data_address, cmi.segment);
+                BorderClipDash dash = fetch_border_clip_dash(cmi.clip_data_address);
                 vPoint_Tangent0 = dash.point_tangent_0 * sign_modifier.xyxy;
                 vPoint_Tangent1 = dash.point_tangent_1 * sign_modifier.xyxy;
                 vDotParams = vec3(0.0);
                 vAlphaMask = vec2(0.0, 1.0);
                 break;
             }
             case CLIP_MODE_DOT: {
-                BorderClipDot cdot = fetch_border_clip_dot(cmi.clip_data_address, cmi.segment);
+                BorderClipDot cdot = fetch_border_clip_dot(cmi.clip_data_address);
                 vPoint_Tangent0 = vec4(1.0);
                 vPoint_Tangent1 = vec4(1.0);
                 vDotParams = vec3(cdot.center_radius.xy * sign_modifier, cdot.center_radius.z);
                 vAlphaMask = vec2(1.0, 1.0);
+
+                // Generate a tighter bounding rect for dots based on their position. Dot
+                // centers are given relative to clip center, so we need to move the dot
+                // rectangle into the clip space with an origin at the top left. First,
+                // we expand the radius slightly to ensure we get full coverage on all the pixels
+                // of the dots.
+                float expanded_radius = cdot.center_radius.z + 2.0;
+                pos = (vClipCenter + vDotParams.xy - vec2(expanded_radius));
+                pos += (aPosition.xy * vec2(expanded_radius * 2.0));
+                pos = clamp(pos, corner.rect.p0, corner.rect.p0 + corner.rect.size);
+
                 break;
             }
             default:
                 vPoint_Tangent0 = vPoint_Tangent1 = vec4(1.0);
                 vDotParams = vec3(0.0);
                 vAlphaMask = vec2(0.0);
         }
     }
 
-    // Get local vertex position for the corner rect.
-    // TODO(gw): We could reduce the number of pixels written here
-    // by calculating a tight fitting bounding box of the dash itself.
-    vec2 pos = corner.rect.p0 + aPosition.xy * corner.rect.size;
-
     // Transform to world pos
     vec4 world_pos = scroll_node.transform * vec4(pos, 0.0, 1.0);
     world_pos.xyz /= world_pos.w;
 
     // Scale into device pixels.
     vec2 device_pos = world_pos.xy * uDevicePixelRatio;
 
     // Position vertex within the render task area.
--- a/gfx/webrender/res/prim_shared.glsl
+++ b/gfx/webrender/res/prim_shared.glsl
@@ -38,16 +38,17 @@ varying vec3 vClipMaskUv;
 
 #ifdef WR_VERTEX_SHADER
 
 #define VECS_PER_LOCAL_CLIP_RECT    1
 #define VECS_PER_PRIM_HEADER        2
 #define VECS_PER_TEXT_RUN           3
 #define VECS_PER_GRADIENT_STOP      2
 
+#define COLOR_MODE_FROM_PASS          0
 #define COLOR_MODE_ALPHA              1
 #define COLOR_MODE_SUBPX_CONST_COLOR  2
 #define COLOR_MODE_SUBPX_BG_PASS0     3
 #define COLOR_MODE_SUBPX_BG_PASS1     4
 #define COLOR_MODE_SUBPX_BG_PASS2     5
 #define COLOR_MODE_SUBPX_DUAL_SOURCE  6
 #define COLOR_MODE_BITMAP             7
 #define COLOR_MODE_COLOR_BITMAP       8
--- a/gfx/webrender/res/ps_text_run.glsl
+++ b/gfx/webrender/res/ps_text_run.glsl
@@ -59,17 +59,22 @@ VertexInfo write_text_vertex(vec2 clampe
 }
 
 void main(void) {
     Primitive prim = load_primitive();
     TextRun text = fetch_text_run(prim.specific_prim_address);
 
     int glyph_index = prim.user_data0;
     int resource_address = prim.user_data1;
-    int subpx_dir = prim.user_data2;
+    int subpx_dir = prim.user_data2 >> 16;
+    int color_mode = prim.user_data2 & 0xffff;
+
+    if (color_mode == COLOR_MODE_FROM_PASS) {
+        color_mode = uMode;
+    }
 
     Glyph glyph = fetch_glyph(prim.specific_prim_address,
                               glyph_index,
                               subpx_dir);
     GlyphResource res = fetch_glyph_resource(resource_address);
 
 #ifdef WR_FEATURE_GLYPH_TRANSFORM
     // Transform from local space to glyph space.
@@ -118,17 +123,17 @@ void main(void) {
     vec2 f = (transform * vi.local_pos - glyph_rect.p0) / glyph_rect.size;
     vUvClip = vec4(f, 1.0 - f);
 #else
     vec2 f = (vi.local_pos - glyph_rect.p0) / glyph_rect.size;
 #endif
 
     write_clip(vi.screen_pos, prim.clip_area);
 
-    switch (uMode) {
+    switch (color_mode) {
         case COLOR_MODE_ALPHA:
         case COLOR_MODE_BITMAP:
             vMaskSwizzle = vec2(0.0, 1.0);
             vColor = text.color;
             break;
         case COLOR_MODE_SUBPX_BG_PASS2:
         case COLOR_MODE_SUBPX_DUAL_SOURCE:
             vMaskSwizzle = vec2(1.0, 0.0);
--- a/gfx/webrender/src/batch.rs
+++ b/gfx/webrender/src/batch.rs
@@ -1,25 +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::{AlphaType, ClipMode, DeviceIntRect, DeviceIntSize};
-use api::{DeviceUintRect, DeviceUintPoint, DeviceUintSize, ExternalImageType, FilterOp, ImageRendering, LayerRect};
+use api::{DeviceUintRect, DeviceUintPoint, DeviceUintSize, ExternalImageType, FilterOp, ImageRendering, LayoutRect};
 use api::{DeviceIntPoint, SubpixelDirection, YuvColorSpace, YuvFormat};
-use api::{LayerToWorldTransform, WorldPixel};
+use api::{LayoutToWorldTransform, WorldPixel};
 use border::{BorderCornerInstance, BorderCornerSide, BorderEdgeKind};
 use clip::{ClipSource, ClipStore, ClipWorkItem};
 use clip_scroll_tree::{CoordinateSystemId};
 use euclid::{TypedTransform3D, vec3};
 use glyph_rasterizer::GlyphFormat;
 use gpu_cache::{GpuCache, GpuCacheAddress};
-use gpu_types::{BrushFlags, BrushInstance, ClipChainRectIndex, ZBufferId, ZBufferIdGenerator};
-use gpu_types::{ClipMaskInstance, ClipScrollNodeIndex, RasterizationSpace};
-use gpu_types::{CompositePrimitiveInstance, PrimitiveInstance, SimplePrimitiveInstance};
+use gpu_types::{BrushFlags, BrushInstance, ClipChainRectIndex, ClipMaskBorderCornerDotDash};
+use gpu_types::{ClipMaskInstance, ClipScrollNodeIndex, CompositePrimitiveInstance};
+use gpu_types::{PrimitiveInstance, RasterizationSpace, SimplePrimitiveInstance, ZBufferId};
+use gpu_types::ZBufferIdGenerator;
 use internal_types::{FastHashMap, SavedTargetIndex, SourceTexture};
 use picture::{PictureCompositeMode, PicturePrimitive, PictureSurface};
 use picture::{IMAGE_BRUSH_BLOCKS, IMAGE_BRUSH_EXTRA_BLOCKS};
 use plane_split::{BspSplitter, Polygon, Splitter};
 use prim_store::{CachedGradient, ImageSource, PrimitiveIndex, PrimitiveKind, PrimitiveMetadata, PrimitiveStore};
 use prim_store::{BrushPrimitive, BrushKind, DeferredResolve, EdgeAaSegmentMask, PictureIndex, PrimitiveRun};
 use render_task::{RenderTaskAddress, RenderTaskId, RenderTaskKind, RenderTaskTree};
 use renderer::{BlendMode, ImageBufferKind};
@@ -1150,41 +1151,66 @@ impl AlphaBatchBuilder {
                             ],
                         };
 
                         let kind = BatchKind::Transformable(
                             transform_kind,
                             TransformBatchKind::TextRun(glyph_format),
                         );
 
-                        let blend_mode = match glyph_format {
+                        let (blend_mode, color_mode) = match glyph_format {
                             GlyphFormat::Subpixel |
                             GlyphFormat::TransformedSubpixel => {
                                 if text_cpu.font.bg_color.a != 0 {
-                                    BlendMode::SubpixelWithBgColor
+                                    (
+                                        BlendMode::SubpixelWithBgColor,
+                                        ShaderColorMode::FromRenderPassMode,
+                                    )
                                 } else if ctx.use_dual_source_blending {
-                                    BlendMode::SubpixelDualSource
+                                    (
+                                        BlendMode::SubpixelDualSource,
+                                        ShaderColorMode::SubpixelDualSource,
+                                    )
                                 } else {
-                                    BlendMode::SubpixelConstantTextColor(text_cpu.font.color.into())
+                                    (
+                                        BlendMode::SubpixelConstantTextColor(text_cpu.font.color.into()),
+                                        ShaderColorMode::SubpixelConstantTextColor,
+                                    )
                                 }
                             }
                             GlyphFormat::Alpha |
-                            GlyphFormat::TransformedAlpha |
-                            GlyphFormat::Bitmap |
-                            GlyphFormat::ColorBitmap => BlendMode::PremultipliedAlpha,
+                            GlyphFormat::TransformedAlpha => {
+                                (
+                                    BlendMode::PremultipliedAlpha,
+                                    ShaderColorMode::Alpha,
+                                )
+                            }
+                            GlyphFormat::Bitmap => {
+                                (
+                                    BlendMode::PremultipliedAlpha,
+                                    ShaderColorMode::Bitmap,
+                                )
+                            }
+                            GlyphFormat::ColorBitmap => {
+                                (
+                                    BlendMode::PremultipliedAlpha,
+                                    ShaderColorMode::ColorBitmap,
+                                )
+                            }
                         };
 
                         let key = BatchKey::new(kind, blend_mode, textures);
                         let batch = batch_list.get_suitable_batch(key, &task_relative_bounding_rect);
 
                         for glyph in glyphs {
                             batch.push(base_instance.build(
                                 glyph.index_in_text_run,
                                 glyph.uv_rect_address.as_int(),
-                                subpx_dir as u32 as i32,
+                                (subpx_dir as u32 as i32) << 16 |
+                                (color_mode as u32 as i32),
                             ));
                         }
                     },
                 );
             }
         }
     }
 
@@ -1582,18 +1608,18 @@ pub fn resolve_image(
         }
     }
 }
 
 /// Construct a polygon from stacking context boundaries.
 /// `anchor` here is an index that's going to be preserved in all the
 /// splits of the polygon.
 fn make_polygon(
-    rect: LayerRect,
-    transform: &LayerToWorldTransform,
+    rect: LayoutRect,
+    transform: &LayoutToWorldTransform,
     anchor: usize,
 ) -> Polygon<f64, WorldPixel> {
     let mat = TypedTransform3D::row_major(
         transform.m11 as f64,
         transform.m12 as f64,
         transform.m13 as f64,
         transform.m14 as f64,
         transform.m21 as f64,
@@ -1615,18 +1641,18 @@ fn make_polygon(
 #[derive(Debug)]
 #[cfg_attr(feature = "capture", derive(Serialize))]
 #[cfg_attr(feature = "replay", derive(Deserialize))]
 pub struct ClipBatcher {
     /// Rectangle draws fill up the rectangles with rounded corners.
     pub rectangles: Vec<ClipMaskInstance>,
     /// Image draws apply the image masking.
     pub images: FastHashMap<SourceTexture, Vec<ClipMaskInstance>>,
-    pub border_clears: Vec<ClipMaskInstance>,
-    pub borders: Vec<ClipMaskInstance>,
+    pub border_clears: Vec<ClipMaskBorderCornerDotDash>,
+    pub borders: Vec<ClipMaskBorderCornerDotDash>,
     pub box_shadows: FastHashMap<SourceTexture, Vec<ClipMaskInstance>>,
     pub line_decorations: Vec<ClipMaskInstance>,
 }
 
 impl ClipBatcher {
     pub fn new() -> Self {
         ClipBatcher {
             rectangles: Vec::new(),
@@ -1740,26 +1766,36 @@ impl ClipBatcher {
                     }
                     ClipSource::RoundedRectangle(..) => {
                         self.rectangles.push(ClipMaskInstance {
                             clip_data_address: gpu_address,
                             ..instance
                         });
                     }
                     ClipSource::BorderCorner(ref source) => {
-                        self.border_clears.push(ClipMaskInstance {
-                            clip_data_address: gpu_address,
-                            segment: 0,
-                            ..instance
-                        });
-                        for clip_index in 0 .. source.actual_clip_count {
-                            self.borders.push(ClipMaskInstance {
+                        let instance = ClipMaskBorderCornerDotDash {
+                            clip_mask_instance: ClipMaskInstance {
                                 clip_data_address: gpu_address,
-                                segment: 1 + clip_index as i32,
+                                segment: 0,
                                 ..instance
+                            },
+                            dot_dash_data: [0.; 8],
+                        };
+
+                        self.border_clears.push(instance);
+
+                        for data in source.dot_dash_data.iter() {
+                            self.borders.push(ClipMaskBorderCornerDotDash {
+                                clip_mask_instance: ClipMaskInstance {
+                                    // The shader understands segment=0 as the clear, so the
+                                    // segment here just needs to be non-zero.
+                                    segment: 1,
+                                    ..instance.clip_mask_instance
+                                },
+                                dot_dash_data: *data,
                             })
                         }
                     }
                 }
             }
         }
     }
 }
--- a/gfx/webrender/src/border.rs
+++ b/gfx/webrender/src/border.rs
@@ -1,14 +1,14 @@
 /* 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, BorderSide, BorderStyle, BorderWidths, ClipMode, ColorF, LayerPoint};
-use api::{LayerPrimitiveInfo, LayerRect, LayerSize, NormalBorder, RepeatMode, TexelRect};
+use api::{BorderRadius, BorderSide, BorderStyle, BorderWidths, ClipMode, ColorF, LayoutPoint};
+use api::{LayoutPrimitiveInfo, LayoutRect, LayoutSize, NormalBorder, RepeatMode, TexelRect};
 use clip::ClipSource;
 use ellipse::Ellipse;
 use display_list_flattener::DisplayListFlattener;
 use gpu_cache::GpuDataRequest;
 use prim_store::{BorderPrimitiveCpu, BrushClipMaskKind, BrushSegment, BrushSegmentDescriptor};
 use prim_store::{EdgeAaSegmentMask, PrimitiveContainer, ScrollNodeAndClipChain};
 use util::{lerp, pack_as_float};
 
@@ -37,70 +37,70 @@ enum BorderCorner {
 
 #[derive(Clone, Debug, PartialEq)]
 pub enum BorderCornerKind {
     None,
     Solid,
     Clip(BorderCornerInstance),
     Mask(
         BorderCornerClipData,
-        LayerSize,
-        LayerSize,
+        LayoutSize,
+        LayoutSize,
         BorderCornerClipKind,
     ),
 }
 
 impl BorderCornerKind {
     fn new_mask(
         kind: BorderCornerClipKind,
         width0: f32,
         width1: f32,
         corner: BorderCorner,
-        radius: LayerSize,
-        border_rect: LayerRect,
+        radius: LayoutSize,
+        border_rect: LayoutRect,
     ) -> BorderCornerKind {
-        let size = LayerSize::new(width0.max(radius.width), width1.max(radius.height));
+        let size = LayoutSize::new(width0.max(radius.width), width1.max(radius.height));
         let (origin, clip_center) = match corner {
             BorderCorner::TopLeft => {
                 let origin = border_rect.origin;
                 let clip_center = origin + size;
                 (origin, clip_center)
             }
             BorderCorner::TopRight => {
-                let origin = LayerPoint::new(
+                let origin = LayoutPoint::new(
                     border_rect.origin.x + border_rect.size.width - size.width,
                     border_rect.origin.y,
                 );
-                let clip_center = origin + LayerSize::new(0.0, size.height);
+                let clip_center = origin + LayoutSize::new(0.0, size.height);
                 (origin, clip_center)
             }
             BorderCorner::BottomRight => {
                 let origin = border_rect.origin + (border_rect.size - size);
                 let clip_center = origin;
                 (origin, clip_center)
             }
             BorderCorner::BottomLeft => {
-                let origin = LayerPoint::new(
+                let origin = LayoutPoint::new(
                     border_rect.origin.x,
                     border_rect.origin.y + border_rect.size.height - size.height,
                 );
-                let clip_center = origin + LayerSize::new(size.width, 0.0);
+                let clip_center = origin + LayoutSize::new(size.width, 0.0);
                 (origin, clip_center)
             }
         };
         let clip_data = BorderCornerClipData {
-            corner_rect: LayerRect::new(origin, size),
+            corner_rect: LayoutRect::new(origin, size),
             clip_center,
             corner: pack_as_float(corner as u32),
             kind: pack_as_float(kind as u32),
         };
-        BorderCornerKind::Mask(clip_data, radius, LayerSize::new(width0, width1), kind)
+        BorderCornerKind::Mask(clip_data, radius, LayoutSize::new(width0, width1), kind)
     }
 
-    fn get_radius(&self, original_radius: &LayerSize) -> LayerSize {
+    fn get_radius(&self, original_radius: &LayoutSize) -> LayoutSize {
         match *self {
             BorderCornerKind::Solid => *original_radius,
             BorderCornerKind::Clip(..) => *original_radius,
             BorderCornerKind::Mask(_, ref radius, _, _) => *radius,
             BorderCornerKind::None => *original_radius,
         }
     }
 }
@@ -112,19 +112,19 @@ pub enum BorderEdgeKind {
     Clip,
 }
 
 fn get_corner(
     edge0: &BorderSide,
     width0: f32,
     edge1: &BorderSide,
     width1: f32,
-    radius: &LayerSize,
+    radius: &LayoutSize,
     corner: BorderCorner,
-    border_rect: &LayerRect,
+    border_rect: &LayoutRect,
 ) -> BorderCornerKind {
     // If both widths are zero, a corner isn't formed.
     if width0 == 0.0 && width1 == 0.0 {
         return BorderCornerKind::None;
     }
 
     // If both edges are transparent, no corner is formed.
     if edge0.color.a == 0.0 && edge1.color.a == 0.0 {
@@ -231,17 +231,17 @@ fn get_edge(edge: &BorderSide, width: f3
         BorderStyle::Ridge |
         BorderStyle::Dashed |
         BorderStyle::Dotted => (BorderEdgeKind::Clip, width),
     }
 }
 
 pub fn ensure_no_corner_overlap(
     radius: &mut BorderRadius,
-    rect: &LayerRect,
+    rect: &LayoutRect,
 ) {
     let mut ratio = 1.0;
     let top_left_radius = &mut radius.top_left;
     let top_right_radius = &mut radius.top_right;
     let bottom_right_radius = &mut radius.bottom_right;
     let bottom_left_radius = &mut radius.bottom_left;
 
     let sum = top_left_radius.width + top_right_radius.width;
@@ -277,17 +277,17 @@ pub fn ensure_no_corner_overlap(
         bottom_right_radius.width *= ratio;
         bottom_right_radius.height *= ratio;
     }
 }
 
 impl<'a> DisplayListFlattener<'a> {
     fn add_normal_border_primitive(
         &mut self,
-        info: &LayerPrimitiveInfo,
+        info: &LayoutPrimitiveInfo,
         border: &NormalBorder,
         radius: &BorderRadius,
         widths: &BorderWidths,
         clip_and_scroll: ScrollNodeAndClipChain,
         corner_instances: [BorderCornerInstance; 4],
         edges: [BorderEdgeKind; 4],
         clip_sources: Vec<ClipSource>,
     ) {
@@ -345,17 +345,17 @@ impl<'a> DisplayListFlattener<'a> {
     }
 
     // TODO(gw): This allows us to move border types over to the
     // simplified shader model one at a time. Once all borders
     // are converted, this can be removed, along with the complex
     // border code path.
     pub fn add_normal_border(
         &mut self,
-        info: &LayerPrimitiveInfo,
+        info: &LayoutPrimitiveInfo,
         border: &NormalBorder,
         widths: &BorderWidths,
         clip_and_scroll: ScrollNodeAndClipChain,
     ) {
         // The border shader is quite expensive. For simple borders, we can just draw
         // the border with a few rectangles. This generally gives better batching, and
         // a GPU win in fragment shader time.
         // More importantly, the software (OSMesa) implementation we run tests on is
@@ -382,40 +382,40 @@ impl<'a> DisplayListFlattener<'a> {
         if is_simple_border {
             let extra_clips = vec![
                 ClipSource::new_rounded_rect(
                     info.rect,
                     border.radius,
                     ClipMode::Clip,
                 ),
                 ClipSource::new_rounded_rect(
-                    LayerRect::new(
-                        LayerPoint::new(
+                    LayoutRect::new(
+                        LayoutPoint::new(
                             info.rect.origin.x + widths.left,
                             info.rect.origin.y + widths.top,
                         ),
-                        LayerSize::new(
+                        LayoutSize::new(
                             info.rect.size.width - widths.left - widths.right,
                             info.rect.size.height - widths.top - widths.bottom,
                         ),
                     ),
                     BorderRadius {
-                        top_left: LayerSize::new(
+                        top_left: LayoutSize::new(
                             (border.radius.top_left.width - widths.left).max(0.0),
                             (border.radius.top_left.height - widths.top).max(0.0),
                         ),
-                        top_right: LayerSize::new(
+                        top_right: LayoutSize::new(
                             (border.radius.top_right.width - widths.right).max(0.0),
                             (border.radius.top_right.height - widths.top).max(0.0),
                         ),
-                        bottom_left: LayerSize::new(
+                        bottom_left: LayoutSize::new(
                             (border.radius.bottom_left.width - widths.left).max(0.0),
                             (border.radius.bottom_left.height - widths.bottom).max(0.0),
                         ),
-                        bottom_right: LayerSize::new(
+                        bottom_right: LayoutSize::new(
                             (border.radius.bottom_right.width - widths.right).max(0.0),
                             (border.radius.bottom_right.height - widths.bottom).max(0.0),
                         ),
                     },
                     ClipMode::ClipOut,
                 ),
             ];
 
@@ -488,29 +488,29 @@ impl<'a> DisplayListFlattener<'a> {
         let all_edges_simple = edges.iter().all(|e| {
             *e == BorderEdgeKind::Solid || *e == BorderEdgeKind::None
         });
 
         let has_no_curve = radius.is_zero();
 
         if has_no_curve && all_corners_simple && all_edges_simple {
             let p0 = info.rect.origin;
-            let p1 = LayerPoint::new(
+            let p1 = LayoutPoint::new(
                 info.rect.origin.x + left_len,
                 info.rect.origin.y + top_len,
             );
-            let p2 = LayerPoint::new(
+            let p2 = LayoutPoint::new(
                 info.rect.origin.x + info.rect.size.width - right_len,
                 info.rect.origin.y + info.rect.size.height - bottom_len,
             );
             let p3 = info.rect.bottom_right();
 
             let segment = |x0, y0, x1, y1| BrushSegment::new(
-                LayerPoint::new(x0, y0),
-                LayerSize::new(x1-x0, y1-y0),
+                LayoutPoint::new(x0, y0),
+                LayoutSize::new(x1-x0, y1-y0),
                 true,
                 EdgeAaSegmentMask::all() // Note: this doesn't seem right, needs revision
             );
 
             // Add a solid rectangle for each visible edge/corner combination.
             if top_edge == BorderEdgeKind::Solid {
                 let descriptor = BrushSegmentDescriptor {
                     segments: vec![
@@ -672,27 +672,27 @@ pub enum BorderCornerClipKind {
     Dot,
 }
 
 /// The source data for a border corner clip mask.
 #[derive(Debug, Clone)]
 pub struct BorderCornerClipSource {
     pub corner_data: BorderCornerClipData,
     pub max_clip_count: usize,
-    pub actual_clip_count: usize,
     kind: BorderCornerClipKind,
-    widths: LayerSize,
+    widths: LayoutSize,
     ellipse: Ellipse,
+    pub dot_dash_data: Vec<[f32; 8]>,
 }
 
 impl BorderCornerClipSource {
     pub fn new(
         corner_data: BorderCornerClipData,
-        corner_radius: LayerSize,
-        widths: LayerSize,
+        corner_radius: LayoutSize,
+        widths: LayoutSize,
         kind: BorderCornerClipKind,
     ) -> BorderCornerClipSource {
         // Work out a dash length (and therefore dash count)
         // based on the width of the border edges. The "correct"
         // dash length is not mentioned in the CSS borders
         // spec. The calculation below is similar, but not exactly
         // the same as what Gecko uses.
         // TODO(gw): Iterate on this to get it closer to what Gecko
@@ -748,55 +748,59 @@ impl BorderCornerClipSource {
                 }
             }
         };
 
         BorderCornerClipSource {
             kind,
             corner_data,
             max_clip_count,
-            actual_clip_count: 0,
             ellipse,
             widths,
+            dot_dash_data: Vec::new(),
         }
     }
 
     pub fn write(&mut self, mut request: GpuDataRequest) {
         self.corner_data.write(&mut request);
+        assert_eq!(request.close(), 2);
 
         match self.kind {
             BorderCornerClipKind::Dash => {
                 // Get the correct dash arc length.
-                self.actual_clip_count = self.max_clip_count;
                 let dash_arc_length =
-                    0.5 * self.ellipse.total_arc_length / (self.actual_clip_count - 1) as f32;
+                    0.5 * self.ellipse.total_arc_length / (self.max_clip_count - 1) as f32;
+                self.dot_dash_data.clear();
                 let mut current_arc_length = -0.5 * dash_arc_length;
-                for _ in 0 .. self.actual_clip_count {
+                for _ in 0 .. self.max_clip_count {
                     let arc_length0 = current_arc_length;
                     current_arc_length += dash_arc_length;
 
                     let arc_length1 = current_arc_length;
                     current_arc_length += dash_arc_length;
 
-                    let dash_data =
-                        BorderCornerDashClipData::new(arc_length0, arc_length1, &self.ellipse);
-                    dash_data.write(&mut request);
+                    let alpha = self.ellipse.find_angle_for_arc_length(arc_length0);
+                    let beta =  self.ellipse.find_angle_for_arc_length(arc_length1);
+
+                    let (point0, tangent0) =  self.ellipse.get_point_and_tangent(alpha);
+                    let (point1, tangent1) =  self.ellipse.get_point_and_tangent(beta);
+
+                    self.dot_dash_data.push([
+                        point0.x, point0.y, tangent0.x, tangent0.y,
+                        point1.x, point1.y, tangent1.x, tangent1.y
+                    ]);
                 }
-
-                assert_eq!(request.close(), 2 + 2 * self.actual_clip_count);
             }
             BorderCornerClipKind::Dot if self.max_clip_count == 1 => {
                 let dot_diameter = lerp(self.widths.width, self.widths.height, 0.5);
-                let dot = BorderCornerDotClipData {
-                    center: LayerPoint::new(self.widths.width / 2.0, self.widths.height / 2.0),
-                    radius: 0.5 * dot_diameter,
-                };
-                self.actual_clip_count = 1;
-                dot.write(&mut request);
-                assert_eq!(request.close(), 3);
+                self.dot_dash_data.clear();
+                self.dot_dash_data.push([
+                    self.widths.width / 2.0, self.widths.height / 2.0, 0.5 * dot_diameter, 0.,
+                    0., 0., 0., 0.,
+                ]);
             }
             BorderCornerClipKind::Dot => {
                 let mut forward_dots = Vec::new();
                 let mut back_dots = Vec::new();
                 let mut leftover_arc_length = 0.0;
 
                 // Alternate between adding dots at the start and end of the
                 // ellipse arc. This ensures that we always end up with an exact
@@ -847,55 +851,56 @@ impl BorderCornerClipSource {
                         back_dots.push(dot);
                     }
                 }
 
                 // Now step through the dots, and distribute any extra
                 // leftover space on the arc between them evenly. Once
                 // the final arc position is determined, generate the correct
                 // arc positions and angles that get passed to the clip shader.
-                self.actual_clip_count = forward_dots.len() + back_dots.len();
-                let extra_space_per_dot = leftover_arc_length / (self.actual_clip_count - 1) as f32;
+                let number_of_dots = forward_dots.len() + back_dots.len();
+                let extra_space_per_dot = leftover_arc_length / (number_of_dots - 1) as f32;
+
+                self.dot_dash_data.clear();
+
+                let create_dot_data = |ellipse: &Ellipse, arc_length: f32, radius: f32| -> [f32; 8] {
+                    // Represents the GPU data for drawing a single dot to a clip mask. The order
+                    // these are specified must stay in sync with the way this data is read in the
+                    // dot clip shader.
+                    let theta = ellipse.find_angle_for_arc_length(arc_length);
+                    let (center, _) = ellipse.get_point_and_tangent(theta);
+                    [center.x, center.y, radius, 0., 0., 0., 0., 0.,]
+                };
 
                 for (i, dot) in forward_dots.iter().enumerate() {
                     let extra_dist = i as f32 * extra_space_per_dot;
-                    let dot = BorderCornerDotClipData::new(
-                        dot.arc_pos + extra_dist,
-                        0.5 * dot.diameter,
-                        &self.ellipse,
-                    );
-                    dot.write(&mut request);
+                    let dot_data = create_dot_data(&self.ellipse, dot.arc_pos + extra_dist, 0.5 * dot.diameter);
+                    self.dot_dash_data.push(dot_data);
                 }
 
                 for (i, dot) in back_dots.iter().enumerate() {
                     let extra_dist = i as f32 * extra_space_per_dot;
-                    let dot = BorderCornerDotClipData::new(
-                        dot.arc_pos - extra_dist,
-                        0.5 * dot.diameter,
-                        &self.ellipse,
-                    );
-                    dot.write(&mut request);
+                    let dot_data = create_dot_data(&self.ellipse, dot.arc_pos - extra_dist, 0.5 * dot.diameter);
+                    self.dot_dash_data.push(dot_data);
                 }
-
-                assert_eq!(request.close(), 2 + self.actual_clip_count);
             }
         }
     }
 }
 
 /// Represents the common GPU data for writing a
 /// clip mask for a border corner.
 #[derive(Debug, Copy, Clone, PartialEq)]
 #[repr(C)]
 pub struct BorderCornerClipData {
     /// Local space rect of the border corner.
-    corner_rect: LayerRect,
+    corner_rect: LayoutRect,
     /// Local space point that is the center of the
     /// circle or ellipse that we are clipping against.
-    clip_center: LayerPoint,
+    clip_center: LayoutPoint,
     /// The shader needs to know which corner, to
     /// be able to flip the dash tangents to the
     /// right orientation.
     corner: f32, // Of type BorderCorner enum
     kind: f32, // Of type BorderCornerClipKind enum
 }
 
 impl BorderCornerClipData {
@@ -905,117 +910,49 @@ impl BorderCornerClipData {
             self.clip_center.x,
             self.clip_center.y,
             self.corner,
             self.kind,
         ]);
     }
 }
 
-/// Represents the GPU data for drawing a single dash
-/// to a clip mask. A dash clip is defined by two lines.
-/// We store a point on the ellipse curve, and a tangent
-/// to that point, which allows for efficient line-distance
-/// calculations in the fragment shader.
-#[derive(Debug, Clone)]
-#[repr(C)]
-pub struct BorderCornerDashClipData {
-    pub point0: LayerPoint,
-    pub tangent0: LayerPoint,
-    pub point1: LayerPoint,
-    pub tangent1: LayerPoint,
-}
-
-impl BorderCornerDashClipData {
-    pub fn new(arc_length0: f32, arc_length1: f32, ellipse: &Ellipse) -> BorderCornerDashClipData {
-        let alpha = ellipse.find_angle_for_arc_length(arc_length0);
-        let beta = ellipse.find_angle_for_arc_length(arc_length1);
-
-        let (p0, t0) = ellipse.get_point_and_tangent(alpha);
-        let (p1, t1) = ellipse.get_point_and_tangent(beta);
-
-        BorderCornerDashClipData {
-            point0: p0,
-            tangent0: t0,
-            point1: p1,
-            tangent1: t1,
-        }
-    }
-
-    fn write(&self, request: &mut GpuDataRequest) {
-        request.push([
-            self.point0.x,
-            self.point0.y,
-            self.tangent0.x,
-            self.tangent0.y,
-        ]);
-        request.push([
-            self.point1.x,
-            self.point1.y,
-            self.tangent1.x,
-            self.tangent1.y,
-        ]);
-    }
-}
-
-/// Represents the GPU data for drawing a single dot
-/// to a clip mask.
-#[derive(Debug, Clone)]
-#[repr(C)]
-pub struct BorderCornerDotClipData {
-    pub center: LayerPoint,
-    pub radius: f32,
-}
-
-impl BorderCornerDotClipData {
-    pub fn new(arc_length: f32, radius: f32, ellipse: &Ellipse) -> BorderCornerDotClipData {
-        let theta = ellipse.find_angle_for_arc_length(arc_length);
-        let (center, _) = ellipse.get_point_and_tangent(theta);
-
-        BorderCornerDotClipData { center, radius }
-    }
-
-    fn write(&self, request: &mut GpuDataRequest) {
-        request.push([self.center.x, self.center.y, self.radius, 0.0]);
-    }
-}
-
 #[derive(Copy, Clone, Debug)]
 struct DotInfo {
     arc_pos: f32,
     diameter: f32,
 }
 
 impl DotInfo {
     fn new(arc_pos: f32, diameter: f32) -> DotInfo {
         DotInfo { arc_pos, diameter }
     }
 }
 
 #[derive(Debug, Clone)]
 pub struct ImageBorderSegment {
-    pub geom_rect: LayerRect,
+    pub geom_rect: LayoutRect,
     pub sub_rect: TexelRect,
-    pub stretch_size: LayerSize,
-    pub tile_spacing: LayerSize,
+    pub stretch_size: LayoutSize,
+    pub tile_spacing: LayoutSize,
 }
 
 impl ImageBorderSegment {
     pub fn new(
-        rect: LayerRect,
+        rect: LayoutRect,
         sub_rect: TexelRect,
         repeat_horizontal: RepeatMode,
         repeat_vertical: RepeatMode,
     ) -> ImageBorderSegment {
-        let tile_spacing = LayerSize::zero();
+        let tile_spacing = LayoutSize::zero();
 
         debug_assert!(sub_rect.uv1.x >= sub_rect.uv0.x);
         debug_assert!(sub_rect.uv1.y >= sub_rect.uv0.y);
 
-        let image_size = LayerSize::new(
+        let image_size = LayoutSize::new(
             sub_rect.uv1.x - sub_rect.uv0.x,
             sub_rect.uv1.y - sub_rect.uv0.y,
         );
 
         let stretch_size_x = match repeat_horizontal {
             RepeatMode::Stretch => rect.size.width,
             RepeatMode::Repeat => image_size.width,
             RepeatMode::Round | RepeatMode::Space => {
@@ -1031,13 +968,13 @@ impl ImageBorderSegment {
                 error!("Round/Space not supported yet!");
                 rect.size.height
             }
         };
 
         ImageBorderSegment {
             geom_rect: rect,
             sub_rect,
-            stretch_size: LayerSize::new(stretch_size_x, stretch_size_y),
+            stretch_size: LayoutSize::new(stretch_size_x, stretch_size_y),
             tile_spacing,
         }
     }
 }
--- a/gfx/webrender/src/box_shadow.rs
+++ b/gfx/webrender/src/box_shadow.rs
@@ -1,14 +1,14 @@
 /* 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, LayerPrimitiveInfo};
-use api::{LayerRect, LayerSize, LayerVector2D, LayoutSize};
+use api::{BorderRadius, BoxShadowClipMode, ClipMode, ColorF, DeviceIntSize, LayoutPrimitiveInfo};
+use api::{LayoutRect, LayoutSize, LayoutVector2D};
 use clip::ClipSource;
 use display_list_flattener::DisplayListFlattener;
 use gpu_cache::GpuCacheHandle;
 use gpu_types::BoxShadowStretchMode;
 use prim_store::{BrushKind, BrushPrimitive, PrimitiveContainer};
 use prim_store::ScrollNodeAndClipChain;
 use render_task::RenderTaskCacheEntryHandle;
 use util::RectHelpers;
@@ -24,25 +24,25 @@ pub struct BoxShadowClipSource {
 
     // The current cache key (in device-pixels), and handles
     // to the cached clip region and blurred texture.
     pub cache_key: Option<(DeviceIntSize, BoxShadowCacheKey)>,
     pub cache_handle: Option<RenderTaskCacheEntryHandle>,
     pub clip_data_handle: GpuCacheHandle,
 
     // Local-space size of the required render task size.
-    pub shadow_rect_alloc_size: LayerSize,
+    pub shadow_rect_alloc_size: LayoutSize,
 
     // The minimal shadow rect for the parameters above,
     // used when drawing the shadow rect to be blurred.
-    pub minimal_shadow_rect: LayerRect,
+    pub minimal_shadow_rect: LayoutRect,
 
     // Local space rect for the shadow to be drawn or
     // stretched in the shadow primitive.
-    pub prim_shadow_rect: LayerRect,
+    pub prim_shadow_rect: LayoutRect,
 }
 
 // The blur shader samples BLUR_SAMPLE_SCALE * blur_radius surrounding texels.
 pub const BLUR_SAMPLE_SCALE: f32 = 3.0;
 
 // Maximum blur radius.
 // Taken from https://searchfox.org/mozilla-central/rev/c633ffa4c4611f202ca11270dcddb7b29edddff8/layout/painting/nsCSSRendering.cpp#4412
 pub const MAX_BLUR_RADIUS : f32 = 300.;
@@ -62,18 +62,18 @@ pub struct BoxShadowCacheKey {
     pub br_bottom_right: DeviceIntSize,
     pub br_bottom_left: DeviceIntSize,
 }
 
 impl<'a> DisplayListFlattener<'a> {
     pub fn add_box_shadow(
         &mut self,
         clip_and_scroll: ScrollNodeAndClipChain,
-        prim_info: &LayerPrimitiveInfo,
-        box_offset: &LayerVector2D,
+        prim_info: &LayoutPrimitiveInfo,
+        box_offset: &LayoutVector2D,
         color: &ColorF,
         mut blur_radius: f32,
         spread_radius: f32,
         border_radius: BorderRadius,
         clip_mode: BoxShadowClipMode,
     ) {
         if color.a == 0.0 {
             return;
@@ -142,22 +142,21 @@ impl<'a> DisplayListFlattener<'a> {
                     (prim_info.rect, border_radius)
                 }
             };
 
             clips.push(ClipSource::new_rounded_rect(final_prim_rect, clip_radius, ClipMode::Clip));
 
             self.add_primitive(
                 clip_and_scroll,
-                &LayerPrimitiveInfo::with_clip_rect(final_prim_rect, prim_info.clip_rect),
+                &LayoutPrimitiveInfo::with_clip_rect(final_prim_rect, prim_info.clip_rect),
                 clips,
                 PrimitiveContainer::Brush(
-                    BrushPrimitive::new(BrushKind::Solid {
-                            color: *color,
-                        },
+                    BrushPrimitive::new(
+                        BrushKind::new_solid(*color),
                         None,
                     )
                 ),
             );
         } else {
             // Normal path for box-shadows with a valid blur radius.
             let blur_offset = BLUR_SAMPLE_SCALE * blur_radius;
             let mut extra_clips = vec![];
@@ -172,19 +171,17 @@ impl<'a> DisplayListFlattener<'a> {
 
             // Get the local rect of where the shadow will be drawn,
             // expanded to include room for the blurred region.
             let dest_rect = shadow_rect.inflate(blur_offset, blur_offset);
 
             // Draw the box-shadow as a solid rect, using a box-shadow
             // clip mask source.
             let prim = BrushPrimitive::new(
-                BrushKind::Solid {
-                    color: *color,
-                },
+                BrushKind::new_solid(*color),
                 None,
             );
 
             // Create the box-shadow clip source.
             let shadow_clip_source = ClipSource::new_box_shadow(
                 shadow_rect,
                 shadow_radius,
                 dest_rect,
@@ -199,17 +196,17 @@ impl<'a> DisplayListFlattener<'a> {
                         return;
                     }
 
                     // Add the box-shadow clip source.
                     extra_clips.push(shadow_clip_source);
 
                     // Outset shadows are expanded by the shadow
                     // region from the original primitive.
-                    LayerPrimitiveInfo::with_clip_rect(dest_rect, prim_info.clip_rect)
+                    LayoutPrimitiveInfo::with_clip_rect(dest_rect, prim_info.clip_rect)
                 }
                 BoxShadowClipMode::Inset => {
                     // If the inner shadow rect contains the prim
                     // rect, no pixels will be shadowed.
                     if border_radius.is_zero() &&
                        shadow_rect.inflate(-blur_radius, -blur_radius).contains_rect(&prim_info.rect) {
                         return;
                     }
--- a/gfx/webrender/src/clip.rs
+++ b/gfx/webrender/src/clip.rs
@@ -1,54 +1,54 @@
 /* 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, LayerRect, LayerSize, LayoutPoint, LayoutVector2D, LocalClip};
-use api::{BoxShadowClipMode, LayerPoint, LayerToWorldScale, LineOrientation, LineStyle};
+use api::{ImageRendering, LayoutRect, LayoutSize, LayoutPoint, LayoutVector2D, LocalClip};
+use api::{BoxShadowClipMode, LayoutToWorldScale, LineOrientation, LineStyle};
 use border::{BorderCornerClipSource, ensure_no_corner_overlap};
 use box_shadow::{BLUR_SAMPLE_SCALE, BoxShadowClipSource, BoxShadowCacheKey};
 use clip_scroll_tree::{ClipChainIndex, CoordinateSystemId};
 use ellipse::Ellipse;
 use freelist::{FreeList, FreeListHandle, WeakFreeListHandle};
 use gpu_cache::{GpuCache, GpuCacheHandle, ToGpuBlocks};
 use gpu_types::{BoxShadowStretchMode, ClipScrollNodeIndex};
 use prim_store::{ClipData, ImageMaskData};
 use render_task::to_cache_size;
 use resource_cache::{ImageRequest, ResourceCache};
-use util::{LayerToWorldFastTransform, MaxRect, calculate_screen_bounding_rect};
+use util::{LayoutToWorldFastTransform, MaxRect, calculate_screen_bounding_rect};
 use util::{extract_inner_rect_safe, pack_as_float};
 use std::sync::Arc;
 
 #[derive(Debug)]
 pub enum ClipStoreMarker {}
 
 pub type ClipStore = FreeList<ClipSources, ClipStoreMarker>;
 pub type ClipSourcesHandle = FreeListHandle<ClipStoreMarker>;
 pub type ClipSourcesWeakHandle = WeakFreeListHandle<ClipStoreMarker>;
 
 #[derive(Debug)]
 pub struct LineDecorationClipSource {
-    rect: LayerRect,
+    rect: LayoutRect,
     style: LineStyle,
     orientation: LineOrientation,
     wavy_line_thickness: f32,
 }
 
 #[derive(Clone, Debug)]
 pub struct ClipRegion {
-    pub main: LayerRect,
+    pub main: LayoutRect,
     pub image_mask: Option<ImageMask>,
     pub complex_clips: Vec<ComplexClipRegion>,
 }
 
 impl ClipRegion {
     pub fn create_for_clip_node(
-        rect: LayerRect,
+        rect: LayoutRect,
         mut complex_clips: Vec<ComplexClipRegion>,
         mut image_mask: Option<ImageMask>,
         reference_frame_relative_offset: &LayoutVector2D,
     ) -> ClipRegion {
         let rect = rect.translate(reference_frame_relative_offset);
 
         if let Some(ref mut image_mask) = image_mask {
             image_mask.rect = image_mask.rect.translate(reference_frame_relative_offset);
@@ -79,18 +79,18 @@ impl ClipRegion {
             None,
             reference_frame_relative_offset
         )
     }
 }
 
 #[derive(Debug)]
 pub enum ClipSource {
-    Rectangle(LayerRect, ClipMode),
-    RoundedRectangle(LayerRect, BorderRadius, ClipMode),
+    Rectangle(LayoutRect, ClipMode),
+    RoundedRectangle(LayoutRect, BorderRadius, ClipMode),
     Image(ImageMask),
     /// TODO(gw): This currently only handles dashed style
     /// clips, where the border style is dashed for both
     /// adjacent border edges. Expand to handle dotted style
     /// and different styles per edge.
     BorderCorner(BorderCornerClipSource),
     BoxShadow(BoxShadowClipSource),
     LineDecoration(LineDecorationClipSource),
@@ -115,62 +115,62 @@ impl From<ClipRegion> for ClipSources {
         }
 
         ClipSources::new(clips)
     }
 }
 
 impl ClipSource {
     pub fn new_rounded_rect(
-        rect: LayerRect,
+        rect: LayoutRect,
         mut radii: BorderRadius,
         clip_mode: ClipMode
     ) -> ClipSource {
         if radii.is_zero() {
             ClipSource::Rectangle(rect, clip_mode)
         } else {
             ensure_no_corner_overlap(&mut radii, &rect);
             ClipSource::RoundedRectangle(
                 rect,
                 radii,
                 clip_mode,
             )
         }
     }
 
     pub fn new_line_decoration(
-        rect: LayerRect,
+        rect: LayoutRect,
         style: LineStyle,
         orientation: LineOrientation,
         wavy_line_thickness: f32,
     ) -> ClipSource {
         ClipSource::LineDecoration(
             LineDecorationClipSource {
                 rect,
                 style,
                 orientation,
                 wavy_line_thickness,
             }
         )
     }
 
     pub fn new_box_shadow(
-        shadow_rect: LayerRect,
+        shadow_rect: LayoutRect,
         shadow_radius: BorderRadius,
-        prim_shadow_rect: LayerRect,
+        prim_shadow_rect: LayoutRect,
         blur_radius: f32,
         clip_mode: BoxShadowClipMode,
     ) -> ClipSource {
         // Get the fractional offsets required to match the
         // source rect with a minimal rect.
-        let fract_offset = LayerPoint::new(
+        let fract_offset = LayoutPoint::new(
             shadow_rect.origin.x.fract().abs(),
             shadow_rect.origin.y.fract().abs(),
         );
-        let fract_size = LayerSize::new(
+        let fract_size = LayoutSize::new(
             shadow_rect.size.width.fract().abs(),
             shadow_rect.size.height.fract().abs(),
         );
 
         // Create a minimal size primitive mask to blur. In this
         // case, we ensure the size of each corner is the same,
         // to simplify the shader logic that stretches the blurred
         // result across the primitive.
@@ -187,28 +187,28 @@ impl ClipSource {
         let blur_region = (BLUR_SAMPLE_SCALE * blur_radius).ceil();
 
         // If the largest corner is smaller than the blur radius, we need to ensure
         // that it's big enough that the corners don't affect the middle segments.
         let used_corner_width = max_corner_width.max(blur_region);
         let used_corner_height = max_corner_height.max(blur_region);
 
         // Minimal nine-patch size, corner + internal + corner.
-        let min_shadow_rect_size = LayerSize::new(
+        let min_shadow_rect_size = LayoutSize::new(
             2.0 * used_corner_width + blur_region,
             2.0 * used_corner_height + blur_region,
         );
 
         // The minimal rect to blur.
-        let mut minimal_shadow_rect = LayerRect::new(
-            LayerPoint::new(
+        let mut minimal_shadow_rect = LayoutRect::new(
+            LayoutPoint::new(
                 blur_region + fract_offset.x,
                 blur_region + fract_offset.y,
             ),
-            LayerSize::new(
+            LayoutSize::new(
                 min_shadow_rect_size.width + fract_size.width,
                 min_shadow_rect_size.height + fract_size.height,
             ),
         );
 
         // If the width or height ends up being bigger than the original
         // primitive shadow rect, just blur the entire rect along that
         // axis and draw that as a simple blit. This is necessary for
@@ -222,17 +222,17 @@ impl ClipSource {
 
         let mut stretch_mode_y = BoxShadowStretchMode::Stretch;
         if shadow_rect.size.height < minimal_shadow_rect.size.height {
             minimal_shadow_rect.size.height = shadow_rect.size.height;
             stretch_mode_y = BoxShadowStretchMode::Simple;
         }
 
         // Expand the shadow rect by enough room for the blur to take effect.
-        let shadow_rect_alloc_size = LayerSize::new(
+        let shadow_rect_alloc_size = LayoutSize::new(
             2.0 * blur_region + minimal_shadow_rect.size.width.ceil(),
             2.0 * blur_region + minimal_shadow_rect.size.height.ceil(),
         );
 
         ClipSource::BoxShadow(BoxShadowClipSource {
             shadow_rect_alloc_size,
             shadow_radius,
             prim_shadow_rect,
@@ -262,18 +262,18 @@ impl ClipSource {
             }
         }
     }
 }
 
 #[derive(Debug)]
 pub struct ClipSources {
     pub clips: Vec<(ClipSource, GpuCacheHandle)>,
-    pub local_inner_rect: LayerRect,
-    pub local_outer_rect: Option<LayerRect>
+    pub local_inner_rect: LayoutRect,
+    pub local_outer_rect: Option<LayoutRect>
 }
 
 impl ClipSources {
     pub fn new(clips: Vec<ClipSource>) -> ClipSources {
         let (local_inner_rect, local_outer_rect) = Self::calculate_inner_and_outer_rects(&clips);
 
         let clips = clips
             .into_iter()
@@ -286,26 +286,26 @@ impl ClipSources {
             local_outer_rect,
         }
     }
 
     pub fn clips(&self) -> &[(ClipSource, GpuCacheHandle)] {
         &self.clips
     }
 
-    fn calculate_inner_and_outer_rects(clips: &Vec<ClipSource>) -> (LayerRect, Option<LayerRect>) {
+    fn calculate_inner_and_outer_rects(clips: &Vec<ClipSource>) -> (LayoutRect, Option<LayoutRect>) {
         if clips.is_empty() {
-            return (LayerRect::zero(), None);
+            return (LayoutRect::zero(), None);
         }
 
         // Depending on the complexity of the clip, we may either know the outer and/or inner
         // rect, or neither or these.  In the case of a clip-out, we currently set the mask bounds
         // to be unknown. This is conservative, but ensures correctness. In the future we can make
         // this a lot more clever with some proper region handling.
-        let mut local_outer = Some(LayerRect::max_rect());
+        let mut local_outer = Some(LayoutRect::max_rect());
         let mut local_inner = local_outer;
         let mut can_calculate_inner_rect = true;
         let mut can_calculate_outer_rect = false;
         for source in clips {
             match *source {
                 ClipSource::Image(ref mask) => {
                     if !mask.repeat {
                         can_calculate_outer_rect = true;
@@ -345,25 +345,25 @@ impl ClipSources {
                 ClipSource::LineDecoration(..) => {
                     can_calculate_inner_rect = false;
                     break;
                 }
             }
         }
 
         let outer = if can_calculate_outer_rect {
-            Some(local_outer.unwrap_or_else(LayerRect::zero))
+            Some(local_outer.unwrap_or_else(LayoutRect::zero))
         } else {
             None
         };
 
         let inner = if can_calculate_inner_rect {
-            local_inner.unwrap_or_else(LayerRect::zero)
+            local_inner.unwrap_or_else(LayoutRect::zero)
         } else {
-            LayerRect::zero()
+            LayoutRect::zero()
         };
 
         (inner, outer)
     }
 
     pub fn update(
         &mut self,
         gpu_cache: &mut GpuCache,
@@ -428,17 +428,17 @@ impl ClipSources {
                 }
                 ClipSource::BoxShadow(ref mut info) => {
                     // Quote from https://drafts.csswg.org/css-backgrounds-3/#shadow-blur
                     // "the image that would be generated by applying to the shadow a
                     // Gaussian blur with a standard deviation equal to half the blur radius."
                     let blur_radius_dp = (info.blur_radius * 0.5 * device_pixel_scale.0).round();
 
                     // Create the cache key for this box-shadow render task.
-                    let content_scale = LayerToWorldScale::new(1.0) * device_pixel_scale;
+                    let content_scale = LayoutToWorldScale::new(1.0) * device_pixel_scale;
                     let cache_size = to_cache_size(info.shadow_rect_alloc_size * content_scale);
                     let bs_cache_key = BoxShadowCacheKey {
                         blur_radius_dp: blur_radius_dp as i32,
                         clip_mode: info.clip_mode,
                         rect_size: (info.shadow_rect_alloc_size * content_scale).round().to_i32(),
                         br_top_left: (info.shadow_radius.top_left * content_scale).round().to_i32(),
                         br_top_right: (info.shadow_radius.top_right * content_scale).round().to_i32(),
                         br_bottom_right: (info.shadow_radius.bottom_right * content_scale).round().to_i32(),
@@ -459,17 +459,17 @@ impl ClipSources {
                 }
                 _ => {}
             }
         }
     }
 
     pub fn get_screen_bounds(
         &self,
-        transform: &LayerToWorldFastTransform,
+        transform: &LayoutToWorldFastTransform,
         device_pixel_scale: DevicePixelScale,
     ) -> (DeviceIntRect, Option<DeviceIntRect>) {
         // If this translation isn't axis aligned or has a perspective component, don't try to
         // calculate the inner rectangle. The rectangle that we produce would include potentially
         // clipped screen area.
         // TODO(mrobinson): We should eventually try to calculate an inner region or some inner
         // rectangle so that we can do screen inner rectangle optimizations for these kind of
         // cilps.
@@ -488,32 +488,32 @@ impl ClipSources {
         (screen_inner_rect, screen_outer_rect)
     }
 }
 
 /// Represents a local rect and a device space
 /// rectangles that are either outside or inside bounds.
 #[derive(Clone, Debug, PartialEq)]
 pub struct Geometry {
-    pub local_rect: LayerRect,
+    pub local_rect: LayoutRect,
     pub device_rect: DeviceIntRect,
 }
 
-impl From<LayerRect> for Geometry {
-    fn from(local_rect: LayerRect) -> Self {
+impl From<LayoutRect> for Geometry {
+    fn from(local_rect: LayoutRect) -> Self {
         Geometry {
             local_rect,
             device_rect: DeviceIntRect::zero(),
         }
     }
 }
 
 pub fn rounded_rectangle_contains_point(
     point: &LayoutPoint,
-    rect: &LayerRect,
+    rect: &LayoutRect,
     radii: &BorderRadius
 ) -> bool {
     if !rect.contains(point) {
         return false;
     }
 
     let top_left_center = rect.origin + radii.top_left.to_vector();
     if top_left_center.x > point.x && top_left_center.y > point.y &&
@@ -544,17 +544,17 @@ pub fn rounded_rectangle_contains_point(
     true
 }
 
 pub type ClipChainNodeRef = Option<Arc<ClipChainNode>>;
 
 #[derive(Debug, Clone)]
 pub struct ClipChainNode {
     pub work_item: ClipWorkItem,
-    pub local_clip_rect: LayerRect,
+    pub local_clip_rect: LayoutRect,
     pub screen_outer_rect: DeviceIntRect,
     pub screen_inner_rect: DeviceIntRect,
     pub prev: ClipChainNodeRef,
 }
 
 #[derive(Debug, Clone)]
 pub struct ClipChain {
     pub parent_index: Option<ClipChainIndex>,
--- a/gfx/webrender/src/clip_scroll_node.rs
+++ b/gfx/webrender/src/clip_scroll_node.rs
@@ -1,50 +1,50 @@
 /* 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::{DevicePixelScale, ExternalScrollId, LayerPixel, LayerPoint, LayerRect, LayerSize};
-use api::{LayerVector2D, LayoutTransform, LayoutVector2D, PipelineId, PropertyBinding};
+use api::{DevicePixelScale, ExternalScrollId, LayoutPixel, LayoutPoint, LayoutRect, LayoutSize};
+use api::{LayoutVector2D, LayoutTransform, PipelineId, PropertyBinding};
 use api::{ScrollClamping, ScrollLocation, ScrollSensitivity, StickyOffsetBounds};
 use api::WorldPoint;
 use clip::{ClipChain, ClipChainNode, ClipSourcesHandle, ClipStore, ClipWorkItem};
 use clip_scroll_tree::{ClipChainIndex, ClipScrollNodeIndex, CoordinateSystemId};
 use clip_scroll_tree::TransformUpdateState;
 use euclid::SideOffsets2D;
 use geometry::ray_intersects_rect;
 use gpu_cache::GpuCache;
 use gpu_types::{ClipScrollNodeIndex as GPUClipScrollNodeIndex, ClipScrollNodeData};
 use resource_cache::ResourceCache;
 use scene::SceneProperties;
-use util::{LayerToWorldFastTransform, LayerFastTransform, LayoutFastTransform};
+use util::{LayoutToWorldFastTransform, LayoutFastTransform};
 use util::{TransformedRectKind};
 
 #[derive(Debug)]
 pub struct StickyFrameInfo {
     pub margins: SideOffsets2D<Option<f32>>,
     pub vertical_offset_bounds: StickyOffsetBounds,
     pub horizontal_offset_bounds: StickyOffsetBounds,
     pub previously_applied_offset: LayoutVector2D,
-    pub current_offset: LayerVector2D,
+    pub current_offset: LayoutVector2D,
 }
 
 impl StickyFrameInfo {
     pub fn new(
         margins: SideOffsets2D<Option<f32>>,
         vertical_offset_bounds: StickyOffsetBounds,
         horizontal_offset_bounds: StickyOffsetBounds,
         previously_applied_offset: LayoutVector2D
     ) -> StickyFrameInfo {
         StickyFrameInfo {
             margins,
             vertical_offset_bounds,
             horizontal_offset_bounds,
             previously_applied_offset,
-            current_offset: LayerVector2D::zero(),
+            current_offset: LayoutVector2D::zero(),
         }
     }
 }
 
 #[derive(Debug)]
 pub enum NodeType {
     /// A reference frame establishes a new coordinate space in the tree.
     ReferenceFrame(ReferenceFrameInfo),
@@ -84,27 +84,27 @@ impl NodeType {
         }
     }
 }
 
 /// Contains information common among all types of ClipScrollTree nodes.
 #[derive(Debug)]
 pub struct ClipScrollNode {
     /// Viewing rectangle in the coordinate system of the parent reference frame.
-    pub local_viewport_rect: LayerRect,
+    pub local_viewport_rect: LayoutRect,
 
     /// The transformation for this viewport in world coordinates is the transformation for
     /// our parent reference frame, plus any accumulated scrolling offsets from nodes
     /// between our reference frame and this node. For reference frames, we also include
     /// whatever local transformation this reference frame provides. This can be combined
     /// with the local_viewport_rect to get its position in world space.
-    pub world_viewport_transform: LayerToWorldFastTransform,
+    pub world_viewport_transform: LayoutToWorldFastTransform,
 
     /// World transform for content transformed by this node.
-    pub world_content_transform: LayerToWorldFastTransform,
+    pub world_content_transform: LayoutToWorldFastTransform,
 
     /// Pipeline that this layer belongs to
     pub pipeline_id: PipelineId,
 
     /// Parent layer. If this is None, we are the root node.
     pub parent: Option<ClipScrollNodeIndex>,
 
     /// Child layers
@@ -119,93 +119,93 @@ pub struct ClipScrollNode {
     pub invertible: bool,
 
     /// The axis-aligned coordinate system id of this node.
     pub coordinate_system_id: CoordinateSystemId,
 
     /// The transformation from the coordinate system which established our compatible coordinate
     /// system (same coordinate system id) and us. This can change via scroll offsets and via new
     /// reference frame transforms.
-    pub coordinate_system_relative_transform: LayerFastTransform,
+    pub coordinate_system_relative_transform: LayoutFastTransform,
 
     /// A linear ID / index of this clip-scroll node. Used as a reference to
     /// pass to shaders, to allow them to fetch a given clip-scroll node.
     pub node_data_index: GPUClipScrollNodeIndex,
 }
 
 impl ClipScrollNode {
     pub fn new(
         pipeline_id: PipelineId,
         parent_index: Option<ClipScrollNodeIndex>,
-        rect: &LayerRect,
+        rect: &LayoutRect,
         node_type: NodeType
     ) -> Self {
         ClipScrollNode {
             local_viewport_rect: *rect,
-            world_viewport_transform: LayerToWorldFastTransform::identity(),
-            world_content_transform: LayerToWorldFastTransform::identity(),
+            world_viewport_transform: LayoutToWorldFastTransform::identity(),
+            world_content_transform: LayoutToWorldFastTransform::identity(),
             parent: parent_index,
             children: Vec::new(),
             pipeline_id,
-            node_type: node_type,
+            node_type,
             invertible: true,
             coordinate_system_id: CoordinateSystemId(0),
-            coordinate_system_relative_transform: LayerFastTransform::identity(),
+            coordinate_system_relative_transform: LayoutFastTransform::identity(),
             node_data_index: GPUClipScrollNodeIndex(0),
         }
     }
 
     pub fn empty() -> ClipScrollNode {
-        ClipScrollNode::new(PipelineId::dummy(), None, &LayerRect::zero(), NodeType::Empty)
+        ClipScrollNode::new(PipelineId::dummy(), None, &LayoutRect::zero(), NodeType::Empty)
     }
 
     pub fn new_scroll_frame(
         pipeline_id: PipelineId,
         parent_index: ClipScrollNodeIndex,
         external_id: Option<ExternalScrollId>,
-        frame_rect: &LayerRect,
-        content_size: &LayerSize,
+        frame_rect: &LayoutRect,
+        content_size: &LayoutSize,
         scroll_sensitivity: ScrollSensitivity,
     ) -> Self {
         let node_type = NodeType::ScrollFrame(ScrollFrameInfo::new(
             scroll_sensitivity,
-            LayerSize::new(
+            LayoutSize::new(
                 (content_size.width - frame_rect.size.width).max(0.0),
                 (content_size.height - frame_rect.size.height).max(0.0)
             ),
             external_id,
         ));
 
         Self::new(pipeline_id, Some(parent_index), frame_rect, node_type)
     }
 
     pub fn new_reference_frame(
         parent_index: Option<ClipScrollNodeIndex>,
-        frame_rect: &LayerRect,
+        frame_rect: &LayoutRect,
         source_transform: Option<PropertyBinding<LayoutTransform>>,
         source_perspective: Option<LayoutTransform>,
-        origin_in_parent_reference_frame: LayerVector2D,
+        origin_in_parent_reference_frame: LayoutVector2D,
         pipeline_id: PipelineId,
     ) -> Self {
         let identity = LayoutTransform::identity();
         let source_perspective = source_perspective.map_or_else(
             LayoutFastTransform::identity, |perspective| perspective.into());
         let info = ReferenceFrameInfo {
-            resolved_transform: LayerFastTransform::identity(),
+            resolved_transform: LayoutFastTransform::identity(),
             source_transform: source_transform.unwrap_or(PropertyBinding::Value(identity)),
-            source_perspective: source_perspective,
+            source_perspective,
             origin_in_parent_reference_frame,
             invertible: true,
         };
         Self::new(pipeline_id, parent_index, frame_rect, NodeType::ReferenceFrame(info))
     }
 
     pub fn new_sticky_frame(
         parent_index: ClipScrollNodeIndex,
-        frame_rect: LayerRect,
+        frame_rect: LayoutRect,
         sticky_frame_info: StickyFrameInfo,
         pipeline_id: PipelineId,
     ) -> Self {
         let node_type = NodeType::StickyFrame(sticky_frame_info);
         Self::new(pipeline_id, Some(parent_index), &frame_rect, node_type)
     }
 
 
@@ -217,24 +217,24 @@ impl ClipScrollNode {
         match self.node_type {
             NodeType::ScrollFrame(ref mut scrolling) => {
                 let scroll_sensitivity = scrolling.scroll_sensitivity;
                 let scrollable_size = scrolling.scrollable_size;
                 *scrolling = *old_scrolling_state;
                 scrolling.scroll_sensitivity = scroll_sensitivity;
                 scrolling.scrollable_size = scrollable_size;
             }
-            _ if old_scrolling_state.offset != LayerVector2D::zero() => {
+            _ if old_scrolling_state.offset != LayoutVector2D::zero() => {
                 warn!("Tried to scroll a non-scroll node.")
             }
             _ => {}
         }
     }
 
-    pub fn set_scroll_origin(&mut self, origin: &LayerPoint, clamp: ScrollClamping) -> bool {
+    pub fn set_scroll_origin(&mut self, origin: &LayoutPoint, clamp: ScrollClamping) -> bool {
         let scrollable_size = self.scrollable_size();
         let scrollable_width = scrollable_size.width;
         let scrollable_height = scrollable_size.height;
 
         let scrolling = match self.node_type {
             NodeType::ScrollFrame(ref mut scrolling) => scrolling,
             _ => {
                 warn!("Tried to scroll a non-scroll node.");
@@ -243,37 +243,37 @@ impl ClipScrollNode {
         };
 
         let new_offset = match clamp {
             ScrollClamping::ToContentBounds => {
                 if scrollable_height <= 0. && scrollable_width <= 0. {
                     return false;
                 }
 
-                let origin = LayerPoint::new(origin.x.max(0.0), origin.y.max(0.0));
-                LayerVector2D::new(
+                let origin = LayoutPoint::new(origin.x.max(0.0), origin.y.max(0.0));
+                LayoutVector2D::new(
                     (-origin.x).max(-scrollable_width).min(0.0).round(),
                     (-origin.y).max(-scrollable_height).min(0.0).round(),
                 )
             }
-            ScrollClamping::NoClamping => LayerPoint::zero() - *origin,
+            ScrollClamping::NoClamping => LayoutPoint::zero() - *origin,
         };
 
         if new_offset == scrolling.offset {
             return false;
         }
 
         scrolling.offset = new_offset;
         true
     }
 
     pub fn mark_uninvertible(&mut self) {
         self.invertible = false;
-        self.world_content_transform = LayerToWorldFastTransform::identity();
-        self.world_viewport_transform = LayerToWorldFastTransform::identity();
+        self.world_content_transform = LayoutToWorldFastTransform::identity();
+        self.world_viewport_transform = LayoutToWorldFastTransform::identity();
     }
 
     pub fn push_gpu_node_data(&mut self, node_data: &mut Vec<ClipScrollNodeData>) {
         if !self.invertible {
             node_data.push(ClipScrollNodeData::invalid());
             return;
         }
 
@@ -419,26 +419,26 @@ impl ClipScrollNode {
             &state.nearest_scrolling_ancestor_offset,
             &state.nearest_scrolling_ancestor_viewport,
         );
 
         // The transformation for the bounds of our viewport is the parent reference frame
         // transform, plus any accumulated scroll offset from our parents, plus any offset
         // provided by our own sticky positioning.
         let accumulated_offset = state.parent_accumulated_scroll_offset + sticky_offset;
-        self.world_viewport_transform = if accumulated_offset != LayerVector2D::zero() {
+        self.world_viewport_transform = if accumulated_offset != LayoutVector2D::zero() {
             state.parent_reference_frame_transform.pre_translate(&accumulated_offset)
         } else {
             state.parent_reference_frame_transform
         };
 
         // The transformation for any content inside of us is the viewport transformation, plus
         // whatever scrolling offset we supply as well.
         let scroll_offset = self.scroll_offset();
-        self.world_content_transform = if scroll_offset != LayerVector2D::zero() {
+        self.world_content_transform = if scroll_offset != LayoutVector2D::zero() {
             self.world_viewport_transform.pre_translate(&scroll_offset)
         } else {
             self.world_viewport_transform
         };
 
         let added_offset = state.parent_accumulated_scroll_offset + sticky_offset + scroll_offset;
         self.coordinate_system_relative_transform =
             state.coordinate_system_relative_transform.offset(added_offset);
@@ -460,75 +460,75 @@ impl ClipScrollNode {
         let info = match self.node_type {
             NodeType::ReferenceFrame(ref mut info) => info,
             _ => unreachable!("Called update_transform_for_reference_frame on non-ReferenceFrame"),
         };
 
         // Resolve the transform against any property bindings.
         let source_transform = scene_properties.resolve_layout_transform(&info.source_transform);
         info.resolved_transform =
-            LayerFastTransform::with_vector(info.origin_in_parent_reference_frame)
+            LayoutFastTransform::with_vector(info.origin_in_parent_reference_frame)
             .pre_mul(&source_transform.into())
             .pre_mul(&info.source_perspective);
 
         // The transformation for this viewport in world coordinates is the transformation for
         // our parent reference frame, plus any accumulated scrolling offsets from nodes
         // between our reference frame and this node. Finally, we also include
         // whatever local transformation this reference frame provides. This can be combined
         // with the local_viewport_rect to get its position in world space.
         let relative_transform = info.resolved_transform
             .post_translate(state.parent_accumulated_scroll_offset)
             .to_transform()
-            .with_destination::<LayerPixel>();
+            .with_destination::<LayoutPixel>();
         self.world_viewport_transform =
             state.parent_reference_frame_transform.pre_mul(&relative_transform.into());
         self.world_content_transform = self.world_viewport_transform;
 
         info.invertible = self.world_viewport_transform.is_invertible();
         if !info.invertible {
             return;
         }
 
         // Try to update our compatible coordinate system transform. If we cannot, start a new
         // incompatible coordinate system.
         match state.coordinate_system_relative_transform.update(relative_transform) {
             Some(offset) => self.coordinate_system_relative_transform = offset,
             None => {
-                self.coordinate_system_relative_transform = LayerFastTransform::identity();
+                self.coordinate_system_relative_transform = LayoutFastTransform::identity();
                 state.current_coordinate_system_id = *next_coordinate_system_id;
                 next_coordinate_system_id.advance();
             }
         }
 
         self.coordinate_system_id = state.current_coordinate_system_id;
     }
 
     fn calculate_sticky_offset(
         &self,
-        viewport_scroll_offset: &LayerVector2D,
-        viewport_rect: &LayerRect,
-    ) -> LayerVector2D {
+        viewport_scroll_offset: &LayoutVector2D,
+        viewport_rect: &LayoutRect,
+    ) -> LayoutVector2D {
         let info = match self.node_type {
             NodeType::StickyFrame(ref info) => info,
-            _ => return LayerVector2D::zero(),
+            _ => return LayoutVector2D::zero(),
         };
 
         if info.margins.top.is_none() && info.margins.bottom.is_none() &&
             info.margins.left.is_none() && info.margins.right.is_none() {
-            return LayerVector2D::zero();
+            return LayoutVector2D::zero();
         }
 
         // The viewport and margins of the item establishes the maximum amount that it can
         // be offset in order to keep it on screen. Since we care about the relationship
         // between the scrolled content and unscrolled viewport we adjust the viewport's
         // position by the scroll offset in order to work with their relative positions on the
         // page.
         let sticky_rect = self.local_viewport_rect.translate(viewport_scroll_offset);
 
-        let mut sticky_offset = LayerVector2D::zero();
+        let mut sticky_offset = LayoutVector2D::zero();
         if let Some(margin) = info.margins.top {
             let top_viewport_edge = viewport_rect.min_y() + margin;
             if sticky_rect.min_y() < top_viewport_edge {
                 // If the sticky rect is positioned above the top edge of the viewport (plus margin)
                 // we move it down so that it is fully inside the viewport.
                 sticky_offset.y = top_viewport_edge - sticky_rect.min_y();
             } else if info.previously_applied_offset.y > 0.0 &&
                 sticky_rect.min_y() > top_viewport_edge {
@@ -618,17 +618,17 @@ impl ClipScrollNode {
 
         // The transformation we are passing is the transformation of the parent
         // reference frame and the offset is the accumulated offset of all the nodes
         // between us and the parent reference frame. If we are a reference frame,
         // we need to reset both these values.
         match self.node_type {
             NodeType::ReferenceFrame(ref info) => {
                 state.parent_reference_frame_transform = self.world_viewport_transform;
-                state.parent_accumulated_scroll_offset = LayerVector2D::zero();
+                state.parent_accumulated_scroll_offset = LayoutVector2D::zero();
                 state.coordinate_system_relative_transform =
                     self.coordinate_system_relative_transform.clone();
                 let translation = -info.origin_in_parent_reference_frame;
                 state.nearest_scrolling_ancestor_viewport =
                     state.nearest_scrolling_ancestor_viewport
                        .translate(&translation);
             }
             NodeType::Clip{ .. } => { }
@@ -644,20 +644,20 @@ impl ClipScrollNode {
                 // only apply to contents inside the node.
                 state.parent_accumulated_scroll_offset =
                     info.current_offset + state.parent_accumulated_scroll_offset;
             }
             NodeType::Empty => unreachable!("Empty node remaining in ClipScrollTree."),
         }
     }
 
-    pub fn scrollable_size(&self) -> LayerSize {
+    pub fn scrollable_size(&self) -> LayoutSize {
         match self.node_type {
            NodeType:: ScrollFrame(state) => state.scrollable_size,
-            _ => LayerSize::zero(),
+            _ => LayoutSize::zero(),
         }
     }
 
 
     pub fn scroll(&mut self, scroll_location: ScrollLocation) -> bool {
         let scrolling = match self.node_type {
             NodeType::ScrollFrame(ref mut scrolling) => scrolling,
             _ => return false,
@@ -714,66 +714,66 @@ impl ClipScrollNode {
         };
 
         let z0 = -10000.0;
         let z1 = 10000.0;
 
         let p0 = inv.transform_point3d(&cursor.extend(z0));
         let p1 = inv.transform_point3d(&cursor.extend(z1));
 
-        if self.scrollable_size() == LayerSize::zero() {
+        if self.scrollable_size() == LayoutSize::zero() {
             return false;
         }
 
         ray_intersects_rect(
             p0.to_untyped(),
             p1.to_untyped(),
             self.local_viewport_rect.to_untyped(),
         )
     }
 
-    pub fn scroll_offset(&self) -> LayerVector2D {
+    pub fn scroll_offset(&self) -> LayoutVector2D {
         match self.node_type {
             NodeType::ScrollFrame(ref scrolling) => scrolling.offset,
-            _ => LayerVector2D::zero(),
+            _ => LayoutVector2D::zero(),
         }
     }
 
     pub fn matches_external_id(&self, external_id: ExternalScrollId) -> bool {
         match self.node_type {
             NodeType::ScrollFrame(info) if info.external_id == Some(external_id) => true,
             _ => false,
         }
     }
 }
 
 #[derive(Copy, Clone, Debug)]
 pub struct ScrollFrameInfo {
-    pub offset: LayerVector2D,
+    pub offset: LayoutVector2D,
     pub scroll_sensitivity: ScrollSensitivity,
 
     /// Amount that this ScrollFrame can scroll in both directions.
-    pub scrollable_size: LayerSize,
+    pub scrollable_size: LayoutSize,
 
     /// An external id to identify this scroll frame to API clients. This
     /// allows setting scroll positions via the API without relying on ClipsIds
     /// which may change between frames.
     pub external_id: Option<ExternalScrollId>,
 
 }
 
 /// Manages scrolling offset.
 impl ScrollFrameInfo {
     pub fn new(
         scroll_sensitivity: ScrollSensitivity,
-        scrollable_size: LayerSize,
+        scrollable_size: LayoutSize,
         external_id: Option<ExternalScrollId>,
     ) -> ScrollFrameInfo {
         ScrollFrameInfo {
-            offset: LayerVector2D::zero(),
+            offset: LayoutVector2D::zero(),
             scroll_sensitivity,
             scrollable_size,
             external_id,
         }
     }
 
     pub fn sensitive_to_input_events(&self) -> bool {
         match self.scroll_sensitivity {
@@ -783,25 +783,25 @@ impl ScrollFrameInfo {
     }
 }
 
 /// Contains information about reference frames.
 #[derive(Copy, Clone, Debug)]
 pub struct ReferenceFrameInfo {
     /// The transformation that establishes this reference frame, relative to the parent
     /// reference frame. The origin of the reference frame is included in the transformation.
-    pub resolved_transform: LayerFastTransform,
+    pub resolved_transform: LayoutFastTransform,
 
     /// The source transform and perspective matrices provided by the stacking context
     /// that forms this reference frame. We maintain the property binding information
     /// here so that we can resolve the animated transform and update the tree each
     /// frame.
     pub source_transform: PropertyBinding<LayoutTransform>,
     pub source_perspective: LayoutFastTransform,
 
     /// The original, not including the transform and relative to the parent reference frame,
     /// origin of this reference frame. This is already rolled into the `transform' property, but
     /// we also store it here to properly transform the viewport for sticky positioning.
-    pub origin_in_parent_reference_frame: LayerVector2D,
+    pub origin_in_parent_reference_frame: LayoutVector2D,
 
     /// True if the resolved transform is invertible.
     pub invertible: bool,
 }
--- a/gfx/webrender/src/clip_scroll_tree.rs
+++ b/gfx/webrender/src/clip_scroll_tree.rs
@@ -1,24 +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::{DeviceIntRect, DevicePixelScale, ExternalScrollId, LayerPoint, LayerRect, LayerVector2D};
+use api::{DeviceIntRect, DevicePixelScale, ExternalScrollId, LayoutPoint, LayoutRect, LayoutVector2D};
 use api::{PipelineId, ScrollClamping, ScrollLocation, ScrollNodeState};
 use api::WorldPoint;
 use clip::{ClipChain, ClipSourcesHandle, ClipStore};
 use clip_scroll_node::{ClipScrollNode, NodeType, ScrollFrameInfo, StickyFrameInfo};
 use gpu_cache::GpuCache;
 use gpu_types::{ClipScrollNodeIndex as GPUClipScrollNodeIndex, ClipScrollNodeData};
 use internal_types::{FastHashMap, FastHashSet};
 use print_tree::{PrintTree, PrintTreePrinter};
 use resource_cache::ResourceCache;
 use scene::SceneProperties;
-use util::{LayerFastTransform, LayerToWorldFastTransform};
+use util::{LayoutFastTransform, LayoutToWorldFastTransform};
 
 pub type ScrollStates = FastHashMap<ExternalScrollId, ScrollFrameInfo>;
 
 /// An id that identifies coordinate systems in the ClipScrollTree. Each
 /// coordinate system has an id and those ids will be shared when the coordinates
 /// system are the same or are in the same axis-aligned space. This allows
 /// for optimizing mask generation.
 #[derive(Debug, Copy, Clone, PartialEq)]
@@ -63,46 +63,46 @@ pub struct ClipScrollTree {
     /// encountered during display list flattening. ClipChains are expected to never be
     /// the children of ClipChains later in the list.
     pub clip_chains_descriptors: Vec<ClipChainDescriptor>,
 
     /// A vector of all ClipChains in this ClipScrollTree including those from
     /// ClipChainDescriptors and also those defined by the clipping node hierarchy.
     pub clip_chains: Vec<ClipChain>,
 
-    pub pending_scroll_offsets: FastHashMap<ExternalScrollId, (LayerPoint, ScrollClamping)>,
+    pub pending_scroll_offsets: FastHashMap<ExternalScrollId, (LayoutPoint, ScrollClamping)>,
 
     /// The current frame id, used for giving a unique id to all new dynamically
     /// added frames and clips. The ClipScrollTree increments this by one every
     /// time a new dynamic frame is created.
     current_new_node_item: u64,
 
     /// A set of pipelines which should be discarded the next time this
     /// tree is drained.
     pub pipelines_to_discard: FastHashSet<PipelineId>,
 }
 
 #[derive(Clone)]
 pub struct TransformUpdateState {
-    pub parent_reference_frame_transform: LayerToWorldFastTransform,
-    pub parent_accumulated_scroll_offset: LayerVector2D,
-    pub nearest_scrolling_ancestor_offset: LayerVector2D,
-    pub nearest_scrolling_ancestor_viewport: LayerRect,
+    pub parent_reference_frame_transform: LayoutToWorldFastTransform,
+    pub parent_accumulated_scroll_offset: LayoutVector2D,
+    pub nearest_scrolling_ancestor_offset: LayoutVector2D,
+    pub nearest_scrolling_ancestor_viewport: LayoutRect,
 
     /// The index of the current parent's clip chain.
     pub parent_clip_chain_index: ClipChainIndex,
 
     /// An id for keeping track of the axis-aligned space of this node. This is used in
     /// order to to track what kinds of clip optimizations can be done for a particular
     /// display list item, since optimizations can usually only be done among
     /// coordinate systems which are relatively axis aligned.
     pub current_coordinate_system_id: CoordinateSystemId,
 
     /// Transform from the coordinate system that started this compatible coordinate system.
-    pub coordinate_system_relative_transform: LayerFastTransform,
+    pub coordinate_system_relative_transform: LayoutFastTransform,
 
     /// True if this node is transformed by an invertible transform.  If not, display items
     /// transformed by this node will not be displayed and display items not transformed by this
     /// node will not be clipped by clips that are transformed by this node.
     pub invertible: bool,
 }
 
 impl ClipScrollTree {
@@ -195,17 +195,17 @@ impl ClipScrollTree {
         self.pipelines_to_discard.clear();
         self.clip_chains = vec![ClipChain::empty(&DeviceIntRect::zero())];
         self.clip_chains_descriptors.clear();
         scroll_states
     }
 
     pub fn scroll_node(
         &mut self,
-        origin: LayerPoint,
+        origin: LayoutPoint,
         id: ExternalScrollId,
         clamp: ScrollClamping
     ) -> bool {
         for node in &mut self.nodes {
             if node.matches_external_id(id) {
                 return node.set_scroll_origin(&origin, clamp);
             }
         }
@@ -241,23 +241,23 @@ impl ClipScrollTree {
         if self.nodes.is_empty() {
             return;
         }
 
         self.clip_chains[0] = ClipChain::empty(screen_rect);
 
         let root_reference_frame_index = self.root_reference_frame_index();
         let mut state = TransformUpdateState {
-            parent_reference_frame_transform: LayerVector2D::new(pan.x, pan.y).into(),
-            parent_accumulated_scroll_offset: LayerVector2D::zero(),
-            nearest_scrolling_ancestor_offset: LayerVector2D::zero(),
-            nearest_scrolling_ancestor_viewport: LayerRect::zero(),
+            parent_reference_frame_transform: LayoutVector2D::new(pan.x, pan.y).into(),
+            parent_accumulated_scroll_offset: LayoutVector2D::zero(),
+            nearest_scrolling_ancestor_offset: LayoutVector2D::zero(),
+            nearest_scrolling_ancestor_viewport: LayoutRect::zero(),
             parent_clip_chain_index: ClipChainIndex(0),
             current_coordinate_system_id: CoordinateSystemId::root(),
-            coordinate_system_relative_transform: LayerFastTransform::identity(),
+            coordinate_system_relative_transform: LayoutFastTransform::identity(),
             invertible: true,
         };
         let mut next_coordinate_system_id = state.current_coordinate_system_id.next();
         self.update_node(
             root_reference_frame_index,
             &mut state,
             &mut next_coordinate_system_id,
             device_pixel_scale,
@@ -375,31 +375,31 @@ impl ClipScrollTree {
         }
     }
 
     pub fn add_clip_node(
         &mut self,
         index: ClipScrollNodeIndex,
         parent_index: ClipScrollNodeIndex,
         handle: ClipSourcesHandle,
-        clip_rect: LayerRect,
+        clip_rect: LayoutRect,
         pipeline_id: PipelineId,
     )  -> ClipChainIndex {
         let clip_chain_index = self.allocate_clip_chain();
         let node_type = NodeType::Clip { handle, clip_chain_index, clip_chain_node: None };
         let node = ClipScrollNode::new(pipeline_id, Some(parent_index), &clip_rect, node_type);
         self.add_node(node, index);
         clip_chain_index
     }
 
     pub fn add_sticky_frame(
         &mut self,
         index: ClipScrollNodeIndex,
         parent_index: ClipScrollNodeIndex,
-        frame_rect: LayerRect,
+        frame_rect: LayoutRect,
         sticky_frame_info: StickyFrameInfo,
         pipeline_id: PipelineId,
     ) {
         let node = ClipScrollNode::new_sticky_frame(
             parent_index,
             frame_rect,
             sticky_frame_info,
             pipeline_id,
--- a/gfx/webrender/src/display_list_flattener.rs
+++ b/gfx/webrender/src/display_list_flattener.rs
@@ -1,20 +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::{AlphaType, BorderDetails, BorderDisplayItem, BuiltDisplayListIter, ClipAndScrollInfo};
 use api::{ClipId, ColorF, ComplexClipRegion, DeviceIntPoint, DeviceIntRect, DeviceIntSize};
 use api::{DevicePixelScale, DeviceUintRect, DisplayItemRef, Epoch, ExtendMode, ExternalScrollId};
-use api::{FilterOp, FontInstanceKey, FontRenderMode, GlyphInstance, GlyphOptions, GlyphRasterSpace, GradientStop};
-use api::{IframeDisplayItem, ImageKey, ImageRendering, ItemRange, LayerPoint, LayerPrimitiveInfo};
-use api::{LayerRect, LayerSize, LayerVector2D, LayoutRect, LayoutSize, LayoutTransform};
-use api::{LayoutVector2D, LineOrientation, LineStyle, LocalClip, PipelineId, PropertyBinding};
+use api::{FilterOp, FontInstanceKey, GlyphInstance, GlyphOptions, GlyphRasterSpace, GradientStop};
+use api::{IframeDisplayItem, ImageKey, ImageRendering, ItemRange, LayoutPoint, LayoutPrimitiveInfo};
+use api::{LayoutRect, LayoutVector2D, LayoutSize, LayoutTransform};
+use api::{LineOrientation, LineStyle, LocalClip, PipelineId, PropertyBinding};
 use api::{RepeatMode, ScrollFrameDisplayItem, ScrollPolicy, ScrollSensitivity, Shadow};
 use api::{SpecificDisplayItem, StackingContext, StickyFrameDisplayItem, TexelRect, TileOffset};
 use api::{TransformStyle, YuvColorSpace, YuvData};
 use app_units::Au;
 use border::ImageBorderSegment;
 use clip::{ClipRegion, ClipSource, ClipSources, ClipStore};
 use clip_scroll_node::{ClipScrollNode, NodeType, StickyFrameInfo};
 use clip_scroll_tree::{ClipChainIndex, ClipScrollNodeIndex, ClipScrollTree};
@@ -23,17 +23,17 @@ use frame_builder::{FrameBuilder, FrameB
 use glyph_rasterizer::FontInstance;
 use hit_test::{HitTestingItem, HitTestingRun};
 use image::{decompose_image, TiledImageInfo};
 use internal_types::{FastHashMap, FastHashSet};
 use picture::PictureCompositeMode;
 use prim_store::{BrushKind, BrushPrimitive, BrushSegmentDescriptor, CachedGradient};
 use prim_store::{CachedGradientIndex, ImageCacheKey, ImagePrimitiveCpu, ImageSource};
 use prim_store::{PictureIndex, PrimitiveContainer, PrimitiveIndex, PrimitiveStore};
-use prim_store::{ScrollNodeAndClipChain, TextRunPrimitiveCpu};
+use prim_store::{OpacityBinding, ScrollNodeAndClipChain, TextRunPrimitiveCpu};
 use render_backend::{DocumentView};
 use resource_cache::{FontInstanceMap, ImageRequest, TiledImageMap};
 use scene::{Scene, ScenePipeline, StackingContextHelpers};
 use scene_builder::{BuiltScene, SceneRequest};
 use std::{f32, mem, usize};
 use tiling::{CompositeOps, ScrollbarPrimitive};
 use util::{MaxRect, RectHelpers, recycle_vec};
 
@@ -337,50 +337,50 @@ impl<'a> DisplayListFlattener<'a> {
             GlyphRasterSpace::Screen,
         );
 
         // For the root pipeline, there's no need to add a full screen rectangle
         // here, as it's handled by the framebuffer clear.
         if self.scene.root_pipeline_id != Some(pipeline_id) {
             if let Some(pipeline) = self.scene.pipelines.get(&pipeline_id) {
                 if let Some(bg_color) = pipeline.background_color {
-                    let root_bounds = LayerRect::new(LayerPoint::zero(), *frame_size);
-                    let info = LayerPrimitiveInfo::new(root_bounds);
+                    let root_bounds = LayoutRect::new(LayoutPoint::zero(), *frame_size);
+                    let info = LayoutPrimitiveInfo::new(root_bounds);
                     self.add_solid_rectangle(
                         reference_frame_info,
                         &info,
                         bg_color,
                         None,
                         Vec::new(),
                     );
                 }
             }
         }
 
-        self.flatten_items(&mut pipeline.display_list.iter(), pipeline_id, LayerVector2D::zero());
+        self.flatten_items(&mut pipeline.display_list.iter(), pipeline_id, LayoutVector2D::zero());
 
         if self.config.enable_scrollbars {
-            let scrollbar_rect = LayerRect::new(LayerPoint::zero(), LayerSize::new(10.0, 70.0));
-            let container_rect = LayerRect::new(LayerPoint::zero(), *frame_size);
+            let scrollbar_rect = LayoutRect::new(LayoutPoint::zero(), LayoutSize::new(10.0, 70.0));
+            let container_rect = LayoutRect::new(LayoutPoint::zero(), *frame_size);
             self.add_scroll_bar(
                 reference_frame_info,
-                &LayerPrimitiveInfo::new(scrollbar_rect),
+                &LayoutPrimitiveInfo::new(scrollbar_rect),
                 DEFAULT_SCROLLBAR_COLOR,
                 ScrollbarInfo(scroll_frame_info.scroll_node_id, container_rect),
             );
         }
 
         self.pop_stacking_context();
     }
 
     fn flatten_items(
         &mut self,
         traversal: &mut BuiltDisplayListIter<'a>,
         pipeline_id: PipelineId,
-        reference_frame_relative_offset: LayerVector2D,
+        reference_frame_relative_offset: LayoutVector2D,
     ) {
         loop {
             let subtraversal = {
                 let item = match traversal.next() {
                     Some(item) => item,
                     None => break,
                 };
 
@@ -404,17 +404,17 @@ impl<'a> DisplayListFlattener<'a> {
     }
 
     fn flatten_sticky_frame(
         &mut self,
         item: &DisplayItemRef,
         info: &StickyFrameDisplayItem,
         clip_and_scroll: &ScrollNodeAndClipChain,
         parent_id: &ClipId,
-        reference_frame_relative_offset: &LayerVector2D,
+        reference_frame_relative_offset: &LayoutVector2D,
     ) {
         let frame_rect = item.rect().translate(reference_frame_relative_offset);
         let sticky_frame_info = StickyFrameInfo::new(
             info.margins,
             info.vertical_offset_bounds,
             info.horizontal_offset_bounds,
             info.previously_applied_offset,
         );
@@ -431,17 +431,17 @@ impl<'a> DisplayListFlattener<'a> {
     }
 
     fn flatten_scroll_frame(
         &mut self,
         item: &DisplayItemRef,
         info: &ScrollFrameDisplayItem,
         pipeline_id: PipelineId,
         clip_and_scroll_ids: &ClipAndScrollInfo,
-        reference_frame_relative_offset: &LayerVector2D,
+        reference_frame_relative_offset: &LayoutVector2D,
     ) {
         let complex_clips = self.get_complex_clips(pipeline_id, item.complex_clip().0);
         let clip_region = ClipRegion::create_for_clip_node(
             *item.clip_rect(),
             complex_clips,
             info.image_mask,
             reference_frame_relative_offset,
         );
@@ -470,17 +470,17 @@ impl<'a> DisplayListFlattener<'a> {
     fn flatten_stacking_context(
         &mut self,
         traversal: &mut BuiltDisplayListIter<'a>,
         pipeline_id: PipelineId,
         item: &DisplayItemRef,
         stacking_context: &StackingContext,
         unreplaced_scroll_id: ClipId,
         mut scroll_node_id: ClipId,
-        mut reference_frame_relative_offset: LayerVector2D,
+        mut reference_frame_relative_offset: LayoutVector2D,
         is_backface_visible: bool,
     ) {
         // Avoid doing unnecessary work for empty stacking contexts.
         if traversal.current_stacking_context_empty() {
             traversal.skip_current_stacking_context();
             return;
         }
 
@@ -510,28 +510,28 @@ impl<'a> DisplayListFlattener<'a> {
         // reference frame id. This means this stacking context establishes a new reference frame.
         // Descendant fixed position content will be positioned relative to us.
         if let Some(reference_frame_id) = stacking_context.reference_frame_id {
             debug_assert!(
                 stacking_context.transform.is_some() ||
                 stacking_context.perspective.is_some()
             );
 
-            let reference_frame_bounds = LayerRect::new(LayerPoint::zero(), bounds.size);
+            let reference_frame_bounds = LayoutRect::new(LayoutPoint::zero(), bounds.size);
             self.push_reference_frame(
                 reference_frame_id,
                 Some(scroll_node_id),
                 pipeline_id,
                 &reference_frame_bounds,
                 stacking_context.transform,
                 stacking_context.perspective,
                 reference_frame_relative_offset,
             );
             self.replacements.push((unreplaced_scroll_id, reference_frame_id));
-            reference_frame_relative_offset = LayerVector2D::zero();
+            reference_frame_relative_offset = LayoutVector2D::zero();
         }
 
         // We apply the replacements one more time in case we need to set it to a replacement
         // that we just pushed above.
         let final_scroll_node = self.apply_scroll_frame_id_replacement(unreplaced_scroll_id);
         self.push_stacking_context(
             pipeline_id,
             composition_operations,
@@ -561,17 +561,17 @@ impl<'a> DisplayListFlattener<'a> {
         self.pop_stacking_context();
     }
 
     fn flatten_iframe(
         &mut self,
         item: &DisplayItemRef,
         info: &IframeDisplayItem,
         clip_and_scroll_ids: &ClipAndScrollInfo,
-        reference_frame_relative_offset: &LayerVector2D,
+        reference_frame_relative_offset: &LayoutVector2D,
     ) {
         let iframe_pipeline_id = info.pipeline_id;
         let pipeline = match self.scene.pipelines.get(&iframe_pipeline_id) {
             Some(pipeline) => pipeline,
             None => {
                 //TODO: assert/debug_assert?
                 error!("Unknown pipeline used for iframe {:?}", info);
                 return
@@ -588,17 +588,17 @@ impl<'a> DisplayListFlattener<'a> {
                 reference_frame_relative_offset
             ),
         );
 
         let epoch = self.scene.pipeline_epochs[&iframe_pipeline_id];
         self.pipeline_epochs.push((iframe_pipeline_id, epoch));
 
         let bounds = item.rect();
-        let iframe_rect = LayerRect::new(LayerPoint::zero(), bounds.size);
+        let iframe_rect = LayoutRect::new(LayoutPoint::zero(), bounds.size);
         let origin = *reference_frame_relative_offset + bounds.origin.to_vector();
         self.push_reference_frame(
             ClipId::root_reference_frame(iframe_pipeline_id),
             Some(info.clip_id),
             iframe_pipeline_id,
             &iframe_rect,
             None,
             None,
@@ -619,25 +619,25 @@ impl<'a> DisplayListFlattener<'a> {
 
         self.pop_reference_frame();
     }
 
     fn flatten_item<'b>(
         &'b mut self,
         item: DisplayItemRef<'a, 'b>,
         pipeline_id: PipelineId,
-        reference_frame_relative_offset: LayerVector2D,
+        reference_frame_relative_offset: LayoutVector2D,
     ) -> Option<BuiltDisplayListIter<'a>> {
         let mut clip_and_scroll_ids = item.clip_and_scroll();
         let unreplaced_scroll_id = clip_and_scroll_ids.scroll_node_id;
         clip_and_scroll_ids.scroll_node_id =
             self.apply_scroll_frame_id_replacement(clip_and_scroll_ids.scroll_node_id);
         let clip_and_scroll = self.id_to_index_mapper.map_clip_and_scroll(&clip_and_scroll_ids);
 
-        let prim_info = item.get_layer_primitive_info(&reference_frame_relative_offset);
+        let prim_info = item.get_layout_primitive_info(&reference_frame_relative_offset);
         match *item.item() {
             SpecificDisplayItem::Image(ref info) => {
                 match self.tiled_image_map.get(&info.image_key).cloned() {
                     Some(tiling) => {
                         // The image resource is tiled. We have to generate an image primitive
                         // for each tile.
                         decompose_image(
                             &TiledImageInfo {
@@ -843,33 +843,33 @@ impl<'a> DisplayListFlattener<'a> {
             // Do nothing; these are dummy items for the display list parser
             SpecificDisplayItem::SetGradientStops => {}
 
             SpecificDisplayItem::PopStackingContext => {
                 unreachable!("Should have returned in parent method.")
             }
             SpecificDisplayItem::PushShadow(shadow) => {
                 let mut prim_info = prim_info.clone();
-                prim_info.rect = LayerRect::zero();
+                prim_info.rect = LayoutRect::zero();
                 self
                     .push_shadow(shadow, clip_and_scroll, &prim_info);
             }
             SpecificDisplayItem::PopAllShadows => {
                 self.pop_all_shadows();
             }
         }
         None
     }
 
     /// Create a primitive and add it to the prim store. This method doesn't
     /// add the primitive to the draw list, so can be used for creating
     /// sub-primitives.
     pub fn create_primitive(
         &mut self,
-        info: &LayerPrimitiveInfo,
+        info: &LayoutPrimitiveInfo,
         clip_sources: Vec<ClipSource>,
         container: PrimitiveContainer,
     ) -> PrimitiveIndex {
         let stacking_context = self.sc_stack.last().expect("bug: no stacking context!");
 
         let clip_sources = if clip_sources.is_empty() {
             None
         } else {
@@ -883,17 +883,17 @@ impl<'a> DisplayListFlattener<'a> {
             clip_sources,
             info.tag,
             container,
         )
     }
 
     pub fn add_primitive_to_hit_testing_list(
         &mut self,
-        info: &LayerPrimitiveInfo,
+        info: &LayoutPrimitiveInfo,
         clip_and_scroll: ScrollNodeAndClipChain
     ) {
         let tag = match info.tag {
             Some(tag) => tag,
             None => return,
         };
 
         let new_item = HitTestingItem::new(tag, info);
@@ -921,17 +921,17 @@ impl<'a> DisplayListFlattener<'a> {
         pic.add_primitive(prim_index, clip_and_scroll);
     }
 
     /// Convenience interface that creates a primitive entry and adds it
     /// to the draw list.
     pub fn add_primitive(
         &mut self,
         clip_and_scroll: ScrollNodeAndClipChain,
-        info: &LayerPrimitiveInfo,
+        info: &LayoutPrimitiveInfo,
         clip_sources: Vec<ClipSource>,
         container: PrimitiveContainer,
     ) {
         if !self.shadow_stack.is_empty() {
             // TODO(gw): Restructure this so we don't need to move the shadow
             //           stack out (borrowck due to create_primitive below).
             let shadow_stack = mem::replace(&mut self.shadow_stack, Vec::new());
             for &(ref shadow, shadow_pic_index) in &shadow_stack {
@@ -992,17 +992,17 @@ impl<'a> DisplayListFlattener<'a> {
         let current_reference_frame_index = self.current_reference_frame_index();
 
         // An arbitrary large clip rect. For now, we don't
         // specify a clip specific to the stacking context.
         // However, now that they are represented as Picture
         // primitives, we can apply any kind of clip mask
         // to them, as for a normal primitive. This is needed
         // to correctly handle some CSS cases (see #1957).
-        let max_clip = LayerRect::max_rect();
+        let max_clip = LayoutRect::max_rect();
 
         // If there is no root picture, create one for the main framebuffer.
         if self.sc_stack.is_empty() {
             // Should be no pictures at all if the stack is empty...
             debug_assert!(self.prim_store.pictures.is_empty());
             debug_assert_eq!(transform_style, TransformStyle::Flat);
 
             // This picture stores primitive runs for items on the
@@ -1070,17 +1070,17 @@ impl<'a> DisplayListFlattener<'a> {
                 current_reference_frame_index,
                 None,
                 true,
             );
 
             let prim = BrushPrimitive::new_picture(container_index);
 
             let prim_index = self.prim_store.add_primitive(
-                &LayerRect::zero(),
+                &LayoutRect::zero(),
                 &max_clip,
                 is_backface_visible,
                 None,
                 None,
                 PrimitiveContainer::Brush(prim),
             );
 
             let parent_pic_index = *self.picture_stack.last().unwrap();
@@ -1119,17 +1119,17 @@ impl<'a> DisplayListFlattener<'a> {
                 pipeline_id,
                 current_reference_frame_index,
                 None,
                 true,
             );
 
             let src_prim = BrushPrimitive::new_picture(src_pic_index);
             let src_prim_index = self.prim_store.add_primitive(
-                &LayerRect::zero(),
+                &LayoutRect::zero(),
                 &max_clip,
                 is_backface_visible,
                 None,
                 None,
                 PrimitiveContainer::Brush(src_prim),
             );
 
             let parent_pic = &mut self.prim_store.pictures[parent_pic_index.0];
@@ -1149,17 +1149,17 @@ impl<'a> DisplayListFlattener<'a> {
                 current_reference_frame_index,
                 None,
                 true,
             );
 
             let src_prim = BrushPrimitive::new_picture(src_pic_index);
 
             let src_prim_index = self.prim_store.add_primitive(
-                &LayerRect::zero(),
+                &LayoutRect::zero(),
                 &max_clip,
                 is_backface_visible,
                 None,
                 None,
                 PrimitiveContainer::Brush(src_prim),
             );
 
             let parent_pic = &mut self.prim_store.pictures[parent_pic_index.0];
@@ -1206,43 +1206,36 @@ impl<'a> DisplayListFlattener<'a> {
             true,
         );
 
         // Create a brush primitive that draws this picture.
         let sc_prim = BrushPrimitive::new_picture(pic_index);
 
         // Add the brush to the parent picture.
         let sc_prim_index = self.prim_store.add_primitive(
-            &LayerRect::zero(),
+            &LayoutRect::zero(),
             &max_clip,
             is_backface_visible,
             None,
             None,
             PrimitiveContainer::Brush(sc_prim),
         );
 
         let parent_pic = &mut self.prim_store.pictures[parent_pic_index.0];
         parent_pic.add_primitive(sc_prim_index, clip_and_scroll);
 
         // Add this as the top-most picture for primitives to be added to.
         self.picture_stack.push(pic_index);
 
-        // TODO(gw): This is super conservative. We can expand on this a lot
-        //           once all the picture code is in place and landed.
-        let allow_subpixel_aa = composite_ops.count() == 0 &&
-                                transform_style == TransformStyle::Flat &&
-                                composite_mode.is_none();
-
         // Push the SC onto the stack, so we know how to handle things in
         // pop_stacking_context.
         let sc = FlattenedStackingContext {
             composite_ops,
             is_backface_visible,
             pipeline_id,
-            allow_subpixel_aa,
             transform_style,
             rendering_context_3d_pic_index,
             glyph_raster_space,
         };
 
         self.sc_stack.push(sc);
     }
 
@@ -1256,17 +1249,21 @@ impl<'a> DisplayListFlattener<'a> {
         pop_count += sc.composite_ops.count();
 
         // Remove the 3d context container if created
         if sc.rendering_context_3d_pic_index.is_some() {
             pop_count += 1;
         }
 
         for _ in 0 .. pop_count {
-            self.picture_stack.pop().expect("bug: mismatched picture stack");
+            let pic_index = self
+                .picture_stack
+                .pop()
+                .expect("bug: mismatched picture stack");
+            self.prim_store.optimize_picture_if_possible(pic_index);
         }
 
         // By the time the stacking context stack is empty, we should
         // also have cleared the picture stack.
         if self.sc_stack.is_empty() {
             self.picture_stack.pop().expect("bug: picture stack invalid");
             debug_assert!(self.picture_stack.is_empty());
         }
@@ -1277,20 +1274,20 @@ impl<'a> DisplayListFlattener<'a> {
         );
     }
 
     pub fn push_reference_frame(
         &mut self,
         reference_frame_id: ClipId,
         parent_id: Option<ClipId>,
         pipeline_id: PipelineId,
-        rect: &LayerRect,
+        rect: &LayoutRect,
         source_transform: Option<PropertyBinding<LayoutTransform>>,
         source_perspective: Option<LayoutTransform>,
-        origin_in_parent_reference_frame: LayerVector2D,
+        origin_in_parent_reference_frame: LayoutVector2D,
     ) -> ClipScrollNodeIndex {
         let index = self.id_to_index_mapper.get_node_index(reference_frame_id);
         let node = ClipScrollNode::new_reference_frame(
             parent_id.map(|id| self.id_to_index_mapper.get_node_index(id)),
             rect,
             source_transform,
             source_perspective,
             origin_in_parent_reference_frame,
@@ -1320,36 +1317,36 @@ impl<'a> DisplayListFlattener<'a> {
         inner_rect: DeviceUintRect,
         device_pixel_scale: DevicePixelScale,
     ) {
         let viewport_offset = (inner_rect.origin.to_vector().to_f32() / device_pixel_scale).round();
         let root_id = self.clip_scroll_tree.root_reference_frame_index();
         let root_node = &mut self.clip_scroll_tree.nodes[root_id.0];
         if let NodeType::ReferenceFrame(ref mut info) = root_node.node_type {
             info.resolved_transform =
-                LayerVector2D::new(viewport_offset.x, viewport_offset.y).into();
+                LayoutVector2D::new(viewport_offset.x, viewport_offset.y).into();
         }
     }
 
     pub fn push_root(
         &mut self,
         pipeline_id: PipelineId,
-        viewport_size: &LayerSize,
-        content_size: &LayerSize,
+        viewport_size: &LayoutSize,
+        content_size: &LayoutSize,
     ) {
-        let viewport_rect = LayerRect::new(LayerPoint::zero(), *viewport_size);
+        let viewport_rect = LayoutRect::new(LayoutPoint::zero(), *viewport_size);
 
         self.push_reference_frame(
             ClipId::root_reference_frame(pipeline_id),
             None,
             pipeline_id,
             &viewport_rect,
             None,
             None,
-            LayerVector2D::zero(),
+            LayoutVector2D::zero(),
         );
 
         self.add_scroll_frame(
             ClipId::root_scroll_node(pipeline_id),
             ClipId::root_reference_frame(pipeline_id),
             Some(ExternalScrollId(0, pipeline_id)),
             pipeline_id,
             &viewport_rect,
@@ -1381,18 +1378,18 @@ impl<'a> DisplayListFlattener<'a> {
     }
 
     pub fn add_scroll_frame(
         &mut self,
         new_node_id: ClipId,
         parent_id: ClipId,
         external_id: Option<ExternalScrollId>,
         pipeline_id: PipelineId,
-        frame_rect: &LayerRect,
-        content_size: &LayerSize,
+        frame_rect: &LayoutRect,
+        content_size: &LayoutSize,
         scroll_sensitivity: ScrollSensitivity,
     ) -> ClipScrollNodeIndex {
         let node_index = self.id_to_index_mapper.get_node_index(new_node_id);
         let node = ClipScrollNode::new_scroll_frame(
             pipeline_id,
             self.id_to_index_mapper.get_node_index(parent_id),
             external_id,
             frame_rect,
@@ -1408,21 +1405,21 @@ impl<'a> DisplayListFlattener<'a> {
     pub fn pop_reference_frame(&mut self) {
         self.reference_frame_stack.pop();
     }
 
     pub fn push_shadow(
         &mut self,
         shadow: Shadow,
         clip_and_scroll: ScrollNodeAndClipChain,
-        info: &LayerPrimitiveInfo,
+        info: &LayoutPrimitiveInfo,
     ) {
         let pipeline_id = self.sc_stack.last().unwrap().pipeline_id;
         let current_reference_frame_index = self.current_reference_frame_index();
-        let max_clip = LayerRect::max_rect();
+        let max_clip = LayoutRect::max_rect();
 
         // Quote from https://drafts.csswg.org/css-backgrounds-3/#shadow-blur
         // "the image that would be generated by applying to the shadow a
         // Gaussian blur with a standard deviation equal to half the blur radius."
         let std_deviation = shadow.blur_radius * 0.5;
 
         // If the shadow has no blur, any elements will get directly rendered
         // into the parent picture surface, instead of allocating and drawing
@@ -1441,17 +1438,17 @@ impl<'a> DisplayListFlattener<'a> {
             current_reference_frame_index,
             None,
             apply_local_clip_rect,
         );
 
         // Create the primitive to draw the shadow picture into the scene.
         let shadow_prim = BrushPrimitive::new_picture(shadow_pic_index);
         let shadow_prim_index = self.prim_store.add_primitive(
-            &LayerRect::zero(),
+            &LayoutRect::zero(),
             &max_clip,
             info.is_backface_visible,
             None,
             None,
             PrimitiveContainer::Brush(shadow_prim),
         );
 
         // Add the shadow primitive. This must be done before pushing this
@@ -1463,47 +1460,45 @@ impl<'a> DisplayListFlattener<'a> {
     pub fn pop_all_shadows(&mut self) {
         assert!(self.shadow_stack.len() > 0, "popped shadows, but none were present");
         self.shadow_stack.clear();
     }
 
     pub fn add_solid_rectangle(
         &mut self,
         clip_and_scroll: ScrollNodeAndClipChain,
-        info: &LayerPrimitiveInfo,
+        info: &LayoutPrimitiveInfo,
         color: ColorF,
         segments: Option<BrushSegmentDescriptor>,
         extra_clips: Vec<ClipSource>,
     ) {
         if color.a == 0.0 {
             // Don't add transparent rectangles to the draw list, but do consider them for hit
             // testing. This allows specifying invisible hit testing areas.
             self.add_primitive_to_hit_testing_list(info, clip_and_scroll);
             return;
         }
 
         let prim = BrushPrimitive::new(
-            BrushKind::Solid {
-                color,
-            },
+            BrushKind::new_solid(color),
             segments,
         );
 
         self.add_primitive(
             clip_and_scroll,
             info,
             extra_clips,
             PrimitiveContainer::Brush(prim),
         );
     }
 
     pub fn add_clear_rectangle(
         &mut self,
         clip_and_scroll: ScrollNodeAndClipChain,
-        info: &LayerPrimitiveInfo,
+        info: &LayoutPrimitiveInfo,
     ) {
         let prim = BrushPrimitive::new(
             BrushKind::Clear,
             None,
         );
 
         self.add_primitive(
             clip_and_scroll,
@@ -1511,28 +1506,26 @@ impl<'a> DisplayListFlattener<'a> {
             Vec::new(),
             PrimitiveContainer::Brush(prim),
         );
     }
 
     pub fn add_scroll_bar(
         &mut self,
         clip_and_scroll: ScrollNodeAndClipChain,
-        info: &LayerPrimitiveInfo,
+        info: &LayoutPrimitiveInfo,
         color: ColorF,
         scrollbar_info: ScrollbarInfo,
     ) {
         if color.a == 0.0 {
             return;
         }
 
         let prim = BrushPrimitive::new(
-            BrushKind::Solid {
-                color,
-            },
+            BrushKind::new_solid(color),
             None,
         );
 
         let prim_index = self.create_primitive(
             info,
             Vec::new(),
             PrimitiveContainer::Brush(prim),
         );
@@ -1547,26 +1540,24 @@ impl<'a> DisplayListFlattener<'a> {
             scroll_frame_index: scrollbar_info.0,
             frame_rect: scrollbar_info.1,
         });
     }
 
     pub fn add_line(
         &mut self,
         clip_and_scroll: ScrollNodeAndClipChain,
-        info: &LayerPrimitiveInfo,
+        info: &LayoutPrimitiveInfo,
         wavy_line_thickness: f32,
         orientation: LineOrientation,
         line_color: &ColorF,
         style: LineStyle,
     ) {
         let prim = BrushPrimitive::new(
-            BrushKind::Solid {
-                color: *line_color,
-            },
+            BrushKind::new_solid(*line_color),
             None,
         );
 
         let extra_clips = match style {
             LineStyle::Solid => {
                 Vec::new()
             }
             LineStyle::Wavy |
@@ -1589,109 +1580,109 @@ impl<'a> DisplayListFlattener<'a> {
             extra_clips,
             PrimitiveContainer::Brush(prim),
         );
     }
 
     pub fn add_border(
         &mut self,
         clip_and_scroll: ScrollNodeAndClipChain,
-        info: &LayerPrimitiveInfo,
+        info: &LayoutPrimitiveInfo,
         border_item: &BorderDisplayItem,
         gradient_stops: ItemRange<GradientStop>,
         gradient_stops_count: usize,
     ) {
         let rect = info.rect;
         let create_segments = |outset: SideOffsets2D<f32>| {
             // Calculate the modified rect as specific by border-image-outset
-            let origin = LayerPoint::new(rect.origin.x - outset.left, rect.origin.y - outset.top);
-            let size = LayerSize::new(
+            let origin = LayoutPoint::new(rect.origin.x - outset.left, rect.origin.y - outset.top);
+            let size = LayoutSize::new(
                 rect.size.width + outset.left + outset.right,
                 rect.size.height + outset.top + outset.bottom,
             );
-            let rect = LayerRect::new(origin, size);
+            let rect = LayoutRect::new(origin, size);
 
-            let tl_outer = LayerPoint::new(rect.origin.x, rect.origin.y);
+            let tl_outer = LayoutPoint::new(rect.origin.x, rect.origin.y);
             let tl_inner = tl_outer + vec2(border_item.widths.left, border_item.widths.top);
 
-            let tr_outer = LayerPoint::new(rect.origin.x + rect.size.width, rect.origin.y);
+            let tr_outer = LayoutPoint::new(rect.origin.x + rect.size.width, rect.origin.y);
             let tr_inner = tr_outer + vec2(-border_item.widths.right, border_item.widths.top);
 
-            let bl_outer = LayerPoint::new(rect.origin.x, rect.origin.y + rect.size.height);
+            let bl_outer = LayoutPoint::new(rect.origin.x, rect.origin.y + rect.size.height);
             let bl_inner = bl_outer + vec2(border_item.widths.left, -border_item.widths.bottom);
 
-            let br_outer = LayerPoint::new(
+            let br_outer = LayoutPoint::new(
                 rect.origin.x + rect.size.width,
                 rect.origin.y + rect.size.height,
             );
             let br_inner = br_outer - vec2(border_item.widths.right, border_item.widths.bottom);
 
             // Build the list of gradient segments
             vec![
                 // Top left
-                LayerRect::from_floats(tl_outer.x, tl_outer.y, tl_inner.x, tl_inner.y),
+                LayoutRect::from_floats(tl_outer.x, tl_outer.y, tl_inner.x, tl_inner.y),
                 // Top right
-                LayerRect::from_floats(tr_inner.x, tr_outer.y, tr_outer.x, tr_inner.y),
+                LayoutRect::from_floats(tr_inner.x, tr_outer.y, tr_outer.x, tr_inner.y),
                 // Bottom right
-                LayerRect::from_floats(br_inner.x, br_inner.y, br_outer.x, br_outer.y),
+                LayoutRect::from_floats(br_inner.x, br_inner.y, br_outer.x, br_outer.y),
                 // Bottom left
-                LayerRect::from_floats(bl_outer.x, bl_inner.y, bl_inner.x, bl_outer.y),
+                LayoutRect::from_floats(bl_outer.x, bl_inner.y, bl_inner.x, bl_outer.y),
                 // Top
-                LayerRect::from_floats(tl_inner.x, tl_outer.y, tr_inner.x, tl_inner.y),
+                LayoutRect::from_floats(tl_inner.x, tl_outer.y, tr_inner.x, tl_inner.y),
                 // Bottom
-                LayerRect::from_floats(bl_inner.x, bl_inner.y, br_inner.x, bl_outer.y),
+                LayoutRect::from_floats(bl_inner.x, bl_inner.y, br_inner.x, bl_outer.y),
                 // Left
-                LayerRect::from_floats(tl_outer.x, tl_inner.y, tl_inner.x, bl_inner.y),
+                LayoutRect::from_floats(tl_outer.x, tl_inner.y, tl_inner.x, bl_inner.y),
                 // Right
-                LayerRect::from_floats(tr_inner.x, tr_inner.y, br_outer.x, br_inner.y),
+                LayoutRect::from_floats(tr_inner.x, tr_inner.y, br_outer.x, br_inner.y),
             ]
         };
 
         match border_item.details {
             BorderDetails::Image(ref border) => {
                 // Calculate the modified rect as specific by border-image-outset
-                let origin = LayerPoint::new(
+                let origin = LayoutPoint::new(
                     rect.origin.x - border.outset.left,
                     rect.origin.y - border.outset.top,
                 );
-                let size = LayerSize::new(
+                let size = LayoutSize::new(
                     rect.size.width + border.outset.left + border.outset.right,
                     rect.size.height + border.outset.top + border.outset.bottom,
                 );
-                let rect = LayerRect::new(origin, size);
+                let rect = LayoutRect::new(origin, size);
 
                 // Calculate the local texel coords of the slices.
                 let px0 = 0.0;
                 let px1 = border.patch.slice.left as f32;
                 let px2 = border.patch.width as f32 - border.patch.slice.right as f32;
                 let px3 = border.patch.width as f32;
 
                 let py0 = 0.0;
                 let py1 = border.patch.slice.top as f32;
                 let py2 = border.patch.height as f32 - border.patch.slice.bottom as f32;
                 let py3 = border.patch.height as f32;
 
-                let tl_outer = LayerPoint::new(rect.origin.x, rect.origin.y);
+                let tl_outer = LayoutPoint::new(rect.origin.x, rect.origin.y);
                 let tl_inner = tl_outer + vec2(border_item.widths.left, border_item.widths.top);
 
-                let tr_outer = LayerPoint::new(rect.origin.x + rect.size.width, rect.origin.y);
+                let tr_outer = LayoutPoint::new(rect.origin.x + rect.size.width, rect.origin.y);
                 let tr_inner = tr_outer + vec2(-border_item.widths.right, border_item.widths.top);
 
-                let bl_outer = LayerPoint::new(rect.origin.x, rect.origin.y + rect.size.height);
+                let bl_outer = LayoutPoint::new(rect.origin.x, rect.origin.y + rect.size.height);
                 let bl_inner = bl_outer + vec2(border_item.widths.left, -border_item.widths.bottom);
 
-                let br_outer = LayerPoint::new(
+                let br_outer = LayoutPoint::new(
                     rect.origin.x + rect.size.width,
                     rect.origin.y + rect.size.height,
                 );
                 let br_inner = br_outer - vec2(border_item.widths.right, border_item.widths.bottom);
 
                 fn add_segment(
                     segments: &mut Vec<ImageBorderSegment>,
-                    rect: LayerRect,
+                    rect: LayoutRect,
                     uv_rect: TexelRect,
                     repeat_horizontal: RepeatMode,
                     repeat_vertical: RepeatMode) {
                     if uv_rect.uv1.x > uv_rect.uv0.x &&
                        uv_rect.uv1.y > uv_rect.uv0.y {
                         segments.push(ImageBorderSegment::new(
                             rect,
                             uv_rect,
@@ -1702,87 +1693,87 @@ impl<'a> DisplayListFlattener<'a> {
                 }
 
                 // Build the list of image segments
                 let mut segments = vec![];
 
                 // Top left
                 add_segment(
                     &mut segments,
-                    LayerRect::from_floats(tl_outer.x, tl_outer.y, tl_inner.x, tl_inner.y),
+                    LayoutRect::from_floats(tl_outer.x, tl_outer.y, tl_inner.x, tl_inner.y),
                     TexelRect::new(px0, py0, px1, py1),
                     RepeatMode::Stretch,
                     RepeatMode::Stretch
                 );
                 // Top right
                 add_segment(
                     &mut segments,
-                    LayerRect::from_floats(tr_inner.x, tr_outer.y, tr_outer.x, tr_inner.y),
+                    LayoutRect::from_floats(tr_inner.x, tr_outer.y, tr_outer.x, tr_inner.y),
                     TexelRect::new(px2, py0, px3, py1),
                     RepeatMode::Stretch,
                     RepeatMode::Stretch
                 );
                 // Bottom right
                 add_segment(
                     &mut segments,
-                    LayerRect::from_floats(br_inner.x, br_inner.y, br_outer.x, br_outer.y),
+                    LayoutRect::from_floats(br_inner.x, br_inner.y, br_outer.x, br_outer.y),
                     TexelRect::new(px2, py2, px3, py3),
                     RepeatMode::Stretch,
                     RepeatMode::Stretch
                 );
                 // Bottom left
                 add_segment(
                     &mut segments,
-                    LayerRect::from_floats(bl_outer.x, bl_inner.y, bl_inner.x, bl_outer.y),
+                    LayoutRect::from_floats(bl_outer.x, bl_inner.y, bl_inner.x, bl_outer.y),
                     TexelRect::new(px0, py2, px1, py3),
                     RepeatMode::Stretch,
                     RepeatMode::Stretch
                 );
 
                 // Center
                 if border.fill {
                     add_segment(
                         &mut segments,
-                        LayerRect::from_floats(tl_inner.x, tl_inner.y, tr_inner.x, bl_inner.y),
+                        LayoutRect::from_floats(tl_inner.x, tl_inner.y, tr_inner.x, bl_inner.y),
                         TexelRect::new(px1, py1, px2, py2),
                         border.repeat_horizontal,
                         border.repeat_vertical
                     );
                 }
 
                 // Add edge segments.
 
                 // Top
                 add_segment(
                     &mut segments,
-                    LayerRect::from_floats(tl_inner.x, tl_outer.y, tr_inner.x, tl_inner.y),
+                    LayoutRect::from_floats(tl_inner.x, tl_outer.y, tr_inner.x, tl_inner.y),
                     TexelRect::new(px1, py0, px2, py1),
                     border.repeat_horizontal,
                     RepeatMode::Stretch,
                 );
                 // Bottom
                 add_segment(
                     &mut segments,
-                    LayerRect::from_floats(bl_inner.x, bl_inner.y, br_inner.x, bl_outer.y),
+                    LayoutRect::from_floats(bl_inner.x, bl_inner.y, br_inner.x, bl_outer.y),
                     TexelRect::new(px1, py2, px2, py3),
                     border.repeat_horizontal,
                     RepeatMode::Stretch,
                 );
                 // Left
                 add_segment(
                     &mut segments,
-                    LayerRect::from_floats(tl_outer.x, tl_inner.y, tl_inner.x, bl_inner.y),
+                    LayoutRect::from_floats(tl_outer.x, tl_inner.y, tl_inner.x, bl_inner.y),
                     TexelRect::new(px0, py1, px1, py2),
                     RepeatMode::Stretch,
                     border.repeat_vertical,
                 );
                 // Right
                 add_segment(
                     &mut segments,
-                    LayerRect::from_floats(tr_inner.x, tr_inner.y, br_outer.x, br_inner.y),
+                    LayoutRect::from_floats(tr_inner.x, tr_inner.y, br_outer.x, br_inner.y),
                     TexelRect::new(px2, py1, px3, py2),
                     RepeatMode::Stretch,
                     border.repeat_vertical,
                 );
 
                 for segment in segments {
                     let mut info = info.clone();
                     info.rect = segment.geom_rect;
@@ -1811,17 +1802,17 @@ impl<'a> DisplayListFlattener<'a> {
                     clip_and_scroll,
                     &info,
                     border.gradient.start_point - segment_rel,
                     border.gradient.end_point - segment_rel,
                     gradient_stops,
                     gradient_stops_count,
                     border.gradient.extend_mode,
                     segment.size,
-                    LayerSize::zero(),
+                    LayoutSize::zero(),
                 );
             },
             BorderDetails::RadialGradient(ref border) => {
                 for segment in create_segments(border.outset) {
                     let segment_rel = segment.origin - rect.origin;
                     let mut info = info.clone();
                     info.rect = segment;
 
@@ -1830,29 +1821,29 @@ impl<'a> DisplayListFlattener<'a> {
                         &info,
                         border.gradient.center - segment_rel,
                         border.gradient.start_offset * border.gradient.radius.width,
                         border.gradient.end_offset * border.gradient.radius.width,
                         border.gradient.radius.width / border.gradient.radius.height,
                         gradient_stops,
                         border.gradient.extend_mode,
                         segment.size,
-                        LayerSize::zero(),
+                        LayoutSize::zero(),
                     );
                 }
             }
         }
     }
 
     fn add_gradient_impl(
         &mut self,
         clip_and_scroll: ScrollNodeAndClipChain,
-        info: &LayerPrimitiveInfo,
-        start_point: LayerPoint,
-        end_point: LayerPoint,
+        info: &LayoutPrimitiveInfo,
+        start_point: LayoutPoint,
+        end_point: LayoutPoint,
         stops: ItemRange<GradientStop>,
         stops_count: usize,
         extend_mode: ExtendMode,
         gradient_index: CachedGradientIndex,
     ) {
         // Try to ensure that if the gradient is specified in reverse, then so long as the stops
         // are also supplied in reverse that the rendered result will be equivalent. To do this,
         // a reference orientation for the gradient line must be chosen, somewhat arbitrarily, so
@@ -1887,24 +1878,24 @@ impl<'a> DisplayListFlattener<'a> {
         let prim = PrimitiveContainer::Brush(prim);
 
         self.add_primitive(clip_and_scroll, info, Vec::new(), prim);
     }
 
     pub fn add_gradient(
         &mut self,
         clip_and_scroll: ScrollNodeAndClipChain,
-        info: &LayerPrimitiveInfo,
-        start_point: LayerPoint,
-        end_point: LayerPoint,
+        info: &LayoutPrimitiveInfo,
+        start_point: LayoutPoint,
+        end_point: LayoutPoint,
         stops: ItemRange<GradientStop>,
         stops_count: usize,
         extend_mode: ExtendMode,
-        tile_size: LayerSize,
-        tile_spacing: LayerSize,
+        tile_size: LayoutSize,
+        tile_spacing: LayoutSize,
     ) {
         let gradient_index = CachedGradientIndex(self.cached_gradients.len());
         self.cached_gradients.push(CachedGradient::new());
 
         let prim_infos = info.decompose(
             tile_size,
             tile_spacing,
             64 * 64,
@@ -1935,18 +1926,18 @@ impl<'a> DisplayListFlattener<'a> {
                 );
             }
         }
     }
 
     fn add_radial_gradient_impl(
         &mut self,
         clip_and_scroll: ScrollNodeAndClipChain,
-        info: &LayerPrimitiveInfo,
-        center: LayerPoint,
+        info: &LayoutPrimitiveInfo,
+        center: LayoutPoint,
         start_radius: f32,
         end_radius: f32,
         ratio_xy: f32,
         stops: ItemRange<GradientStop>,
         extend_mode: ExtendMode,
         gradient_index: CachedGradientIndex,
     ) {
         let prim = BrushPrimitive::new(
@@ -1968,25 +1959,25 @@ impl<'a> DisplayListFlattener<'a> {
             Vec::new(),
             PrimitiveContainer::Brush(prim),
         );
     }
 
     pub fn add_radial_gradient(
         &mut self,
         clip_and_scroll: ScrollNodeAndClipChain,
-        info: &LayerPrimitiveInfo,
-        center: LayerPoint,
+        info: &LayoutPrimitiveInfo,
+        center: LayoutPoint,
         start_radius: f32,
         end_radius: f32,
         ratio_xy: f32,
         stops: ItemRange<GradientStop>,
         extend_mode: ExtendMode,
-        tile_size: LayerSize,
-        tile_spacing: LayerSize,
+        tile_size: LayoutSize,
+        tile_spacing: LayoutSize,
     ) {
         let gradient_index = CachedGradientIndex(self.cached_gradients.len());
         self.cached_gradients.push(CachedGradient::new());
 
         let prim_infos = info.decompose(
             tile_size,
             tile_spacing,
             64 * 64,
@@ -2020,17 +2011,17 @@ impl<'a> DisplayListFlattener<'a> {
             }
         }
     }
 
     pub fn add_text(
         &mut self,
         clip_and_scroll: ScrollNodeAndClipChain,
         run_offset: LayoutVector2D,
-        prim_info: &LayerPrimitiveInfo,
+        prim_info: &LayoutPrimitiveInfo,
         font_instance_key: &FontInstanceKey,
         text_color: &ColorF,
         glyph_range: ItemRange<GlyphInstance>,
         glyph_options: Option<GlyphOptions>,
     ) {
         let prim = {
             let instance_map = self.font_instances.read().unwrap();
             let font_instance = match instance_map.get(font_instance_key) {
@@ -2064,36 +2055,21 @@ impl<'a> DisplayListFlattener<'a> {
                 .default_font_render_mode
                 .limit_by(font_instance.render_mode);
             let mut flags = font_instance.flags;
             if let Some(options) = glyph_options {
                 render_mode = render_mode.limit_by(options.render_mode);
                 flags |= options.flags;
             }
 
-            let (allow_subpixel_aa, glyph_raster_space) = match self.sc_stack.last() {
-                Some(stacking_context) => {
-                    (stacking_context.allow_subpixel_aa, stacking_context.glyph_raster_space)
-                }
-                None => {
-                    (true, GlyphRasterSpace::Screen)
-                }
+            let glyph_raster_space = match self.sc_stack.last() {
+                Some(stacking_context) => stacking_context.glyph_raster_space,
+                None => GlyphRasterSpace::Screen,
             };
 
-            // There are some conditions under which we can't use
-            // subpixel text rendering, even if enabled.
-            if !allow_subpixel_aa {
-                // text on a picture that has filters
-                // (e.g. opacity) can't use sub-pixel.
-                // TODO(gw): It's possible we can relax this in
-                //           the future, if we modify the way
-                //           we handle subpixel blending.
-                render_mode = render_mode.limit_by(FontRenderMode::Alpha);
-            }
-
             let prim_font = FontInstance::new(
                 font_instance.font_key,
                 font_instance.size,
                 *text_color,
                 font_instance.bg_color,
                 render_mode,
                 font_instance.subpx_dir,
                 flags,
@@ -2117,31 +2093,31 @@ impl<'a> DisplayListFlattener<'a> {
             Vec::new(),
             PrimitiveContainer::TextRun(prim),
         );
     }
 
     pub fn add_image(
         &mut self,
         clip_and_scroll: ScrollNodeAndClipChain,
-        info: &LayerPrimitiveInfo,
-        stretch_size: LayerSize,
-        mut tile_spacing: LayerSize,
+        info: &LayoutPrimitiveInfo,
+        stretch_size: LayoutSize,
+        mut tile_spacing: LayoutSize,
         sub_rect: Option<TexelRect>,
         image_key: ImageKey,
         image_rendering: ImageRendering,
         alpha_type: AlphaType,
         tile_offset: Option<TileOffset>,
     ) {
         // If the tile spacing is the same as the rect size,
         // then it is effectively zero. We use this later on
         // in prim_store to detect if an image can be considered
         // opaque.
         if tile_spacing == info.rect.size {
-            tile_spacing = LayerSize::zero();
+            tile_spacing = LayoutSize::zero();
         }
 
         let request = ImageRequest {
             key: image_key,
             rendering: image_rendering,
             tile: tile_offset,
         };
 
@@ -2155,28 +2131,29 @@ impl<'a> DisplayListFlattener<'a> {
                     (texel_rect.uv1.x - texel_rect.uv0.x) as i32,
                     (texel_rect.uv1.y - texel_rect.uv0.y) as i32,
                 ),
             )
         });
 
         // See if conditions are met to run through the new
         // image brush shader, which supports segments.
-        if tile_spacing == LayerSize::zero() &&
+        if tile_spacing == LayoutSize::zero() &&
            stretch_size == info.rect.size &&
            tile_offset.is_none() {
             let prim = BrushPrimitive::new(
                 BrushKind::Image {
                     request,
                     current_epoch: Epoch::invalid(),
                     alpha_type,
                     stretch_size,
                     tile_spacing,
                     source: ImageSource::Default,
                     sub_rect,
+                    opacity_binding: OpacityBinding::new(),
                 },
                 None,
             );
 
             self.add_primitive(
                 clip_and_scroll,
                 info,
                 Vec::new(),
@@ -2202,17 +2179,17 @@ impl<'a> DisplayListFlattener<'a> {
                 PrimitiveContainer::Image(prim_cpu),
             );
         }
     }
 
     pub fn add_yuv_image(
         &mut self,
         clip_and_scroll: ScrollNodeAndClipChain,
-        info: &LayerPrimitiveInfo,
+        info: &LayoutPrimitiveInfo,
         yuv_data: YuvData,
         color_space: YuvColorSpace,
         image_rendering: ImageRendering,
     ) {
         let format = yuv_data.get_format();
         let yuv_key = match yuv_data {
             YuvData::NV12(plane_0, plane_1) => [plane_0, plane_1, ImageKey::DUMMY],
             YuvData::PlanarYCbCr(plane_0, plane_1, plane_2) => [plane_0, plane_1, plane_2],
@@ -2261,29 +2238,29 @@ pub fn build_scene(config: &FrameBuilder
         clip_scroll_tree,
         removed_pipelines: request.removed_pipelines,
     }
 }
 
 trait PrimitiveInfoTiler {
     fn decompose(
         &self,
-        tile_size: LayerSize,
-        tile_spacing: LayerSize,
+        tile_size: LayoutSize,
+        tile_spacing: LayoutSize,
         max_prims: usize,
-    ) -> Vec<LayerPrimitiveInfo>;
+    ) -> Vec<LayoutPrimitiveInfo>;
 }
 
-impl PrimitiveInfoTiler for LayerPrimitiveInfo {
+impl PrimitiveInfoTiler for LayoutPrimitiveInfo {
     fn decompose(
         &self,
-        tile_size: LayerSize,
-        tile_spacing: LayerSize,
+        tile_size: LayoutSize,
+        tile_spacing: LayoutSize,
         max_prims: usize,
-    ) -> Vec<LayerPrimitiveInfo> {
+    ) -> Vec<LayoutPrimitiveInfo> {
         let mut prims = Vec::new();
         let tile_repeat = tile_size + tile_spacing;
 
         if tile_repeat.width <= 0.0 ||
            tile_repeat.height <= 0.0 {
             return prims;
         }
 
@@ -2295,19 +2272,19 @@ impl PrimitiveInfoTiler for LayerPrimiti
             let rect_p0 = self.rect.origin;
             let rect_p1 = self.rect.bottom_right();
 
             let mut y0 = rect_p0.y;
             while y0 < rect_p1.y {
                 let mut x0 = rect_p0.x;
 
                 while x0 < rect_p1.x {
-                    prims.push(LayerPrimitiveInfo {
-                        rect: LayerRect::new(
-                            LayerPoint::new(x0, y0),
+                    prims.push(LayoutPrimitiveInfo {
+                        rect: LayoutRect::new(
+                            LayoutPoint::new(x0, y0),
                             tile_size,
                         ),
                         clip_rect,
                         is_backface_visible: self.is_backface_visible,
                         tag: self.tag,
                     });
 
                     // Mostly a safety against a crazy number of primitives
@@ -2337,28 +2314,23 @@ struct FlattenedStackingContext {
     pipeline_id: PipelineId,
 
     /// Filters / mix-blend-mode effects
     composite_ops: CompositeOps,
 
     /// If true, visible when backface is visible.
     is_backface_visible: bool,
 
-    /// Allow subpixel AA for text runs on this stacking context.
-    /// This is a temporary hack while we don't support subpixel AA
-    /// on transparent stacking contexts.
-    allow_subpixel_aa: bool,
-
     /// The rasterization mode for any text runs that are part
     /// of this stacking context.
     glyph_raster_space: GlyphRasterSpace,
 
     /// CSS transform-style property.
     transform_style: TransformStyle,
 
     /// If Some(..), this stacking context establishes a new
     /// 3d rendering context, and the value is the picture
     // index of the 3d context container.
     rendering_context_3d_pic_index: Option<PictureIndex>,
 }
 
 #[derive(Debug)]
-pub struct ScrollbarInfo(pub ClipScrollNodeIndex, pub LayerRect);
+pub struct ScrollbarInfo(pub ClipScrollNodeIndex, pub LayoutRect);
--- a/gfx/webrender/src/ellipse.rs
+++ b/gfx/webrender/src/ellipse.rs
@@ -1,27 +1,27 @@
 /* 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::{LayerPoint, LayerSize, LayerVector2D};
+use api::{LayoutPoint, LayoutSize, LayoutVector2D};
 use std::f32::consts::FRAC_PI_2;
 
 /// Number of steps to integrate arc length over.
 const STEP_COUNT: usize = 20;
 
 /// Represents an ellipse centred at a local space origin.
 #[derive(Debug, Clone)]
 pub struct Ellipse {
-    pub radius: LayerSize,
+    pub radius: LayoutSize,
     pub total_arc_length: f32,
 }
 
 impl Ellipse {
-    pub fn new(radius: LayerSize) -> Ellipse {
+    pub fn new(radius: LayoutSize) -> Ellipse {
         // Approximate the total length of the first quadrant of this ellipse.
         let total_arc_length = get_simpson_length(FRAC_PI_2, radius.width, radius.height);
 
         Ellipse {
             radius,
             total_arc_length,
         }
     }
@@ -51,42 +51,42 @@ impl Ellipse {
             }
         }
 
         theta
     }
 
     /// Get a point and tangent on this ellipse from a given angle.
     /// This only works for the first quadrant of the ellipse.
-    pub fn get_point_and_tangent(&self, theta: f32) -> (LayerPoint, LayerPoint) {
+    pub fn get_point_and_tangent(&self, theta: f32) -> (LayoutPoint, LayoutPoint) {
         let (sin_theta, cos_theta) = theta.sin_cos();
-        let point = LayerPoint::new(
+        let point = LayoutPoint::new(
             self.radius.width * cos_theta,
             self.radius.height * sin_theta,
         );
-        let tangent = LayerPoint::new(
+        let tangent = LayoutPoint::new(
             -self.radius.width * sin_theta,
             self.radius.height * cos_theta,
         );
         (point, tangent)
     }
 
-    pub fn contains(&self, point: LayerPoint) -> bool {
+    pub fn contains(&self, point: LayoutPoint) -> bool {
         self.signed_distance(point.to_vector()) <= 0.0
     }
 
     /// Find the signed distance from this ellipse given a point.
     /// Taken from http://www.iquilezles.org/www/articles/ellipsedist/ellipsedist.htm
-    fn signed_distance(&self, point: LayerVector2D) -> f32 {
+    fn signed_distance(&self, point: LayoutVector2D) -> f32 {
         // This algorithm fails for circles, so we handle them here.
         if self.radius.width == self.radius.height {
             return point.length() - self.radius.width;
         }
 
-        let mut p = LayerVector2D::new(point.x.abs(), point.y.abs());
+        let mut p = LayoutVector2D::new(point.x.abs(), point.y.abs());
         let mut ab = self.radius.to_vector();
         if p.x > p.y {
             p = p.yx();
             ab = ab.yx();
         }
 
         let l = ab.y * ab.y - ab.x * ab.x;
 
@@ -116,17 +116,17 @@ impl Ellipse {
             let rx = -s - u - c * 4.0 + 2.0 * m2;
             let ry = (s - u) * (3.0_f32).sqrt();
             let rm = (rx * rx + ry * ry).sqrt();
             let p = ry / (rm - rx).sqrt();
             (p + 2.0 * g / rm - m) / 2.0
         };
 
         let si = (1.0 - co * co).sqrt();
-        let r = LayerVector2D::new(ab.x * co, ab.y * si);
+        let r = LayoutVector2D::new(ab.x * co, ab.y * si);
         (r - p).length() * (p.y - r.y).signum()
     }
 }
 
 /// Use Simpsons rule to approximate the arc length of
 /// part of an ellipse. Note that this only works over
 /// the range of [0, pi/2].
 // TODO(gw): This is a simplistic way to estimate the
--- a/gfx/webrender/src/frame_builder.rs
+++ b/gfx/webrender/src/frame_builder.rs
@@ -1,15 +1,15 @@
 /* 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::{BuiltDisplayList, ColorF, DeviceIntPoint, DeviceIntRect, DevicePixelScale};
 use api::{DeviceUintPoint, DeviceUintRect, DeviceUintSize, DocumentLayer, FontRenderMode};
-use api::{LayerRect, LayerSize, PipelineId, WorldPoint};
+use api::{LayoutRect, LayoutSize, PipelineId, WorldPoint};
 use clip::{ClipChain, ClipStore};
 use clip_scroll_node::{ClipScrollNode};
 use clip_scroll_tree::{ClipScrollNodeIndex, ClipScrollTree};
 use display_list_flattener::{DisplayListFlattener};
 use gpu_cache::GpuCache;
 use gpu_types::{ClipChainRectIndex, ClipScrollNodeData};
 use hit_test::{HitTester, HitTestingRun};
 use internal_types::{FastHashMap};
@@ -19,17 +19,17 @@ use profiler::{FrameProfileCounters, Gpu
 use render_backend::FrameId;
 use render_task::{RenderTask, RenderTaskId, RenderTaskLocation, RenderTaskTree};
 use resource_cache::{ResourceCache};
 use scene::{ScenePipeline, SceneProperties};
 use std::{mem, f32};
 use std::sync::Arc;
 use tiling::{Frame, RenderPass, RenderPassKind, RenderTargetContext};
 use tiling::{ScrollbarPrimitive, SpecialRenderPasses};
-use util::{self, MaxRect, WorldToLayerFastTransform};
+use util::{self, MaxRect, WorldToLayoutFastTransform};
 
 #[derive(Clone, Copy)]
 #[cfg_attr(feature = "capture", derive(Serialize))]
 #[cfg_attr(feature = "replay", derive(Deserialize))]
 pub struct FrameBuilderConfig {
     pub enable_scrollbars: bool,
     pub default_font_render_mode: FontRenderMode,
     pub dual_source_blending_is_supported: bool,
@@ -57,31 +57,32 @@ pub struct FrameBuildingContext<'a> {
     pub clip_scroll_tree: &'a ClipScrollTree,
     pub node_data: &'a [ClipScrollNodeData],
 }
 
 pub struct FrameBuildingState<'a> {
     pub render_tasks: &'a mut RenderTaskTree,
     pub profile_counters: &'a mut FrameProfileCounters,
     pub clip_store: &'a mut ClipStore,
-    pub local_clip_rects: &'a mut Vec<LayerRect>,
+    pub local_clip_rects: &'a mut Vec<LayoutRect>,
     pub resource_cache: &'a mut ResourceCache,
     pub gpu_cache: &'a mut GpuCache,
     pub cached_gradients: &'a mut [CachedGradient],
     pub special_render_passes: &'a mut SpecialRenderPasses,
 }
 
 pub struct PictureContext<'a> {
     pub pipeline_id: PipelineId,
     pub prim_runs: Vec<PrimitiveRun>,
     pub original_reference_frame_index: Option<ClipScrollNodeIndex>,
     pub display_list: &'a BuiltDisplayList,
-    pub inv_world_transform: Option<WorldToLayerFastTransform>,
+    pub inv_world_transform: Option<WorldToLayoutFastTransform>,
     pub apply_local_clip_rect: bool,
     pub inflation_factor: f32,
+    pub allow_subpixel_aa: bool,
 }
 
 pub struct PictureState {
     pub tasks: Vec<RenderTaskId>,
     pub has_non_root_coord_system: bool,
 }
 
 impl PictureState {
@@ -160,17 +161,17 @@ impl FrameBuilder {
         pipelines: &FastHashMap<PipelineId, Arc<ScenePipeline>>,
         resource_cache: &mut ResourceCache,
         gpu_cache: &mut GpuCache,
         render_tasks: &mut RenderTaskTree,
         special_render_passes: &mut SpecialRenderPasses,
         profile_counters: &mut FrameProfileCounters,
         device_pixel_scale: DevicePixelScale,
         scene_properties: &SceneProperties,
-        local_clip_rects: &mut Vec<LayerRect>,
+        local_clip_rects: &mut Vec<LayoutRect>,
         node_data: &[ClipScrollNodeData],
     ) -> Option<RenderTaskId> {
         profile_scope!("cull");
 
         if self.prim_store.pictures.is_empty() {
             return None
         }
 
@@ -206,16 +207,17 @@ impl FrameBuilder {
         let pic_context = PictureContext {
             pipeline_id: root_clip_scroll_node.pipeline_id,
             prim_runs: mem::replace(&mut self.prim_store.pictures[0].runs, Vec::new()),
             original_reference_frame_index: None,
             display_list,
             inv_world_transform: None,
             apply_local_clip_rect: true,
             inflation_factor: 0.0,
+            allow_subpixel_aa: true,
         };
 
         let mut pic_state = PictureState::new();
 
         self.prim_store.reset_prim_visibility();
         self.prim_store.prepare_prim_runs(
             &pic_context,
             &mut pic_state,
@@ -245,17 +247,17 @@ impl FrameBuilder {
             let metadata = &mut self.prim_store.cpu_metadata[scrollbar_prim.prim_index.0];
             let scroll_frame = &clip_scroll_tree.nodes[scrollbar_prim.scroll_frame_index.0];
 
             // Invalidate what's in the cache so it will get rebuilt.
             gpu_cache.invalidate(&metadata.gpu_location);
 
             let scrollable_distance = scroll_frame.scrollable_size().height;
             if scrollable_distance <= 0.0 {
-                metadata.local_clip_rect.size = LayerSize::zero();
+                metadata.local_clip_rect.size = LayoutSize::zero();
                 continue;
             }
             let amount_scrolled = -scroll_frame.scroll_offset().y / scrollable_distance;
 
             let frame_rect = scrollbar_prim.frame_rect;
             let min_y = frame_rect.origin.y + SCROLLBAR_PADDING;
             let max_y = frame_rect.origin.y + frame_rect.size.height -
                 (SCROLLBAR_PADDING + metadata.local_rect.size.height);
@@ -294,17 +296,17 @@ impl FrameBuilder {
 
         resource_cache.begin_frame(frame_id);
         gpu_cache.begin_frame();
 
         let mut node_data = Vec::with_capacity(clip_scroll_tree.nodes.len());
         let total_prim_runs =
             self.prim_store.pictures.iter().fold(1, |count, pic| count + pic.runs.len());
         let mut clip_chain_local_clip_rects = Vec::with_capacity(total_prim_runs);
-        clip_chain_local_clip_rects.push(LayerRect::max_rect());
+        clip_chain_local_clip_rects.push(LayoutRect::max_rect());
 
         clip_scroll_tree.update_tree(
             &self.screen_rect.to_i32(),
             device_pixel_scale,
             &mut self.clip_store,
             resource_cache,
             gpu_cache,
             pan,
--- a/gfx/webrender/src/glyph_rasterizer.rs
+++ b/gfx/webrender/src/glyph_rasterizer.rs
@@ -2,17 +2,17 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #[cfg(test)]
 use api::{IdNamespace, LayoutPoint};
 use api::{ColorF, ColorU};
 use api::{FontInstanceFlags, FontInstancePlatformOptions};
 use api::{FontKey, FontRenderMode, FontTemplate, FontVariation};
-use api::{GlyphDimensions, GlyphKey, LayerToWorldTransform, SubpixelDirection};
+use api::{GlyphDimensions, GlyphKey, LayoutToWorldTransform, SubpixelDirection};
 #[cfg(feature = "pathfinder")]
 use api::NativeFontHandle;
 #[cfg(any(test, feature = "pathfinder"))]
 use api::DeviceIntSize;
 #[cfg(not(feature = "pathfinder"))]
 use api::{ImageData, ImageDescriptor, ImageFormat};
 use app_units::Au;
 #[cfg(not(feature = "pathfinder"))]
@@ -32,19 +32,19 @@ use platform::font::FontContext;
 use profiler::TextureCacheProfileCounters;
 use rayon::ThreadPool;
 #[cfg(not(feature = "pathfinder"))]
 use rayon::prelude::*;
 #[cfg(test)]
 use render_backend::FrameId;
 use render_task::{RenderTaskCache, RenderTaskTree};
 #[cfg(feature = "pathfinder")]
-use render_task::{RenderTask, RenderTaskCacheKey, RenderTaskCacheKeyKind};
+use render_task::{RenderTask, RenderTaskCacheKey, RenderTaskCacheEntryHandle};
 #[cfg(feature = "pathfinder")]
-use render_task::{RenderTaskId, RenderTaskLocation};
+use render_task::{RenderTaskCacheKeyKind, RenderTaskId, RenderTaskLocation};
 #[cfg(feature = "pathfinder")]
 use resource_cache::CacheItem;
 use std::cmp;
 use std::collections::hash_map::Entry;
 use std::f32;
 use std::hash::{Hash, Hasher};
 use std::mem;
 use std::sync::{Arc, Mutex, MutexGuard};
@@ -179,18 +179,18 @@ impl FontTransform {
         FontTransform::new(-self.scale_x, self.skew_x, -self.skew_y, self.scale_y)
     }
 
     pub fn flip_y(&self) -> Self {
         FontTransform::new(self.scale_x, -self.skew_y, self.skew_y, -self.scale_y)
     }
 }
 
-impl<'a> From<&'a LayerToWorldTransform> for FontTransform {
-    fn from(xform: &'a LayerToWorldTransform) -> Self {
+impl<'a> From<&'a LayoutToWorldTransform> for FontTransform {
+    fn from(xform: &'a LayoutToWorldTransform) -> Self {
         FontTransform::new(xform.m11, xform.m21, xform.m12, xform.m22)
     }
 }
 
 #[derive(Clone, Hash, PartialEq, Eq, Debug, Ord, PartialOrd)]
 #[cfg_attr(feature = "capture", derive(Serialize))]
 #[cfg_attr(feature = "replay", derive(Deserialize))]
 pub struct FontInstance {
@@ -412,17 +412,17 @@ impl GlyphRasterizer {
         }
 
         let pathfinder_context = create_pathfinder_font_context()?;
 
         Ok(GlyphRasterizer {
             font_contexts: Arc::new(FontContexts {
                 worker_contexts: contexts,
                 shared_context: Mutex::new(shared_context),
-                pathfinder_context: pathfinder_context,
+                pathfinder_context,
                 workers: Arc::clone(&workers),
             }),
             pending_glyphs: 0,
             glyph_rx,
             glyph_tx,
             workers,
             fonts_to_remove: Vec::new(),
             next_gpu_glyph_cache_key: GpuGlyphCacheKey(0),
@@ -499,38 +499,40 @@ impl GlyphRasterizer {
                                                   glyph_key: &GlyphKey,
                                                   font: &FontInstance,
                                                   cached_glyph_info: CachedGlyphInfo,
                                                   texture_cache: &mut TextureCache,
                                                   gpu_cache: &mut GpuCache,
                                                   render_task_cache: &mut RenderTaskCache,
                                                   render_task_tree: &mut RenderTaskTree,
                                                   render_passes: &mut SpecialRenderPasses)
-                                                  -> Result<(CacheItem, GlyphFormat), ()> {
+                                                  -> Result<(RenderTaskCacheEntryHandle,
+                                                             GlyphFormat), ()> {
         let mut pathfinder_font_context = self.font_contexts.lock_pathfinder_context();
         let render_task_cache_key = cached_glyph_info.render_task_cache_key;
         let (glyph_origin, glyph_size) = (cached_glyph_info.origin, render_task_cache_key.size);
         let user_data = [glyph_origin.x as f32, (glyph_origin.y - glyph_size.height) as f32, 1.0];
-        let cache_item = try!(render_task_cache.request_render_task(render_task_cache_key,
-                                                                    texture_cache,
-                                                                    gpu_cache,
-                                                                    render_task_tree,
-                                                                    Some(user_data),
-                                                                    |render_tasks| {
+        let handle = try!(render_task_cache.request_render_task(render_task_cache_key,
+                                                                texture_cache,
+                                                                gpu_cache,
+                                                                render_task_tree,
+                                                                Some(user_data),
+                                                                false,
+                                                                |render_tasks| {
             // TODO(pcwalton): Non-subpixel font render mode.
             request_render_task_from_pathfinder(glyph_key,
                                                 font,
                                                 &glyph_origin,
                                                 &glyph_size,
                                                 &mut *pathfinder_font_context,
                                                 font.render_mode,
                                                 render_tasks,
                                                 render_passes)
         }));
-        Ok((cache_item, font.get_glyph_format()))
+        Ok((handle, font.get_glyph_format()))
     }
 
     #[cfg(feature = "pathfinder")]
     pub fn request_glyphs(
         &mut self,
         glyph_cache: &mut GlyphCache,
         font: FontInstance,
         glyph_keys: &[GlyphKey],
@@ -592,30 +594,30 @@ impl GlyphRasterizer {
                         origin: DeviceIntPoint::new(glyph_dimensions.origin.x as i32,
                                                     -glyph_dimensions.origin.y as i32),
                     };
                     self.next_gpu_glyph_cache_key.0 += 1;
                     cached_glyph_info
                 }
             };
 
-            let cache_entry =
+            let handle =
                 match self.request_glyph_from_pathfinder_if_necessary(glyph_key,
                                                                       &font,
                                                                       cached_glyph_info.clone(),
                                                                       texture_cache,
                                                                       gpu_cache,
                                                                       render_task_cache,
                                                                       render_task_tree,
                                                                       render_passes) {
                     Ok(_) => GlyphCacheEntry::Cached(cached_glyph_info),
                     Err(_) => GlyphCacheEntry::Blank,
                 };
 
-            glyph_key_cache.insert(glyph_key.clone(), cache_entry);
+            glyph_key_cache.insert(glyph_key.clone(), handle);
         }
     }
 
     #[cfg(not(feature = "pathfinder"))]
     pub fn request_glyphs(
         &mut self,
         glyph_cache: &mut GlyphCache,
         font: FontInstance,
@@ -1021,17 +1023,17 @@ fn compute_embolden_amount(ppem: f32) ->
 fn request_render_task_from_pathfinder(glyph_key: &GlyphKey,
                                        font: &FontInstance,
                                        glyph_origin: &DeviceIntPoint,
                                        glyph_size: &DeviceIntSize,
                                        font_context: &mut PathfinderFontContext,
                                        render_mode: FontRenderMode,
                                        render_tasks: &mut RenderTaskTree,
                                        render_passes: &mut SpecialRenderPasses)
-                                       -> Result<(RenderTaskId, bool), ()> {
+                                       -> Result<RenderTaskId, ()> {
     let pathfinder_font_instance = pathfinder_font_renderer::FontInstance {
         font_key: font.font_key.clone(),
         size: font.size,
     };
 
     let pathfinder_subpixel_offset =
         pathfinder_font_renderer::SubpixelOffset(glyph_key.subpixel_offset as u8);
     let glyph_subpixel_offset: f64 = glyph_key.subpixel_offset.into();
@@ -1048,28 +1050,28 @@ fn request_render_task_from_pathfinder(g
 
     // FIXME(pcwalton): Support vertical subpixel offsets.
     // FIXME(pcwalton): Embolden amount should be 0 on macOS if "Use LCD font
     // smoothing" is unchecked in System Preferences.
 
     let subpixel_offset = TypedPoint2D::new(glyph_subpixel_offset as f32, 0.0);
     let embolden_amount = compute_embolden_amount(font.size.to_f32_px());
 
-    let location = RenderTaskLocation::Dynamic(None, *glyph_size);
+    let location = RenderTaskLocation::Dynamic(None, Some(*glyph_size));
     let glyph_render_task = RenderTask::new_glyph(location,
                                                   mesh,
                                                   &glyph_origin,
                                                   &subpixel_offset,
                                                   font.render_mode,
                                                   &embolden_amount);
 
     let root_task_id = render_tasks.add(glyph_render_task);
     let render_pass = match render_mode {
         FontRenderMode::Mono | FontRenderMode::Alpha => &mut render_passes.alpha_glyph_pass,
         FontRenderMode::Subpixel => &mut render_passes.color_glyph_pass,
     };
     render_pass.add_render_task(root_task_id, *glyph_size, RenderTargetKind::Color);
 
-    Ok((root_task_id, false))
+    Ok(root_task_id)
 }
 
 #[cfg(feature = "pathfinder")]
 pub struct NativeFontHandleWrapper<'a>(pub &'a NativeFontHandle);
--- a/gfx/webrender/src/gpu_types.rs
+++ b/gfx/webrender/src/gpu_types.rs
@@ -1,13 +1,13 @@
 /* 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::{DevicePoint, LayerToWorldTransform, WorldToLayerTransform};
+use api::{DevicePoint, LayoutToWorldTransform, WorldToLayoutTransform};
 use gpu_cache::{GpuCacheAddress, GpuDataRequest};
 use prim_store::EdgeAaSegmentMask;
 use render_task::RenderTaskAddress;
 
 // Contains type that must exactly match the same structures declared in GLSL.
 
 #[derive(Copy, Clone, Debug)]
 #[repr(C)]
@@ -78,16 +78,26 @@ pub struct BlurInstance {
 pub struct ClipMaskInstance {
     pub render_task_address: RenderTaskAddress,
     pub scroll_node_data_index: ClipScrollNodeIndex,
     pub segment: i32,
     pub clip_data_address: GpuCacheAddress,
     pub resource_address: GpuCacheAddress,
 }
 
+/// A border corner dot or dash drawn into the clipping mask.
+#[derive(Debug, Copy, Clone)]
+#[cfg_attr(feature = "capture", derive(Serialize))]
+#[cfg_attr(feature = "replay", derive(Deserialize))]
+#[repr(C)]
+pub struct ClipMaskBorderCornerDotDash {
+    pub clip_mask_instance: ClipMaskInstance,
+    pub dot_dash_data: [f32; 8],
+}
+
 // 32 bytes per instance should be enough for anyone!
 #[derive(Debug, Clone)]
 #[cfg_attr(feature = "capture", derive(Serialize))]
 #[cfg_attr(feature = "replay", derive(Deserialize))]
 pub struct PrimitiveInstance {
     data: [i32; 8],
 }
 
@@ -241,27 +251,27 @@ impl From<BrushInstance> for PrimitiveIn
 #[repr(C)]
 pub struct ClipScrollNodeIndex(pub u32);
 
 #[derive(Debug)]
 #[cfg_attr(feature = "capture", derive(Serialize))]
 #[cfg_attr(feature = "replay", derive(Deserialize))]
 #[repr(C)]
 pub struct ClipScrollNodeData {
-    pub transform: LayerToWorldTransform,
-    pub inv_transform: WorldToLayerTransform,
+    pub transform: LayoutToWorldTransform,
+    pub inv_transform: WorldToLayoutTransform,
     pub transform_kind: f32,
     pub padding: [f32; 3],
 }
 
 impl ClipScrollNodeData {
     pub fn invalid() -> Self {
         ClipScrollNodeData {
-            transform: LayerToWorldTransform::identity(),
-            inv_transform: WorldToLayerTransform::identity(),
+            transform: LayoutToWorldTransform::identity(),
+            inv_transform: WorldToLayoutTransform::identity(),
             transform_kind: 0.0,
             padding: [0.0; 3],
         }
     }
 }
 
 #[derive(Copy, Debug, Clone, PartialEq)]
 #[repr(C)]
--- a/gfx/webrender/src/hit_test.rs
+++ b/gfx/webrender/src/hit_test.rs
@@ -1,40 +1,40 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-use api::{BorderRadius, ClipMode, HitTestFlags, HitTestItem, HitTestResult, ItemTag, LayerPoint};
-use api::{LayerPrimitiveInfo, LayerRect, PipelineId, WorldPoint};
+use api::{BorderRadius, ClipMode, HitTestFlags, HitTestItem, HitTestResult, ItemTag, LayoutPoint};
+use api::{LayoutPrimitiveInfo, LayoutRect, PipelineId, WorldPoint};
 use clip::{ClipSource, ClipStore, rounded_rectangle_contains_point};
 use clip_scroll_node::{ClipScrollNode, NodeType};
 use clip_scroll_tree::{ClipChainIndex, ClipScrollNodeIndex, ClipScrollTree};
 use internal_types::FastHashMap;
 use prim_store::ScrollNodeAndClipChain;
-use util::LayerToWorldFastTransform;
+use util::LayoutToWorldFastTransform;
 
 /// A copy of important clip scroll node data to use during hit testing. This a copy of
 /// data from the ClipScrollTree that will persist as a new frame is under construction,
 /// allowing hit tests consistent with the currently rendered frame.
 pub struct HitTestClipScrollNode {
     /// The pipeline id of this node.
     pipeline_id: PipelineId,
 
     /// A particular point must be inside all of these regions to be considered clipped in
     /// for the purposes of a hit test.
     regions: Vec<HitTestRegion>,
 
     /// World transform for content transformed by this node.
-    world_content_transform: LayerToWorldFastTransform,
+    world_content_transform: LayoutToWorldFastTransform,
 
     /// World viewport transform for content transformed by this node.
-    world_viewport_transform: LayerToWorldFastTransform,
+    world_viewport_transform: LayoutToWorldFastTransform,
 
     /// Origin of the viewport of the node, used to calculate node-relative positions.
-    node_origin: LayerPoint,
+    node_origin: LayoutPoint,
 }
 
 /// A description of a clip chain in the HitTester. This is used to describe
 /// hierarchical clip scroll nodes as well as ClipChains, so that they can be
 /// handled the same way during hit testing. Once we represent all ClipChains
 /// using ClipChainDescriptors, we can get rid of this and just use the
 /// ClipChainDescriptor here.
 #[derive(Clone)]
@@ -49,43 +49,43 @@ impl HitTestClipChainDescriptor {
             parent: None,
             clips: Vec::new(),
         }
     }
 }
 
 #[derive(Clone)]
 pub struct HitTestingItem {
-    rect: LayerRect,
-    clip_rect: LayerRect,
+    rect: LayoutRect,
+    clip_rect: LayoutRect,
     tag: ItemTag,
     is_backface_visible: bool,
 }
 
 impl HitTestingItem {
-    pub fn new(tag: ItemTag, info: &LayerPrimitiveInfo) -> HitTestingItem {
+    pub fn new(tag: ItemTag, info: &LayoutPrimitiveInfo) -> HitTestingItem {
         HitTestingItem {
             rect: info.rect,
             clip_rect: info.clip_rect,
-            tag: tag,
+            tag,
             is_backface_visible: info.is_backface_visible,
         }
     }
 }
 
 #[derive(Clone)]
 pub struct HitTestingRun(pub Vec<HitTestingItem>, pub ScrollNodeAndClipChain);
 
 enum HitTestRegion {
-    Rectangle(LayerRect, ClipMode),
-    RoundedRectangle(LayerRect, BorderRadius, ClipMode),
+    Rectangle(LayoutRect, ClipMode),
+    RoundedRectangle(LayoutRect, BorderRadius, ClipMode),
 }
 
 impl HitTestRegion {
-    pub fn contains(&self, point: &LayerPoint) -> bool {
+    pub fn contains(&self, point: &LayoutPoint) -> bool {
         match *self {
             HitTestRegion::Rectangle(ref rectangle, ClipMode::Clip) =>
                 rectangle.contains(point),
             HitTestRegion::Rectangle(ref rectangle, ClipMode::ClipOut) =>
                 !rectangle.contains(point),
             HitTestRegion::RoundedRectangle(rect, radii, ClipMode::Clip) =>
                 rounded_rectangle_contains_point(point, &rect, &radii),
             HitTestRegion::RoundedRectangle(rect, radii, ClipMode::ClipOut) =>
@@ -322,17 +322,17 @@ fn get_regions_for_clip_scroll_node(
         }
     }).collect()
 }
 
 pub struct HitTest {
     pipeline_id: Option<PipelineId>,
     point: WorldPoint,
     flags: HitTestFlags,
-    node_cache: FastHashMap<ClipScrollNodeIndex, Option<LayerPoint>>,
+    node_cache: FastHashMap<ClipScrollNodeIndex, Option<LayoutPoint>>,
     clip_chain_cache: Vec<Option<bool>>,
 }
 
 impl HitTest {
     pub fn new(
         pipeline_id: Option<PipelineId>,
         point: WorldPoint,
         flags: HitTestFlags,
@@ -361,14 +361,14 @@ impl HitTest {
         self.clip_chain_cache[index.0] = Some(value);
     }
 
     pub fn get_absolute_point(&self, hit_tester: &HitTester) -> WorldPoint {
         if !self.flags.contains(HitTestFlags::POINT_RELATIVE_TO_PIPELINE_VIEWPORT) {
             return self.point;
         }
 
-        let point =  &LayerPoint::new(self.point.x, self.point.y);
+        let point =  &LayoutPoint::new(self.point.x, self.point.y);
         self.pipeline_id.map(|id|
             hit_tester.get_pipeline_root(id).world_viewport_transform.transform_point2d(point)
         ).unwrap_or_else(|| WorldPoint::new(self.point.x, self.point.y))
     }
 }
--- a/gfx/webrender/src/image.rs
+++ b/gfx/webrender/src/image.rs
@@ -1,28 +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::{TileOffset, LayerRect, LayerSize, LayerVector2D, DeviceUintSize};
+use api::{TileOffset, LayoutRect, LayoutSize, LayoutVector2D, DeviceUintSize};
 use euclid::rect;
 
 pub struct DecomposedTile {
-    pub rect: LayerRect,
-    pub stretch_size: LayerSize,
+    pub rect: LayoutRect,
+    pub stretch_size: LayoutSize,
     pub tile_offset: TileOffset,
 }
 
 pub struct TiledImageInfo {
     /// The bounds of the item in layout space.
-    pub rect: LayerRect,
+    pub rect: LayoutRect,
     /// The space between each repeated pattern in layout space.
-    pub tile_spacing: LayerSize,
+    pub tile_spacing: LayoutSize,
     /// The size in layout space of each repetition of the image.
-    pub stretch_size: LayerSize,
+    pub stretch_size: LayoutSize,
 
     /// The size the image occupies in the cache in device space.
     pub device_image_size: DeviceUintSize,
     /// The size of the tiles in the cache in device pixels.
     pub device_tile_size: u32,
 }
 
 /// Decomposes an image that is repeated into an image per individual repetition.
@@ -64,17 +64,17 @@ pub fn decompose_image(info: &TiledImage
 
         if let Some(row_rect) = row_rect {
             decompose_row(&row_rect, info, callback);
         }
     }
 }
 
 
-fn decompose_row(item_rect: &LayerRect, info: &TiledImageInfo, callback: &mut FnMut(&DecomposedTile)) {
+fn decompose_row(item_rect: &LayoutRect, info: &TiledImageInfo, callback: &mut FnMut(&DecomposedTile)) {
 
     let no_horizontal_tiling = info.device_image_size.width <= info.device_tile_size;
     let no_horizontal_spacing = info.tile_spacing.width == 0.0;
 
     if no_horizontal_tiling && no_horizontal_spacing {
         decompose_cache_tiles(item_rect, info, callback);
         return;
     }
@@ -93,17 +93,17 @@ fn decompose_row(item_rect: &LayerRect, 
 
         if let Some(decomposed_rect) = decomposed_rect {
             decompose_cache_tiles(&decomposed_rect, info, callback);
         }
     }
 }
 
 fn decompose_cache_tiles(
-    item_rect: &LayerRect,
+    item_rect: &LayoutRect,
     info: &TiledImageInfo,
     callback: &mut FnMut(&DecomposedTile),
 ) {
     // The image resource is tiled. We have to generate an image primitive
     // for each tile.
     // We need to do this because the image is broken up into smaller tiles in the texture
     // cache and the image shader is not able to work with this type of sparse representation.
 
@@ -150,17 +150,17 @@ fn decompose_cache_tiles(
     let num_tiles_x = (info.device_image_size.width / info.device_tile_size) as u16;
     let num_tiles_y = (info.device_image_size.height / info.device_tile_size) as u16;
 
     // Ratio between (image space) tile size and image size.
     let img_dw = tile_size_f32 / (info.device_image_size.width as f32);
     let img_dh = tile_size_f32 / (info.device_image_size.height as f32);
 
     // Stretched size of the tile in layout space.
-    let stretched_tile_size = LayerSize::new(
+    let stretched_tile_size = LayoutSize::new(
         img_dw * info.stretch_size.width,
         img_dh * info.stretch_size.height,
     );
 
     // The size in pixels of the tiles on the right and bottom edges, smaller
     // than the regular tile size if the image is not a multiple of the tile size.
     // Zero means the image size is a multiple of the tile size.
     let leftover = DeviceUintSize::new(
@@ -223,41 +223,41 @@ fn decompose_cache_tiles(
                 shader_repeat_y,
                 callback,
             );
         }
     }
 }
 
 fn add_device_tile(
-    item_rect: &LayerRect,
-    stretched_tile_size: LayerSize,
+    item_rect: &LayoutRect,
+    stretched_tile_size: LayoutSize,
     tile_offset: TileOffset,
     tile_ratio_width: f32,
     tile_ratio_height: f32,
     shader_repeat_x: bool,
     shader_repeat_y: bool,
     callback: &mut FnMut(&DecomposedTile),
 ) {
     // If the image is tiled along a given axis, we can't have the shader compute
     // the image repetition pattern. In this case we base the primitive's rectangle size
     // on the stretched tile size which effectively cancels the repetition (and repetition
     // has to be emulated by generating more primitives).
     // If the image is not tiled along this axis, we can perform the repetition in the
     // shader. In this case we use the item's size in the primitive (on that particular
     // axis).
     // See the shader_repeat_x/y code below.
 
-    let stretch_size = LayerSize::new(
+    let stretch_size = LayoutSize::new(
         stretched_tile_size.width * tile_ratio_width,
         stretched_tile_size.height * tile_ratio_height,
     );
 
-    let mut prim_rect = LayerRect::new(
-        item_rect.origin + LayerVector2D::new(
+    let mut prim_rect = LayoutRect::new(
+        item_rect.origin + LayoutVector2D::new(
             tile_offset.x as f32 * stretched_tile_size.width,
             tile_offset.y as f32 * stretched_tile_size.height,
         ),
         stretch_size,
     );
 
     if shader_repeat_x {
         assert_eq!(tile_offset.x, 0);
--- a/gfx/webrender/src/picture.rs
+++ b/gfx/webrender/src/picture.rs
@@ -1,14 +1,14 @@
 /* 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::{FilterOp, MixBlendMode, PipelineId, PremultipliedColorF};
-use api::{DeviceIntRect, DeviceIntSize, LayerRect};
+use api::{DeviceIntRect, DeviceIntSize, LayoutRect};
 use api::{PictureIntPoint, PictureIntRect, PictureIntSize};
 use box_shadow::{BLUR_SAMPLE_SCALE};
 use clip_scroll_tree::ClipScrollNodeIndex;
 use frame_builder::{FrameBuildingContext, FrameBuildingState, PictureState};
 use gpu_cache::{GpuCacheHandle};
 use prim_store::{PrimitiveIndex, PrimitiveRun, PrimitiveRunLocalRect};
 use prim_store::{PrimitiveMetadata, ScrollNodeAndClipChain};
 use render_task::{ClearMode, RenderTask, RenderTaskCacheEntryHandle};
@@ -146,17 +146,17 @@ pub struct PicturePrimitive {
     // If requested as a frame output (for rendering
     // pages to a texture), this is the pipeline this
     // picture is the root of.
     pub frame_output_pipeline_id: Option<PipelineId>,
     // The original reference frame ID for this picture.
     // It is only different if this is part of a 3D
     // rendering context.
     pub reference_frame_index: ClipScrollNodeIndex,
-    pub real_local_rect: LayerRect,
+    pub real_local_rect: LayoutRect,
     // An optional cache handle for storing extra data
     // in the GPU cache, depending on the type of
     // picture.
     pub extra_gpu_data_handle: GpuCacheHandle,
 
     // Unique identifier for this picture.
     pub id: PictureId,
 }
@@ -190,17 +190,17 @@ impl PicturePrimitive {
         PicturePrimitive {
             runs: Vec::new(),
             surface: None,
             secondary_render_task_id: None,
             composite_mode,
             is_in_3d_context,
             frame_output_pipeline_id,
             reference_frame_index,
-            real_local_rect: LayerRect::zero(),
+            real_local_rect: LayoutRect::zero(),
             extra_gpu_data_handle: GpuCacheHandle::new(),
             apply_local_clip_rect,
             pipeline_id,
             task_rect: DeviceIntRect::zero(),
             id,
         }
     }
 
@@ -222,17 +222,17 @@ impl PicturePrimitive {
             count: 1,
             clip_and_scroll,
         });
     }
 
     pub fn update_local_rect(
         &mut self,
         prim_run_rect: PrimitiveRunLocalRect,
-    ) -> LayerRect {
+    ) -> LayoutRect {
         let local_content_rect = prim_run_rect.local_rect_in_actual_parent_space;
 
         self.real_local_rect = prim_run_rect.local_rect_in_original_parent_space;
 
         match self.composite_mode {
             Some(PictureCompositeMode::Filter(FilterOp::Blur(blur_radius))) => {
                 let inflate_size = (blur_radius * BLUR_SAMPLE_SCALE).ceil();
                 local_content_rect.inflate(inflate_size, inflate_size)
@@ -267,16 +267,21 @@ impl PicturePrimitive {
                 false
             }
             None => {
                 true
             }
         }
     }
 
+    // Disallow subpixel AA if an intermediate surface is needed.
+    pub fn allow_subpixel_aa(&self) -> bool {
+        self.can_draw_directly_to_parent_surface()
+    }
+
     pub fn prepare_for_render_inner(
         &mut self,
         prim_index: PrimitiveIndex,
         prim_metadata: &mut PrimitiveMetadata,
         mut pic_state_for_children: PictureState,
         pic_state: &mut PictureState,
         frame_context: &FrameBuildingContext,
         frame_state: &mut FrameBuildingState,
--- a/gfx/webrender/src/prim_store.rs
+++ b/gfx/webrender/src/prim_store.rs
@@ -1,17 +1,17 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 use api::{AlphaType, BorderRadius, BoxShadowClipMode, BuiltDisplayList, ClipMode, ColorF, ComplexClipRegion};
 use api::{DeviceIntRect, DeviceIntSize, DevicePixelScale, Epoch, ExtendMode, FontRenderMode};
 use api::{FilterOp, GlyphInstance, GlyphKey, GradientStop, ImageKey, ImageRendering, ItemRange, ItemTag};
-use api::{GlyphRasterSpace, LayerPoint, LayerRect, LayerSize, LayerToWorldTransform, LayerVector2D};
-use api::{PipelineId, PremultipliedColorF, Shadow, YuvColorSpace, YuvFormat};
+use api::{GlyphRasterSpace, LayoutPoint, LayoutRect, LayoutSize, LayoutToWorldTransform, LayoutVector2D};
+use api::{PipelineId, PremultipliedColorF, PropertyBinding, Shadow, YuvColorSpace, YuvFormat};
 use border::{BorderCornerInstance, BorderEdgeKind};
 use box_shadow::BLUR_SAMPLE_SCALE;
 use clip_scroll_tree::{ClipChainIndex, ClipScrollNodeIndex, CoordinateSystemId};
 use clip_scroll_node::ClipScrollNode;
 use clip::{ClipChain, ClipChainNode, ClipChainNodeIter, ClipChainNodeRef, ClipSource};
 use clip::{ClipSourcesHandle, ClipWorkItem};
 use frame_builder::{FrameBuildingContext, FrameBuildingState, PictureContext, PictureState};
 use frame_builder::PrimitiveRunContext;
@@ -21,20 +21,21 @@ use gpu_cache::{GpuBlockData, GpuCache, 
 use gpu_types::{ClipChainRectIndex};
 use picture::{PictureCompositeMode, PictureId, PicturePrimitive};
 #[cfg(debug_assertions)]
 use render_backend::FrameId;
 use render_task::{BlitSource, RenderTask, RenderTaskCacheKey};
 use render_task::{RenderTaskCacheKeyKind, RenderTaskId, RenderTaskCacheEntryHandle};
 use renderer::{MAX_VERTEX_TEXTURE_WIDTH};
 use resource_cache::{ImageProperties, ImageRequest};
+use scene::SceneProperties;
 use segment::SegmentBuilder;
 use std::{mem, usize};
 use std::sync::Arc;
-use util::{MatrixHelpers, WorldToLayerFastTransform, calculate_screen_bounding_rect};
+use util::{MatrixHelpers, WorldToLayoutFastTransform, calculate_screen_bounding_rect};
 use util::{pack_as_float, recycle_vec};
 
 
 const MIN_BRUSH_SPLIT_AREA: f32 = 256.0 * 256.0;
 
 #[derive(Clone, Copy, Debug, Eq, PartialEq)]
 pub struct ScrollNodeAndClipChain {
     pub scroll_node_id: ClipScrollNodeIndex,
@@ -105,18 +106,18 @@ impl CachedGradient {
 // for the primitive, to enable the plane splitting
 // logic to work correctly.
 // TODO(gw) In the future, we can probably simplify
 //          this - perhaps calculate the world space
 //          polygons directly and store internally
 //          in the picture structure.
 #[derive(Debug)]
 pub struct PrimitiveRunLocalRect {
-    pub local_rect_in_actual_parent_space: LayerRect,
-    pub local_rect_in_original_parent_space: LayerRect,
+    pub local_rect_in_actual_parent_space: LayoutRect,
+    pub local_rect_in_original_parent_space: LayoutRect,
 }
 
 /// For external images, it's not possible to know the
 /// UV coords of the image (or the image data itself)
 /// until the render thread receives the frame and issues
 /// callbacks to the client application. For external
 /// images that are visible, a DeferredResolve is created
 /// that is stored in the frame. This allows the render
@@ -179,73 +180,116 @@ pub struct PrimitiveMetadata {
     pub prim_kind: PrimitiveKind,
     pub cpu_prim_index: SpecificPrimitiveIndex,
     pub gpu_location: GpuCacheHandle,
     pub clip_task_id: Option<RenderTaskId>,
 
     // TODO(gw): In the future, we should just pull these
     //           directly from the DL item, instead of
     //           storing them here.
-    pub local_rect: LayerRect,
-    pub local_clip_rect: LayerRect,
+    pub local_rect: LayoutRect,
+    pub local_clip_rect: LayoutRect,
     pub clip_chain_rect_index: ClipChainRectIndex,
     pub is_backface_visible: bool,
     pub screen_rect: Option<ScreenRect>,
 
     /// A tag used to identify this primitive outside of WebRender. This is
     /// used for returning useful data during hit testing.
     pub tag: Option<ItemTag>,
 
     /// The last frame ID (of the `RenderTaskTree`) this primitive
     /// was prepared for rendering in.
     #[cfg(debug_assertions)]
     pub prepared_frame_id: FrameId,
 }
 
+// Maintains a list of opacity bindings that have been collapsed into
+// the color of a single primitive. This is an important optimization
+// that avoids allocating an intermediate surface for most common
+// uses of opacity filters.
+#[derive(Debug)]
+pub struct OpacityBinding {
+    bindings: Vec<PropertyBinding<f32>>,
+    current: f32,
+}
+
+impl OpacityBinding {
+    pub fn new() -> OpacityBinding {
+        OpacityBinding {
+            bindings: Vec::new(),
+            current: 1.0,
+        }
+    }
+
+    // Add a new opacity value / binding to the list
+    pub fn push(&mut self, binding: PropertyBinding<f32>) {
+        self.bindings.push(binding);
+    }
+
+    // Resolve the current value of each opacity binding, and
+    // store that as a single combined opacity. Returns true
+    // if the opacity value changed from last time.
+    pub fn update(&mut self, scene_properties: &SceneProperties) -> bool {
+        let mut new_opacity = 1.0;
+
+        for binding in &self.bindings {
+            let opacity = scene_properties.resolve_float(binding, 1.0);
+            new_opacity = new_opacity * opacity;
+        }
+
+        let changed = new_opacity != self.current;
+        self.current = new_opacity;
+
+        changed
+    }
+}
+
 #[derive(Debug)]
 pub enum BrushKind {
     Solid {
         color: ColorF,
+        opacity_binding: OpacityBinding,
     },
     Clear,
     Picture {
         pic_index: PictureIndex,
     },
     Image {
         request: ImageRequest,
         current_epoch: Epoch,
         alpha_type: AlphaType,
-        stretch_size: LayerSize,
-        tile_spacing: LayerSize,
+        stretch_size: LayoutSize,
+        tile_spacing: LayoutSize,
         source: ImageSource,
         sub_rect: Option<DeviceIntRect>,
+        opacity_binding: OpacityBinding,
     },
     YuvImage {
         yuv_key: [ImageKey; 3],
         format: YuvFormat,
         color_space: YuvColorSpace,
         image_rendering: ImageRendering,
     },
     RadialGradient {
         gradient_index: CachedGradientIndex,
         stops_range: ItemRange<GradientStop>,
         extend_mode: ExtendMode,
-        center: LayerPoint,
+        center: LayoutPoint,
         start_radius: f32,
         end_radius: f32,
         ratio_xy: f32,
     },
     LinearGradient {
         gradient_index: CachedGradientIndex,
         stops_range: ItemRange<GradientStop>,
         stops_count: usize,
         extend_mode: ExtendMode,
         reverse_stops: bool,
-        start_point: LayerPoint,
-        end_point: LayerPoint,
+        start_point: LayoutPoint,
+        end_point: LayoutPoint,
     }
 }
 
 impl BrushKind {
     fn supports_segments(&self) -> bool {
         match *self {
             BrushKind::Solid { .. } |
             BrushKind::Image { .. } |
@@ -255,16 +299,24 @@ impl BrushKind {
 
             // TODO(gw): Allow batch.rs to add segment instances
             //           for Picture primitives.
             BrushKind::Picture { .. } => false,
 
             BrushKind::Clear => false,
         }
     }
+
+    // Construct a brush that is a solid color rectangle.
+    pub fn new_solid(color: ColorF) -> BrushKind {
+        BrushKind::Solid {
+            color,
+            opacity_binding: OpacityBinding::new(),
+        }
+    }
 }
 
 bitflags! {
     /// Each bit of the edge AA mask is:
     /// 0, when the edge of the primitive needs to be considered for AA
     /// 1, when the edge of the segment needs to be considered for AA
     ///
     /// *Note*: the bit values have to match the shader logic in
@@ -274,31 +326,31 @@ bitflags! {
         const TOP = 0x2;
         const RIGHT = 0x4;
         const BOTTOM = 0x8;
     }
 }
 
 #[derive(Debug)]
 pub struct BrushSegment {
-    pub local_rect: LayerRect,
+    pub local_rect: LayoutRect,
     pub clip_task_id: Option<RenderTaskId>,
     pub may_need_clip_mask: bool,
     pub edge_flags: EdgeAaSegmentMask,
 }
 
 impl BrushSegment {
     pub fn new(
-        origin: LayerPoint,
-        size: LayerSize,
+        origin: LayoutPoint,
+        size: LayoutSize,
         may_need_clip_mask: bool,
         edge_flags: EdgeAaSegmentMask,
     ) -> BrushSegment {
         BrushSegment {
-            local_rect: LayerRect::new(origin, size),
+            local_rect: LayoutRect::new(origin, size),
             clip_task_id: None,
             may_need_clip_mask,
             edge_flags,
         }
     }
 }
 
 #[derive(Copy, Clone, Debug, PartialEq)]
@@ -342,25 +394,29 @@ impl BrushPrimitive {
 
     fn write_gpu_blocks(
         &self,
         request: &mut GpuDataRequest,
     ) {
         // has to match VECS_PER_SPECIFIC_BRUSH
         match self.kind {
             BrushKind::YuvImage { .. } => {}
-
-            BrushKind::Picture { .. } |
-            BrushKind::Image { .. } => {
+            BrushKind::Picture { .. } => {
                 request.push(PremultipliedColorF::WHITE);
                 request.push(PremultipliedColorF::WHITE);
             }
-
-            BrushKind::Solid { color } => {
-                request.push(color.premultiplied());
+            // Images are drawn as a white color, modulated by the total
+            // opacity coming from any collapsed property bindings.
+            BrushKind::Image { ref opacity_binding, .. } => {
+                request.push(ColorF::new(1.0, 1.0, 1.0, opacity_binding.current).premultiplied());
+                request.push(PremultipliedColorF::WHITE);
+            }
+            // Solid rects also support opacity collapsing.
+            BrushKind::Solid { color, ref opacity_binding, .. } => {
+                request.push(color.scale_alpha(opacity_binding.current).premultiplied());
             }
             BrushKind::Clear => {
                 // Opaque black with operator dest out
                 request.push(PremultipliedColorF::BLACK);
             }
             BrushKind::LinearGradient { start_point, end_point, extend_mode, .. } => {
                 request.push([
                     start_point.x,
@@ -413,19 +469,19 @@ pub enum ImageSource {
     Cache {
         size: DeviceIntSize,
         handle: Option<RenderTaskCacheEntryHandle>,
     },
 }
 
 #[derive(Debug)]
 pub struct ImagePrimitiveCpu {
-    pub tile_spacing: LayerSize,
+    pub tile_spacing: LayoutSize,
     pub alpha_type: AlphaType,
-    pub stretch_size: LayerSize,
+    pub stretch_size: LayoutSize,
     pub current_epoch: Epoch,
     pub source: ImageSource,
     pub key: ImageCacheKey,
 }
 
 impl ToGpuBlocks for ImagePrimitiveCpu {
     fn write_gpu_blocks(&self, mut request: GpuDataRequest) {
         request.push([
@@ -629,29 +685,29 @@ impl<'a> GradientGpuBlockBuilder<'a> {
             request.push(entry.end_color);
         }
     }
 }
 
 #[derive(Debug, Clone)]
 pub struct TextRunPrimitiveCpu {
     pub font: FontInstance,
-    pub offset: LayerVector2D,
+    pub offset: LayoutVector2D,
     pub glyph_range: ItemRange<GlyphInstance>,
     pub glyph_keys: Vec<GlyphKey>,
     pub glyph_gpu_blocks: Vec<GpuBlockData>,
     pub shadow: bool,
     pub glyph_raster_space: GlyphRasterSpace,
 }
 
 impl TextRunPrimitiveCpu {
     pub fn get_font(
         &self,
         device_pixel_scale: DevicePixelScale,
-        transform: Option<LayerToWorldTransform>,
+        transform: Option<LayoutToWorldTransform>,
     ) -> FontInstance {
         let mut font = self.font.clone();
         font.size = font.size.scale_by(device_pixel_scale.0);
         if let Some(transform) = transform {
             if transform.has_perspective_component() ||
                !transform.has_2d_inverse() ||
                self.glyph_raster_space != GlyphRasterSpace::Screen {
                 font.render_mode = font.render_mode.limit_by(FontRenderMode::Alpha);
@@ -660,20 +716,25 @@ impl TextRunPrimitiveCpu {
             }
         }
         font
     }
 
     fn prepare_for_render(
         &mut self,
         device_pixel_scale: DevicePixelScale,
-        transform: Option<LayerToWorldTransform>,
+        transform: Option<LayoutToWorldTransform>,
+        allow_subpixel_aa: bool,
         display_list: &BuiltDisplayList,
         frame_building_state: &mut FrameBuildingState,
     ) {
+        if !allow_subpixel_aa {
+            self.font.render_mode = self.font.render_mode.limit_by(FontRenderMode::Alpha);
+        }
+
         let font = self.get_font(device_pixel_scale, transform);
 
         // Cache the glyph positions, if not in the cache already.
         // TODO(gw): In the future, remove `glyph_instances`
         //           completely, and just reference the glyphs
         //           directly from the display list.
         if self.glyph_keys.is_empty() {
             let subpx_dir = font.subpx_dir.limit_by(font.render_mode);
@@ -729,24 +790,24 @@ impl TextRunPrimitiveCpu {
 
         assert!(request.current_used_block_num() <= MAX_VERTEX_TEXTURE_WIDTH);
     }
 }
 
 #[derive(Debug)]
 #[repr(C)]
 struct ClipRect {
-    rect: LayerRect,
+    rect: LayoutRect,
     mode: f32,
 }
 
 #[derive(Debug)]
 #[repr(C)]
 struct ClipCorner {
-    rect: LayerRect,
+    rect: LayoutRect,
     outer_radius_x: f32,
     outer_radius_y: f32,
     inner_radius_x: f32,
     inner_radius_y: f32,
 }
 
 impl ToGpuBlocks for ClipCorner {
     fn write_gpu_blocks(&self, mut request: GpuDataRequest) {
@@ -760,31 +821,31 @@ impl ClipCorner {
         request.push([
             self.outer_radius_x,
             self.outer_radius_y,
             self.inner_radius_x,
             self.inner_radius_y,
         ]);
     }
 
-    fn uniform(rect: LayerRect, outer_radius: f32, inner_radius: f32) -> ClipCorner {
+    fn uniform(rect: LayoutRect, outer_radius: f32, inner_radius: f32) -> ClipCorner {
         ClipCorner {
             rect,
             outer_radius_x: outer_radius,
             outer_radius_y: outer_radius,
             inner_radius_x: inner_radius,
             inner_radius_y: inner_radius,
         }
     }
 }
 
 #[derive(Debug)]
 #[repr(C)]
 pub struct ImageMaskData {
-    pub local_rect: LayerRect,
+    pub local_rect: LayoutRect,
 }
 
 impl ToGpuBlocks for ImageMaskData {
     fn write_gpu_blocks(&self, mut request: GpuDataRequest) {
         request.push(self.local_rect);
     }
 }
 
@@ -793,111 +854,111 @@ pub struct ClipData {
     rect: ClipRect,
     top_left: ClipCorner,
     top_right: ClipCorner,
     bottom_left: ClipCorner,
     bottom_right: ClipCorner,
 }
 
 impl ClipData {
-    pub fn rounded_rect(rect: &LayerRect, radii: &BorderRadius, mode: ClipMode) -> ClipData {
+    pub fn rounded_rect(rect: &LayoutRect, radii: &BorderRadius, mode: ClipMode) -> ClipData {
         ClipData {
             rect: ClipRect {
                 rect: *rect,
                 mode: mode as u32 as f32,
             },
             top_left: ClipCorner {
-                rect: LayerRect::new(
-                    LayerPoint::new(rect.origin.x, rect.origin.y),
-                    LayerSize::new(radii.top_left.width, radii.top_left.height),
+                rect: LayoutRect::new(
+                    LayoutPoint::new(rect.origin.x, rect.origin.y),
+                    LayoutSize::new(radii.top_left.width, radii.top_left.height),
                 ),
                 outer_radius_x: radii.top_left.width,
                 outer_radius_y: radii.top_left.height,
                 inner_radius_x: 0.0,
                 inner_radius_y: 0.0,
             },
             top_right: ClipCorner {
-                rect: LayerRect::new(
-                    LayerPoint::new(
+                rect: LayoutRect::new(
+                    LayoutPoint::new(
                         rect.origin.x + rect.size.width - radii.top_right.width,
                         rect.origin.y,
                     ),
-                    LayerSize::new(radii.top_right.width, radii.top_right.height),
+                    LayoutSize::new(radii.top_right.width, radii.top_right.height),
                 ),
                 outer_radius_x: radii.top_right.width,
                 outer_radius_y: radii.top_right.height,
                 inner_radius_x: 0.0,
                 inner_radius_y: 0.0,
             },
             bottom_left: ClipCorner {
-                rect: LayerRect::new(
-                    LayerPoint::new(
+                rect: LayoutRect::new(
+                    LayoutPoint::new(
                         rect.origin.x,
                         rect.origin.y + rect.size.height - radii.bottom_left.height,
                     ),
-                    LayerSize::new(radii.bottom_left.width, radii.bottom_left.height),
+                    LayoutSize::new(radii.bottom_left.width, radii.bottom_left.height),
                 ),
                 outer_radius_x: radii.bottom_left.width,
                 outer_radius_y: radii.bottom_left.height,
                 inner_radius_x: 0.0,
                 inner_radius_y: 0.0,
             },
             bottom_right: ClipCorner {
-                rect: LayerRect::new(
-                    LayerPoint::new(
+                rect: LayoutRect::new(
+                    LayoutPoint::new(
                         rect.origin.x + rect.size.width - radii.bottom_right.width,
                         rect.origin.y + rect.size.height - radii.bottom_right.height,
                     ),
-                    LayerSize::new(radii.bottom_right.width, radii.bottom_right.height),
+                    LayoutSize::new(radii.bottom_right.width, radii.bottom_right.height),
                 ),
                 outer_radius_x: radii.bottom_right.width,
                 outer_radius_y: radii.bottom_right.height,
                 inner_radius_x: 0.0,
                 inner_radius_y: 0.0,
             },
         }
     }
 
-    pub fn uniform(rect: LayerRect, radius: f32, mode: ClipMode) -> ClipData {
+    pub fn uniform(rect: LayoutRect, radius: f32, mode: ClipMode) -> ClipData {
         ClipData {
             rect: ClipRect {
                 rect,
                 mode: mode as u32 as f32,
             },
             top_left: ClipCorner::uniform(
-                LayerRect::new(
-                    LayerPoint::new(rect.origin.x, rect.origin.y),
-                    LayerSize::new(radius, radius),
+                LayoutRect::new(
+                    LayoutPoint::new(rect.origin.x, rect.origin.y),
+                    LayoutSize::new(radius, radius),
                 ),
                 radius,
                 0.0,
             ),
             top_right: ClipCorner::uniform(
-                LayerRect::new(
-                    LayerPoint::new(rect.origin.x + rect.size.width - radius, rect.origin.y),
-                    LayerSize::new(radius, radius),
+                LayoutRect::new(
+                    LayoutPoint::new(rect.origin.x + rect.size.width - radius, rect.origin.y),
+                    LayoutSize::new(radius, radius),
                 ),
                 radius,
                 0.0,
             ),
             bottom_left: ClipCorner::uniform(
-                LayerRect::new(
-                    LayerPoint::new(rect.origin.x, rect.origin.y + rect.size.height - radius),
-                    LayerSize::new(radius, radius),
+                LayoutRect::new(
+                    LayoutPoint::new(rect.origin.x, rect.origin.y + rect.size.height - radius),
+                    LayoutSize::new(radius, radius),
                 ),
                 radius,
                 0.0,
             ),
             bottom_right: ClipCorner::uniform(
-                LayerRect::new(
-                    LayerPoint::new(
+                LayoutRect::new(
+                    LayoutPoint::new(
                         rect.origin.x + rect.size.width - radius,
                         rect.origin.y + rect.size.height - radius,
                     ),
-                    LayerSize::new(radius, radius),
+                    LayoutSize::new(radius, radius),
                 ),
                 radius,
                 0.0,
             ),
         }
     }
 
     pub fn write(&self, request: &mut GpuDataRequest) {
@@ -932,17 +993,17 @@ impl PrimitiveContainer {
     //           primitive types to use this.
     pub fn is_visible(&self) -> bool {
         match *self {
             PrimitiveContainer::TextRun(ref info) => {
                 info.font.color.a > 0
             }
             PrimitiveContainer::Brush(ref brush) => {
                 match brush.kind {
-                    BrushKind::Solid { ref color } => {
+                    BrushKind::Solid { ref color, .. } => {
                         color.a > 0.0
                     }
                     BrushKind::Clear |
                     BrushKind::Picture { .. } |
                     BrushKind::Image { .. } |
                     BrushKind::YuvImage { .. } |
                     BrushKind::RadialGradient { .. } |
                     BrushKind::LinearGradient { .. } => {
@@ -982,19 +1043,17 @@ impl PrimitiveContainer {
                     shadow: true,
                     glyph_raster_space: info.glyph_raster_space,
                 })
             }
             PrimitiveContainer::Brush(ref brush) => {
                 match brush.kind {
                     BrushKind::Solid { .. } => {
                         PrimitiveContainer::Brush(BrushPrimitive::new(
-                            BrushKind::Solid {
-                                color: shadow.color,
-                            },
+                            BrushKind::new_solid(shadow.color),
                             None,
                         ))
                     }
                     BrushKind::Clear |
                     BrushKind::Picture { .. } |
                     BrushKind::Image { .. } |
                     BrushKind::YuvImage { .. } |
                     BrushKind::RadialGradient { .. } |
@@ -1072,47 +1131,47 @@ impl PrimitiveStore {
         let picture_index = PictureIndex(self.pictures.len());
         self.pictures.push(picture);
         self.next_picture_id += 1;
         picture_index
     }
 
     pub fn add_primitive(
         &mut self,
-        local_rect: &LayerRect,
-        local_clip_rect: &LayerRect,
+        local_rect: &LayoutRect,
+        local_clip_rect: &LayoutRect,
         is_backface_visible: bool,
         clip_sources: Option<ClipSourcesHandle>,
         tag: Option<ItemTag>,
         container: PrimitiveContainer,
     ) -> PrimitiveIndex {
         let prim_index = self.cpu_metadata.len();
 
         let base_metadata = PrimitiveMetadata {
             clip_sources,
             gpu_location: GpuCacheHandle::new(),
             clip_task_id: None,
             local_rect: *local_rect,
             local_clip_rect: *local_clip_rect,
             clip_chain_rect_index: ClipChainRectIndex(0),
-            is_backface_visible: is_backface_visible,
+            is_backface_visible,
             screen_rect: None,
             tag,
             opacity: PrimitiveOpacity::translucent(),
             prim_kind: PrimitiveKind::Brush,
             cpu_prim_index: SpecificPrimitiveIndex(0),
             #[cfg(debug_assertions)]
             prepared_frame_id: FrameId(0),
         };
 
         let metadata = match container {
             PrimitiveContainer::Brush(brush) => {
                 let opacity = match brush.kind {
                     BrushKind::Clear => PrimitiveOpacity::translucent(),
-                    BrushKind::Solid { ref color } => PrimitiveOpacity::from_alpha(color.a),
+                    BrushKind::Solid { ref color, .. } => PrimitiveOpacity::from_alpha(color.a),
                     BrushKind::Image { .. } => PrimitiveOpacity::translucent(),
                     BrushKind::YuvImage { .. } => PrimitiveOpacity::opaque(),
                     BrushKind::RadialGradient { .. } => PrimitiveOpacity::translucent(),
                     BrushKind::LinearGradient { .. } => PrimitiveOpacity::translucent(),
                     BrushKind::Picture { .. } => PrimitiveOpacity::translucent(),
                 };
 
                 let metadata = PrimitiveMetadata {
@@ -1161,16 +1220,131 @@ impl PrimitiveStore {
             }
         };
 
         self.cpu_metadata.push(metadata);
 
         PrimitiveIndex(prim_index)
     }
 
+    // Internal method that retrieves the primitive index of a primitive
+    // that can be the target for collapsing parent opacity filters into.
+    fn get_opacity_collapse_prim(
+        &self,
+        pic_index: PictureIndex,
+    ) -> Option<PrimitiveIndex> {
+        let pic = &self.pictures[pic_index.0];
+
+        // We can only collapse opacity if there is a single primitive, otherwise
+        // the opacity needs to be applied to the primitives as a group.
+        if pic.runs.len() != 1 {
+            return None;
+        }
+
+        let run = &pic.runs[0];
+        if run.count != 1 {
+            return None;
+        }
+
+        let prim_metadata = &self.cpu_metadata[run.base_prim_index.0];
+
+        // For now, we only support opacity collapse on solid rects and images.
+        // This covers the most common types of opacity filters that can be
+        // handled by this optimization. In the future, we can easily extend
+        // this to other primitives, such as text runs and gradients.
+        match prim_metadata.prim_kind {
+            PrimitiveKind::Brush => {
+                let brush = &self.cpu_brushes[prim_metadata.cpu_prim_index.0];
+                match brush.kind {
+                    BrushKind::Picture { pic_index, .. } => {
+                        let pic = &self.pictures[pic_index.0];
+                        // If we encounter a picture that is a pass-through
+                        // (i.e. no composite mode), then we can recurse into
+                        // that to try and find a primitive to collapse to.
+                        if pic.composite_mode.is_none() {
+                            return self.get_opacity_collapse_prim(pic_index);
+                        }
+                    }
+                    // If we find a single rect or image, we can use that
+                    // as the primitive to collapse the opacity into.
+                    BrushKind::Solid { .. } | BrushKind::Image { .. } => {
+                        return Some(run.base_prim_index)
+                    }
+                    BrushKind::YuvImage { .. } |
+                    BrushKind::LinearGradient { .. } |
+                    BrushKind::RadialGradient { .. } |
+                    BrushKind::Clear => {}
+                }
+            }
+            PrimitiveKind::TextRun |
+            PrimitiveKind::Image |
+            PrimitiveKind::Border => {}
+        }
+
+        None
+    }
+
+    // Apply any optimizations to drawing this picture. Currently,
+    // we just support collapsing pictures with an opacity filter
+    // by pushing that opacity value into the color of a primitive
+    // if that picture contains one compatible primitive.
+    pub fn optimize_picture_if_possible(
+        &mut self,
+        pic_index: PictureIndex,
+    ) {
+        // Only handle opacity filters for now.
+        let binding = match self.pictures[pic_index.0].composite_mode {
+            Some(PictureCompositeMode::Filter(FilterOp::Opacity(binding, _))) => {
+                binding
+            }
+            _ => {
+                return;
+            }
+        };
+
+        // See if this picture contains a single primitive that supports
+        // opacity collapse.
+        if let Some(prim_index) = self.get_opacity_collapse_prim(pic_index) {
+            let prim_metadata = &self.cpu_metadata[prim_index.0];
+            match prim_metadata.prim_kind {
+                PrimitiveKind::Brush => {
+                    let brush = &mut self.cpu_brushes[prim_metadata.cpu_prim_index.0];
+
+                    // By this point, we know we should only have found a primitive
+                    // that supports opacity collapse.
+                    match brush.kind {
+                        BrushKind::Solid { ref mut opacity_binding, .. } |
+                        BrushKind::Image { ref mut opacity_binding, .. } => {
+                            opacity_binding.push(binding);
+                        }
+                        BrushKind::Clear { .. } |
+                        BrushKind::Picture { .. } |
+                        BrushKind::YuvImage { .. } |
+                        BrushKind::LinearGradient { .. } |
+                        BrushKind::RadialGradient { .. } => {
+                            unreachable!("bug: invalid prim type for opacity collapse");
+                        }
+                    };
+                }
+                PrimitiveKind::TextRun |
+                PrimitiveKind::Image |
+                PrimitiveKind::Border => {
+                    unreachable!("bug: invalid prim type for opacity collapse");
+                }
+            }
+
+            // The opacity filter has been collapsed, so mark this picture
+            // as a pass though. This means it will no longer allocate an
+            // intermediate surface or incur an extra blend / blit. Instead,
+            // the collapsed primitive will be drawn directly into the
+            // parent picture.
+            self.pictures[pic_index.0].composite_mode = None;
+        }
+    }
+
     pub fn get_metadata(&self, index: PrimitiveIndex) -> &PrimitiveMetadata {
         &self.cpu_metadata[index.0]
     }
 
     pub fn prim_count(&self) -> usize {
         self.cpu_metadata.len()
     }
 
@@ -1194,16 +1368,17 @@ impl PrimitiveStore {
             PrimitiveKind::Border => {}
             PrimitiveKind::TextRun => {
                 let text = &mut self.cpu_text_runs[metadata.cpu_prim_index.0];
                 // The transform only makes sense for screen space rasterization
                 let transform = Some(prim_run_context.scroll_node.world_content_transform.into());
                 text.prepare_for_render(
                     frame_context.device_pixel_scale,
                     transform,
+                    pic_context.allow_subpixel_aa,
                     pic_context.display_list,
                     frame_state,
                 );
             }
             PrimitiveKind::Image => {
                 let image_cpu = &mut self.cpu_images[metadata.cpu_prim_index.0];
                 let image_properties = frame_state
                     .resource_cache
@@ -1313,30 +1488,37 @@ impl PrimitiveStore {
                         );
                     }
                 }
             }
             PrimitiveKind::Brush => {
                 let brush = &mut self.cpu_brushes[metadata.cpu_prim_index.0];
 
                 match brush.kind {
-                    BrushKind::Image { request, sub_rect, ref mut current_epoch, ref mut source, .. } => {
+                    BrushKind::Image { request, sub_rect, ref mut current_epoch, ref mut source, ref mut opacity_binding, .. } => {
                         let image_properties = frame_state
                             .resource_cache
                             .get_image_properties(request.key);
 
                         // Set if we need to request the source image from the cache this frame.
                         if let Some(image_properties) = image_properties {
-                            // See if this image has been updated since we last hit this code path.
-                            // If so, we need to update the opacity.
-                            if image_properties.epoch != *current_epoch {
-                                *current_epoch = image_properties.epoch;
-                                metadata.opacity.is_opaque = image_properties.descriptor.is_opaque;
+                            *current_epoch = image_properties.epoch;
+
+                            // If the opacity changed, invalidate the GPU cache so that
+                            // the new color for this primitive gets uploaded.
+                            if opacity_binding.update(frame_context.scene_properties) {
+                                frame_state.gpu_cache.invalidate(&mut metadata.gpu_location);
                             }
 
+                            // Update opacity for this primitive to ensure the correct
+                            // batching parameters are used.
+                            metadata.opacity.is_opaque =
+                                image_properties.descriptor.is_opaque &&
+                                opacity_binding.current == 1.0;
+
                             // Work out whether this image is a normal / simple type, or if
                             // we need to pre-render it to the render task cache.
                             if let Some(rect) = sub_rect {
                                 *source = ImageSource::Cache {
                                     // Size in device-pixels we need to allocate in render task cache.
                                     size: rect.size,
                                     handle: None,
                                 };
@@ -1460,17 +1642,26 @@ impl PrimitiveStore {
                             prim_index,
                             metadata,
                             pic_state_for_children,
                             pic_state,
                             frame_context,
                             frame_state,
                         );
                     }
-                    BrushKind::Solid { .. } |
+                    BrushKind::Solid { ref color, ref mut opacity_binding, .. } => {
+                        // If the opacity changed, invalidate the GPU cache so that
+                        // the new color for this primitive gets uploaded. Also update
+                        // the opacity field that controls which batches this primitive
+                        // will be added to.
+                        if opacity_binding.update(frame_context.scene_properties) {
+                            metadata.opacity = PrimitiveOpacity::from_alpha(opacity_binding.current * color.a);
+                            frame_state.gpu_cache.invalidate(&mut metadata.gpu_location);
+                        }
+                    }
                     BrushKind::Clear => {}
                 }
             }
         }
 
         // Mark this GPU resource as required for this frame.
         if let Some(mut request) = frame_state.gpu_cache.request(&mut metadata.gpu_location) {
             // has to match VECS_PER_BRUSH_PRIM
@@ -1626,17 +1817,17 @@ impl PrimitiveStore {
                     local_clip_rect
                 } else {
                     let clip_transform = frame_context
                         .node_data[clip_item.scroll_node_data_index.0 as usize]
                         .transform;
                     let prim_transform = &prim_run_context.scroll_node.world_content_transform;
                     let relative_transform = prim_transform
                         .inverse()
-                        .unwrap_or(WorldToLayerFastTransform::identity())
+                        .unwrap_or(WorldToLayoutFastTransform::identity())
                         .pre_mul(&clip_transform.into());
 
                     relative_transform.transform_rect(&local_clip_rect)
                 };
 
                 segment_builder.push_clip_rect(local_clip_rect, radius, mode);
             }
         }
@@ -1803,17 +1994,17 @@ impl PrimitiveStore {
                         scroll_node_data_index: prim_run_context.scroll_node.node_data_index,
                         clip_sources: clip_sources.weak(),
                         coordinate_system_id: prim_coordinate_system_id,
                     },
                     // The local_clip_rect a property of ClipChain nodes that are ClipScrollNodes.
                     // It's used to calculate a local clipping rectangle before we reach this
                     // point, so we can set it to zero here. It should be unused from this point
                     // on.
-                    local_clip_rect: LayerRect::zero(),
+                    local_clip_rect: LayoutRect::zero(),
                     screen_inner_rect,
                     screen_outer_rect: screen_outer_rect.unwrap_or(prim_screen_rect),
                     prev: None,
                 })
             })
         };
 
         // If everything is clipped out, then we don't need to render this primitive.
@@ -1894,17 +2085,17 @@ impl PrimitiveStore {
     pub fn prepare_prim_for_render(
         &mut self,
         prim_index: PrimitiveIndex,
         prim_run_context: &PrimitiveRunContext,
         pic_context: &PictureContext,
         pic_state: &mut PictureState,
         frame_context: &FrameBuildingContext,
         frame_state: &mut FrameBuildingState,
-    ) -> Option<LayerRect> {
+    ) -> Option<LayoutRect> {
         let mut may_need_clip_mask = true;
         let mut pic_state_for_children = PictureState::new();
 
         // Do some basic checks first, that can early out
         // without even knowing the local rect.
         let (prim_kind, cpu_prim_index) = {
             let metadata = &self.cpu_metadata[prim_index.0];
 
@@ -1961,16 +2152,18 @@ impl PrimitiveStore {
                     PictureContext {
                         pipeline_id: pic.pipeline_id,
                         prim_runs: mem::replace(&mut pic.runs, Vec::new()),
                         original_reference_frame_index: Some(pic.reference_frame_index),
                         display_list,
                         inv_world_transform,
                         apply_local_clip_rect: pic.apply_local_clip_rect,
                         inflation_factor,
+                        // TODO(lsalzman): allow overriding parent if intermediate surface is opaque
+                        allow_subpixel_aa: pic_context.allow_subpixel_aa && pic.allow_subpixel_aa(),
                     }
                 };
 
                 let result = self.prepare_prim_runs(
                     &pic_context_for_children,
                     &mut pic_state_for_children,
                     frame_context,
                     frame_state,
@@ -2071,18 +2264,18 @@ impl PrimitiveStore {
     pub fn prepare_prim_runs(
         &mut self,
         pic_context: &PictureContext,
         pic_state: &mut PictureState,
         frame_context: &FrameBuildingContext,
         frame_state: &mut FrameBuildingState,
     ) -> PrimitiveRunLocalRect {
         let mut result = PrimitiveRunLocalRect {
-            local_rect_in_actual_parent_space: LayerRect::zero(),
-            local_rect_in_original_parent_space: LayerRect::zero(),
+            local_rect_in_actual_parent_space: LayoutRect::zero(),
+            local_rect_in_original_parent_space: LayoutRect::zero(),
         };
 
         for run in &pic_context.prim_runs {
             // TODO(gw): Perhaps we can restructure this to not need to create
             //           a new primitive context for every run (if the hash
             //           lookups ever show up in a profile).
             let scroll_node = &frame_context
                 .clip_scroll_tree
@@ -2233,27 +2426,27 @@ fn convert_clip_chain_to_clip_vector(
             Some(node.work_item.clone())
         })
         .collect()
 }
 
 fn get_local_clip_rect_for_nodes(
     scroll_node: &ClipScrollNode,
     clip_chain: &ClipChain,
-) -> Option<LayerRect> {
+) -> Option<LayoutRect> {
     let local_rect = ClipChainNodeIter { current: clip_chain.nodes.clone() }.fold(
         None,
-        |combined_local_clip_rect: Option<LayerRect>, node| {
+        |combined_local_clip_rect: Option<LayoutRect>, node| {
             if node.work_item.coordinate_system_id != scroll_node.coordinate_system_id {
                 return combined_local_clip_rect;
             }
 
             Some(match combined_local_clip_rect {
                 Some(combined_rect) =>
-                    combined_rect.intersection(&node.local_clip_rect).unwrap_or_else(LayerRect::zero),
+                    combined_rect.intersection(&node.local_clip_rect).unwrap_or_else(LayoutRect::zero),
                 None => node.local_clip_rect,
             })
         }
     );
 
     match local_rect {
         Some(local_rect) => scroll_node.coordinate_system_relative_transform.unapply(&local_rect),
         None => None,
@@ -2263,17 +2456,17 @@ fn get_local_clip_rect_for_nodes(
 impl<'a> GpuDataRequest<'a> {
     // Write the GPU cache data for an individual segment.
     // TODO(gw): The second block is currently unused. In
     //           the future, it will be used to store a
     //           UV rect, allowing segments to reference
     //           part of an image.
     fn write_segment(
         &mut self,
-        local_rect: LayerRect,
+        local_rect: LayoutRect,
     ) {
         self.push(local_rect);
         self.push([
             1.0,
             1.0,
             0.0,
             0.0
         ]);
--- a/gfx/webrender/src/render_backend.rs
+++ b/gfx/webrender/src/render_backend.rs
@@ -2,17 +2,17 @@
  * 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::{ApiMsg, BuiltDisplayList, ClearCache, DebugCommand};
 #[cfg(feature = "debugger")]
 use api::{BuiltDisplayListIter, SpecificDisplayItem};
 use api::{DeviceIntPoint, DevicePixelScale, DeviceUintPoint, DeviceUintRect, DeviceUintSize};
 use api::{DocumentId, DocumentLayer, ExternalScrollId, FrameMsg, HitTestResult};
-use api::{IdNamespace, LayerPoint, PipelineId, RenderNotifier, SceneMsg, ScrollClamping};
+use api::{IdNamespace, LayoutPoint, PipelineId, RenderNotifier, SceneMsg, ScrollClamping};
 use api::{ScrollLocation, ScrollNodeState, TransactionMsg, WorldPoint};
 use api::channel::{MsgReceiver, Payload};
 #[cfg(feature = "capture")]
 use api::CaptureBits;
 #[cfg(feature = "replay")]
 use api::CapturedDocument;
 use clip_scroll_tree::ClipScrollTree;
 #[cfg(feature = "debugger")]
@@ -322,17 +322,17 @@ impl Document {
         cursor: WorldPoint,
     ) -> bool {
         self.clip_scroll_tree.scroll(scroll_location, cursor)
     }
 
     /// Returns true if the node actually changed position or false otherwise.
     pub fn scroll_node(
         &mut self,
-        origin: LayerPoint,
+        origin: LayoutPoint,
         id: ExternalScrollId,
         clamp: ScrollClamping
     ) -> bool {
         self.clip_scroll_tree.scroll_node(origin, id, clamp)
     }
 
     pub fn get_scroll_node_state(&self) -> Vec<ScrollNodeState> {
         self.clip_scroll_tree.get_scroll_node_state()
@@ -726,32 +726,44 @@ impl RenderBackend {
                         if !transaction_msg.is_empty() {
                             self.update_document(
                                 document_id,
                                 transaction_msg,
                                 &mut frame_counter,
                                 &mut profile_counters
                             );
                         }
+                    },
+                    SceneBuilderResult::Stopped => {
+                        panic!("We haven't sent a Stop yet, how did we get a Stopped back?");
                     }
                 }
             }
 
             keep_going = match self.api_rx.recv() {
                 Ok(msg) => {
                     if let Some(ref mut r) = self.recorder {
                         r.write_msg(frame_counter, &msg);
                     }
                     self.process_api_msg(msg, &mut profile_counters, &mut frame_counter)
                 }
                 Err(..) => { false }
             };
         }
 
         let _ = self.scene_tx.send(SceneBuilderRequest::Stop);
+        // Ensure we read everything the scene builder is sending us from
+        // inflight messages, otherwise the scene builder might panic.
+        while let Ok(msg) = self.scene_rx.recv() {
+            match msg {
+                SceneBuilderResult::Stopped => break,
+                _ => continue,
+            }
+        }
+
         self.notifier.shut_down();
 
         if let Some(ref sampler) = self.sampler {
             sampler.deregister();
         }
 
     }
 
@@ -1029,18 +1041,18 @@ impl RenderBackend {
                 pending_update,
                 profile_counters.clone()
             );
             self.result_tx.send(msg).unwrap();
             profile_counters.reset();
             doc.render_on_hittest = false;
         }
 
-        if op.render || op.scroll {
-            self.notifier.new_document_ready(document_id, op.scroll, op.composite);
+        if transaction_msg.generate_frame {
+            self.notifier.new_frame_ready(document_id, op.scroll, op.composite);
         }
     }
 
     #[cfg(not(feature = "debugger"))]
     fn get_docs_for_debugger(&self) -> String {
         String::new()
     }
 
@@ -1323,14 +1335,14 @@ impl RenderBackend {
                 id,
                 render_doc,
                 self.resource_cache.pending_updates(),
                 profile_counters.clone(),
             );
             self.result_tx.send(msg_publish).unwrap();
             profile_counters.reset();
 
-            self.notifier.new_document_ready(id, false, true);
+            self.notifier.new_frame_ready(id, false, true);
             self.documents.insert(id, doc);
         }
     }
 }
 
--- a/gfx/webrender/src/renderer.rs
+++ b/gfx/webrender/src/renderer.rs
@@ -11,33 +11,32 @@
 
 use api::{BlobImageRenderer, ColorF, DeviceIntPoint, DeviceIntRect, DeviceIntSize};
 use api::{DeviceUintPoint, DeviceUintRect, DeviceUintSize, DocumentId, Epoch, ExternalImageId};
 use api::{ExternalImageType, FontRenderMode, FrameMsg, ImageFormat, PipelineId};
 use api::{RenderApiSender, RenderNotifier, TexelRect, TextureTarget};
 use api::{channel};
 use api::DebugCommand;
 use api::channel::PayloadReceiverHelperMethods;
-use batch::{BatchKey, BatchKind, BatchTextures, BrushBatchKind, TransformBatchKind};
+use batch::{BatchKind, BatchTextures, BrushBatchKind, TransformBatchKind};
 #[cfg(any(feature = "capture", feature = "replay"))]
 use capture::{CaptureConfig, ExternalCaptureImage, PlainExternalImage};
 use debug_colors;
 use device::{DepthFunction, Device, FrameId, Program, UploadMethod, Texture, PBO};
 use device::{ExternalTexture, FBOId, TextureSlot};
 use device::{FileWatcherHandler, ShaderError, TextureFilter,
              VertexUsageHint, VAO, VBO, CustomVAO};
 use device::{ProgramCache, ReadPixelsFormat};
 use euclid::{rect, Transform3D};
 use frame_builder::FrameBuilderConfig;
 use gleam::gl;
 use glyph_rasterizer::{GlyphFormat, GlyphRasterizer};
 use gpu_cache::{GpuBlockData, GpuCacheUpdate, GpuCacheUpdateList};
 #[cfg(feature = "pathfinder")]
 use gpu_glyph_renderer::GpuGlyphRenderer;
-use gpu_types::PrimitiveInstance;
 use internal_types::{SourceTexture, ORTHO_FAR_PLANE, ORTHO_NEAR_PLANE, ResourceCacheError};
 use internal_types::{CacheTextureId, DebugOutput, FastHashMap, RenderedDocument, ResultMsg};
 use internal_types::{TextureUpdateList, TextureUpdateOp, TextureUpdateSource};
 use internal_types::{RenderTargetInfo, SavedTargetIndex};
 use prim_store::DeferredResolve;
 use profiler::{BackendProfileCounters, FrameProfileCounters,
                GpuProfileTag, RendererProfileCounters, RendererProfileTimers};
 use query::GpuProfiler;
@@ -263,17 +262,20 @@ fn flag_changed(before: DebugFlags, afte
     if before & select != after & select {
         Some(after.contains(select))
     } else {
         None
     }
 }
 
 #[repr(C)]
+#[derive(Copy, Clone, Debug)]
 pub enum ShaderColorMode {
+    FromRenderPassMode = 0,
+
     Alpha = 1,
     SubpixelConstantTextColor = 2,
     SubpixelWithBgColorPass0 = 3,
     SubpixelWithBgColorPass1 = 4,
     SubpixelWithBgColorPass2 = 5,
     SubpixelDualSource = 6,
     Bitmap = 7,
     ColorBitmap = 8,
@@ -426,16 +428,58 @@ pub(crate) mod desc {
             VertexAttribute {
                 name: "aClipDataResourceAddress",
                 count: 4,
                 kind: VertexAttributeKind::U16,
             },
         ],
     };
 
+    pub const BORDER_CORNER_DASH_AND_DOT: VertexDescriptor = VertexDescriptor {
+        vertex_attributes: &[
+            VertexAttribute {
+                name: "aPosition",
+                count: 2,
+                kind: VertexAttributeKind::F32,
+            },
+        ],
+        instance_attributes: &[
+            VertexAttribute {
+                name: "aClipRenderTaskAddress",
+                count: 1,
+                kind: VertexAttributeKind::I32,
+            },
+            VertexAttribute {
+                name: "aScrollNodeId",
+                count: 1,
+                kind: VertexAttributeKind::I32,
+            },
+            VertexAttribute {
+                name: "aClipSegment",
+                count: 1,
+                kind: VertexAttributeKind::I32,
+            },
+            VertexAttribute {
+                name: "aClipDataResourceAddress",
+                count: 4,
+                kind: VertexAttributeKind::U16,
+            },
+            VertexAttribute {
+                name: "aDashOrDot0",
+                count: 4,
+                kind: VertexAttributeKind::F32,
+            },
+            VertexAttribute {
+                name: "aDashOrDot1",
+                count: 4,
+                kind: VertexAttributeKind::F32,
+            },
+        ],
+    };
+
     pub const GPU_CACHE_UPDATE: VertexDescriptor = VertexDescriptor {
         vertex_attributes: &[
             VertexAttribute {
                 name: "aPosition",
                 count: 2,
                 kind: VertexAttributeKind::U16Norm,
             },
             VertexAttribute {
@@ -532,16 +576,17 @@ pub(crate) mod desc {
     };
 }
 
 #[derive(Debug, Copy, Clone)]
 pub(crate) enum VertexArrayKind {
     Primitive,
     Blur,
     Clip,
+    DashAndDot,
     VectorStencil,
     VectorCover,
 }
 
 #[derive(Clone, Debug, PartialEq)]
 pub enum GraphicsApi {
     OpenGL,
 }
@@ -1253,16 +1298,17 @@ impl LazyInitializedDebugRenderer {
         }
     }
 }
 
 pub struct RendererVAOs {
     prim_vao: VAO,
     blur_vao: VAO,
     clip_vao: VAO,
+    dash_and_dot_vao: VAO,
 }
 
 /// The renderer is responsible for submitting to the GPU the work prepared by the
 /// RenderBackend.
 pub struct Renderer {
     result_rx: Receiver<ResultMsg>,
     debug_server: DebugServer,
     pub device: Device,
@@ -1539,16 +1585,18 @@ impl Renderer {
         device.update_vao_main_vertices(&prim_vao, &quad_vertices, VertexUsageHint::Static);
 
         let gpu_glyph_renderer = try!(GpuGlyphRenderer::new(&mut device,
                                                             &prim_vao,
                                                             options.precache_shaders));
 
         let blur_vao = device.create_vao_with_new_instances(&desc::BLUR, &prim_vao);
         let clip_vao = device.create_vao_with_new_instances(&desc::CLIP, &prim_vao);
+        let dash_and_dot_vao =
+            device.create_vao_with_new_instances(&desc::BORDER_CORNER_DASH_AND_DOT, &prim_vao);
         let texture_cache_upload_pbo = device.create_pbo();
 
         let texture_resolver = SourceTextureResolver::new(&mut device);
 
         let node_data_texture = VertexDataTexture::new(&mut device);
         let local_clip_rects_texture = VertexDataTexture::new(&mut device);
         let render_task_texture = VertexDataTexture::new(&mut device);
 
@@ -1691,16 +1739,17 @@ impl Renderer {
             enable_clear_scissor: options.enable_clear_scissor,
             last_time: 0,
             gpu_profile,
             gpu_glyph_renderer,
             vaos: RendererVAOs {
                 prim_vao,
                 blur_vao,
                 clip_vao,
+                dash_and_dot_vao,
             },
             node_data_texture,
             local_clip_rects_texture,
             render_task_texture,
             pipeline_info: PipelineInfo::default(),
             dither_matrix_texture,
             external_image_handler: None,
             output_image_handler: None,
@@ -2606,58 +2655,16 @@ impl Renderer {
         // Note: leaving the viewport unchanged, it's not a part of FBO state
         self.device.bind_draw_target(render_target, None);
 
         if scissor_rect.is_some() {
             self.device.enable_scissor();
         }
     }
 
-    fn submit_batch(
-        &mut self,
-        key: &BatchKey,
-        instances: &[PrimitiveInstance],
-        projection: &Transform3D<f32>,
-        render_tasks: &RenderTaskTree,
-        render_target: Option<(&Texture, i32)>,
-        framebuffer_size: DeviceUintSize,
-        stats: &mut RendererStats,
-        scissor_rect: Option<DeviceIntRect>,
-    ) {
-        self.shaders
-            .get(key)
-            .bind(
-                &mut self.device, projection,
-                &mut self.renderer_errors,
-            );
-
-        // Handle special case readback for composites.
-        if let BatchKind::Brush(BrushBatchKind::MixBlend { task_id, source_id, backdrop_id }) = key.kind {
-            // composites can't be grouped together because
-            // they may overlap and affect each other.
-            debug_assert_eq!(instances.len(), 1);
-            self.handle_readback_composite(
-                render_target,
-                framebuffer_size,
-                scissor_rect,
-                &render_tasks[source_id],
-                &render_tasks[task_id],
-                &render_tasks[backdrop_id],
-            );
-        }
-
-        let _timer = self.gpu_profile.start_timer(key.kind.sampler_tag());
-        self.draw_instanced_batch(
-            instances,
-            VertexArrayKind::Primitive,
-            &key.textures,
-            stats
-        );
-    }
-
     fn handle_blits(
         &mut self,
         blits: &[BlitJob],
         render_tasks: &RenderTaskTree,
     ) {
         if blits.is_empty() {
             return;
         }
@@ -2842,186 +2849,134 @@ impl Renderer {
 
                 // Draw opaque batches front-to-back for maximum
                 // z-buffer efficiency!
                 for batch in alpha_batch_container
                     .opaque_batches
                     .iter()
                     .rev()
                 {
-                    self.submit_batch(
-                        &batch.key,
+                    self.shaders
+                        .get(&batch.key)
+                        .bind(
+                            &mut self.device, projection,
+                            &mut self.renderer_errors,
+                        );
+
+                    let _timer = self.gpu_profile.start_timer(batch.key.kind.sampler_tag());
+                    self.draw_instanced_batch(
                         &batch.instances,
-                        projection,
-                        render_tasks,
-                        render_target,
-                        target_size,
-                        stats,
-                        alpha_batch_container.target_rect,
+                        VertexArrayKind::Primitive,
+                        &batch.key.textures,
+                        stats
                     );
                 }
 
                 if alpha_batch_container.target_rect.is_some() {
                     self.device.disable_scissor();
                 }
             }
 
             self.device.disable_depth_write();
             self.gpu_profile.finish_sampler(opaque_sampler);
         }
 
         let _gl = self.gpu_profile.start_marker("alpha batches");
         let transparent_sampler = self.gpu_profile.start_sampler(GPU_SAMPLER_TAG_TRANSPARENT);
-        self.device.set_blend(false);
+        self.device.set_blend(true);
         let mut prev_blend_mode = BlendMode::None;
 
         for alpha_batch_container in &target.alpha_batch_containers {
             if let Some(target_rect) = alpha_batch_container.target_rect {
                 self.device.enable_scissor();
                 self.device.set_scissor_rect(target_rect);
             }
 
             for batch in &alpha_batch_container.alpha_batches {
-                match batch.key.kind {
-                    BatchKind::Transformable(transform_kind, TransformBatchKind::TextRun(glyph_format)) => {
-                        // Text run batches are handled by this special case branch.
-                        // In the case of subpixel text, we draw it as a two pass
-                        // effect, to ensure we can apply clip masks correctly.
-                        // In the future, there are several optimizations available:
-                        // 1) Use dual source blending where available (almost all recent hardware).
-                        // 2) Use frame buffer fetch where available (most modern hardware).
-                        // 3) Consider the old constant color blend method where no clip is applied.
-                        let _timer = self.gpu_profile.start_timer(GPU_TAG_PRIM_TEXT_RUN);
-
-                        self.device.set_blend(true);
-                        // bind the proper shader first
-                        match batch.key.blend_mode {
-                            BlendMode::SubpixelDualSource => &mut self.shaders.ps_text_run_dual_source,
-                            _ => &mut self.shaders.ps_text_run,
+                if batch.key.blend_mode != prev_blend_mode {
+                    match batch.key.blend_mode {
+                        BlendMode::None => {
+                            unreachable!("bug: opaque blend in alpha pass");
+                        }
+                        BlendMode::Alpha => {
+                            self.device.set_blend_mode_alpha();
+                        }
+                        BlendMode::PremultipliedAlpha => {
+                            self.device.set_blend_mode_premultiplied_alpha();
+                        }
+                        BlendMode::PremultipliedDestOut => {
+                            self.device.set_blend_mode_premultiplied_dest_out();
+                        }
+                        BlendMode::SubpixelDualSource => {
+                            self.device.set_blend_mode_subpixel_dual_source();
+                        }
+                        BlendMode::SubpixelConstantTextColor(color) => {
+                            self.device.set_blend_mode_subpixel_constant_text_color(color);
+                        }
+                        BlendMode::SubpixelWithBgColor => {
+                            // Using the three pass "component alpha with font smoothing
+                            // background color" rendering technique:
+                            //
+                            // /webrender/doc/text-rendering.md
+                            //
+                            self.device.set_blend_mode_subpixel_with_bg_color_pass0();
+                            self.device.switch_mode(ShaderColorMode::SubpixelWithBgColorPass0 as _);
                         }
-                            .get(glyph_format, transform_kind)
-                            .bind(
-                                &mut self.device,
-                                projection,
-                                &mut self.renderer_errors,
-                            );
-
-                        match batch.key.blend_mode {
-                            BlendMode::Alpha => panic!("Attempt to composite non-premultiplied text primitives."),
-                            BlendMode::PremultipliedAlpha => {
-                                self.device.set_blend_mode_premultiplied_alpha();
-                                self.device.switch_mode(ShaderColorMode::from(glyph_format) as _);
-
-                                self.draw_instanced_batch(
-                                    &batch.instances,
-                                    VertexArrayKind::Primitive,
-                                    &batch.key.textures,
-                                    stats,
-                                );
-                            }
-                            BlendMode::SubpixelDualSource => {
-                                self.device.set_blend_mode_subpixel_dual_source();
-                                self.device.switch_mode(ShaderColorMode::SubpixelDualSource as _);
-
-                                self.draw_instanced_batch(
-                                    &batch.instances,
-                                    VertexArrayKind::Primitive,
-                                    &batch.key.textures,
-                                    stats,
-                                );
-                            }
-                            BlendMode::SubpixelConstantTextColor(color) => {
-                                self.device.set_blend_mode_subpixel_constant_text_color(color);
-                                self.device.switch_mode(ShaderColorMode::SubpixelConstantTextColor as _);
-
-                                self.draw_instanced_batch(
-                                    &batch.instances,
-                                    VertexArrayKind::Primitive,
-                                    &batch.key.textures,
-                                    stats,
-                                );
-                            }
-                            BlendMode::SubpixelWithBgColor => {
-                                // Using the three pass "component alpha with font smoothing
-                                // background color" rendering technique:
-                                //
-                                // /webrender/doc/text-rendering.md
-                                //
-                                self.device.set_blend_mode_subpixel_with_bg_color_pass0();
-                                self.device.switch_mode(ShaderColorMode::SubpixelWithBgColorPass0 as _);
-
-                                self.draw_instanced_batch(
-                                    &batch.instances,
-                                    VertexArrayKind::Primitive,
-                                    &batch.key.textures,
-                                    stats,
-                                );
-
-                                self.device.set_blend_mode_subpixel_with_bg_color_pass1();
-                                self.device.switch_mode(ShaderColorMode::SubpixelWithBgColorPass1 as _);
-
-                                // When drawing the 2nd and 3rd passes, we know that the VAO, textures etc
-                                // are all set up from the previous draw_instanced_batch call,
-                                // so just issue a draw call here to avoid re-uploading the
-                                // instances and re-binding textures etc.
-                                self.device
-                                    .draw_indexed_triangles_instanced_u16(6, batch.instances.len() as i32);
-
-                                self.device.set_blend_mode_subpixel_with_bg_color_pass2();
-                                self.device.switch_mode(ShaderColorMode::SubpixelWithBgColorPass2 as _);
-
-                                self.device
-                                    .draw_indexed_triangles_instanced_u16(6, batch.instances.len() as i32);
-                            }
-                            BlendMode::PremultipliedDestOut | BlendMode::None => {
-                                unreachable!("bug: bad blend mode for text");
-                            }
-                        }
-
-                        prev_blend_mode = BlendMode::None;
-                        self.device.set_blend(false);
                     }
-                    _ => {
-                        if batch.key.blend_mode != prev_blend_mode {
-                            match batch.key.blend_mode {
-                                BlendMode::None => {
-                                    self.device.set_blend(false);
-                                }
-                                BlendMode::Alpha => {
-                                    self.device.set_blend(true);
-                                    self.device.set_blend_mode_alpha();
-                                }
-                                BlendMode::PremultipliedAlpha => {
-                                    self.device.set_blend(true);
-                                    self.device.set_blend_mode_premultiplied_alpha();
-                                }
-                                BlendMode::PremultipliedDestOut => {
-                                    self.device.set_blend(true);
-                                    self.device.set_blend_mode_premultiplied_dest_out();
-                                }
-                                BlendMode::SubpixelConstantTextColor(..) |
-                                BlendMode::SubpixelWithBgColor |
-                                BlendMode::SubpixelDualSource => {
-                                    unreachable!("bug: subpx text handled earlier");
-                                }
-                            }
-                            prev_blend_mode = batch.key.blend_mode;
-                        }
-
-                        self.submit_batch(
-                            &batch.key,
-                            &batch.instances,
-                            projection,
-                            render_tasks,
-                            render_target,
-                            target_size,
-                            stats,
-                            alpha_batch_container.target_rect,
-                        );
-                    }
+                    prev_blend_mode = batch.key.blend_mode;
+                }
+
+                self.shaders
+                    .get(&batch.key)
+                    .bind(
+                        &mut self.device, projection,
+                        &mut self.renderer_errors,
+                    );
+
+                // Handle special case readback for composites.
+                if let BatchKind::Brush(BrushBatchKind::MixBlend { task_id, source_id, backdrop_id }) = batch.key.kind {
+                    // composites can't be grouped together because
+                    // they may overlap and affect each other.
+                    debug_assert_eq!(batch.instances.len(), 1);
+                    self.handle_readback_composite(
+                        render_target,
+                        target_size,
+                        alpha_batch_container.target_rect,
+                        &render_tasks[source_id],
+                        &render_tasks[task_id],
+                        &render_tasks[backdrop_id],
+                    );
+                }
+
+                let _timer = self.gpu_profile.start_timer(batch.key.kind.sampler_tag());
+                self.draw_instanced_batch(
+                    &batch.instances,
+                    VertexArrayKind::Primitive,
+                    &batch.key.textures,
+                    stats
+                );
+
+                if batch.key.blend_mode == BlendMode::SubpixelWithBgColor {
+                    self.device.set_blend_mode_subpixel_with_bg_color_pass1();
+                    self.device.switch_mode(ShaderColorMode::SubpixelWithBgColorPass1 as _);
+
+                    // When drawing the 2nd and 3rd passes, we know that the VAO, textures etc
+                    // are all set up from the previous draw_instanced_batch call,
+                    // so just issue a draw call here to avoid re-uploading the
+                    // instances and re-binding textures etc.
+                    self.device
+                        .draw_indexed_triangles_instanced_u16(6, batch.instances.len() as i32);
+
+                    self.device.set_blend_mode_subpixel_with_bg_color_pass2();
+                    self.device.switch_mode(ShaderColorMode::SubpixelWithBgColorPass2 as _);
+
+                    self.device
+                        .draw_indexed_triangles_instanced_u16(6, batch.instances.len() as i32);
+
+                    prev_blend_mode = BlendMode::None;
                 }
             }
 
             if alpha_batch_container.target_rect.is_some() {
                 self.device.disable_scissor();
             }
         }
 
@@ -3152,17 +3107,17 @@ impl Renderer {
             // in regions below.
             if !target.clip_batcher.border_clears.is_empty() {
                 let _gm2 = self.gpu_profile.start_marker("clip borders [clear]");
                 self.device.set_blend(false);
                 self.shaders.cs_clip_border
                     .bind(&mut self.device, projection, &mut self.renderer_errors);
                 self.draw_instanced_batch(
                     &target.clip_batcher.border_clears,
-                    VertexArrayKind::Clip,
+                    VertexArrayKind::DashAndDot,
                     &BatchTextures::no_texture(),
                     stats,
                 );
             }
 
             // Draw any dots or dashes for border corners.
             if !target.clip_batcher.borders.is_empty() {
                 let _gm2 = self.gpu_profile.start_marker("clip borders");
@@ -3171,17 +3126,17 @@ impl Renderer {
                 // The individual dots and dashes in a border never overlap, so using
                 // a max blend mode here is fine.
                 self.device.set_blend(true);
                 self.device.set_blend_mode_max();
                 self.shaders.cs_clip_border
                     .bind(&mut self.device, projection, &mut self.renderer_errors);
                 self.draw_instanced_batch(
                     &target.clip_batcher.borders,
-                    VertexArrayKind::Clip,
+                    VertexArrayKind::DashAndDot,
                     &BatchTextures::no_texture(),
                     stats,
                 );
             }
 
             // switch to multiplicative blending
             self.device.set_blend(true);
             self.device.set_blend_mode_multiply();
@@ -3904,16 +3859,17 @@ impl Renderer {
         self.node_data_texture.deinit(&mut self.device);
         self.local_clip_rects_texture.deinit(&mut self.device);
         self.render_task_texture.deinit(&mut self.device);
         self.device.delete_pbo(self.texture_cache_upload_pbo);
         self.texture_resolver.deinit(&mut self.device);
         self.device.delete_vao(self.vaos.prim_vao);
         self.device.delete_vao(self.vaos.clip_vao);
         self.device.delete_vao(self.vaos.blur_vao);
+        self.device.delete_vao(self.vaos.dash_and_dot_vao);
 
         #[cfg(feature = "debug_renderer")]
         {
             self.debug.deinit(&mut self.device);
         }
 
         for (_, target) in self.output_targets {
             self.device.delete_fbo(target.fbo_id);
@@ -4496,25 +4452,27 @@ impl Renderer {
 fn get_vao<'a>(vertex_array_kind: VertexArrayKind,
                vaos: &'a RendererVAOs,
                gpu_glyph_renderer: &'a GpuGlyphRenderer)
                -> &'a VAO {
     match vertex_array_kind {
         VertexArrayKind::Primitive => &vaos.prim_vao,
         VertexArrayKind::Clip => &vaos.clip_vao,
         VertexArrayKind::Blur => &vaos.blur_vao,
+        VertexArrayKind::DashAndDot => &vaos.dash_and_dot_vao,
         VertexArrayKind::VectorStencil => &gpu_glyph_renderer.vector_stencil_vao,
         VertexArrayKind::VectorCover => &gpu_glyph_renderer.vector_cover_vao,
     }
 }
 
 #[cfg(not(feature = "pathfinder"))]
 fn get_vao<'a>(vertex_array_kind: VertexArrayKind,
                vaos: &'a RendererVAOs,
                _: &'a GpuGlyphRenderer)
                -> &'a VAO {
     match vertex_array_kind {
         VertexArrayKind::Primitive => &vaos.prim_vao,
         VertexArrayKind::Clip => &vaos.clip_vao,
         VertexArrayKind::Blur => &vaos.blur_vao,
+        VertexArrayKind::DashAndDot => &vaos.dash_and_dot_vao,
         VertexArrayKind::VectorStencil | VertexArrayKind::VectorCover => unreachable!(),
     }
 }
--- a/gfx/webrender/src/scene.rs
+++ b/gfx/webrender/src/scene.rs
@@ -1,13 +1,13 @@
 /* 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::{BuiltDisplayList, ColorF, DynamicProperties, Epoch, LayerSize, LayoutSize};
+use api::{BuiltDisplayList, ColorF, DynamicProperties, Epoch, LayoutSize};
 use api::{FilterOp, LayoutTransform, PipelineId, PropertyBinding, PropertyBindingId};
 use api::{ItemRange, MixBlendMode, StackingContext};
 use internal_types::FastHashMap;
 use std::sync::Arc;
 
 /// Stores a map of the animated property bindings for the current display list. These
 /// can be used to animate the transform and/or opacity of a display list without
 /// re-submitting the display list itself.
@@ -90,17 +90,17 @@ impl SceneProperties {
 }
 
 /// A representation of the layout within the display port for a given document or iframe.
 #[cfg_attr(feature = "capture", derive(Serialize))]
 #[cfg_attr(feature = "replay", derive(Deserialize))]
 #[derive(Clone)]
 pub struct ScenePipeline {
     pub pipeline_id: PipelineId,
-    pub viewport_size: LayerSize,
+    pub viewport_size: LayoutSize,
     pub content_size: LayoutSize,
     pub background_color: Option<ColorF>,
     pub display_list: BuiltDisplayList,
 }
 
 /// A complete representation of the layout bundling visible pipelines together.
 #[cfg_attr(feature = "capture", derive(Serialize))]
 #[cfg_attr(feature = "replay", derive(Deserialize))]
@@ -125,17 +125,17 @@ impl Scene {
     }
 
     pub fn set_display_list(
         &mut self,
         pipeline_id: PipelineId,
         epoch: Epoch,
         display_list: BuiltDisplayList,
         background_color: Option<ColorF>,
-        viewport_size: LayerSize,
+        viewport_size: LayoutSize,
         content_size: LayoutSize,
     ) {
         let new_pipeline = ScenePipeline {
             pipeline_id,
             viewport_size,
             content_size,
             background_color,
             display_list,
--- a/gfx/webrender/src/scene_builder.rs
+++ b/gfx/webrender/src/scene_builder.rs
@@ -33,16 +33,17 @@ pub enum SceneBuilderResult {
     Transaction {
         document_id: DocumentId,
         built_scene: Option<BuiltScene>,
         resource_updates: ResourceUpdates,
         frame_ops: Vec<FrameMsg>,
         render: bool,
         result_tx: Sender<SceneSwapResult>,
     },
+    Stopped,
 }
 
 // Message from render backend to scene builder to indicate the
 // 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,
     Aborted,
@@ -165,14 +166,19 @@ impl SceneBuilder {
                 let _ = self.api_tx.send(ApiMsg::WakeUp);
 
                 // Block until the swap is done, then invoke the hook
                 let _ = result_rx.recv();
                 if let Some(ref hooks) = self.hooks {
                     hooks.post_scene_swap(pipeline_info);
                 }
             }
-            SceneBuilderRequest::Stop => { return false; }
+            SceneBuilderRequest::Stop => {
+                self.tx.send(SceneBuilderResult::Stopped).unwrap();
+                // We don't need to send a WakeUp to api_tx because we only
+                // get the Stop when the RenderBackend loop is exiting.
+                return false;
+            }
         }
 
         true
     }
 }
--- a/gfx/webrender/src/segment.rs
+++ b/gfx/webrender/src/segment.rs
@@ -1,30 +1,30 @@
 /* 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, LayerPoint, LayerPointAu, LayerRect, LayerSize};
+use api::{BorderRadius, ClipMode, LayoutPoint, LayoutPointAu, LayoutRect, LayoutSize};
 use app_units::Au;
 use prim_store::EdgeAaSegmentMask;
 use std::{cmp, usize};
 use util::extract_inner_rect_safe;
 
 bitflags! {
     pub struct ItemFlags: u8 {
         const X_ACTIVE = 0x1;
         const Y_ACTIVE = 0x2;
         const HAS_MASK = 0x4;
     }
 }
 
 // The segment builder outputs a list of these segments.
 #[derive(Debug, PartialEq)]
 pub struct Segment {
-    pub rect: LayerRect,
+    pub rect: LayoutRect,
     pub has_mask: bool,
     pub edge_flags: EdgeAaSegmentMask,
     pub region_x: usize,
     pub region_y: usize,
 }
 
 // The segment builder creates a list of x/y axis events
 // that are used to build a segment list. Right now, we
@@ -138,24 +138,24 @@ impl Event {
         items[self.item_index.0].flags.set(flag, is_active);
     }
 }
 
 // An item that provides some kind of clip region (either
 // a clip in/out rect, or a mask region).
 #[derive(Debug)]
 struct Item {
-    rect: LayerRect,
+    rect: LayoutRect,
     mode: Option<ClipMode>,
     flags: ItemFlags,
 }
 
 impl Item {
     fn new(
-        rect: LayerRect,
+        rect: LayoutRect,
         mode: Option<ClipMode>,
         has_mask: bool,
     ) -> Item {
         let flags = if has_mask {
             ItemFlags::HAS_MASK
         } else {
             ItemFlags::empty()
         };
@@ -169,27 +169,27 @@ impl Item {
 }
 
 #[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd)]
 struct ItemIndex(usize);
 
 // The main public interface to the segment module.
 pub struct SegmentBuilder {
     items: Vec<Item>,
-    inner_rect: Option<LayerRect>,
-    bounding_rect: Option<LayerRect>,
+    inner_rect: Option<LayoutRect>,
+    bounding_rect: Option<LayoutRect>,
 }
 
 impl SegmentBuilder {
     // Create a new segment builder, supplying the primitive
     // local rect and associated local clip rect.
     pub fn new(
-        local_rect: LayerRect,
-        inner_rect: Option<LayerRect>,
-        local_clip_rect: LayerRect,
+        local_rect: LayoutRect,
+        inner_rect: Option<LayoutRect>,
+        local_clip_rect: LayoutRect,
     ) -> SegmentBuilder {
         let mut builder = SegmentBuilder {
             items: Vec::new(),
             bounding_rect: Some(local_rect),
             inner_rect,
         };
 
         builder.push_clip_rect(local_rect, None, ClipMode::Clip);
@@ -201,59 +201,59 @@ impl SegmentBuilder {
     // Push a region defined by an inner and outer rect where there
     // is a mask required. This ensures that segments which intersect
     // with these areas will get a clip mask task allocated. This
     // is currently used to mark where a box-shadow region can affect
     // the pixels of a clip-mask. It might be useful for other types
     // such as dashed and dotted borders in the future.
     pub fn push_mask_region(
         &mut self,
-        outer_rect: LayerRect,
-        inner_rect: LayerRect,
+        outer_rect: LayoutRect,
+        inner_rect: LayoutRect,
         inner_clip_mode: Option<ClipMode>,
     ) {
         debug_assert!(outer_rect.contains_rect(&inner_rect));
 
         let p0 = outer_rect.origin;
         let p1 = inner_rect.origin;
         let p2 = inner_rect.bottom_right();
         let p3 = outer_rect.bottom_right();
 
         let segments = &[
-            LayerRect::new(
-                LayerPoint::new(p0.x, p0.y),
-                LayerSize::new(p1.x - p0.x, p1.y - p0.y),
+            LayoutRect::new(
+                LayoutPoint::new(p0.x, p0.y),
+                LayoutSize::new(p1.x - p0.x, p1.y - p0.y),
             ),
-            LayerRect::new(
-                LayerPoint::new(p2.x, p0.y),
-                LayerSize::new(p3.x - p2.x, p1.y - p0.y),
+            LayoutRect::new(
+                LayoutPoint::new(p2.x, p0.y),
+                LayoutSize::new(p3.x - p2.x, p1.y - p0.y),
             ),
-            LayerRect::new(
-                LayerPoint::new(p2.x, p2.y),
-                LayerSize::new(p3.x - p2.x, p3.y - p2.y),
+            LayoutRect::new(
+                LayoutPoint::new(p2.x, p2.y),
+                LayoutSize::new(p3.x - p2.x, p3.y - p2.y),
             ),
-            LayerRect::new(
-                LayerPoint::new(p0.x, p2.y),
-                LayerSize::new(p1.x - p0.x, p3.y - p2.y),
+            LayoutRect::new(
+                LayoutPoint::new(p0.x, p2.y),
+                LayoutSize::new(p1.x - p0.x, p3.y - p2.y),
             ),
-            LayerRect::new(
-                LayerPoint::new(p1.x, p0.y),
-                LayerSize::new(p2.x - p1.x, p1.y - p0.y),
+            LayoutRect::new(
+                LayoutPoint::new(p1.x, p0.y),
+                LayoutSize::new(p2.x - p1.x, p1.y - p0.y),
             ),
-            LayerRect::new(
-                LayerPoint::new(p2.x, p1.y),
-                LayerSize::new(p3.x - p2.x, p2.y - p1.y),
+            LayoutRect::new(
+                LayoutPoint::new(p2.x, p1.y),
+                LayoutSize::new(p3.x - p2.x, p2.y - p1.y),
             ),
-            LayerRect::new(
-                LayerPoint::new(p1.x, p2.y),
-                LayerSize::new(p2.x - p1.x, p3.y - p2.y),
+            LayoutRect::new(
+                LayoutPoint::new(p1.x, p2.y),
+                LayoutSize::new(p2.x - p1.x, p3.y - p2.y),
             ),
-            LayerRect::new(
-                LayerPoint::new(p0.x, p1.y),
-                LayerSize::new(p1.x - p0.x, p2.y - p1.y),
+            LayoutRect::new(
+                LayoutPoint::new(p0.x, p1.y),
+                LayoutSize::new(p1.x - p0.x, p2.y - p1.y),
             ),
         ];
 
         for segment in segments {
             self.items.push(Item::new(
                 *segment,
                 None,
                 true
@@ -268,17 +268,17 @@ impl SegmentBuilder {
             ));
         }
     }
 
     // Push some kind of clipping region into the segment builder.
     // If radius is None, it's a simple rect.
     pub fn push_clip_rect(
         &mut self,
-        rect: LayerRect,
+        rect: LayoutRect,
         radius: Option<BorderRadius>,
         mode: ClipMode,
     ) {
         // Keep track of a minimal bounding rect for the set of
         // segments that will be generated.
         if mode == ClipMode::Clip {
             self.bounding_rect = self.bounding_rect.and_then(|bounding_rect| {
                 bounding_rect.intersection(&rect)
@@ -293,62 +293,62 @@ impl SegmentBuilder {
                 match extract_inner_rect_safe(&rect, &radius) {
                     Some(inner) => {
                         let p0 = rect.origin;
                         let p1 = inner.origin;
                         let p2 = inner.bottom_right();
                         let p3 = rect.bottom_right();
 
                         let corner_segments = &[
-                            LayerRect::new(
-                                LayerPoint::new(p0.x, p0.y),
-                                LayerSize::new(p1.x - p0.x, p1.y - p0.y),
+                            LayoutRect::new(
+                                LayoutPoint::new(p0.x, p0.y),
+                                LayoutSize::new(p1.x - p0.x, p1.y - p0.y),
                             ),
-                            LayerRect::new(
-                                LayerPoint::new(p2.x, p0.y),
-                                LayerSize::new(p3.x - p2.x, p1.y - p0.y),
+                            LayoutRect::new(
+                                LayoutPoint::new(p2.x, p0.y),
+                                LayoutSize::new(p3.x - p2.x, p1.y - p0.y),
                             ),
-                            LayerRect::new(
-                                LayerPoint::new(p2.x, p2.y),
-                                LayerSize::new(p3.x - p2.x, p3.y - p2.y),
+                            LayoutRect::new(
+                                LayoutPoint::new(p2.x, p2.y),
+                                LayoutSize::new(p3.x - p2.x, p3.y - p2.y),
                             ),
-                            LayerRect::new(
-                                LayerPoint::new(p0.x, p2.y),
-                                LayerSize::new(p1.x - p0.x, p3.y - p2.y),
+                            LayoutRect::new(
+                                LayoutPoint::new(p0.x, p2.y),
+                                LayoutSize::new(p1.x - p0.x, p3.y - p2.y),
                             ),
                         ];
 
                         for segment in corner_segments {
                             self.items.push(Item::new(
                                 *segment,
                                 mode,
                                 true
                             ));
                         }
 
                         let other_segments = &[
-                            LayerRect::new(
-                                LayerPoint::new(p1.x, p0.y),
-                                LayerSize::new(p2.x - p1.x, p1.y - p0.y),
+                            LayoutRect::new(
+                                LayoutPoint::new(p1.x, p0.y),
+                                LayoutSize::new(p2.x - p1.x, p1.y - p0.y),
                             ),
-                            LayerRect::new(
-                                LayerPoint::new(p2.x, p1.y),
-                                LayerSize::new(p3.x - p2.x, p2.y - p1.y),
+                            LayoutRect::new(
+                                LayoutPoint::new(p2.x, p1.y),
+                                LayoutSize::new(p3.x - p2.x, p2.y - p1.y),
                             ),
-                            LayerRect::new(
-                                LayerPoint::new(p1.x, p2.y),
-                                LayerSize::new(p2.x - p1.x, p3.y - p2.y),
+                            LayoutRect::new(
+                                LayoutPoint::new(p1.x, p2.y),
+                                LayoutSize::new(p2.x - p1.x, p3.y - p2.y),
                             ),
-                            LayerRect::new(
-                                LayerPoint::new(p0.x, p1.y),
-                                LayerSize::new(p1.x - p0.x, p2.y - p1.y),
+                            LayoutRect::new(
+                                LayoutPoint::new(p0.x, p1.y),
+                                LayoutSize::new(p1.x - p0.x, p2.y - p1.y),
                             ),
-                            LayerRect::new(
-                                LayerPoint::new(p1.x, p1.y),
-                                LayerSize::new(p2.x - p1.x, p2.y - p1.y),
+                            LayoutRect::new(
+                                LayoutPoint::new(p1.x, p1.y),
+                                LayoutSize::new(p2.x - p1.x, p2.y - p1.y),
                             ),
                         ];
 
                         for segment in other_segments {
                             self.items.push(Item::new(
                                 *segment,
                                 mode,
                                 false,
@@ -415,22 +415,22 @@ impl SegmentBuilder {
 
             y_events.push(Event::region(inner_rect.origin.y));
             y_events.push(Event::region(inner_rect.origin.y + inner_rect.size.height));
         }
 
         // Get the minimal bounding rect in app units. We will
         // work in fixed point in order to avoid float precision
         // error while handling events.
-        let p0 = LayerPointAu::new(
+        let p0 = LayoutPointAu::new(
             Au::from_f32_px(bounding_rect.origin.x),
             Au::from_f32_px(bounding_rect.origin.y),
         );
 
-        let p1 = LayerPointAu::new(
+        let p1 = LayoutPointAu::new(
             Au::from_f32_px(bounding_rect.origin.x + bounding_rect.size.width),
             Au::from_f32_px(bounding_rect.origin.y + bounding_rect.size.height),
         );
 
         // Sort the events in ascending order.
         x_events.sort();
         y_events.sort();
 
@@ -553,47 +553,47 @@ fn emit_segment_if_needed(
             has_clip_mask |= item.flags.contains(ItemFlags::HAS_MASK);
 
             if item.mode == Some(ClipMode::ClipOut) && !item.flags.contains(ItemFlags::HAS_MASK) {
                 return None;
             }
         }
     }
 
-    let segment_rect = LayerRect::new(
-        LayerPoint::new(
+    let segment_rect = LayoutRect::new(
+        LayoutPoint::new(
             x0.to_f32_px(),
             y0.to_f32_px(),
         ),
-        LayerSize::new(
+        LayoutSize::new(
             (x1 - x0).to_f32_px(),
             (y1 - y0).to_f32_px(),
         ),
     );
 
     Some(Segment {
         rect: segment_rect,
         has_mask: has_clip_mask,
         edge_flags: EdgeAaSegmentMask::empty(),
         region_x,
         region_y,
     })
 }
 
 #[cfg(test)]
 mod test {
-    use api::{BorderRadius, ClipMode, LayerPoint, LayerRect, LayerSize};
+    use api::{BorderRadius, ClipMode, LayoutPoint, LayoutRect, LayoutSize};
     use prim_store::EdgeAaSegmentMask;
     use super::{Segment, SegmentBuilder};
     use std::cmp;
 
-    fn rect(x0: f32, y0: f32, x1: f32, y1: f32) -> LayerRect {
-        LayerRect::new(
-            LayerPoint::new(x0, y0),
-            LayerSize::new(x1-x0, y1-y0),
+    fn rect(x0: f32, y0: f32, x1: f32, y1: f32) -> LayoutRect {
+        LayoutRect::new(
+            LayoutPoint::new(x0, y0),
+            LayoutSize::new(x1-x0, y1-y0),
         )
     }
 
     fn seg(
         x0: f32,
         y0: f32,
         x1: f32,
         y1: f32,
@@ -609,19 +609,19 @@ mod test {
         x1: f32,
         y1: f32,
         region_x: usize,
         region_y: usize,
         has_mask: bool,
         edge_flags: Option<EdgeAaSegmentMask>,
     ) -> Segment {
         Segment {
-            rect: LayerRect::new(
-                LayerPoint::new(x0, y0),
-                LayerSize::new(x1-x0, y1-y0),
+            rect: LayoutRect::new(
+                LayoutPoint::new(x0, y0),
+                LayoutSize::new(x1-x0, y1-y0),
             ),
             has_mask,
             edge_flags: edge_flags.unwrap_or(EdgeAaSegmentMask::empty()),
             region_x,
             region_y,
         }
     }
 
@@ -632,20 +632,20 @@ mod test {
         (
             (r0.origin.x, r0.origin.y, r0.size.width, r0.size.height)
         ).partial_cmp(&
             (r1.origin.x, r1.origin.y, r1.size.width, r1.size.height)
         ).unwrap()
     }
 
     fn seg_test(
-        local_rect: LayerRect,
-        inner_rect: Option<LayerRect>,
-        local_clip_rect: LayerRect,
-        clips: &[(LayerRect, Option<BorderRadius>, ClipMode)],
+        local_rect: LayoutRect,
+        inner_rect: Option<LayoutRect>,
+        local_clip_rect: LayoutRect,
+        clips: &[(LayoutRect, Option<BorderRadius>, ClipMode)],
         expected_segments: &mut [Segment]
     ) {
         let mut sb = SegmentBuilder::new(
             local_rect,
             inner_rect,
             local_clip_rect,
         );
         let mut segments = Vec::new();
--- a/gfx/webrender/src/shade.rs
+++ b/gfx/webrender/src/shade.rs
@@ -48,16 +48,17 @@ pub const IMAGE_BUFFER_KINDS: [ImageBuff
     ImageBufferKind::TextureRect,
     ImageBufferKind::TextureExternal,
     ImageBufferKind::Texture2DArray,
 ];
 
 const TRANSFORM_FEATURE: &str = "TRANSFORM";
 const ALPHA_FEATURE: &str = "ALPHA_PASS";
 const DITHERING_FEATURE: &str = "DITHERING";
+const DUAL_SOURCE_FEATURE: &str = "DUAL_SOURCE_BLENDING";
 
 pub(crate) enum ShaderKind {
     Primitive,
     Cache(VertexArrayKind),
     ClipCache,
     Brush,
     Text,
     #[allow(dead_code)]
@@ -176,24 +177,26 @@ impl LazilyCompiledShader {
 // alpha:
 //   Used for brush primitives in the alpha
 //   pass. Assumes that AA should be applied
 //   along the primitive edge, and also that
 //   clip mask is present.
 struct BrushShader {
     opaque: LazilyCompiledShader,
     alpha: LazilyCompiledShader,
+    dual_source: Option<LazilyCompiledShader>,
 }
 
 impl BrushShader {
     fn new(
         name: &'static str,
         device: &mut Device,
         features: &[&'static str],
         precache: bool,
+        dual_source: bool,
     ) -> Result<Self, ShaderError> {
         let opaque = LazilyCompiledShader::new(
             ShaderKind::Brush,
             name,
             features,
             device,
             precache,
         )?;
@@ -204,34 +207,62 @@ impl BrushShader {
         let alpha = LazilyCompiledShader::new(
             ShaderKind::Brush,
             name,
             &alpha_features,
             device,
             precache,
         )?;
 
-        Ok(BrushShader { opaque, alpha })
+        let dual_source = if dual_source {
+            let mut dual_source_features = alpha_features.to_vec();
+            dual_source_features.push(DUAL_SOURCE_FEATURE);
+
+            let shader = LazilyCompiledShader::new(
+                ShaderKind::Brush,
+                name,
+                &dual_source_features,
+                device,
+                precache,
+            )?;
+
+            Some(shader)
+        } else {
+            None
+        };
+
+        Ok(BrushShader {
+            opaque,
+            alpha,
+            dual_source,
+        })
     }
 
     fn get(&mut self, blend_mode: BlendMode) -> &mut LazilyCompiledShader {
         match blend_mode {
             BlendMode::None => &mut self.opaque,
             BlendMode::Alpha |
             BlendMode::PremultipliedAlpha |
             BlendMode::PremultipliedDestOut |
-            BlendMode::SubpixelDualSource |
             BlendMode::SubpixelConstantTextColor(..) |
             BlendMode::SubpixelWithBgColor => &mut self.alpha,
+            BlendMode::SubpixelDualSource => {
+                self.dual_source
+                    .as_mut()
+                    .expect("bug: no dual source shader loaded")
+            }
         }
     }
 
     fn deinit(self, device: &mut Device) {
         self.opaque.deinit(device);
         self.alpha.deinit(device);
+        if let Some(dual_source) = self.dual_source {
+            dual_source.deinit(device);
+        }
     }
 }
 
 struct PrimitiveShader {
     simple: LazilyCompiledShader,
     transform: LazilyCompiledShader,
 }
 
@@ -364,16 +395,17 @@ fn create_prim_shader(
     }
 
     debug!("PrimShader {}", name);
 
     let vertex_descriptor = match vertex_format {
         VertexArrayKind::Primitive => desc::PRIM_INSTANCES,
         VertexArrayKind::Blur => desc::BLUR,
         VertexArrayKind::Clip => desc::CLIP,
+        VertexArrayKind::DashAndDot => desc::BORDER_CORNER_DASH_AND_DOT,
         VertexArrayKind::VectorStencil => desc::VECTOR_STENCIL,
         VertexArrayKind::VectorCover => desc::VECTOR_COVER,
     };
 
     let program = device.create_program(name, &prefix, &vertex_descriptor);
 
     if let Ok(ref program) = program {
         device.bind_shader_samplers(
@@ -482,52 +514,57 @@ impl Shaders {
             None
         };
 
         let brush_solid = BrushShader::new(
             "brush_solid",
             device,
             &[],
             options.precache_shaders,
+            false,
         )?;
 
         let brush_blend = BrushShader::new(
             "brush_blend",
             device,
             &[],
             options.precache_shaders,
+            false,
         )?;
 
         let brush_mix_blend = BrushShader::new(
             "brush_mix_blend",
             device,
             &[],
             options.precache_shaders,
+            false,
         )?;
 
         let brush_radial_gradient = BrushShader::new(
             "brush_radial_gradient",
             device,
             if options.enable_dithering {
                &[DITHERING_FEATURE]
             } else {
                &[]
             },
             options.precache_shaders,
+            false,
         )?;
 
         let brush_linear_gradient = BrushShader::new(
             "brush_linear_gradient",
             device,
             if options.enable_dithering {
                &[DITHERING_FEATURE]
             } else {
                &[]
             },
             options.precache_shaders,
+            false,
         )?;
 
         let cs_blur_a8 = LazilyCompiledShader::new(
             ShaderKind::Cache(VertexArrayKind::Blur),
             "cs_blur",
             &["ALPHA_TARGET"],
             device,
             options.precache_shaders,
@@ -614,16 +651,17 @@ impl Shaders {
                     &image_features,
                     options.precache_shaders,
                 )?);
                 brush_image[buffer_kind] = Some(BrushShader::new(
                     "brush_image",
                     device,
                     &image_features,
                     options.precache_shaders,
+                    true,
                 )?);
             }
             image_features.clear();
         }
 
         // All yuv_image configuration.
         let mut yuv_features = Vec::new();
         let yuv_shader_num = IMAGE_BUFFER_KINDS.len() * YUV_FORMATS.len() * YUV_COLOR_SPACES.len();
@@ -649,16 +687,17 @@ impl Shaders {
                             yuv_features.push(feature_string);
                         }
 
                         let shader = BrushShader::new(
                             "brush_yuv_image",
                             device,
                             &yuv_features,
                             options.precache_shaders,
+                            false,
                         )?;
                         let index = Self::get_yuv_shader_index(
                             *image_buffer_kind,
                             *format_kind,
                             *color_space_kind,
                         );
                         brush_yuv_image[index] = Some(shader);
                         yuv_features.clear();
@@ -760,18 +799,26 @@ impl Shaders {
                             .as_mut()
                             .expect("Unsupported YUV shader kind")
                     }
                 };
                 brush_shader.get(key.blend_mode)
             }
             BatchKind::Transformable(transform_kind, batch_kind) => {
                 let prim_shader = match batch_kind {
-                    TransformBatchKind::TextRun(..) => {
-                        unreachable!("bug: text batches are special cased");
+                    TransformBatchKind::TextRun(glyph_format) => {
+                        let text_shader = match key.blend_mode {
+                            BlendMode::SubpixelDualSource => {
+                                &mut self.ps_text_run_dual_source
+                            }
+                            _ => {
+                                &mut self.ps_text_run
+                            }
+                        };
+                        return text_shader.get(glyph_format, transform_kind);
                     }
                     TransformBatchKind::Image(image_buffer_kind) => {
                         self.ps_image[image_buffer_kind as usize]
                             .as_mut()
                             .expect("Unsupported image shader kind")
                     }
                     TransformBatchKind::BorderCorner => {
                         &mut self.ps_border_corner
--- a/gfx/webrender/src/texture_cache.rs
+++ b/gfx/webrender/src/texture_cache.rs
@@ -230,17 +230,17 @@ pub struct TextureCache {
     // A list of texture IDs that represent native
     // texture handles. This indirection allows the texture
     // cache to create / destroy / reuse texture handles
     // without knowing anything about the device code.
     cache_textures: CacheTextureIdList,
 
     // A list of updates that need to be applied to the
     // texture cache in the rendering thread this frame.
-    #[cfg_attr(feature = "serde", serde(skip))]
+    #[cfg_attr(all(feature = "serde", any(feature = "capture", feature = "replay")), serde(skip))]
     pending_updates: TextureUpdateList,
 
     // The current frame ID. Used for cache eviction policies.
     frame_id: FrameId,
 
     // Maintains the list of all current items in
     // the texture cache.
     entries: FreeList<CacheEntry, CacheEntryMarker>,
--- a/gfx/webrender/src/tiling.rs
+++ b/gfx/webrender/src/tiling.rs
@@ -1,14 +1,14 @@
 /* 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, DeviceIntPoint, DeviceIntRect, DeviceIntSize, DevicePixelScale, DeviceUintPoint};
-use api::{DeviceUintRect, DeviceUintSize, DocumentLayer, FilterOp, ImageFormat, LayerRect};
+use api::{DeviceUintRect, DeviceUintSize, DocumentLayer, FilterOp, ImageFormat, LayoutRect};
 use api::{MixBlendMode, PipelineId};
 use batch::{AlphaBatchBuilder, AlphaBatchContainer, ClipBatcher, resolve_image};
 use clip::{ClipStore};
 use clip_scroll_tree::{ClipScrollTree, ClipScrollNodeIndex};
 use device::{FrameId, Texture};
 #[cfg(feature = "pathfinder")]
 use euclid::{TypedPoint2D, TypedVector2D};
 use gpu_cache::{GpuCache};
@@ -29,17 +29,17 @@ use texture_allocator::GuillotineAllocat
 use webrender_api::{DevicePixel, FontRenderMode};
 
 const MIN_TARGET_SIZE: u32 = 2048;
 
 #[derive(Debug)]
 pub struct ScrollbarPrimitive {
     pub scroll_frame_index: ClipScrollNodeIndex,
     pub prim_index: PrimitiveIndex,
-    pub frame_rect: LayerRect,
+    pub frame_rect: LayoutRect,
 }
 
 #[derive(Debug, Copy, Clone)]
 #[cfg_attr(feature = "capture", derive(Serialize))]
 #[cfg_attr(feature = "replay", derive(Deserialize))]
 pub struct RenderTargetIndex(pub usize);
 
 pub struct RenderTargetContext<'a, 'rc> {
@@ -933,17 +933,17 @@ pub struct Frame {
     pub background_color: Option<ColorF>,
     pub layer: DocumentLayer,
     pub device_pixel_ratio: f32,
     pub passes: Vec<RenderPass>,
     #[cfg_attr(any(feature = "capture", feature = "replay"), serde(default = "FrameProfileCounters::new", skip))]
     pub profile_counters: FrameProfileCounters,
 
     pub node_data: Vec<ClipScrollNodeData>,
-    pub clip_chain_local_clip_rects: Vec<LayerRect>,
+    pub clip_chain_local_clip_rects: Vec<LayoutRect>,
     pub render_tasks: RenderTaskTree,
 
     /// The GPU cache frame that the contents of Self depend on
     pub gpu_cache_frame_id: FrameId,
 
     /// List of textures that we don't know about yet
     /// from the backend thread. The render thread
     /// will use a callback to resolve these and
--- a/gfx/webrender/src/util.rs
+++ b/gfx/webrender/src/util.rs
@@ -1,15 +1,15 @@
 /* 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, DeviceIntPoint, DeviceIntRect, DeviceIntSize, DevicePixelScale};
-use api::{DevicePoint, DeviceRect, DeviceSize, LayerPixel, LayerPoint, LayerRect, LayerSize};
-use api::{LayoutPixel, WorldPixel, WorldRect};
+use api::{DevicePoint, DeviceRect, DeviceSize, LayoutPixel, LayoutPoint, LayoutRect, LayoutSize};
+use api::{WorldPixel, WorldRect};
 use euclid::{Point2D, Rect, Size2D, TypedPoint2D, TypedPoint3D, TypedRect, TypedSize2D};
 use euclid::{TypedTransform2D, TypedTransform3D, TypedVector2D};
 use num_traits::Zero;
 use std::{i32, f32};
 
 // Matches the definition of SK_ScalarNearlyZero in Skia.
 const NEARLY_ZERO: f32 = 1.0 / 4096.0;
 
@@ -152,18 +152,18 @@ pub fn rect_from_points_f(x0: f32, y0: f
     Rect::new(Point2D::new(x0, y0), Size2D::new(x1 - x0, y1 - y0))
 }
 
 pub fn lerp(a: f32, b: f32, t: f32) -> f32 {
     (b - a) * t + a
 }
 
 pub fn calculate_screen_bounding_rect(
-    transform: &LayerToWorldFastTransform,
-    rect: &LayerRect,
+    transform: &LayoutToWorldFastTransform,
+    rect: &LayoutRect,
     device_pixel_scale: DevicePixelScale,
 ) -> DeviceIntRect {
     let points = [
         transform.transform_point2d(&rect.origin),
         transform.transform_point2d(&rect.top_right()),
         transform.transform_point2d(&rect.bottom_left()),
         transform.transform_point2d(&rect.bottom_right()),
     ];
@@ -304,21 +304,21 @@ pub mod test {
         assert_eq!(m1.inverse_project(&p0), Some(Point2D::new(2.0, 2.0)));
     }
 }
 
 pub trait MaxRect {
     fn max_rect() -> Self;
 }
 
-impl MaxRect for LayerRect {
+impl MaxRect for LayoutRect {
     fn max_rect() -> Self {
-        LayerRect::new(
-            LayerPoint::new(f32::MIN / 2.0, f32::MIN / 2.0),
-            LayerSize::new(f32::MAX, f32::MAX),
+        LayoutRect::new(
+            LayoutPoint::new(f32::MIN / 2.0, f32::MIN / 2.0),
+            LayoutSize::new(f32::MAX, f32::MAX),
         )
     }
 }
 
 impl MaxRect for DeviceIntRect {
     fn max_rect() -> Self {
         DeviceIntRect::new(
             DeviceIntPoint::new(i32::MIN / 2, i32::MIN / 2),
@@ -551,11 +551,10 @@ impl<Src, Dst> Into<TypedTransform3D<f32
 
 impl<Src, Dst> From<TypedVector2D<f32, Src>> for FastTransform<Src, Dst> {
     fn from(vector: TypedVector2D<f32, Src>) -> FastTransform<Src, Dst> {
         FastTransform::with_vector(vector)
     }
 }
 
 pub type LayoutFastTransform = FastTransform<LayoutPixel, LayoutPixel>;
-pub type LayerFastTransform = FastTransform<LayerPixel, LayerPixel>;
-pub type LayerToWorldFastTransform = FastTransform<LayerPixel, WorldPixel>;
-pub type WorldToLayerFastTransform = FastTransform<WorldPixel, LayerPixel>;
+pub type LayoutToWorldFastTransform = FastTransform<LayoutPixel, WorldPixel>;
+pub type WorldToLayoutFastTransform = FastTransform<WorldPixel, LayoutPixel>;
\ No newline at end of file
--- a/gfx/webrender_api/src/api.rs
+++ b/gfx/webrender_api/src/api.rs
@@ -214,35 +214,31 @@ impl Transaction {
     /// is reset back to `None`.
     pub fn remove_pipeline(&mut self, pipeline_id: PipelineId) {
         self.scene_ops.push(SceneMsg::RemovePipeline(pipeline_id));
     }
 
     /// Supplies a new frame to WebRender.
     ///
     /// Non-blocking, it notifies a worker process which processes the display list.
-    /// When it's done and a RenderNotifier has been set in `webrender::Renderer`,
-    /// [new_frame_ready()][notifier] gets called.
     ///
     /// Note: Scrolling doesn't require an own Frame.
     ///
     /// Arguments:
     ///
     /// * `document_id`: Target Document ID.
     /// * `epoch`: The unique Frame ID, monotonically increasing.
     /// * `background`: The background color of this pipeline.
     /// * `viewport_size`: The size of the viewport for this frame.
     /// * `pipeline_id`: The ID of the pipeline that is supplying this display list.
     /// * `content_size`: The total screen space size of this display list's display items.
     /// * `display_list`: The root Display list used in this frame.
     /// * `preserve_frame_state`: If a previous frame exists which matches this pipeline
     ///                           id, this setting determines if frame state (such as scrolling
     ///                           position) should be preserved for this new display list.
-    ///
-    /// [notifier]: trait.RenderNotifier.html#tymethod.new_frame_ready
     pub fn set_display_list(
         &mut self,
         epoch: Epoch,
         background: Option<ColorF>,
         viewport_size: LayoutSize,
         (pipeline_id, content_size, display_list): (PipelineId, LayoutSize, BuiltDisplayList),
         preserve_frame_state: bool,
     ) {
@@ -308,17 +304,23 @@ impl Transaction {
     pub fn set_pinch_zoom(&mut self, pinch_zoom: ZoomFactor) {
         self.scene_ops.push(SceneMsg::SetPinchZoom(pinch_zoom));
     }
 
     pub fn set_pan(&mut self, pan: DeviceIntPoint) {
         self.frame_ops.push(FrameMsg::SetPan(pan));
     }
 
-    /// Generate a new frame.
+    /// Generate a new frame. When it's done and a RenderNotifier has been set
+    /// in `webrender::Renderer`, [new_frame_ready()][notifier] gets called.
+    /// Note that the notifier is called even if the frame generation was a
+    /// no-op; the arguments passed to `new_frame_ready` will provide information
+    /// as to what happened.
+    ///
+    /// [notifier]: trait.RenderNotifier.html#tymethod.new_frame_ready
     pub fn generate_frame(&mut self) {
         self.generate_frame = true;
     }
 
     /// Supply a list of animated property bindings that should be used to resolve
     /// bindings in the current display list.
     pub fn update_dynamic_properties(&mut self, properties: DynamicProperties) {
         self.frame_ops.push(FrameMsg::UpdateDynamicProperties(properties));
@@ -1102,14 +1104,14 @@ pub struct PropertyValue<T> {
 pub struct DynamicProperties {
     pub transforms: Vec<PropertyValue<LayoutTransform>>,
     pub floats: Vec<PropertyValue<f32>>,
 }
 
 pub trait RenderNotifier: Send {
     fn clone(&self) -> Box<RenderNotifier>;
     fn wake_up(&self);
-    fn new_document_ready(&self, DocumentId, scrolled: bool, composite_needed: bool);
+    fn new_frame_ready(&self, DocumentId, scrolled: bool, composite_needed: bool);
     fn external_event(&self, _evt: ExternalEvent) {
         unimplemented!()
     }
     fn shut_down(&self) {}
 }
--- a/gfx/webrender_api/src/color.rs
+++ b/gfx/webrender_api/src/color.rs
@@ -58,16 +58,26 @@ impl ColorF {
         ColorF {
             r: self.r * scale,
             g: self.g * scale,
             b: self.b * scale,
             a: self.a,
         }
     }
 
+    // Scale the alpha by a given factor.
+    pub fn scale_alpha(&self, scale: f32) -> Self {
+        ColorF {
+            r: self.r,
+            g: self.g,
+            b: self.b,
+            a: self.a * scale,
+        }
+    }
+
     pub fn to_array(&self) -> [f32; 4] {
         [self.r, self.g, self.b, self.a]
     }
 
     /// Multiply the RGB components with the alpha channel.
     pub fn premultiplied(&self) -> PremultipliedColorF {
         let c = self.scale_rgb(self.a);
         PremultipliedColorF { r: c.r, g: c.g, b: c.b, a: c.a }
--- a/gfx/webrender_api/src/display_item.rs
+++ b/gfx/webrender_api/src/display_item.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/. */
 
 #[cfg(any(feature = "serialize", feature = "deserialize"))]
 use GlyphInstance;
 use euclid::{SideOffsets2D, TypedRect};
 use std::ops::Not;
-use {ColorF, FontInstanceKey, GlyphOptions, ImageKey, LayerPixel, LayoutPixel, LayoutPoint};
+use {ColorF, FontInstanceKey, GlyphOptions, ImageKey, LayoutPixel, LayoutPoint};
 use {LayoutRect, LayoutSize, LayoutTransform, LayoutVector2D, PipelineId, PropertyBinding};
 
 
 // NOTE: some of these structs have an "IMPLICIT" comment.
 // This indicates that the BuiltDisplayList will have serialized
 // a list of values nearby that this item consumes. The traversal
 // iterator should handle finding these.
 
@@ -64,36 +64,35 @@ pub type DisplayItem = GenericDisplayIte
 #[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)]
 pub struct PrimitiveInfo<T> {
     pub rect: TypedRect<f32, T>,
     pub clip_rect: TypedRect<f32, T>,
     pub is_backface_visible: bool,
     pub tag: Option<ItemTag>,
 }
 
-impl LayerPrimitiveInfo {
-    pub fn new(rect: TypedRect<f32, LayerPixel>) -> Self {
+impl LayoutPrimitiveInfo {
+    pub fn new(rect: TypedRect<f32, LayoutPixel>) -> Self {
         Self::with_clip_rect(rect, rect)
     }
 
     pub fn with_clip_rect(
-        rect: TypedRect<f32, LayerPixel>,
-        clip_rect: TypedRect<f32, LayerPixel>,
+        rect: TypedRect<f32, LayoutPixel>,
+        clip_rect: TypedRect<f32, LayoutPixel>,
     ) -> Self {
         PrimitiveInfo {
             rect,
             clip_rect,
             is_backface_visible: true,
             tag: None,
         }
     }
 }
 
 pub type LayoutPrimitiveInfo = PrimitiveInfo<LayoutPixel>;
-pub type LayerPrimitiveInfo = PrimitiveInfo<LayerPixel>;
 
 #[repr(u8)]
 #[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)]
 pub enum SpecificDisplayItem {
     Clip(ClipDisplayItem),
     ScrollFrame(ScrollFrameDisplayItem),
     StickyFrame(StickyFrameDisplayItem),
     Rectangle(RectangleDisplayItem),
@@ -663,22 +662,22 @@ impl LocalClip {
             ),
         }
     }
 
     pub fn clip_by(&self, rect: &LayoutRect) -> LocalClip {
         match *self {
             LocalClip::Rect(clip_rect) => {
                 LocalClip::Rect(
-                    clip_rect.intersection(rect).unwrap_or(LayoutRect::zero())
+                    clip_rect.intersection(rect).unwrap_or_else(LayoutRect::zero)
                 )
             }
             LocalClip::RoundedRect(clip_rect, complex) => {
                 LocalClip::RoundedRect(
-                    clip_rect.intersection(rect).unwrap_or(LayoutRect::zero()),
+                    clip_rect.intersection(rect).unwrap_or_else(LayoutRect::zero),
                     complex,
                 )
             }
         }
     }
 }
 
 #[repr(C)]
--- a/gfx/webrender_api/src/display_list.rs
+++ b/gfx/webrender_api/src/display_list.rs
@@ -12,17 +12,17 @@ use serde::{Deserialize, Serialize};
 use std::io::{Read, Write};
 use std::marker::PhantomData;
 use std::{io, mem, ptr, slice};
 use time::precise_time_ns;
 use {AlphaType, BorderDetails, BorderDisplayItem, BorderRadius, BorderWidths, BoxShadowClipMode};
 use {BoxShadowDisplayItem, ClipAndScrollInfo, ClipChainId, ClipChainItem, ClipDisplayItem, ClipId};
 use {ColorF, ComplexClipRegion, DisplayItem, ExtendMode, ExternalScrollId, FilterOp};
 use {FontInstanceKey, GlyphInstance, GlyphOptions, GlyphRasterSpace, Gradient, GradientDisplayItem, GradientStop};
-use {IframeDisplayItem, ImageDisplayItem, ImageKey, ImageMask, ImageRendering, LayerPrimitiveInfo};
+use {IframeDisplayItem, ImageDisplayItem, ImageKey, ImageMask, ImageRendering};
 use {LayoutPoint, LayoutPrimitiveInfo, LayoutRect, LayoutSize, LayoutTransform, LayoutVector2D};
 use {LineDisplayItem, LineOrientation, LineStyle, MixBlendMode, PipelineId, PropertyBinding};
 use {PushStackingContextDisplayItem, RadialGradient, RadialGradientDisplayItem};
 use {RectangleDisplayItem, ScrollFrameDisplayItem, ScrollPolicy, ScrollSensitivity, Shadow};
 use {SpecificDisplayItem, StackingContext, StickyFrameDisplayItem, StickyOffsetBounds};
 use {TextDisplayItem, TransformStyle, YuvColorSpace, YuvData, YuvImageDisplayItem};
 
 // We don't want to push a long text-run. If a text-run is too long, split it into several parts.
@@ -326,19 +326,19 @@ impl<'a, 'b> DisplayItemRef<'a, 'b> {
     pub fn display_item(&self) -> &DisplayItem {
         &self.iter.cur_item
     }
 
     pub fn rect(&self) -> LayoutRect {
         self.iter.cur_item.info.rect
     }
 
-    pub fn get_layer_primitive_info(&self, offset: &LayoutVector2D) -> LayerPrimitiveInfo {
+    pub fn get_layout_primitive_info(&self, offset: &LayoutVector2D) -> LayoutPrimitiveInfo {
         let info = self.iter.cur_item.info;
-        LayerPrimitiveInfo {
+        LayoutPrimitiveInfo {
             rect: info.rect.translate(offset),
             clip_rect: info.clip_rect.translate(offset),
             is_backface_visible: info.is_backface_visible,
             tag: info.tag,
         }
     }
 
     pub fn clip_rect(&self) -> &LayoutRect {
--- a/gfx/webrender_api/src/image.rs
+++ b/gfx/webrender_api/src/image.rs
@@ -118,17 +118,17 @@ pub enum ImageData {
 }
 
 mod serde_image_data_raw {
     extern crate serde_bytes;
 
     use std::sync::Arc;
     use serde::{Deserializer, Serializer};
 
-    pub fn serialize<'a, S: Serializer>(bytes: &'a Arc<Vec<u8>>, serializer: S) -> Result<S::Ok, S::Error> {
+    pub fn serialize<S: Serializer>(bytes: &Arc<Vec<u8>>, serializer: S) -> Result<S::Ok, S::Error> {
         serde_bytes::serialize(bytes.as_slice(), serializer)
     }
 
     pub fn deserialize<'de, D: Deserializer<'de>>(deserializer: D) -> Result<Arc<Vec<u8>>, D::Error> {
         serde_bytes::deserialize(deserializer).map(Arc::new)
     }
 }
 
--- a/gfx/webrender_api/src/lib.rs
+++ b/gfx/webrender_api/src/lib.rs
@@ -1,14 +1,14 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #![cfg_attr(feature = "nightly", feature(nonzero))]
-#![cfg_attr(feature = "cargo-clippy", allow(too_many_arguments, float_cmp))]
+#![cfg_attr(feature = "cargo-clippy", allow(float_cmp, too_many_arguments, unreadable_literal))]
 
 extern crate app_units;
 extern crate bincode;
 #[macro_use]
 extern crate bitflags;
 extern crate byteorder;
 #[cfg(feature = "nightly")]
 extern crate core;
--- a/gfx/webrender_api/src/units.rs
+++ b/gfx/webrender_api/src/units.rs
@@ -40,36 +40,25 @@ pub type DeviceSize = TypedSize2D<f32, D
 #[derive(Hash, Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd)]
 pub struct PicturePixel;
 
 pub type PictureIntRect = TypedRect<i32, PicturePixel>;
 pub type PictureIntPoint = TypedPoint2D<i32, PicturePixel>;
 pub type PictureIntSize = TypedSize2D<i32, PicturePixel>;
 
 /// Geometry in a stacking context's local coordinate space (logical pixels).
-///
-/// For now layout pixels are equivalent to layer pixels, but it may change.
-pub type LayoutPixel = LayerPixel;
-
-pub type LayoutRect = LayerRect;
-pub type LayoutPoint = LayerPoint;
-pub type LayoutVector2D = LayerVector2D;
-pub type LayoutVector3D = LayerVector3D;
-pub type LayoutSize = LayerSize;
+#[derive(Hash, Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, Deserialize, Serialize)]
+pub struct LayoutPixel;
 
-/// Geometry in a layer's local coordinate space (logical pixels).
-#[derive(Hash, Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, Deserialize, Serialize)]
-pub struct LayerPixel;
-
-pub type LayerRect = TypedRect<f32, LayerPixel>;
-pub type LayerPoint = TypedPoint2D<f32, LayerPixel>;
-pub type LayerPoint3D = TypedPoint3D<f32, LayerPixel>;
-pub type LayerVector2D = TypedVector2D<f32, LayerPixel>;
-pub type LayerVector3D = TypedVector3D<f32, LayerPixel>;
-pub type LayerSize = TypedSize2D<f32, LayerPixel>;
+pub type LayoutRect = TypedRect<f32, LayoutPixel>;
+pub type LayoutPoint = TypedPoint2D<f32, LayoutPixel>;
+pub type LayoutPoint3D = TypedPoint3D<f32, LayoutPixel>;
+pub type LayoutVector2D = TypedVector2D<f32, LayoutPixel>;
+pub type LayoutVector3D = TypedVector3D<f32, LayoutPixel>;
+pub type LayoutSize = TypedSize2D<f32, LayoutPixel>;
 
 /// Geometry in a layer's scrollable parent coordinate space (logical pixels).
 ///
 /// Some layers are scrollable while some are not. There is a distinction between
 /// a layer's parent layer and a layer's scrollable parent layer (its closest parent
 /// that is scrollable, but not necessarily its immediate parent). Most of the internal
 /// transforms are expressed in terms of the scrollable parent and not the immediate
 /// parent.
@@ -94,38 +83,37 @@ pub type WorldVector3D = TypedVector3D<f
 
 /// Offset in number of tiles.
 #[derive(Hash, Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd)]
 pub struct Tiles;
 pub type TileOffset = TypedPoint2D<u16, Tiles>;
 
 /// Scaling ratio from world pixels to device pixels.
 pub type DevicePixelScale = TypedScale<f32, WorldPixel, DevicePixel>;
-/// Scaling ratio from layer to world. Used for cases where we know the layer
+/// Scaling ratio from layout to world. Used for cases where we know the layout
 /// is in world space, or specifically want to treat it this way.
-pub type LayerToWorldScale = TypedScale<f32, LayerPixel, WorldPixel>;
+pub type LayoutToWorldScale = TypedScale<f32, LayoutPixel, WorldPixel>;
 
 pub type LayoutTransform = TypedTransform3D<f32, LayoutPixel, LayoutPixel>;
-pub type LayerTransform = TypedTransform3D<f32, LayerPixel, LayerPixel>;
-pub type LayerToScrollTransform = TypedTransform3D<f32, LayerPixel, ScrollLayerPixel>;
-pub type ScrollToLayerTransform = TypedTransform3D<f32, ScrollLayerPixel, LayerPixel>;
-pub type LayerToWorldTransform = TypedTransform3D<f32, LayerPixel, WorldPixel>;
-pub type WorldToLayerTransform = TypedTransform3D<f32, WorldPixel, LayerPixel>;
+pub type LayoutToScrollTransform = TypedTransform3D<f32, LayoutPixel, ScrollLayerPixel>;
+pub type ScrollToLayoutTransform = TypedTransform3D<f32, ScrollLayerPixel, LayoutPixel>;
+pub type LayoutToWorldTransform = TypedTransform3D<f32, LayoutPixel, WorldPixel>;
+pub type WorldToLayoutTransform = TypedTransform3D<f32, WorldPixel, LayoutPixel>;
 pub type ScrollToWorldTransform = TypedTransform3D<f32, ScrollLayerPixel, WorldPixel>;
 
 // Fixed position coordinates, to avoid float precision errors.
-pub type LayerPointAu = TypedPoint2D<Au, LayerPixel>;
-pub type LayerRectAu = TypedRect<Au, LayerPixel>;
-pub type LayerSizeAu = TypedSize2D<Au, LayerPixel>;
+pub type LayoutPointAu = TypedPoint2D<Au, LayoutPixel>;
+pub type LayoutRectAu = TypedRect<Au, LayoutPixel>;
+pub type LayoutSizeAu = TypedSize2D<Au, LayoutPixel>;
 
-pub fn as_scroll_parent_rect(rect: &LayerRect) -> ScrollLayerRect {
+pub fn as_scroll_parent_rect(rect: &LayoutRect) -> ScrollLayerRect {
     ScrollLayerRect::from_untyped(&rect.to_untyped())
 }
 
-pub fn as_scroll_parent_vector(vector: &LayerVector2D) -> ScrollLayerVector2D {
+pub fn as_scroll_parent_vector(vector: &LayoutVector2D) -> ScrollLayerVector2D {
     ScrollLayerVector2D::from_untyped(&vector.to_untyped())
 }
 
 /// Stores two coordinates in texel space. The coordinates
 /// are stored in texel coordinates because the texture atlas
 /// may grow. Storing them as texel coords and normalizing
 /// the UVs in the vertex shader means nothing needs to be
 /// updated on the CPU when the texture size changes.
--- a/gfx/webrender_bindings/revision.txt
+++ b/gfx/webrender_bindings/revision.txt
@@ -1,1 +1,1 @@
-ad06d8e05e8475c9788cffa7e6cbac70acbdb399
+751236199b39bb8dac78522713133ca18c603fb3
--- a/gfx/wrench/src/main.rs
+++ b/gfx/wrench/src/main.rs
@@ -344,17 +344,17 @@ impl RenderNotifier for Notifier {
     fn wake_up(&self) {
         self.tx.send(NotifierEvent::WakeUp).unwrap();
     }
 
     fn shut_down(&self) {
         self.tx.send(NotifierEvent::ShutDown).unwrap();
     }
 
-    fn new_document_ready(&self, _: DocumentId, _scrolled: bool, composite_needed: bool) {
+    fn new_frame_ready(&self, _: DocumentId, _scrolled: bool, composite_needed: bool) {
         if composite_needed {
             self.wake_up();
         }
     }
 }
 
 fn create_notifier() -> (Box<RenderNotifier>, Receiver<NotifierEvent>) {
     let (tx, rx) = channel();
--- a/gfx/wrench/src/reftest.rs
+++ b/gfx/wrench/src/reftest.rs
@@ -486,17 +486,21 @@ impl<'a> ReftestHarness<'a> {
         reader.allow_mipmaps(allow_mipmaps);
         reader.do_frame(self.wrench);
 
         // wait for the frame
         self.rx.recv().unwrap();
         let stats = self.wrench.render();
 
         let window_size = self.window.get_inner_size();
-        assert!(size.width <= window_size.width && size.height <= window_size.height);
+        assert!(
+            size.width <= window_size.width &&
+            size.height <= window_size.height,
+            format!("size={:?} ws={:?}", size, window_size)
+        );
 
         // taking the bottom left sub-rectangle
         let rect = DeviceUintRect::new(DeviceUintPoint::new(0, window_size.height - size.height), size);
         let pixels = self.wrench.renderer.read_pixels_rgba8(rect);
         self.window.swap_buffers();
 
         let write_debug_images = false;
         if write_debug_images {
--- a/gfx/wrench/src/scene.rs
+++ b/gfx/wrench/src/scene.rs
@@ -1,15 +1,15 @@
 /* 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 std::collections::HashMap;
 use webrender::api::{BuiltDisplayList, ColorF, Epoch};
-use webrender::api::{LayerSize, PipelineId};
+use webrender::api::{LayoutSize, PipelineId};
 use webrender::api::{PropertyBinding, PropertyBindingId, LayoutTransform, DynamicProperties};
 
 /// Stores a map of the animated property bindings for the current display list. These
 /// can be used to animate the transform and/or opacity of a display list without
 /// re-submitting the display list itself.
 #[derive(Default)]
 pub struct SceneProperties {
     transform_properties: HashMap<PropertyBindingId, LayoutTransform>,
@@ -69,17 +69,17 @@ impl SceneProperties {
         }
     }
 }
 
 /// A representation of the layout within the display port for a given document or iframe.
 #[derive(Debug)]
 pub struct ScenePipeline {
     pub epoch: Epoch,
-    pub viewport_size: LayerSize,
+    pub viewport_size: LayoutSize,
     pub background_color: Option<ColorF>,
 }
 
 /// A complete representation of the layout bundling visible pipelines together.
 pub struct Scene {
     pub properties: SceneProperties,
     pub root_pipeline_id: Option<PipelineId>,
     pub pipeline_map: HashMap<PipelineId, ScenePipeline>,
@@ -108,17 +108,17 @@ impl Scene {
         self.display_lists.remove(pipeline_id);
     }
 
     pub fn begin_display_list(
         &mut self,
         pipeline_id: &PipelineId,
         epoch: &Epoch,
         background_color: &Option<ColorF>,
-        viewport_size: &LayerSize,
+        viewport_size: &LayoutSize,
     ) {
         let new_pipeline = ScenePipeline {
             epoch: epoch.clone(),
             viewport_size: viewport_size.clone(),
             background_color: background_color.clone(),
         };
 
         self.pipeline_map.insert(pipeline_id.clone(), new_pipeline);
--- a/gfx/wrench/src/wrench.rs
+++ b/gfx/wrench/src/wrench.rs
@@ -104,17 +104,17 @@ impl RenderNotifier for Notifier {
     fn clone(&self) -> Box<RenderNotifier> {
         Box::new(Notifier(self.0.clone()))
     }
 
     fn wake_up(&self) {
         self.update(false);
     }
 
-    fn new_document_ready(&self, _: DocumentId, scrolled: bool, _composite_needed: bool) {
+    fn new_frame_ready(&self, _: DocumentId, scrolled: bool, _composite_needed: bool) {
         self.update(!scrolled);
     }
 }
 
 pub trait WrenchThing {
     fn next_frame(&mut self);
     fn prev_frame(&mut self);
     fn do_frame(&mut self, &mut Wrench) -> u32;
@@ -278,53 +278,53 @@ impl Wrench {
 
     pub fn layout_simple_ascii(
         &mut self,
         font_key: FontKey,
         instance_key: FontInstanceKey,
         render_mode: Option<FontRenderMode>,
         text: &str,
         size: Au,
-        origin: LayerPoint,
+        origin: LayoutPoint,
         flags: FontInstanceFlags,
-    ) -> (Vec<u32>, Vec<LayerPoint>, LayoutRect) {
+    ) -> (Vec<u32>, Vec<LayoutPoint>, LayoutRect) {
         // Map the string codepoints to glyph indices in this font.
         // Just drop any glyph that isn't present in this font.
         let indices: Vec<u32> = self.api
             .get_glyph_indices(font_key, text)
             .iter()
             .filter_map(|idx| *idx)
             .collect();
 
         let render_mode = render_mode.unwrap_or(<FontInstanceOptions as Default>::default().render_mode);
         let subpx_dir = SubpixelDirection::Horizontal.limit_by(render_mode);
 
         // Retrieve the metrics for each glyph.
         let mut keys = Vec::new();
         for glyph_index in &indices {
             keys.push(GlyphKey::new(
                 *glyph_index,
-                LayerPoint::zero(),
+                LayoutPoint::zero(),
                 render_mode,
                 subpx_dir,
             ));
         }
         let metrics = self.api.get_glyph_dimensions(instance_key, keys);
 
         let mut bounding_rect = LayoutRect::zero();
         let mut positions = Vec::new();
 
         let mut cursor = origin;
         let direction = if flags.contains(FontInstanceFlags::TRANSPOSE) {
-            LayerVector2D::new(
+            LayoutVector2D::new(
                 0.0,
                 if flags.contains(FontInstanceFlags::FLIP_Y) { -1.0 } else { 1.0 },
             )
         } else {
-            LayerVector2D::new(
+            LayoutVector2D::new(
                 if flags.contains(FontInstanceFlags::FLIP_X) { -1.0 } else { 1.0 },
                 0.0,
             )
         };
         for metric in metrics {
             positions.push(cursor);
 
             match metric {
@@ -495,18 +495,18 @@ impl Wrench {
 
     pub fn begin_frame(&mut self) {
         self.frame_start_sender.push(time::SteadyTime::now());
     }
 
     pub fn send_lists(
         &mut self,
         frame_number: u32,
-        display_lists: Vec<(PipelineId, LayerSize, BuiltDisplayList)>,
-        scroll_offsets: &HashMap<ExternalScrollId, LayerPoint>,
+        display_lists: Vec<(PipelineId, LayoutSize, BuiltDisplayList)>,
+        scroll_offsets: &HashMap<ExternalScrollId, LayoutPoint>,
     ) {
         let root_background_color = Some(ColorF::new(1.0, 1.0, 1.0, 1.0));
 
         let mut txn = Transaction::new();
         for display_list in display_lists {
             txn.set_display_list(
                 Epoch(frame_number),
                 root_background_color,
--- a/gfx/wrench/src/yaml_frame_reader.rs
+++ b/gfx/wrench/src/yaml_frame_reader.rs
@@ -188,17 +188,17 @@ pub struct YamlFrameReader {
 
     include_only: Vec<String>,
 
     watch_source: bool,
     list_resources: bool,
 
     /// A HashMap of offsets which specify what scroll offsets particular
     /// scroll layers should be initialized with.
-    scroll_offsets: HashMap<ExternalScrollId, LayerPoint>,
+    scroll_offsets: HashMap<ExternalScrollId, LayoutPoint>,
 
     image_map: HashMap<(PathBuf, Option<i64>), (ImageKey, LayoutSize)>,
 
     fonts: HashMap<FontDescriptor, FontKey>,
     font_instances: HashMap<(FontKey, Au, FontInstanceFlags), FontInstanceKey>,
     font_render_mode: Option<FontRenderMode>,
     allow_mipmaps: bool,
 
@@ -1346,26 +1346,26 @@ impl YamlFrameReader {
         dl: &mut DisplayListBuilder,
         wrench: &mut Wrench,
         yaml: &Yaml,
     ) {
         let clip_rect = yaml["bounds"]
             .as_rect()
             .expect("scroll frame must have a bounds");
         let content_size = yaml["content-size"].as_size().unwrap_or(clip_rect.size);
-        let content_rect = LayerRect::new(clip_rect.origin, content_size);
+        let content_rect = LayoutRect::new(clip_rect.origin, content_size);
 
         let numeric_id = yaml["id"].as_i64().map(|id| id as u64);
 
         let complex_clips = self.to_complex_clip_regions(&yaml["complex"]);
         let image_mask = self.to_image_mask(&yaml["image-mask"], wrench);
 
         let external_id =  yaml["scroll-offset"].as_point().map(|size| {
             let id = ExternalScrollId((self.scroll_offsets.len() + 1) as u64, dl.pipeline_id);
-            self.scroll_offsets.insert(id, LayerPoint::new(size.x, size.y));
+            self.scroll_offsets.insert(id, LayoutPoint::new(size.x, size.y));
             id
         });
 
         let real_id = dl.define_scroll_frame(
             external_id,
             content_rect,
             clip_rect,
             complex_clips,
@@ -1536,17 +1536,17 @@ impl YamlFrameReader {
             .unwrap_or(ScrollPolicy::Scrollable);
         let glyph_raster_space = yaml["glyph-raster-space"]
             .as_glyph_raster_space()
             .unwrap_or(GlyphRasterSpace::Screen);
 
         if is_root {
             if let Some(size) = yaml["scroll-offset"].as_point() {
                 let external_id = ExternalScrollId(0, dl.pipeline_id);
-                self.scroll_offsets.insert(external_id, LayerPoint::new(size.x, size.y));
+                self.scroll_offsets.insert(external_id, LayoutPoint::new(size.x, size.y));
             }
         }
 
         let filters = yaml["filters"].as_vec_filter_op().unwrap_or(vec![]);
         info.rect = bounds;
         info.clip_rect = bounds;
 
         dl.push_stacking_context(
--- a/gfx/wrench/src/yaml_frame_writer.rs
+++ b/gfx/wrench/src/yaml_frame_writer.rs
@@ -702,17 +702,17 @@ impl YamlFrameWriter {
                 *list_iterator = traversal;
             }
             let base = match list_iterator.next() {
                 Some(base) => base,
                 None => break,
             };
 
             let mut v = new_table();
-            let info = base.get_layer_primitive_info(&LayoutVector2D::zero());
+            let info = base.get_layout_primitive_info(&LayoutVector2D::zero());
             rect_node(&mut v, "bounds", &info.rect);
             rect_node(&mut v, "clip-rect", &info.clip_rect);
 
             if let Some(tag) = info.tag {
                 yaml_node(
                     &mut v,
                     "hit-testing-tag",
                      Yaml::Array(vec![Yaml::Integer(tag.0 as i64), Yaml::Integer(tag.1 as i64)])