Bug 1582273. Pass scrollbar flags from gecko to webrender so it can identify them. r=gw
authorTimothy Nikkel <tnikkel@gmail.com>
Tue, 24 Sep 2019 02:40:27 +0000
changeset 494619 e9b09f4047b81f1e716db6bc05911acd6094962e
parent 494618 90484e5de01e410fcd706b544286cde890799bfe
child 494620 0c2c86f22204ad5c7e3abcb11957fd18f9c41c38
push id114124
push usercbrindusan@mozilla.com
push dateTue, 24 Sep 2019 09:47:58 +0000
treeherdermozilla-inbound@79b08a0a1c3f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersgw
bugs1582273
milestone71.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 1582273. Pass scrollbar flags from gecko to webrender so it can identify them. r=gw Differential Revision: https://phabricator.services.mozilla.com/D46587
gfx/webrender_bindings/WebRenderAPI.h
gfx/webrender_bindings/src/bindings.rs
gfx/wr/examples/alpha_perf.rs
gfx/wr/examples/animation.rs
gfx/wr/examples/basic.rs
gfx/wr/examples/blob.rs
gfx/wr/examples/document.rs
gfx/wr/examples/frame_output.rs
gfx/wr/examples/iframe.rs
gfx/wr/examples/image_resize.rs
gfx/wr/examples/multiwindow.rs
gfx/wr/examples/scrolling.rs
gfx/wr/examples/texture_cache_stress.rs
gfx/wr/examples/yuv.rs
gfx/wr/webrender/src/scene_building.rs
gfx/wr/webrender_api/src/display_item.rs
gfx/wr/webrender_api/src/display_list.rs
gfx/wr/wrench/src/yaml_frame_reader.rs
gfx/wr/wrench/src/yaml_frame_writer.rs
layout/painting/nsDisplayList.cpp
--- a/gfx/webrender_bindings/WebRenderAPI.h
+++ b/gfx/webrender_bindings/WebRenderAPI.h
@@ -331,26 +331,27 @@ class MOZ_RAII AutoTransactionSender {
   TransactionBuilder* mTxn;
 };
 
 /**
  * A set of optional parameters for stacking context creation.
  */
 struct MOZ_STACK_CLASS StackingContextParams : public WrStackingContextParams {
   StackingContextParams()
-      : WrStackingContextParams{WrStackingContextClip::None(),
-                                nullptr,
-                                nullptr,
-                                wr::TransformStyle::Flat,
-                                wr::WrReferenceFrameKind::Transform,
-                                nullptr,
-                                /* is_backface_visible = */ true,
-                                /* cache_tiles = */ false,
-                                wr::MixBlendMode::Normal,
-                                /* is_backdrop_root = */ false} {}
+      : WrStackingContextParams{
+            WrStackingContextClip::None(),
+            nullptr,
+            nullptr,
+            wr::TransformStyle::Flat,
+            wr::WrReferenceFrameKind::Transform,
+            nullptr,
+            /* prim_flags = */ wr::PrimitiveFlags_IS_BACKFACE_VISIBLE,
+            /* cache_tiles = */ false,
+            wr::MixBlendMode::Normal,
+            /* is_backdrop_root = */ false} {}
 
   void SetPreserve3D(bool aPreserve) {
     transform_style =
         aPreserve ? wr::TransformStyle::Preserve3D : wr::TransformStyle::Flat;
   }
 
   nsTArray<wr::FilterOp> mFilters;
   nsTArray<wr::WrFilterData> mFilterDatas;
--- a/gfx/webrender_bindings/src/bindings.rs
+++ b/gfx/webrender_bindings/src/bindings.rs
@@ -2060,17 +2060,17 @@ pub enum WrReferenceFrameKind {
 #[repr(C)]
 pub struct WrStackingContextParams {
     pub clip: WrStackingContextClip,
     pub animation: *const WrAnimationProperty,
     pub opacity: *const f32,
     pub transform_style: TransformStyle,
     pub reference_frame_kind: WrReferenceFrameKind,
     pub scrolling_relative_to: *const u64,
-    pub is_backface_visible: bool,
+    pub prim_flags: PrimitiveFlags,
     /// True if picture caching should be enabled for this stacking context.
     pub cache_tiles: bool,
     pub mix_blend_mode: MixBlendMode,
     /// True if this stacking context is a backdrop root.
     /// https://drafts.fxtf.org/filter-effects-2/#BackdropRoot
     pub is_backdrop_root: bool,
 }
 
@@ -2180,17 +2180,17 @@ pub extern "C" fn wr_dp_push_stacking_co
         result.id = wr_spatial_id.0;
         assert_ne!(wr_spatial_id.0, 0);
     }
 
     state.frame_builder
          .dl_builder
          .push_stacking_context(bounds.origin,
                                 wr_spatial_id,
-                                params.is_backface_visible,
+                                params.prim_flags,
                                 wr_clip_id,
                                 params.transform_style,
                                 params.mix_blend_mode,
                                 &filters,
                                 &r_filter_datas,
                                 &[],
                                 glyph_raster_space,
                                 params.cache_tiles,
--- a/gfx/wr/examples/alpha_perf.rs
+++ b/gfx/wr/examples/alpha_perf.rs
@@ -32,17 +32,17 @@ impl Example for App {
         _document_id: DocumentId,
     ) {
         let bounds = (0, 0).to(1920, 1080);
         let space_and_clip = SpaceAndClipInfo::root_scroll(pipeline_id);
 
         builder.push_simple_stacking_context(
             bounds.origin,
             space_and_clip.spatial_id,
-            true,
+            PrimitiveFlags::IS_BACKFACE_VISIBLE,
         );
 
         for _ in 0 .. self.rect_count {
             builder.push_rect(
                 &CommonItemProperties::new(bounds, space_and_clip),
                 ColorF::new(1.0, 1.0, 1.0, 0.05)
             );
         }
--- a/gfx/wr/examples/animation.rs
+++ b/gfx/wr/examples/animation.rs
@@ -63,17 +63,17 @@ impl App {
             TransformStyle::Flat,
             PropertyBinding::Binding(property_key, LayoutTransform::identity()),
             ReferenceFrameKind::Transform,
         );
 
         builder.push_simple_stacking_context_with_filters(
             LayoutPoint::zero(),
             spatial_id,
-            true,
+            PrimitiveFlags::IS_BACKFACE_VISIBLE,
             &filters,
             &[],
             &[]
         );
 
         let space_and_clip = SpaceAndClipInfo {
             spatial_id,
             clip_id: ClipId::root(pipeline_id),
--- a/gfx/wr/examples/basic.rs
+++ b/gfx/wr/examples/basic.rs
@@ -192,17 +192,17 @@ impl Example for App {
     ) {
         let content_bounds = LayoutRect::new(LayoutPoint::zero(), builder.content_size());
         let root_space_and_clip = SpaceAndClipInfo::root_scroll(pipeline_id);
         let spatial_id = root_space_and_clip.spatial_id;
 
         builder.push_simple_stacking_context(
             content_bounds.origin,
             spatial_id,
-            true,
+            PrimitiveFlags::IS_BACKFACE_VISIBLE,
         );
 
         let image_mask_key = api.generate_image_key();
         txn.add_image(
             image_mask_key,
             ImageDescriptor::new(2, 2, ImageFormat::R8, true, false),
             ImageData::new(vec![0, 80, 180, 255]),
             None,
--- a/gfx/wr/examples/blob.rs
+++ b/gfx/wr/examples/blob.rs
@@ -11,17 +11,17 @@ extern crate winit;
 #[path = "common/boilerplate.rs"]
 mod boilerplate;
 
 use crate::boilerplate::{Example, HandyDandyRectBuilder};
 use rayon::{ThreadPool, ThreadPoolBuilder};
 use rayon::prelude::*;
 use std::collections::HashMap;
 use std::sync::Arc;
-use webrender::api::{self, DisplayListBuilder, DocumentId, PipelineId, RenderApi, Transaction};
+use webrender::api::{self, DisplayListBuilder, DocumentId, PipelineId, PrimitiveFlags, RenderApi, Transaction};
 use webrender::api::{ColorF, CommonItemProperties, SpaceAndClipInfo};
 use webrender::api::units::*;
 use webrender::euclid::{size2, rect};
 
 // This example shows how to implement a very basic BlobImageHandler that can only render
 // a checkerboard pattern.
 
 // The deserialized command list internally used by this example is just a color.
@@ -224,17 +224,17 @@ impl Example for App {
             None,
         );
 
         let space_and_clip = SpaceAndClipInfo::root_scroll(pipeline_id);
 
         builder.push_simple_stacking_context(
             LayoutPoint::zero(),
             space_and_clip.spatial_id,
-            true,
+            PrimitiveFlags::IS_BACKFACE_VISIBLE,
         );
 
         let bounds = (30, 30).by(500, 500);
         builder.push_image(
             &CommonItemProperties::new(bounds, space_and_clip),
             bounds,
             api::ImageRendering::Auto,
             api::AlphaType::PremultipliedAlpha,
--- a/gfx/wr/examples/document.rs
+++ b/gfx/wr/examples/document.rs
@@ -113,17 +113,17 @@ impl Example for App {
             let local_rect = LayoutRect::new(
                 LayoutPoint::zero(),
                 doc.content_rect.size,
             );
 
             builder.push_simple_stacking_context(
                 doc.content_rect.origin,
                 space_and_clip.spatial_id,
-                true,
+                PrimitiveFlags::IS_BACKFACE_VISIBLE,
             );
             builder.push_rect(
                 &CommonItemProperties::new(local_rect, space_and_clip),
                 doc.color,
             );
             builder.pop_stacking_context();
 
             let mut txn = Transaction::new();
--- a/gfx/wr/examples/frame_output.rs
+++ b/gfx/wr/examples/frame_output.rs
@@ -114,17 +114,17 @@ impl App {
         let mut builder = DisplayListBuilder::new(
             document.pipeline_id,
             document.content_rect.size,
         );
 
         builder.push_simple_stacking_context(
             document.content_rect.origin,
             space_and_clip.spatial_id,
-            true,
+            PrimitiveFlags::IS_BACKFACE_VISIBLE,
         );
 
         builder.push_rect(
             &CommonItemProperties::new(document.content_rect, space_and_clip),
             ColorF::new(1.0, 1.0, 0.0, 1.0)
         );
         builder.pop_stacking_context();
 
@@ -159,17 +159,17 @@ impl Example for App {
         }
 
         let bounds = (100, 100).to(200, 200);
         let space_and_clip = SpaceAndClipInfo::root_scroll(pipeline_id);
 
         builder.push_simple_stacking_context(
             bounds.origin,
             space_and_clip.spatial_id,
-            true,
+            PrimitiveFlags::IS_BACKFACE_VISIBLE,
         );
 
         builder.push_image(
             &CommonItemProperties::new(bounds, space_and_clip),
             bounds,
             ImageRendering::Auto,
             AlphaType::PremultipliedAlpha,
             self.external_image_key.unwrap(),
--- a/gfx/wr/examples/iframe.rs
+++ b/gfx/wr/examples/iframe.rs
@@ -36,17 +36,17 @@ impl Example for App {
 
         let sub_pipeline_id = PipelineId(pipeline_id.0, 42);
         let mut sub_builder = DisplayListBuilder::new(sub_pipeline_id, sub_bounds.size);
         let mut space_and_clip = SpaceAndClipInfo::root_scroll(pipeline_id);
 
         sub_builder.push_simple_stacking_context(
             sub_bounds.origin,
             space_and_clip.spatial_id,
-            true,
+            PrimitiveFlags::IS_BACKFACE_VISIBLE,
         );
 
         // green rect visible == success
         sub_builder.push_rect(
             &CommonItemProperties::new(sub_bounds, space_and_clip),
             ColorF::new(0.0, 1.0, 0.0, 1.0)
         );
         sub_builder.pop_stacking_context();
@@ -68,17 +68,17 @@ impl Example for App {
             PropertyBinding::Binding(PropertyBindingKey::new(42), LayoutTransform::identity()),
             ReferenceFrameKind::Transform,
         );
 
         // And this is for the root pipeline
         builder.push_simple_stacking_context(
             sub_bounds.origin,
             space_and_clip.spatial_id,
-            true,
+            PrimitiveFlags::IS_BACKFACE_VISIBLE,
         );
 
         // red rect under the iframe: if this is visible, things have gone wrong
         builder.push_rect(
             &CommonItemProperties::new(sub_bounds, space_and_clip),
             ColorF::new(1.0, 0.0, 0.0, 1.0)
         );
         builder.push_iframe(sub_bounds, sub_bounds, &space_and_clip, sub_pipeline_id, false);
--- a/gfx/wr/examples/image_resize.rs
+++ b/gfx/wr/examples/image_resize.rs
@@ -39,17 +39,17 @@ impl Example for App {
         );
 
         let bounds = (0, 0).to(512, 512);
         let space_and_clip = SpaceAndClipInfo::root_scroll(pipeline_id);
 
         builder.push_simple_stacking_context(
             bounds.origin,
             space_and_clip.spatial_id,
-            true,
+            PrimitiveFlags::IS_BACKFACE_VISIBLE,
         );
 
         let image_size = LayoutSize::new(100.0, 100.0);
 
         builder.push_image(
             &CommonItemProperties::new(
                 LayoutRect::new(LayoutPoint::new(100.0, 100.0), image_size),
                 space_and_clip,
--- a/gfx/wr/examples/multiwindow.rs
+++ b/gfx/wr/examples/multiwindow.rs
@@ -185,17 +185,17 @@ impl Window {
         let mut txn = Transaction::new();
         let mut builder = DisplayListBuilder::new(self.pipeline_id, layout_size);
         let space_and_clip = SpaceAndClipInfo::root_scroll(self.pipeline_id);
 
         let bounds = LayoutRect::new(LayoutPoint::zero(), builder.content_size());
         builder.push_simple_stacking_context(
             bounds.origin,
             space_and_clip.spatial_id,
-            true,
+            PrimitiveFlags::IS_BACKFACE_VISIBLE,
         );
 
         builder.push_rect(
             &CommonItemProperties::new(
                 LayoutRect::new(
                     LayoutPoint::new(100.0, 200.0),
                     LayoutSize::new(100.0, 200.0),
                 ),
--- a/gfx/wr/examples/scrolling.rs
+++ b/gfx/wr/examples/scrolling.rs
@@ -31,27 +31,27 @@ impl Example for App {
         _device_size: DeviceIntSize,
         pipeline_id: PipelineId,
         _document_id: DocumentId,
     ) {
         let root_space_and_clip = SpaceAndClipInfo::root_scroll(pipeline_id);
         builder.push_simple_stacking_context(
             LayoutPoint::zero(),
             root_space_and_clip.spatial_id,
-            true,
+            PrimitiveFlags::IS_BACKFACE_VISIBLE,
         );
 
         if true {
             // scrolling and clips stuff
             // let's make a scrollbox
             let scrollbox = (0, 0).to(300, 400);
             builder.push_simple_stacking_context(
                 LayoutPoint::new(10., 10.),
                 root_space_and_clip.spatial_id,
-                true,
+                PrimitiveFlags::IS_BACKFACE_VISIBLE,
             );
             // set the scrolling clip
             let space_and_clip1 = builder.define_scroll_frame(
                 &root_space_and_clip,
                 None,
                 (0, 0).by(1000, 1000),
                 scrollbox,
                 vec![],
--- a/gfx/wr/examples/texture_cache_stress.rs
+++ b/gfx/wr/examples/texture_cache_stress.rs
@@ -97,17 +97,17 @@ impl Example for App {
         _document_id: DocumentId,
     ) {
         let bounds = (0, 0).to(512, 512);
         let space_and_clip = SpaceAndClipInfo::root_scroll(pipeline_id);
 
         builder.push_simple_stacking_context(
             bounds.origin,
             space_and_clip.spatial_id,
-            true,
+            PrimitiveFlags::IS_BACKFACE_VISIBLE,
         );
 
         let x0 = 50.0;
         let y0 = 50.0;
         let image_size = LayoutSize::new(4.0, 4.0);
 
         if self.swap_keys.is_empty() {
             let key0 = api.generate_image_key();
--- a/gfx/wr/examples/yuv.rs
+++ b/gfx/wr/examples/yuv.rs
@@ -94,17 +94,17 @@ impl Example for App {
         _document_id: DocumentId,
     ) {
         let bounds = LayoutRect::new(LayoutPoint::zero(), builder.content_size());
         let space_and_clip = SpaceAndClipInfo::root_scroll(pipeline_id);
 
         builder.push_simple_stacking_context(
             bounds.origin,
             space_and_clip.spatial_id,
-            true,
+            PrimitiveFlags::IS_BACKFACE_VISIBLE,
         );
 
         let yuv_chanel1 = api.generate_image_key();
         let yuv_chanel2 = api.generate_image_key();
         let yuv_chanel2_1 = api.generate_image_key();
         let yuv_chanel3 = api.generate_image_key();
         txn.add_image(
             yuv_chanel1,
--- a/gfx/wr/webrender/src/scene_building.rs
+++ b/gfx/wr/webrender/src/scene_building.rs
@@ -356,17 +356,17 @@ impl<'a> SceneBuilder<'a> {
         //
         // Note that we don't do this for iframes, even if they're pipeline
         // roots, because they should be entirely contained within a stacking
         // context, and we probably wouldn't crash if they weren't.
         builder.push_stacking_context(
             root_pipeline.pipeline_id,
             CompositeOps::default(),
             TransformStyle::Flat,
-            /* is_backface_visible = */ true,
+            /* prim_flags = */ PrimitiveFlags::IS_BACKFACE_VISIBLE,
             /* create_tile_cache = */ false,
             ROOT_SPATIAL_NODE_INDEX,
             ClipChainId::NONE,
             RasterSpace::Screen,
             /* is_backdrop_root = */ true,
             device_pixel_scale,
         );
 
@@ -907,17 +907,17 @@ impl<'a> SceneBuilder<'a> {
         traversal: &mut BuiltDisplayListIter<'a>,
         pipeline_id: PipelineId,
         stacking_context: &StackingContext,
         spatial_node_index: SpatialNodeIndex,
         origin: LayoutPoint,
         filters: ItemRange<FilterOp>,
         filter_datas: &[TempFilterData],
         filter_primitives: ItemRange<FilterPrimitive>,
-        is_backface_visible: bool,
+        prim_flags: PrimitiveFlags,
         apply_pipeline_clip: bool,
     ) {
         // Avoid doing unnecessary work for empty stacking contexts.
         if traversal.current_stacking_context_empty() {
             traversal.skip_current_stacking_context();
             return;
         }
 
@@ -934,17 +934,17 @@ impl<'a> SceneBuilder<'a> {
             Some(clip_id) => self.id_to_index_mapper.get_clip_chain_id(clip_id),
             None => ClipChainId::NONE,
         };
 
         self.push_stacking_context(
             pipeline_id,
             composition_operations,
             stacking_context.transform_style,
-            is_backface_visible,
+            prim_flags,
             stacking_context.cache_tiles,
             spatial_node_index,
             clip_chain_id,
             stacking_context.raster_space,
             stacking_context.is_backdrop_root,
             self.sc_stack.last().unwrap().snap_to_device.device_pixel_scale,
         );
 
@@ -1368,17 +1368,17 @@ impl<'a> SceneBuilder<'a> {
                     &mut subtraversal,
                     pipeline_id,
                     &info.stacking_context,
                     space,
                     info.origin,
                     item.filters(),
                     item.filter_datas(),
                     item.filter_primitives(),
-                    info.is_backface_visible,
+                    info.prim_flags,
                     apply_pipeline_clip,
                 );
                 return Some(subtraversal);
             }
             DisplayItem::PushReferenceFrame(ref info) => {
                 let parent_space = self.get_space(&info.parent_spatial_id);
                 let mut subtraversal = item.sub_iter();
                 self.build_reference_frame(
@@ -1766,17 +1766,17 @@ impl<'a> SceneBuilder<'a> {
         );
     }
 
     pub fn push_stacking_context(
         &mut self,
         pipeline_id: PipelineId,
         composite_ops: CompositeOps,
         transform_style: TransformStyle,
-        is_backface_visible: bool,
+        prim_flags: PrimitiveFlags,
         create_tile_cache: bool,
         spatial_node_index: SpatialNodeIndex,
         clip_chain_id: ClipChainId,
         requested_raster_space: RasterSpace,
         is_backdrop_root: bool,
         device_pixel_scale: DevicePixelScale,
     ) {
         // Check if this stacking context is the root of a pipeline, and the caller
@@ -1890,22 +1890,16 @@ impl<'a> SceneBuilder<'a> {
         let snap_to_device = self.sc_stack.last().map_or(
             SpaceSnapper::new(
                 ROOT_SPATIAL_NODE_INDEX,
                 device_pixel_scale,
             ),
             |sc| sc.snap_to_device.clone(),
         );
 
-        let prim_flags = if is_backface_visible {
-            PrimitiveFlags::IS_BACKFACE_VISIBLE
-        } else {
-            PrimitiveFlags::empty()
-        };
-
         // Push the SC onto the stack, so we know how to handle things in
         // pop_stacking_context.
         self.sc_stack.push(FlattenedStackingContext {
             prim_list: PrimitiveList::empty(),
             pipeline_id,
             prim_flags,
             requested_raster_space,
             spatial_node_index,
--- a/gfx/wr/webrender_api/src/display_item.rs
+++ b/gfx/wr/webrender_api/src/display_item.rs
@@ -29,22 +29,25 @@ pub const MAX_BLUR_RADIUS: f32 = 300.;
 /// is composed of two numbers. In Servo, the first is an identifier while the
 /// second is used to select the cursor that should be used during mouse
 /// movement. In Gecko, the first is a scrollframe identifier, while the second
 /// is used to store various flags that APZ needs to properly process input
 /// events.
 pub type ItemTag = (u64, u16);
 
 bitflags! {
+    #[repr(C)]
     #[derive(Deserialize, MallocSizeOf, Serialize, PeekPoke)]
     pub struct PrimitiveFlags: u8 {
         /// The CSS backface-visibility property (yes, it can be really granular)
         const IS_BACKFACE_VISIBLE = 1 << 0;
-        /// If set, this primitive represents part of a scroll bar
-        const IS_SCROLL_BAR = 1 << 1;
+        /// If set, this primitive represents a scroll bar container
+        const IS_SCROLLBAR_CONTAINER = 1 << 1;
+        /// If set, this primitive represents a scroll bar thumb
+        const IS_SCROLLBAR_THUMB = 1 << 2;
     }
 }
 
 impl Default for PrimitiveFlags {
     fn default() -> Self {
         PrimitiveFlags::IS_BACKFACE_VISIBLE
     }
 }
@@ -665,17 +668,17 @@ pub struct ReferenceFrame {
     pub transform: PropertyBinding<LayoutTransform>,
     pub id: SpatialId,
 }
 
 #[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)]
 pub struct PushStackingContextDisplayItem {
     pub origin: LayoutPoint,
     pub spatial_id: SpatialId,
-    pub is_backface_visible: bool,
+    pub prim_flags: PrimitiveFlags,
     pub stacking_context: StackingContext,
 }
 
 #[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)]
 pub struct StackingContext {
     pub transform_style: TransformStyle,
     pub mix_blend_mode: MixBlendMode,
     pub clip_id: Option<ClipId>,
--- a/gfx/wr/webrender_api/src/display_list.rs
+++ b/gfx/wr/webrender_api/src/display_list.rs
@@ -1249,33 +1249,33 @@ impl DisplayListBuilder {
     pub fn pop_reference_frame(&mut self) {
         self.push_item(&di::DisplayItem::PopReferenceFrame);
     }
 
     pub fn push_stacking_context(
         &mut self,
         origin: LayoutPoint,
         spatial_id: di::SpatialId,
-        is_backface_visible: bool,
+        prim_flags: di::PrimitiveFlags,
         clip_id: Option<di::ClipId>,
         transform_style: di::TransformStyle,
         mix_blend_mode: di::MixBlendMode,
         filters: &[di::FilterOp],
         filter_datas: &[di::FilterData],
         filter_primitives: &[di::FilterPrimitive],
         raster_space: di::RasterSpace,
         cache_tiles: bool,
         is_backdrop_root: bool,
     ) {
         self.push_filters(filters, filter_datas, filter_primitives);
 
         let item = di::DisplayItem::PushStackingContext(di::PushStackingContextDisplayItem {
             origin,
             spatial_id,
-            is_backface_visible,
+            prim_flags,
             stacking_context: di::StackingContext {
                 transform_style,
                 mix_blend_mode,
                 clip_id,
                 raster_space,
                 cache_tiles,
                 is_backdrop_root,
             },
@@ -1284,42 +1284,42 @@ impl DisplayListBuilder {
         self.push_item(&item);
     }
 
     /// Helper for examples/ code.
     pub fn push_simple_stacking_context(
         &mut self,
         origin: LayoutPoint,
         spatial_id: di::SpatialId,
-        is_backface_visible: bool,
+        prim_flags: di::PrimitiveFlags,
     ) {
         self.push_simple_stacking_context_with_filters(
             origin,
             spatial_id,
-            is_backface_visible,
+            prim_flags,
             &[],
             &[],
             &[],
         );
     }
 
     /// Helper for examples/ code.
     pub fn push_simple_stacking_context_with_filters(
         &mut self,
         origin: LayoutPoint,
         spatial_id: di::SpatialId,
-        is_backface_visible: bool,
+        prim_flags: di::PrimitiveFlags,
         filters: &[di::FilterOp],
         filter_datas: &[di::FilterData],
         filter_primitives: &[di::FilterPrimitive],
     ) {
         self.push_stacking_context(
             origin,
             spatial_id,
-            is_backface_visible,
+            prim_flags,
             None,
             di::TransformStyle::Flat,
             di::MixBlendMode::Normal,
             filters,
             filter_datas,
             filter_primitives,
             di::RasterSpace::Screen,
             /* cache_tiles = */ false,
--- a/gfx/wr/wrench/src/yaml_frame_reader.rs
+++ b/gfx/wr/wrench/src/yaml_frame_reader.rs
@@ -2030,17 +2030,17 @@ impl YamlFrameReader {
 
         let filters = yaml["filters"].as_vec_filter_op().unwrap_or(vec![]);
         let filter_datas = yaml["filter-datas"].as_vec_filter_data().unwrap_or(vec![]);
         let filter_primitives = yaml["filter-primitives"].as_vec_filter_primitive().unwrap_or(vec![]);
 
         dl.push_stacking_context(
             bounds.origin,
             *self.spatial_id_stack.last().unwrap(),
-            info.flags.contains(PrimitiveFlags::IS_BACKFACE_VISIBLE),
+            info.flags,
             clip_node_id,
             transform_style,
             mix_blend_mode,
             &filters,
             &filter_datas,
             &filter_primitives,
             raster_space,
             cache_tiles,
--- a/gfx/wr/wrench/src/yaml_frame_writer.rs
+++ b/gfx/wr/wrench/src/yaml_frame_writer.rs
@@ -199,16 +199,18 @@ fn maybe_radius_yaml(radius: &BorderRadi
         size_node(&mut table, "bottom-right", &radius.bottom_right);
         Some(Yaml::Hash(table))
     }
 }
 
 fn common_node(v: &mut Table, clip_id_mapper: &mut ClipIdMapper, info: &CommonItemProperties) {
     rect_node(v, "clip-rect", &info.clip_rect);
     bool_node(v, "backface-visible", info.flags.contains(PrimitiveFlags::IS_BACKFACE_VISIBLE));
+    bool_node(v, "scrollbar-container", info.flags.contains(PrimitiveFlags::IS_SCROLLBAR_CONTAINER));
+    bool_node(v, "scrollbar-thumb", info.flags.contains(PrimitiveFlags::IS_SCROLLBAR_THUMB));
 
     clip_and_scroll_node(v, clip_id_mapper, info.clip_id, info.spatial_id);
 
     if let Some(tag) = info.hit_info {
         yaml_node(
             v,
             "hit-testing-tag",
              Yaml::Array(vec![Yaml::Integer(tag.0 as i64), Yaml::Integer(tag.1 as i64)])
@@ -1288,17 +1290,28 @@ impl YamlFrameWriter {
                     str_node(&mut v, "type", "stacking-context");
                     clip_and_scroll_node(
                         &mut v,
                         clip_id_mapper,
                         item.stacking_context.clip_id.unwrap_or(ClipId::invalid()),
                         item.spatial_id
                     );
                     point_node(&mut v, "origin", &item.origin);
-                    bool_node(&mut v, "backface-visible", item.is_backface_visible);
+                    bool_node(
+                        &mut v,
+                        "backface-visible",
+                        item.prim_flags.contains(PrimitiveFlags::IS_BACKFACE_VISIBLE));
+                    bool_node(
+                        &mut v,
+                        "scrollbar-container",
+                        item.prim_flags.contains(PrimitiveFlags::IS_SCROLLBAR_CONTAINER));
+                    bool_node(
+                        &mut v,
+                        "scrollbar-thumb",
+                        item.prim_flags.contains(PrimitiveFlags::IS_SCROLLBAR_THUMB));
                     write_stacking_context(
                         &mut v,
                         &item.stacking_context,
                         &scene.properties,
                         base.filters(),
                         base.filter_datas(),
                         base.filter_primitives(),
                     );
--- a/layout/painting/nsDisplayList.cpp
+++ b/layout/painting/nsDisplayList.cpp
@@ -6936,16 +6936,22 @@ bool nsDisplayOwnLayer::CreateWebRenderC
     prop->id = mWrAnimationId;
     prop->effect_type = wr::WrAnimationType::Transform;
   }
 
   wr::StackingContextParams params;
   params.animation = prop.ptrOr(nullptr);
   params.clip =
       wr::WrStackingContextClip::ClipChain(aBuilder.CurrentClipChainId());
+  if (IsScrollbarContainer()) {
+    params.prim_flags |= wr::PrimitiveFlags_IS_SCROLLBAR_CONTAINER;
+  }
+  if (IsScrollThumbLayer()) {
+    params.prim_flags |= wr::PrimitiveFlags_IS_SCROLLBAR_THUMB;
+  }
   StackingContextHelper sc(aSc, GetActiveScrolledRoot(), mFrame, this, aBuilder,
                            params);
 
   nsDisplayWrapList::CreateWebRenderCommands(aBuilder, aResources, sc, aManager,
                                              aDisplayListBuilder);
   return true;
 }
 
@@ -8621,17 +8627,19 @@ bool nsDisplayTransform::CreateWebRender
 
   // Determine if we're possibly animated (= would need an active layer in FLB).
   bool animated = ActiveLayerTracker::IsTransformMaybeAnimated(Frame());
 
   wr::StackingContextParams params;
   params.mBoundTransform = &newTransformMatrix;
   params.animation = animationsId ? &prop : nullptr;
   params.mTransformPtr = transformForSC;
-  params.is_backface_visible = !BackfaceIsHidden();
+  params.prim_flags = !BackfaceIsHidden()
+                          ? wr::PrimitiveFlags_IS_BACKFACE_VISIBLE
+                          : wr::PrimitiveFlags{0};
   params.mDeferredTransformItem = deferredTransformItem;
   params.mAnimated = animated;
   // Determine if we would have to rasterize any items in local raster space
   // (i.e. disable subpixel AA). We don't always need to rasterize locally even
   // if the stacking context is possibly animated (at the cost of potentially
   // some false negatives with respect to will-change handling), so we pass in
   // this determination separately to accurately match with when FLB would
   // normally disable subpixel AA.
@@ -9324,17 +9332,19 @@ bool nsDisplayPerspective::CreateWebRend
   // or the perspective frame in order to not confuse WR's preserve-3d code in
   // very awful ways.
   bool preserve3D =
       mFrame->Extend3DContext() || perspectiveFrame->Extend3DContext();
 
   wr::StackingContextParams params;
   params.mTransformPtr = &perspectiveMatrix;
   params.reference_frame_kind = wr::WrReferenceFrameKind::Perspective;
-  params.is_backface_visible = !BackfaceIsHidden();
+  params.prim_flags = !BackfaceIsHidden()
+                          ? wr::PrimitiveFlags_IS_BACKFACE_VISIBLE
+                          : wr::PrimitiveFlags{0};
   params.SetPreserve3D(preserve3D);
   params.clip =
       wr::WrStackingContextClip::ClipChain(aBuilder.CurrentClipChainId());
 
   Maybe<uint64_t> scrollingRelativeTo;
   for (auto* asr = GetActiveScrolledRoot(); asr; asr = asr->mParent) {
     if (nsLayoutUtils::IsAncestorFrameCrossDoc(
             asr->mScrollableFrame->GetScrolledFrame(), perspectiveFrame)) {