diff options
Diffstat (limited to 'components/script')
-rw-r--r-- | components/script/dom/bindings/trace.rs | 2 | ||||
-rw-r--r-- | components/script/dom/node.rs | 6 | ||||
-rw-r--r-- | components/script/dom/webidls/Element.webidl | 8 | ||||
-rw-r--r-- | components/script/dom/webidls/Window.webidl | 6 | ||||
-rw-r--r-- | components/script/dom/window.rs | 37 | ||||
-rw-r--r-- | components/script/lib.rs | 14 | ||||
-rw-r--r-- | components/script/script_thread.rs | 39 |
7 files changed, 96 insertions, 16 deletions
diff --git a/components/script/dom/bindings/trace.rs b/components/script/dom/bindings/trace.rs index 2a9f0e52134..34ec7d19e14 100644 --- a/components/script/dom/bindings/trace.rs +++ b/components/script/dom/bindings/trace.rs @@ -43,6 +43,7 @@ use dom::bindings::utils::WindowProxyHandler; use encoding::types::EncodingRef; use euclid::length::Length as EuclidLength; use euclid::matrix2d::Matrix2D; +use euclid::point::Point2D; use euclid::rect::Rect; use euclid::size::Size2D; use html5ever::tree_builder::QuirksMode; @@ -279,6 +280,7 @@ no_jsmanaged_fields!(usize, u8, u16, u32, u64); no_jsmanaged_fields!(isize, i8, i16, i32, i64); no_jsmanaged_fields!(Sender<T>); no_jsmanaged_fields!(Receiver<T>); +no_jsmanaged_fields!(Point2D<T>); no_jsmanaged_fields!(Rect<T>); no_jsmanaged_fields!(Size2D<T>); no_jsmanaged_fields!(Arc<T>); diff --git a/components/script/dom/node.rs b/components/script/dom/node.rs index 3032abe0685..a3289cca56e 100644 --- a/components/script/dom/node.rs +++ b/components/script/dom/node.rs @@ -298,6 +298,10 @@ impl Node { self.owner_doc().content_and_heritage_changed(self, NodeDamage::OtherNodeDamage); child.owner_doc().content_and_heritage_changed(child, NodeDamage::OtherNodeDamage); } + + pub fn to_untrusted_node_address(&self) -> UntrustedNodeAddress { + UntrustedNodeAddress(self.reflector().get_jsobject().get() as *const c_void) + } } pub struct QuerySelectorIterator { @@ -622,7 +626,7 @@ impl Node { pub fn scroll_offset(&self) -> Point2D<f32> { let document = self.owner_doc(); let window = document.window(); - window.scroll_offset_query(self.to_trusted_node_address()) + window.scroll_offset_query(self) } // https://dom.spec.whatwg.org/#dom-childnode-before diff --git a/components/script/dom/webidls/Element.webidl b/components/script/dom/webidls/Element.webidl index 48aeed7fbbb..d09f4846c98 100644 --- a/components/script/dom/webidls/Element.webidl +++ b/components/script/dom/webidls/Element.webidl @@ -84,14 +84,22 @@ partial interface Element { DOMRectList getClientRects(); DOMRect getBoundingClientRect(); + [Func="::script_can_initiate_scroll"] void scroll(optional ScrollToOptions options); + [Func="::script_can_initiate_scroll"] void scroll(unrestricted double x, unrestricted double y); + [Func="::script_can_initiate_scroll"] void scrollTo(optional ScrollToOptions options); + [Func="::script_can_initiate_scroll"] void scrollTo(unrestricted double x, unrestricted double y); + [Func="::script_can_initiate_scroll"] void scrollBy(optional ScrollToOptions options); + [Func="::script_can_initiate_scroll"] void scrollBy(unrestricted double x, unrestricted double y); + [Func="::script_can_initiate_scroll"] attribute unrestricted double scrollTop; + [Func="::script_can_initiate_scroll"] attribute unrestricted double scrollLeft; readonly attribute long scrollWidth; readonly attribute long scrollHeight; diff --git a/components/script/dom/webidls/Window.webidl b/components/script/dom/webidls/Window.webidl index fcac82ea0c5..1bf0f7f2c50 100644 --- a/components/script/dom/webidls/Window.webidl +++ b/components/script/dom/webidls/Window.webidl @@ -136,11 +136,17 @@ partial interface Window { readonly attribute long pageXOffset; readonly attribute long scrollY; readonly attribute long pageYOffset; + [Func="::script_can_initiate_scroll"] void scroll(optional ScrollToOptions options); + [Func="::script_can_initiate_scroll"] void scroll(unrestricted double x, unrestricted double y); + [Func="::script_can_initiate_scroll"] void scrollTo(optional ScrollToOptions options); + [Func="::script_can_initiate_scroll"] void scrollTo(unrestricted double x, unrestricted double y); + [Func="::script_can_initiate_scroll"] void scrollBy(optional ScrollToOptions options); + [Func="::script_can_initiate_scroll"] void scrollBy(unrestricted double x, unrestricted double y); // client diff --git a/components/script/dom/window.rs b/components/script/dom/window.rs index 4bfbb1993d1..34f7c1acdb0 100644 --- a/components/script/dom/window.rs +++ b/components/script/dom/window.rs @@ -12,6 +12,7 @@ use dom::bindings::codegen::Bindings::EventHandlerBinding::EventHandlerNonNull; use dom::bindings::codegen::Bindings::EventHandlerBinding::OnBeforeUnloadEventHandlerNonNull; use dom::bindings::codegen::Bindings::EventHandlerBinding::OnErrorEventHandlerNonNull; use dom::bindings::codegen::Bindings::FunctionBinding::Function; +use dom::bindings::codegen::Bindings::NodeBinding::NodeMethods; use dom::bindings::codegen::Bindings::WindowBinding::{ScrollBehavior, ScrollToOptions}; use dom::bindings::codegen::Bindings::WindowBinding::{self, FrameRequestCallback, WindowMethods}; use dom::bindings::error::{Error, ErrorResult, Fallible, report_pending_exception}; @@ -68,7 +69,7 @@ use script_traits::{ScriptMsg as ConstellationMsg, TimerEventRequest, TimerSourc use std::ascii::AsciiExt; use std::borrow::ToOwned; use std::cell::Cell; -use std::collections::HashSet; +use std::collections::{HashMap, HashSet}; use std::default::Default; use std::ffi::CString; use std::io::{Write, stderr, stdout}; @@ -264,6 +265,9 @@ pub struct Window { error_reporter: CSSErrorReporter, + /// A list of scroll offsets for each scrollable element. + scroll_offsets: DOMRefCell<HashMap<UntrustedNodeAddress, Point2D<f32>>>, + #[ignore_heap_size_of = "Defined in ipc-channel"] panic_chan: IpcSender<PanicMsg>, } @@ -354,6 +358,13 @@ impl Window { pub fn css_error_reporter(&self) -> Box<ParseErrorReporter + Send> { self.error_reporter.clone() } + + /// Sets a new list of scroll offsets. + /// + /// This is called when layout gives us new ones and WebRender is in use. + pub fn set_scroll_offsets(&self, offsets: HashMap<UntrustedNodeAddress, Point2D<f32>>) { + *self.scroll_offsets.borrow_mut() = offsets + } } #[cfg(any(target_os = "macos", target_os = "linux"))] @@ -1243,7 +1254,28 @@ impl Window { self.layout_rpc.node_overflow().0.unwrap() } - pub fn scroll_offset_query(&self, node: TrustedNodeAddress) -> Point2D<f32> { + pub fn scroll_offset_query(&self, node: &Node) -> Point2D<f32> { + // WebRender always keeps the scroll offsets up to date and stored here in the window. So, + // if WR is in use, all we need to do is to check our list of scroll offsets and return the + // result. + if opts::get().use_webrender { + let mut node = Root::from_ref(node); + loop { + if let Some(scroll_offset) = self.scroll_offsets + .borrow() + .get(&node.to_untrusted_node_address()) { + return *scroll_offset + } + node = match node.GetParentNode() { + Some(node) => node, + None => break, + } + } + let offset = self.current_viewport.get().origin; + return Point2D::new(offset.x.to_f32_px(), offset.y.to_f32_px()) + } + + let node = node.to_trusted_node_address(); if !self.reflow(ReflowGoal::ForScriptQuery, ReflowQueryType::NodeLayerIdQuery(node), ReflowReason::Query) { @@ -1642,6 +1674,7 @@ impl Window { webdriver_script_chan: DOMRefCell::new(None), ignore_further_async_events: Arc::new(AtomicBool::new(false)), error_reporter: error_reporter, + scroll_offsets: DOMRefCell::new(HashMap::new()), panic_chan: panic_chan, }; diff --git a/components/script/lib.rs b/components/script/lib.rs index 50b0c47ac6b..71e53141d9a 100644 --- a/components/script/lib.rs +++ b/components/script/lib.rs @@ -112,8 +112,9 @@ mod unpremultiplytable; mod webdriver_handlers; use dom::bindings::codegen::RegisterBindings; -use js::jsapi::SetDOMProxyInformation; +use js::jsapi::{Handle, JSContext, JSObject, SetDOMProxyInformation}; use std::ptr; +use util::opts; #[cfg(target_os = "linux")] #[allow(unsafe_code)] @@ -168,3 +169,14 @@ pub fn init() { perform_platform_specific_initialization(); } + +/// FIXME(pcwalton): Currently WebRender cannot handle DOM-initiated scrolls. Remove this when it +/// can. See PR #11680 for details. +/// +/// This function is only marked `unsafe` because the `[Func=foo]` WebIDL attribute requires it. It +/// shouldn't actually do anything unsafe. +#[allow(unsafe_code)] +pub unsafe fn script_can_initiate_scroll(_: *mut JSContext, _: Handle<*mut JSObject>) -> bool { + !opts::get().use_webrender +} + diff --git a/components/script/script_thread.rs b/components/script/script_thread.rs index 51460cd4bb9..7684eb9e336 100644 --- a/components/script/script_thread.rs +++ b/components/script/script_thread.rs @@ -85,11 +85,12 @@ use script_traits::{CompositorEvent, ConstellationControlMsg, EventResult}; use script_traits::{InitialScriptState, MouseButton, MouseEventType, MozBrowserEvent}; use script_traits::{NewLayoutInfo, ScriptMsg as ConstellationMsg}; use script_traits::{ScriptThreadFactory, TimerEvent, TimerEventRequest, TimerSource}; -use script_traits::{TouchEventType, TouchId}; +use script_traits::{TouchEventType, TouchId, UntrustedNodeAddress}; use std::borrow::ToOwned; use std::cell::{Cell, RefCell}; use std::collections::{HashMap, HashSet}; use std::option::Option; +use std::ptr; use std::rc::Rc; use std::result::Result; use std::sync::atomic::{Ordering, AtomicBool}; @@ -728,9 +729,9 @@ impl ScriptThread { self.handle_viewport(id, rect); }) } - FromConstellation(ConstellationControlMsg::SetScrollState(id, scroll_offset)) => { + FromConstellation(ConstellationControlMsg::SetScrollState(id, scroll_state)) => { self.profile_event(ScriptThreadEventCategory::SetScrollState, || { - self.handle_set_scroll_state(id, &scroll_offset); + self.handle_set_scroll_state(id, &scroll_state); }) } FromConstellation(ConstellationControlMsg::TickAllAnimations( @@ -1110,17 +1111,31 @@ impl ScriptThread { panic!("Page rect message sent to nonexistent pipeline"); } - fn handle_set_scroll_state(&self, id: PipelineId, scroll_state: &Point2D<f32>) { - let context = self.browsing_context.get(); - if let Some(context) = context { - if let Some(inner_context) = context.find(id) { - let window = inner_context.active_window(); - window.update_viewport_for_scroll(-scroll_state.x, -scroll_state.y); - return + fn handle_set_scroll_state(&self, + id: PipelineId, + scroll_states: &[(UntrustedNodeAddress, Point2D<f32>)]) { + let window = match self.browsing_context.get() { + Some(context) => { + match context.find(id) { + Some(inner_context) => inner_context.active_window(), + None => { + panic!("Set scroll state message sent to nonexistent pipeline: {:?}", id) + } + } } - } + None => panic!("Set scroll state message sent to nonexistent pipeline: {:?}", id), + }; - panic!("Set scroll state message message sent to nonexistent pipeline: {:?}", id); + let mut scroll_offsets = HashMap::new(); + for &(node_address, ref scroll_offset) in scroll_states { + if node_address == UntrustedNodeAddress(ptr::null()) { + window.update_viewport_for_scroll(-scroll_offset.x, -scroll_offset.y); + } else { + scroll_offsets.insert(node_address, + Point2D::new(-scroll_offset.x, -scroll_offset.y)); + } + } + window.set_scroll_offsets(scroll_offsets) } fn handle_new_layout(&self, new_layout_info: NewLayoutInfo) { |