servo: Merge #7090 - layout: Implement basic `overflow: scroll` functionality (from pcwalton:overflow-scroll); r=glennw

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.

Note that multiple layers per stacking context aren't needed for the Enyo demo; rather the issue is that the height of the main area is being calculated incorrectly. (It looks like JS is measuring the height and poking in an explicit value that is too tall.)

r? @glennw

Source-Repo: https://github.com/servo/servo
Source-Revision: b05b02e11fb849e1f0153d009d8fcf0501ace8dc
This commit is contained in:
Patrick Walton 2015-08-10 22:29:40 -06:00
Родитель e02a85f369
Коммит a95ad541cf
11 изменённых файлов: 307 добавлений и 111 удалений

Просмотреть файл

@ -255,13 +255,13 @@ impl<Window: WindowMethods> IOCompositor<Window> {
time_profiler_chan: time::ProfilerChan,
mem_profiler_chan: mem::ProfilerChan)
-> IOCompositor<Window> {
// 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<Window: WindowMethods> IOCompositor<Window> {
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<Window: WindowMethods> IOCompositor<Window> {
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<Window: WindowMethods> IOCompositor<Window> {
}
}
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<Window: WindowMethods> IOCompositor<Window> {
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<Window: WindowMethods> IOCompositor<Window> {
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<CompositorData>, 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<Layer<CompositorData>>,

Просмотреть файл

@ -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<CompositorData> {
delta: TypedPoint2D<LayerPixel, f32>,
cursor: TypedPoint2D<LayerPixel, f32>)
-> 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<CompositorData> {
}
}
// 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)
}

Просмотреть файл

@ -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<PaintLayer>,
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,
}
}

Просмотреть файл

@ -334,7 +334,9 @@ impl<C> PaintTask<C> 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<LayerProperties>,
stacking_context: &StackingContext,
@ -342,29 +344,27 @@ impl<C> PaintTask<C> where C: PaintListener + Send + 'static {
transform: &Matrix4,
perspective: &Matrix4,
parent_id: Option<LayerId>) {
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<C> PaintTask<C> 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

Просмотреть файл

@ -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() {

Просмотреть файл

@ -109,9 +109,6 @@ pub struct SharedLayoutContext {
/// The URL.
pub url: Url,
/// The dirty rectangle, used during display list building.
pub dirty: Rect<Au>,
/// 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,

Просмотреть файл

@ -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<Au>,
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<Au>)
stacking_relative_border_box: &Rect<Au>,
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<DisplayList>,
layout_context: &LayoutContext,
layer: StackingContextLayer)
layer: StackingContextLayer,
mode: StackingContextCreationMode)
-> Arc<StackingContext>;
}
@ -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<DisplayList>,
layout_context: &LayoutContext,
layer: StackingContextLayer)
layer: StackingContextLayer,
mode: StackingContextCreationMode)
-> Arc<StackingContext> {
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<Au>)
stacking_relative_border_box: &Rect<Au>,
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: <scrolling>` 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<DisplayList>,
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,
}

Просмотреть файл

@ -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;

Просмотреть файл

@ -119,9 +119,6 @@ pub struct LayoutTaskData {
/// The workers that we use for parallel operation.
pub parallel_traversal: Option<WorkQueue<SharedLayoutContext, WorkQueueData>>,
/// The dirty rect. Used during display list construction.
pub dirty: Rect<Au>,
/// 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.");

Просмотреть файл

@ -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

Просмотреть файл

@ -0,0 +1,30 @@
<style>
section {
width: 300px;
height: 300px;
position: absolute;
top: 16px;
left: 16px;
border: inset gray 3px;
overflow: scroll;
background: white;
}
nav {
width: 300px;
height: 300px;
background: blue;
position: absolute;
top: 16px;
left: 16px;
}
</style>
<nav></nav><section>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.