diff options
Diffstat (limited to 'components/gfx/display_list/mod.rs')
-rw-r--r-- | components/gfx/display_list/mod.rs | 137 |
1 files changed, 102 insertions, 35 deletions
diff --git a/components/gfx/display_list/mod.rs b/components/gfx/display_list/mod.rs index 99b1fc0b21c..ab8f1ba7a8f 100644 --- a/components/gfx/display_list/mod.rs +++ b/components/gfx/display_list/mod.rs @@ -81,7 +81,15 @@ impl DisplayList { scroll_offsets, result); } - &DisplayItem::PopStackingContext(_) => return, + &DisplayItem::PushScrollRoot(ref item) => { + self.hit_test_scroll_root(traversal, + &item.scroll_root, + *translated_point, + client_point, + scroll_offsets, + result); + } + &DisplayItem::PopStackingContext(_) | &DisplayItem::PopScrollRoot(_) => return, _ => { if let Some(meta) = item.hit_test(*translated_point) { result.push(meta); @@ -91,6 +99,26 @@ impl DisplayList { } } + fn hit_test_scroll_root<'a>(&self, + traversal: &mut DisplayListTraversal<'a>, + scroll_root: &ScrollRoot, + mut translated_point: Point2D<Au>, + client_point: &Point2D<Au>, + scroll_offsets: &ScrollOffsetMap, + result: &mut Vec<DisplayItemMetadata>) { + // Adjust the translated point to account for the scroll offset if + // necessary. This can only happen when WebRender is in use. + // + // We don't perform this adjustment on the root stacking context because + // the DOM-side code has already translated the point for us (e.g. in + // `Window::hit_test_query()`) by now. + 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); + } + self.hit_test_contents(traversal, &translated_point, client_point, scroll_offsets, result); + } + fn hit_test_stacking_context<'a>(&self, traversal: &mut DisplayListTraversal<'a>, stacking_context: &StackingContext, @@ -102,7 +130,7 @@ impl DisplayList { // stacking context isn't fixed. If it's fixed, we need to use the client point anyway. debug_assert!(stacking_context.context_type == StackingContextType::Real); let is_fixed = stacking_context.scroll_policy == ScrollPolicy::FixedPosition; - let mut translated_point = if is_fixed { + let translated_point = if is_fixed { *client_point } else { let point = *translated_point - stacking_context.bounds.origin; @@ -112,21 +140,6 @@ impl DisplayList { Point2D::new(Au::from_f32_px(frac_point.x), Au::from_f32_px(frac_point.y)) }; - // Adjust the translated point to account for the scroll offset if - // necessary. This can only happen when WebRender is in use. - // - // We don't perform this adjustment on the root stacking context because - // 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_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); - } - } - } - self.hit_test_contents(traversal, &translated_point, client_point, scroll_offsets, result); } @@ -138,9 +151,10 @@ impl DisplayList { pub fn print_with_tree(&self, print_tree: &mut PrintTree) { print_tree.new_level("Items".to_owned()); for item in &self.list { - print_tree.add_item(format!("{:?} StackingContext: {:?}", + print_tree.add_item(format!("{:?} StackingContext: {:?} ScrollRoot: {:?}", item, - item.base().stacking_context_id)); + item.base().stacking_context_id, + item.scroll_root_id())); } print_tree.end_level(); } @@ -250,6 +264,7 @@ pub enum StackingContextType { Real, PseudoPositioned, PseudoFloat, + PseudoScrollingArea, } #[derive(Clone, HeapSizeOf, Deserialize, Serialize)] @@ -291,8 +306,8 @@ pub struct StackingContext { /// Children of this StackingContext. pub children: Vec<StackingContext>, - /// If this StackingContext scrolls its overflow area, this will contain the id. - pub overflow_scroll_id: Option<ScrollRootId>, + /// The id of the parent scrolling area that contains this StackingContext. + pub parent_scroll_id: ScrollRootId, } impl StackingContext { @@ -309,7 +324,7 @@ impl StackingContext { perspective: Matrix4D<f32>, establishes_3d_context: bool, scroll_policy: ScrollPolicy, - scroll_root_id: Option<ScrollRootId>) + parent_scroll_id: ScrollRootId) -> StackingContext { StackingContext { id: id, @@ -324,7 +339,7 @@ impl StackingContext { establishes_3d_context: establishes_3d_context, scroll_policy: scroll_policy, children: Vec::new(), - overflow_scroll_id: scroll_root_id, + parent_scroll_id: parent_scroll_id, } } @@ -341,7 +356,7 @@ impl StackingContext { Matrix4D::identity(), true, ScrollPolicy::Scrollable, - None) + ScrollRootId::root()) } pub fn add_child(&mut self, mut child: StackingContext) { @@ -453,21 +468,40 @@ impl fmt::Debug for StackingContext { "Pseudo-StackingContext" }; - let scrollable_string = if self.overflow_scroll_id.is_some() { - " (scrolls overflow area)" - } else { - "" - }; - - write!(f, "{}{} at {:?} with overflow {:?}: {:?}", + write!(f, "{} at {:?} with overflow {:?}: {:?}", type_string, - scrollable_string, self.bounds, self.overflow, self.id) } } +/// Defines a stacking context. +#[derive(Clone, Debug, HeapSizeOf, Deserialize, Serialize)] +pub struct ScrollRoot { + /// The unique ID of this ScrollRoot. + pub id: ScrollRootId, + + /// The unique ID of the parent of this ScrollRoot. + pub parent_id: ScrollRootId, + + /// The position of this scroll root's frame in the parent stacking context. + pub clip: Rect<Au>, + + /// The size of the contents that can be scrolled inside of the scroll root. + pub size: Size2D<Au>, +} + +impl ScrollRoot { + pub fn to_push(&self) -> DisplayItem { + DisplayItem::PushScrollRoot(box PushScrollRootItem { + base: BaseDisplayItem::empty(), + scroll_root: self.clone(), + }) + } +} + + /// One drawing command in the list. #[derive(Clone, Deserialize, HeapSizeOf, Serialize)] pub enum DisplayItem { @@ -482,6 +516,8 @@ pub enum DisplayItem { Iframe(Box<IframeDisplayItem>), PushStackingContext(Box<PushStackingContextItem>), PopStackingContext(Box<PopStackingContextItem>), + PushScrollRoot(Box<PushScrollRootItem>), + PopScrollRoot(Box<BaseDisplayItem>), } /// Information common to all display items. @@ -501,6 +537,9 @@ pub struct BaseDisplayItem { /// The id of the stacking context this item belongs to. pub stacking_context_id: StackingContextId, + + /// The id of the scroll root this item belongs to. + pub scroll_root_id: ScrollRootId, } impl BaseDisplayItem { @@ -509,7 +548,8 @@ impl BaseDisplayItem { metadata: DisplayItemMetadata, clip: &ClippingRegion, section: DisplayListSection, - stacking_context_id: StackingContextId) + stacking_context_id: StackingContextId, + scroll_root_id: ScrollRootId) -> BaseDisplayItem { // Detect useless clipping regions here and optimize them to `ClippingRegion::max()`. // The painting backend may want to optimize out clipping regions and this makes it easier @@ -524,6 +564,7 @@ impl BaseDisplayItem { }, section: section, stacking_context_id: stacking_context_id, + scroll_root_id: scroll_root_id, } } @@ -538,6 +579,7 @@ impl BaseDisplayItem { clip: ClippingRegion::max(), section: DisplayListSection::Content, stacking_context_id: StackingContextId::root(), + scroll_root_id: ScrollRootId::root(), } } } @@ -981,6 +1023,15 @@ pub struct PopStackingContextItem { pub stacking_context_id: StackingContextId, } +/// Starts a group of items inside a particular scroll root. +#[derive(Clone, HeapSizeOf, Deserialize, Serialize)] +pub struct PushScrollRootItem { + /// Fields common to all display items. + pub base: BaseDisplayItem, + + /// The scroll root that this item starts. + pub scroll_root: ScrollRoot, +} /// How a box shadow should be clipped. #[derive(Clone, Copy, Debug, PartialEq, HeapSizeOf, Deserialize, Serialize)] @@ -1009,9 +1060,15 @@ impl DisplayItem { DisplayItem::Iframe(ref iframe) => &iframe.base, DisplayItem::PushStackingContext(ref stacking_context) => &stacking_context.base, DisplayItem::PopStackingContext(ref item) => &item.base, + DisplayItem::PushScrollRoot(ref item) => &item.base, + DisplayItem::PopScrollRoot(ref base) => &base, } } + pub fn scroll_root_id(&self) -> ScrollRootId { + self.base().scroll_root_id + } + pub fn stacking_context_id(&self) -> StackingContextId { self.base().stacking_context_id } @@ -1090,6 +1147,14 @@ impl fmt::Debug for DisplayItem { return write!(f, "PopStackingContext({:?}", item.stacking_context_id); } + if let DisplayItem::PushScrollRoot(ref item) = *self { + return write!(f, "PushScrollRoot({:?}", item.scroll_root); + } + + if let DisplayItem::PopScrollRoot(_) = *self { + return write!(f, "PopScrollRoot"); + } + write!(f, "{} @ {:?} {:?}", match *self { DisplayItem::SolidColor(ref solid_color) => @@ -1106,8 +1171,10 @@ impl fmt::Debug for DisplayItem { DisplayItem::Line(_) => "Line".to_owned(), DisplayItem::BoxShadow(_) => "BoxShadow".to_owned(), DisplayItem::Iframe(_) => "Iframe".to_owned(), - DisplayItem::PushStackingContext(_) => "".to_owned(), - DisplayItem::PopStackingContext(_) => "".to_owned(), + DisplayItem::PushStackingContext(_) | + DisplayItem::PopStackingContext(_) | + DisplayItem::PushScrollRoot(_) | + DisplayItem::PopScrollRoot(_) => "".to_owned(), }, self.bounds(), self.base().clip |