Bug 1405399 - Update webrender to commit a884e676449e5b41669cd6de51af14e70cbe3512. r?Gankro draft
authorKartikaya Gupta <kgupta@mozilla.com>
Wed, 04 Oct 2017 14:51:00 -0400
changeset 675022 cd51c6668d75dccf46493199753b575ca9ed4d5c
parent 674983 ee1c41cf306df0043a8e68af042f133acf2ef94e
child 675023 3c4c62ce9fbc77472237b9ba74d8dc1d11a6faf3
push id83018
push userkgupta@mozilla.com
push dateWed, 04 Oct 2017 19:05:12 +0000
reviewersGankro
bugs1405399
milestone58.0a1
Bug 1405399 - Update webrender to commit a884e676449e5b41669cd6de51af14e70cbe3512. r?Gankro MozReview-Commit-ID: AABRgb2Ruds
gfx/doc/README.webrender
gfx/webrender/res/ps_angle_gradient.glsl
gfx/webrender/res/ps_image.glsl
gfx/webrender/src/frame.rs
gfx/webrender/src/frame_builder.rs
gfx/webrender/src/prim_store.rs
gfx/webrender/src/render_backend.rs
gfx/webrender/src/renderer.rs
gfx/webrender/src/tiling.rs
gfx/webrender_api/src/display_item.rs
gfx/webrender_api/src/display_list.rs
--- a/gfx/doc/README.webrender
+++ b/gfx/doc/README.webrender
@@ -74,9 +74,9 @@ there is another crate in m-c called moz
 the same folder to store its rust dependencies. If one of the libraries that is
 required by both mozjs_sys and webrender is updated without updating the other
 project's Cargo.lock file, that results in build bustage.
 This means that any time you do this sort of manual update of packages, you need
 to make sure that mozjs_sys also has its Cargo.lock file updated if needed, hence
 the need to run the cargo update command in js/src as well. Hopefully this will
 be resolved soon.
 
