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
@@ -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,37 +334,37 @@ 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,
page_position: &Point2D<Au>,
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,
ProTip! Use n and p to navigate between commits in a pull request.
You can’t perform that action at this time.