diff options
author | Martin Robinson <mrobinson@igalia.com> | 2017-09-30 15:50:47 +0200 |
---|---|---|
committer | Martin Robinson <mrobinson@igalia.com> | 2017-10-17 23:33:13 +0200 |
commit | b5d51dd2636935471447fc741ffbb95c62e37f94 (patch) | |
tree | d437a0a5114788c529692628729cdc3169ec4b2e /components/compositing | |
parent | 00e2a1c62a04ae337f9008dcea8e265edd2d3ef4 (diff) | |
download | servo-b5d51dd2636935471447fc741ffbb95c62e37f94.tar.gz servo-b5d51dd2636935471447fc741ffbb95c62e37f94.zip |
Switch to using WebRender hit testing
This trades quite a bit of complicated code in Servo for few more
messages and a significant performance improvement. In particular,
WebRender can search the entire display list at once instead of
ping-ponging down the pipeline tree. This allows us to send mouse
events to the correct pipeline immediately.
Diffstat (limited to 'components/compositing')
-rw-r--r-- | components/compositing/Cargo.toml | 1 | ||||
-rw-r--r-- | components/compositing/compositor.rs | 180 | ||||
-rw-r--r-- | components/compositing/compositor_thread.rs | 4 | ||||
-rw-r--r-- | components/compositing/lib.rs | 1 |
4 files changed, 102 insertions, 84 deletions
diff --git a/components/compositing/Cargo.toml b/components/compositing/Cargo.toml index 40ec9105448..56cdd8c1e4a 100644 --- a/components/compositing/Cargo.toml +++ b/components/compositing/Cargo.toml @@ -15,6 +15,7 @@ gfx_traits = {path = "../gfx_traits"} gleam = "0.4" image = "0.16" ipc-channel = "0.9" +libc = "0.2" log = "0.3.5" msg = {path = "../msg"} net_traits = {path = "../net_traits"} diff --git a/components/compositing/compositor.rs b/components/compositing/compositor.rs index a652346c794..92c8aff4719 100644 --- a/components/compositing/compositor.rs +++ b/components/compositing/compositor.rs @@ -6,20 +6,20 @@ use CompositionPipeline; use SendableFrameTree; use compositor_thread::{CompositorProxy, CompositorReceiver}; use compositor_thread::{InitialCompositorState, Msg, RenderListener}; -use euclid::{Point2D, TypedPoint2D, TypedVector2D, ScaleFactor}; +use euclid::{TypedPoint2D, TypedVector2D, ScaleFactor}; use gfx_traits::Epoch; use gleam::gl; use image::{DynamicImage, ImageFormat, RgbImage}; use ipc_channel::ipc::{self, IpcSharedMemory}; +use libc::c_void; use msg::constellation_msg::{PipelineId, PipelineIndex, PipelineNamespaceId}; use net_traits::image::base::{Image, PixelFormat}; use nonzero::NonZero; use profile_traits::time::{self, ProfilerCategory, profile}; -use script_traits::{AnimationState, AnimationTickType, ConstellationControlMsg}; -use script_traits::{ConstellationMsg, LayoutControlMsg, MouseButton}; -use script_traits::{MouseEventType, ScrollState}; -use script_traits::{TouchpadPressurePhase, TouchEventType, TouchId, WindowSizeData, WindowSizeType}; -use script_traits::CompositorEvent::{self, MouseMoveEvent, MouseButtonEvent, TouchEvent, TouchpadPressureEvent}; +use script_traits::{AnimationState, AnimationTickType, ConstellationMsg, LayoutControlMsg}; +use script_traits::{MouseButton, MouseEventType, ScrollState, TouchEventType, TouchId}; +use script_traits::{TouchpadPressurePhase, UntrustedNodeAddress, WindowSizeData, WindowSizeType}; +use script_traits::CompositorEvent::{MouseMoveEvent, MouseButtonEvent, TouchEvent, TouchpadPressureEvent}; use servo_config::opts; use servo_config::prefs::PREFS; use servo_geometry::DeviceIndependentPixel; @@ -29,12 +29,13 @@ use std::rc::Rc; use std::sync::mpsc::Sender; use std::time::{Duration, Instant}; use style_traits::{CSSPixel, DevicePixel, PinchZoomFactor}; +use style_traits::cursor::Cursor; use style_traits::viewport::ViewportConstraints; use time::{precise_time_ns, precise_time_s}; use touch::{TouchHandler, TouchAction}; use webrender; -use webrender_api::{self, ClipId, DeviceUintRect, DeviceUintSize, LayoutPoint, LayoutVector2D}; -use webrender_api::{ScrollEventPhase, ScrollLocation, ScrollClamping}; +use webrender_api::{self, DeviceUintRect, DeviceUintSize, HitTestFlags, HitTestResult}; +use webrender_api::{LayoutVector2D, ScrollEventPhase, ScrollLocation}; use windowing::{self, MouseWindowEvent, WebRenderDebugOption, WindowMethods}; #[derive(Debug, PartialEq)] @@ -464,11 +465,6 @@ impl<Window: WindowMethods> IOCompositor<Window> { self.send_viewport_rects(); } - (Msg::ScrollFragmentPoint(scroll_root_id, point, _), - ShutdownState::NotShuttingDown) => { - self.scroll_fragment_to_point(scroll_root_id, point); - } - (Msg::Recomposite(reason), ShutdownState::NotShuttingDown) => { self.composition_request = CompositionRequest::CompositeNow(reason) } @@ -656,13 +652,6 @@ impl<Window: WindowMethods> IOCompositor<Window> { } } - fn scroll_fragment_to_point(&mut self, id: ClipId, point: Point2D<f32>) { - self.webrender_api.scroll_node_with_id(self.webrender_document, - LayoutPoint::from_untyped(&point), - id, - ScrollClamping::ToContentBounds); - } - pub fn on_resize_window_event(&mut self, new_size: DeviceUintSize) { debug!("compositor resizing to {:?}", new_size.to_untyped()); @@ -707,32 +696,47 @@ impl<Window: WindowMethods> IOCompositor<Window> { MouseWindowEvent::MouseUp(_, p) => p, }; - let root_pipeline_id = match self.get_root_pipeline_id() { - Some(root_pipeline_id) => root_pipeline_id, + let results = self.hit_test_at_point(point); + let result = match results.items.first() { + Some(result) => result, None => return, }; - if let Some(pipeline) = self.pipeline(root_pipeline_id) { - let dppx = self.page_zoom * self.hidpi_factor(); - let translated_point = (point / dppx).to_untyped(); - let event_to_send = match mouse_window_event { - MouseWindowEvent::Click(button, _) => { - MouseButtonEvent(MouseEventType::Click, button, translated_point) - } - MouseWindowEvent::MouseDown(button, _) => { - MouseButtonEvent(MouseEventType::MouseDown, button, translated_point) - } - MouseWindowEvent::MouseUp(button, _) => { - MouseButtonEvent(MouseEventType::MouseUp, button, translated_point) - } - }; - let msg = ConstellationControlMsg::SendEvent(root_pipeline_id, event_to_send); - if let Err(e) = pipeline.script_chan.send(msg) { - warn!("Sending control event to script failed ({}).", e); + let point = result.point_in_viewport.to_untyped(); + let node_address = Some(UntrustedNodeAddress(result.tag.0 as *const c_void)); + let event_to_send = match mouse_window_event { + MouseWindowEvent::Click(button, _) => { + MouseButtonEvent(MouseEventType::Click, button, point, node_address) } + MouseWindowEvent::MouseDown(button, _) => { + MouseButtonEvent(MouseEventType::MouseDown, button, point, node_address) + } + MouseWindowEvent::MouseUp(button, _) => { + MouseButtonEvent(MouseEventType::MouseUp, button, point, node_address) + } + }; + + let pipeline_id = PipelineId::from_webrender(result.pipeline); + let msg = ConstellationMsg::ForwardEvent(pipeline_id, event_to_send); + if let Err(e) = self.constellation_chan.send(msg) { + warn!("Sending event to constellation failed ({}).", e); } } + fn hit_test_at_point(&self, point: TypedPoint2D<f32, DevicePixel>) -> HitTestResult { + let dppx = self.page_zoom * self.hidpi_factor(); + let scaled_point = (point / dppx).to_untyped(); + + let world_cursor = webrender_api::WorldPoint::from_untyped(&scaled_point); + self.webrender_api.hit_test( + self.webrender_document, + None, + world_cursor, + HitTestFlags::empty() + ) + + } + pub fn on_mouse_window_move_event_class(&mut self, cursor: TypedPoint2D<f32, DevicePixel>) { if opts::get().convert_mouse_to_touch { self.on_touch_move(TouchId(0), cursor); @@ -751,26 +755,43 @@ impl<Window: WindowMethods> IOCompositor<Window> { return; } - let dppx = self.page_zoom * self.hidpi_factor(); - let event_to_send = MouseMoveEvent(Some((cursor / dppx).to_untyped())); - let msg = ConstellationControlMsg::SendEvent(root_pipeline_id, event_to_send); - if let Some(pipeline) = self.pipeline(root_pipeline_id) { - if let Err(e) = pipeline.script_chan.send(msg) { - warn!("Sending mouse control event to script failed ({}).", e); + let results = self.hit_test_at_point(cursor); + if let Some(item) = results.items.first() { + let node_address = Some(UntrustedNodeAddress(item.tag.0 as *const c_void)); + let event = MouseMoveEvent(Some(item.point_in_viewport.to_untyped()), node_address); + let pipeline_id = PipelineId::from_webrender(item.pipeline); + let msg = ConstellationMsg::ForwardEvent(pipeline_id, event); + if let Err(e) = self.constellation_chan.send(msg) { + warn!("Sending event to constellation failed ({}).", e); + } + + if let Some(cursor) = Cursor::from_u8(item.tag.1).ok() { + let msg = ConstellationMsg::SetCursor(cursor); + if let Err(e) = self.constellation_chan.send(msg) { + warn!("Sending event to constellation failed ({}).", e); + } } } } - fn send_event_to_root_pipeline(&self, event: CompositorEvent) { - let root_pipeline_id = match self.get_root_pipeline_id() { - Some(root_pipeline_id) => root_pipeline_id, - None => return, - }; - - if let Some(pipeline) = self.pipeline(root_pipeline_id) { - let msg = ConstellationControlMsg::SendEvent(root_pipeline_id, event); - if let Err(e) = pipeline.script_chan.send(msg) { - warn!("Sending control event to script failed ({}).", e); + fn send_touch_event( + &self, + event_type: TouchEventType, + identifier: TouchId, + point: TypedPoint2D<f32, DevicePixel>) + { + let results = self.hit_test_at_point(point); + if let Some(item) = results.items.first() { + let event = TouchEvent( + event_type, + identifier, + item.point_in_viewport.to_untyped(), + Some(UntrustedNodeAddress(item.tag.0 as *const c_void)), + ); + let pipeline_id = PipelineId::from_webrender(item.pipeline); + let msg = ConstellationMsg::ForwardEvent(pipeline_id, event); + if let Err(e) = self.constellation_chan.send(msg) { + warn!("Sending event to constellation failed ({}).", e); } } } @@ -789,11 +810,7 @@ impl<Window: WindowMethods> IOCompositor<Window> { fn on_touch_down(&mut self, identifier: TouchId, point: TypedPoint2D<f32, DevicePixel>) { self.touch_handler.on_touch_down(identifier, point); - let dppx = self.page_zoom * self.hidpi_factor(); - let translated_point = (point / dppx).to_untyped(); - self.send_event_to_root_pipeline(TouchEvent(TouchEventType::Down, - identifier, - translated_point)); + self.send_touch_event(TouchEventType::Down, identifier, point); } fn on_touch_move(&mut self, identifier: TouchId, point: TypedPoint2D<f32, DevicePixel>) { @@ -821,22 +838,15 @@ impl<Window: WindowMethods> IOCompositor<Window> { }); } TouchAction::DispatchEvent => { - let dppx = self.page_zoom * self.hidpi_factor(); - let translated_point = (point / dppx).to_untyped(); - self.send_event_to_root_pipeline(TouchEvent(TouchEventType::Move, - identifier, - translated_point)); + self.send_touch_event(TouchEventType::Move, identifier, point); } _ => {} } } fn on_touch_up(&mut self, identifier: TouchId, point: TypedPoint2D<f32, DevicePixel>) { - let dppx = self.page_zoom * self.hidpi_factor(); - let translated_point = (point / dppx).to_untyped(); - self.send_event_to_root_pipeline(TouchEvent(TouchEventType::Up, - identifier, - translated_point)); + self.send_touch_event(TouchEventType::Up, identifier, point); + if let TouchAction::Click = self.touch_handler.on_touch_up(identifier, point) { self.simulate_mouse_click(point); } @@ -845,23 +855,31 @@ impl<Window: WindowMethods> IOCompositor<Window> { fn on_touch_cancel(&mut self, identifier: TouchId, point: TypedPoint2D<f32, DevicePixel>) { // Send the event to script. self.touch_handler.on_touch_cancel(identifier, point); - let dppx = self.page_zoom * self.hidpi_factor(); - let translated_point = (point / dppx).to_untyped(); - self.send_event_to_root_pipeline(TouchEvent(TouchEventType::Cancel, - identifier, - translated_point)); + self.send_touch_event(TouchEventType::Cancel, identifier, point); } pub fn on_touchpad_pressure_event(&self, point: TypedPoint2D<f32, DevicePixel>, pressure: f32, phase: TouchpadPressurePhase) { - if let Some(true) = PREFS.get("dom.forcetouch.enabled").as_boolean() { - let dppx = self.page_zoom * self.hidpi_factor(); - let translated_point = (point / dppx).to_untyped(); - self.send_event_to_root_pipeline(TouchpadPressureEvent(translated_point, - pressure, - phase)); + match PREFS.get("dom.forcetouch.enabled").as_boolean() { + Some(true) => {}, + _ => return, + } + + let results = self.hit_test_at_point(point); + if let Some(item) = results.items.first() { + let event = TouchpadPressureEvent( + item.point_in_viewport.to_untyped(), + pressure, + phase, + Some(UntrustedNodeAddress(item.tag.0 as *const c_void)), + ); + let pipeline_id = PipelineId::from_webrender(item.pipeline); + let msg = ConstellationMsg::ForwardEvent(pipeline_id, event); + if let Err(e) = self.constellation_chan.send(msg) { + warn!("Sending event to constellation failed ({}).", e); + } } } diff --git a/components/compositing/compositor_thread.rs b/components/compositing/compositor_thread.rs index 03a7b46c7c0..2fc1373da56 100644 --- a/components/compositing/compositor_thread.rs +++ b/components/compositing/compositor_thread.rs @@ -158,8 +158,6 @@ pub enum Msg { /// (e.g. SetFrameTree) at the time that we send it an ExitMsg. ShutdownComplete, - /// Scroll a page in a window - ScrollFragmentPoint(webrender_api::ClipId, Point2D<f32>, bool), /// Alerts the compositor that the given pipeline has changed whether it is running animations. ChangeRunningAnimationsState(PipelineId, AnimationState), /// Replaces the current frame tree, typically called during main frame navigation. @@ -195,6 +193,7 @@ pub enum Msg { PendingPaintMetric(PipelineId, Epoch), /// The load of a page has completed LoadComplete(TopLevelBrowsingContextId), + } impl Debug for Msg { @@ -202,7 +201,6 @@ impl Debug for Msg { match *self { Msg::Exit => write!(f, "Exit"), Msg::ShutdownComplete => write!(f, "ShutdownComplete"), - Msg::ScrollFragmentPoint(..) => write!(f, "ScrollFragmentPoint"), Msg::ChangeRunningAnimationsState(..) => write!(f, "ChangeRunningAnimationsState"), Msg::SetFrameTree(..) => write!(f, "SetFrameTree"), Msg::Recomposite(..) => write!(f, "Recomposite"), diff --git a/components/compositing/lib.rs b/components/compositing/lib.rs index b2abdcbf94d..82702dfb734 100644 --- a/components/compositing/lib.rs +++ b/components/compositing/lib.rs @@ -9,6 +9,7 @@ extern crate gfx_traits; extern crate gleam; extern crate image; extern crate ipc_channel; +extern crate libc; #[macro_use] extern crate log; extern crate msg; |