diff options
author | bors-servo <lbergstrom+bors@mozilla.com> | 2015-12-04 02:54:22 +0530 |
---|---|---|
committer | bors-servo <lbergstrom+bors@mozilla.com> | 2015-12-04 02:54:22 +0530 |
commit | bc62b5aadb62267582fbd65daa28438ce6c6ac9c (patch) | |
tree | 535a0f8a529fe0f76ee5b6e852a317b0f0d36203 /components/script/dom | |
parent | 5ee6fe120d43506e263cb4482b3a468d967a8386 (diff) | |
parent | 9551363bfba695b17c55cc551b87a6c0d16eb6a0 (diff) | |
download | servo-bc62b5aadb62267582fbd65daa28438ce6c6ac9c.tar.gz servo-bc62b5aadb62267582fbd65daa28438ce6c6ac9c.zip |
Auto merge of #8785 - mbrubeck:fixed-hit-test, r=pcwalton
Add slow path for hit testing of iframe behind positioned content layer
Fixes browser.html blocker #8759. r? @pcwalton
This adds a slow path for cases where the compositor's layer-based hit testing is incorrect. If the script task discovers that a mouse event should have been dispatched to an iframe, it bounces the event back to the constellation to be forwarded to the correct pipeline.
This isn't terribly slow (on the slow path, it adds one extra round-trip message between script and constellation), but if we want to optimize this better we could instead replace the compositor's layer hit testing with display list hit testing in the paint task. This would be a more complicated change that I think we should save for a follow-up.
This only fixes mouse input for now. A basically-identical change will be needed for touch-screen input, whether we stick with this approach or switch to the paint task.
<!-- Reviewable:start -->
[<img src="https://reviewable.io/review_button.png" height=40 alt="Review on Reviewable"/>](https://reviewable.io/reviews/servo/servo/8785)
<!-- Reviewable:end -->
Diffstat (limited to 'components/script/dom')
-rw-r--r-- | components/script/dom/document.rs | 51 | ||||
-rw-r--r-- | components/script/dom/htmliframeelement.rs | 5 |
2 files changed, 42 insertions, 14 deletions
diff --git a/components/script/dom/document.rs b/components/script/dom/document.rs index a30e923cee8..0e790188320 100644 --- a/components/script/dom/document.rs +++ b/components/script/dom/document.rs @@ -5,12 +5,15 @@ use document_loader::{DocumentLoader, LoadType}; use dom::attr::{Attr, AttrValue}; use dom::bindings::cell::DOMRefCell; +use dom::bindings::codegen::Bindings::DOMRectBinding::DOMRectMethods; use dom::bindings::codegen::Bindings::DocumentBinding; use dom::bindings::codegen::Bindings::DocumentBinding::{DocumentMethods, DocumentReadyState}; +use dom::bindings::codegen::Bindings::ElementBinding::ElementMethods; use dom::bindings::codegen::Bindings::EventBinding::EventMethods; use dom::bindings::codegen::Bindings::EventHandlerBinding::EventHandlerNonNull; use dom::bindings::codegen::Bindings::EventHandlerBinding::OnErrorEventHandlerNonNull; use dom::bindings::codegen::Bindings::EventTargetBinding::EventTargetMethods; +use dom::bindings::codegen::Bindings::HTMLIFrameElementBinding::HTMLIFrameElementMethods; use dom::bindings::codegen::Bindings::NodeBinding::NodeMethods; use dom::bindings::codegen::Bindings::NodeFilterBinding::NodeFilter; use dom::bindings::codegen::Bindings::PerformanceBinding::PerformanceMethods; @@ -82,13 +85,14 @@ use msg::compositor_msg::ScriptToCompositorMsg; use msg::constellation_msg::ScriptMsg as ConstellationMsg; use msg::constellation_msg::{ALT, CONTROL, SHIFT, SUPER}; use msg::constellation_msg::{AnimationState, PipelineId}; -use msg::constellation_msg::{ConstellationChan, FocusType, Key, KeyModifiers, KeyState, MozBrowserEvent, SubpageId}; +use msg::constellation_msg::{ConstellationChan, FocusType, Key, KeyModifiers, KeyState}; +use msg::constellation_msg::{MouseButton, MouseEventType, MozBrowserEvent, SubpageId}; use net_traits::ControlMsg::{GetCookiesForUrl, SetCookiesForUrl}; use net_traits::CookieSource::NonHTTP; use net_traits::{AsyncResponseTarget, PendingAsyncLoad}; use num::ToPrimitive; use script_task::{MainThreadScriptMsg, Runnable}; -use script_traits::{MouseButton, TouchEventType, TouchId, UntrustedNodeAddress}; +use script_traits::{TouchEventType, TouchId, UntrustedNodeAddress}; use std::ascii::AsciiExt; use std::borrow::ToOwned; use std::boxed::FnBox; @@ -603,7 +607,7 @@ impl Document { pub fn handle_mouse_event(&self, js_runtime: *mut JSRuntime, - _button: MouseButton, + button: MouseButton, client_point: Point2D<f32>, mouse_event_type: MouseEventType) { let mouse_event_type_string = match mouse_event_type { @@ -634,6 +638,21 @@ impl Document { }, }; + // If the target is an iframe, forward the event to the child document. + if let Some(iframe) = el.downcast::<HTMLIFrameElement>() { + if let Some(pipeline_id) = iframe.pipeline_id() { + let rect = iframe.upcast::<Element>().GetBoundingClientRect(); + let child_origin = Point2D::new(rect.X() as f32, rect.Y() as f32); + let child_point = client_point - child_origin; + + let event = ConstellationMsg::ForwardMouseButtonEvent(pipeline_id, + mouse_event_type, + button, child_point); + self.window.constellation_chan().0.send(event).unwrap(); + } + return; + } + let node = el.upcast::<Node>(); debug!("{} on {:?}", mouse_event_type_string, node.debug_str()); // Prevent click event if form control element is disabled. @@ -766,11 +785,23 @@ impl Document { if mouse_over_addresses.len() > 0 { let top_most_node = node::from_untrusted_node_address(js_runtime, mouse_over_addresses[0]); + let client_point = client_point.unwrap(); // Must succeed because hit test succeeded. - let target = top_most_node.upcast(); - if let Some(client_point) = client_point { - self.fire_mouse_event(client_point, target, "mousemove".to_owned()); + // If the target is an iframe, forward the event to the child document. + if let Some(iframe) = top_most_node.downcast::<HTMLIFrameElement>() { + if let Some(pipeline_id) = iframe.pipeline_id() { + let rect = iframe.upcast::<Element>().GetBoundingClientRect(); + let child_origin = Point2D::new(rect.X() as f32, rect.Y() as f32); + let child_point = client_point - child_origin; + + let event = ConstellationMsg::ForwardMouseMoveEvent(pipeline_id, child_point); + self.window.constellation_chan().0.send(event).unwrap(); + } + return; } + + let target = top_most_node.upcast(); + self.fire_mouse_event(client_point, target, "mousemove".to_owned()); } // Store the current mouse over targets for next frame @@ -1362,14 +1393,6 @@ impl Document { } } -#[derive(HeapSizeOf)] -pub enum MouseEventType { - Click, - MouseDown, - MouseUp, -} - - #[derive(PartialEq, HeapSizeOf)] pub enum DocumentSource { FromParser, diff --git a/components/script/dom/htmliframeelement.rs b/components/script/dom/htmliframeelement.rs index 4c7f7276ca7..3798ab4f539 100644 --- a/components/script/dom/htmliframeelement.rs +++ b/components/script/dom/htmliframeelement.rs @@ -186,6 +186,11 @@ impl HTMLIFrameElement { } #[inline] + pub fn pipeline_id(&self) -> Option<PipelineId> { + self.pipeline_id.get() + } + + #[inline] pub fn subpage_id(&self) -> Option<SubpageId> { self.subpage_id.get() } |