Merge pull request #3464 from mrobinson/scroll_offset

Allow iframes to scroll their contents
This commit is contained in:
Martin Robinson 2014-09-25 08:41:51 -07:00
commit 0951936abb
5 changed files with 104 additions and 52 deletions

10
Cargo.lock generated
View file

@ -33,7 +33,7 @@ dependencies = [
"freetype 0.1.0 (git+https://github.com/servo/rust-freetype#0b03da276e4bdeae2300596dabc4ccb16733ad70)",
"geom 0.1.0 (git+https://github.com/servo/rust-geom#50a294fd997f0c6eb43e9a58ad6e227fdc2a4692)",
"glfw 0.0.1 (git+https://github.com/servo/glfw-rs?ref=servo#7ccfaca315a43d97914e1601c90ad348ef190edf)",
"layers 0.1.0 (git+https://github.com/servo/rust-layers#ef89918471815dfced7aaf2f1594d5469f03eab7)",
"layers 0.1.0 (git+https://github.com/servo/rust-layers#ed570335738913fb41fc62a024389dfa415962e8)",
"opengles 0.1.0 (git+https://github.com/servo/rust-opengles#6776e9c07feb149d34b087039ecf6b2c143e3afc)",
"skia-sys 0.0.20130412 (git+https://github.com/servo/skia#6d696712962fd0d41120b7a414a48417da8e6a92)",
"xlib 0.1.0 (git+https://github.com/servo/rust-xlib#581d4faddec5188d3c3ae5307dbea28aab90644c)",
@ -66,7 +66,7 @@ dependencies = [
"gfx 0.0.1",
"glfw 0.0.1 (git+https://github.com/servo/glfw-rs?ref=servo#7ccfaca315a43d97914e1601c90ad348ef190edf)",
"glut 0.0.1 (git+https://github.com/servo/rust-glut#01af0162ea0322ad1a40d6adb023a39813605949)",
"layers 0.1.0 (git+https://github.com/servo/rust-layers#ef89918471815dfced7aaf2f1594d5469f03eab7)",
"layers 0.1.0 (git+https://github.com/servo/rust-layers#ed570335738913fb41fc62a024389dfa415962e8)",
"layout_traits 0.0.1",
"msg 0.0.1",
"net 0.0.1",
@ -181,7 +181,7 @@ dependencies = [
"freetype 0.1.0 (git+https://github.com/servo/rust-freetype#0b03da276e4bdeae2300596dabc4ccb16733ad70)",
"geom 0.1.0 (git+https://github.com/servo/rust-geom#50a294fd997f0c6eb43e9a58ad6e227fdc2a4692)",
"harfbuzz 0.1.0 (git+https://github.com/servo/rust-harfbuzz#ad520942cc17232e1a40cdd8a99c2905623d35f6)",
"layers 0.1.0 (git+https://github.com/servo/rust-layers#ef89918471815dfced7aaf2f1594d5469f03eab7)",
"layers 0.1.0 (git+https://github.com/servo/rust-layers#ed570335738913fb41fc62a024389dfa415962e8)",
"msg 0.0.1",
"net 0.0.1",
"plugins 0.0.1",
@ -265,7 +265,7 @@ dependencies = [
[[package]]
name = "layers"
version = "0.1.0"
source = "git+https://github.com/servo/rust-layers#ef89918471815dfced7aaf2f1594d5469f03eab7"
source = "git+https://github.com/servo/rust-layers#ed570335738913fb41fc62a024389dfa415962e8"
dependencies = [
"core_foundation 0.1.0 (git+https://github.com/servo/rust-core-foundation#166a601ff3e0fc3a64ca1a9090d02c8d4f22b61a)",
"egl 0.1.0 (git+https://github.com/servo/rust-egl#88f2a13812ddbce2bf2317221663a61c31b3e220)",
@ -321,7 +321,7 @@ dependencies = [
"core_foundation 0.1.0 (git+https://github.com/servo/rust-core-foundation#166a601ff3e0fc3a64ca1a9090d02c8d4f22b61a)",
"geom 0.1.0 (git+https://github.com/servo/rust-geom#50a294fd997f0c6eb43e9a58ad6e227fdc2a4692)",
"io_surface 0.1.0 (git+https://github.com/servo/rust-io-surface#7038341220bd7e86e21118fac2cbc6bd50890e47)",
"layers 0.1.0 (git+https://github.com/servo/rust-layers#ef89918471815dfced7aaf2f1594d5469f03eab7)",
"layers 0.1.0 (git+https://github.com/servo/rust-layers#ed570335738913fb41fc62a024389dfa415962e8)",
"url 0.1.0 (git+https://github.com/servo/rust-url#bfdf809365600a7941a77524f9bb065886de3379)",
"util 0.0.1",
]

View file

@ -9,6 +9,7 @@ use compositor_task::{SetLayerOrigin, Paint, ScrollFragmentPoint, LoadComplete};
use compositor_task::{ShutdownComplete, ChangeRenderState, RenderMsgDiscarded};
use constellation::SendableFrameTree;
use events;
use events::ScrollPositionChanged;
use pipeline::CompositionPipeline;
use platform::{Application, Window};
use windowing;
@ -24,7 +25,7 @@ use azure::azure_hl;
use std::cmp;
use std::time::duration::Duration;
use geom::point::{Point2D, TypedPoint2D};
use geom::rect::Rect;
use geom::rect::{Rect, TypedRect};
use geom::size::TypedSize2D;
use geom::scale_factor::ScaleFactor;
use gfx::render_task::{RenderChan, RenderMsg, RenderRequest, UnusedBufferMsg};
@ -35,8 +36,8 @@ use layers::rendergl::RenderContext;
use layers::scene::Scene;
use opengles::gl2;
use png;
use servo_msg::compositor_msg::{Blank, Epoch, FixedPosition, FinishedLoading, IdleRenderState};
use servo_msg::compositor_msg::{LayerId, ReadyState, RenderingRenderState, RenderState};
use servo_msg::compositor_msg::{Blank, Epoch, FinishedLoading, IdleRenderState, LayerId};
use servo_msg::compositor_msg::{ReadyState, RenderingRenderState, RenderState, Scrollable};
use servo_msg::constellation_msg::{ConstellationChan, ExitMsg, LoadUrlMsg, NavigateMsg};
use servo_msg::constellation_msg::{PipelineId, ResizedWindowMsg, WindowSizeData};
use servo_msg::constellation_msg;
@ -413,7 +414,8 @@ impl IOCompositor {
Some(ref mut layer) => CompositorData::clear_all_tiles(layer.clone()),
None => { }
}
self.scene.root = Some(self.create_frame_tree_root_layers(frame_tree));
self.scene.root = Some(self.create_frame_tree_root_layers(frame_tree, None));
self.scene.set_root_layer_size(self.window_size.as_f32());
// Initialize the new constellation channel by sending it the root window size.
self.constellation_chan = new_constellation_chan;
@ -421,7 +423,8 @@ impl IOCompositor {
}
fn create_frame_tree_root_layers(&mut self,
frame_tree: &SendableFrameTree)
frame_tree: &SendableFrameTree,
frame_rect: Option<TypedRect<PagePx, f32>>)
-> Rc<Layer<CompositorData>> {
// Initialize the ReadyState and RenderState for this pipeline.
self.ready_states.insert(frame_tree.pipeline.id, Blank);
@ -433,15 +436,22 @@ impl IOCompositor {
id: LayerId::null(),
rect: Rect::zero(),
background_color: azure_hl::Color::new(0., 0., 0., 0.),
scroll_policy: FixedPosition,
scroll_policy: Scrollable,
};
let root_layer = CompositorData::new_layer(frame_tree.pipeline.clone(),
layer_properties,
WantsScrollEvents,
self.opts.tile_size);
match frame_rect {
Some(ref frame_rect) => {
*root_layer.bounds.borrow_mut() = frame_rect * self.device_pixels_per_page_px();
}
None => {}
}
for kid in frame_tree.children.iter() {
root_layer.add_child(self.create_frame_tree_root_layers(&kid.frame_tree));
root_layer.add_child(self.create_frame_tree_root_layers(&kid.frame_tree, kid.rect));
}
return root_layer;
}
@ -490,7 +500,7 @@ impl IOCompositor {
let need_new_root_layer = !self.update_layer_if_exists(layer_properties);
if need_new_root_layer {
let root_layer = self.find_pipeline_root_layer(layer_properties.pipeline_id);
CompositorData::update_layer(root_layer.clone(), layer_properties);
CompositorData::update_layer_except_size(root_layer.clone(), layer_properties);
let root_layer_pipeline = root_layer.extra_data.borrow().pipeline.clone();
let first_child = CompositorData::new_layer(root_layer_pipeline.clone(),
@ -701,13 +711,15 @@ impl IOCompositor {
self.hidpi_factor = new_hidpi_factor;
self.update_zoom_transform();
}
if self.window_size != new_size {
debug!("osmain: window resized to {:?}", new_size);
self.window_size = new_size;
self.send_window_size();
} else {
debug!("osmain: dropping window resize since size is still {:?}", new_size);
if self.window_size == new_size {
return;
}
debug!("osmain: window resized to {:?}", new_size);
self.window_size = new_size;
self.scene.set_root_layer_size(new_size.as_f32());
self.send_window_size();
}
fn on_load_url_window_event(&mut self, url_string: String) {
@ -755,7 +767,7 @@ impl IOCompositor {
delta,
cursor.as_f32(),
window_size,
scene_scale) || scroll;
scene_scale) == ScrollPositionChanged;
}
None => { }
}

View file

@ -18,6 +18,7 @@ use layers::platform::surface::NativeSurfaceMethods;
use servo_msg::compositor_msg::{Epoch, LayerId};
use servo_msg::compositor_msg::ScrollPolicy;
use servo_msg::constellation_msg::PipelineId;
use servo_util::geometry::PagePx;
use std::rc::Rc;
pub struct CompositorData {
@ -39,6 +40,10 @@ pub struct CompositorData {
/// A monotonically increasing counter that keeps track of the current epoch.
/// add_buffer() calls that don't match the current epoch will be ignored.
pub epoch: Epoch,
/// The scroll offset originating from this scrolling root. This allows scrolling roots
/// to track their current scroll position even while their content_offset does not change.
pub scroll_offset: TypedPoint2D<PagePx, f32>,
}
#[deriving(PartialEq, Clone)]
@ -60,19 +65,24 @@ impl CompositorData {
scroll_policy: layer_properties.scroll_policy,
background_color: layer_properties.background_color,
epoch: layer_properties.epoch,
scroll_offset: TypedPoint2D(0., 0.),
};
Rc::new(Layer::new(Rect::from_untyped(&layer_properties.rect),
tile_size, new_compositor_data))
}
pub fn update_layer(layer: Rc<Layer<CompositorData>>, layer_properties: LayerProperties) {
pub fn update_layer_except_size(layer: Rc<Layer<CompositorData>>,
layer_properties: LayerProperties) {
layer.extra_data.borrow_mut().epoch = layer_properties.epoch;
layer.extra_data.borrow_mut().scroll_policy = layer_properties.scroll_policy;
layer.extra_data.borrow_mut().background_color = layer_properties.background_color;
layer.contents_changed();
}
pub fn update_layer(layer: Rc<Layer<CompositorData>>, layer_properties: LayerProperties) {
let size: TypedSize2D<DevicePixel, f32> = Size2D::from_untyped(&layer_properties.rect.size);
layer.resize(size);
layer.contents_changed();
// Call scroll for bounds checking if the page shrunk. Use (-1, -1) as the
// cursor position to make sure the scroll isn't propagated downwards. The
@ -82,6 +92,7 @@ impl CompositorData {
TypedPoint2D(-1f32, -1f32),
size,
ScaleFactor(1.0) /* scene_scale */);
CompositorData::update_layer_except_size(layer, layer_properties);
}
pub fn find_layer_with_pipeline_and_layer_id(layer: Rc<Layer<CompositorData>>,

View file

@ -8,6 +8,7 @@ use windowing::MouseWindowMouseUpEvent;
use geom::length::Length;
use geom::point::{Point2D, TypedPoint2D};
use geom::rect::Rect;
use geom::scale_factor::ScaleFactor;
use geom::size::TypedSize2D;
use layers::geometry::DevicePixel;
@ -39,6 +40,13 @@ impl Clampable for f32 {
}
}
#[deriving(PartialEq)]
pub enum ScrollEventResult {
ScrollEventUnhandled,
ScrollPositionChanged,
ScrollPositionUnchanged,
}
/// Move the layer's descendants that don't want scroll events and scroll by a relative
/// specified amount in page coordinates. This also takes in a cursor position to see if the
/// mouse is over child layers first. If a layer successfully scrolled, returns true; otherwise
@ -48,40 +56,51 @@ pub fn handle_scroll_event(layer: Rc<Layer<CompositorData>>,
cursor: TypedPoint2D<DevicePixel, f32>,
window_size: TypedSize2D<DevicePixel, f32>,
scale: ScaleFactor<PagePx, DevicePixel, f32>)
-> bool {
-> ScrollEventResult {
// If this layer doesn't want scroll events, neither it nor its children can handle scroll
// events.
if layer.extra_data.borrow().wants_scroll_events != WantsScrollEvents {
return false
return ScrollEventUnhandled;
}
// Allow children to scroll.
let content_offset_in_page_pixels : TypedPoint2D<PagePx, f32> =
Point2D::from_untyped(&*layer.content_offset.borrow());
let content_offset : TypedPoint2D<DevicePixel, f32> = content_offset_in_page_pixels * scale;
let new_cursor = cursor - content_offset;
let scroll_offset = layer.extra_data.borrow().scroll_offset;
let scroll_offset_in_device_pixels = scroll_offset * scale;
let new_cursor = cursor - scroll_offset_in_device_pixels;
for child in layer.children().iter() {
let child_bounds = child.bounds.borrow();
if child_bounds.contains(&new_cursor) &&
handle_scroll_event(child.clone(),
delta,
new_cursor - child_bounds.origin,
child_bounds.size,
scale) {
return true
if child_bounds.contains(&new_cursor) {
let result = handle_scroll_event(child.clone(),
delta,
new_cursor - child_bounds.origin,
child_bounds.size,
scale);
if result != ScrollEventUnhandled {
return result;
}
}
}
clamp_scroll_offset_and_scroll_layer(layer, content_offset + delta, window_size, scale)
clamp_scroll_offset_and_scroll_layer(layer,
scroll_offset_in_device_pixels + delta,
window_size,
scale)
}
pub fn calculate_content_size_for_layer(layer: Rc<Layer<CompositorData>>)
-> TypedSize2D<DevicePixel, f32> {
layer.children().iter().fold(Rect::zero(),
|unioned_rect, child_rect| {
unioned_rect.union(&*child_rect.bounds.borrow())
}).size
}
pub fn clamp_scroll_offset_and_scroll_layer(layer: Rc<Layer<CompositorData>>,
new_offset: TypedPoint2D<DevicePixel, f32>,
window_size: TypedSize2D<DevicePixel, f32>,
scale: ScaleFactor<PagePx, DevicePixel, f32>)
-> bool {
let layer_size = layer.bounds.borrow().size;
-> ScrollEventResult {
let layer_size = calculate_content_size_for_layer(layer.clone());
let min_x = (window_size.width - layer_size.width).get().min(0.0);
let min_y = (window_size.height - layer_size.height).get().min(0.0);
let new_offset : TypedPoint2D<DevicePixel, f32> =
@ -89,15 +108,24 @@ pub fn clamp_scroll_offset_and_scroll_layer(layer: Rc<Layer<CompositorData>>,
Length(new_offset.y.get().clamp(&min_y, &0.0)));
let new_offset_in_page_px = new_offset / scale;
let untyped_new_offset = new_offset_in_page_px.to_untyped();
if *layer.content_offset.borrow() == untyped_new_offset {
return false
if layer.extra_data.borrow().scroll_offset == new_offset_in_page_px {
return ScrollPositionUnchanged;
}
// FIXME: This allows the base layer to record the current content offset without
// updating its transform. This should be replaced with something less strange.
*layer.content_offset.borrow_mut() = untyped_new_offset;
scroll_layer_and_all_child_layers(layer.clone(), new_offset_in_page_px)
// The scroll offset is just a record of the scroll position of this scrolling root,
// but scroll_layer_and_all_child_layers actually moves the child layers.
layer.extra_data.borrow_mut().scroll_offset = new_offset_in_page_px;
let mut result = false;
for child in layer.children().iter() {
result |= scroll_layer_and_all_child_layers(child.clone(), new_offset_in_page_px);
}
if result {
return ScrollPositionChanged;
} else {
return ScrollPositionUnchanged;
}
}
fn scroll_layer_and_all_child_layers(layer: Rc<Layer<CompositorData>>,
@ -115,8 +143,9 @@ fn scroll_layer_and_all_child_layers(layer: Rc<Layer<CompositorData>>,
result = true
}
let offset_for_children = new_offset + layer.extra_data.borrow().scroll_offset;
for child in layer.children().iter() {
result |= scroll_layer_and_all_child_layers(child.clone(), new_offset);
result |= scroll_layer_and_all_child_layers(child.clone(), offset_for_children);
}
return result;

12
ports/cef/Cargo.lock generated
View file

@ -11,7 +11,7 @@ dependencies = [
"glfw 0.0.1 (git+https://github.com/servo/glfw-rs?ref=servo#955dbe919870b0536f79123232d87c0efe3c552e)",
"glut 0.0.1 (git+https://github.com/servo/rust-glut#01af0162ea0322ad1a40d6adb023a39813605949)",
"js 0.1.0 (git+https://github.com/servo/rust-mozjs#41fb0d80a5ed5614ca13a120cdb3281e599d4e04)",
"layers 0.1.0 (git+https://github.com/servo/rust-layers#ef89918471815dfced7aaf2f1594d5469f03eab7)",
"layers 0.1.0 (git+https://github.com/servo/rust-layers#ed570335738913fb41fc62a024389dfa415962e8)",
"plugins 0.0.1",
"msg 0.0.1",
"net 0.0.1",
@ -45,7 +45,7 @@ dependencies = [
"freetype 0.1.0 (git+https://github.com/servo/rust-freetype#0b03da276e4bdeae2300596dabc4ccb16733ad70)",
"geom 0.1.0 (git+https://github.com/servo/rust-geom#50a294fd997f0c6eb43e9a58ad6e227fdc2a4692)",
"glfw 0.0.1 (git+https://github.com/servo/glfw-rs?ref=servo#955dbe919870b0536f79123232d87c0efe3c552e)",
"layers 0.1.0 (git+https://github.com/servo/rust-layers#ef89918471815dfced7aaf2f1594d5469f03eab7)",
"layers 0.1.0 (git+https://github.com/servo/rust-layers#ed570335738913fb41fc62a024389dfa415962e8)",
"opengles 0.1.0 (git+https://github.com/servo/rust-opengles#6776e9c07feb149d34b087039ecf6b2c143e3afc)",
"skia-sys 0.0.20130412 (git+https://github.com/servo/skia#6d696712962fd0d41120b7a414a48417da8e6a92)",
"xlib 0.1.0 (git+https://github.com/servo/rust-xlib#581d4faddec5188d3c3ae5307dbea28aab90644c)",
@ -78,7 +78,7 @@ dependencies = [
"gfx 0.0.1",
"glfw 0.0.1 (git+https://github.com/servo/glfw-rs?ref=servo#955dbe919870b0536f79123232d87c0efe3c552e)",
"glut 0.0.1 (git+https://github.com/servo/rust-glut#01af0162ea0322ad1a40d6adb023a39813605949)",
"layers 0.1.0 (git+https://github.com/servo/rust-layers#ef89918471815dfced7aaf2f1594d5469f03eab7)",
"layers 0.1.0 (git+https://github.com/servo/rust-layers#ed570335738913fb41fc62a024389dfa415962e8)",
"layout_traits 0.0.1",
"msg 0.0.1",
"net 0.0.1",
@ -193,7 +193,7 @@ dependencies = [
"freetype 0.1.0 (git+https://github.com/servo/rust-freetype#0b03da276e4bdeae2300596dabc4ccb16733ad70)",
"geom 0.1.0 (git+https://github.com/servo/rust-geom#50a294fd997f0c6eb43e9a58ad6e227fdc2a4692)",
"harfbuzz 0.1.0 (git+https://github.com/servo/rust-harfbuzz#ad520942cc17232e1a40cdd8a99c2905623d35f6)",
"layers 0.1.0 (git+https://github.com/servo/rust-layers#ef89918471815dfced7aaf2f1594d5469f03eab7)",
"layers 0.1.0 (git+https://github.com/servo/rust-layers#ed570335738913fb41fc62a024389dfa415962e8)",
"plugins 0.0.1",
"msg 0.0.1",
"net 0.0.1",
@ -277,7 +277,7 @@ dependencies = [
[[package]]
name = "layers"
version = "0.1.0"
source = "git+https://github.com/servo/rust-layers#ef89918471815dfced7aaf2f1594d5469f03eab7"
source = "git+https://github.com/servo/rust-layers#ed570335738913fb41fc62a024389dfa415962e8"
dependencies = [
"core_foundation 0.1.0 (git+https://github.com/servo/rust-core-foundation#166a601ff3e0fc3a64ca1a9090d02c8d4f22b61a)",
"egl 0.1.0 (git+https://github.com/servo/rust-egl#88f2a13812ddbce2bf2317221663a61c31b3e220)",
@ -337,7 +337,7 @@ dependencies = [
"core_foundation 0.1.0 (git+https://github.com/servo/rust-core-foundation#166a601ff3e0fc3a64ca1a9090d02c8d4f22b61a)",
"geom 0.1.0 (git+https://github.com/servo/rust-geom#50a294fd997f0c6eb43e9a58ad6e227fdc2a4692)",
"io_surface 0.1.0 (git+https://github.com/servo/rust-io-surface#7038341220bd7e86e21118fac2cbc6bd50890e47)",
"layers 0.1.0 (git+https://github.com/servo/rust-layers#ef89918471815dfced7aaf2f1594d5469f03eab7)",
"layers 0.1.0 (git+https://github.com/servo/rust-layers#ed570335738913fb41fc62a024389dfa415962e8)",
"url 0.1.0 (git+https://github.com/servo/rust-url#bfdf809365600a7941a77524f9bb065886de3379)",
"util 0.0.1",
]