Bug 1456114 - Update webrender to commit 751236199b39bb8dac78522713133ca18c603fb3. r=jrmuizel
authorKartikaya Gupta <kgupta@mozilla.com>
Thu, 26 Apr 2018 14:14:24 -0400
changeset 415927 60f901febe0d83fec6fb072b39d9c6837fb114e6
parent 415926 94d0e43dad115ca9c7295278415ffa11abfb00a1
child 415928 c7f74ea37604b5e021dcd94acd4fb4f140a7bc09
push id102694
push usercsabou@mozilla.com
push dateFri, 27 Apr 2018 10:15:42 +0000
treeherdermozilla-inbound@d8c8620f0be8 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjrmuizel
bugs1456114
milestone61.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 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)])