Skip to content

Commit

Permalink
Use a new id type for tracking scrolling areas
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
mrobinson committed Oct 30, 2016
1 parent fbec79e commit 71d285a
Show file tree
Hide file tree
Showing 22 changed files with 242 additions and 92 deletions.
14 changes: 7 additions & 7 deletions components/compositing/compositor.rs
Expand Up @@ -11,7 +11,7 @@ use euclid::{Point2D, Size2D};
use euclid::point::TypedPoint2D;
use euclid::scale_factor::ScaleFactor;
use euclid::size::TypedSize2D;
use gfx_traits::{DevicePixel, LayerPixel, StackingContextId};
use gfx_traits::{DevicePixel, LayerPixel, ScrollRootId};
use gfx_traits::{Epoch, FrameTreeId, FragmentType};
use gleam::gl;
use gleam::gl::types::{GLint, GLsizei};
Expand Down Expand Up @@ -74,13 +74,13 @@ impl ConvertPipelineIdFromWebRender for webrender_traits::PipelineId {
}
}

trait ConvertStackingContextFromWebRender {
fn from_webrender(&self) -> StackingContextId;
trait ConvertScrollRootIdFromWebRender {
fn from_webrender(&self) -> ScrollRootId;
}

impl ConvertStackingContextFromWebRender for webrender_traits::ServoStackingContextId {
fn from_webrender(&self) -> StackingContextId {
StackingContextId::new_of_type(self.1, self.0.from_webrender())
impl ConvertScrollRootIdFromWebRender for webrender_traits::ServoScrollRootId {
fn from_webrender(&self) -> ScrollRootId {
ScrollRootId(self.0)
}
}

Expand Down Expand Up @@ -1312,7 +1312,7 @@ impl<Window: WindowMethods> IOCompositor<Window> {
let mut stacking_context_scroll_states_per_pipeline = HashMap::new();
for scroll_layer_state in self.webrender_api.get_scroll_layer_state() {
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,
};
let pipeline_id = scroll_layer_state.pipeline_id;
Expand Down
18 changes: 10 additions & 8 deletions components/gfx/display_list/mod.rs
Expand Up @@ -20,7 +20,7 @@ use euclid::{Matrix4D, Point2D, Rect, Size2D};
use euclid::num::{One, Zero};
use euclid::rect::TypedRect;
use euclid::side_offsets::SideOffsets2D;
use gfx_traits::{ScrollPolicy, StackingContextId};
use gfx_traits::{ScrollPolicy, ScrollRootId, StackingContextId};
use gfx_traits::print_tree::PrintTree;
use ipc_channel::ipc::IpcSharedMemory;
use msg::constellation_msg::PipelineId;
Expand Down Expand Up @@ -215,9 +215,11 @@ impl DisplayList {
// the DOM-side code has already translated the point for us (e.g. in
// `Window::hit_test_query()`) by now.
if !is_fixed && stacking_context.id != StackingContextId::root() {
if let Some(scroll_offset) = scroll_offsets.get(&stacking_context.id) {
translated_point.x -= Au::from_f32_px(scroll_offset.x);
translated_point.y -= Au::from_f32_px(scroll_offset.y);
if let Some(scroll_root_id) = stacking_context.overflow_scroll_id {
if let Some(scroll_offset) = scroll_offsets.get(&scroll_root_id) {
translated_point.x -= Au::from_f32_px(scroll_offset.x);
translated_point.y -= Au::from_f32_px(scroll_offset.y);
}
}
}

Expand Down Expand Up @@ -386,7 +388,7 @@ pub struct StackingContext {
pub children: Vec<StackingContext>,

/// 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 {
Expand All @@ -403,7 +405,7 @@ impl StackingContext {
perspective: Matrix4D<f32>,
establishes_3d_context: bool,
scroll_policy: ScrollPolicy,
scroll_id: Option<StackingContextId>)
scroll_root_id: Option<ScrollRootId>)
-> StackingContext {
StackingContext {
id: id,
Expand All @@ -418,7 +420,7 @@ impl StackingContext {
establishes_3d_context: establishes_3d_context,
scroll_policy: scroll_policy,
children: Vec::new(),
overflow_scroll_id: scroll_id,
overflow_scroll_id: scroll_root_id,
}
}

Expand Down Expand Up @@ -1194,7 +1196,7 @@ impl WebRenderImageInfo {
}

/// 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 {
Expand Down
52 changes: 52 additions & 0 deletions components/gfx_traits/lib.rs
Expand Up @@ -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.
///
/// This can only ever grow to maximum 4 entries. That's because we cram the value of this enum
Expand Down
7 changes: 5 additions & 2 deletions components/layout/block.rs
Expand Up @@ -44,6 +44,7 @@ use flow_ref::FlowRef;
use fragment::{CoordinateSystem, Fragment, FragmentBorderBoxIterator, Overflow};
use fragment::SpecificFragmentInfo;
use gfx::display_list::{ClippingRegion, StackingContext};
use gfx_traits::ScrollRootId;
use gfx_traits::print_tree::PrintTree;
use layout_debug;
use model::{CollapsibleMargins, IntrinsicISizes, MarginCollapseInfo, MaybeAuto};
Expand Down Expand Up @@ -2162,8 +2163,10 @@ impl Flow for BlockFlow {
}
}

fn collect_stacking_contexts(&mut self, parent: &mut StackingContext) {
self.collect_stacking_contexts_for_block(parent);
fn collect_stacking_contexts(&mut self,
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) {
Expand Down
69 changes: 50 additions & 19 deletions components/layout/display_list_builder.rs
Expand Up @@ -28,7 +28,7 @@ use gfx::display_list::{GradientStop, IframeDisplayItem, ImageDisplayItem, WebGL
use gfx::display_list::{LineDisplayItem, OpaqueNode};
use gfx::display_list::{SolidColorDisplayItem, StackingContext, StackingContextType};
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 ipc_channel::ipc;
use list_item::ListItemFlow;
Expand Down Expand Up @@ -78,6 +78,7 @@ pub struct DisplayListBuildState<'a> {
pub shared_layout_context: &'a SharedLayoutContext,
pub items: Vec<DisplayItem>,
pub stacking_context_id_stack: Vec<StackingContextId>,
pub scroll_root_id_stack: Vec<ScrollRootId>,
}

impl<'a> DisplayListBuildState<'a> {
Expand All @@ -88,14 +89,15 @@ impl<'a> DisplayListBuildState<'a> {
shared_layout_context: shared_layout_context,
items: Vec::new(),
stacking_context_id_stack: vec!(stacking_context_id),
scroll_root_id_stack: vec!(ScrollRootId::root()),
}
}

fn add_display_item(&mut self, display_item: DisplayItem) {
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()
}

Expand All @@ -108,6 +110,19 @@ impl<'a> DisplayListBuildState<'a> {
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,
bounds: &Rect<Au>,
clip: &ClippingRegion,
Expand Down Expand Up @@ -299,7 +314,7 @@ pub trait FragmentDisplayListBuilding {
base_flow: &BaseFlow,
scroll_policy: ScrollPolicy,
mode: StackingContextCreationMode,
scroll_id: Option<StackingContextId>)
scroll_root_id: Option<ScrollRootId>)
-> StackingContext;

/// Returns the 4D matrix representing this fragment's transform.
Expand Down Expand Up @@ -1356,7 +1371,7 @@ impl FragmentDisplayListBuilding for Fragment {
base_flow: &BaseFlow,
scroll_policy: ScrollPolicy,
mode: StackingContextCreationMode,
scroll_id: Option<StackingContextId>)
scroll_root_id: Option<ScrollRootId>)
-> StackingContext {
let scrolls_overflow_area = mode == StackingContextCreationMode::ScrollWrapper;
let border_box =
Expand Down Expand Up @@ -1431,7 +1446,7 @@ impl FragmentDisplayListBuilding for Fragment {
perspective,
establishes_3d_context,
scroll_policy,
scroll_id)
scroll_root_id)
}

fn adjust_clipping_region_for_children(&self,
Expand Down Expand Up @@ -1687,7 +1702,9 @@ impl FragmentDisplayListBuilding for Fragment {
}

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,
state: &mut DisplayListBuildState,
border_painting_mode: BorderPaintingMode);
Expand All @@ -1704,17 +1721,29 @@ pub trait BlockFlowDisplayListBuilding {
}

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();
if block_stacking_context_type == BlockStackingContextType::NonstackingContext {
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;
}

let has_scrolling_overflow = self.has_scrolling_overflow();
let stacking_context_id = StackingContextId::new_of_type(self.fragment.node.id() as usize,
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;

if block_stacking_context_type == BlockStackingContextType::PseudoStackingContext {
Expand All @@ -1731,7 +1760,7 @@ impl BlockFlowDisplayListBuilding for BlockFlow {
ScrollPolicy::Scrollable,
creation_mode,
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 mut non_floating_children = Vec::new();
Expand All @@ -1755,10 +1784,7 @@ impl BlockFlowDisplayListBuilding for BlockFlow {
};

let (creation_mode, internal_id) = if has_scrolling_overflow {
(StackingContextCreationMode::ScrollWrapper,
Some(StackingContextId::new_of_type(self.fragment.node.id() as usize,
self.fragment.fragment_type())))

(StackingContextCreationMode::ScrollWrapper, Some(self.base.scroll_root_id))
} else {
(StackingContextCreationMode::Normal, None)
};
Expand All @@ -1769,7 +1795,7 @@ impl BlockFlowDisplayListBuilding for BlockFlow {
scroll_policy,
creation_mode,
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);
}
Expand Down Expand Up @@ -1859,26 +1885,31 @@ impl BlockFlowDisplayListBuilding for BlockFlow {
}

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,
state: &mut DisplayListBuildState,
index: usize);
fn build_display_list_for_inline(&mut self, state: &mut DisplayListBuildState);
}

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.scroll_root_id = parent_scroll_root_id;

for mut fragment in self.fragments.fragments.iter_mut() {
match fragment.specific {
SpecificFragmentInfo::InlineBlock(ref mut block_flow) => {
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) => {
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() => {
fragment.stacking_context_id =
Expand Down
7 changes: 5 additions & 2 deletions components/layout/flex.rs
Expand Up @@ -17,6 +17,7 @@ use flow::{Flow, FlowClass, ImmutableFlowUtils, OpaqueFlow};
use flow::{INLINE_POSITION_IS_STATIC, IS_ABSOLUTELY_POSITIONED};
use fragment::{Fragment, FragmentBorderBoxIterator, Overflow};
use gfx::display_list::StackingContext;
use gfx_traits::ScrollRootId;
use layout_debug;
use model::{Direction, IntrinsicISizes, MaybeAuto, MinMaxConstraint};
use model::{specified, specified_or_none};
Expand Down Expand Up @@ -956,8 +957,10 @@ impl Flow for FlexFlow {
self.build_display_list_for_flex(state);
}

fn collect_stacking_contexts(&mut self, parent: &mut StackingContext) {
self.block_flow.collect_stacking_contexts(parent);
fn collect_stacking_contexts(&mut self,
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>) {
Expand Down

0 comments on commit 71d285a

Please sign in to comment.