aboutsummaryrefslogtreecommitdiffstats
path: root/components/script
diff options
context:
space:
mode:
Diffstat (limited to 'components/script')
-rw-r--r--components/script/dom/document.rs227
-rw-r--r--components/script/dom/window.rs38
-rw-r--r--components/script/script_thread.rs73
3 files changed, 137 insertions, 201 deletions
diff --git a/components/script/dom/document.rs b/components/script/dom/document.rs
index b04b681afca..fd8bf37a897 100644
--- a/components/script/dom/document.rs
+++ b/components/script/dom/document.rs
@@ -10,10 +10,8 @@ use dom::attr::Attr;
use dom::beforeunloadevent::BeforeUnloadEvent;
use dom::bindings::callback::ExceptionHandling;
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, ElementCreationOptions};
-use dom::bindings::codegen::Bindings::ElementBinding::ElementMethods;
use dom::bindings::codegen::Bindings::HTMLIFrameElementBinding::HTMLIFrameElementBinding::HTMLIFrameElementMethods;
use dom::bindings::codegen::Bindings::NodeBinding::NodeMethods;
use dom::bindings::codegen::Bindings::NodeFilterBinding::NodeFilter;
@@ -94,7 +92,7 @@ use dom::windowproxy::WindowProxy;
use dom_struct::dom_struct;
use encoding::EncodingRef;
use encoding::all::UTF_8;
-use euclid::{Point2D, Vector2D};
+use euclid::Point2D;
use html5ever::{LocalName, Namespace, QualName};
use hyper::header::{Header, SetCookie};
use hyper_serde::Serde;
@@ -110,14 +108,12 @@ use net_traits::pub_domains::is_pub_domain;
use net_traits::request::RequestInit;
use net_traits::response::HttpsState;
use num_traits::ToPrimitive;
-use script_layout_interface::message::{Msg, ReflowGoal};
+use script_layout_interface::message::{Msg, NodesFromPointQueryType, ReflowGoal};
use script_runtime::{CommonScriptMsg, ScriptThreadEventCategory};
use script_thread::{MainThreadScriptMsg, ScriptThread};
-use script_traits::{AnimationState, CompositorEvent, DocumentActivity};
-use script_traits::{MouseButton, MouseEventType, MozBrowserEvent};
-use script_traits::{MsDuration, ScriptMsg, TouchpadPressurePhase};
-use script_traits::{TouchEventType, TouchId};
-use script_traits::UntrustedNodeAddress;
+use script_traits::{AnimationState, DocumentActivity, MouseButton, MouseEventType};
+use script_traits::{MozBrowserEvent, MsDuration, ScriptMsg, TouchEventType, TouchId};
+use script_traits::{TouchpadPressurePhase, UntrustedNodeAddress};
use servo_arc::Arc;
use servo_atoms::Atom;
use servo_config::prefs::PREFS;
@@ -834,11 +830,14 @@ impl Document {
}
#[allow(unsafe_code)]
- pub fn handle_mouse_event(&self,
- js_runtime: *mut JSRuntime,
- button: MouseButton,
- client_point: Point2D<f32>,
- mouse_event_type: MouseEventType) {
+ pub fn handle_mouse_event(
+ &self,
+ js_runtime: *mut JSRuntime,
+ _button: MouseButton,
+ client_point: Point2D<f32>,
+ mouse_event_type: MouseEventType,
+ node_address: Option<UntrustedNodeAddress>
+ ) {
let mouse_event_type_string = match mouse_event_type {
MouseEventType::Click => "click".to_owned(),
MouseEventType::MouseUp => "mouseup".to_owned(),
@@ -846,41 +845,17 @@ impl Document {
};
debug!("{}: at {:?}", mouse_event_type_string, client_point);
- let node = match self.window.hit_test_query(client_point, false) {
- Some(node_address) => {
- debug!("node address is {:?}", node_address);
- unsafe {
- node::from_untrusted_node_address(js_runtime, node_address)
- }
- },
+ let el = node_address.and_then(|address| {
+ let node = unsafe { node::from_untrusted_node_address(js_runtime, address) };
+ node.inclusive_ancestors()
+ .filter_map(DomRoot::downcast::<Element>)
+ .next()
+ });
+ let el = match el {
+ Some(el) => el,
None => return,
};
- let el = match node.downcast::<Element>() {
- Some(el) => DomRoot::from_ref(el),
- None => {
- let parent = node.GetParentNode();
- match parent.and_then(DomRoot::downcast::<Element>) {
- Some(parent) => parent,
- None => return,
- }
- },
- };
-
- // 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 = Vector2D::new(rect.X() as f32, rect.Y() as f32);
- let child_point = client_point - child_origin;
-
- let event = CompositorEvent::MouseButtonEvent(mouse_event_type, button, child_point);
- let event = ScriptMsg::ForwardEvent(pipeline_id, event);
- self.send_to_constellation(event);
- }
- return;
- }
-
let node = el.upcast::<Node>();
debug!("{} on {:?}", mouse_event_type_string, node.debug_str());
// Prevent click event if form control element is disabled.
@@ -997,45 +972,24 @@ impl Document {
}
#[allow(unsafe_code)]
- pub fn handle_touchpad_pressure_event(&self,
- js_runtime: *mut JSRuntime,
- client_point: Point2D<f32>,
- pressure: f32,
- phase_now: TouchpadPressurePhase) {
- let node = match self.window.hit_test_query(client_point, false) {
- Some(node_address) => unsafe {
- node::from_untrusted_node_address(js_runtime, node_address)
- },
- None => return
- };
-
- let el = match node.downcast::<Element>() {
- Some(el) => DomRoot::from_ref(el),
- None => {
- let parent = node.GetParentNode();
- match parent.and_then(DomRoot::downcast::<Element>) {
- Some(parent) => parent,
- None => return
- }
- },
+ pub fn handle_touchpad_pressure_event(
+ &self,
+ js_runtime: *mut JSRuntime,
+ pressure: f32,
+ phase_now: TouchpadPressurePhase,
+ node_address: Option<UntrustedNodeAddress>
+ ) {
+ let el = node_address.and_then(|address| {
+ let node = unsafe { node::from_untrusted_node_address(js_runtime, address) };
+ node.inclusive_ancestors()
+ .filter_map(DomRoot::downcast::<Element>)
+ .next()
+ });
+ let el = match el {
+ Some(el) => el,
+ None => return,
};
- // 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 = Vector2D::new(rect.X() as f32, rect.Y() as f32);
- let child_point = client_point - child_origin;
-
- let event = CompositorEvent::TouchpadPressureEvent(child_point,
- pressure,
- phase_now);
- let event = ScriptMsg::ForwardEvent(pipeline_id, event);
- self.send_to_constellation(event);
- }
- return;
- }
-
let phase_before = self.touchpad_pressure_phase.get();
self.touchpad_pressure_phase.set(phase_now);
@@ -1101,10 +1055,13 @@ impl Document {
}
#[allow(unsafe_code)]
- pub fn handle_mouse_move_event(&self,
- js_runtime: *mut JSRuntime,
- client_point: Option<Point2D<f32>>,
- prev_mouse_over_target: &MutNullableDom<Element>) {
+ pub fn handle_mouse_move_event(
+ &self,
+ js_runtime: *mut JSRuntime,
+ client_point: Option<Point2D<f32>>,
+ prev_mouse_over_target: &MutNullableDom<Element>,
+ node_address: Option<UntrustedNodeAddress>
+ ) {
let client_point = match client_point {
None => {
// If there's no point, there's no target under the mouse
@@ -1115,31 +1072,21 @@ impl Document {
Some(client_point) => client_point,
};
- let maybe_new_target = self.window.hit_test_query(client_point, true).and_then(|address| {
+ let maybe_new_target = node_address.and_then(|address| {
let node = unsafe { node::from_untrusted_node_address(js_runtime, address) };
node.inclusive_ancestors()
.filter_map(DomRoot::downcast::<Element>)
.next()
});
- // Send mousemove event to topmost target, and forward it if it's an iframe
- if let Some(ref new_target) = maybe_new_target {
- // If the target is an iframe, forward the event to the child document.
- if let Some(iframe) = new_target.downcast::<HTMLIFrameElement>() {
- if let Some(pipeline_id) = iframe.pipeline_id() {
- let rect = iframe.upcast::<Element>().GetBoundingClientRect();
- let child_origin = Vector2D::new(rect.X() as f32, rect.Y() as f32);
- let child_point = client_point - child_origin;
-
- let event = CompositorEvent::MouseMoveEvent(Some(child_point));
- let event = ScriptMsg::ForwardEvent(pipeline_id, event);
- self.send_to_constellation(event);
- }
- return;
- }
+ // Send mousemove event to topmost target, unless it's an iframe, in which case the
+ // compositor should have also sent an event to the inner document.
+ let new_target = match maybe_new_target {
+ Some(ref target) => target,
+ None => return,
+ };
- self.fire_mouse_event(client_point, new_target.upcast(), "mousemove".to_owned());
- }
+ self.fire_mouse_event(client_point, new_target.upcast(), "mousemove".to_owned());
// Nothing more to do here, mousemove is sent,
// and the element under the mouse hasn't changed.
@@ -1197,12 +1144,14 @@ impl Document {
}
#[allow(unsafe_code)]
- pub fn handle_touch_event(&self,
- js_runtime: *mut JSRuntime,
- event_type: TouchEventType,
- touch_id: TouchId,
- point: Point2D<f32>)
- -> TouchEventResult {
+ pub fn handle_touch_event(
+ &self,
+ js_runtime: *mut JSRuntime,
+ event_type: TouchEventType,
+ touch_id: TouchId,
+ point: Point2D<f32>,
+ node_address: Option<UntrustedNodeAddress>
+ ) -> TouchEventResult {
let TouchId(identifier) = touch_id;
let event_name = match event_type {
@@ -1212,37 +1161,17 @@ impl Document {
TouchEventType::Cancel => "touchcancel",
};
- let node = match self.window.hit_test_query(point, false) {
- Some(node_address) => unsafe {
- node::from_untrusted_node_address(js_runtime, node_address)
- },
- None => return TouchEventResult::Processed(false),
- };
- let el = match node.downcast::<Element>() {
- Some(el) => DomRoot::from_ref(el),
- None => {
- let parent = node.GetParentNode();
- match parent.and_then(DomRoot::downcast::<Element>) {
- Some(parent) => parent,
- None => return TouchEventResult::Processed(false),
- }
- },
+ let el = node_address.and_then(|address| {
+ let node = unsafe { node::from_untrusted_node_address(js_runtime, address) };
+ node.inclusive_ancestors()
+ .filter_map(DomRoot::downcast::<Element>)
+ .next()
+ });
+ let el = match el {
+ Some(el) => el,
+ None => return TouchEventResult::Forwarded,
};
- // 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 = Vector2D::new(rect.X() as f32, rect.Y() as f32);
- let child_point = point - child_origin;
-
- let event = CompositorEvent::TouchEvent(event_type, touch_id, child_point);
- let event = ScriptMsg::ForwardEvent(pipeline_id, event);
- self.send_to_constellation(event);
- }
- return TouchEventResult::Forwarded;
- }
-
let target = DomRoot::upcast::<EventTarget>(el);
let window = &*self.window;
@@ -2005,8 +1934,12 @@ impl Document {
!self.has_browsing_context || !url_has_network_scheme(&self.url())
}
- pub fn nodes_from_point(&self, client_point: &Point2D<f32>) -> Vec<UntrustedNodeAddress> {
- if !self.window.reflow(ReflowGoal::NodesFromPoint(*client_point), ReflowReason::Query) {
+ pub fn nodes_from_point(&self,
+ client_point: &Point2D<f32>,
+ reflow_goal: NodesFromPointQueryType)
+ -> Vec<UntrustedNodeAddress> {
+ if !self.window.reflow(ReflowGoal::NodesFromPointQuery(*client_point, reflow_goal),
+ ReflowReason::Query) {
return vec!();
};
@@ -3662,12 +3595,11 @@ impl DocumentMethods for Document {
return None;
}
- match self.window.hit_test_query(*point, false) {
- Some(untrusted_node_address) => {
+ match self.nodes_from_point(point, NodesFromPointQueryType::Topmost).first() {
+ Some(address) => {
let js_runtime = unsafe { JS_GetRuntime(window.get_cx()) };
-
let node = unsafe {
- node::from_untrusted_node_address(js_runtime, untrusted_node_address)
+ node::from_untrusted_node_address(js_runtime, *address)
};
let parent_node = node.GetParentNode().unwrap();
let element_ref = node.downcast::<Element>().unwrap_or_else(|| {
@@ -3701,7 +3633,8 @@ impl DocumentMethods for Document {
let js_runtime = unsafe { JS_GetRuntime(window.get_cx()) };
// Step 1 and Step 3
- let mut elements: Vec<DomRoot<Element>> = self.nodes_from_point(point).iter()
+ let nodes = self.nodes_from_point(point, NodesFromPointQueryType::All);
+ let mut elements: Vec<DomRoot<Element>> = nodes.iter()
.flat_map(|&untrusted_node_address| {
let node = unsafe {
node::from_untrusted_node_address(js_runtime, untrusted_node_address)
diff --git a/components/script/dom/window.rs b/components/script/dom/window.rs
index b076b3f9941..9d2137911d7 100644
--- a/components/script/dom/window.rs
+++ b/components/script/dom/window.rs
@@ -1149,28 +1149,15 @@ impl Window {
x: f32,
y: f32,
scroll_root_id: ClipId,
- behavior: ScrollBehavior,
- element: Option<&Element>) {
- //TODO Step 1
- let point = Point2D::new(x, y);
- let smooth = match behavior {
- ScrollBehavior::Auto => {
- element.map_or(false, |_element| {
- // TODO check computed scroll-behaviour CSS property
- true
- })
- }
- ScrollBehavior::Instant => false,
- ScrollBehavior::Smooth => true
- };
-
+ _behavior: ScrollBehavior,
+ _element: Option<&Element>) {
+ // TODO Step 1
+ // TODO(mrobinson, #18709): Add smooth scrolling support to WebRender so that we can
+ // properly process ScrollBehavior here.
self.layout_chan.send(Msg::UpdateScrollStateFromScript(ScrollState {
scroll_root_id: scroll_root_id,
scroll_offset: Vector2D::new(-x, -y),
})).unwrap();
-
- let message = ScriptMsg::ScrollFragmentPoint(scroll_root_id, point, smooth);
- self.send_to_constellation(message);
}
pub fn update_viewport_for_scroll(&self, x: f32, y: f32) {
@@ -1406,18 +1393,6 @@ impl Window {
self.layout_rpc.node_geometry().client_rect
}
- pub fn hit_test_query(&self,
- client_point: Point2D<f32>,
- update_cursor: bool)
- -> Option<UntrustedNodeAddress> {
- if !self.reflow(ReflowGoal::HitTestQuery(client_point, update_cursor),
- ReflowReason::Query) {
- return None
- }
-
- self.layout_rpc.hit_test().node_address
- }
-
pub fn scroll_area_query(&self, node: TrustedNodeAddress) -> Rect<i32> {
if !self.reflow(ReflowGoal::NodeScrollGeometryQuery(node), ReflowReason::Query) {
return Rect::zero();
@@ -1910,8 +1885,7 @@ fn debug_reflow_events(id: PipelineId, reflow_goal: &ReflowGoal, reason: &Reflow
ReflowGoal::Full => "\tFull",
ReflowGoal::ContentBoxQuery(_n) => "\tContentBoxQuery",
ReflowGoal::ContentBoxesQuery(_n) => "\tContentBoxesQuery",
- ReflowGoal::HitTestQuery(..) => "\tHitTestQuery",
- ReflowGoal::NodesFromPoint(..) => "\tNodesFromPoint",
+ ReflowGoal::NodesFromPointQuery(..) => "\tNodesFromPointQuery",
ReflowGoal::NodeGeometryQuery(_n) => "\tNodeGeometryQuery",
ReflowGoal::NodeOverflowQuery(_n) => "\tNodeOverFlowQuery",
ReflowGoal::NodeScrollGeometryQuery(_n) => "\tNodeScrollGeometryQuery",
diff --git a/components/script/script_thread.rs b/components/script/script_thread.rs
index 2e7ad6aad18..1413a0c40dc 100644
--- a/components/script/script_thread.rs
+++ b/components/script/script_thread.rs
@@ -1010,7 +1010,7 @@ impl ScriptThread {
}
FromConstellation(ConstellationControlMsg::SendEvent(
_,
- MouseMoveEvent(_))) => {
+ MouseMoveEvent(..))) => {
match mouse_move_event_index {
None => {
mouse_move_event_index = Some(sequential.len());
@@ -2187,11 +2187,11 @@ impl ScriptThread {
self.handle_resize_event(pipeline_id, new_size, size_type);
}
- MouseButtonEvent(event_type, button, point) => {
- self.handle_mouse_event(pipeline_id, event_type, button, point);
+ MouseButtonEvent(event_type, button, point, node_address) => {
+ self.handle_mouse_event(pipeline_id, event_type, button, point, node_address);
}
- MouseMoveEvent(point) => {
+ MouseMoveEvent(point, node_address) => {
let document = match { self.documents.borrow().find_document(pipeline_id) } {
Some(document) => document,
None => return warn!("Message sent to closed pipeline {}.", pipeline_id),
@@ -2201,7 +2201,8 @@ impl ScriptThread {
let prev_mouse_over_target = self.topmost_mouse_over_target.get();
document.handle_mouse_move_event(self.js_runtime.rt(), point,
- &self.topmost_mouse_over_target);
+ &self.topmost_mouse_over_target,
+ node_address);
// Short-circuit if nothing changed
if self.topmost_mouse_over_target.get() == prev_mouse_over_target {
@@ -2244,8 +2245,14 @@ impl ScriptThread {
}
}
}
- TouchEvent(event_type, identifier, point) => {
- let touch_result = self.handle_touch_event(pipeline_id, event_type, identifier, point);
+ TouchEvent(event_type, identifier, point, node_address) => {
+ let touch_result = self.handle_touch_event(
+ pipeline_id,
+ event_type,
+ identifier,
+ point,
+ node_address
+ );
match (event_type, touch_result) {
(TouchEventType::Down, TouchEventResult::Processed(handled)) => {
let result = if handled {
@@ -2263,12 +2270,17 @@ impl ScriptThread {
}
}
- TouchpadPressureEvent(point, pressure, phase) => {
+ TouchpadPressureEvent(_point, pressure, phase, node_address) => {
let doc = match { self.documents.borrow().find_document(pipeline_id) } {
Some(doc) => doc,
None => return warn!("Message sent to closed pipeline {}.", pipeline_id),
};
- doc.handle_touchpad_pressure_event(self.js_runtime.rt(), point, pressure, phase);
+ doc.handle_touchpad_pressure_event(
+ self.js_runtime.rt(),
+ pressure,
+ phase,
+ node_address
+ );
}
KeyEvent(ch, key, state, modifiers) => {
@@ -2281,24 +2293,35 @@ impl ScriptThread {
}
}
- fn handle_mouse_event(&self,
- pipeline_id: PipelineId,
- mouse_event_type: MouseEventType,
- button: MouseButton,
- point: Point2D<f32>) {
+ fn handle_mouse_event(
+ &self,
+ pipeline_id: PipelineId,
+ mouse_event_type: MouseEventType,
+ button: MouseButton,
+ point: Point2D<f32>,
+ node_address: Option<UntrustedNodeAddress>
+ ) {
let document = match { self.documents.borrow().find_document(pipeline_id) } {
Some(document) => document,
None => return warn!("Message sent to closed pipeline {}.", pipeline_id),
};
- document.handle_mouse_event(self.js_runtime.rt(), button, point, mouse_event_type);
+ document.handle_mouse_event(
+ self.js_runtime.rt(),
+ button,
+ point,
+ mouse_event_type,
+ node_address
+ );
}
- fn handle_touch_event(&self,
- pipeline_id: PipelineId,
- event_type: TouchEventType,
- identifier: TouchId,
- point: Point2D<f32>)
- -> TouchEventResult {
+ fn handle_touch_event(
+ &self,
+ pipeline_id: PipelineId,
+ event_type: TouchEventType,
+ identifier: TouchId,
+ point: Point2D<f32>,
+ node_address: Option<UntrustedNodeAddress>
+ ) -> TouchEventResult {
let document = match { self.documents.borrow().find_document(pipeline_id) } {
Some(document) => document,
None => {
@@ -2306,7 +2329,13 @@ impl ScriptThread {
return TouchEventResult::Processed(true);
},
};
- document.handle_touch_event(self.js_runtime.rt(), event_type, identifier, point)
+ document.handle_touch_event(
+ self.js_runtime.rt(),
+ event_type,
+ identifier,
+ point,
+ node_address
+ )
}
/// <https://html.spec.whatwg.org/multipage/#navigating-across-documents>