mirror of
https://github.com/servo/servo.git
synced 2025-07-23 07:13:52 +01:00
If a mouse event is targeting an iframe, forward it to the iframe's inner window
Fixes #8759. This adds a slow path for cases where the compositor's layer-based hit testing is incorrect. To optimize for this case, we could instead replace the layer hit testing with display-list hit testing done in the paint task.
This commit is contained in:
parent
8c4fed42b0
commit
9551363bfb
4 changed files with 57 additions and 4 deletions
|
@ -613,6 +613,19 @@ impl<LTF: LayoutTaskFactory, STF: ScriptTaskFactory> Constellation<LTF, STF> {
|
|||
debug!("constellation got focus message");
|
||||
self.handle_focus_msg(pipeline_id);
|
||||
}
|
||||
Request::Script(FromScriptMsg::ForwardMouseButtonEvent(
|
||||
pipeline_id, event_type, button, point)) => {
|
||||
if let Some(pipeline) = self.pipelines.get(&pipeline_id) {
|
||||
pipeline.script_chan.send(ConstellationControlMsg::SendEvent(pipeline_id,
|
||||
CompositorEvent::MouseButtonEvent(event_type, button, point)));
|
||||
}
|
||||
}
|
||||
Request::Script(FromScriptMsg::ForwardMouseMoveEvent(pipeline_id, point)) => {
|
||||
if let Some(pipeline) = self.pipelines.get(&pipeline_id) {
|
||||
pipeline.script_chan.send(ConstellationControlMsg::SendEvent(pipeline_id,
|
||||
CompositorEvent::MouseMoveEvent(Some(point))));
|
||||
}
|
||||
}
|
||||
Request::Script(FromScriptMsg::GetClipboardContents(sender)) => {
|
||||
let result = self.clipboard_ctx.as_ref().map_or(
|
||||
"".to_owned(),
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
|
||||
use canvas_traits::CanvasMsg;
|
||||
use compositor_msg::Epoch;
|
||||
use euclid::point::Point2D;
|
||||
use euclid::scale_factor::ScaleFactor;
|
||||
use euclid::size::{Size2D, TypedSize2D};
|
||||
use hyper::header::Headers;
|
||||
|
@ -283,6 +284,10 @@ pub enum ScriptMsg {
|
|||
Failure(Failure),
|
||||
/// Notifies the constellation that this frame has received focus.
|
||||
Focus(PipelineId),
|
||||
/// Re-send a mouse button event that was sent to the parent window.
|
||||
ForwardMouseButtonEvent(PipelineId, MouseEventType, MouseButton, Point2D<f32>),
|
||||
/// Re-send a mouse move event that was sent to the parent window.
|
||||
ForwardMouseMoveEvent(PipelineId, Point2D<f32>),
|
||||
/// Requests that the constellation retrieve the current contents of the clipboard
|
||||
GetClipboardContents(IpcSender<String>),
|
||||
/// <head> tag finished parsing
|
||||
|
|
|
@ -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;
|
||||
|
@ -604,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 {
|
||||
|
@ -635,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.
|
||||
|
@ -767,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.
|
||||
|
||||
// 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();
|
||||
if let Some(client_point) = client_point {
|
||||
self.fire_mouse_event(client_point, target, "mousemove".to_owned());
|
||||
}
|
||||
self.fire_mouse_event(client_point, target, "mousemove".to_owned());
|
||||
}
|
||||
|
||||
// Store the current mouse over targets for next frame
|
||||
|
|
|
@ -185,6 +185,11 @@ impl HTMLIFrameElement {
|
|||
self.containing_page_pipeline_id.get()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn pipeline_id(&self) -> Option<PipelineId> {
|
||||
self.pipeline_id.get()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn subpage_id(&self) -> Option<SubpageId> {
|
||||
self.subpage_id.get()
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue