From 11822f3eb14ab3622f54652c77f2f3742d733961 Mon Sep 17 00:00:00 2001 From: Patrick Walton Date: Fri, 7 Aug 2015 18:06:16 -0700 Subject: [PATCH 1/6] layout: Remove the now-useless `dirty` field from the layout context. At this point the only thing it does is to try to avoid adding display items that are outside the root scrollable area, which is both wrong (since it's incompatible with having scrollable areas outside the root) and is useless (because we have displayports now). --- components/layout/context.rs | 3 --- components/layout/display_list_builder.rs | 9 +-------- components/layout/layout_task.rs | 8 -------- 3 files changed, 1 insertion(+), 19 deletions(-) diff --git a/components/layout/context.rs b/components/layout/context.rs index b2d80110f87..96fdc31beac 100644 --- a/components/layout/context.rs +++ b/components/layout/context.rs @@ -109,9 +109,6 @@ pub struct SharedLayoutContext { /// The URL. pub url: Url, - /// The dirty rectangle, used during display list building. - pub dirty: Rect, - /// Starts at zero, and increased by one every time a layout completes. /// This can be used to easily check for invalid stale data. pub generation: u32, diff --git a/components/layout/display_list_builder.rs b/components/layout/display_list_builder.rs index af143586513..e30a7d08635 100644 --- a/components/layout/display_list_builder.rs +++ b/components/layout/display_list_builder.rs @@ -900,11 +900,9 @@ impl FragmentDisplayListBuilding for Fragment { relative_containing_block_mode, CoordinateSystem::Own); - debug!("Fragment::build_display_list at rel={:?}, abs={:?}, dirty={:?}, flow origin={:?}: \ - {:?}", + debug!("Fragment::build_display_list at rel={:?}, abs={:?}, flow origin={:?}: {:?}", self.border_box, stacking_relative_border_box, - layout_context.shared.dirty, stacking_relative_flow_origin, self); @@ -913,11 +911,6 @@ impl FragmentDisplayListBuilding for Fragment { return } - if !stacking_relative_border_box.intersects(&layout_context.shared.dirty) { - debug!("Fragment::build_display_list: Did not intersect..."); - return - } - // Calculate the clip rect. If there's nothing to render at all, don't even construct // display list items. let clip = self.calculate_style_specified_clip(clip, &stacking_relative_border_box); diff --git a/components/layout/layout_task.rs b/components/layout/layout_task.rs index 38653037f6b..690b95edfa9 100644 --- a/components/layout/layout_task.rs +++ b/components/layout/layout_task.rs @@ -119,9 +119,6 @@ pub struct LayoutTaskData { /// The workers that we use for parallel operation. pub parallel_traversal: Option>, - /// The dirty rect. Used during display list construction. - pub dirty: Rect, - /// Starts at zero, and increased by one every time a layout completes. /// This can be used to easily check for invalid stale data. pub generation: u32, @@ -377,7 +374,6 @@ impl LayoutTask { stacking_context: None, stylist: stylist, parallel_traversal: parallel_traversal, - dirty: Rect::zero(), generation: 0, content_box_response: Rect::zero(), content_boxes_response: Vec::new(), @@ -421,7 +417,6 @@ impl LayoutTask { stylist: &*rw_data.stylist, url: (*url).clone(), reflow_root: reflow_root.map(|node| node.opaque()), - dirty: Rect::zero(), visible_rects: rw_data.visible_rects.clone(), generation: rw_data.generation, new_animations_sender: rw_data.new_animations_sender.clone(), @@ -1005,9 +1000,6 @@ impl LayoutTask { self.profiler_metadata(), self.time_profiler_chan.clone(), || { - shared_layout_context.dirty = - flow::base(&**layout_root).position.to_physical(writing_mode, - rw_data.screen_size); flow::mut_base(&mut **layout_root).stacking_relative_position = LogicalPoint::zero(writing_mode).to_physical(writing_mode, rw_data.screen_size); From fc13dd11698524b2b332ad4579fb377a8324248f Mon Sep 17 00:00:00 2001 From: Patrick Walton Date: Fri, 7 Aug 2015 18:08:08 -0700 Subject: [PATCH 2/6] compositor: Allow children of layers that don't want scroll events to be scrolled. Necessary for `overflow: scroll`. --- components/compositing/compositor_layer.rs | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/components/compositing/compositor_layer.rs b/components/compositing/compositor_layer.rs index 707b7ce06b6..302ac340f09 100644 --- a/components/compositing/compositor_layer.rs +++ b/components/compositing/compositor_layer.rs @@ -292,13 +292,7 @@ impl CompositorLayer for Layer { delta: TypedPoint2D, cursor: TypedPoint2D) -> ScrollEventResult { - // If this layer doesn't want scroll events, neither it nor its children can handle scroll - // events. - if self.wants_scroll_events() != WantsScrollEventsFlag::WantsScrollEvents { - return ScrollEventResult::ScrollEventUnhandled; - } - - //// Allow children to scroll. + // Allow children to scroll. let scroll_offset = self.extra_data.borrow().scroll_offset; let new_cursor = cursor - scroll_offset; for child in self.children().iter() { @@ -311,6 +305,11 @@ impl CompositorLayer for Layer { } } + // If this layer doesn't want scroll events, it can't handle scroll events. + if self.wants_scroll_events() != WantsScrollEventsFlag::WantsScrollEvents { + return ScrollEventResult::ScrollEventUnhandled; + } + self.clamp_scroll_offset_and_scroll_layer(scroll_offset + delta) } From df4acbac0424514ecbcdf0212e44ab4ae39a7387 Mon Sep 17 00:00:00 2001 From: Patrick Walton Date: Fri, 7 Aug 2015 18:10:48 -0700 Subject: [PATCH 3/6] layout: Implement basic `overflow: scroll` functionality. Known issues: * Display list optimization can sometimes optimize out elements that should be shown. This affects the Enyo demo. * The `overflow: scroll` container doesn't clip the inner layer properly when borders, border radius, etc. are present. * `overflow-x: scroll` and `overflow-y: scroll` don't work individually; elements are scrolled all at once. * Scrolling only works on absolutely-positioned elements. --- components/compositing/compositor.rs | 14 +- components/gfx/display_list/mod.rs | 7 +- components/gfx/paint_task.rs | 27 ++- components/layout/block.rs | 17 +- components/layout/display_list_builder.rs | 220 +++++++++++++++++----- components/layout/inline.rs | 3 +- components/layout/layout_task.rs | 3 +- components/msg/compositor_msg.rs | 2 + 8 files changed, 221 insertions(+), 72 deletions(-) diff --git a/components/compositing/compositor.rs b/components/compositing/compositor.rs index cfa5f68a4e0..3c4b5419303 100644 --- a/components/compositing/compositor.rs +++ b/components/compositing/compositor.rs @@ -629,6 +629,7 @@ impl IOCompositor { transform: Matrix4::identity(), perspective: Matrix4::identity(), establishes_3d_context: true, + scrolls_overflow_area: false, }; let root_layer = CompositorData::new_layer(pipeline.id, @@ -740,10 +741,21 @@ impl IOCompositor { if let Some(parent_layer) = self.find_layer_with_pipeline_and_layer_id(pipeline_id, parent_id) { + let wants_scroll_events = if layer_properties.scrolls_overflow_area { + WantsScrollEventsFlag::WantsScrollEvents + } else { + WantsScrollEventsFlag::DoesntWantScrollEvents + }; + let new_layer = CompositorData::new_layer(pipeline_id, layer_properties, - WantsScrollEventsFlag::DoesntWantScrollEvents, + wants_scroll_events, parent_layer.tile_size); + + if layer_properties.scrolls_overflow_area { + *new_layer.masks_to_bounds.borrow_mut() = true + } + parent_layer.add_child(new_layer); } } diff --git a/components/gfx/display_list/mod.rs b/components/gfx/display_list/mod.rs index eda83adf795..6f2ebed0851 100644 --- a/components/gfx/display_list/mod.rs +++ b/components/gfx/display_list/mod.rs @@ -252,6 +252,9 @@ pub struct StackingContext { /// Whether this stacking context creates a new 3d rendering context. pub establishes_3d_context: bool, + + /// Whether this stacking context scrolls its overflow area. + pub scrolls_overflow_area: bool, } impl StackingContext { @@ -266,7 +269,8 @@ impl StackingContext { layer: Option, transform: Matrix4, perspective: Matrix4, - establishes_3d_context: bool) + establishes_3d_context: bool, + scrolls_overflow_area: bool) -> StackingContext { StackingContext { display_list: display_list, @@ -279,6 +283,7 @@ impl StackingContext { transform: transform, perspective: perspective, establishes_3d_context: establishes_3d_context, + scrolls_overflow_area: scrolls_overflow_area, } } diff --git a/components/gfx/paint_task.rs b/components/gfx/paint_task.rs index ebe86de75e6..e386ea011ad 100644 --- a/components/gfx/paint_task.rs +++ b/components/gfx/paint_task.rs @@ -342,29 +342,27 @@ impl PaintTask where C: PaintListener + Send + 'static { transform: &Matrix4, perspective: &Matrix4, parent_id: Option) { - let transform = transform.mul(&stacking_context.transform); let perspective = perspective.mul(&stacking_context.perspective); let (next_parent_id, page_position, transform, perspective) = match stacking_context.layer { Some(ref paint_layer) => { - // Layers start at the top left of their overflow rect, as far as the info we - // give to the compositor is concerned. + let overflow_size = + Size2D::new(stacking_context.overflow.size.width.to_nearest_px() as f32, + stacking_context.overflow.size.height.to_nearest_px() as f32); + let establishes_3d_context = stacking_context.establishes_3d_context; + let scrolls_overflow_area = stacking_context.scrolls_overflow_area; + + // Layers start at the top left of their overflow rect, as far as the info + // we give to the compositor is concerned. let overflow_relative_page_position = *page_position + stacking_context.bounds.origin + stacking_context.overflow.origin; - let layer_position = - Rect::new(Point2D::new(overflow_relative_page_position.x.to_nearest_px() as - f32, - overflow_relative_page_position.y.to_nearest_px() as - f32), - Size2D::new(stacking_context.overflow.size.width.to_nearest_px() - as f32, - stacking_context.overflow.size.height.to_nearest_px() - as f32)); - - let establishes_3d_context = stacking_context.establishes_3d_context; + let layer_position = Rect::new( + Point2D::new(overflow_relative_page_position.x.to_nearest_px() as f32, + overflow_relative_page_position.y.to_nearest_px() as f32), + overflow_size); properties.push(LayerProperties { id: paint_layer.id, @@ -375,6 +373,7 @@ impl PaintTask where C: PaintListener + Send + 'static { transform: transform, perspective: perspective, establishes_3d_context: establishes_3d_context, + scrolls_overflow_area: scrolls_overflow_area, }); // When there is a new layer, the transforms and origin diff --git a/components/layout/block.rs b/components/layout/block.rs index c8f960dc7cc..e044c04d3c0 100644 --- a/components/layout/block.rs +++ b/components/layout/block.rs @@ -1756,6 +1756,17 @@ impl Flow for BlockFlow { } if self.base.flags.contains(IS_ABSOLUTELY_POSITIONED) { + // `overflow: auto` and `overflow: scroll` force creation of layers, since we can only + // scroll layers. + match (self.fragment.style().get_box().overflow_x, + self.fragment.style().get_box().overflow_y.0) { + (overflow_x::T::auto, _) | (overflow_x::T::scroll, _) | + (_, overflow_x::T::auto) | (_, overflow_x::T::scroll) => { + self.base.flags.insert(NEEDS_LAYER); + } + _ => {} + } + let position_start = self.base.position.start.to_physical(self.base.writing_mode, container_size); @@ -1892,8 +1903,10 @@ impl Flow for BlockFlow { .absolute_position_info .relative_containing_block_mode, CoordinateSystem::Own); - let clip = self.fragment.clipping_region_for_children(&clip_in_child_coordinate_system, - &stacking_relative_border_box); + let clip = self.fragment.clipping_region_for_children( + &clip_in_child_coordinate_system, + &stacking_relative_border_box, + self.base.flags.contains(IS_ABSOLUTELY_POSITIONED)); // Process children. for kid in self.base.child_iter() { diff --git a/components/layout/display_list_builder.rs b/components/layout/display_list_builder.rs index e30a7d08635..00dbb8b2570 100644 --- a/components/layout/display_list_builder.rs +++ b/components/layout/display_list_builder.rs @@ -62,6 +62,11 @@ use util::geometry::{Au, ZERO_POINT}; use util::logical_geometry::{LogicalPoint, LogicalRect, LogicalSize, WritingMode}; use util::opts; +/// The fake fragment ID we use to indicate the inner display list for `overflow: scroll`. +/// +/// FIXME(pcwalton): This is pretty ugly. Consider modifying `LayerId` somehow. +const FAKE_FRAGMENT_ID_FOR_OVERFLOW_SCROLL: u32 = 1000000; + /// A possible `PaintLayer` for an stacking context pub enum StackingContextLayer { Existing(PaintLayer), @@ -208,10 +213,11 @@ pub trait FragmentDisplayListBuilding { offset: Point2D, layout_context: &LayoutContext); - /// Returns the appropriate clipping region for descendants of this flow. + /// Returns the appropriate clipping region for descendants of this fragment. fn clipping_region_for_children(&self, current_clip: &ClippingRegion, - stacking_relative_border_box: &Rect) + stacking_relative_border_box: &Rect, + is_absolutely_positioned: bool) -> ClippingRegion; /// Calculates the clipping rectangle for a fragment, taking the `clip` property into account @@ -253,7 +259,8 @@ pub trait FragmentDisplayListBuilding { base_flow: &BaseFlow, display_list: Box, layout_context: &LayoutContext, - layer: StackingContextLayer) + layer: StackingContextLayer, + mode: StackingContextCreationMode) -> Arc; } @@ -1129,17 +1136,37 @@ impl FragmentDisplayListBuilding for Fragment { base_flow: &BaseFlow, display_list: Box, layout_context: &LayoutContext, - layer: StackingContextLayer) + layer: StackingContextLayer, + mode: StackingContextCreationMode) -> Arc { - let border_box = self.stacking_relative_border_box(&base_flow.stacking_relative_position, - &base_flow.absolute_position_info - .relative_containing_block_size, - base_flow.absolute_position_info - .relative_containing_block_mode, - CoordinateSystem::Parent); + // FIXME(pcwalton): Is this vertical-writing-direction-safe? + let margin = self.margin.to_physical(base_flow.writing_mode); + + let border_box = match mode { + StackingContextCreationMode::Normal | + StackingContextCreationMode::OuterScrollWrapper => { + self.stacking_relative_border_box(&base_flow.stacking_relative_position, + &base_flow.absolute_position_info + .relative_containing_block_size, + base_flow.absolute_position_info + .relative_containing_block_mode, + CoordinateSystem::Parent) + } + StackingContextCreationMode::InnerScrollWrapper => { + Rect::new(ZERO_POINT, base_flow.overflow.size) + } + }; + let overflow = match mode { + StackingContextCreationMode::Normal => { + base_flow.overflow.translate(&-Point2D::new(margin.left, Au(0))) + } + StackingContextCreationMode::InnerScrollWrapper | + StackingContextCreationMode::OuterScrollWrapper => { + Rect::new(ZERO_POINT, border_box.size) + } + }; let mut transform = Matrix4::identity(); - if let Some(ref operations) = self.style().get_effects().transform.0 { let transform_origin = self.style().get_effects().transform_origin; let transform_origin = @@ -1213,10 +1240,6 @@ impl FragmentDisplayListBuilding for Fragment { } }; - // FIXME(pcwalton): Is this vertical-writing-direction-safe? - let margin = self.margin.to_physical(base_flow.writing_mode); - let overflow = base_flow.overflow.translate(&-Point2D::new(margin.left, Au(0))); - // Create the filter pipeline. let effects = self.style().get_effects(); let mut filters = effects.filter.clone(); @@ -1247,7 +1270,10 @@ impl FragmentDisplayListBuilding for Fragment { } } + let scrolls_overflow_area = mode == StackingContextCreationMode::OuterScrollWrapper; let transform_style = self.style().get_used_transform_style(); + let establishes_3d_context = scrolls_overflow_area || + transform_style == transform_style::T::flat; Arc::new(StackingContext::new(display_list, &border_box, @@ -1258,7 +1284,8 @@ impl FragmentDisplayListBuilding for Fragment { layer, transform, perspective, - transform_style == transform_style::T::flat)) + establishes_3d_context, + scrolls_overflow_area)) } #[inline(never)] @@ -1284,7 +1311,8 @@ impl FragmentDisplayListBuilding for Fragment { fn clipping_region_for_children(&self, current_clip: &ClippingRegion, - stacking_relative_border_box: &Rect) + stacking_relative_border_box: &Rect, + is_absolutely_positioned: bool) -> ClippingRegion { // Don't clip if we're text. if self.is_scanned_text_fragment() { @@ -1297,12 +1325,14 @@ impl FragmentDisplayListBuilding for Fragment { // Clip according to the values of `overflow-x` and `overflow-y`. // - // TODO(pcwalton): Support scrolling. + // TODO(pcwalton): Support scrolling of non-absolutely-positioned elements. // FIXME(pcwalton): This may be more complex than it needs to be, since it seems to be // impossible with the computed value rules as they are to have `overflow-x: visible` with // `overflow-y: ` or vice versa! - match self.style.get_box().overflow_x { - overflow_x::T::hidden | overflow_x::T::auto | overflow_x::T::scroll => { + match (self.style.get_box().overflow_x, is_absolutely_positioned) { + (overflow_x::T::hidden, _) | + (overflow_x::T::auto, false) | + (overflow_x::T::scroll, false) => { let mut bounds = current_clip.bounding_rect(); let max_x = cmp::min(bounds.max_x(), stacking_relative_border_box.max_x()); bounds.origin.x = cmp::max(bounds.origin.x, stacking_relative_border_box.origin.x); @@ -1311,8 +1341,10 @@ impl FragmentDisplayListBuilding for Fragment { } _ => {} } - match self.style.get_box().overflow_y.0 { - overflow_x::T::hidden | overflow_x::T::auto | overflow_x::T::scroll => { + match (self.style.get_box().overflow_y.0, is_absolutely_positioned) { + (overflow_x::T::hidden, _) | + (overflow_x::T::auto, false) | + (overflow_x::T::scroll, false) => { let mut bounds = current_clip.bounding_rect(); let max_y = cmp::min(bounds.max_y(), stacking_relative_border_box.max_y()); bounds.origin.y = cmp::max(bounds.origin.y, stacking_relative_border_box.origin.y); @@ -1527,17 +1559,21 @@ impl BlockFlowDisplayListBuilding for BlockFlow { let paint_layer = PaintLayer::new(self.layer_id(0), color::transparent(), scroll_policy); let layer = StackingContextLayer::Existing(paint_layer); - let stacking_context = self.fragment.create_stacking_context(&self.base, - display_list, - layout_context, - layer); + let stacking_context = self.fragment.create_stacking_context( + &self.base, + display_list, + layout_context, + layer, + StackingContextCreationMode::Normal); DisplayListBuildingResult::StackingContext(stacking_context) } else { DisplayListBuildingResult::StackingContext( - self.fragment.create_stacking_context(&self.base, - display_list, - layout_context, - StackingContextLayer::IfCanvas(self.layer_id(0)))) + self.fragment.create_stacking_context( + &self.base, + display_list, + layout_context, + StackingContextLayer::IfCanvas(self.layer_id(0)), + StackingContextCreationMode::Normal)) } } else { match self.fragment.style.get_box().position { @@ -1560,19 +1596,57 @@ impl BlockFlowDisplayListBuilding for BlockFlow { mut display_list: Box, layout_context: &LayoutContext, border_painting_mode: BorderPaintingMode) { - self.build_display_list_for_block_base(&mut *display_list, - layout_context, - border_painting_mode, - BackgroundAndBorderLevel::RootOfStackingContext); + // If `overflow: scroll` is in effect, we add this fragment's display items to a new + // stacking context. + let outer_display_list_for_overflow_scroll = + match (self.fragment.style().get_box().overflow_x, + self.fragment.style().get_box().overflow_y.0) { + (overflow_x::T::auto, _) | + (overflow_x::T::scroll, _) | + (_, overflow_x::T::auto) | + (_, overflow_x::T::scroll) => { + // Create a separate display list for our own fragment. + let mut outer_display_list_for_overflow_scroll = box DisplayList::new(); + let clip = self.base.clip.translate(&-self.base.stacking_relative_position); + self.fragment.build_display_list( + &mut outer_display_list_for_overflow_scroll, + layout_context, + &self.base.stacking_relative_position, + &self.base.absolute_position_info.relative_containing_block_size, + self.base.absolute_position_info.relative_containing_block_mode, + border_painting_mode, + BackgroundAndBorderLevel::RootOfStackingContext, + &clip, + &self.base.stacking_relative_position_of_display_port); + + // Add the fragments of our children to the display list we'll use for the inner + // stacking context. + for kid in self.base.children.iter_mut() { + flow::mut_base(kid).display_list_building_result.add_to(&mut *display_list); + } + + Some(outer_display_list_for_overflow_scroll) + } + _ => { + self.build_display_list_for_block_base( + &mut *display_list, + layout_context, + border_painting_mode, + BackgroundAndBorderLevel::RootOfStackingContext); + None + } + }; if !self.will_get_layer() { // We didn't need a layer. self.base.display_list_building_result = DisplayListBuildingResult::StackingContext( - self.fragment.create_stacking_context(&self.base, - display_list, - layout_context, - StackingContextLayer::IfCanvas(self.layer_id(0)))); + self.fragment.create_stacking_context( + &self.base, + display_list, + layout_context, + StackingContextLayer::IfCanvas(self.layer_id(0)), + StackingContextCreationMode::Normal)); return } @@ -1583,13 +1657,44 @@ impl BlockFlowDisplayListBuilding for BlockFlow { ScrollPolicy::Scrollable }; - let paint_layer = PaintLayer::new(self.layer_id(0), color::transparent(), scroll_policy); - let stacking_context = self.fragment.create_stacking_context(&self.base, - display_list, - layout_context, - StackingContextLayer::Existing(paint_layer)); + let stacking_context_creation_mode = if outer_display_list_for_overflow_scroll.is_some() { + StackingContextCreationMode::InnerScrollWrapper + } else { + StackingContextCreationMode::Normal + }; + + let layer_id = if outer_display_list_for_overflow_scroll.is_some() { + self.layer_id(FAKE_FRAGMENT_ID_FOR_OVERFLOW_SCROLL) + } else { + self.layer_id(0) + }; + let paint_layer = PaintLayer::new(layer_id, color::transparent(), scroll_policy); + let stacking_context = self.fragment.create_stacking_context( + &self.base, + display_list, + layout_context, + StackingContextLayer::Existing(paint_layer), + stacking_context_creation_mode); + + let outermost_stacking_context = match outer_display_list_for_overflow_scroll { + Some(mut outer_display_list_for_overflow_scroll) => { + outer_display_list_for_overflow_scroll.children.push_back(stacking_context); + + let paint_layer = PaintLayer::new(self.layer_id(0), + color::transparent(), + scroll_policy); + self.fragment.create_stacking_context( + &self.base, + outer_display_list_for_overflow_scroll, + layout_context, + StackingContextLayer::Existing(paint_layer), + StackingContextCreationMode::OuterScrollWrapper) + } + None => stacking_context, + }; + self.base.display_list_building_result = - DisplayListBuildingResult::StackingContext(stacking_context) + DisplayListBuildingResult::StackingContext(outermost_stacking_context) } fn build_display_list_for_floating_block(&mut self, @@ -1604,10 +1709,12 @@ impl BlockFlowDisplayListBuilding for BlockFlow { self.base.display_list_building_result = if self.fragment.establishes_stacking_context() { DisplayListBuildingResult::StackingContext( - self.fragment.create_stacking_context(&self.base, - display_list, - layout_context, - StackingContextLayer::IfCanvas(self.layer_id(0)))) + self.fragment.create_stacking_context( + &self.base, + display_list, + layout_context, + StackingContextLayer::IfCanvas(self.layer_id(0)), + StackingContextCreationMode::Normal)) } else { DisplayListBuildingResult::Normal(display_list) } @@ -1702,10 +1809,12 @@ impl InlineFlowDisplayListBuilding for InlineFlow { self.base.display_list_building_result = if has_stacking_context { DisplayListBuildingResult::StackingContext( - self.fragments.fragments[0].create_stacking_context(&self.base, - display_list, - layout_context, - StackingContextLayer::IfCanvas(self.layer_id(0)))) + self.fragments.fragments[0].create_stacking_context( + &self.base, + display_list, + layout_context, + StackingContextLayer::IfCanvas(self.layer_id(0)), + StackingContextCreationMode::Normal)) } else { DisplayListBuildingResult::Normal(display_list) }; @@ -1895,3 +2004,10 @@ pub enum BorderPaintingMode<'a> { Hidden, } +#[derive(Copy, Clone, PartialEq)] +pub enum StackingContextCreationMode { + Normal, + OuterScrollWrapper, + InnerScrollWrapper, +} + diff --git a/components/layout/inline.rs b/components/layout/inline.rs index b293478656e..359660e05ed 100644 --- a/components/layout/inline.rs +++ b/components/layout/inline.rs @@ -1627,7 +1627,8 @@ impl Flow for InlineFlow { .relative_containing_block_mode, CoordinateSystem::Parent); let clip = fragment.clipping_region_for_children(&self.base.clip, - &stacking_relative_border_box); + &stacking_relative_border_box, + false); match fragment.specific { SpecificFragmentInfo::InlineBlock(ref mut info) => { flow::mut_base(&mut *info.flow_ref).clip = clip; diff --git a/components/layout/layout_task.rs b/components/layout/layout_task.rs index 690b95edfa9..76baafc8013 100644 --- a/components/layout/layout_task.rs +++ b/components/layout/layout_task.rs @@ -1046,7 +1046,8 @@ impl LayoutTask { Some(paint_layer), Matrix4::identity(), Matrix4::identity(), - true)); + true, + false)); if opts::get().dump_display_list { println!("#### start printing display list."); diff --git a/components/msg/compositor_msg.rs b/components/msg/compositor_msg.rs index a3e42af041d..59a3ed3f3df 100644 --- a/components/msg/compositor_msg.rs +++ b/components/msg/compositor_msg.rs @@ -88,6 +88,8 @@ pub struct LayerProperties { pub perspective: Matrix4, /// Whether this layer establishes a new 3d rendering context. pub establishes_3d_context: bool, + /// Whether this layer scrolls its overflow area. + pub scrolls_overflow_area: bool, } /// The interface used by the painter to acquire draw targets for each paint frame and From 300315bb78e611b23370364c8acdeda1dd719a6c Mon Sep 17 00:00:00 2001 From: Patrick Walton Date: Fri, 7 Aug 2015 18:14:56 -0700 Subject: [PATCH 4/6] compositing: Add some layer tree debugging infrastructure. --- components/compositing/compositor.rs | 27 ++++++++++++++++++++++ components/compositing/compositor_layer.rs | 3 ++- components/msg/compositor_msg.rs | 2 +- 3 files changed, 30 insertions(+), 2 deletions(-) diff --git a/components/compositing/compositor.rs b/components/compositing/compositor.rs index 3c4b5419303..60ca0a717c3 100644 --- a/components/compositing/compositor.rs +++ b/components/compositing/compositor.rs @@ -1622,6 +1622,33 @@ impl IOCompositor { self.surface_map.insert_surfaces(&self.native_display, surfaces); } } + + #[allow(dead_code)] + fn dump_layer_tree(&self) { + if let Some(ref layer) = self.scene.root { + println!("Layer tree:"); + self.dump_layer_tree_with_indent(&**layer, 0); + } + } + + #[allow(dead_code)] + fn dump_layer_tree_with_indent(&self, layer: &Layer, level: u32) { + let mut indentation = String::new(); + for _ in 0..level { + indentation.push_str(" "); + } + + println!("{}Layer {:x}: {:?} @ {:?} masks to bounds: {:?} establishes 3D context: {:?}", + indentation, + layer as *const _ as usize, + layer.extra_data, + *layer.bounds.borrow(), + *layer.masks_to_bounds.borrow(), + layer.establishes_3d_context); + for kid in layer.children().iter() { + self.dump_layer_tree_with_indent(&**kid, level + 1) + } + } } fn find_layer_with_pipeline_and_layer_id_for_layer(layer: Rc>, diff --git a/components/compositing/compositor_layer.rs b/components/compositing/compositor_layer.rs index 302ac340f09..71a21b0c9ba 100644 --- a/components/compositing/compositor_layer.rs +++ b/components/compositing/compositor_layer.rs @@ -19,6 +19,7 @@ use msg::compositor_msg::{Epoch, LayerId, LayerProperties, ScrollPolicy}; use msg::constellation_msg::PipelineId; use std::rc::Rc; +#[derive(Debug)] pub struct CompositorData { /// This layer's pipeline id. The compositor can associate this id with an /// actual CompositionPipeline. @@ -143,7 +144,7 @@ pub trait CompositorLayer { fn pipeline_id(&self) -> PipelineId; } -#[derive(Copy, PartialEq, Clone)] +#[derive(Copy, PartialEq, Clone, Debug)] pub enum WantsScrollEventsFlag { WantsScrollEvents, DoesntWantScrollEvents, diff --git a/components/msg/compositor_msg.rs b/components/msg/compositor_msg.rs index 59a3ed3f3df..2d29256f092 100644 --- a/components/msg/compositor_msg.rs +++ b/components/msg/compositor_msg.rs @@ -60,7 +60,7 @@ pub enum LayerKind { } /// The scrolling policy of a layer. -#[derive(Clone, PartialEq, Eq, Copy, Deserialize, Serialize)] +#[derive(Clone, PartialEq, Eq, Copy, Deserialize, Serialize, Debug)] pub enum ScrollPolicy { /// These layers scroll when the parent receives a scrolling message. Scrollable, From bf26a2373f297f4b34347c0c12e406361dfff7f3 Mon Sep 17 00:00:00 2001 From: Patrick Walton Date: Fri, 7 Aug 2015 18:15:39 -0700 Subject: [PATCH 5/6] layout: Carry out some minor style cleanups. --- components/compositing/compositor.rs | 11 +++++++---- components/gfx/paint_task.rs | 4 +++- components/layout/display_list_builder.rs | 15 +++++++++------ 3 files changed, 19 insertions(+), 11 deletions(-) diff --git a/components/compositing/compositor.rs b/components/compositing/compositor.rs index 60ca0a717c3..5dfe85a4390 100644 --- a/components/compositing/compositor.rs +++ b/components/compositing/compositor.rs @@ -255,13 +255,13 @@ impl IOCompositor { time_profiler_chan: time::ProfilerChan, mem_profiler_chan: mem::ProfilerChan) -> IOCompositor { - // Register this thread as a memory reporter, via its own channel. let (reporter_sender, reporter_receiver) = ipc::channel().unwrap(); let compositor_proxy_for_memory_reporter = sender.clone_compositor_proxy(); ROUTER.add_route(reporter_receiver.to_opaque(), box move |reporter_request| { let reporter_request: ReporterRequest = reporter_request.to().unwrap(); - compositor_proxy_for_memory_reporter.send(Msg::CollectMemoryReports(reporter_request.reports_channel)); + compositor_proxy_for_memory_reporter.send(Msg::CollectMemoryReports( + reporter_request.reports_channel)); }); let reporter = Reporter(reporter_sender); mem_profiler_chan.send(mem::ProfilerMsg::RegisterReporter(reporter_name(), reporter)); @@ -376,7 +376,8 @@ impl IOCompositor { self.get_title_for_main_frame(); } - (Msg::InitializeLayersForPipeline(pipeline_id, epoch, properties), ShutdownState::NotShuttingDown) => { + (Msg::InitializeLayersForPipeline(pipeline_id, epoch, properties), + ShutdownState::NotShuttingDown) => { self.get_or_create_pipeline_details(pipeline_id).current_epoch = epoch; for (index, layer_properties) in properties.iter().enumerate() { if index == 0 { @@ -692,7 +693,9 @@ impl IOCompositor { } } - fn create_or_update_base_layer(&mut self, pipeline_id: PipelineId, layer_properties: LayerProperties) { + fn create_or_update_base_layer(&mut self, + pipeline_id: PipelineId, + layer_properties: LayerProperties) { debug_assert!(layer_properties.parent_id.is_none()); let root_layer = match self.find_pipeline_root_layer(pipeline_id) { diff --git a/components/gfx/paint_task.rs b/components/gfx/paint_task.rs index e386ea011ad..9b893160424 100644 --- a/components/gfx/paint_task.rs +++ b/components/gfx/paint_task.rs @@ -334,7 +334,9 @@ impl PaintTask where C: PaintListener + Send + 'static { &Matrix4::identity(), &Matrix4::identity(), None); - self.compositor.initialize_layers_for_pipeline(self.id, properties, self.current_epoch.unwrap()); + self.compositor.initialize_layers_for_pipeline(self.id, + properties, + self.current_epoch.unwrap()); fn build(properties: &mut Vec, stacking_context: &StackingContext, diff --git a/components/layout/display_list_builder.rs b/components/layout/display_list_builder.rs index 00dbb8b2570..4e86f880768 100644 --- a/components/layout/display_list_builder.rs +++ b/components/layout/display_list_builder.rs @@ -477,7 +477,7 @@ impl FragmentDisplayListBuilding for Fragment { (-border.left, -border.top) } background_origin::T::content_box => { - let border_padding = (self.border_padding).to_physical(self.style.writing_mode); + let border_padding = self.border_padding.to_physical(self.style.writing_mode); (border_padding.left - border.left, border_padding.top - border.top) } }; @@ -676,10 +676,11 @@ impl FragmentDisplayListBuilding for Fragment { clip: &ClippingRegion) { // NB: According to CSS-BACKGROUNDS, box shadows render in *reverse* order (front to back). for box_shadow in style.get_effects().box_shadow.0.iter().rev() { - let bounds = shadow_bounds(&absolute_bounds.translate(&Point2D::new(box_shadow.offset_x, - box_shadow.offset_y)), - box_shadow.blur_radius, - box_shadow.spread_radius); + let bounds = + shadow_bounds(&absolute_bounds.translate(&Point2D::new(box_shadow.offset_x, + box_shadow.offset_y)), + box_shadow.blur_radius, + box_shadow.spread_radius); list.push(DisplayItem::BoxShadowClass(box BoxShadowDisplayItem { base: BaseDisplayItem::new(bounds, DisplayItemMetadata::new(self.node, @@ -1557,7 +1558,9 @@ impl BlockFlowDisplayListBuilding for BlockFlow { ScrollPolicy::Scrollable }; - let paint_layer = PaintLayer::new(self.layer_id(0), color::transparent(), scroll_policy); + let paint_layer = PaintLayer::new(self.layer_id(0), + color::transparent(), + scroll_policy); let layer = StackingContextLayer::Existing(paint_layer); let stacking_context = self.fragment.create_stacking_context( &self.base, From dd7345ad641c9d1f14e60582050e508edd602d66 Mon Sep 17 00:00:00 2001 From: Patrick Walton Date: Fri, 7 Aug 2015 18:16:42 -0700 Subject: [PATCH 6/6] tests: Add a simple test case for `overflow: scroll`. --- tests/html/simple-overflow-scroll.html | 30 ++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 tests/html/simple-overflow-scroll.html diff --git a/tests/html/simple-overflow-scroll.html b/tests/html/simple-overflow-scroll.html new file mode 100644 index 00000000000..0df956eb905 --- /dev/null +++ b/tests/html/simple-overflow-scroll.html @@ -0,0 +1,30 @@ + +
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc ultricies tortor eu augue eleifend malesuada. Duis id condimentum urna. Duis vulputate urna a dignissim sodales. Aenean et magna id dui rutrum suscipit. Etiam metus mauris, congue ac suscipit dapibus, mattis non neque. Donec porttitor eros sed mauris tristique, non condimentum augue feugiat. Suspendisse iaculis faucibus nunc at porttitor. Integer convallis enim in feugiat molestie. Ut eget tincidunt mi, vel malesuada lectus. Quisque fermentum neque a sapien interdum consectetur. Nam tincidunt leo sit amet tortor ornare, sit amet ultrices ante semper. Fusce malesuada mi vitae venenatis sagittis. Duis eget urna quam. + +Sed lacinia aliquam tortor quis elementum. Cras vitae mauris erat. Vestibulum posuere justo et dolor condimentum feugiat. Sed at magna nunc. Suspendisse est nunc, ultrices sed enim lobortis, vulputate rutrum mauris. Fusce ultrices eget erat blandit porta. Sed eros nulla, tristique eget porta a, viverra vel velit. Praesent sit amet odio eleifend, tempor arcu ut, elementum tellus. Suspendisse lorem tortor, sodales eget nulla a, rhoncus lobortis magna. Phasellus purus ante, rhoncus a ipsum nec, condimentum lacinia purus. Cras lobortis posuere nisi, vitae dapibus ante feugiat et. Quisque ornare nisi quis erat congue viverra. Vestibulum a nunc odio. + +Sed id venenatis tortor. Curabitur sit amet mauris eget mi semper rutrum vel et odio. Phasellus eu sapien in sem ultricies pretium eu sit amet magna. Nulla finibus nec lorem ac semper. Nulla eleifend eros id fringilla pellentesque. Proin eleifend, sem vel lobortis viverra, massa augue viverra felis, quis ultricies sapien ipsum at magna. Duis rutrum tempus lobortis. Aliquam quis nulla eget velit viverra pretium. Maecenas venenatis nec nisl at pulvinar. Duis in sodales lectus, ac porta augue. + +Sed sed ante aliquam, rutrum nisl quis, fermentum tellus. Proin ac leo molestie, euismod mauris sed, consequat nunc. Vivamus ut leo a nunc pharetra accumsan a non lorem. Aliquam iaculis mattis augue, in eleifend est accumsan vel. Pellentesque efficitur pulvinar leo vel ornare. Pellentesque non fermentum enim, ut efficitur elit. Duis risus quam, congue vel nulla a, blandit egestas erat. Suspendisse at sodales dolor. Vivamus auctor, lorem et ultrices venenatis, erat ex mollis nisi, quis maximus libero quam a libero. + +Curabitur elit lacus, bibendum non tempus a, bibendum sit amet ante. Mauris eget nibh quis leo rhoncus consequat. Integer iaculis sed sapien eu pellentesque. In aliquet elementum lorem, ut consequat elit ultrices id. Phasellus vestibulum ex ex, ac sagittis tortor convallis et. Curabitur placerat id lectus at aliquam. Morbi sed nisl sem. Nam sit amet arcu maximus, volutpat nisl ac, dignissim neque. Etiam nec efficitur libero. Quisque tristique pulvinar est, eget dictum ex vehicula non. Nam dignissim non felis a iaculis. Nullam vel dolor vitae libero aliquet congue. Donec mi eros, semper non lectus at, commodo ullamcorper ligula. Donec commodo, sem vel lacinia porttitor, elit orci maximus felis, eget eleifend est velit id lorem. +