mirror of
https://github.com/servo/servo.git
synced 2025-07-22 14:53:49 +01:00
Allow script to scroll overflow: scroll
elements
Before the code was only allowing `overflow: hidden` elements to scroll. This fixes that issue and also clean up the code that deals with detecting whether the body is a "potentially scrollable" in quirks mode.
This commit is contained in:
parent
3ab5e2a188
commit
eca0acf459
11 changed files with 60 additions and 173 deletions
|
@ -120,7 +120,6 @@ use style::invalidation::element::restyle_hints::RestyleHint;
|
||||||
use style::properties::longhands::{
|
use style::properties::longhands::{
|
||||||
self, background_image, border_spacing, font_family, font_size,
|
self, background_image, border_spacing, font_family, font_size,
|
||||||
};
|
};
|
||||||
use style::properties::longhands::{overflow_x, overflow_y};
|
|
||||||
use style::properties::{parse_style_attribute, PropertyDeclarationBlock};
|
use style::properties::{parse_style_attribute, PropertyDeclarationBlock};
|
||||||
use style::properties::{ComputedValues, Importance, PropertyDeclaration};
|
use style::properties::{ComputedValues, Importance, PropertyDeclaration};
|
||||||
use style::rule_tree::CascadeLevel;
|
use style::rule_tree::CascadeLevel;
|
||||||
|
@ -408,46 +407,59 @@ impl Element {
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://drafts.csswg.org/cssom-view/#potentially-scrollable
|
// https://drafts.csswg.org/cssom-view/#potentially-scrollable
|
||||||
fn potentially_scrollable(&self) -> bool {
|
fn is_potentially_scrollable_body(&self) -> bool {
|
||||||
self.has_css_layout_box() && !self.has_any_visible_overflow()
|
let node = self.upcast::<Node>();
|
||||||
|
debug_assert!(
|
||||||
|
node.owner_doc().GetBody().as_deref() == self.downcast::<HTMLElement>(),
|
||||||
|
"Called is_potentially_scrollable_body on element that is not the <body>"
|
||||||
|
);
|
||||||
|
|
||||||
|
// "An element body (which will be the body element) is potentially
|
||||||
|
// scrollable if all of the following conditions are true:
|
||||||
|
// - body has an associated box."
|
||||||
|
if !self.has_css_layout_box() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// " - body’s parent element’s computed value of the overflow-x or
|
||||||
|
// overflow-y properties is neither visible nor clip."
|
||||||
|
if let Some(parent) = node.GetParentElement() {
|
||||||
|
if let Some(style) = parent.style() {
|
||||||
|
if !style.get_box().clone_overflow_x().is_scrollable() &&
|
||||||
|
!style.get_box().clone_overflow_y().is_scrollable()
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// " - body’s computed value of the overflow-x or overflow-y properties
|
||||||
|
// is neither visible nor clip."
|
||||||
|
if let Some(style) = self.style() {
|
||||||
|
if !style.get_box().clone_overflow_x().is_scrollable() &&
|
||||||
|
!style.get_box().clone_overflow_y().is_scrollable()
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://drafts.csswg.org/cssom-view/#scrolling-box
|
// https://drafts.csswg.org/cssom-view/#scrolling-box
|
||||||
fn has_scrolling_box(&self) -> bool {
|
fn has_scrolling_box(&self) -> bool {
|
||||||
// TODO: scrolling mechanism, such as scrollbar (We don't have scrollbar yet)
|
// TODO: scrolling mechanism, such as scrollbar (We don't have scrollbar yet)
|
||||||
// self.has_scrolling_mechanism()
|
// self.has_scrolling_mechanism()
|
||||||
self.has_any_hidden_overflow()
|
self.style().map_or(false, |style| {
|
||||||
|
style.get_box().clone_overflow_x().is_scrollable() ||
|
||||||
|
style.get_box().clone_overflow_y().is_scrollable()
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn has_overflow(&self) -> bool {
|
fn has_overflow(&self) -> bool {
|
||||||
self.ScrollHeight() > self.ClientHeight() || self.ScrollWidth() > self.ClientWidth()
|
self.ScrollHeight() > self.ClientHeight() || self.ScrollWidth() > self.ClientWidth()
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Once #19183 is closed (overflow-x/y types moved out of mako), then we could implement
|
|
||||||
// a more generic `fn has_some_overflow(&self, overflow: Overflow)` rather than have
|
|
||||||
// these two `has_any_{visible,hidden}_overflow` methods which are very structurally
|
|
||||||
// similar.
|
|
||||||
|
|
||||||
/// Computed value of overflow-x or overflow-y is "visible"
|
|
||||||
fn has_any_visible_overflow(&self) -> bool {
|
|
||||||
self.style().map_or(false, |s| {
|
|
||||||
let box_ = s.get_box();
|
|
||||||
|
|
||||||
box_.clone_overflow_x() == overflow_x::computed_value::T::Visible ||
|
|
||||||
box_.clone_overflow_y() == overflow_y::computed_value::T::Visible
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Computed value of overflow-x or overflow-y is "hidden"
|
|
||||||
fn has_any_hidden_overflow(&self) -> bool {
|
|
||||||
self.style().map_or(false, |s| {
|
|
||||||
let box_ = s.get_box();
|
|
||||||
|
|
||||||
box_.clone_overflow_x() == overflow_x::computed_value::T::Hidden ||
|
|
||||||
box_.clone_overflow_y() == overflow_y::computed_value::T::Hidden
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
fn shadow_root(&self) -> Option<DomRoot<ShadowRoot>> {
|
fn shadow_root(&self) -> Option<DomRoot<ShadowRoot>> {
|
||||||
self.rare_data()
|
self.rare_data()
|
||||||
.as_ref()?
|
.as_ref()?
|
||||||
|
@ -1765,7 +1777,7 @@ impl Element {
|
||||||
// Step 9
|
// Step 9
|
||||||
if doc.GetBody().as_deref() == self.downcast::<HTMLElement>() &&
|
if doc.GetBody().as_deref() == self.downcast::<HTMLElement>() &&
|
||||||
doc.quirks_mode() == QuirksMode::Quirks &&
|
doc.quirks_mode() == QuirksMode::Quirks &&
|
||||||
!self.potentially_scrollable()
|
!self.is_potentially_scrollable_body()
|
||||||
{
|
{
|
||||||
win.scroll(x, y, behavior);
|
win.scroll(x, y, behavior);
|
||||||
return;
|
return;
|
||||||
|
@ -2305,7 +2317,7 @@ impl ElementMethods for Element {
|
||||||
// Step 7
|
// Step 7
|
||||||
if doc.GetBody().as_deref() == self.downcast::<HTMLElement>() &&
|
if doc.GetBody().as_deref() == self.downcast::<HTMLElement>() &&
|
||||||
doc.quirks_mode() == QuirksMode::Quirks &&
|
doc.quirks_mode() == QuirksMode::Quirks &&
|
||||||
!self.potentially_scrollable()
|
!self.is_potentially_scrollable_body()
|
||||||
{
|
{
|
||||||
return win.ScrollY() as f64;
|
return win.ScrollY() as f64;
|
||||||
}
|
}
|
||||||
|
@ -2355,7 +2367,7 @@ impl ElementMethods for Element {
|
||||||
// Step 9
|
// Step 9
|
||||||
if doc.GetBody().as_deref() == self.downcast::<HTMLElement>() &&
|
if doc.GetBody().as_deref() == self.downcast::<HTMLElement>() &&
|
||||||
doc.quirks_mode() == QuirksMode::Quirks &&
|
doc.quirks_mode() == QuirksMode::Quirks &&
|
||||||
!self.potentially_scrollable()
|
!self.is_potentially_scrollable_body()
|
||||||
{
|
{
|
||||||
win.scroll(win.ScrollX() as f64, y, behavior);
|
win.scroll(win.ScrollX() as f64, y, behavior);
|
||||||
return;
|
return;
|
||||||
|
@ -2401,7 +2413,7 @@ impl ElementMethods for Element {
|
||||||
// Step 7
|
// Step 7
|
||||||
if doc.GetBody().as_deref() == self.downcast::<HTMLElement>() &&
|
if doc.GetBody().as_deref() == self.downcast::<HTMLElement>() &&
|
||||||
doc.quirks_mode() == QuirksMode::Quirks &&
|
doc.quirks_mode() == QuirksMode::Quirks &&
|
||||||
!self.potentially_scrollable()
|
!self.is_potentially_scrollable_body()
|
||||||
{
|
{
|
||||||
return win.ScrollX() as f64;
|
return win.ScrollX() as f64;
|
||||||
}
|
}
|
||||||
|
@ -2452,7 +2464,7 @@ impl ElementMethods for Element {
|
||||||
// Step 9
|
// Step 9
|
||||||
if doc.GetBody().as_deref() == self.downcast::<HTMLElement>() &&
|
if doc.GetBody().as_deref() == self.downcast::<HTMLElement>() &&
|
||||||
doc.quirks_mode() == QuirksMode::Quirks &&
|
doc.quirks_mode() == QuirksMode::Quirks &&
|
||||||
!self.potentially_scrollable()
|
!self.is_potentially_scrollable_body()
|
||||||
{
|
{
|
||||||
win.scroll(x, win.ScrollY() as f64, behavior);
|
win.scroll(x, win.ScrollY() as f64, behavior);
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -1699,24 +1699,23 @@ impl Window {
|
||||||
|
|
||||||
// TODO Step 4 - determine if a window has a viewport
|
// TODO Step 4 - determine if a window has a viewport
|
||||||
|
|
||||||
// Step 5
|
// Step 5 & 6
|
||||||
//TODO remove scrollbar width
|
// TODO: Remove scrollbar dimensions.
|
||||||
let width = self.InnerWidth() as f64;
|
let viewport = self.window_size.get().initial_viewport;
|
||||||
// Step 6
|
|
||||||
//TODO remove scrollbar height
|
|
||||||
let height = self.InnerHeight() as f64;
|
|
||||||
|
|
||||||
// Step 7 & 8
|
// Step 7 & 8
|
||||||
//TODO use overflow direction
|
// TODO: Consider `block-end` and `inline-end` overflow direction.
|
||||||
let body = self.Document().GetBody();
|
let body = self.Document().GetBody();
|
||||||
let (x, y) = match body {
|
let (x, y) = match body {
|
||||||
Some(e) => {
|
Some(e) => {
|
||||||
let content_size = e.upcast::<Node>().bounding_content_box_or_zero();
|
let scroll_area = e.upcast::<Node>().scroll_area();
|
||||||
let content_height = content_size.size.height.to_f64_px();
|
|
||||||
let content_width = content_size.size.width.to_f64_px();
|
|
||||||
(
|
(
|
||||||
xfinite.min(content_width - width).max(0.0f64),
|
xfinite
|
||||||
yfinite.min(content_height - height).max(0.0f64),
|
.min(scroll_area.width() as f64 - viewport.width as f64)
|
||||||
|
.max(0.0f64),
|
||||||
|
yfinite
|
||||||
|
.min(scroll_area.height() as f64 - viewport.height as f64)
|
||||||
|
.max(0.0f64),
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
None => (xfinite.max(0.0f64), yfinite.max(0.0f64)),
|
None => (xfinite.max(0.0f64), yfinite.max(0.0f64)),
|
||||||
|
@ -1731,14 +1730,13 @@ impl Window {
|
||||||
//TODO Step 11
|
//TODO Step 11
|
||||||
//let document = self.Document();
|
//let document = self.Document();
|
||||||
// Step 12
|
// Step 12
|
||||||
let global_scope = self.upcast::<GlobalScope>();
|
|
||||||
let x = x.to_f32().unwrap_or(0.0f32);
|
let x = x.to_f32().unwrap_or(0.0f32);
|
||||||
let y = y.to_f32().unwrap_or(0.0f32);
|
let y = y.to_f32().unwrap_or(0.0f32);
|
||||||
self.update_viewport_for_scroll(x, y);
|
self.update_viewport_for_scroll(x, y);
|
||||||
self.perform_a_scroll(
|
self.perform_a_scroll(
|
||||||
x,
|
x,
|
||||||
y,
|
y,
|
||||||
global_scope.pipeline_id().root_scroll_id(),
|
self.upcast::<GlobalScope>().pipeline_id().root_scroll_id(),
|
||||||
behavior,
|
behavior,
|
||||||
None,
|
None,
|
||||||
);
|
);
|
||||||
|
|
2
tests/wpt/metadata/css/css-ui/text-overflow-021.html.ini
Normal file
2
tests/wpt/metadata/css/css-ui/text-overflow-021.html.ini
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
[text-overflow-021.html]
|
||||||
|
expected: FAIL
|
|
@ -1,2 +0,0 @@
|
||||||
[add-background-attachment-fixed-during-smooth-scroll.html]
|
|
||||||
expected: TIMEOUT
|
|
|
@ -1,4 +0,0 @@
|
||||||
[background-change-during-smooth-scroll.html]
|
|
||||||
expected: TIMEOUT
|
|
||||||
[background change during smooth scroll]
|
|
||||||
expected: NOTRUN
|
|
|
@ -1,6 +1,3 @@
|
||||||
[elementScroll-002.html]
|
[elementScroll-002.html]
|
||||||
[simple scroll with style: 'margin' and 'overflow: scroll']
|
[simple scroll with style: 'margin' and 'overflow: scroll']
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
[simple scroll with style: 'padding' and 'overflow: scroll']
|
|
||||||
expected: FAIL
|
|
||||||
|
|
|
@ -4,6 +4,3 @@
|
||||||
|
|
||||||
[Smooth scrolling of an element with default scroll-behavior]
|
[Smooth scrolling of an element with default scroll-behavior]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
[Instant scrolling of an element with default scroll-behavior]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
|
@ -67,48 +67,3 @@
|
||||||
|
|
||||||
[Set scrollTop to element with smooth scroll-behavior]
|
[Set scrollTop to element with smooth scroll-behavior]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
[Element with auto scroll-behavior ; scroll() with default behavior]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Element with auto scroll-behavior ; scroll() with auto behavior]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Element with auto scroll-behavior ; scroll() with instant behavior]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Element with smooth scroll-behavior ; scroll() with instant behavior]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Element with auto scroll-behavior ; scrollTo() with default behavior]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Element with auto scroll-behavior ; scrollTo() with auto behavior]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Element with auto scroll-behavior ; scrollTo() with instant behavior]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Element with smooth scroll-behavior ; scrollTo() with instant behavior]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Element with auto scroll-behavior ; scrollBy() with default behavior]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Element with auto scroll-behavior ; scrollBy() with auto behavior]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Element with auto scroll-behavior ; scrollBy() with instant behavior]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Element with smooth scroll-behavior ; scrollBy() with instant behavior]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Set scrollLeft to element with auto scroll-behavior]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Set scrollTop to element with auto scroll-behavior]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Aborting an ongoing smooth scrolling on an element with another smooth scrolling]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
|
@ -10,57 +10,3 @@
|
||||||
|
|
||||||
[Scroll positions when performing smooth scrolling from (0, 500) to (500, 250) using scrollIntoView() ]
|
[Scroll positions when performing smooth scrolling from (0, 500) to (500, 250) using scrollIntoView() ]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
[Scroll positions when performing smooth scrolling from (0, 0) to (500, 250) using scroll() ]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Scroll positions when performing smooth scrolling from (1000, 0) to (500, 250) using scroll() ]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Scroll positions when performing smooth scrolling from (0, 500) to (500, 250) using scroll() ]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Scroll positions when performing smooth scrolling from (1000, 500) to (500, 250) using scroll() ]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Scroll positions when performing smooth scrolling from (0, 0) to (500, 250) using scrollTo() ]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Scroll positions when performing smooth scrolling from (1000, 0) to (500, 250) using scrollTo() ]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Scroll positions when performing smooth scrolling from (0, 500) to (500, 250) using scrollTo() ]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Scroll positions when performing smooth scrolling from (1000, 500) to (500, 250) using scrollTo() ]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Scroll positions when performing smooth scrolling from (0, 0) to (500, 250) using scrollBy() ]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Scroll positions when performing smooth scrolling from (1000, 0) to (500, 250) using scrollBy() ]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Scroll positions when performing smooth scrolling from (0, 500) to (500, 250) using scrollBy() ]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Scroll positions when performing smooth scrolling from (1000, 500) to (500, 250) using scrollBy() ]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Scroll positions when performing smooth scrolling from 0 to 500 by setting scrollLeft ]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Scroll positions when performing smooth scrolling from 1000 to 500 by setting scrollLeft ]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Scroll positions when performing smooth scrolling from 0 to 250 by setting scrollTop ]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Scroll positions when performing smooth scrolling from 500 to 250 by setting scrollTop ]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Scroll positions when aborting a smooth scrolling with another smooth scrolling]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[Scroll positions when aborting a smooth scrolling with an instant scrolling]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
|
@ -17,15 +17,6 @@
|
||||||
[scrollingElement in non-quirks mode]
|
[scrollingElement in non-quirks mode]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
[scroll() on the root element in non-quirks mode]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[scrollBy() on the root element in non-quirks mode]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[scrollLeft/scrollTop on the root element in non-quirks mode]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[scrollWidth/scrollHeight on the root element in non-quirks mode]
|
[scrollWidth/scrollHeight on the root element in non-quirks mode]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
|
@ -43,4 +34,3 @@
|
||||||
|
|
||||||
[scrollLeft/scrollRight of the content in non-quirks mode]
|
[scrollLeft/scrollRight of the content in non-quirks mode]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
|
|
|
@ -1,4 +0,0 @@
|
||||||
[fieldset-overflow-cssomview.html]
|
|
||||||
[Test cssom-view API for FIELDSET]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue