script: When using WebRender, keep the DOM-side scroll positions for

elements with `overflow: scroll` up to date, and take them into account
when doing hit testing.

Closes #11648.
This commit is contained in:
Patrick Walton 2016-06-08 18:46:02 -07:00
parent ce88b8ed30
commit 041cfe6d0a
14 changed files with 259 additions and 47 deletions

View file

@ -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>);

View file

@ -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

View file

@ -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;

View file

@ -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

View file

@ -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,
};