mirror of
https://github.com/servo/servo.git
synced 2025-08-03 20:50:07 +01:00
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.
This commit is contained in:
parent
fc13dd1169
commit
df4acbac04
8 changed files with 221 additions and 72 deletions
|
@ -629,6 +629,7 @@ impl<Window: WindowMethods> IOCompositor<Window> {
|
||||||
transform: Matrix4::identity(),
|
transform: Matrix4::identity(),
|
||||||
perspective: Matrix4::identity(),
|
perspective: Matrix4::identity(),
|
||||||
establishes_3d_context: true,
|
establishes_3d_context: true,
|
||||||
|
scrolls_overflow_area: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
let root_layer = CompositorData::new_layer(pipeline.id,
|
let root_layer = CompositorData::new_layer(pipeline.id,
|
||||||
|
@ -740,10 +741,21 @@ impl<Window: WindowMethods> IOCompositor<Window> {
|
||||||
|
|
||||||
if let Some(parent_layer) = self.find_layer_with_pipeline_and_layer_id(pipeline_id,
|
if let Some(parent_layer) = self.find_layer_with_pipeline_and_layer_id(pipeline_id,
|
||||||
parent_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,
|
let new_layer = CompositorData::new_layer(pipeline_id,
|
||||||
layer_properties,
|
layer_properties,
|
||||||
WantsScrollEventsFlag::DoesntWantScrollEvents,
|
wants_scroll_events,
|
||||||
parent_layer.tile_size);
|
parent_layer.tile_size);
|
||||||
|
|
||||||
|
if layer_properties.scrolls_overflow_area {
|
||||||
|
*new_layer.masks_to_bounds.borrow_mut() = true
|
||||||
|
}
|
||||||
|
|
||||||
parent_layer.add_child(new_layer);
|
parent_layer.add_child(new_layer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -252,6 +252,9 @@ pub struct StackingContext {
|
||||||
|
|
||||||
/// Whether this stacking context creates a new 3d rendering context.
|
/// Whether this stacking context creates a new 3d rendering context.
|
||||||
pub establishes_3d_context: bool,
|
pub establishes_3d_context: bool,
|
||||||
|
|
||||||
|
/// Whether this stacking context scrolls its overflow area.
|
||||||
|
pub scrolls_overflow_area: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl StackingContext {
|
impl StackingContext {
|
||||||
|
@ -266,7 +269,8 @@ impl StackingContext {
|
||||||
layer: Option<PaintLayer>,
|
layer: Option<PaintLayer>,
|
||||||
transform: Matrix4,
|
transform: Matrix4,
|
||||||
perspective: Matrix4,
|
perspective: Matrix4,
|
||||||
establishes_3d_context: bool)
|
establishes_3d_context: bool,
|
||||||
|
scrolls_overflow_area: bool)
|
||||||
-> StackingContext {
|
-> StackingContext {
|
||||||
StackingContext {
|
StackingContext {
|
||||||
display_list: display_list,
|
display_list: display_list,
|
||||||
|
@ -279,6 +283,7 @@ impl StackingContext {
|
||||||
transform: transform,
|
transform: transform,
|
||||||
perspective: perspective,
|
perspective: perspective,
|
||||||
establishes_3d_context: establishes_3d_context,
|
establishes_3d_context: establishes_3d_context,
|
||||||
|
scrolls_overflow_area: scrolls_overflow_area,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -342,29 +342,27 @@ impl<C> PaintTask<C> where C: PaintListener + Send + 'static {
|
||||||
transform: &Matrix4,
|
transform: &Matrix4,
|
||||||
perspective: &Matrix4,
|
perspective: &Matrix4,
|
||||||
parent_id: Option<LayerId>) {
|
parent_id: Option<LayerId>) {
|
||||||
|
|
||||||
let transform = transform.mul(&stacking_context.transform);
|
let transform = transform.mul(&stacking_context.transform);
|
||||||
let perspective = perspective.mul(&stacking_context.perspective);
|
let perspective = perspective.mul(&stacking_context.perspective);
|
||||||
|
|
||||||
let (next_parent_id, page_position, transform, perspective) =
|
let (next_parent_id, page_position, transform, perspective) =
|
||||||
match stacking_context.layer {
|
match stacking_context.layer {
|
||||||
Some(ref paint_layer) => {
|
Some(ref paint_layer) => {
|
||||||
// Layers start at the top left of their overflow rect, as far as the info we
|
let overflow_size =
|
||||||
// give to the compositor is concerned.
|
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 +
|
let overflow_relative_page_position = *page_position +
|
||||||
stacking_context.bounds.origin +
|
stacking_context.bounds.origin +
|
||||||
stacking_context.overflow.origin;
|
stacking_context.overflow.origin;
|
||||||
let layer_position =
|
let layer_position = Rect::new(
|
||||||
Rect::new(Point2D::new(overflow_relative_page_position.x.to_nearest_px() as
|
Point2D::new(overflow_relative_page_position.x.to_nearest_px() as f32,
|
||||||
f32,
|
overflow_relative_page_position.y.to_nearest_px() as f32),
|
||||||
overflow_relative_page_position.y.to_nearest_px() as
|
overflow_size);
|
||||||
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;
|
|
||||||
|
|
||||||
properties.push(LayerProperties {
|
properties.push(LayerProperties {
|
||||||
id: paint_layer.id,
|
id: paint_layer.id,
|
||||||
|
@ -375,6 +373,7 @@ impl<C> PaintTask<C> where C: PaintListener + Send + 'static {
|
||||||
transform: transform,
|
transform: transform,
|
||||||
perspective: perspective,
|
perspective: perspective,
|
||||||
establishes_3d_context: establishes_3d_context,
|
establishes_3d_context: establishes_3d_context,
|
||||||
|
scrolls_overflow_area: scrolls_overflow_area,
|
||||||
});
|
});
|
||||||
|
|
||||||
// When there is a new layer, the transforms and origin
|
// 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) {
|
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,
|
let position_start = self.base.position.start.to_physical(self.base.writing_mode,
|
||||||
container_size);
|
container_size);
|
||||||
|
|
||||||
|
@ -1892,8 +1903,10 @@ impl Flow for BlockFlow {
|
||||||
.absolute_position_info
|
.absolute_position_info
|
||||||
.relative_containing_block_mode,
|
.relative_containing_block_mode,
|
||||||
CoordinateSystem::Own);
|
CoordinateSystem::Own);
|
||||||
let clip = self.fragment.clipping_region_for_children(&clip_in_child_coordinate_system,
|
let clip = self.fragment.clipping_region_for_children(
|
||||||
&stacking_relative_border_box);
|
&clip_in_child_coordinate_system,
|
||||||
|
&stacking_relative_border_box,
|
||||||
|
self.base.flags.contains(IS_ABSOLUTELY_POSITIONED));
|
||||||
|
|
||||||
// Process children.
|
// Process children.
|
||||||
for kid in self.base.child_iter() {
|
for kid in self.base.child_iter() {
|
||||||
|
|
|
@ -62,6 +62,11 @@ use util::geometry::{Au, ZERO_POINT};
|
||||||
use util::logical_geometry::{LogicalPoint, LogicalRect, LogicalSize, WritingMode};
|
use util::logical_geometry::{LogicalPoint, LogicalRect, LogicalSize, WritingMode};
|
||||||
use util::opts;
|
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
|
/// A possible `PaintLayer` for an stacking context
|
||||||
pub enum StackingContextLayer {
|
pub enum StackingContextLayer {
|
||||||
Existing(PaintLayer),
|
Existing(PaintLayer),
|
||||||
|
@ -208,10 +213,11 @@ pub trait FragmentDisplayListBuilding {
|
||||||
offset: Point2D<Au>,
|
offset: Point2D<Au>,
|
||||||
layout_context: &LayoutContext);
|
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,
|
fn clipping_region_for_children(&self,
|
||||||
current_clip: &ClippingRegion,
|
current_clip: &ClippingRegion,
|
||||||
stacking_relative_border_box: &Rect<Au>)
|
stacking_relative_border_box: &Rect<Au>,
|
||||||
|
is_absolutely_positioned: bool)
|
||||||
-> ClippingRegion;
|
-> ClippingRegion;
|
||||||
|
|
||||||
/// Calculates the clipping rectangle for a fragment, taking the `clip` property into account
|
/// Calculates the clipping rectangle for a fragment, taking the `clip` property into account
|
||||||
|
@ -253,7 +259,8 @@ pub trait FragmentDisplayListBuilding {
|
||||||
base_flow: &BaseFlow,
|
base_flow: &BaseFlow,
|
||||||
display_list: Box<DisplayList>,
|
display_list: Box<DisplayList>,
|
||||||
layout_context: &LayoutContext,
|
layout_context: &LayoutContext,
|
||||||
layer: StackingContextLayer)
|
layer: StackingContextLayer,
|
||||||
|
mode: StackingContextCreationMode)
|
||||||
-> Arc<StackingContext>;
|
-> Arc<StackingContext>;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1129,17 +1136,37 @@ impl FragmentDisplayListBuilding for Fragment {
|
||||||
base_flow: &BaseFlow,
|
base_flow: &BaseFlow,
|
||||||
display_list: Box<DisplayList>,
|
display_list: Box<DisplayList>,
|
||||||
layout_context: &LayoutContext,
|
layout_context: &LayoutContext,
|
||||||
layer: StackingContextLayer)
|
layer: StackingContextLayer,
|
||||||
|
mode: StackingContextCreationMode)
|
||||||
-> Arc<StackingContext> {
|
-> Arc<StackingContext> {
|
||||||
let border_box = self.stacking_relative_border_box(&base_flow.stacking_relative_position,
|
// FIXME(pcwalton): Is this vertical-writing-direction-safe?
|
||||||
&base_flow.absolute_position_info
|
let margin = self.margin.to_physical(base_flow.writing_mode);
|
||||||
.relative_containing_block_size,
|
|
||||||
base_flow.absolute_position_info
|
let border_box = match mode {
|
||||||
.relative_containing_block_mode,
|
StackingContextCreationMode::Normal |
|
||||||
CoordinateSystem::Parent);
|
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();
|
let mut transform = Matrix4::identity();
|
||||||
|
|
||||||
if let Some(ref operations) = self.style().get_effects().transform.0 {
|
if let Some(ref operations) = self.style().get_effects().transform.0 {
|
||||||
let transform_origin = self.style().get_effects().transform_origin;
|
let transform_origin = self.style().get_effects().transform_origin;
|
||||||
let 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.
|
// Create the filter pipeline.
|
||||||
let effects = self.style().get_effects();
|
let effects = self.style().get_effects();
|
||||||
let mut filters = effects.filter.clone();
|
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 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,
|
Arc::new(StackingContext::new(display_list,
|
||||||
&border_box,
|
&border_box,
|
||||||
|
@ -1258,7 +1284,8 @@ impl FragmentDisplayListBuilding for Fragment {
|
||||||
layer,
|
layer,
|
||||||
transform,
|
transform,
|
||||||
perspective,
|
perspective,
|
||||||
transform_style == transform_style::T::flat))
|
establishes_3d_context,
|
||||||
|
scrolls_overflow_area))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(never)]
|
#[inline(never)]
|
||||||
|
@ -1284,7 +1311,8 @@ impl FragmentDisplayListBuilding for Fragment {
|
||||||
|
|
||||||
fn clipping_region_for_children(&self,
|
fn clipping_region_for_children(&self,
|
||||||
current_clip: &ClippingRegion,
|
current_clip: &ClippingRegion,
|
||||||
stacking_relative_border_box: &Rect<Au>)
|
stacking_relative_border_box: &Rect<Au>,
|
||||||
|
is_absolutely_positioned: bool)
|
||||||
-> ClippingRegion {
|
-> ClippingRegion {
|
||||||
// Don't clip if we're text.
|
// Don't clip if we're text.
|
||||||
if self.is_scanned_text_fragment() {
|
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`.
|
// 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
|
// 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
|
// impossible with the computed value rules as they are to have `overflow-x: visible` with
|
||||||
// `overflow-y: <scrolling>` or vice versa!
|
// `overflow-y: <scrolling>` or vice versa!
|
||||||
match self.style.get_box().overflow_x {
|
match (self.style.get_box().overflow_x, is_absolutely_positioned) {
|
||||||
overflow_x::T::hidden | overflow_x::T::auto | overflow_x::T::scroll => {
|
(overflow_x::T::hidden, _) |
|
||||||
|
(overflow_x::T::auto, false) |
|
||||||
|
(overflow_x::T::scroll, false) => {
|
||||||
let mut bounds = current_clip.bounding_rect();
|
let mut bounds = current_clip.bounding_rect();
|
||||||
let max_x = cmp::min(bounds.max_x(), stacking_relative_border_box.max_x());
|
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);
|
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 {
|
match (self.style.get_box().overflow_y.0, is_absolutely_positioned) {
|
||||||
overflow_x::T::hidden | overflow_x::T::auto | overflow_x::T::scroll => {
|
(overflow_x::T::hidden, _) |
|
||||||
|
(overflow_x::T::auto, false) |
|
||||||
|
(overflow_x::T::scroll, false) => {
|
||||||
let mut bounds = current_clip.bounding_rect();
|
let mut bounds = current_clip.bounding_rect();
|
||||||
let max_y = cmp::min(bounds.max_y(), stacking_relative_border_box.max_y());
|
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);
|
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 paint_layer = PaintLayer::new(self.layer_id(0), color::transparent(), scroll_policy);
|
||||||
let layer = StackingContextLayer::Existing(paint_layer);
|
let layer = StackingContextLayer::Existing(paint_layer);
|
||||||
let stacking_context = self.fragment.create_stacking_context(&self.base,
|
let stacking_context = self.fragment.create_stacking_context(
|
||||||
display_list,
|
&self.base,
|
||||||
layout_context,
|
display_list,
|
||||||
layer);
|
layout_context,
|
||||||
|
layer,
|
||||||
|
StackingContextCreationMode::Normal);
|
||||||
DisplayListBuildingResult::StackingContext(stacking_context)
|
DisplayListBuildingResult::StackingContext(stacking_context)
|
||||||
} else {
|
} else {
|
||||||
DisplayListBuildingResult::StackingContext(
|
DisplayListBuildingResult::StackingContext(
|
||||||
self.fragment.create_stacking_context(&self.base,
|
self.fragment.create_stacking_context(
|
||||||
display_list,
|
&self.base,
|
||||||
layout_context,
|
display_list,
|
||||||
StackingContextLayer::IfCanvas(self.layer_id(0))))
|
layout_context,
|
||||||
|
StackingContextLayer::IfCanvas(self.layer_id(0)),
|
||||||
|
StackingContextCreationMode::Normal))
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
match self.fragment.style.get_box().position {
|
match self.fragment.style.get_box().position {
|
||||||
|
@ -1560,19 +1596,57 @@ impl BlockFlowDisplayListBuilding for BlockFlow {
|
||||||
mut display_list: Box<DisplayList>,
|
mut display_list: Box<DisplayList>,
|
||||||
layout_context: &LayoutContext,
|
layout_context: &LayoutContext,
|
||||||
border_painting_mode: BorderPaintingMode) {
|
border_painting_mode: BorderPaintingMode) {
|
||||||
self.build_display_list_for_block_base(&mut *display_list,
|
// If `overflow: scroll` is in effect, we add this fragment's display items to a new
|
||||||
layout_context,
|
// stacking context.
|
||||||
border_painting_mode,
|
let outer_display_list_for_overflow_scroll =
|
||||||
BackgroundAndBorderLevel::RootOfStackingContext);
|
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() {
|
if !self.will_get_layer() {
|
||||||
// We didn't need a layer.
|
// We didn't need a layer.
|
||||||
self.base.display_list_building_result =
|
self.base.display_list_building_result =
|
||||||
DisplayListBuildingResult::StackingContext(
|
DisplayListBuildingResult::StackingContext(
|
||||||
self.fragment.create_stacking_context(&self.base,
|
self.fragment.create_stacking_context(
|
||||||
display_list,
|
&self.base,
|
||||||
layout_context,
|
display_list,
|
||||||
StackingContextLayer::IfCanvas(self.layer_id(0))));
|
layout_context,
|
||||||
|
StackingContextLayer::IfCanvas(self.layer_id(0)),
|
||||||
|
StackingContextCreationMode::Normal));
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1583,13 +1657,44 @@ impl BlockFlowDisplayListBuilding for BlockFlow {
|
||||||
ScrollPolicy::Scrollable
|
ScrollPolicy::Scrollable
|
||||||
};
|
};
|
||||||
|
|
||||||
let paint_layer = PaintLayer::new(self.layer_id(0), color::transparent(), scroll_policy);
|
let stacking_context_creation_mode = if outer_display_list_for_overflow_scroll.is_some() {
|
||||||
let stacking_context = self.fragment.create_stacking_context(&self.base,
|
StackingContextCreationMode::InnerScrollWrapper
|
||||||
display_list,
|
} else {
|
||||||
layout_context,
|
StackingContextCreationMode::Normal
|
||||||
StackingContextLayer::Existing(paint_layer));
|
};
|
||||||
|
|
||||||
|
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 =
|
self.base.display_list_building_result =
|
||||||
DisplayListBuildingResult::StackingContext(stacking_context)
|
DisplayListBuildingResult::StackingContext(outermost_stacking_context)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn build_display_list_for_floating_block(&mut self,
|
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() {
|
self.base.display_list_building_result = if self.fragment.establishes_stacking_context() {
|
||||||
DisplayListBuildingResult::StackingContext(
|
DisplayListBuildingResult::StackingContext(
|
||||||
self.fragment.create_stacking_context(&self.base,
|
self.fragment.create_stacking_context(
|
||||||
display_list,
|
&self.base,
|
||||||
layout_context,
|
display_list,
|
||||||
StackingContextLayer::IfCanvas(self.layer_id(0))))
|
layout_context,
|
||||||
|
StackingContextLayer::IfCanvas(self.layer_id(0)),
|
||||||
|
StackingContextCreationMode::Normal))
|
||||||
} else {
|
} else {
|
||||||
DisplayListBuildingResult::Normal(display_list)
|
DisplayListBuildingResult::Normal(display_list)
|
||||||
}
|
}
|
||||||
|
@ -1702,10 +1809,12 @@ impl InlineFlowDisplayListBuilding for InlineFlow {
|
||||||
|
|
||||||
self.base.display_list_building_result = if has_stacking_context {
|
self.base.display_list_building_result = if has_stacking_context {
|
||||||
DisplayListBuildingResult::StackingContext(
|
DisplayListBuildingResult::StackingContext(
|
||||||
self.fragments.fragments[0].create_stacking_context(&self.base,
|
self.fragments.fragments[0].create_stacking_context(
|
||||||
display_list,
|
&self.base,
|
||||||
layout_context,
|
display_list,
|
||||||
StackingContextLayer::IfCanvas(self.layer_id(0))))
|
layout_context,
|
||||||
|
StackingContextLayer::IfCanvas(self.layer_id(0)),
|
||||||
|
StackingContextCreationMode::Normal))
|
||||||
} else {
|
} else {
|
||||||
DisplayListBuildingResult::Normal(display_list)
|
DisplayListBuildingResult::Normal(display_list)
|
||||||
};
|
};
|
||||||
|
@ -1895,3 +2004,10 @@ pub enum BorderPaintingMode<'a> {
|
||||||
Hidden,
|
Hidden,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, PartialEq)]
|
||||||
|
pub enum StackingContextCreationMode {
|
||||||
|
Normal,
|
||||||
|
OuterScrollWrapper,
|
||||||
|
InnerScrollWrapper,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -1627,7 +1627,8 @@ impl Flow for InlineFlow {
|
||||||
.relative_containing_block_mode,
|
.relative_containing_block_mode,
|
||||||
CoordinateSystem::Parent);
|
CoordinateSystem::Parent);
|
||||||
let clip = fragment.clipping_region_for_children(&self.base.clip,
|
let clip = fragment.clipping_region_for_children(&self.base.clip,
|
||||||
&stacking_relative_border_box);
|
&stacking_relative_border_box,
|
||||||
|
false);
|
||||||
match fragment.specific {
|
match fragment.specific {
|
||||||
SpecificFragmentInfo::InlineBlock(ref mut info) => {
|
SpecificFragmentInfo::InlineBlock(ref mut info) => {
|
||||||
flow::mut_base(&mut *info.flow_ref).clip = clip;
|
flow::mut_base(&mut *info.flow_ref).clip = clip;
|
||||||
|
|
|
@ -1046,7 +1046,8 @@ impl LayoutTask {
|
||||||
Some(paint_layer),
|
Some(paint_layer),
|
||||||
Matrix4::identity(),
|
Matrix4::identity(),
|
||||||
Matrix4::identity(),
|
Matrix4::identity(),
|
||||||
true));
|
true,
|
||||||
|
false));
|
||||||
|
|
||||||
if opts::get().dump_display_list {
|
if opts::get().dump_display_list {
|
||||||
println!("#### start printing display list.");
|
println!("#### start printing display list.");
|
||||||
|
|
|
@ -88,6 +88,8 @@ pub struct LayerProperties {
|
||||||
pub perspective: Matrix4,
|
pub perspective: Matrix4,
|
||||||
/// Whether this layer establishes a new 3d rendering context.
|
/// Whether this layer establishes a new 3d rendering context.
|
||||||
pub establishes_3d_context: bool,
|
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
|
/// The interface used by the painter to acquire draw targets for each paint frame and
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue