diff --git a/components/compositing/compositor.rs b/components/compositing/compositor.rs index dc2a44fc082..30abae50c50 100644 --- a/components/compositing/compositor.rs +++ b/components/compositing/compositor.rs @@ -40,7 +40,7 @@ use style_traits::viewport::ViewportConstraints; use time::{precise_time_ns, precise_time_s}; use touch::{TouchHandler, TouchAction}; use webrender; -use webrender_traits::{self, ScrollEventPhase, ServoScrollRootId, LayoutPoint, ScrollLocation}; +use webrender_traits::{self, LayoutPoint, ScrollEventPhase, ScrollLayerId, ScrollLocation}; use windowing::{self, MouseWindowEvent, WindowEvent, WindowMethods, WindowNavigateMsg}; #[derive(Debug, PartialEq)] @@ -77,9 +77,9 @@ trait ConvertScrollRootIdFromWebRender { fn from_webrender(&self) -> ScrollRootId; } -impl ConvertScrollRootIdFromWebRender for webrender_traits::ServoScrollRootId { +impl ConvertScrollRootIdFromWebRender for usize { fn from_webrender(&self) -> ScrollRootId { - ScrollRootId(self.0) + ScrollRootId(*self) } } @@ -791,10 +791,8 @@ impl IOCompositor { pipeline_id: PipelineId, scroll_root_id: ScrollRootId, point: Point2D) { - self.webrender_api.scroll_layers_with_scroll_root_id( - LayoutPoint::from_untyped(&point), - pipeline_id.to_webrender(), - ServoScrollRootId(scroll_root_id.0)); + let id = ScrollLayerId::new(scroll_root_id.0, pipeline_id.to_webrender()); + self.webrender_api.scroll_layer_with_id(LayoutPoint::from_untyped(&point), id); } fn handle_window_message(&mut self, event: WindowEvent) { @@ -1386,13 +1384,18 @@ impl IOCompositor { fn send_viewport_rects(&self) { let mut stacking_context_scroll_states_per_pipeline = HashMap::new(); for scroll_layer_state in self.webrender_api.get_scroll_layer_state() { + let external_id = match scroll_layer_state.id.external_id() { + Some(id) => id, + None => continue, + }; + let stacking_context_scroll_state = StackingContextScrollState { - scroll_root_id: scroll_layer_state.scroll_root_id.from_webrender(), + scroll_root_id: external_id.from_webrender(), scroll_offset: scroll_layer_state.scroll_offset.to_untyped(), }; - let pipeline_id = scroll_layer_state.pipeline_id; + stacking_context_scroll_states_per_pipeline - .entry(pipeline_id) + .entry(scroll_layer_state.id.pipeline_id()) .or_insert(vec![]) .push(stacking_context_scroll_state); } diff --git a/components/gfx/display_list/mod.rs b/components/gfx/display_list/mod.rs index 04fcf7b367c..78d50530168 100644 --- a/components/gfx/display_list/mod.rs +++ b/components/gfx/display_list/mod.rs @@ -434,6 +434,7 @@ impl StackingContext { pub fn to_display_list_items(self) -> (DisplayItem, DisplayItem) { let mut base_item = BaseDisplayItem::empty(); base_item.stacking_context_id = self.id; + base_item.scroll_root_id = self.parent_scroll_id; let pop_item = DisplayItem::PopStackingContext(Box::new( PopStackingContextItem { diff --git a/components/layout/block.rs b/components/layout/block.rs index 31f44f0ec0e..5504f0fc412 100644 --- a/components/layout/block.rs +++ b/components/layout/block.rs @@ -2233,10 +2233,11 @@ impl Flow for BlockFlow { fn compute_overflow(&self) -> Overflow { let flow_size = self.base.position.size.to_physical(self.base.writing_mode); - self.fragment.compute_overflow(&flow_size, + let overflow = self.fragment.compute_overflow(&flow_size, &self.base .early_absolute_position_info - .relative_containing_block_size) + .relative_containing_block_size); + overflow } fn iterate_through_fragment_border_boxes(&self, diff --git a/components/layout/display_list_builder.rs b/components/layout/display_list_builder.rs index 2ee9985cf0e..26814351429 100644 --- a/components/layout/display_list_builder.rs +++ b/components/layout/display_list_builder.rs @@ -120,12 +120,31 @@ fn get_cyclic(arr: &[T], index: usize) -> &T { &arr[index % arr.len()] } +#[derive(Debug)] +struct StackingContextInfo { + children: Vec, + scroll_roots: Vec, +} + +impl StackingContextInfo { + fn new() -> StackingContextInfo { + StackingContextInfo { + children: Vec::new(), + scroll_roots: Vec::new(), + } + } + + fn take_children(&mut self) -> Vec { + mem::replace(&mut self.children, Vec::new()) + } +} + pub struct DisplayListBuildState<'a> { pub layout_context: &'a LayoutContext<'a>, pub root_stacking_context: StackingContext, pub items: HashMap>, - pub stacking_context_children: HashMap>, - pub scroll_roots: HashMap, + stacking_context_info: HashMap, + pub scroll_root_parents: HashMap, pub processing_scroll_root_element: bool, /// The current stacking context id, used to keep track of state when building. @@ -147,8 +166,8 @@ impl<'a> DisplayListBuildState<'a> { layout_context: layout_context, root_stacking_context: StackingContext::root(), items: HashMap::new(), - stacking_context_children: HashMap::new(), - scroll_roots: HashMap::new(), + stacking_context_info: HashMap::new(), + scroll_root_parents: HashMap::new(), processing_scroll_root_element: false, current_stacking_context_id: StackingContextId::root(), current_scroll_root_id: ScrollRootId::root(), @@ -164,13 +183,18 @@ impl<'a> DisplayListBuildState<'a> { fn add_stacking_context(&mut self, parent_id: StackingContextId, stacking_context: StackingContext) { - let contexts = self.stacking_context_children.entry(parent_id).or_insert(Vec::new()); - contexts.push(stacking_context); + let info = self.stacking_context_info + .entry(parent_id) + .or_insert(StackingContextInfo::new()); + info.children.push(stacking_context); } - fn add_scroll_root(&mut self, scroll_root: ScrollRoot) { - debug_assert!(!self.scroll_roots.contains_key(&scroll_root.id)); - self.scroll_roots.insert(scroll_root.id, scroll_root); + fn add_scroll_root(&mut self, scroll_root: ScrollRoot, stacking_context_id: StackingContextId) { + self.scroll_root_parents.insert(scroll_root.id, scroll_root.parent_id); + let info = self.stacking_context_info + .entry(stacking_context_id) + .or_insert(StackingContextInfo::new()); + info.scroll_roots.push(scroll_root); } fn parent_scroll_root_id(&self, scroll_root_id: ScrollRootId) -> ScrollRootId { @@ -178,8 +202,8 @@ impl<'a> DisplayListBuildState<'a> { return ScrollRootId::root() } - debug_assert!(self.scroll_roots.contains_key(&scroll_root_id)); - self.scroll_roots.get(&scroll_root_id).unwrap().parent_id + debug_assert!(self.scroll_root_parents.contains_key(&scroll_root_id)); + *self.scroll_root_parents.get(&scroll_root_id).unwrap() } fn create_base_display_item(&self, @@ -209,13 +233,10 @@ impl<'a> DisplayListBuildState<'a> { } pub fn to_display_list(mut self) -> DisplayList { - let mut scroll_root_stack = Vec::new(); - scroll_root_stack.push(ScrollRootId::root()); - let mut list = Vec::new(); let root_context = mem::replace(&mut self.root_stacking_context, StackingContext::root()); - self.to_display_list_for_stacking_context(&mut list, root_context, &mut scroll_root_stack); + self.to_display_list_for_stacking_context(&mut list, root_context); DisplayList { list: list, @@ -224,128 +245,75 @@ impl<'a> DisplayListBuildState<'a> { fn to_display_list_for_stacking_context(&mut self, list: &mut Vec, - stacking_context: StackingContext, - scroll_root_stack: &mut Vec) { + stacking_context: StackingContext) { let mut child_items = self.items.remove(&stacking_context.id).unwrap_or(Vec::new()); child_items.sort_by(|a, b| a.base().section.cmp(&b.base().section)); child_items.reverse(); - let mut child_stacking_contexts = - self.stacking_context_children.remove(&stacking_context.id).unwrap_or_else(Vec::new); - child_stacking_contexts.sort(); + let mut info = self.stacking_context_info.remove(&stacking_context.id) + .unwrap_or_else(StackingContextInfo::new); - let real_stacking_context = stacking_context.context_type == StackingContextType::Real; - if !real_stacking_context { - self.to_display_list_for_items(list, - child_items, - child_stacking_contexts, - scroll_root_stack); - return; + info.children.sort(); + + if stacking_context.context_type != StackingContextType::Real { + list.extend(info.scroll_roots.into_iter().map(|root| root.to_push())); + self.to_display_list_for_items(list, child_items, info.children); + } else { + let (push_item, pop_item) = stacking_context.to_display_list_items(); + list.push(push_item); + list.extend(info.scroll_roots.into_iter().map(|root| root.to_push())); + self.to_display_list_for_items(list, child_items, info.children); + list.push(pop_item); } - - let mut scroll_root_stack = Vec::new(); - scroll_root_stack.push(stacking_context.parent_scroll_id); - - let (push_item, pop_item) = stacking_context.to_display_list_items(); - list.push(push_item); - self.to_display_list_for_items(list, - child_items, - child_stacking_contexts, - &mut scroll_root_stack); - list.push(pop_item); } fn to_display_list_for_items(&mut self, list: &mut Vec, mut child_items: Vec, - child_stacking_contexts: Vec, - scroll_root_stack: &mut Vec) { + child_stacking_contexts: Vec) { // Properly order display items that make up a stacking context. "Steps" here // refer to the steps in CSS 2.1 Appendix E. // Steps 1 and 2: Borders and background for the root. while child_items.last().map_or(false, |child| child.section() == DisplayListSection::BackgroundAndBorders) { - let item = child_items.pop().unwrap(); - self.switch_scroll_roots(list, item.scroll_root_id(), scroll_root_stack); - list.push(item); + list.push(child_items.pop().unwrap()); } // Step 3: Positioned descendants with negative z-indices. let mut child_stacking_contexts = child_stacking_contexts.into_iter().peekable(); while child_stacking_contexts.peek().map_or(false, |child| child.z_index < 0) { let context = child_stacking_contexts.next().unwrap(); - self.switch_scroll_roots(list, context.parent_scroll_id, scroll_root_stack); - self.to_display_list_for_stacking_context(list, context, scroll_root_stack); + self.to_display_list_for_stacking_context(list, context); } // Step 4: Block backgrounds and borders. while child_items.last().map_or(false, |child| child.section() == DisplayListSection::BlockBackgroundsAndBorders) { - let item = child_items.pop().unwrap(); - self.switch_scroll_roots(list, item.scroll_root_id(), scroll_root_stack); - list.push(item); + list.push(child_items.pop().unwrap()); } // Step 5: Floats. while child_stacking_contexts.peek().map_or(false, |child| child.context_type == StackingContextType::PseudoFloat) { let context = child_stacking_contexts.next().unwrap(); - self.switch_scroll_roots(list, context.parent_scroll_id, scroll_root_stack); - self.to_display_list_for_stacking_context(list, context, scroll_root_stack); + self.to_display_list_for_stacking_context(list, context); } // Step 6 & 7: Content and inlines that generate stacking contexts. while child_items.last().map_or(false, |child| child.section() == DisplayListSection::Content) { - let item = child_items.pop().unwrap(); - self.switch_scroll_roots(list, item.scroll_root_id(), scroll_root_stack); - list.push(item); + list.push(child_items.pop().unwrap()); } // Step 8 & 9: Positioned descendants with nonnegative, numeric z-indices. for child in child_stacking_contexts { - self.switch_scroll_roots(list, child.parent_scroll_id, scroll_root_stack); - self.to_display_list_for_stacking_context(list, child, scroll_root_stack); + self.to_display_list_for_stacking_context(list, child); } // Step 10: Outlines. for item in child_items.drain(..) { - self.switch_scroll_roots(list, item.scroll_root_id(), scroll_root_stack); list.push(item); } - - for _ in scroll_root_stack.drain(1..) { - list.push(DisplayItem::PopScrollRoot(Box::new(BaseDisplayItem::empty()))); - } - } - - fn switch_scroll_roots(&self, - list: &mut Vec, - new_id: ScrollRootId, - scroll_root_stack: &mut Vec) { - if new_id == *scroll_root_stack.last().unwrap() { - return; - } - - if new_id == *scroll_root_stack.first().unwrap() { - for _ in scroll_root_stack.drain(1..) { - list.push(DisplayItem::PopScrollRoot(Box::new(BaseDisplayItem::empty()))); - } - return; - } - - // We never want to reach the root of the ScrollRoot tree without encountering the - // containing scroll root of this StackingContext. If this does happen we've tried to - // switch to a ScrollRoot that does not contain our current stacking context or isn't - // itself a direct child of our current stacking context. This should never happen - // due to CSS stacking rules. - debug_assert!(new_id != ScrollRootId::root()); - - let scroll_root = self.scroll_roots.get(&new_id).unwrap(); - self.switch_scroll_roots(list, scroll_root.parent_id, scroll_root_stack); - - scroll_root_stack.push(new_id); - list.push(scroll_root.to_push()); } } @@ -507,6 +475,10 @@ pub trait FragmentDisplayListBuilding { mode: StackingContextCreationMode, parent_scroll_id: ScrollRootId) -> StackingContext; + + + /// The id of stacking context this fragment would create. + fn stacking_context_id(&self) -> StackingContextId; } fn handle_overlapping_radii(size: &Size2D, radii: &BorderRadii) -> BorderRadii { @@ -1612,6 +1584,10 @@ impl FragmentDisplayListBuilding for Fragment { } } + fn stacking_context_id(&self) -> StackingContextId { + StackingContextId::new_of_type(self.node.id() as usize, self.fragment_type()) + } + fn create_stacking_context(&self, id: StackingContextId, base_flow: &BaseFlow, @@ -1858,14 +1834,12 @@ impl FragmentDisplayListBuilding for Fragment { pub trait BlockFlowDisplayListBuilding { fn collect_stacking_contexts_for_block(&mut self, state: &mut DisplayListBuildState); - fn collect_scroll_root_for_block(&mut self, state: &mut DisplayListBuildState) -> ScrollRootId; + fn setup_scroll_root_for_block(&mut self, state: &mut DisplayListBuildState) -> ScrollRootId; fn create_pseudo_stacking_context_for_block(&mut self, - stacking_context_id: StackingContextId, parent_stacking_context_id: StackingContextId, parent_scroll_root_id: ScrollRootId, state: &mut DisplayListBuildState); fn create_real_stacking_context_for_block(&mut self, - stacking_context_id: StackingContextId, parent_stacking_context_id: StackingContextId, parent_scroll_root_id: ScrollRootId, state: &mut DisplayListBuildState); @@ -1876,43 +1850,49 @@ pub trait BlockFlowDisplayListBuilding { impl BlockFlowDisplayListBuilding for BlockFlow { fn collect_stacking_contexts_for_block(&mut self, state: &mut DisplayListBuildState) { - let parent_scroll_root_id = state.current_scroll_root_id; - self.base.scroll_root_id = self.collect_scroll_root_for_block(state); - state.current_scroll_root_id = self.base.scroll_root_id; - + let parent_stacking_context_id = state.current_stacking_context_id; let block_stacking_context_type = self.block_stacking_context_type(); - if block_stacking_context_type == BlockStackingContextType::NonstackingContext { - self.base.stacking_context_id = state.current_stacking_context_id; - self.base.collect_stacking_contexts_for_children(state); - } else { - let parent_stacking_context_id = state.current_stacking_context_id; - let stacking_context_id = - StackingContextId::new_of_type(self.fragment.node.id() as usize, - self.fragment.fragment_type()); - state.current_stacking_context_id = stacking_context_id; - self.base.stacking_context_id = stacking_context_id; + self.base.stacking_context_id = match block_stacking_context_type { + BlockStackingContextType::NonstackingContext => state.current_stacking_context_id, + BlockStackingContextType::PseudoStackingContext | + BlockStackingContextType::StackingContext => self.fragment.stacking_context_id(), + }; + state.current_stacking_context_id = self.base.stacking_context_id; - if block_stacking_context_type == BlockStackingContextType::PseudoStackingContext { - self.create_pseudo_stacking_context_for_block(stacking_context_id, - parent_stacking_context_id, - parent_scroll_root_id, + let original_scroll_root_id = state.current_scroll_root_id; + + // We are getting the id of the scroll root that contains us here, not the id of + // any scroll root that we create. If we create a scroll root, its id will be + // stored in state.current_scroll_root_id. If we should create a stacking context, + // we don't want it to be clipped by its own scroll root. + let containing_scroll_root_id = self.setup_scroll_root_for_block(state); + + match block_stacking_context_type { + BlockStackingContextType::NonstackingContext => { + self.base.collect_stacking_contexts_for_children(state); + } + BlockStackingContextType::PseudoStackingContext => { + self.create_pseudo_stacking_context_for_block(parent_stacking_context_id, + containing_scroll_root_id, state); - } else { - self.create_real_stacking_context_for_block(stacking_context_id, - parent_stacking_context_id, - parent_scroll_root_id, + } + BlockStackingContextType::StackingContext => { + self.create_real_stacking_context_for_block(parent_stacking_context_id, + containing_scroll_root_id, state); } - - state.current_stacking_context_id = parent_stacking_context_id; } - state.current_scroll_root_id = parent_scroll_root_id; + state.current_scroll_root_id = original_scroll_root_id; + state.current_stacking_context_id = parent_stacking_context_id; } - fn collect_scroll_root_for_block(&mut self, state: &mut DisplayListBuildState) -> ScrollRootId { + fn setup_scroll_root_for_block(&mut self, state: &mut DisplayListBuildState) -> ScrollRootId { + let containing_scroll_root_id = state.current_scroll_root_id; + self.base.scroll_root_id = containing_scroll_root_id; + if !self.style_permits_scrolling_overflow() { - return state.current_scroll_root_id; + return containing_scroll_root_id; } let coordinate_system = if self.fragment.establishes_stacking_context() { @@ -1933,25 +1913,27 @@ impl BlockFlowDisplayListBuilding for BlockFlow { self.base.overflow.scroll.size.height > clip.size.height; self.mark_scrolling_overflow(has_scrolling_overflow); if !has_scrolling_overflow { - return state.current_scroll_root_id; + return containing_scroll_root_id; } - let scroll_root_id = ScrollRootId::new_of_type(self.fragment.node.id() as usize, - self.fragment.fragment_type()); - let parent_scroll_root_id = state.current_scroll_root_id; + let new_scroll_root_id = ScrollRootId::new_of_type(self.fragment.node.id() as usize, + self.fragment.fragment_type()); state.add_scroll_root( ScrollRoot { - id: scroll_root_id, - parent_id: parent_scroll_root_id, + id: new_scroll_root_id, + parent_id: containing_scroll_root_id, clip: clip, size: self.base.overflow.scroll.size, - } + }, + self.base.stacking_context_id ); - scroll_root_id + + self.base.scroll_root_id = new_scroll_root_id; + state.current_scroll_root_id = new_scroll_root_id; + containing_scroll_root_id } fn create_pseudo_stacking_context_for_block(&mut self, - stacking_context_id: StackingContextId, parent_stacking_context_id: StackingContextId, parent_scroll_root_id: ScrollRootId, state: &mut DisplayListBuildState) { @@ -1963,7 +1945,7 @@ impl BlockFlowDisplayListBuilding for BlockFlow { StackingContextCreationMode::PseudoFloat }; - let new_context = self.fragment.create_stacking_context(stacking_context_id, + let new_context = self.fragment.create_stacking_context(self.base.stacking_context_id, &self.base, ScrollPolicy::Scrollable, creation_mode, @@ -1972,19 +1954,20 @@ impl BlockFlowDisplayListBuilding for BlockFlow { self.base.collect_stacking_contexts_for_children(state); - let new_children = - state.stacking_context_children.remove(&stacking_context_id).unwrap_or_else(Vec::new); - for child in new_children { - if child.context_type == StackingContextType::PseudoFloat { - state.add_stacking_context(stacking_context_id, child); - } else { - state.add_stacking_context(parent_stacking_context_id, child); + let children = state.stacking_context_info.get_mut(&self.base.stacking_context_id) + .map(|info| info.take_children()); + if let Some(children) = children { + for child in children { + if child.context_type == StackingContextType::PseudoFloat { + state.add_stacking_context(self.base.stacking_context_id, child); + } else { + state.add_stacking_context(parent_stacking_context_id, child); + } } } } fn create_real_stacking_context_for_block(&mut self, - stacking_context_id: StackingContextId, parent_stacking_context_id: StackingContextId, parent_scroll_root_id: ScrollRootId, state: &mut DisplayListBuildState) { @@ -1995,7 +1978,7 @@ impl BlockFlowDisplayListBuilding for BlockFlow { }; let stacking_context = self.fragment.create_stacking_context( - stacking_context_id, + self.base.stacking_context_id, &self.base, scroll_policy, StackingContextCreationMode::Normal, diff --git a/components/layout/webrender_helpers.rs b/components/layout/webrender_helpers.rs index 63814f6f5ed..2e94b79adaa 100644 --- a/components/layout/webrender_helpers.rs +++ b/components/layout/webrender_helpers.rs @@ -16,14 +16,16 @@ use msg::constellation_msg::PipelineId; use style::computed_values::{image_rendering, mix_blend_mode}; use style::computed_values::filter::{self, Filter}; use style::values::computed::BorderStyle; -use webrender_traits::{self, DisplayListBuilder, ExtendMode, LayoutTransform}; +use webrender_traits::{self, DisplayListBuilder, ExtendMode, LayoutTransform, ScrollLayerId}; pub trait WebRenderDisplayListConverter { fn convert_to_webrender(&self, pipeline_id: PipelineId) -> DisplayListBuilder; } trait WebRenderDisplayItemConverter { - fn convert_to_webrender(&self, builder: &mut DisplayListBuilder); + fn convert_to_webrender(&self, + builder: &mut DisplayListBuilder, + current_scroll_root_id: &mut ScrollRootId); } trait ToBorderStyle { @@ -212,16 +214,31 @@ impl ToFilterOps for filter::T { impl WebRenderDisplayListConverter for DisplayList { fn convert_to_webrender(&self, pipeline_id: PipelineId) -> DisplayListBuilder { let traversal = DisplayListTraversal::new(self); - let mut builder = DisplayListBuilder::new(pipeline_id.to_webrender()); + let webrender_pipeline_id = pipeline_id.to_webrender(); + let mut builder = DisplayListBuilder::new(webrender_pipeline_id); + + let mut current_scroll_root_id = ScrollRootId::root(); + builder.push_clip_id(current_scroll_root_id.convert_to_webrender(webrender_pipeline_id)); + for item in traversal { - item.convert_to_webrender(&mut builder); + item.convert_to_webrender(&mut builder, &mut current_scroll_root_id); } builder } } impl WebRenderDisplayItemConverter for DisplayItem { - fn convert_to_webrender(&self, builder: &mut DisplayListBuilder) { + fn convert_to_webrender(&self, + builder: &mut DisplayListBuilder, + current_scroll_root_id: &mut ScrollRootId) { + let scroll_root_id = self.base().scroll_root_id; + if scroll_root_id != *current_scroll_root_id { + let pipeline_id = builder.pipeline_id; + builder.pop_clip_id(); + builder.push_clip_id(scroll_root_id.convert_to_webrender(pipeline_id)); + *current_scroll_root_id = scroll_root_id; + } + match *self { DisplayItem::SolidColor(ref item) => { let color = item.color; @@ -403,21 +420,26 @@ impl WebRenderDisplayItemConverter for DisplayItem { vec![], None); - builder.push_scroll_layer(clip, - item.scroll_root.size.to_sizef(), - Some(item.scroll_root.id.convert_to_webrender())); + let provided_id = ScrollLayerId::new(item.scroll_root.id.0, builder.pipeline_id); + let id = builder.define_clip(clip, + item.scroll_root.size.to_sizef(), + Some(provided_id)); + debug_assert!(provided_id == id); } - DisplayItem::PopScrollRoot(_) => builder.pop_scroll_layer(), + DisplayItem::PopScrollRoot(_) => {} //builder.pop_scroll_layer(), } } } - trait WebRenderScrollRootIdConverter { - fn convert_to_webrender(&self) -> webrender_traits::ServoScrollRootId; + fn convert_to_webrender(&self, pipeline_id: webrender_traits::PipelineId) -> ScrollLayerId; } impl WebRenderScrollRootIdConverter for ScrollRootId { - fn convert_to_webrender(&self) -> webrender_traits::ServoScrollRootId { - webrender_traits::ServoScrollRootId(self.0) + fn convert_to_webrender(&self, pipeline_id: webrender_traits::PipelineId) -> ScrollLayerId { + if *self == ScrollRootId::root() { + ScrollLayerId::root_scroll_layer(pipeline_id) + } else { + ScrollLayerId::new(self.0, pipeline_id) + } } }