-Latest Commit: aa81aebba2c1b8ff8af5d40796154d66349fd131
+Latest Commit: a884e676449e5b41669cd6de51af14e70cbe3512
--- a/gfx/webrender/res/ps_angle_gradient.glsl
+++ b/gfx/webrender/res/ps_angle_gradient.glsl
@@ -38,27 +38,42 @@ void main(void) {
 
     vTileSize = gradient.tile_size_repeat.xy;
     vTileRepeat = gradient.tile_size_repeat.zw;
 
     vGradientAddress = prim.specific_prim_address + VECS_PER_GRADIENT;
 
     // Whether to repeat the gradient instead of clamping.
     vGradientRepeat = float(int(gradient.extend_mode.x) != EXTEND_MODE_CLAMP);
+
+    write_clip(vi.screen_pos, prim.clip_area);
 }
 #endif
 
 #ifdef WR_FRAGMENT_SHADER
 void main(void) {
     vec2 pos = mod(vPos, vTileRepeat);
 
     if (pos.x >= vTileSize.x ||
         pos.y >= vTileSize.y) {
         discard;
     }
 
     float offset = dot(pos - vStartPoint, vScaledDir);
 
-    oFragColor = sample_gradient(vGradientAddress,
+    vec4 color = sample_gradient(vGradientAddress,
                                  offset,
                                  vGradientRepeat);
+
+    // Un-premultiply the color from sampling the gradient.
+    if (color.a > 0.0) {
+        color.rgb /= color.a;
+
+        // Apply the clip mask
+        color.a = min(color.a, do_clip());
+
+        // Pre-multiply the result.
+        color.rgb *= color.a;
+    }
+
+    oFragColor = color;
 }
 #endif
--- a/gfx/webrender/res/ps_image.glsl
+++ b/gfx/webrender/res/ps_image.glsl
@@ -86,28 +86,35 @@ void main(void) {
 #ifdef WR_FRAGMENT_SHADER
 void main(void) {
 #ifdef WR_FEATURE_TRANSFORM
     float alpha = 0.0;
     vec2 pos = init_transform_fs(vLocalPos, alpha);
 
     // We clamp the texture coordinate calculation here to the local rectangle boundaries,
     // which makes the edge of the texture stretch instead of repeat.
+    vec2 upper_bound_mask = step(vLocalRect.zw, pos);
     vec2 relative_pos_in_rect = clamp(pos, vLocalRect.xy, vLocalRect.zw) - vLocalRect.xy;
 #else
     float alpha = 1.0;
     vec2 relative_pos_in_rect = vLocalPos;
+    vec2 upper_bound_mask = vec2(0.0);
 #endif
 
     alpha = min(alpha, do_clip());
 
     // We calculate the particular tile this fragment belongs to, taking into
     // account the spacing in between tiles. We only paint if our fragment does
     // not fall into that spacing.
-    vec2 position_in_tile = mod(relative_pos_in_rect, vStretchSize + vTileSpacing);
+    // If the pixel is at the local rectangle upper bound, we force the current
+    // tile upper bound in order to avoid wrapping.
+    vec2 position_in_tile = mix(
+        mod(relative_pos_in_rect, vStretchSize + vTileSpacing),
+        vStretchSize,
+        upper_bound_mask);
     vec2 st = vTextureOffset + ((position_in_tile / vStretchSize) * vTextureSize);
     st = clamp(st, vStRect.xy, vStRect.zw);
 
     alpha = alpha * float(all(bvec2(step(position_in_tile, vStretchSize))));
 
     oFragColor = vec4(alpha) * TEX_SAMPLE(sColor0, vec3(st, vLayer));
 }
 #endif
--- a/gfx/webrender/src/frame.rs
+++ b/gfx/webrender/src/frame.rs
@@ -795,25 +795,25 @@ impl Frame {
             SpecificDisplayItem::PopNestedDisplayList => context.pop_nested_display_list_ids(),
 
             // Do nothing; these are dummy items for the display list parser
             SpecificDisplayItem::SetGradientStops => {}
 
             SpecificDisplayItem::PopStackingContext => {
                 unreachable!("Should have returned in parent method.")
             }
-            SpecificDisplayItem::PushTextShadow(shadow) => {
+            SpecificDisplayItem::PushShadow(shadow) => {
                 let mut prim_info = prim_info.clone();
                 prim_info.rect = LayerRect::zero();
                 context
                     .builder
-                    .push_text_shadow(shadow, clip_and_scroll, &prim_info);
+                    .push_shadow(shadow, clip_and_scroll, &prim_info);
             }
-            SpecificDisplayItem::PopTextShadow => {
-                context.builder.pop_text_shadow();
+            SpecificDisplayItem::PopShadow => {
+                context.builder.pop_shadow();
             }
         }
         None
     }
 
     fn flatten_root<'a>(
         &mut self,
         traversal: &mut BuiltDisplayListIter<'a>,
--- a/gfx/webrender/src/frame_builder.rs
+++ b/gfx/webrender/src/frame_builder.rs
@@ -5,33 +5,33 @@
 use api::{BorderDetails, BorderDisplayItem, BorderRadius, BoxShadowClipMode, BuiltDisplayList};
 use api::{ClipAndScrollInfo, ClipId, ColorF};
 use api::{DeviceIntPoint, DeviceIntRect, DeviceIntSize, DeviceUintRect, DeviceUintSize};
 use api::{ExtendMode, FIND_ALL, FilterOp, FontInstance, FontRenderMode};
 use api::{GlyphInstance, GlyphOptions, GradientStop, HitTestFlags, HitTestItem, HitTestResult};
 use api::{ImageKey, ImageRendering, ItemRange, ItemTag, LayerPoint, LayerPrimitiveInfo, LayerRect};
 use api::{LayerSize, LayerToScrollTransform, LayerVector2D, LayoutVector2D, LineOrientation};
 use api::{LineStyle, LocalClip, POINT_RELATIVE_TO_PIPELINE_VIEWPORT, PipelineId, RepeatMode};
-use api::{ScrollSensitivity, SubpixelDirection, TextShadow, TileOffset, TransformStyle};
+use api::{ScrollSensitivity, SubpixelDirection, Shadow, TileOffset, TransformStyle};
 use api::{WorldPixel, WorldPoint, YuvColorSpace, YuvData, device_length};
 use app_units::Au;
 use border::ImageBorderSegment;
 use clip::{ClipMode, ClipRegion, ClipSource, ClipSources, ClipStore, Contains};
 use clip_scroll_node::{ClipInfo, ClipScrollNode, NodeType};
 use clip_scroll_tree::ClipScrollTree;
 use euclid::{SideOffsets2D, vec2, vec3};
 use frame::FrameId;
 use gpu_cache::GpuCache;
 use internal_types::{FastHashMap, FastHashSet, HardwareCompositeOp};
 use plane_split::{BspSplitter, Polygon, Splitter};
 use prim_store::{BoxShadowPrimitiveCpu, TexelRect, YuvImagePrimitiveCpu};
 use prim_store::{GradientPrimitiveCpu, ImagePrimitiveCpu, LinePrimitive, PrimitiveKind};
 use prim_store::{PrimitiveContainer, PrimitiveIndex};
 use prim_store::{PrimitiveStore, RadialGradientPrimitiveCpu};
-use prim_store::{RectanglePrimitive, TextRunPrimitiveCpu, TextShadowPrimitiveCpu};
+use prim_store::{RectanglePrimitive, TextRunPrimitiveCpu, ShadowPrimitiveCpu};
 use profiler::{FrameProfileCounters, GpuCacheProfileCounters, TextureCacheProfileCounters};
 use render_task::{AlphaRenderItem, ClipWorkItem, RenderTask};
 use render_task::{RenderTaskId, RenderTaskLocation, RenderTaskTree};
 use resource_cache::ResourceCache;
 use scene::ScenePipeline;
 use std::{mem, usize, f32, i32};
 use tiling::{ClipScrollGroup, ClipScrollGroupIndex, CompositeOps, Frame};
 use tiling::{ContextIsolation, StackingContextIndex};
@@ -95,17 +95,17 @@ pub struct FrameBuilder {
 
     stacking_context_store: Vec<StackingContext>,
     clip_scroll_group_store: Vec<ClipScrollGroup>,
     // Note: value here is meant to be `ClipScrollGroupIndex`,
     // but we already have `ClipAndScrollInfo` in the key
     clip_scroll_group_indices: FastHashMap<ClipAndScrollInfo, usize>,
     packed_layers: Vec<PackedLayer>,
 
-    // A stack of the current text-shadow primitives.
+    // A stack of the current shadow primitives.
     shadow_prim_stack: Vec<PrimitiveIndex>,
 
     scrollbar_prims: Vec<ScrollbarPrimitive>,
 
     /// A stack of scroll nodes used during display list processing to properly
     /// parent new scroll nodes.
     reference_frame_stack: Vec<ClipId>,
 
@@ -573,53 +573,53 @@ impl FrameBuilder {
 
         clip_scroll_tree.add_node(node, new_node_id);
     }
 
     pub fn pop_reference_frame(&mut self) {
         self.reference_frame_stack.pop();
     }
 
-    pub fn push_text_shadow(
+    pub fn push_shadow(
         &mut self,
-        shadow: TextShadow,
+        shadow: Shadow,
         clip_and_scroll: ClipAndScrollInfo,
         info: &LayerPrimitiveInfo,
     ) {
-        let prim = TextShadowPrimitiveCpu {
+        let prim = ShadowPrimitiveCpu {
             shadow,
             primitives: Vec::new(),
             render_task_id: None,
         };
 
-        // Create an empty text-shadow primitive. Insert it into
+        // Create an empty shadow primitive. Insert it into
         // the draw lists immediately so that it will be drawn
         // before any visual text elements that are added as
-        // part of this text-shadow context.
+        // part of this shadow context.
         let prim_index = self.add_primitive(
             clip_and_scroll,
             info,
             Vec::new(),
-            PrimitiveContainer::TextShadow(prim),
+            PrimitiveContainer::Shadow(prim),
         );
 
         self.shadow_prim_stack.push(prim_index);
     }
 
-    pub fn pop_text_shadow(&mut self) {
+    pub fn pop_shadow(&mut self) {
         let prim_index = self.shadow_prim_stack
             .pop()
             .expect("invalid shadow push/pop count");
 
         // By now, the local rect of the text shadow has been calculated. It
         // is calculated as the items in the shadow are added. It's now
         // safe to offset the local rect by the offset of the shadow, which
         // is then used when blitting the shadow to the final location.
         let metadata = &mut self.prim_store.cpu_metadata[prim_index.0];
-        let prim = &self.prim_store.cpu_text_shadows[metadata.cpu_prim_index.0];
+        let prim = &self.prim_store.cpu_shadows[metadata.cpu_prim_index.0];
 
         metadata.local_rect = metadata.local_rect.translate(&prim.shadow.offset);
     }
 
     pub fn add_solid_rectangle(
         &mut self,
         clip_and_scroll: ClipAndScrollInfo,
         info: &LayerPrimitiveInfo,
@@ -678,25 +678,25 @@ impl FrameBuilder {
         };
 
         let line = LinePrimitive {
             color: *color,
             style: style,
             orientation: orientation,
         };
 
-        let mut fast_text_shadow_prims = Vec::new();
+        let mut fast_shadow_prims = Vec::new();
         for shadow_prim_index in &self.shadow_prim_stack {
             let shadow_metadata = &self.prim_store.cpu_metadata[shadow_prim_index.0];
-            let shadow_prim = &self.prim_store.cpu_text_shadows[shadow_metadata.cpu_prim_index.0];
+            let shadow_prim = &self.prim_store.cpu_shadows[shadow_metadata.cpu_prim_index.0];
             if shadow_prim.shadow.blur_radius == 0.0 {
-                fast_text_shadow_prims.push(shadow_prim.shadow);
+                fast_shadow_prims.push(shadow_prim.shadow);
             }
         }
-        for shadow in fast_text_shadow_prims {
+        for shadow in fast_shadow_prims {
             let mut line = line.clone();
             line.color = shadow.color;
             let mut info = info.clone();
             info.rect = new_rect.translate(&shadow.offset);
             self.add_primitive(
                 clip_and_scroll,
                 &info,
                 Vec::new(),
@@ -715,19 +715,19 @@ impl FrameBuilder {
 
         if color.a > 0.0 {
             self.add_primitive_to_hit_testing_list(&info, clip_and_scroll);
             self.add_primitive_to_draw_list(prim_index, clip_and_scroll);
         }
 
         for shadow_prim_index in &self.shadow_prim_stack {
             let shadow_metadata = &mut self.prim_store.cpu_metadata[shadow_prim_index.0];
-            debug_assert_eq!(shadow_metadata.prim_kind, PrimitiveKind::TextShadow);
+            debug_assert_eq!(shadow_metadata.prim_kind, PrimitiveKind::Shadow);
             let shadow_prim =
-                &mut self.prim_store.cpu_text_shadows[shadow_metadata.cpu_prim_index.0];
+                &mut self.prim_store.cpu_shadows[shadow_metadata.cpu_prim_index.0];
 
             // Only run real blurs here (fast path zero blurs are handled above).
             if shadow_prim.shadow.blur_radius > 0.0 {
                 let shadow_rect = new_rect.inflate(
                     shadow_prim.shadow.blur_radius,
                     shadow_prim.shadow.blur_radius,
                 );
                 shadow_metadata.local_rect = shadow_metadata.local_rect.union(&shadow_rect);
@@ -1203,37 +1203,37 @@ impl FrameBuilder {
         // Text shadows that have a blur radius of 0 need to be rendered as normal
         // text elements to get pixel perfect results for reftests. It's also a big
         // performance win to avoid blurs and render target allocations where
         // possible. For any text shadows that have zero blur, create a normal text
         // primitive with the shadow's color and offset. These need to be added
         // *before* the visual text primitive in order to get the correct paint
         // order. Store them in a Vec first to work around borrowck issues.
         // TODO(gw): Refactor to avoid having to store them in a Vec first.
-        let mut fast_text_shadow_prims = Vec::new();
+        let mut fast_shadow_prims = Vec::new();
         for shadow_prim_index in &self.shadow_prim_stack {
             let shadow_metadata = &self.prim_store.cpu_metadata[shadow_prim_index.0];
-            let shadow_prim = &self.prim_store.cpu_text_shadows[shadow_metadata.cpu_prim_index.0];
+            let shadow_prim = &self.prim_store.cpu_shadows[shadow_metadata.cpu_prim_index.0];
             if shadow_prim.shadow.blur_radius == 0.0 {
                 let mut text_prim = prim.clone();
                 if font.render_mode != FontRenderMode::Bitmap {
                     text_prim.font.color = shadow_prim.shadow.color.into();
                 }
                 // If we have translucent text, we need to ensure it won't go
                 // through the subpixel blend mode, which doesn't work with
                 // traditional alpha blending.
                 if shadow_prim.shadow.color.a != 1.0 {
                     text_prim.font.render_mode = text_prim.font.render_mode.limit_by(FontRenderMode::Alpha);
                 }
                 text_prim.color = shadow_prim.shadow.color;
                 text_prim.offset += shadow_prim.shadow.offset;
-                fast_text_shadow_prims.push(text_prim);
+                fast_shadow_prims.push(text_prim);
             }
         }
-        for text_prim in fast_text_shadow_prims {
+        for text_prim in fast_shadow_prims {
             let rect = info.rect;
             let mut info = info.clone();
             info.rect = rect.translate(&text_prim.offset);
             self.add_primitive(
                 clip_and_scroll,
                 &info,
                 Vec::new(),
                 PrimitiveContainer::TextRun(text_prim),
@@ -1253,25 +1253,25 @@ impl FrameBuilder {
         if color.a > 0.0 {
             self.add_primitive_to_hit_testing_list(info, clip_and_scroll);
             self.add_primitive_to_draw_list(prim_index, clip_and_scroll);
         }
 
         // Now add this primitive index to all the currently active text shadow
         // primitives. Although we're adding the indices *after* the visual
         // primitive here, they will still draw before the visual text, since
-        // the text-shadow primitive itself has been added to the draw cmd
-        // list *before* the visual element, during push_text_shadow. We need
+        // the shadow primitive itself has been added to the draw cmd
+        // list *before* the visual element, during push_shadow. We need
         // the primitive index of the visual element here before we can add
         // the indices as sub-primitives to the shadow primitives.
         for shadow_prim_index in &self.shadow_prim_stack {
             let shadow_metadata = &mut self.prim_store.cpu_metadata[shadow_prim_index.0];
-            debug_assert_eq!(shadow_metadata.prim_kind, PrimitiveKind::TextShadow);
+            debug_assert_eq!(shadow_metadata.prim_kind, PrimitiveKind::Shadow);
             let shadow_prim =
-                &mut self.prim_store.cpu_text_shadows[shadow_metadata.cpu_prim_index.0];
+                &mut self.prim_store.cpu_shadows[shadow_metadata.cpu_prim_index.0];
 
             // Only run real blurs here (fast path zero blurs are handled above).
             if shadow_prim.shadow.blur_radius > 0.0 {
                 let shadow_rect = rect.inflate(
                     shadow_prim.shadow.blur_radius,
                     shadow_prim.shadow.blur_radius,
                 );
                 shadow_metadata.local_rect = shadow_metadata.local_rect.union(&shadow_rect);
--- a/gfx/webrender/src/prim_store.rs
+++ b/gfx/webrender/src/prim_store.rs
@@ -1,16 +1,16 @@
 /* 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, BuiltDisplayList, ColorF, ComplexClipRegion, DeviceIntRect, DeviceIntSize};
 use api::{DevicePoint, ExtendMode, FontInstance, FontRenderMode, GlyphInstance, GlyphKey};
 use api::{GradientStop, ImageKey, ImageRendering, ItemRange, ItemTag, LayerPoint, LayerRect};
-use api::{LayerSize, LayerVector2D, LineOrientation, LineStyle, TextShadow};
+use api::{LayerSize, LayerVector2D, LineOrientation, LineStyle, Shadow};
 use api::{TileOffset, YuvColorSpace, YuvFormat, device_length};
 use app_units::Au;
 use border::BorderCornerInstance;
 use clip::{ClipMode, ClipSourcesHandle, ClipStore, Geometry};
 use euclid::Size2D;
 use frame_builder::PrimitiveContext;
 use gpu_cache::{GpuBlockData, GpuCache, GpuCacheAddress, GpuCacheHandle, GpuDataRequest,
                 ToGpuBlocks};
@@ -105,17 +105,17 @@ pub enum PrimitiveKind {
     TextRun,
     Image,
     YuvImage,
     Border,
     AlignedGradient,
     AngleGradient,
     RadialGradient,
     BoxShadow,
-    TextShadow,
+    Shadow,
     Line,
 }
 
 impl GpuCacheHandle {
     pub fn as_int(&self, gpu_cache: &GpuCache) -> i32 {
         gpu_cache.get_address(self).as_int()
     }
 }
@@ -510,18 +510,18 @@ impl RadialGradientPrimitiveCpu {
         request.extend_from_slice(&self.gpu_blocks);
 
         let gradient_builder = GradientGpuBlockBuilder::new(self.stops_range, display_list);
         gradient_builder.build(false, &mut request);
     }
 }
 
 #[derive(Debug)]
-pub struct TextShadowPrimitiveCpu {
-    pub shadow: TextShadow,
+pub struct ShadowPrimitiveCpu {
+    pub shadow: Shadow,
     pub primitives: Vec<PrimitiveIndex>,
     pub render_task_id: Option<RenderTaskId>,
 }
 
 #[derive(Debug, Clone)]
 pub struct TextRunPrimitiveCpu {
     pub font: FontInstance,
     pub offset: LayerVector2D,
@@ -802,58 +802,58 @@ pub enum PrimitiveContainer {
     TextRun(TextRunPrimitiveCpu),
     Image(ImagePrimitiveCpu),
     YuvImage(YuvImagePrimitiveCpu),
     Border(BorderPrimitiveCpu),
     AlignedGradient(GradientPrimitiveCpu),
     AngleGradient(GradientPrimitiveCpu),
     RadialGradient(RadialGradientPrimitiveCpu),
     BoxShadow(BoxShadowPrimitiveCpu),
-    TextShadow(TextShadowPrimitiveCpu),
+    Shadow(ShadowPrimitiveCpu),
     Line(LinePrimitive),
 }
 
 pub struct PrimitiveStore {
     /// CPU side information only.
     pub cpu_rectangles: Vec<RectanglePrimitive>,
     pub cpu_text_runs: Vec<TextRunPrimitiveCpu>,
-    pub cpu_text_shadows: Vec<TextShadowPrimitiveCpu>,
+    pub cpu_shadows: Vec<ShadowPrimitiveCpu>,
     pub cpu_images: Vec<ImagePrimitiveCpu>,
     pub cpu_yuv_images: Vec<YuvImagePrimitiveCpu>,
     pub cpu_gradients: Vec<GradientPrimitiveCpu>,
     pub cpu_radial_gradients: Vec<RadialGradientPrimitiveCpu>,
     pub cpu_metadata: Vec<PrimitiveMetadata>,
     pub cpu_borders: Vec<BorderPrimitiveCpu>,
     pub cpu_box_shadows: Vec<BoxShadowPrimitiveCpu>,
     pub cpu_lines: Vec<LinePrimitive>,
 }
 
 impl PrimitiveStore {
     pub fn new() -> PrimitiveStore {
         PrimitiveStore {
             cpu_metadata: Vec::new(),
             cpu_rectangles: Vec::new(),
             cpu_text_runs: Vec::new(),
-            cpu_text_shadows: Vec::new(),
+            cpu_shadows: Vec::new(),
             cpu_images: Vec::new(),
             cpu_yuv_images: Vec::new(),
             cpu_gradients: Vec::new(),
             cpu_radial_gradients: Vec::new(),
             cpu_borders: Vec::new(),
             cpu_box_shadows: Vec::new(),
             cpu_lines: Vec::new(),
         }
     }
 
     pub fn recycle(self) -> Self {
         PrimitiveStore {
             cpu_metadata: recycle_vec(self.cpu_metadata),
             cpu_rectangles: recycle_vec(self.cpu_rectangles),
             cpu_text_runs: recycle_vec(self.cpu_text_runs),
-            cpu_text_shadows: recycle_vec(self.cpu_text_shadows),
+            cpu_shadows: recycle_vec(self.cpu_shadows),
             cpu_images: recycle_vec(self.cpu_images),
             cpu_yuv_images: recycle_vec(self.cpu_yuv_images),
             cpu_gradients: recycle_vec(self.cpu_gradients),
             cpu_radial_gradients: recycle_vec(self.cpu_radial_gradients),
             cpu_borders: recycle_vec(self.cpu_borders),
             cpu_box_shadows: recycle_vec(self.cpu_box_shadows),
             cpu_lines: recycle_vec(self.cpu_lines),
         }
@@ -915,25 +915,25 @@ impl PrimitiveStore {
                     prim_kind: PrimitiveKind::TextRun,
                     cpu_prim_index: SpecificPrimitiveIndex(self.cpu_text_runs.len()),
                     ..base_metadata
                 };
 
                 self.cpu_text_runs.push(text_cpu);
                 metadata
             }
-            PrimitiveContainer::TextShadow(text_shadow) => {
+            PrimitiveContainer::Shadow(shadow) => {
                 let metadata = PrimitiveMetadata {
                     opacity: PrimitiveOpacity::translucent(),
-                    prim_kind: PrimitiveKind::TextShadow,
-                    cpu_prim_index: SpecificPrimitiveIndex(self.cpu_text_shadows.len()),
+                    prim_kind: PrimitiveKind::Shadow,
+                    cpu_prim_index: SpecificPrimitiveIndex(self.cpu_shadows.len()),
                     ..base_metadata
                 };
 
-                self.cpu_text_shadows.push(text_shadow);
+                self.cpu_shadows.push(shadow);
                 metadata
             }
             PrimitiveContainer::Image(image_cpu) => {
                 let metadata = PrimitiveMetadata {
                     opacity: PrimitiveOpacity::translucent(),
                     prim_kind: PrimitiveKind::Image,
                     cpu_prim_index: SpecificPrimitiveIndex(self.cpu_images.len()),
                     ..base_metadata
@@ -1030,19 +1030,19 @@ impl PrimitiveStore {
         // Add any dynamic render tasks needed to render this primitive
         let metadata = &self.cpu_metadata[prim_index.0];
 
         let render_task_id = match metadata.prim_kind {
             PrimitiveKind::BoxShadow => {
                 let box_shadow = &self.cpu_box_shadows[metadata.cpu_prim_index.0];
                 box_shadow.render_task_id
             }
-            PrimitiveKind::TextShadow => {
-                let text_shadow = &self.cpu_text_shadows[metadata.cpu_prim_index.0];
-                text_shadow.render_task_id
+            PrimitiveKind::Shadow => {
+                let shadow = &self.cpu_shadows[metadata.cpu_prim_index.0];
+                shadow.render_task_id
             }
             PrimitiveKind::Rectangle |
             PrimitiveKind::TextRun |
             PrimitiveKind::Image |
             PrimitiveKind::AlignedGradient |
             PrimitiveKind::YuvImage |
             PrimitiveKind::Border |
             PrimitiveKind::AngleGradient |
@@ -1109,20 +1109,20 @@ impl PrimitiveStore {
                     cache_key,
                     cache_size,
                     prim_index
                 );
 
                 // ignore the new task if we are in a dependency context
                 box_shadow.render_task_id = render_tasks.map(|rt| rt.add(render_task));
             }
-            PrimitiveKind::TextShadow => {
-                let shadow = &mut self.cpu_text_shadows[metadata.cpu_prim_index.0];
+            PrimitiveKind::Shadow => {
+                let shadow = &mut self.cpu_shadows[metadata.cpu_prim_index.0];
 
-                // This is a text-shadow element. Create a render task that will
+                // This is a shadow element. Create a render task that will
                 // render the text run to a target, and then apply a gaussian
                 // blur to that text run in order to build the actual primitive
                 // which will be blitted to the framebuffer.
                 let cache_width =
                     (metadata.local_rect.size.width * prim_context.device_pixel_ratio).ceil() as i32;
                 let cache_height =
                     (metadata.local_rect.size.height * prim_context.device_pixel_ratio).ceil() as i32;
                 let cache_size = DeviceIntSize::new(cache_width, cache_height);
@@ -1229,18 +1229,18 @@ impl PrimitiveStore {
                 PrimitiveKind::RadialGradient => {
                     let gradient = &self.cpu_radial_gradients[metadata.cpu_prim_index.0];
                     gradient.build_gpu_blocks_for_angle_radial(prim_context.display_list, request);
                 }
                 PrimitiveKind::TextRun => {
                     let text = &self.cpu_text_runs[metadata.cpu_prim_index.0];
                     text.write_gpu_blocks(&mut request);
                 }
-                PrimitiveKind::TextShadow => {
-                    let prim = &self.cpu_text_shadows[metadata.cpu_prim_index.0];
+                PrimitiveKind::Shadow => {
+                    let prim = &self.cpu_shadows[metadata.cpu_prim_index.0];
                     request.push(prim.shadow.color);
                     request.push([
                         prim.shadow.offset.x,
                         prim.shadow.offset.y,
                         prim.shadow.blur_radius,
                         0.0,
                     ]);
                 }
@@ -1369,18 +1369,18 @@ impl PrimitiveStore {
                 Some(device_rect) => Geometry {
                     local_rect,
                     device_rect,
                 },
                 None => return None,
             };
 
             let dependencies = match metadata.prim_kind {
-                PrimitiveKind::TextShadow =>
-                    self.cpu_text_shadows[metadata.cpu_prim_index.0].primitives.clone(),
+                PrimitiveKind::Shadow =>
+                    self.cpu_shadows[metadata.cpu_prim_index.0].primitives.clone(),
                 _ => Vec::new(),
             };
             (geometry, dependencies)
         };
 
         // Recurse into any sub primitives and prepare them for rendering first.
         // TODO(gw): This code is a bit hacky to work around the borrow checker.
         //           Specifically, the clone() below on the primitive list for
--- a/gfx/webrender/src/render_backend.rs
+++ b/gfx/webrender/src/render_backend.rs
@@ -711,13 +711,13 @@ impl ToDebugString for SpecificDisplayIt
             SpecificDisplayItem::Iframe(..) => String::from("iframe"),
             SpecificDisplayItem::Clip(..) => String::from("clip"),
             SpecificDisplayItem::ScrollFrame(..) => String::from("scroll_frame"),
             SpecificDisplayItem::StickyFrame(..) => String::from("sticky_frame"),
             SpecificDisplayItem::PushNestedDisplayList => String::from("push_nested_display_list"),
             SpecificDisplayItem::PopNestedDisplayList => String::from("pop_nested_display_list"),
             SpecificDisplayItem::SetGradientStops => String::from("set_gradient_stops"),
             SpecificDisplayItem::PopStackingContext => String::from("pop_stacking_context"),
-            SpecificDisplayItem::PushTextShadow(..) => String::from("push_text_shadow"),
-            SpecificDisplayItem::PopTextShadow => String::from("pop_text_shadow"),
+            SpecificDisplayItem::PushShadow(..) => String::from("push_shadow"),
+            SpecificDisplayItem::PopShadow => String::from("pop_shadow"),
         }
     }
 }
--- a/gfx/webrender/src/renderer.rs
+++ b/gfx/webrender/src/renderer.rs
@@ -2654,17 +2654,17 @@ impl Renderer {
                     VertexArrayKind::Blur,
                     &BatchTextures::no_texture(),
                 );
             }
         }
 
         // Draw any textrun caches for this target. For now, this
         // is only used to cache text runs that are to be blurred
-        // for text-shadow support. In the future it may be worth
+        // for shadow support. In the future it may be worth
         // considering using this for (some) other text runs, since
         // it removes the overhead of submitting many small glyphs
         // to multiple tiles in the normal text run case.
         if !target.text_run_cache_prims.is_empty() {
             self.device.set_blend(true);
             self.device.set_blend_mode_alpha();
 
             let _gm = self.gpu_profile.add_marker(GPU_TAG_CACHE_TEXT_RUN);
--- a/gfx/webrender/src/tiling.rs
+++ b/gfx/webrender/src/tiling.rs
@@ -59,17 +59,17 @@ impl AlphaBatchHelpers for PrimitiveStor
                     FontRenderMode::Mono |
                     FontRenderMode::Bitmap => BlendMode::Alpha,
                 }
             }
             PrimitiveKind::Image |
             PrimitiveKind::AlignedGradient |
             PrimitiveKind::AngleGradient |
             PrimitiveKind::RadialGradient |
-            PrimitiveKind::TextShadow => if needs_blending {
+            PrimitiveKind::Shadow => if needs_blending {
                 BlendMode::PremultipliedAlpha
             } else {
                 BlendMode::None
             },
             _ => if needs_blending {
                 BlendMode::Alpha
             } else {
                 BlendMode::None
@@ -536,20 +536,20 @@ impl AlphaRenderItem {
                                         glyph.index_in_text_run,
                                         glyph.uv_rect_address.as_int(),
                                         0,
                                     ));
                                 }
                             },
                         );
                     }
-                    PrimitiveKind::TextShadow => {
-                        let text_shadow =
-                            &ctx.prim_store.cpu_text_shadows[prim_metadata.cpu_prim_index.0];
-                        let cache_task_id = text_shadow.render_task_id.expect("no render task!");
+                    PrimitiveKind::Shadow => {
+                        let shadow =
+                            &ctx.prim_store.cpu_shadows[prim_metadata.cpu_prim_index.0];
+                        let cache_task_id = shadow.render_task_id.expect("no render task!");
                         let cache_task_address = render_tasks.get_task_address(cache_task_id);
                         let textures = BatchTextures::render_target_cache();
                         let kind = BatchKind::Transformable(
                             transform_kind,
                             TransformBatchKind::CacheImage,
                         );
                         let key = BatchKey::new(kind, blend_mode, textures);
                         let batch = batch_list.get_suitable_batch(key, item_bounding_rect);
@@ -1135,18 +1135,18 @@ impl RenderTarget for ColorRenderTarget 
                     blur_direction: BlurDirection::Horizontal,
                 });
             }
             RenderTaskKind::CachePrimitive(prim_index) => {
                 let prim_metadata = ctx.prim_store.get_metadata(prim_index);
                 let prim_address = prim_metadata.gpu_location.as_int(gpu_cache);
 
                 match prim_metadata.prim_kind {
-                    PrimitiveKind::TextShadow => {
-                        let prim = &ctx.prim_store.cpu_text_shadows[prim_metadata.cpu_prim_index.0];
+                    PrimitiveKind::Shadow => {
+                        let prim = &ctx.prim_store.cpu_shadows[prim_metadata.cpu_prim_index.0];
 
                         let task_index = render_tasks.get_task_address(task_id);
 
                         for sub_prim_index in &prim.primitives {
                             let sub_metadata = ctx.prim_store.get_metadata(*sub_prim_index);
                             let sub_prim_address =
                                 gpu_cache.get_address(&sub_metadata.gpu_location);
                             let instance = SimplePrimitiveInstance::new(
@@ -1155,18 +1155,18 @@ impl RenderTarget for ColorRenderTarget 
                                 RenderTaskAddress(0),
                                 PackedLayerIndex(0).into(),
                                 0,
                             ); // z is disabled for rendering cache primitives
 
                             match sub_metadata.prim_kind {
                                 PrimitiveKind::TextRun => {
                                     // Add instances that reference the text run GPU location. Also supply
-                                    // the parent text-shadow prim address as a user data field, allowing
-                                    // the shader to fetch the text-shadow parameters.
+                                    // the parent shadow prim address as a user data field, allowing
+                                    // the shader to fetch the shadow parameters.
                                     let text = &ctx.prim_store.cpu_text_runs
                                         [sub_metadata.cpu_prim_index.0];
                                     let text_run_cache_prims = &mut self.text_run_cache_prims;
 
                                     let mut font = text.font.clone();
                                     font.size = font.size.scale_by(ctx.device_pixel_ratio);
                                     font.render_mode = text.shadow_render_mode;
 
--- a/gfx/webrender_api/src/display_item.rs
+++ b/gfx/webrender_api/src/display_item.rs
@@ -99,18 +99,18 @@ pub enum SpecificDisplayItem {
     Gradient(GradientDisplayItem),
     RadialGradient(RadialGradientDisplayItem),
     Iframe(IframeDisplayItem),
     PushStackingContext(PushStackingContextDisplayItem),
     PopStackingContext,
     SetGradientStops,
     PushNestedDisplayList,
     PopNestedDisplayList,
-    PushTextShadow(TextShadow),
-    PopTextShadow,
+    PushShadow(Shadow),
+    PopShadow,
 }
 
 #[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)]
 pub struct ClipDisplayItem {
     pub id: ClipId,
     pub parent_id: ClipId,
     pub image_mask: Option<ImageMask>,
 }
@@ -303,17 +303,17 @@ pub struct BoxShadowDisplayItem {
     pub blur_radius: f32,
     pub spread_radius: f32,
     pub border_radius: f32,
     pub clip_mode: BoxShadowClipMode,
 }
 
 #[repr(C)]
 #[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)]
-pub struct TextShadow {
+pub struct Shadow {
     pub offset: LayoutVector2D,
     pub color: ColorF,
     pub blur_radius: f32,
 }
 
 #[repr(u32)]
 #[derive(Debug, Copy, Clone, Hash, Eq, PartialEq, Serialize, Deserialize, Ord, PartialOrd)]
 pub enum ExtendMode {
--- a/gfx/webrender_api/src/display_list.rs
+++ b/gfx/webrender_api/src/display_list.rs
@@ -7,17 +7,17 @@ use {ClipAndScrollInfo, ClipDisplayItem,
 use {ExtendMode, FastHashMap, FastHashSet, FilterOp, FontInstanceKey, GlyphIndex, GlyphInstance};
 use {GlyphOptions, Gradient, GradientDisplayItem, GradientStop, IframeDisplayItem};
 use {ImageDisplayItem, ImageKey, ImageMask, ImageRendering, LayerPrimitiveInfo, LayoutPoint};
 use {LayoutPrimitiveInfo, LayoutRect, LayoutSize, LayoutTransform, LayoutVector2D};
 use {LineDisplayItem, LineOrientation, LineStyle, LocalClip, MixBlendMode, PipelineId};
 use {PropertyBinding, PushStackingContextDisplayItem, RadialGradient, RadialGradientDisplayItem};
 use {RectangleDisplayItem, ScrollFrameDisplayItem, ScrollPolicy, ScrollSensitivity};
 use {SpecificDisplayItem, StackingContext, StickyFrameDisplayItem, StickyFrameInfo};
-use {TextDisplayItem, TextShadow, TransformStyle, YuvColorSpace, YuvData};
+use {TextDisplayItem, Shadow, TransformStyle, YuvColorSpace, YuvData};
 use YuvImageDisplayItem;
 use bincode;
 use serde::{Deserialize, Serialize, Serializer};
 use serde::ser::{SerializeMap, SerializeSeq};
 use std::marker::PhantomData;
 use time::precise_time_ns;
 
 // We don't want to push a long text-run. If a text-run is too long, split it into several parts.
@@ -981,20 +981,45 @@ impl DisplayListBuilder {
         complex_clips: I,
         image_mask: Option<ImageMask>,
         scroll_sensitivity: ScrollSensitivity,
     ) -> ClipId
     where
         I: IntoIterator<Item = ComplexClipRegion>,
         I::IntoIter: ExactSizeIterator,
     {
+        let parent_id = self.clip_stack.last().unwrap().scroll_node_id;
+        self.define_scroll_frame_with_parent(
+            id,
+            parent_id,
+            content_rect,
+            clip_rect,
+            complex_clips,
+            image_mask,
+            scroll_sensitivity)
+    }
+
+    pub fn define_scroll_frame_with_parent<I>(
+        &mut self,
+        id: Option<ClipId>,
+        parent_id: ClipId,
+        content_rect: LayoutRect,
+        clip_rect: LayoutRect,
+        complex_clips: I,
+        image_mask: Option<ImageMask>,
+        scroll_sensitivity: ScrollSensitivity,
+    ) -> ClipId
+    where
+        I: IntoIterator<Item = ComplexClipRegion>,
+        I::IntoIter: ExactSizeIterator,
+    {
         let id = self.generate_clip_id(id);
         let item = SpecificDisplayItem::ScrollFrame(ScrollFrameDisplayItem {
             id: id,
-            parent_id: self.clip_stack.last().unwrap().scroll_node_id,
+            parent_id: parent_id,
             image_mask: image_mask,
             scroll_sensitivity,
         });
 
         let info = LayoutPrimitiveInfo {
             rect: content_rect,
             local_clip: LocalClip::from(clip_rect),
             is_backface_visible: true,
@@ -1012,20 +1037,41 @@ impl DisplayListBuilder {
         clip_rect: LayoutRect,
         complex_clips: I,
         image_mask: Option<ImageMask>,
     ) -> ClipId
     where
         I: IntoIterator<Item = ComplexClipRegion>,
         I::IntoIter: ExactSizeIterator,
     {
+        let parent_id = self.clip_stack.last().unwrap().scroll_node_id;
+        self.define_clip_with_parent(
+            id,
+            parent_id,
+            clip_rect,
+            complex_clips,
+            image_mask)
+    }
+
+    pub fn define_clip_with_parent<I>(
+        &mut self,
+        id: Option<ClipId>,
+        parent_id: ClipId,
+        clip_rect: LayoutRect,
+        complex_clips: I,
+        image_mask: Option<ImageMask>,
+    ) -> ClipId
+    where
+        I: IntoIterator<Item = ComplexClipRegion>,
+        I::IntoIter: ExactSizeIterator,
+    {
         let id = self.generate_clip_id(id);
         let item = SpecificDisplayItem::Clip(ClipDisplayItem {
             id,
-            parent_id: self.clip_stack.last().unwrap().scroll_node_id,
+            parent_id: parent_id,
             image_mask: image_mask,
         });
 
         let info = LayoutPrimitiveInfo::new(clip_rect);
 
         self.push_item(item, &info);
         self.push_iter(complex_clips);
         id
@@ -1082,22 +1128,22 @@ impl DisplayListBuilder {
             self.cache_glyphs(font_key, color, built_display_list.get(glyphs));
         }
 
         // Only append the actual items, not any caches
         self.data.extend_from_slice(built_display_list.item_slice());
         self.push_new_empty_item(SpecificDisplayItem::PopNestedDisplayList);
     }
 
-    pub fn push_text_shadow(&mut self, info: &LayoutPrimitiveInfo, shadow: TextShadow) {
-        self.push_item(SpecificDisplayItem::PushTextShadow(shadow), info);
+    pub fn push_shadow(&mut self, info: &LayoutPrimitiveInfo, shadow: Shadow) {
+        self.push_item(SpecificDisplayItem::PushShadow(shadow), info);
     }
 
-    pub fn pop_text_shadow(&mut self) {
-        self.push_new_empty_item(SpecificDisplayItem::PopTextShadow);
+    pub fn pop_shadow(&mut self) {
+        self.push_new_empty_item(SpecificDisplayItem::PopShadow);
     }
 
     pub fn finalize(mut self) -> (PipelineId, LayoutSize, BuiltDisplayList) {
         let glyph_offset = self.data.len();
 
         // Want to use self.push_iter, so can't borrow self
         let glyphs = ::std::mem::replace(&mut self.glyphs, FastHashMap::default());