diff --git a/src/components/compositing/compositor.rs b/src/components/compositing/compositor.rs index 54f0c637f2f..131b908c7df 100644 --- a/src/components/compositing/compositor.rs +++ b/src/components/compositing/compositor.rs @@ -478,11 +478,6 @@ impl IOCompositor { } } - /// The size of the content area in CSS px at the current zoom level - fn page_window(&self) -> TypedSize2D { - self.window_size.as_f32() / self.device_pixels_per_page_px() - } - fn send_window_size(&self) { let dppx = self.page_zoom * self.device_pixels_per_screen_px(); let initial_viewport = self.window_size.as_f32() / dppx; @@ -499,17 +494,17 @@ impl IOCompositor { fn scroll_layer_to_fragment_point_if_necessary(&mut self, pipeline_id: PipelineId, layer_id: LayerId) { - let page_window = self.page_window(); let device_pixels_per_page_px = self.device_pixels_per_page_px(); + let window_size = self.window_size.as_f32(); let needs_recomposite = match self.scene.root { Some(ref mut root_layer) => { self.fragment_point.take().map_or(false, |fragment_point| { + let fragment_point = fragment_point * device_pixels_per_page_px.get(); events::move(root_layer.clone(), pipeline_id, layer_id, fragment_point, - page_window, - device_pixels_per_page_px) + window_size) }) } None => fail!("Compositor: Tried to scroll to fragment without root layer."), @@ -589,17 +584,19 @@ impl IOCompositor { pipeline_id: PipelineId, layer_id: LayerId, point: Point2D) { - let page_window = self.page_window(); + let device_pixels_per_page_px = self.device_pixels_per_page_px(); + let device_point = point * device_pixels_per_page_px.get(); + let window_size = self.window_size.as_f32(); + let (ask, move): (bool, bool) = match self.scene.root { Some(ref layer) if layer.extra_data.borrow().pipeline.id == pipeline_id => { (true, events::move(layer.clone(), pipeline_id, layer_id, - point, - page_window, - device_pixels_per_page_px)) + device_point, + window_size)) } Some(_) | None => { self.fragment_point = Some(point); @@ -711,7 +708,7 @@ impl IOCompositor { MouseWindowMouseUpEvent(_, p) => p / scale, }; for layer in self.scene.root.iter() { - events::send_mouse_event(layer.clone(), mouse_window_event, point); + events::send_mouse_event(layer.clone(), mouse_window_event, point, scale); } } @@ -725,20 +722,14 @@ impl IOCompositor { fn on_scroll_window_event(&mut self, delta: TypedPoint2D, cursor: TypedPoint2D) { - let scale = self.device_pixels_per_page_px(); - // TODO: modify delta to snap scroll to pixels. - let page_delta = delta / scale; - let page_cursor = cursor.as_f32() / scale; - let page_window = self.page_window(); let mut scroll = false; - let device_pixels_per_page_px = self.device_pixels_per_page_px(); + let window_size = self.window_size.as_f32(); match self.scene.root { Some(ref mut layer) => { scroll = events::handle_scroll_event(layer.clone(), - page_delta, - page_cursor, - page_window, - device_pixels_per_page_px) || scroll; + delta, + cursor.as_f32(), + window_size) || scroll; } None => { } } @@ -775,7 +766,6 @@ impl IOCompositor { self.zoom_action = true; self.zoom_time = precise_time_s(); let old_viewport_zoom = self.viewport_zoom; - let window_size = self.window_size.as_f32(); self.viewport_zoom = ScaleFactor((self.viewport_zoom.get() * magnification).max(1.0)); let viewport_zoom = self.viewport_zoom; @@ -783,21 +773,19 @@ impl IOCompositor { self.update_zoom_transform(); // Scroll as needed - let page_delta = TypedPoint2D( + let window_size = self.window_size.as_f32(); + let page_delta: TypedPoint2D = TypedPoint2D( window_size.width.get() * (viewport_zoom.inv() - old_viewport_zoom.inv()).get() * 0.5, window_size.height.get() * (viewport_zoom.inv() - old_viewport_zoom.inv()).get() * 0.5); - // TODO: modify delta to snap scroll to pixels. - let page_cursor = TypedPoint2D(-1f32, -1f32); // Make sure this hits the base layer - let page_window = self.page_window(); - let device_pixels_per_page_px = self.device_pixels_per_page_px(); + let delta = page_delta * self.device_pixels_per_page_px(); + let cursor = TypedPoint2D(-1f32, -1f32); // Make sure this hits the base layer. match self.scene.root { Some(ref mut layer) => { events::handle_scroll_event(layer.clone(), - page_delta, - page_cursor, - page_window, - device_pixels_per_page_px); + delta, + cursor, + window_size); } None => { } } diff --git a/src/components/compositing/compositor_data.rs b/src/components/compositing/compositor_data.rs index 577afb3851f..62c915bd421 100644 --- a/src/components/compositing/compositor_data.rs +++ b/src/components/compositing/compositor_data.rs @@ -8,7 +8,6 @@ use pipeline::CompositionPipeline; use azure::azure_hl::Color; use geom::point::TypedPoint2D; -use geom::scale_factor::ScaleFactor; use geom::size::{Size2D, TypedSize2D}; use gfx::render_task::UnusedBufferMsg; use layers::layers::{Layer, LayerBufferSet}; @@ -16,7 +15,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 servo_util::geometry::DevicePixel; use std::rc::Rc; pub struct CompositorData { @@ -26,10 +25,6 @@ pub struct CompositorData { /// The ID of this layer within the pipeline. pub id: LayerId, - /// The offset of the page due to scrolling. (0,0) is when the window sees the - /// top left corner of the page. - pub scroll_offset: TypedPoint2D, - /// The behavior of this layer when a scroll message is received. pub wants_scroll_events: WantsScrollEventsFlag, @@ -59,7 +54,6 @@ impl CompositorData { let new_compositor_data = CompositorData { pipeline: pipeline, id: layer_properties.id, - scroll_offset: TypedPoint2D(0f32, 0f32), wants_scroll_events: wants_scroll_events, scroll_policy: layer_properties.scroll_policy, background_color: layer_properties.background_color, @@ -76,15 +70,12 @@ impl CompositorData { 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 - // scale factor does not matter here since we are scrolling to 0 offset and - // 0 * n == 0. - let size: TypedSize2D = Size2D::from_untyped(&layer.bounds.borrow().size); + // cursor position to make sure the scroll isn't propagated downwards. + let size: TypedSize2D = Size2D::from_untyped(&layer.bounds.borrow().size); events::handle_scroll_event(layer.clone(), TypedPoint2D(0f32, 0f32), TypedPoint2D(-1f32, -1f32), - size, - ScaleFactor(1.0)); + size); } pub fn find_layer_with_pipeline_and_layer_id(layer: Rc>, diff --git a/src/components/compositing/events.rs b/src/components/compositing/events.rs index 8ded49a5477..e4f57a3bb15 100644 --- a/src/components/compositing/events.rs +++ b/src/components/compositing/events.rs @@ -6,12 +6,10 @@ use compositor_data::{CompositorData, WantsScrollEvents}; use windowing::{MouseWindowEvent, MouseWindowClickEvent, MouseWindowMouseDownEvent}; use windowing::MouseWindowMouseUpEvent; -use geom::length::Length; -use geom::matrix::identity; use geom::point::{Point2D, TypedPoint2D}; use geom::rect::{Rect, TypedRect}; use geom::scale_factor::ScaleFactor; -use geom::size::TypedSize2D; +use geom::size::{Size2D, TypedSize2D}; use layers::layers::Layer; use script::dom::event::{ClickEvent, MouseDownEvent, MouseMoveEvent, MouseUpEvent}; use script::script_task::{ScriptChan, SendEventMsg}; @@ -20,6 +18,9 @@ use servo_msg::constellation_msg::PipelineId; use servo_util::geometry::{DevicePixel, PagePx}; use std::rc::Rc; + +use geom::matrix::identity; + trait Clampable { fn clamp(&self, mn: &Self, mx: &Self) -> Self; } @@ -43,10 +44,9 @@ impl Clampable for f32 { /// mouse is over child layers first. If a layer successfully scrolled, returns true; otherwise /// returns false, so a parent layer can scroll instead. pub fn handle_scroll_event(layer: Rc>, - delta: TypedPoint2D, - cursor: TypedPoint2D, - window_size: TypedSize2D, - page_to_device_pixels_scale: ScaleFactor) + delta: TypedPoint2D, + cursor: TypedPoint2D, + window_size: TypedSize2D) -> bool { // If this layer doesn't want scroll events, neither it nor its children can handle scroll // events. @@ -55,80 +55,80 @@ pub fn handle_scroll_event(layer: Rc>, } // Allow children to scroll. - let cursor = cursor - layer.extra_data.borrow().scroll_offset; + let content_offset: TypedPoint2D = + Point2D::from_untyped(&*layer.content_offset.borrow()); + let cursor = cursor - content_offset; for child in layer.children().iter() { - let rect: TypedRect = Rect::from_untyped(&*child.bounds.borrow()); + let rect: TypedRect = Rect::from_untyped(&*child.bounds.borrow()); if rect.contains(&cursor) && handle_scroll_event(child.clone(), delta, cursor - rect.origin, - rect.size, - page_to_device_pixels_scale) { + rect.size) { return true } } - // This scroll event is mine! - // Scroll this layer! - let old_origin = layer.extra_data.borrow().scroll_offset.clone(); - layer.extra_data.borrow_mut().scroll_offset = old_origin + delta; + clamp_scroll_offset_and_scroll_layer(layer, + content_offset.to_untyped() + delta.to_untyped(), + window_size.to_untyped()) - // bounds checking - let page_size = layer.bounds.borrow().size; - let window_size = window_size.to_untyped(); - let scroll_offset = layer.extra_data.borrow().scroll_offset.to_untyped(); +} - let min_x = (window_size.width - page_size.width).min(0.0); - layer.extra_data.borrow_mut().scroll_offset.x = Length(scroll_offset.x.clamp(&min_x, &0.0)); +pub fn clamp_scroll_offset_and_scroll_layer(layer: Rc>, + mut new_offset: Point2D, + window_size: Size2D) + -> bool { + let layer_size = layer.bounds.borrow().size; + let min_x = (window_size.width - layer_size.width).min(0.0); + new_offset.x = new_offset.x.clamp(&min_x, &0.0); - let min_y = (window_size.height - page_size.height).min(0.0); - layer.extra_data.borrow_mut().scroll_offset.y = Length(scroll_offset.y.clamp(&min_y, &0.0)); + let min_y = (window_size.height - layer_size.height).min(0.0); + new_offset.y = new_offset.y.clamp(&min_y, &0.0); - if old_origin - layer.extra_data.borrow().scroll_offset == TypedPoint2D(0f32, 0f32) { + if *layer.content_offset.borrow() == new_offset { return false } - let offset = layer.extra_data.borrow().scroll_offset.clone(); - scroll(layer.clone(), offset, page_to_device_pixels_scale) + // 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() = new_offset; + scroll_layer_and_all_child_layers(layer.clone(), new_offset) } -/// Actually scrolls the descendants of a layer that scroll. This is called by -/// `handle_scroll_event` above when it determines that a layer wants to scroll. -fn scroll(layer: Rc>, - scroll_offset: TypedPoint2D, - page_to_device_pixels_scale: ScaleFactor) - -> bool { +fn scroll_layer_and_all_child_layers(layer: Rc>, + new_offset: Point2D) + -> bool { let mut result = false; // Only scroll this layer if it's not fixed-positioned. if layer.extra_data.borrow().scroll_policy != FixedPosition { - // Scroll this layer! - layer.extra_data.borrow_mut().scroll_offset = scroll_offset; - - let scroll_offset = layer.extra_data.borrow().scroll_offset.clone(); - *layer.transform.borrow_mut() = identity().translate(scroll_offset.x.get(), scroll_offset.y.get(), 0.0); - *layer.content_offset.borrow_mut() = (scroll_offset * page_to_device_pixels_scale).to_untyped(); - + *layer.transform.borrow_mut() = identity().translate(new_offset.x, new_offset.y, 0.0); + *layer.content_offset.borrow_mut() = new_offset; result = true } for child in layer.children().iter() { - result = scroll(child.clone(), scroll_offset, page_to_device_pixels_scale) || result; + result |= scroll_layer_and_all_child_layers(child.clone(), new_offset); } - result + return result; } // Takes in a MouseWindowEvent, determines if it should be passed to children, and // sends the event off to the appropriate pipeline. NB: the cursor position is in // page coordinates. pub fn send_mouse_event(layer: Rc>, - event: MouseWindowEvent, cursor: TypedPoint2D) { - let cursor = cursor - layer.extra_data.borrow().scroll_offset; + event: MouseWindowEvent, + cursor: TypedPoint2D, + device_pixels_per_page_px: ScaleFactor) { + let content_offset : TypedPoint2D = + Point2D::from_untyped(&*layer.content_offset.borrow()); + let cursor = cursor - (content_offset / device_pixels_per_page_px); for child in layer.children().iter() { let rect: TypedRect = Rect::from_untyped(&*child.bounds.borrow()); if rect.contains(&cursor) { - send_mouse_event(child.clone(), event, cursor - rect.origin); + send_mouse_event(child.clone(), event, cursor - rect.origin, device_pixels_per_page_px); return; } } @@ -154,8 +154,7 @@ pub fn move(layer: Rc>, pipeline_id: PipelineId, layer_id: LayerId, origin: Point2D, - window_size: TypedSize2D, - page_to_device_pixels_scale: ScaleFactor) + window_size: TypedSize2D) -> bool { // Search children for the right layer to move. if layer.extra_data.borrow().pipeline.id != pipeline_id || @@ -165,8 +164,7 @@ pub fn move(layer: Rc>, pipeline_id, layer_id, origin, - window_size, - page_to_device_pixels_scale) + window_size) }); } @@ -174,25 +172,5 @@ pub fn move(layer: Rc>, return false } - // Scroll this layer! - let old_origin = layer.extra_data.borrow().scroll_offset; - layer.extra_data.borrow_mut().scroll_offset = Point2D::from_untyped(&(origin * -1.0)); - - // bounds checking - let page_size = layer.bounds.borrow().size; - let window_size = window_size.to_untyped(); - let scroll_offset = layer.extra_data.borrow().scroll_offset.to_untyped(); - - let min_x = (window_size.width - page_size.width).min(0.0); - layer.extra_data.borrow_mut().scroll_offset.x = Length(scroll_offset.x.clamp(&min_x, &0.0)); - let min_y = (window_size.height - page_size.height).min(0.0); - layer.extra_data.borrow_mut().scroll_offset.y = Length(scroll_offset.y.clamp(&min_y, &0.0)); - - // check to see if we scrolled - if old_origin - layer.extra_data.borrow().scroll_offset == TypedPoint2D(0f32, 0f32) { - return false; - } - - let offset = layer.extra_data.borrow().scroll_offset.clone(); - scroll(layer.clone(), offset, page_to_device_pixels_scale) + clamp_scroll_offset_and_scroll_layer(layer, origin * -1.0, window_size.to_untyped()) }