aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--components/compositing/compositor.rs4
-rw-r--r--components/script/dom/element.rs268
-rw-r--r--components/script/dom/webidls/Element.webidl7
-rw-r--r--components/script/dom/window.rs23
-rw-r--r--tests/html/simple-overflow-scroll.html4
-rw-r--r--tests/wpt/metadata/MANIFEST.json4
-rw-r--r--tests/wpt/metadata/cssom-view/elementScroll.html.ini4
-rw-r--r--tests/wpt/web-platform-tests/cssom-view/elementScroll.html89
8 files changed, 363 insertions, 40 deletions
diff --git a/components/compositing/compositor.rs b/components/compositing/compositor.rs
index bfc2fa1abc6..2dddffe15a9 100644
--- a/components/compositing/compositor.rs
+++ b/components/compositing/compositor.rs
@@ -720,7 +720,9 @@ impl<Window: WindowMethods> IOCompositor<Window> {
let typed = layer.extra_data.borrow().scroll_offset;
let _ = sender.send(Point2D::new(typed.x.get(), typed.y.get()));
},
- None => {},
+ None => {
+ warn!("Can't find requested layer in handling Msg::GetScrollOffset");
+ },
}
}
diff --git a/components/script/dom/element.rs b/components/script/dom/element.rs
index 8fa454c0e73..1844bd3e426 100644
--- a/components/script/dom/element.rs
+++ b/components/script/dom/element.rs
@@ -20,6 +20,7 @@ use dom::bindings::codegen::Bindings::HTMLInputElementBinding::HTMLInputElementM
use dom::bindings::codegen::Bindings::HTMLTemplateElementBinding::HTMLTemplateElementMethods;
use dom::bindings::codegen::Bindings::NodeBinding::NodeMethods;
use dom::bindings::codegen::Bindings::WindowBinding::WindowMethods;
+use dom::bindings::codegen::Bindings::WindowBinding::{ScrollBehavior, ScrollToOptions};
use dom::bindings::codegen::UnionTypes::NodeOrString;
use dom::bindings::error::{Error, ErrorResult, Fallible};
use dom::bindings::global::GlobalRef;
@@ -1227,6 +1228,49 @@ impl Element {
_ => Err(Error::Syntax)
}
}
+
+ // https://drafts.csswg.org/cssom-view/#dom-element-scroll
+ pub fn scroll(&self, x_: f64, y_: f64, behavior: ScrollBehavior) {
+
+ // Step 1.2 or 2.3
+ let x = if x_.is_finite() { x_ } else { 0.0f64 };
+ let y = if y_.is_finite() { y_ } else { 0.0f64 };
+
+ let node = self.upcast::<Node>();
+
+ // Step 3
+ let doc = node.owner_doc();
+
+ // Step 4
+ if !doc.is_fully_active() {
+ return;
+ }
+
+ // Step 5
+ let win = doc.DefaultView();
+
+ // Step 7
+ if *self.root_element() == *self {
+ if doc.quirks_mode() != Quirks {
+ win.scroll(x, y, behavior);
+ }
+
+ return;
+ }
+
+ // Step 9
+ if doc.GetBody().r() == self.downcast::<HTMLElement>() &&
+ doc.quirks_mode() == Quirks &&
+ !self.potentially_scrollable() {
+ win.scroll(x, y, behavior);
+ return;
+ }
+
+ // Step 10 (TODO)
+
+ // Step 11
+ win.scroll_node(node.to_trusted_node_address(), x, y, behavior);
+ }
}
impl ElementMethods for Element {
@@ -1483,66 +1527,218 @@ impl ElementMethods for Element {
rect.size.height.to_f64_px())
}
+ // https://drafts.csswg.org/cssom-view/#dom-element-scroll
+ fn Scroll(&self, options: &ScrollToOptions) {
+ // Step 1
+ let left = options.left.unwrap_or(self.ScrollLeft());
+ let top = options.top.unwrap_or(self.ScrollTop());
+ self.scroll(left, top, options.parent.behavior);
+ }
+
+ // https://drafts.csswg.org/cssom-view/#dom-element-scroll
+ fn Scroll_(&self, x: f64, y: f64) {
+ self.scroll(x, y, ScrollBehavior::Auto);
+ }
+
+ // https://drafts.csswg.org/cssom-view/#dom-element-scrollto
+ fn ScrollTo(&self, options: &ScrollToOptions) {
+ self.Scroll(options);
+ }
+
+ // https://drafts.csswg.org/cssom-view/#dom-element-scrollto
+ fn ScrollTo_(&self, x: f64, y: f64) {
+ self.Scroll_(x, y);
+ }
+
+ // https://drafts.csswg.org/cssom-view/#dom-element-scrollby
+ fn ScrollBy(&self, options: &ScrollToOptions) {
+ // Step 2
+ let delta_left = options.left.unwrap_or(0.0f64);
+ let delta_top = options.top.unwrap_or(0.0f64);
+ let left = self.ScrollLeft();
+ let top = self.ScrollTop();
+ self.scroll(left + delta_left, top + delta_top,
+ options.parent.behavior);
+ }
+
+ // https://drafts.csswg.org/cssom-view/#dom-element-scrollby
+ fn ScrollBy_(&self, x: f64, y: f64) {
+ let left = self.ScrollLeft();
+ let top = self.ScrollTop();
+ self.scroll(left + x, top + y, ScrollBehavior::Auto);
+ }
+
// https://drafts.csswg.org/cssom-view/#dom-element-scrolltop
fn ScrollTop(&self) -> f64 {
let node = self.upcast::<Node>();
- // 1. Let document be the element’s node document.
+ // Step 1
let doc = node.owner_doc();
- // 2. If the document is not the active document, return zero and terminate these steps.
+ // Step 2
if !doc.is_fully_active() {
return 0.0;
- } else {
- // 3. Let window be the value of document’s defaultView attribute.
- let win = doc.DefaultView();
-
- // 5. If the element is the root element and document is in quirks mode,
- // return zero and terminate these steps.
- if *self.root_element() == *self {
- if doc.quirks_mode() == Quirks {
- return 0.0;
- }
+ }
- // 6. If the element is the root element return the value of scrollY on window.
- return (*win).ScrollY() as f64;
- }
+ // Step 3
+ let win = doc.DefaultView();
- // 7. If the element is the HTML body element, document is in quirks mode,
- // and the element is not potentially scrollable, return the value of scrollY on window.
- if doc.GetBody().r() == self.downcast::<HTMLElement>() &&
- doc.quirks_mode() == Quirks &&
- !self.potentially_scrollable() {
- return (*win).ScrollY() as f64;
+ // Step 5
+ if *self.root_element() == *self {
+ if doc.quirks_mode() == Quirks {
+ return 0.0;
}
+ // Step 6
+ return win.ScrollY() as f64;
+ }
- // 8. If the element does not have any associated CSS layout box, return zero and terminate these steps.
- if !self.has_css_layout_box() {
- return 0.0;
- }
+ // Step 7
+ if doc.GetBody().r() == self.downcast::<HTMLElement>() &&
+ doc.quirks_mode() == Quirks &&
+ !self.potentially_scrollable() {
+ return win.ScrollY() as f64;
+ }
- // 9. Return the y-coordinate of the scrolling area at the alignment point
- // with the top of the padding edge of the element.
- let point = node.scroll_offset();
- return -point.y as f64;
+
+ // Step 8
+ if !self.has_css_layout_box() {
+ return 0.0;
}
+
+ // Step 9
+ let point = node.scroll_offset();
+ return point.y.abs() as f64;
}
// https://drafts.csswg.org/cssom-view/#dom-element-scrolltop
- fn SetScrollTop(&self, _scroll_top: f64) {
- unimplemented!()
+ fn SetScrollTop(&self, y_: f64) {
+ let behavior = ScrollBehavior::Auto;
+
+ // Step 1, 2
+ let y = if y_.is_finite() { y_ } else { 0.0f64 };
+
+ let node = self.upcast::<Node>();
+
+ // Step 3
+ let doc = node.owner_doc();
+
+ // Step 4
+ if !doc.is_fully_active() {
+ return;
+ }
+
+ // Step 5
+ let win = doc.DefaultView();
+
+ // Step 7
+ if *self.root_element() == *self {
+ if doc.quirks_mode() != Quirks {
+ win.scroll(win.ScrollX() as f64, y, behavior);
+ }
+
+ return;
+ }
+
+ // Step 9
+ if doc.GetBody().r() == self.downcast::<HTMLElement>() &&
+ doc.quirks_mode() == Quirks &&
+ !self.potentially_scrollable() {
+ win.scroll(win.ScrollX() as f64, y, behavior);
+ return;
+ }
+
+ // Step 10 (TODO)
+
+ // Step 11
+ win.scroll_node(node.to_trusted_node_address(), self.ScrollLeft(), y, behavior);
}
- // https://drafts.csswg.org/cssom-view/#dom-element-scrollleft
+ // https://drafts.csswg.org/cssom-view/#dom-element-scrolltop
fn ScrollLeft(&self) -> f64 {
- let point = self.upcast::<Node>().scroll_offset();
- return -point.x as f64;
+ let node = self.upcast::<Node>();
+
+ // Step 1
+ let doc = node.owner_doc();
+
+ // Step 2
+ if !doc.is_fully_active() {
+ return 0.0;
+ }
+
+ // Step 3
+ let win = doc.DefaultView();
+
+ // Step 5
+ if *self.root_element() == *self {
+ if doc.quirks_mode() != Quirks {
+ // Step 6
+ return win.ScrollX() as f64;
+ }
+
+ return 0.0;
+ }
+
+ // Step 7
+ if doc.GetBody().r() == self.downcast::<HTMLElement>() &&
+ doc.quirks_mode() == Quirks &&
+ !self.potentially_scrollable() {
+ return win.ScrollX() as f64;
+ }
+
+
+ // Step 8
+ if !self.has_css_layout_box() {
+ return 0.0;
+ }
+
+ // Step 9
+ let point = node.scroll_offset();
+ return point.x.abs() as f64;
}
// https://drafts.csswg.org/cssom-view/#dom-element-scrollleft
- fn SetScrollLeft(&self, _scroll_left: f64) {
- unimplemented!()
+ fn SetScrollLeft(&self, x_: f64) {
+ let behavior = ScrollBehavior::Auto;
+
+ // Step 1, 2
+ let x = if x_.is_finite() { x_ } else { 0.0f64 };
+
+ let node = self.upcast::<Node>();
+
+ // Step 3
+ let doc = node.owner_doc();
+
+ // Step 4
+ if !doc.is_fully_active() {
+ return;
+ }
+
+ // Step 5
+ let win = doc.DefaultView();
+
+ // Step 7
+ if *self.root_element() == *self {
+ if doc.quirks_mode() == Quirks {
+ return;
+ }
+
+ win.scroll(x, win.ScrollY() as f64, behavior);
+ return;
+ }
+
+ // Step 9
+ if doc.GetBody().r() == self.downcast::<HTMLElement>() &&
+ doc.quirks_mode() == Quirks &&
+ !self.potentially_scrollable() {
+ win.scroll(x, win.ScrollY() as f64, behavior);
+ return;
+ }
+
+ // Step 10 (TODO)
+
+ // Step 11
+ win.scroll_node(node.to_trusted_node_address(), x, self.ScrollTop(), behavior);
}
// https://drafts.csswg.org/cssom-view/#dom-element-scrollwidth
diff --git a/components/script/dom/webidls/Element.webidl b/components/script/dom/webidls/Element.webidl
index b161a782a55..19cb67e8cb9 100644
--- a/components/script/dom/webidls/Element.webidl
+++ b/components/script/dom/webidls/Element.webidl
@@ -81,6 +81,13 @@ partial interface Element {
DOMRectList getClientRects();
DOMRect getBoundingClientRect();
+ void scroll(optional ScrollToOptions options);
+ void scroll(unrestricted double x, unrestricted double y);
+
+ void scrollTo(optional ScrollToOptions options);
+ void scrollTo(unrestricted double x, unrestricted double y);
+ void scrollBy(optional ScrollToOptions options);
+ void scrollBy(unrestricted double x, unrestricted double y);
attribute unrestricted double scrollTop;
attribute unrestricted double scrollLeft;
readonly attribute long scrollWidth;
diff --git a/components/script/dom/window.rs b/components/script/dom/window.rs
index 75c7089fac3..8f36193c2eb 100644
--- a/components/script/dom/window.rs
+++ b/components/script/dom/window.rs
@@ -912,11 +912,13 @@ impl Window {
//TODO Step 11
//let document = self.Document();
// Step 12
- self.perform_a_scroll(x.to_f32().unwrap_or(0.0f32), y.to_f32().unwrap_or(0.0f32), behavior, None);
+ self.perform_a_scroll(x.to_f32().unwrap_or(0.0f32), y.to_f32().unwrap_or(0.0f32),
+ LayerId::null(), behavior, None);
}
/// https://drafts.csswg.org/cssom-view/#perform-a-scroll
- pub fn perform_a_scroll(&self, x: f32, y: f32, behavior: ScrollBehavior, element: Option<&Element>) {
+ pub fn perform_a_scroll(&self, x: f32, y: f32, layer_id: LayerId,
+ behavior: ScrollBehavior, element: Option<&Element>) {
//TODO Step 1
let point = Point2D::new(x, y);
let smooth = match behavior {
@@ -935,7 +937,7 @@ impl Window {
self.current_viewport.set(Rect::new(Point2D::new(Au::from_f32_px(x), Au::from_f32_px(y)), size));
self.compositor.send(ScriptToCompositorMsg::ScrollFragmentPoint(
- self.pipeline(), LayerId::null(), point, smooth)).unwrap()
+ self.pipeline(), layer_id, point, smooth)).unwrap()
}
pub fn client_window(&self) -> (Size2D<u32>, Point2D<i32>) {
@@ -1142,6 +1144,21 @@ impl Window {
recv.recv().unwrap_or(Point2D::zero())
}
+ // https://drafts.csswg.org/cssom-view/#dom-element-scroll
+ pub fn scroll_node(&self, node: TrustedNodeAddress,
+ x_: f64, y_: f64, behavior: ScrollBehavior) {
+
+ self.reflow(ReflowGoal::ForScriptQuery,
+ ReflowQueryType::NodeLayerIdQuery(node),
+ ReflowReason::Query);
+
+ let layer_id = self.layout_rpc.node_layer_id().layer_id;
+
+ // Step 12
+ self.perform_a_scroll(x_.to_f32().unwrap_or(0.0f32), y_.to_f32().unwrap_or(0.0f32),
+ layer_id, behavior, None);
+ }
+
pub fn resolved_style_query(&self,
element: TrustedNodeAddress,
pseudo: Option<PseudoElement>,
diff --git a/tests/html/simple-overflow-scroll.html b/tests/html/simple-overflow-scroll.html
index b8544cfec38..f0a158b7eaa 100644
--- a/tests/html/simple-overflow-scroll.html
+++ b/tests/html/simple-overflow-scroll.html
@@ -37,6 +37,10 @@ Curabitur elit lacus, bibendum non tempus a, bibendum sit amet ante. Mauris eget
<script>
var section = document.getElementById("section");
+window.setTimeout(function () {
+ section.scroll(0, 1000);
+}, 2000)
+
window.setInterval(function () {
console.log("scrollTop: " + section.scrollTop);
console.log("scrollLeft: " + section.scrollLeft);
diff --git a/tests/wpt/metadata/MANIFEST.json b/tests/wpt/metadata/MANIFEST.json
index 823ca7747f4..f6970aa8d54 100644
--- a/tests/wpt/metadata/MANIFEST.json
+++ b/tests/wpt/metadata/MANIFEST.json
@@ -13740,6 +13740,10 @@
"url": "/cssom-view/elementFromPoint.html"
},
{
+ "path": "cssom-view/elementScroll.html",
+ "url": "/cssom-view/elementScroll.html"
+ },
+ {
"path": "cssom-view/elementsFromPoint.html",
"url": "/cssom-view/elementsFromPoint.html"
},
diff --git a/tests/wpt/metadata/cssom-view/elementScroll.html.ini b/tests/wpt/metadata/cssom-view/elementScroll.html.ini
new file mode 100644
index 00000000000..8d1d147753b
--- /dev/null
+++ b/tests/wpt/metadata/cssom-view/elementScroll.html.ini
@@ -0,0 +1,4 @@
+[elementScroll.html]
+ type: testharness
+ [Element scroll maximum test]
+ expected: FAIL
diff --git a/tests/wpt/web-platform-tests/cssom-view/elementScroll.html b/tests/wpt/web-platform-tests/cssom-view/elementScroll.html
new file mode 100644
index 00000000000..6227d665457
--- /dev/null
+++ b/tests/wpt/web-platform-tests/cssom-view/elementScroll.html
@@ -0,0 +1,89 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<title>cssom-view - elementScroll</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<style>
+ section {
+ width: 300px;
+ height: 300px;
+ /*position: absolute;*/
+ top: 16px;
+ left: 16px;
+ border: inset gray 3px;
+ overflow: scroll;
+ background: white;
+ }
+
+ div {
+ width: 400px;
+ }
+
+</style>
+
+<section id="section">
+ <div>
+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc ultricies tortor eu augue eleifend malesuada. Duis id condimentum urna. Duis vulputate urna a dignissim sodales. Aenean et magna id dui rutrum suscipit. Etiam metus mauris, congue ac suscipit dapibus, mattis non neque. Donec porttitor eros sed mauris tristique, non condimentum augue feugiat. Suspendisse iaculis faucibus nunc at porttitor. Integer convallis enim in feugiat molestie. Ut eget tincidunt mi, vel malesuada lectus. Quisque fermentum neque a sapien interdum consectetur. Nam tincidunt leo sit amet tortor ornare, sit amet ultrices ante semper. Fusce malesuada mi vitae venenatis sagittis. Duis eget urna quam.
+
+ Sed lacinia aliquam tortor quis elementum. Cras vitae mauris erat. Vestibulum posuere justo et dolor condimentum feugiat. Sed at magna nunc. Suspendisse est nunc, ultrices sed enim lobortis, vulputate rutrum mauris. Fusce ultrices eget erat blandit porta. Sed eros nulla, tristique eget porta a, viverra vel velit. Praesent sit amet odio eleifend, tempor arcu ut, elementum tellus. Suspendisse lorem tortor, sodales eget nulla a, rhoncus lobortis magna. Phasellus purus ante, rhoncus a ipsum nec, condimentum lacinia purus. Cras lobortis posuere nisi, vitae dapibus ante feugiat et. Quisque ornare nisi quis erat congue viverra. Vestibulum a nunc odio.
+
+ Sed id venenatis tortor. Curabitur sit amet mauris eget mi semper rutrum vel et odio. Phasellus eu sapien in sem ultricies pretium eu sit amet magna. Nulla finibus nec lorem ac semper. Nulla eleifend eros id fringilla pellentesque. Proin eleifend, sem vel lobortis viverra, massa augue viverra felis, quis ultricies sapien ipsum at magna. Duis rutrum tempus lobortis. Aliquam quis nulla eget velit viverra pretium. Maecenas venenatis nec nisl at pulvinar. Duis in sodales lectus, ac porta augue.
+
+ Sed sed ante aliquam, rutrum nisl quis, fermentum tellus. Proin ac leo molestie, euismod mauris sed, consequat nunc. Vivamus ut leo a nunc pharetra accumsan a non lorem. Aliquam iaculis mattis augue, in eleifend est accumsan vel. Pellentesque efficitur pulvinar leo vel ornare. Pellentesque non fermentum enim, ut efficitur elit. Duis risus quam, congue vel nulla a, blandit egestas erat. Suspendisse at sodales dolor. Vivamus auctor, lorem et ultrices venenatis, erat ex mollis nisi, quis maximus libero quam a libero.
+
+ Curabitur elit lacus, bibendum non tempus a, bibendum sit amet ante. Mauris eget nibh quis leo rhoncus consequat. Integer iaculis sed sapien eu pellentesque. In aliquet elementum lorem, ut consequat elit ultrices id. Phasellus vestibulum ex ex, ac sagittis tortor convallis et. Curabitur placerat id lectus at aliquam. Morbi sed nisl sem. Nam sit amet arcu maximus, volutpat nisl ac, dignissim neque. Etiam nec efficitur libero. Quisque tristique pulvinar est, eget dictum ex vehicula non. Nam dignissim non felis a iaculis. Nullam vel dolor vitae libero aliquet congue. Donec mi eros, semper non lectus at, commodo ullamcorper ligula. Donec commodo, sem vel lacinia porttitor, elit orci maximus felis, eget eleifend est velit id lorem.
+ </div>
+</section>
+
+<script>
+ setup({explicit_done:true});
+ window.onload = function () {
+ var section = document.getElementById("section");
+
+ test(function () {
+ assert_equals(section.scrollTop, 0, "initial scrollTop should be 0");
+ assert_equals(section.scrollLeft, 0, "initial scrollLeft should be 0");
+
+ section.scrollTop = 30;
+ section.scrollLeft = 40;
+
+ assert_equals(section.scrollTop, 30, "changed scrollTop should be 40");
+ assert_equals(section.scrollLeft, 40, "changed scrollLeft should be 40");
+ }, "Element scrollTop/Left getter/setter test");
+
+ test(function () {
+ section.scroll(50, 60);
+
+ assert_equals(section.scrollLeft, 50, "changed scrollLeft should be 60");
+ assert_equals(section.scrollTop, 60, "changed scrollTop should be 50");
+ }, "Element scroll test");
+
+ test(function () {
+ section.scrollTo(80, 70);
+
+ assert_equals(section.scrollLeft, 80, "changed scrollLeft should be 70");
+ assert_equals(section.scrollTop, 70, "changed scrollTop should be 80");
+ }, "Element scrollTo test");
+
+ test(function () {
+ var left = section.scrollLeft;
+ var top = section.scrollTop;
+
+ section.scrollBy(10, 20);
+
+ assert_equals(section.scrollLeft, left + 10, "increment of scrollLeft should be 10")
+ assert_equals(section.scrollTop, top + 20, "increment of scrollTop should be 20")
+ })
+
+ test(function () {
+ section.scrollTop = 1000;
+ section.scrollLeft = 1000;
+
+ assert_equals(section.scrollTop, 636, "changed scrollTop should be 636");
+ assert_equals(section.scrollLeft, 100, "changed scrollLeft should be 100");
+
+ }, "Element scroll maximum test");
+
+ done();
+ };
+</script>