diff --git a/components/compositing/compositor.rs b/components/compositing/compositor.rs index cfa5f68a4e0..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 { @@ -629,6 +630,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, @@ -691,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) { @@ -740,10 +744,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); } } @@ -1610,6 +1625,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 707b7ce06b6..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, @@ -292,13 +293,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 +306,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) } 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..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, @@ -342,29 +344,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 +375,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/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..4e86f880768 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; } @@ -470,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) } }; @@ -669,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, @@ -900,11 +908,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 +919,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); @@ -1136,17 +1137,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 = @@ -1220,10 +1241,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(); @@ -1254,7 +1271,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, @@ -1265,7 +1285,8 @@ impl FragmentDisplayListBuilding for Fragment { layer, transform, perspective, - transform_style == transform_style::T::flat)) + establishes_3d_context, + scrolls_overflow_area)) } #[inline(never)] @@ -1291,7 +1312,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() { @@ -1304,12 +1326,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); @@ -1318,8 +1342,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); @@ -1532,19 +1558,25 @@ 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, - 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 { @@ -1567,19 +1599,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 } @@ -1590,13 +1660,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, @@ -1611,10 +1712,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) } @@ -1709,10 +1812,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) }; @@ -1902,3 +2007,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 38653037f6b..76baafc8013 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); @@ -1054,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..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, @@ -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 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. +