Use a new id type for tracking scrolling areas

This is a step in disassociating scrolling areas from stacking
contexts. Now scroll areas are defined by unique ids, which means that
in the future stacking context will be able to contain more than one.
This commit is contained in:
Martin Robinson 2016-10-21 08:03:01 +02:00
parent fbec79e920
commit 71d285af80
22 changed files with 242 additions and 92 deletions

View file

@ -11,7 +11,7 @@ use euclid::{Point2D, Size2D};
use euclid::point::TypedPoint2D; use euclid::point::TypedPoint2D;
use euclid::scale_factor::ScaleFactor; use euclid::scale_factor::ScaleFactor;
use euclid::size::TypedSize2D; use euclid::size::TypedSize2D;
use gfx_traits::{DevicePixel, LayerPixel, StackingContextId}; use gfx_traits::{DevicePixel, LayerPixel, ScrollRootId};
use gfx_traits::{Epoch, FrameTreeId, FragmentType}; use gfx_traits::{Epoch, FrameTreeId, FragmentType};
use gleam::gl; use gleam::gl;
use gleam::gl::types::{GLint, GLsizei}; use gleam::gl::types::{GLint, GLsizei};
@ -74,13 +74,13 @@ impl ConvertPipelineIdFromWebRender for webrender_traits::PipelineId {
} }
} }
trait ConvertStackingContextFromWebRender { trait ConvertScrollRootIdFromWebRender {
fn from_webrender(&self) -> StackingContextId; fn from_webrender(&self) -> ScrollRootId;
} }
impl ConvertStackingContextFromWebRender for webrender_traits::ServoStackingContextId { impl ConvertScrollRootIdFromWebRender for webrender_traits::ServoScrollRootId {
fn from_webrender(&self) -> StackingContextId { fn from_webrender(&self) -> ScrollRootId {
StackingContextId::new_of_type(self.1, self.0.from_webrender()) ScrollRootId(self.0)
} }
} }
@ -1312,7 +1312,7 @@ impl<Window: WindowMethods> IOCompositor<Window> {
let mut stacking_context_scroll_states_per_pipeline = HashMap::new(); let mut stacking_context_scroll_states_per_pipeline = HashMap::new();
for scroll_layer_state in self.webrender_api.get_scroll_layer_state() { for scroll_layer_state in self.webrender_api.get_scroll_layer_state() {
let stacking_context_scroll_state = StackingContextScrollState { let stacking_context_scroll_state = StackingContextScrollState {
stacking_context_id: scroll_layer_state.stacking_context_id.from_webrender(), scroll_root_id: scroll_layer_state.scroll_root_id.from_webrender(),
scroll_offset: scroll_layer_state.scroll_offset, scroll_offset: scroll_layer_state.scroll_offset,
}; };
let pipeline_id = scroll_layer_state.pipeline_id; let pipeline_id = scroll_layer_state.pipeline_id;

View file

@ -20,7 +20,7 @@ use euclid::{Matrix4D, Point2D, Rect, Size2D};
use euclid::num::{One, Zero}; use euclid::num::{One, Zero};
use euclid::rect::TypedRect; use euclid::rect::TypedRect;
use euclid::side_offsets::SideOffsets2D; use euclid::side_offsets::SideOffsets2D;
use gfx_traits::{ScrollPolicy, StackingContextId}; use gfx_traits::{ScrollPolicy, ScrollRootId, StackingContextId};
use gfx_traits::print_tree::PrintTree; use gfx_traits::print_tree::PrintTree;
use ipc_channel::ipc::IpcSharedMemory; use ipc_channel::ipc::IpcSharedMemory;
use msg::constellation_msg::PipelineId; use msg::constellation_msg::PipelineId;
@ -215,9 +215,11 @@ impl DisplayList {
// the DOM-side code has already translated the point for us (e.g. in // the DOM-side code has already translated the point for us (e.g. in
// `Window::hit_test_query()`) by now. // `Window::hit_test_query()`) by now.
if !is_fixed && stacking_context.id != StackingContextId::root() { if !is_fixed && stacking_context.id != StackingContextId::root() {
if let Some(scroll_offset) = scroll_offsets.get(&stacking_context.id) { if let Some(scroll_root_id) = stacking_context.overflow_scroll_id {
translated_point.x -= Au::from_f32_px(scroll_offset.x); if let Some(scroll_offset) = scroll_offsets.get(&scroll_root_id) {
translated_point.y -= Au::from_f32_px(scroll_offset.y); translated_point.x -= Au::from_f32_px(scroll_offset.x);
translated_point.y -= Au::from_f32_px(scroll_offset.y);
}
} }
} }
@ -386,7 +388,7 @@ pub struct StackingContext {
pub children: Vec<StackingContext>, pub children: Vec<StackingContext>,
/// If this StackingContext scrolls its overflow area, this will contain the id. /// If this StackingContext scrolls its overflow area, this will contain the id.
pub overflow_scroll_id: Option<StackingContextId>, pub overflow_scroll_id: Option<ScrollRootId>,
} }
impl StackingContext { impl StackingContext {
@ -403,7 +405,7 @@ impl StackingContext {
perspective: Matrix4D<f32>, perspective: Matrix4D<f32>,
establishes_3d_context: bool, establishes_3d_context: bool,
scroll_policy: ScrollPolicy, scroll_policy: ScrollPolicy,
scroll_id: Option<StackingContextId>) scroll_root_id: Option<ScrollRootId>)
-> StackingContext { -> StackingContext {
StackingContext { StackingContext {
id: id, id: id,
@ -418,7 +420,7 @@ impl StackingContext {
establishes_3d_context: establishes_3d_context, establishes_3d_context: establishes_3d_context,
scroll_policy: scroll_policy, scroll_policy: scroll_policy,
children: Vec::new(), children: Vec::new(),
overflow_scroll_id: scroll_id, overflow_scroll_id: scroll_root_id,
} }
} }
@ -1194,7 +1196,7 @@ impl WebRenderImageInfo {
} }
/// The type of the scroll offset list. This is only populated if WebRender is in use. /// The type of the scroll offset list. This is only populated if WebRender is in use.
pub type ScrollOffsetMap = HashMap<StackingContextId, Point2D<f32>>; pub type ScrollOffsetMap = HashMap<ScrollRootId, Point2D<f32>>;
pub trait SimpleMatrixDetection { pub trait SimpleMatrixDetection {

View file

@ -162,6 +162,58 @@ impl StackingContextId {
} }
} }
/// A unique ID for every scrolling root.
#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, HeapSizeOf, PartialEq, Serialize)]
pub struct ScrollRootId(
/// The identifier for this StackingContext, derived from the Flow's memory address
/// and fragment type. As a space optimization, these are combined into a single word.
pub usize
);
impl ScrollRootId {
/// Returns a new stacking context ID for a special stacking context.
fn next_special_id() -> usize {
// We shift this left by 2 to make room for the fragment type ID.
((NEXT_SPECIAL_STACKING_CONTEXT_ID.fetch_add(1, Ordering::SeqCst) + 1) << 2) &
SPECIAL_STACKING_CONTEXT_ID_MASK
}
#[inline]
pub fn new_of_type(id: usize, fragment_type: FragmentType) -> ScrollRootId {
debug_assert_eq!(id & (fragment_type as usize), 0);
if fragment_type == FragmentType::FragmentBody {
ScrollRootId(id)
} else {
ScrollRootId(ScrollRootId::next_special_id() | (fragment_type as usize))
}
}
/// Returns the stacking context ID for the outer document/layout root.
#[inline]
pub fn root() -> ScrollRootId {
ScrollRootId(0)
}
/// Returns true if this is a special stacking context.
///
/// A special stacking context is a stacking context that is one of (a) the outer stacking
/// context of an element with `overflow: scroll`; (b) generated content; (c) both (a) and (b).
#[inline]
pub fn is_special(&self) -> bool {
(self.0 & !SPECIAL_STACKING_CONTEXT_ID_MASK) == 0
}
#[inline]
pub fn id(&self) -> usize {
self.0 & !3
}
#[inline]
pub fn fragment_type(&self) -> FragmentType {
FragmentType::from_usize(self.0 & 3)
}
}
/// The type of fragment that a stacking context represents. /// The type of fragment that a stacking context represents.
/// ///
/// This can only ever grow to maximum 4 entries. That's because we cram the value of this enum /// This can only ever grow to maximum 4 entries. That's because we cram the value of this enum

View file

@ -44,6 +44,7 @@ use flow_ref::FlowRef;
use fragment::{CoordinateSystem, Fragment, FragmentBorderBoxIterator, Overflow}; use fragment::{CoordinateSystem, Fragment, FragmentBorderBoxIterator, Overflow};
use fragment::SpecificFragmentInfo; use fragment::SpecificFragmentInfo;
use gfx::display_list::{ClippingRegion, StackingContext}; use gfx::display_list::{ClippingRegion, StackingContext};
use gfx_traits::ScrollRootId;
use gfx_traits::print_tree::PrintTree; use gfx_traits::print_tree::PrintTree;
use layout_debug; use layout_debug;
use model::{CollapsibleMargins, IntrinsicISizes, MarginCollapseInfo, MaybeAuto}; use model::{CollapsibleMargins, IntrinsicISizes, MarginCollapseInfo, MaybeAuto};
@ -2162,8 +2163,10 @@ impl Flow for BlockFlow {
} }
} }
fn collect_stacking_contexts(&mut self, parent: &mut StackingContext) { fn collect_stacking_contexts(&mut self,
self.collect_stacking_contexts_for_block(parent); parent: &mut StackingContext,
parent_scroll_root_id: ScrollRootId) {
self.collect_stacking_contexts_for_block(parent, parent_scroll_root_id);
} }
fn build_display_list(&mut self, state: &mut DisplayListBuildState) { fn build_display_list(&mut self, state: &mut DisplayListBuildState) {

View file

@ -28,7 +28,7 @@ use gfx::display_list::{GradientStop, IframeDisplayItem, ImageDisplayItem, WebGL
use gfx::display_list::{LineDisplayItem, OpaqueNode}; use gfx::display_list::{LineDisplayItem, OpaqueNode};
use gfx::display_list::{SolidColorDisplayItem, StackingContext, StackingContextType}; use gfx::display_list::{SolidColorDisplayItem, StackingContext, StackingContextType};
use gfx::display_list::{TextDisplayItem, TextOrientation, WebRenderImageInfo}; use gfx::display_list::{TextDisplayItem, TextOrientation, WebRenderImageInfo};
use gfx_traits::{ScrollPolicy, StackingContextId, color}; use gfx_traits::{ScrollPolicy, ScrollRootId, StackingContextId, color};
use inline::{FIRST_FRAGMENT_OF_ELEMENT, InlineFlow, LAST_FRAGMENT_OF_ELEMENT}; use inline::{FIRST_FRAGMENT_OF_ELEMENT, InlineFlow, LAST_FRAGMENT_OF_ELEMENT};
use ipc_channel::ipc; use ipc_channel::ipc;
use list_item::ListItemFlow; use list_item::ListItemFlow;
@ -78,6 +78,7 @@ pub struct DisplayListBuildState<'a> {
pub shared_layout_context: &'a SharedLayoutContext, pub shared_layout_context: &'a SharedLayoutContext,
pub items: Vec<DisplayItem>, pub items: Vec<DisplayItem>,
pub stacking_context_id_stack: Vec<StackingContextId>, pub stacking_context_id_stack: Vec<StackingContextId>,
pub scroll_root_id_stack: Vec<ScrollRootId>,
} }
impl<'a> DisplayListBuildState<'a> { impl<'a> DisplayListBuildState<'a> {
@ -88,6 +89,7 @@ impl<'a> DisplayListBuildState<'a> {
shared_layout_context: shared_layout_context, shared_layout_context: shared_layout_context,
items: Vec::new(), items: Vec::new(),
stacking_context_id_stack: vec!(stacking_context_id), stacking_context_id_stack: vec!(stacking_context_id),
scroll_root_id_stack: vec!(ScrollRootId::root()),
} }
} }
@ -95,7 +97,7 @@ impl<'a> DisplayListBuildState<'a> {
self.items.push(display_item); self.items.push(display_item);
} }
fn stacking_context_id(&self) -> StackingContextId { pub fn stacking_context_id(&self) -> StackingContextId {
self.stacking_context_id_stack.last().unwrap().clone() self.stacking_context_id_stack.last().unwrap().clone()
} }
@ -108,6 +110,19 @@ impl<'a> DisplayListBuildState<'a> {
assert!(!self.stacking_context_id_stack.is_empty()); assert!(!self.stacking_context_id_stack.is_empty());
} }
pub fn scroll_root_id(&mut self) -> ScrollRootId {
self.scroll_root_id_stack.last().unwrap().clone()
}
pub fn push_scroll_root_id(&mut self, id: ScrollRootId) {
self.scroll_root_id_stack.push(id);
}
pub fn pop_scroll_root_id(&mut self) {
self.scroll_root_id_stack.pop();
assert!(!self.scroll_root_id_stack.is_empty());
}
fn create_base_display_item(&self, fn create_base_display_item(&self,
bounds: &Rect<Au>, bounds: &Rect<Au>,
clip: &ClippingRegion, clip: &ClippingRegion,
@ -299,7 +314,7 @@ pub trait FragmentDisplayListBuilding {
base_flow: &BaseFlow, base_flow: &BaseFlow,
scroll_policy: ScrollPolicy, scroll_policy: ScrollPolicy,
mode: StackingContextCreationMode, mode: StackingContextCreationMode,
scroll_id: Option<StackingContextId>) scroll_root_id: Option<ScrollRootId>)
-> StackingContext; -> StackingContext;
/// Returns the 4D matrix representing this fragment's transform. /// Returns the 4D matrix representing this fragment's transform.
@ -1356,7 +1371,7 @@ impl FragmentDisplayListBuilding for Fragment {
base_flow: &BaseFlow, base_flow: &BaseFlow,
scroll_policy: ScrollPolicy, scroll_policy: ScrollPolicy,
mode: StackingContextCreationMode, mode: StackingContextCreationMode,
scroll_id: Option<StackingContextId>) scroll_root_id: Option<ScrollRootId>)
-> StackingContext { -> StackingContext {
let scrolls_overflow_area = mode == StackingContextCreationMode::ScrollWrapper; let scrolls_overflow_area = mode == StackingContextCreationMode::ScrollWrapper;
let border_box = let border_box =
@ -1431,7 +1446,7 @@ impl FragmentDisplayListBuilding for Fragment {
perspective, perspective,
establishes_3d_context, establishes_3d_context,
scroll_policy, scroll_policy,
scroll_id) scroll_root_id)
} }
fn adjust_clipping_region_for_children(&self, fn adjust_clipping_region_for_children(&self,
@ -1687,7 +1702,9 @@ impl FragmentDisplayListBuilding for Fragment {
} }
pub trait BlockFlowDisplayListBuilding { pub trait BlockFlowDisplayListBuilding {
fn collect_stacking_contexts_for_block(&mut self, parent: &mut StackingContext); fn collect_stacking_contexts_for_block(&mut self,
parent: &mut StackingContext,
parent_scroll_root_id: ScrollRootId);
fn build_display_list_for_block(&mut self, fn build_display_list_for_block(&mut self,
state: &mut DisplayListBuildState, state: &mut DisplayListBuildState,
border_painting_mode: BorderPaintingMode); border_painting_mode: BorderPaintingMode);
@ -1704,17 +1721,29 @@ pub trait BlockFlowDisplayListBuilding {
} }
impl BlockFlowDisplayListBuilding for BlockFlow { impl BlockFlowDisplayListBuilding for BlockFlow {
fn collect_stacking_contexts_for_block(&mut self, parent: &mut StackingContext) { fn collect_stacking_contexts_for_block(&mut self,
parent: &mut StackingContext,
parent_scroll_root_id: ScrollRootId) {
let block_stacking_context_type = self.block_stacking_context_type(); let block_stacking_context_type = self.block_stacking_context_type();
if block_stacking_context_type == BlockStackingContextType::NonstackingContext { if block_stacking_context_type == BlockStackingContextType::NonstackingContext {
self.base.stacking_context_id = parent.id; self.base.stacking_context_id = parent.id;
self.base.collect_stacking_contexts_for_children(parent); self.base.collect_stacking_contexts_for_children(parent, parent_scroll_root_id);
return; return;
} }
let has_scrolling_overflow = self.has_scrolling_overflow();
let stacking_context_id = StackingContextId::new_of_type(self.fragment.node.id() as usize, let stacking_context_id = StackingContextId::new_of_type(self.fragment.node.id() as usize,
self.fragment.fragment_type()); self.fragment.fragment_type());
let has_scrolling_overflow = self.has_scrolling_overflow();
let scroll_root_id = if has_scrolling_overflow {
ScrollRootId::new_of_type(self.fragment.node.id() as usize,
self.fragment.fragment_type())
} else {
parent_scroll_root_id
};
self.base.scroll_root_id = scroll_root_id;
self.base.stacking_context_id = stacking_context_id; self.base.stacking_context_id = stacking_context_id;
if block_stacking_context_type == BlockStackingContextType::PseudoStackingContext { if block_stacking_context_type == BlockStackingContextType::PseudoStackingContext {
@ -1731,7 +1760,7 @@ impl BlockFlowDisplayListBuilding for BlockFlow {
ScrollPolicy::Scrollable, ScrollPolicy::Scrollable,
creation_mode, creation_mode,
None); None);
self.base.collect_stacking_contexts_for_children(&mut new_context); self.base.collect_stacking_contexts_for_children(&mut new_context, scroll_root_id);
let new_children: Vec<StackingContext> = new_context.children.drain(..).collect(); let new_children: Vec<StackingContext> = new_context.children.drain(..).collect();
let mut non_floating_children = Vec::new(); let mut non_floating_children = Vec::new();
@ -1755,10 +1784,7 @@ impl BlockFlowDisplayListBuilding for BlockFlow {
}; };
let (creation_mode, internal_id) = if has_scrolling_overflow { let (creation_mode, internal_id) = if has_scrolling_overflow {
(StackingContextCreationMode::ScrollWrapper, (StackingContextCreationMode::ScrollWrapper, Some(self.base.scroll_root_id))
Some(StackingContextId::new_of_type(self.fragment.node.id() as usize,
self.fragment.fragment_type())))
} else { } else {
(StackingContextCreationMode::Normal, None) (StackingContextCreationMode::Normal, None)
}; };
@ -1769,7 +1795,7 @@ impl BlockFlowDisplayListBuilding for BlockFlow {
scroll_policy, scroll_policy,
creation_mode, creation_mode,
internal_id); internal_id);
self.base.collect_stacking_contexts_for_children(&mut stacking_context); self.base.collect_stacking_contexts_for_children(&mut stacking_context, scroll_root_id);
parent.add_child(stacking_context); parent.add_child(stacking_context);
} }
@ -1859,7 +1885,9 @@ impl BlockFlowDisplayListBuilding for BlockFlow {
} }
pub trait InlineFlowDisplayListBuilding { pub trait InlineFlowDisplayListBuilding {
fn collect_stacking_contexts_for_inline(&mut self, parent: &mut StackingContext); fn collect_stacking_contexts_for_inline(&mut self,
parent: &mut StackingContext,
parent_scroll_root_id: ScrollRootId);
fn build_display_list_for_inline_fragment_at_index(&mut self, fn build_display_list_for_inline_fragment_at_index(&mut self,
state: &mut DisplayListBuildState, state: &mut DisplayListBuildState,
index: usize); index: usize);
@ -1867,18 +1895,21 @@ pub trait InlineFlowDisplayListBuilding {
} }
impl InlineFlowDisplayListBuilding for InlineFlow { impl InlineFlowDisplayListBuilding for InlineFlow {
fn collect_stacking_contexts_for_inline(&mut self, parent: &mut StackingContext) { fn collect_stacking_contexts_for_inline(&mut self,
parent: &mut StackingContext,
parent_scroll_root_id: ScrollRootId) {
self.base.stacking_context_id = parent.id; self.base.stacking_context_id = parent.id;
self.base.scroll_root_id = parent_scroll_root_id;
for mut fragment in self.fragments.fragments.iter_mut() { for mut fragment in self.fragments.fragments.iter_mut() {
match fragment.specific { match fragment.specific {
SpecificFragmentInfo::InlineBlock(ref mut block_flow) => { SpecificFragmentInfo::InlineBlock(ref mut block_flow) => {
let block_flow = flow_ref::deref_mut(&mut block_flow.flow_ref); let block_flow = flow_ref::deref_mut(&mut block_flow.flow_ref);
block_flow.collect_stacking_contexts(parent); block_flow.collect_stacking_contexts(parent, parent_scroll_root_id);
} }
SpecificFragmentInfo::InlineAbsoluteHypothetical(ref mut block_flow) => { SpecificFragmentInfo::InlineAbsoluteHypothetical(ref mut block_flow) => {
let block_flow = flow_ref::deref_mut(&mut block_flow.flow_ref); let block_flow = flow_ref::deref_mut(&mut block_flow.flow_ref);
block_flow.collect_stacking_contexts(parent); block_flow.collect_stacking_contexts(parent, parent_scroll_root_id);
} }
_ if fragment.establishes_stacking_context() => { _ if fragment.establishes_stacking_context() => {
fragment.stacking_context_id = fragment.stacking_context_id =

View file

@ -17,6 +17,7 @@ use flow::{Flow, FlowClass, ImmutableFlowUtils, OpaqueFlow};
use flow::{INLINE_POSITION_IS_STATIC, IS_ABSOLUTELY_POSITIONED}; use flow::{INLINE_POSITION_IS_STATIC, IS_ABSOLUTELY_POSITIONED};
use fragment::{Fragment, FragmentBorderBoxIterator, Overflow}; use fragment::{Fragment, FragmentBorderBoxIterator, Overflow};
use gfx::display_list::StackingContext; use gfx::display_list::StackingContext;
use gfx_traits::ScrollRootId;
use layout_debug; use layout_debug;
use model::{Direction, IntrinsicISizes, MaybeAuto, MinMaxConstraint}; use model::{Direction, IntrinsicISizes, MaybeAuto, MinMaxConstraint};
use model::{specified, specified_or_none}; use model::{specified, specified_or_none};
@ -956,8 +957,10 @@ impl Flow for FlexFlow {
self.build_display_list_for_flex(state); self.build_display_list_for_flex(state);
} }
fn collect_stacking_contexts(&mut self, parent: &mut StackingContext) { fn collect_stacking_contexts(&mut self,
self.block_flow.collect_stacking_contexts(parent); parent: &mut StackingContext,
parent_scroll_root_id: ScrollRootId) {
self.block_flow.collect_stacking_contexts(parent, parent_scroll_root_id);
} }
fn repair_style(&mut self, new_style: &Arc<ServoComputedValues>) { fn repair_style(&mut self, new_style: &Arc<ServoComputedValues>) {

View file

@ -35,7 +35,7 @@ use flow_list::{FlowList, MutFlowListIterator};
use flow_ref::{self, FlowRef, WeakFlowRef}; use flow_ref::{self, FlowRef, WeakFlowRef};
use fragment::{Fragment, FragmentBorderBoxIterator, Overflow}; use fragment::{Fragment, FragmentBorderBoxIterator, Overflow};
use gfx::display_list::{ClippingRegion, StackingContext}; use gfx::display_list::{ClippingRegion, StackingContext};
use gfx_traits::StackingContextId; use gfx_traits::{ScrollRootId, StackingContextId};
use gfx_traits::print_tree::PrintTree; use gfx_traits::print_tree::PrintTree;
use inline::InlineFlow; use inline::InlineFlow;
use model::{CollapsibleMargins, IntrinsicISizes, MarginCollapseInfo}; use model::{CollapsibleMargins, IntrinsicISizes, MarginCollapseInfo};
@ -223,7 +223,9 @@ pub trait Flow: fmt::Debug + Sync + Send + 'static {
None None
} }
fn collect_stacking_contexts(&mut self, _parent: &mut StackingContext); fn collect_stacking_contexts(&mut self,
_parent: &mut StackingContext,
parent_scroll_root_id: ScrollRootId);
/// If this is a float, places it. The default implementation does nothing. /// If this is a float, places it. The default implementation does nothing.
fn place_float_if_applicable<'a>(&mut self) {} fn place_float_if_applicable<'a>(&mut self) {}
@ -935,6 +937,8 @@ pub struct BaseFlow {
/// to 0, but it assigned during the collect_stacking_contexts phase of display /// to 0, but it assigned during the collect_stacking_contexts phase of display
/// list construction. /// list construction.
pub stacking_context_id: StackingContextId, pub stacking_context_id: StackingContextId,
pub scroll_root_id: ScrollRootId,
} }
impl fmt::Debug for BaseFlow { impl fmt::Debug for BaseFlow {
@ -1105,6 +1109,7 @@ impl BaseFlow {
writing_mode: writing_mode, writing_mode: writing_mode,
thread_id: 0, thread_id: 0,
stacking_context_id: StackingContextId::new(0), stacking_context_id: StackingContextId::new(0),
scroll_root_id: ScrollRootId::root(),
} }
} }
@ -1136,9 +1141,11 @@ impl BaseFlow {
return self as *const BaseFlow as usize; return self as *const BaseFlow as usize;
} }
pub fn collect_stacking_contexts_for_children(&mut self, parent: &mut StackingContext) { pub fn collect_stacking_contexts_for_children(&mut self,
parent: &mut StackingContext,
parent_scroll_root_id: ScrollRootId) {
for kid in self.children.iter_mut() { for kid in self.children.iter_mut() {
kid.collect_stacking_contexts(parent); kid.collect_stacking_contexts(parent, parent_scroll_root_id);
} }
} }

View file

@ -19,6 +19,7 @@ use fragment::SpecificFragmentInfo;
use gfx::display_list::{OpaqueNode, StackingContext}; use gfx::display_list::{OpaqueNode, StackingContext};
use gfx::font::FontMetrics; use gfx::font::FontMetrics;
use gfx::font_context::FontContext; use gfx::font_context::FontContext;
use gfx_traits::ScrollRootId;
use gfx_traits::print_tree::PrintTree; use gfx_traits::print_tree::PrintTree;
use layout_debug; use layout_debug;
use model::IntrinsicISizesContribution; use model::IntrinsicISizesContribution;
@ -1613,8 +1614,10 @@ impl Flow for InlineFlow {
fn update_late_computed_block_position_if_necessary(&mut self, _: Au) {} fn update_late_computed_block_position_if_necessary(&mut self, _: Au) {}
fn collect_stacking_contexts(&mut self, parent: &mut StackingContext) { fn collect_stacking_contexts(&mut self,
self.collect_stacking_contexts_for_inline(parent); parent: &mut StackingContext,
parent_scroll_root_id: ScrollRootId) {
self.collect_stacking_contexts_for_inline(parent, parent_scroll_root_id);
} }
fn build_display_list(&mut self, state: &mut DisplayListBuildState) { fn build_display_list(&mut self, state: &mut DisplayListBuildState) {

View file

@ -18,6 +18,7 @@ use fragment::{CoordinateSystem, Fragment, FragmentBorderBoxIterator, GeneratedC
use fragment::Overflow; use fragment::Overflow;
use generated_content; use generated_content;
use gfx::display_list::StackingContext; use gfx::display_list::StackingContext;
use gfx_traits::ScrollRootId;
use inline::InlineFlow; use inline::InlineFlow;
use script_layout_interface::restyle_damage::RESOLVE_GENERATED_CONTENT; use script_layout_interface::restyle_damage::RESOLVE_GENERATED_CONTENT;
use std::sync::Arc; use std::sync::Arc;
@ -145,8 +146,10 @@ impl Flow for ListItemFlow {
self.build_display_list_for_list_item(state); self.build_display_list_for_list_item(state);
} }
fn collect_stacking_contexts(&mut self, parent: &mut StackingContext) { fn collect_stacking_contexts(&mut self,
self.block_flow.collect_stacking_contexts(parent); parent: &mut StackingContext,
parent_scroll_root_id: ScrollRootId) {
self.block_flow.collect_stacking_contexts(parent, parent_scroll_root_id);
} }
fn repair_style(&mut self, new_style: &Arc<ServoComputedValues>) { fn repair_style(&mut self, new_style: &Arc<ServoComputedValues>) {

View file

@ -17,6 +17,7 @@ use flow::{Flow, FlowClass, OpaqueFlow, mut_base, FragmentationContext};
use flow_ref::{self, FlowRef}; use flow_ref::{self, FlowRef};
use fragment::{Fragment, FragmentBorderBoxIterator, Overflow}; use fragment::{Fragment, FragmentBorderBoxIterator, Overflow};
use gfx::display_list::StackingContext; use gfx::display_list::StackingContext;
use gfx_traits::ScrollRootId;
use gfx_traits::print_tree::PrintTree; use gfx_traits::print_tree::PrintTree;
use std::cmp::{min, max}; use std::cmp::{min, max};
use std::fmt; use std::fmt;
@ -185,8 +186,10 @@ impl Flow for MulticolFlow {
self.block_flow.build_display_list(state); self.block_flow.build_display_list(state);
} }
fn collect_stacking_contexts(&mut self, parent: &mut StackingContext) { fn collect_stacking_contexts(&mut self,
self.block_flow.collect_stacking_contexts(parent); parent: &mut StackingContext,
parent_scroll_root_id: ScrollRootId) {
self.block_flow.collect_stacking_contexts(parent, parent_scroll_root_id);
} }
fn repair_style(&mut self, new_style: &Arc<ServoComputedValues>) { fn repair_style(&mut self, new_style: &Arc<ServoComputedValues>) {
@ -267,8 +270,10 @@ impl Flow for MulticolColumnFlow {
self.block_flow.build_display_list(state); self.block_flow.build_display_list(state);
} }
fn collect_stacking_contexts(&mut self, parent: &mut StackingContext) { fn collect_stacking_contexts(&mut self,
self.block_flow.collect_stacking_contexts(parent); parent: &mut StackingContext,
parent_scroll_root_id: ScrollRootId) {
self.block_flow.collect_stacking_contexts(parent, parent_scroll_root_id);
} }
fn repair_style(&mut self, new_style: &Arc<ServoComputedValues>) { fn repair_style(&mut self, new_style: &Arc<ServoComputedValues>) {

View file

@ -15,6 +15,7 @@ use flow::IS_ABSOLUTELY_POSITIONED;
use fragment::FragmentBorderBoxIterator; use fragment::FragmentBorderBoxIterator;
use generated_content::ResolveGeneratedContent; use generated_content::ResolveGeneratedContent;
use gfx::display_list::{DisplayItem, StackingContext}; use gfx::display_list::{DisplayItem, StackingContext};
use gfx_traits::ScrollRootId;
use script_layout_interface::restyle_damage::{REFLOW, STORE_OVERFLOW}; use script_layout_interface::restyle_damage::{REFLOW, STORE_OVERFLOW};
use style::context::StyleContext; use style::context::StyleContext;
use traversal::{AssignBSizes, AssignISizes, BubbleISizes, BuildDisplayList}; use traversal::{AssignBSizes, AssignISizes, BubbleISizes, BuildDisplayList};
@ -78,7 +79,7 @@ pub fn build_display_list_for_subtree(flow_root: &mut Flow,
root_stacking_context: &mut StackingContext, root_stacking_context: &mut StackingContext,
shared_layout_context: &SharedLayoutContext) shared_layout_context: &SharedLayoutContext)
-> Vec<DisplayItem> { -> Vec<DisplayItem> {
flow_root.collect_stacking_contexts(root_stacking_context); flow_root.collect_stacking_contexts(root_stacking_context, ScrollRootId::root());
let mut build_display_list = BuildDisplayList { let mut build_display_list = BuildDisplayList {
state: DisplayListBuildState::new(shared_layout_context, state: DisplayListBuildState::new(shared_layout_context,
flow::base(flow_root).stacking_context_id), flow::base(flow_root).stacking_context_id),

View file

@ -17,6 +17,7 @@ use flow::{BaseFlow, EarlyAbsolutePositionInfo, Flow, FlowClass, ImmutableFlowUt
use flow_list::MutFlowListIterator; use flow_list::MutFlowListIterator;
use fragment::{Fragment, FragmentBorderBoxIterator, Overflow}; use fragment::{Fragment, FragmentBorderBoxIterator, Overflow};
use gfx::display_list::StackingContext; use gfx::display_list::StackingContext;
use gfx_traits::ScrollRootId;
use gfx_traits::print_tree::PrintTree; use gfx_traits::print_tree::PrintTree;
use layout_debug; use layout_debug;
use model::{IntrinsicISizes, IntrinsicISizesContribution, MaybeAuto}; use model::{IntrinsicISizes, IntrinsicISizesContribution, MaybeAuto};
@ -489,8 +490,10 @@ impl Flow for TableFlow {
self.block_flow.build_display_list_for_block(state, border_painting_mode); self.block_flow.build_display_list_for_block(state, border_painting_mode);
} }
fn collect_stacking_contexts(&mut self, parent: &mut StackingContext) { fn collect_stacking_contexts(&mut self,
self.block_flow.collect_stacking_contexts(parent); parent: &mut StackingContext,
parent_scroll_root_id: ScrollRootId) {
self.block_flow.collect_stacking_contexts(parent, parent_scroll_root_id);
} }
fn repair_style(&mut self, new_style: &Arc<ServoComputedValues>) { fn repair_style(&mut self, new_style: &Arc<ServoComputedValues>) {

View file

@ -14,6 +14,7 @@ use euclid::Point2D;
use flow::{Flow, FlowClass, OpaqueFlow}; use flow::{Flow, FlowClass, OpaqueFlow};
use fragment::{Fragment, FragmentBorderBoxIterator, Overflow}; use fragment::{Fragment, FragmentBorderBoxIterator, Overflow};
use gfx::display_list::StackingContext; use gfx::display_list::StackingContext;
use gfx_traits::ScrollRootId;
use gfx_traits::print_tree::PrintTree; use gfx_traits::print_tree::PrintTree;
use std::fmt; use std::fmt;
use std::sync::Arc; use std::sync::Arc;
@ -82,8 +83,10 @@ impl Flow for TableCaptionFlow {
self.block_flow.build_display_list(state); self.block_flow.build_display_list(state);
} }
fn collect_stacking_contexts(&mut self, parent: &mut StackingContext) { fn collect_stacking_contexts(&mut self,
self.block_flow.collect_stacking_contexts(parent); parent: &mut StackingContext,
parent_scroll_root_id: ScrollRootId) {
self.block_flow.collect_stacking_contexts(parent, parent_scroll_root_id);
} }
fn repair_style(&mut self, new_style: &Arc<ServoComputedValues>) { fn repair_style(&mut self, new_style: &Arc<ServoComputedValues>) {

View file

@ -15,6 +15,7 @@ use euclid::{Point2D, Rect, SideOffsets2D, Size2D};
use flow::{self, Flow, FlowClass, IS_ABSOLUTELY_POSITIONED, OpaqueFlow}; use flow::{self, Flow, FlowClass, IS_ABSOLUTELY_POSITIONED, OpaqueFlow};
use fragment::{Fragment, FragmentBorderBoxIterator, Overflow}; use fragment::{Fragment, FragmentBorderBoxIterator, Overflow};
use gfx::display_list::StackingContext; use gfx::display_list::StackingContext;
use gfx_traits::ScrollRootId;
use gfx_traits::print_tree::PrintTree; use gfx_traits::print_tree::PrintTree;
use layout_debug; use layout_debug;
use model::MaybeAuto; use model::MaybeAuto;
@ -256,8 +257,10 @@ impl Flow for TableCellFlow {
self.block_flow.build_display_list_for_block(state, border_painting_mode) self.block_flow.build_display_list_for_block(state, border_painting_mode)
} }
fn collect_stacking_contexts(&mut self, parent: &mut StackingContext) { fn collect_stacking_contexts(&mut self,
self.block_flow.collect_stacking_contexts(parent); parent: &mut StackingContext,
parent_scroll_root_id: ScrollRootId) {
self.block_flow.collect_stacking_contexts(parent, parent_scroll_root_id);
} }
fn repair_style(&mut self, new_style: &Arc<ServoComputedValues>) { fn repair_style(&mut self, new_style: &Arc<ServoComputedValues>) {

View file

@ -13,6 +13,7 @@ use euclid::Point2D;
use flow::{BaseFlow, Flow, FlowClass, ForceNonfloatedFlag, OpaqueFlow}; use flow::{BaseFlow, Flow, FlowClass, ForceNonfloatedFlag, OpaqueFlow};
use fragment::{Fragment, FragmentBorderBoxIterator, Overflow, SpecificFragmentInfo}; use fragment::{Fragment, FragmentBorderBoxIterator, Overflow, SpecificFragmentInfo};
use gfx::display_list::StackingContext; use gfx::display_list::StackingContext;
use gfx_traits::ScrollRootId;
use layout_debug; use layout_debug;
use std::cmp::max; use std::cmp::max;
use std::fmt; use std::fmt;
@ -95,7 +96,9 @@ impl Flow for TableColGroupFlow {
// Table columns are invisible. // Table columns are invisible.
fn build_display_list(&mut self, _: &mut DisplayListBuildState) { } fn build_display_list(&mut self, _: &mut DisplayListBuildState) { }
fn collect_stacking_contexts(&mut self, _parent: &mut StackingContext) { } fn collect_stacking_contexts(&mut self,
_parent: &mut StackingContext,
_parent_scroll_root_id: ScrollRootId) {}
fn repair_style(&mut self, _: &Arc<ServoComputedValues>) {} fn repair_style(&mut self, _: &Arc<ServoComputedValues>) {}

View file

@ -16,6 +16,7 @@ use flow::{self, EarlyAbsolutePositionInfo, Flow, FlowClass, ImmutableFlowUtils,
use flow_list::MutFlowListIterator; use flow_list::MutFlowListIterator;
use fragment::{Fragment, FragmentBorderBoxIterator, Overflow}; use fragment::{Fragment, FragmentBorderBoxIterator, Overflow};
use gfx::display_list::StackingContext; use gfx::display_list::StackingContext;
use gfx_traits::ScrollRootId;
use gfx_traits::print_tree::PrintTree; use gfx_traits::print_tree::PrintTree;
use layout_debug; use layout_debug;
use model::MaybeAuto; use model::MaybeAuto;
@ -458,8 +459,10 @@ impl Flow for TableRowFlow {
self.block_flow.build_display_list_for_block(state, border_painting_mode); self.block_flow.build_display_list_for_block(state, border_painting_mode);
} }
fn collect_stacking_contexts(&mut self, parent: &mut StackingContext) { fn collect_stacking_contexts(&mut self,
self.block_flow.collect_stacking_contexts(parent); parent: &mut StackingContext,
parent_scroll_root_id: ScrollRootId) {
self.block_flow.collect_stacking_contexts(parent, parent_scroll_root_id);
} }
fn repair_style(&mut self, new_style: &Arc<ServoComputedValues>) { fn repair_style(&mut self, new_style: &Arc<ServoComputedValues>) {

View file

@ -14,6 +14,7 @@ use euclid::Point2D;
use flow::{Flow, FlowClass, OpaqueFlow}; use flow::{Flow, FlowClass, OpaqueFlow};
use fragment::{Fragment, FragmentBorderBoxIterator, Overflow}; use fragment::{Fragment, FragmentBorderBoxIterator, Overflow};
use gfx::display_list::StackingContext; use gfx::display_list::StackingContext;
use gfx_traits::ScrollRootId;
use gfx_traits::print_tree::PrintTree; use gfx_traits::print_tree::PrintTree;
use layout_debug; use layout_debug;
use rustc_serialize::{Encodable, Encoder}; use rustc_serialize::{Encodable, Encoder};
@ -211,8 +212,10 @@ impl Flow for TableRowGroupFlow {
self.block_flow.build_display_list(state); self.block_flow.build_display_list(state);
} }
fn collect_stacking_contexts(&mut self, parent: &mut StackingContext) { fn collect_stacking_contexts(&mut self,
self.block_flow.collect_stacking_contexts(parent); parent: &mut StackingContext,
parent_scroll_root_id: ScrollRootId) {
self.block_flow.collect_stacking_contexts(parent, parent_scroll_root_id);
} }
fn repair_style(&mut self, new_style: &Arc<ServoComputedValues>) { fn repair_style(&mut self, new_style: &Arc<ServoComputedValues>) {

View file

@ -23,6 +23,7 @@ use floats::FloatKind;
use flow::{Flow, FlowClass, ImmutableFlowUtils, INLINE_POSITION_IS_STATIC, OpaqueFlow}; use flow::{Flow, FlowClass, ImmutableFlowUtils, INLINE_POSITION_IS_STATIC, OpaqueFlow};
use fragment::{Fragment, FragmentBorderBoxIterator, Overflow}; use fragment::{Fragment, FragmentBorderBoxIterator, Overflow};
use gfx::display_list::StackingContext; use gfx::display_list::StackingContext;
use gfx_traits::ScrollRootId;
use gfx_traits::print_tree::PrintTree; use gfx_traits::print_tree::PrintTree;
use model::MaybeAuto; use model::MaybeAuto;
use std::cmp::{max, min}; use std::cmp::{max, min};
@ -468,8 +469,10 @@ impl Flow for TableWrapperFlow {
self.block_flow.build_display_list(state); self.block_flow.build_display_list(state);
} }
fn collect_stacking_contexts(&mut self, parent: &mut StackingContext) { fn collect_stacking_contexts(&mut self,
self.block_flow.collect_stacking_contexts(parent); parent: &mut StackingContext,
parent_scroll_root_id: ScrollRootId) {
self.block_flow.collect_stacking_contexts(parent, parent_scroll_root_id);
} }
fn repair_style(&mut self, new_style: &Arc<ServoComputedValues>) { fn repair_style(&mut self, new_style: &Arc<ServoComputedValues>) {

View file

@ -247,10 +247,28 @@ impl<'a> BuildDisplayList<'a> {
#[inline] #[inline]
pub fn traverse(&mut self, flow: &mut Flow) { pub fn traverse(&mut self, flow: &mut Flow) {
if self.should_process() { if self.should_process() {
self.state.push_stacking_context_id(flow::base(flow).stacking_context_id); let new_stacking_context =
flow::base(flow).stacking_context_id != self.state.stacking_context_id();
if new_stacking_context {
self.state.push_stacking_context_id(flow::base(flow).stacking_context_id);
}
let new_scroll_root =
flow::base(flow).scroll_root_id != self.state.scroll_root_id();
if new_scroll_root {
self.state.push_scroll_root_id(flow::base(flow).scroll_root_id);
}
flow.build_display_list(&mut self.state); flow.build_display_list(&mut self.state);
flow::mut_base(flow).restyle_damage.remove(REPAINT); flow::mut_base(flow).restyle_damage.remove(REPAINT);
self.state.pop_stacking_context_id();
if new_stacking_context {
self.state.pop_stacking_context_id();
}
if new_scroll_root {
self.state.pop_scroll_root_id();
}
} }
for kid in flow::child_iter_mut(flow) { for kid in flow::child_iter_mut(flow) {

View file

@ -13,7 +13,7 @@ use euclid::{Point2D, Rect, Size2D};
use gfx::display_list::{BorderRadii, BoxShadowClipMode, ClippingRegion}; use gfx::display_list::{BorderRadii, BoxShadowClipMode, ClippingRegion};
use gfx::display_list::{DisplayItem, DisplayList, DisplayListTraversal}; use gfx::display_list::{DisplayItem, DisplayList, DisplayListTraversal};
use gfx::display_list::{GradientStop, StackingContext, StackingContextType}; use gfx::display_list::{GradientStop, StackingContext, StackingContextType};
use gfx_traits::{FragmentType, ScrollPolicy, StackingContextId}; use gfx_traits::{FragmentType, ScrollPolicy, StackingContextId, ScrollRootId};
use style::computed_values::{image_rendering, mix_blend_mode}; use style::computed_values::{image_rendering, mix_blend_mode};
use style::computed_values::filter::{self, Filter}; use style::computed_values::filter::{self, Filter};
use style::values::computed::BorderStyle; use style::values::computed::BorderStyle;
@ -287,18 +287,16 @@ impl WebRenderStackingContextConverter for StackingContext {
ScrollPolicy::FixedPosition => webrender_traits::ScrollPolicy::Fixed, ScrollPolicy::FixedPosition => webrender_traits::ScrollPolicy::Fixed,
}; };
let webrender_stacking_context_id = self.id.convert_to_webrender(); let scroll_layer_id = if let Some(scroll_root_id) = self.overflow_scroll_id {
Some(frame_builder.next_scroll_layer_id(scroll_root_id))
let scroll_layer_id = if self.overflow_scroll_id.is_some() || } else if self.id == StackingContextId::root() {
self.id == StackingContextId::root() { Some(frame_builder.next_scroll_layer_id(ScrollRootId::root()))
Some(frame_builder.next_scroll_layer_id())
} else { } else {
None None
}; };
let mut sc = let mut sc =
webrender_traits::StackingContext::new(webrender_stacking_context_id, webrender_traits::StackingContext::new(scroll_layer_id,
scroll_layer_id,
webrender_scroll_policy, webrender_scroll_policy,
self.bounds.to_rectf(), self.bounds.to_rectf(),
self.overflow.to_rectf(), self.overflow.to_rectf(),
@ -532,21 +530,25 @@ impl WebRenderFrameBuilder {
id id
} }
pub fn next_scroll_layer_id(&mut self) -> webrender_traits::ScrollLayerId { pub fn next_scroll_layer_id(&mut self,
scroll_root_id: ScrollRootId)
-> webrender_traits::ScrollLayerId {
let scroll_layer_id = self.next_scroll_layer_id; let scroll_layer_id = self.next_scroll_layer_id;
self.next_scroll_layer_id += 1; self.next_scroll_layer_id += 1;
webrender_traits::ScrollLayerId::new(self.root_pipeline_id, scroll_layer_id) webrender_traits::ScrollLayerId::new(self.root_pipeline_id,
scroll_layer_id,
scroll_root_id.convert_to_webrender())
} }
} }
trait WebRenderStackingContextIdConverter { trait WebRenderScrollRootIdConverter {
fn convert_to_webrender(&self) -> webrender_traits::ServoStackingContextId; fn convert_to_webrender(&self) -> webrender_traits::ServoScrollRootId;
} }
impl WebRenderStackingContextIdConverter for StackingContextId { impl WebRenderScrollRootIdConverter for ScrollRootId {
fn convert_to_webrender(&self) -> webrender_traits::ServoStackingContextId { fn convert_to_webrender(&self) -> webrender_traits::ServoScrollRootId {
webrender_traits::ServoStackingContextId(self.fragment_type().convert_to_webrender(), webrender_traits::ServoScrollRootId(self.0)
self.id())
} }
} }

View file

@ -56,7 +56,7 @@ use gfx::display_list::{StackingContext, StackingContextType, WebRenderImageInfo
use gfx::font; use gfx::font;
use gfx::font_cache_thread::FontCacheThread; use gfx::font_cache_thread::FontCacheThread;
use gfx::font_context; use gfx::font_context;
use gfx_traits::{Epoch, FragmentType, ScrollPolicy, StackingContextId, color}; use gfx_traits::{Epoch, FragmentType, ScrollPolicy, ScrollRootId, StackingContextId, color};
use heapsize::HeapSizeOf; use heapsize::HeapSizeOf;
use ipc_channel::ipc::{self, IpcReceiver, IpcSender}; use ipc_channel::ipc::{self, IpcReceiver, IpcSender};
use ipc_channel::router::ROUTER; use ipc_channel::router::ROUTER;
@ -1282,14 +1282,13 @@ impl LayoutThread {
let mut layout_scroll_states = HashMap::new(); let mut layout_scroll_states = HashMap::new();
for new_scroll_state in &new_scroll_states { for new_scroll_state in &new_scroll_states {
let offset = new_scroll_state.scroll_offset; let offset = new_scroll_state.scroll_offset;
layout_scroll_states.insert(new_scroll_state.stacking_context_id, offset); layout_scroll_states.insert(new_scroll_state.scroll_root_id, offset);
if new_scroll_state.stacking_context_id == StackingContextId::root() { if new_scroll_state.scroll_root_id == ScrollRootId::root() {
script_scroll_states.push((UntrustedNodeAddress::from_id(0), offset)) script_scroll_states.push((UntrustedNodeAddress::from_id(0), offset))
} else if !new_scroll_state.stacking_context_id.is_special() && } else if !new_scroll_state.scroll_root_id.is_special() &&
new_scroll_state.stacking_context_id.fragment_type() == new_scroll_state.scroll_root_id.fragment_type() == FragmentType::FragmentBody {
FragmentType::FragmentBody { let id = new_scroll_state.scroll_root_id.id();
let id = new_scroll_state.stacking_context_id.id();
script_scroll_states.push((UntrustedNodeAddress::from_id(id), offset)) script_scroll_states.push((UntrustedNodeAddress::from_id(id), offset))
} }
} }

View file

@ -45,7 +45,7 @@ use euclid::scale_factor::ScaleFactor;
use euclid::size::TypedSize2D; use euclid::size::TypedSize2D;
use gfx_traits::DevicePixel; use gfx_traits::DevicePixel;
use gfx_traits::Epoch; use gfx_traits::Epoch;
use gfx_traits::StackingContextId; use gfx_traits::ScrollRootId;
use heapsize::HeapSizeOf; use heapsize::HeapSizeOf;
use hyper::header::Headers; use hyper::header::Headers;
use hyper::method::Method; use hyper::method::Method;
@ -600,8 +600,8 @@ pub enum AnimationTickType {
/// The scroll state of a stacking context. /// The scroll state of a stacking context.
#[derive(Copy, Clone, Debug, Deserialize, Serialize)] #[derive(Copy, Clone, Debug, Deserialize, Serialize)]
pub struct StackingContextScrollState { pub struct StackingContextScrollState {
/// The ID of the stacking context. /// The ID of the scroll root.
pub stacking_context_id: StackingContextId, pub scroll_root_id: ScrollRootId,
/// The scrolling offset of this stacking context. /// The scrolling offset of this stacking context.
pub scroll_offset: Point2D<f32>, pub scroll_offset: Point2D<f32>,
} }