diff options
Diffstat (limited to 'components/script')
-rw-r--r-- | components/script/dom/document.rs | 26 | ||||
-rw-r--r-- | components/script/dom/node.rs | 18 | ||||
-rw-r--r-- | components/script/dom/window.rs | 23 | ||||
-rw-r--r-- | components/script/script_thread.rs | 49 |
4 files changed, 83 insertions, 33 deletions
diff --git a/components/script/dom/document.rs b/components/script/dom/document.rs index 2f0d9dcfde3..bce898e6347 100644 --- a/components/script/dom/document.rs +++ b/components/script/dom/document.rs @@ -826,6 +826,7 @@ impl Document { } } + #[allow(unsafe_code)] pub fn handle_mouse_event(&self, js_runtime: *mut JSRuntime, button: MouseButton, @@ -841,7 +842,9 @@ impl Document { let node = match self.window.hit_test_query(client_point, false) { Some(node_address) => { debug!("node address is {:?}", node_address); - node::from_untrusted_node_address(js_runtime, node_address) + unsafe { + node::from_untrusted_node_address(js_runtime, node_address) + } }, None => return, }; @@ -988,13 +991,16 @@ impl Document { *self.last_click_info.borrow_mut() = Some((now, click_pos)); } + #[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) => node::from_untrusted_node_address(js_runtime, node_address), + Some(node_address) => unsafe { + node::from_untrusted_node_address(js_runtime, node_address) + }, None => return }; @@ -1089,6 +1095,7 @@ impl Document { event.fire(target); } + #[allow(unsafe_code)] pub fn handle_mouse_move_event(&self, js_runtime: *mut JSRuntime, client_point: Option<Point2D<f32>>, @@ -1104,7 +1111,7 @@ impl Document { }; let maybe_new_target = self.window.hit_test_query(client_point, true).and_then(|address| { - let node = node::from_untrusted_node_address(js_runtime, address); + let node = unsafe { node::from_untrusted_node_address(js_runtime, address) }; node.inclusive_ancestors() .filter_map(Root::downcast::<Element>) .next() @@ -1186,6 +1193,7 @@ impl Document { ReflowReason::MouseEvent); } + #[allow(unsafe_code)] pub fn handle_touch_event(&self, js_runtime: *mut JSRuntime, event_type: TouchEventType, @@ -1202,7 +1210,9 @@ impl Document { }; let node = match self.window.hit_test_query(point, false) { - Some(node_address) => node::from_untrusted_node_address(js_runtime, node_address), + Some(node_address) => unsafe { + node::from_untrusted_node_address(js_runtime, node_address) + }, None => return TouchEventResult::Processed(false), }; let el = match node.downcast::<Element>() { @@ -3480,7 +3490,9 @@ impl DocumentMethods for Document { Some(untrusted_node_address) => { let js_runtime = unsafe { JS_GetRuntime(window.get_cx()) }; - let node = node::from_untrusted_node_address(js_runtime, untrusted_node_address); + let node = unsafe { + node::from_untrusted_node_address(js_runtime, untrusted_node_address) + }; let parent_node = node.GetParentNode().unwrap(); let element_ref = node.downcast::<Element>().unwrap_or_else(|| { parent_node.downcast::<Element>().unwrap() @@ -3515,7 +3527,9 @@ impl DocumentMethods for Document { // Step 1 and Step 3 let mut elements: Vec<Root<Element>> = self.nodes_from_point(point).iter() .flat_map(|&untrusted_node_address| { - let node = node::from_untrusted_node_address(js_runtime, untrusted_node_address); + let node = unsafe { + node::from_untrusted_node_address(js_runtime, untrusted_node_address) + }; Root::downcast::<Element>(node) }).collect(); diff --git a/components/script/dom/node.rs b/components/script/dom/node.rs index 81a06850757..6d16cac6731 100644 --- a/components/script/dom/node.rs +++ b/components/script/dom/node.rs @@ -927,20 +927,18 @@ fn first_node_not_in<I>(mut nodes: I, not_in: &[NodeOrString]) -> Option<Root<No /// If the given untrusted node address represents a valid DOM node in the given runtime, /// returns it. #[allow(unsafe_code)] -pub fn from_untrusted_node_address(_runtime: *mut JSRuntime, candidate: UntrustedNodeAddress) +pub unsafe fn from_untrusted_node_address(_runtime: *mut JSRuntime, candidate: UntrustedNodeAddress) -> Root<Node> { - unsafe { - // https://github.com/servo/servo/issues/6383 - let candidate: uintptr_t = mem::transmute(candidate.0); + // https://github.com/servo/servo/issues/6383 + let candidate: uintptr_t = mem::transmute(candidate.0); // let object: *mut JSObject = jsfriendapi::bindgen::JS_GetAddressableObject(runtime, // candidate); - let object: *mut JSObject = mem::transmute(candidate); - if object.is_null() { - panic!("Attempted to create a `JS<Node>` from an invalid pointer!") - } - let boxed_node = conversions::private_from_object(object) as *const Node; - Root::from_ref(&*boxed_node) + let object: *mut JSObject = mem::transmute(candidate); + if object.is_null() { + panic!("Attempted to create a `JS<Node>` from an invalid pointer!") } + let boxed_node = conversions::private_from_object(object) as *const Node; + Root::from_ref(&*boxed_node) } #[allow(unsafe_code)] diff --git a/components/script/dom/window.rs b/components/script/dom/window.rs index 993749b00c2..4317d2890b7 100644 --- a/components/script/dom/window.rs +++ b/components/script/dom/window.rs @@ -76,7 +76,7 @@ use script_layout_interface::rpc::{MarginStyleResponse, NodeScrollRootIdResponse use script_layout_interface::rpc::{ResolvedStyleResponse, TextIndexResponse}; use script_runtime::{CommonScriptMsg, ScriptChan, ScriptPort, ScriptThreadEventCategory}; use script_thread::{MainThreadScriptChan, MainThreadScriptMsg, Runnable, RunnableWrapper}; -use script_thread::{SendableMainThreadScriptChan, ImageCacheMsg}; +use script_thread::{SendableMainThreadScriptChan, ImageCacheMsg, ScriptThread}; use script_traits::{ConstellationControlMsg, LoadData, MozBrowserEvent, UntrustedNodeAddress}; use script_traits::{DocumentState, TimerEvent, TimerEventId}; use script_traits::{ScriptMsg as ConstellationMsg, TimerSchedulerMsg, WindowSizeData, WindowSizeType}; @@ -1150,6 +1150,7 @@ impl Window { /// off-main-thread layout. /// /// Returns true if layout actually happened, false otherwise. + #[allow(unsafe_code)] pub fn force_reflow(&self, goal: ReflowGoal, query_type: ReflowQueryType, @@ -1213,16 +1214,16 @@ impl Window { debug!("script: layout forked"); - match join_port.try_recv() { + let complete = match join_port.try_recv() { Err(Empty) => { info!("script: waiting on layout"); - join_port.recv().unwrap(); + join_port.recv().unwrap() } - Ok(_) => {} + Ok(reflow_complete) => reflow_complete, Err(Disconnected) => { panic!("Layout thread failed while script was waiting for a result."); } - } + }; debug!("script: layout joined"); @@ -1236,12 +1237,11 @@ impl Window { self.emit_timeline_marker(marker.end()); } - let pending_images = self.layout_rpc.pending_images(); - for image in pending_images { + for image in complete.pending_images { let id = image.id; let js_runtime = self.js_runtime.borrow(); let js_runtime = js_runtime.as_ref().unwrap(); - let node = from_untrusted_node_address(js_runtime.rt(), image.node); + let node = unsafe { from_untrusted_node_address(js_runtime.rt(), image.node) }; if let PendingImageState::Unrequested(ref url) = image.state { fetch_image_for_layout(url.clone(), &*node, id, self.image_cache.clone()); @@ -1261,6 +1261,10 @@ impl Window { } } + unsafe { + ScriptThread::note_newly_transitioning_nodes(complete.newly_transitioning_nodes); + } + true } @@ -1455,6 +1459,7 @@ impl Window { DOMString::from(resolved) } + #[allow(unsafe_code)] pub fn offset_parent_query(&self, node: TrustedNodeAddress) -> (Option<Root<Element>>, Rect<Au>) { if !self.reflow(ReflowGoal::ForScriptQuery, ReflowQueryType::OffsetParentQuery(node), @@ -1466,7 +1471,7 @@ impl Window { let js_runtime = self.js_runtime.borrow(); let js_runtime = js_runtime.as_ref().unwrap(); let element = response.node_address.and_then(|parent_node_address| { - let node = from_untrusted_node_address(js_runtime.rt(), parent_node_address); + let node = unsafe { from_untrusted_node_address(js_runtime.rt(), parent_node_address) }; Root::downcast(node) }); (element, response.rect) diff --git a/components/script/script_thread.rs b/components/script/script_thread.rs index 8a861e92570..b817fc77d1d 100644 --- a/components/script/script_thread.rs +++ b/components/script/script_thread.rs @@ -47,7 +47,7 @@ use dom::globalscope::GlobalScope; use dom::htmlanchorelement::HTMLAnchorElement; use dom::htmliframeelement::{HTMLIFrameElement, NavigationType}; use dom::mutationobserver::MutationObserver; -use dom::node::{Node, NodeDamage, window_from_node}; +use dom::node::{Node, NodeDamage, window_from_node, from_untrusted_node_address}; use dom::serviceworker::TrustedServiceWorkerAddress; use dom::serviceworkerregistration::ServiceWorkerRegistration; use dom::servoparser::{ParserContext, ServoParser}; @@ -69,7 +69,6 @@ use js::jsapi::{JSAutoCompartment, JSContext, JS_SetWrapObjectCallbacks}; use js::jsapi::{JSTracer, SetWindowProxyClass}; use js::jsval::UndefinedValue; use js::rust::Runtime; -use layout_wrapper::ServoLayoutNode; use mem::heap_size_of_self_and_children; use microtask::{MicrotaskQueue, Microtask}; use msg::constellation_msg::{FrameId, FrameType, PipelineId, PipelineNamespace}; @@ -109,7 +108,6 @@ use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::mpsc::{Receiver, Select, Sender, channel}; use std::thread; use style::context::ReflowGoal; -use style::dom::{TNode, UnsafeNode}; use style::thread_state; use task_source::dom_manipulation::{DOMManipulationTask, DOMManipulationTaskSource}; use task_source::file_reading::FileReadingTaskSource; @@ -490,6 +488,10 @@ pub struct ScriptThread { /// A list of pipelines containing documents that finished loading all their blocking /// resources during a turn of the event loop. docs_with_no_blocking_loads: DOMRefCell<HashSet<JS<Document>>>, + + /// A list of nodes with in-progress CSS transitions, which roots them for the duration + /// of the transition. + transitioning_nodes: DOMRefCell<Vec<JS<Node>>>, } /// In the event of thread panic, all data on the stack runs its destructor. However, there @@ -574,6 +576,17 @@ impl ScriptThreadFactory for ScriptThread { } impl ScriptThread { + pub unsafe fn note_newly_transitioning_nodes(nodes: Vec<UntrustedNodeAddress>) { + SCRIPT_THREAD_ROOT.with(|root| { + let script_thread = &*root.get().unwrap(); + let js_runtime = script_thread.js_runtime.rt(); + let new_nodes = nodes + .into_iter() + .map(|n| JS::from_ref(&*from_untrusted_node_address(js_runtime, n))); + script_thread.transitioning_nodes.borrow_mut().extend(new_nodes); + }) + } + pub fn add_mutation_observer(observer: &MutationObserver) { SCRIPT_THREAD_ROOT.with(|root| { let script_thread = unsafe { &*root.get().unwrap() }; @@ -742,6 +755,8 @@ impl ScriptThread { webvr_thread: state.webvr_thread, docs_with_no_blocking_loads: Default::default(), + + transitioning_nodes: Default::default(), } } @@ -1602,11 +1617,29 @@ impl ScriptThread { } /// Handles firing of transition events. - #[allow(unsafe_code)] - fn handle_transition_event(&self, unsafe_node: UnsafeNode, name: String, duration: f64) { - let node = unsafe { ServoLayoutNode::from_unsafe(&unsafe_node) }; - let node = unsafe { node.get_jsmanaged().get_for_script() }; - let window = window_from_node(node); + fn handle_transition_event(&self, unsafe_node: UntrustedNodeAddress, name: String, duration: f64) { + let js_runtime = self.js_runtime.rt(); + let node = unsafe { + from_untrusted_node_address(js_runtime, unsafe_node) + }; + + let idx = self.transitioning_nodes + .borrow() + .iter() + .position(|n| &**n as *const _ == &*node as *const _); + match idx { + Some(idx) => { + self.transitioning_nodes.borrow_mut().remove(idx); + } + None => { + // If no index is found, we can't know whether this node is safe to use. + // It's better not to fire a DOM event than crash. + warn!("Ignoring transition end notification for unknown node."); + return; + } + } + + let window = window_from_node(&*node); // Not quite the right thing - see #13865. node.dirty(NodeDamage::NodeStyleDamaged); |