aboutsummaryrefslogtreecommitdiffstats
path: root/components/script
diff options
context:
space:
mode:
Diffstat (limited to 'components/script')
-rw-r--r--components/script/dom/bindings/trace.rs2
-rw-r--r--components/script/dom/node.rs6
-rw-r--r--components/script/dom/webidls/Element.webidl8
-rw-r--r--components/script/dom/webidls/Window.webidl6
-rw-r--r--components/script/dom/window.rs37
-rw-r--r--components/script/lib.rs14
-rw-r--r--components/script/script_thread.rs39
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) {