Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

layout: Implement basic `overflow: scroll` functionality. #7090

Merged
merged 6 commits into from Aug 11, 2015

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.
  • Loading branch information
pcwalton committed Aug 11, 2015
commit df4acbac0424514ecbcdf0212e44ab4ae39a7387
@@ -629,6 +629,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,
@@ -740,10 +741,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);
}
}
@@ -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,
}
}

@@ -342,29 +342,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 +373,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() {
ProTip! Use n and p to navigate between commits in a pull request.
You can’t perform that action at this time.