script: Implement scrollIntoView (#38230)

This is an implementation for `scrollIntoView`. For now, it is called
when a certain element gains focus.

Testing: Existing WPT tests
Fixes: #24059

Signed-off-by: abdelrahman1234567 <abdelrahman.hossameldin.awadalla@huawei.com>
This commit is contained in:
Abdelrahman Hossam 2025-08-06 16:08:25 +08:00 committed by GitHub
parent dcb90bb85e
commit 17a269a8ad
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
34 changed files with 492 additions and 318 deletions

View file

@ -58,6 +58,7 @@ use percent_encoding::percent_decode;
use profile_traits::ipc as profile_ipc;
use profile_traits::time::TimerMetadataFrameType;
use regex::bytes::Regex;
use script_bindings::codegen::GenericBindings::ElementBinding::ElementMethods;
use script_bindings::interfaces::DocumentHelpers;
use script_bindings::script_runtime::JSContext;
use script_traits::{ConstellationInputEvent, DocumentActivity, ProgressiveWebMetricType};
@ -93,6 +94,9 @@ use crate::dom::bindings::codegen::Bindings::BeforeUnloadEventBinding::BeforeUnl
use crate::dom::bindings::codegen::Bindings::DocumentBinding::{
DocumentMethods, DocumentReadyState, DocumentVisibilityState, NamedPropertyValue,
};
use crate::dom::bindings::codegen::Bindings::ElementBinding::{
ScrollIntoViewContainer, ScrollIntoViewOptions, ScrollLogicalPosition,
};
use crate::dom::bindings::codegen::Bindings::EventBinding::Event_Binding::EventMethods;
use crate::dom::bindings::codegen::Bindings::HTMLIFrameElementBinding::HTMLIFrameElement_Binding::HTMLIFrameElementMethods;
use crate::dom::bindings::codegen::Bindings::HTMLInputElementBinding::HTMLInputElementMethods;
@ -105,12 +109,13 @@ use crate::dom::bindings::codegen::Bindings::PermissionStatusBinding::Permission
use crate::dom::bindings::codegen::Bindings::ShadowRootBinding::ShadowRootMethods;
use crate::dom::bindings::codegen::Bindings::TouchBinding::TouchMethods;
use crate::dom::bindings::codegen::Bindings::WindowBinding::{
FrameRequestCallback, ScrollBehavior, WindowMethods,
FrameRequestCallback, ScrollBehavior, ScrollOptions, WindowMethods,
};
use crate::dom::bindings::codegen::Bindings::XPathEvaluatorBinding::XPathEvaluatorMethods;
use crate::dom::bindings::codegen::Bindings::XPathNSResolverBinding::XPathNSResolver;
use crate::dom::bindings::codegen::UnionTypes::{
NodeOrString, StringOrElementCreationOptions, TrustedHTMLOrString,
BooleanOrScrollIntoViewOptions, NodeOrString, StringOrElementCreationOptions,
TrustedHTMLOrString,
};
use crate::dom::bindings::domname::{
self, is_valid_attribute_local_name, is_valid_element_local_name, namespace_from_domstring,
@ -1384,6 +1389,18 @@ impl Document {
DeviceIntRect::from_untyped(&rect.to_box2d()),
));
}
// Scroll operation to happen after element gets focus.
// This is needed to ensure that the focused element is visible.
elem.ScrollIntoView(BooleanOrScrollIntoViewOptions::ScrollIntoViewOptions(
ScrollIntoViewOptions {
parent: ScrollOptions {
behavior: ScrollBehavior::Smooth,
},
block: ScrollLogicalPosition::Center,
inline: ScrollLogicalPosition::Center,
container: ScrollIntoViewContainer::All,
},
));
}
}

View file

@ -34,6 +34,7 @@ use selectors::sink::Push;
use servo_arc::Arc;
use style::applicable_declarations::ApplicableDeclarationBlock;
use style::attr::{AttrValue, LengthOrPercentageOrAuto};
use style::computed_values::position::T as Position;
use style::context::QuirksMode;
use style::invalidation::element::restyle_hints::RestyleHint;
use style::media_queries::MediaList;
@ -73,7 +74,7 @@ use crate::dom::bindings::cell::{DomRefCell, Ref, RefMut};
use crate::dom::bindings::codegen::Bindings::AttrBinding::AttrMethods;
use crate::dom::bindings::codegen::Bindings::DocumentBinding::DocumentMethods;
use crate::dom::bindings::codegen::Bindings::ElementBinding::{
ElementMethods, GetHTMLOptions, ShadowRootInit,
ElementMethods, GetHTMLOptions, ScrollIntoViewContainer, ScrollLogicalPosition, ShadowRootInit,
};
use crate::dom::bindings::codegen::Bindings::FunctionBinding::Function;
use crate::dom::bindings::codegen::Bindings::HTMLTemplateElementBinding::HTMLTemplateElementMethods;
@ -85,7 +86,8 @@ use crate::dom::bindings::codegen::Bindings::WindowBinding::{
ScrollBehavior, ScrollToOptions, WindowMethods,
};
use crate::dom::bindings::codegen::UnionTypes::{
NodeOrString, TrustedHTMLOrNullIsEmptyString, TrustedHTMLOrString, TrustedScriptURLOrUSVString,
BooleanOrScrollIntoViewOptions, NodeOrString, TrustedHTMLOrNullIsEmptyString,
TrustedHTMLOrString, TrustedScriptURLOrUSVString,
};
use crate::dom::bindings::conversions::DerivedFrom;
use crate::dom::bindings::domname::{
@ -262,6 +264,20 @@ impl FromStr for AdjacentPosition {
}
}
/// Represents a scrolling box that can be either an element or the viewport
/// <https://drafts.csswg.org/cssom-view/#scrolling-box>
enum ScrollingBox {
Element(DomRoot<Element>),
Viewport(DomRoot<Document>),
}
/// Represents a scroll position with x and y coordinates
#[derive(Clone, Copy, Debug)]
struct ScrollPosition {
x: f64,
y: f64,
}
//
// Element methods
//
@ -852,6 +868,377 @@ impl Element {
let result = media_list.evaluate(document.window().layout().device(), quirks_mode);
result
}
/// <https://drafts.csswg.org/cssom-view/#scroll-a-target-into-view>
fn scroll_into_view_with_options(
&self,
behavior: ScrollBehavior,
block: ScrollLogicalPosition,
inline: ScrollLogicalPosition,
container: Option<&Element>,
) {
let target_document = self.upcast::<Node>().owner_doc();
// Step 1: For each ancestor element or viewport that establishes a scrolling box,
// in order of innermost to outermost scrolling box
let mut out_of_bound = false;
self.upcast::<Node>()
.inclusive_ancestors(ShadowIncluding::Yes)
.skip(1) // Skip self
.filter(|node| self.establishes_scroll_box(node))
.map_while(|node| {
if out_of_bound {
return None;
}
let scrolling_box = if node.is::<Document>() {
let document = node.downcast::<Document>().unwrap();
ScrollingBox::Viewport(DomRoot::from_ref(document))
} else {
let element = node.downcast::<Element>().unwrap();
ScrollingBox::Element(DomRoot::from_ref(element))
};
// Step 1.4: Check container stopping condition
if let Some(container) = container {
// If container is not null and either scrolling box is a
// shadow-including inclusive ancestor of container or is a viewport
// whose document is a shadow-including inclusive ancestor of
// container, abort the rest of these steps.
let stop_condition = match scrolling_box {
ScrollingBox::Element(ref element) => {
// Check if the scrolling box element is a shadow-including inclusive ancestor of container
element
.upcast::<Node>()
.is_shadow_including_inclusive_ancestor_of(
container.upcast::<Node>(),
)
},
ScrollingBox::Viewport(ref document) => {
// Check if the viewport's document is a shadow-including inclusive ancestor of container
document
.upcast::<Node>()
.is_shadow_including_inclusive_ancestor_of(
container.upcast::<Node>(),
)
},
};
if stop_condition {
out_of_bound = true;
}
}
Some(scrolling_box)
})
.for_each(|scrolling_box| {
match scrolling_box {
ScrollingBox::Element(ref element) => {
// Step 1.1: Check same origin
let scrolling_box_document = element.upcast::<Node>().owner_doc();
if !target_document
.origin()
.same_origin(scrolling_box_document.origin())
{
return;
}
// Step 1.2: Determine scroll position
let position = self.determine_scroll_into_view_position(
element.upcast::<Node>(),
block,
inline,
);
// Step 1.3: Check if scroll is needed
// TODO: check if scrolling box has an ongoing smooth scroll
let current_scroll_x = element.ScrollLeft();
let current_scroll_y = element.ScrollTop();
if position.x != current_scroll_x || position.y != current_scroll_y {
// Step 1.3.1: If scrolling box is associated with an element:
// Perform a scroll of the elements scrolling box to position,
// with the element as the associated element and behavior as the scroll behavior.
let window = target_document.window();
window.scroll_an_element(element, position.x, position.y, behavior);
}
},
ScrollingBox::Viewport(ref viewport) => {
// Step 1.1: Check same origin (viewport is always same origin with target)
// Step 1.2: Determine scroll position
let position = self.determine_scroll_into_view_position(
viewport.upcast::<Node>(),
block,
inline,
);
// Step 1.3: Check if scroll is needed
let window = viewport.window();
let current_scroll_x = window.ScrollX() as f64;
let current_scroll_y = window.ScrollY() as f64;
if position.x != current_scroll_x || position.y != current_scroll_y {
// Step 1.3.2: Perform a scroll of the viewport to position, with root
// element as the associated element
window.scroll(position.x, position.y, behavior);
}
},
}
});
}
/// Check if an element establishes a scrolling box
fn establishes_scroll_box(&self, node: &Node) -> bool {
if node.is::<Document>() {
true // Document's viewport is always a scrolling box
} else if node.is::<Element>() {
let element: &Element = node.downcast::<Element>().unwrap();
if let Some(style) = element.style() {
let overflow_x = style.get_box().clone_overflow_x();
let overflow_y = style.get_box().clone_overflow_y();
return overflow_x.is_scrollable() || overflow_y.is_scrollable();
} else {
false // Element without style is not a scrolling box
}
} else {
false // Shadow roots and other nodes are not scrolling boxes
}
}
/// <https://drafts.csswg.org/cssom-view/#element-scrolling-members>
fn determine_scroll_into_view_position(
&self,
scrolling_node: &Node,
block: ScrollLogicalPosition,
inline: ScrollLogicalPosition,
) -> ScrollPosition {
let target_bounding_box = self.upcast::<Node>().bounding_content_box_or_zero();
let device_pixel_ratio = self
.upcast::<Node>()
.owner_doc()
.window()
.device_pixel_ratio()
.get();
// Target element bounds
let element_left = target_bounding_box
.origin
.x
.to_nearest_pixel(device_pixel_ratio) as f64;
let element_top = target_bounding_box
.origin
.y
.to_nearest_pixel(device_pixel_ratio) as f64;
let element_width = target_bounding_box
.size
.width
.to_nearest_pixel(device_pixel_ratio) as f64;
let element_height = target_bounding_box
.size
.height
.to_nearest_pixel(device_pixel_ratio) as f64;
let element_right = element_left + element_width;
let element_bottom = element_top + element_height;
let (target_x, target_y) = if scrolling_node.is::<Document>() {
// Handle document-specific scrolling
// Viewport bounds and current scroll position
let owner_doc = self.upcast::<Node>().owner_doc();
let window = owner_doc.window();
let viewport_width = window.InnerWidth() as f64;
let viewport_height = window.InnerHeight() as f64;
let current_scroll_x = window.ScrollX() as f64;
let current_scroll_y = window.ScrollY() as f64;
// For viewport scrolling, we need to add current scroll to get document-relative positions
let document_element_left = element_left + current_scroll_x;
let document_element_top = element_top + current_scroll_y;
let document_element_right = element_right + current_scroll_x;
let document_element_bottom = element_bottom + current_scroll_y;
(
self.calculate_scroll_position_one_axis(
inline,
document_element_left,
document_element_right,
element_width,
viewport_width,
current_scroll_x,
),
self.calculate_scroll_position_one_axis(
block,
document_element_top,
document_element_bottom,
element_height,
viewport_height,
current_scroll_y,
),
)
} else {
// Handle element-specific scrolling
// Scrolling box bounds and current scroll position
let scrolling_box = scrolling_node.bounding_content_box_or_zero();
let scrolling_left = scrolling_box.origin.x.to_nearest_pixel(device_pixel_ratio) as f64;
let scrolling_top = scrolling_box.origin.y.to_nearest_pixel(device_pixel_ratio) as f64;
let scrolling_width = scrolling_box
.size
.width
.to_nearest_pixel(device_pixel_ratio) as f64;
let scrolling_height = scrolling_box
.size
.height
.to_nearest_pixel(device_pixel_ratio) as f64;
let current_scroll_x = scrolling_node.downcast::<Element>().unwrap().ScrollLeft();
let current_scroll_y = scrolling_node.downcast::<Element>().unwrap().ScrollTop();
// Calculate element position in scroller's content coordinate system
// Element's viewport position relative to scroller, then add scroll offset to get content position
let viewport_relative_left = element_left - scrolling_left;
let viewport_relative_top = element_top - scrolling_top;
let viewport_relative_right = element_right - scrolling_left;
let viewport_relative_bottom = element_bottom - scrolling_top;
// For absolutely positioned elements, we need to account for the positioning context
// If the element is positioned relative to an ancestor that's within the scrolling container,
// we need to adjust coordinates accordingly
let (
adjusted_relative_left,
adjusted_relative_top,
adjusted_relative_right,
adjusted_relative_bottom,
) = {
// Check if this element has a positioned ancestor between it and the scrolling container
let mut current_node = self.upcast::<Node>().GetParentNode();
let mut final_coords = (
viewport_relative_left,
viewport_relative_top,
viewport_relative_right,
viewport_relative_bottom,
);
while let Some(node) = current_node {
// Stop if we reach the scrolling container
if &*node == scrolling_node {
break;
}
// Check if this node establishes a positioning context and has position relative/absolute
if let Some(element) = node.downcast::<Element>() {
if let Some(computed_style) = element.style() {
let position = computed_style.get_box().position;
if matches!(position, Position::Relative | Position::Absolute) {
// If this element establishes a positioning context,
// Get its bounding box to calculate the offset
let positioning_box = node.bounding_content_box_or_zero();
let positioning_left = positioning_box
.origin
.x
.to_nearest_pixel(device_pixel_ratio)
as f64;
let positioning_top = positioning_box
.origin
.y
.to_nearest_pixel(device_pixel_ratio)
as f64;
// Calculate the offset of the positioning context relative to the scrolling container
let offset_left = positioning_left - scrolling_left;
let offset_top = positioning_top - scrolling_top;
// Adjust the coordinates by subtracting the positioning context offset
final_coords = (
viewport_relative_left - offset_left,
viewport_relative_top - offset_top,
viewport_relative_right - offset_left,
viewport_relative_bottom - offset_top,
);
break;
}
}
}
current_node = node.GetParentNode();
}
final_coords
};
let content_element_left = adjusted_relative_left + current_scroll_x;
let content_element_top = adjusted_relative_top + current_scroll_y;
let content_element_right = adjusted_relative_right + current_scroll_x;
let content_element_bottom = adjusted_relative_bottom + current_scroll_y;
(
self.calculate_scroll_position_one_axis(
inline,
content_element_left,
content_element_right,
element_width,
scrolling_width,
current_scroll_x,
),
self.calculate_scroll_position_one_axis(
block,
content_element_top,
content_element_bottom,
element_height,
scrolling_height,
current_scroll_y,
),
)
};
ScrollPosition {
x: target_x,
y: target_y,
}
}
fn calculate_scroll_position_one_axis(
&self,
alignment: ScrollLogicalPosition,
element_start: f64,
element_end: f64,
element_size: f64,
container_size: f64,
current_scroll_offset: f64,
) -> f64 {
match alignment {
// Step 1 & 5: If inline is "start", then align element start edge with scrolling box start edge.
ScrollLogicalPosition::Start => element_start,
// Step 2 & 6: If inline is "end", then align element end edge with
// scrolling box end edge.
ScrollLogicalPosition::End => element_end - container_size,
// Step 3 & 7: If inline is "center", then align the center of target bounding
// border box with the center of scrolling box in scrolling boxs inline base direction.
ScrollLogicalPosition::Center => element_start + (element_size - container_size) / 2.0,
// Step 4 & 8: If inline is "nearest",
ScrollLogicalPosition::Nearest => {
let viewport_start = current_scroll_offset;
let viewport_end = current_scroll_offset + container_size;
// Step 4.2 & 8.2: If element start edge is outside scrolling box start edge and element
// size is less than scrolling box size or If element end edge is outside
// scrolling box end edge and element size is greater than scrolling box size:
// Align element start edge with scrolling box start edge.
if (element_start < viewport_start && element_size <= container_size) ||
(element_end > viewport_end && element_size >= container_size)
{
element_start
}
// Step 4.3 & 8.3: If element end edge is outside scrolling box start edge and element
// size is greater than scrolling box size or If element start edge is outside
// scrolling box end edge and element size is less than scrolling box size:
// Align element end edge with scrolling box end edge.
else if (element_end > viewport_end && element_size < container_size) ||
(element_start < viewport_start && element_size > container_size)
{
element_end - container_size
}
// Step 4.1 & 8.1: If element start edge and element end edge are both outside scrolling
// box start edge and scrolling box end edge or an invalid situation: Do nothing.
else {
current_scroll_offset
}
},
}
}
}
/// <https://dom.spec.whatwg.org/#valid-shadow-host-name>
@ -3219,7 +3606,7 @@ impl ElementMethods<crate::DomTypeHolder> for Element {
win.scroll_an_element(self, self.ScrollLeft(), y, behavior);
}
// https://drafts.csswg.org/cssom-view/#dom-element-scrolltop
// https://drafts.csswg.org/cssom-view/#dom-element-scrollleft
fn ScrollLeft(&self) -> f64 {
let node = self.upcast::<Node>();
@ -3316,6 +3703,52 @@ impl ElementMethods<crate::DomTypeHolder> for Element {
win.scroll_an_element(self, x, self.ScrollTop(), behavior);
}
/// <https://drafts.csswg.org/cssom-view/#dom-element-scrollintoview>
fn ScrollIntoView(&self, arg: BooleanOrScrollIntoViewOptions) {
let (behavior, block, inline, container) = match arg {
// If arg is true:
BooleanOrScrollIntoViewOptions::Boolean(true) => (
ScrollBehavior::Auto, // Step 1: Let behavior be "auto".
ScrollLogicalPosition::Start, // Step 2: Let block be "start".
ScrollLogicalPosition::Nearest, // Step 3: Let inline be "nearest".
None, // Step 4: Let container be null.
),
// Step 5: If arg is a ScrollIntoViewOptions dictionary, set its properties
// to the corresponding values in the dictionary.
BooleanOrScrollIntoViewOptions::ScrollIntoViewOptions(options) => (
options.parent.behavior,
options.block,
options.inline,
// Step 5.4: If the container dictionary member of options is "nearest",
// set container to the element.
if options.container == ScrollIntoViewContainer::Nearest {
Some(self)
} else {
None
},
),
// Step 6: Otherwise, if arg is false, then set block to "end".
BooleanOrScrollIntoViewOptions::Boolean(false) => (
ScrollBehavior::Auto,
ScrollLogicalPosition::End,
ScrollLogicalPosition::Nearest,
None,
),
};
// Step 7: If the element does not have any associated box, or is not
// available to user-agent features, then return.
if !self.has_css_layout_box() {
return;
}
// Step 8: Scroll the element into view with behavior, block, inline, and container.
self.scroll_into_view_with_options(behavior, block, inline, container);
// Step 9: Optionally perform some other action that brings the
// element to the users attention.
}
// https://drafts.csswg.org/cssom-view/#dom-element-scrollwidth
fn ScrollWidth(&self) -> i32 {
self.upcast::<Node>().scroll_area().size.width

View file

@ -102,6 +102,7 @@ partial interface Element {
[NewObject]
DOMRect getBoundingClientRect();
undefined scrollIntoView(optional (boolean or ScrollIntoViewOptions) arg = {});
undefined scroll(optional ScrollToOptions options = {});
undefined scroll(unrestricted double x, unrestricted double y);
@ -134,6 +135,16 @@ dictionary GetHTMLOptions {
sequence<ShadowRoot> shadowRoots = [];
};
// https://drafts.csswg.org/cssom-view/#dictdef-scrollintoviewoptions
dictionary ScrollIntoViewOptions : ScrollOptions {
ScrollLogicalPosition block = "start";
ScrollLogicalPosition inline = "nearest";
ScrollIntoViewContainer container = "all";
};
enum ScrollLogicalPosition { "start", "center", "end", "nearest" };
enum ScrollIntoViewContainer { "all", "nearest" };
// https://fullscreen.spec.whatwg.org/#api
partial interface Element {
Promise<undefined> requestFullscreen();

View file

@ -1,2 +1,2 @@
[position-sticky-fixed-ancestor-iframe.html]
expected: TIMEOUT
expected: FAIL

View file

@ -1,3 +0,0 @@
[position-sticky-input-box-gets-focused-after-scroll.html]
[Focusing on visible sticky input box should reset the scroll to unshifted sticky position.]
expected: FAIL

View file

@ -1,4 +1,5 @@
[elementFromPoint.html]
expected: CRASH
[SVG element at x,y]
expected: FAIL

View file

@ -266,9 +266,6 @@
[Element interface: document.createElement("div") must inherit property "scrollIntoView([object Object\],[object Object\])" with the proper type]
expected: FAIL
[Element interface: calling scrollIntoView(optional (boolean or ScrollIntoViewOptions)) on document.createElement("img") with too few arguments must throw TypeError]
expected: FAIL
[Element interface: document.createElement("img") must inherit property "convertQuadFromNode(DOMQuadInit, GeometryNode, optional ConvertCoordinateOptions)" with the proper type]
expected: FAIL
@ -278,9 +275,6 @@
[CSSPseudoElement interface: operation convertPointFromNode(DOMPointInit, GeometryNode, optional ConvertCoordinateOptions)]
expected: FAIL
[Element interface: document.createElementNS("x", "y") must inherit property "scrollIntoView(optional (boolean or ScrollIntoViewOptions))" with the proper type]
expected: FAIL
[Element interface: document.createElement("img") must inherit property "getBoxQuads(optional BoxQuadOptions)" with the proper type]
expected: FAIL
@ -401,15 +395,6 @@
[Text interface: calling getBoxQuads(optional BoxQuadOptions) on document.createTextNode("x") with too few arguments must throw TypeError]
expected: FAIL
[Element interface: calling scrollIntoView(optional (boolean or ScrollIntoViewOptions)) on document.createElement("div") with too few arguments must throw TypeError]
expected: FAIL
[Element interface: document.createElement("img") must inherit property "scrollIntoView(optional (boolean or ScrollIntoViewOptions))" with the proper type]
expected: FAIL
[Element interface: operation scrollIntoView(optional (boolean or ScrollIntoViewOptions))]
expected: FAIL
[Document interface: document must inherit property "convertPointFromNode(DOMPointInit, GeometryNode, optional ConvertCoordinateOptions)" with the proper type]
expected: FAIL
@ -422,12 +407,6 @@
[CSSPseudoElement interface: operation getBoxQuads(optional BoxQuadOptions)]
expected: FAIL
[Element interface: calling scrollIntoView(optional (boolean or ScrollIntoViewOptions)) on document.createElementNS("x", "y") with too few arguments must throw TypeError]
expected: FAIL
[Element interface: document.createElement("div") must inherit property "scrollIntoView(optional (boolean or ScrollIntoViewOptions))" with the proper type]
expected: FAIL
[Element interface: document.createElementNS("x", "y") must inherit property "convertRectFromNode(DOMRectReadOnly, GeometryNode, optional ConvertCoordinateOptions)" with the proper type]
expected: FAIL

View file

@ -35,15 +35,6 @@
[Element with smooth scroll-behavior ; scrollBy() with smooth behavior]
expected: FAIL
[Element with auto scroll-behavior ; scrollIntoView() with default behavior]
expected: FAIL
[Element with auto scroll-behavior ; scrollIntoView() with auto behavior]
expected: FAIL
[Element with auto scroll-behavior ; scrollIntoView() with instant behavior]
expected: FAIL
[Element with auto scroll-behavior ; scrollIntoView() with smooth behavior]
expected: FAIL
@ -53,9 +44,6 @@
[Element with smooth scroll-behavior ; scrollIntoView() with auto behavior]
expected: FAIL
[Element with smooth scroll-behavior ; scrollIntoView() with instant behavior]
expected: FAIL
[Element with smooth scroll-behavior ; scrollIntoView() with smooth behavior]
expected: FAIL

View file

@ -35,15 +35,6 @@
[Main frame with smooth scroll-behavior ; scrollBy() with smooth behavior]
expected: FAIL
[Main frame with auto scroll-behavior ; scrollIntoView() with default behavior]
expected: FAIL
[Main frame with auto scroll-behavior ; scrollIntoView() with auto behavior]
expected: FAIL
[Main frame with auto scroll-behavior ; scrollIntoView() with instant behavior]
expected: FAIL
[Main frame with auto scroll-behavior ; scrollIntoView() with smooth behavior]
expected: FAIL
@ -53,9 +44,6 @@
[Main frame with smooth scroll-behavior ; scrollIntoView() with auto behavior]
expected: FAIL
[Main frame with smooth scroll-behavior ; scrollIntoView() with instant behavior]
expected: FAIL
[Main frame with smooth scroll-behavior ; scrollIntoView() with smooth behavior]
expected: FAIL

View file

@ -1,15 +1,3 @@
[scroll-behavior-smooth-positions.html]
[Scroll positions when performing smooth scrolling from (0, 500) to (500, 250) using scrollIntoView() ]
expected: FAIL
[Scroll positions when performing smooth scrolling from (1000, 500) to (500, 250) using scrollIntoView() ]
expected: FAIL
[Scroll positions when performing smooth scrolling from (0, 0) to (500, 250) using scrollIntoView() ]
expected: FAIL
[Scroll positions when performing smooth scrolling from (1000, 0) to (500, 250) using scrollIntoView() ]
expected: FAIL
[Make sure the page is ready for animation.]
expected: FAIL
expected: FAIL

View file

@ -35,15 +35,6 @@
[Subframe with smooth scroll-behavior ; scrollBy() with smooth behavior]
expected: FAIL
[Subframe with auto scroll-behavior ; scrollIntoView() with default behavior]
expected: FAIL
[Subframe with auto scroll-behavior ; scrollIntoView() with auto behavior]
expected: FAIL
[Subframe with auto scroll-behavior ; scrollIntoView() with instant behavior]
expected: FAIL
[Subframe with auto scroll-behavior ; scrollIntoView() with smooth behavior]
expected: FAIL
@ -53,9 +44,6 @@
[Subframe with smooth scroll-behavior ; scrollIntoView() with auto behavior]
expected: FAIL
[Subframe with smooth scroll-behavior ; scrollIntoView() with instant behavior]
expected: FAIL
[Subframe with smooth scroll-behavior ; scrollIntoView() with smooth behavior]
expected: FAIL

View file

@ -1,3 +0,0 @@
[scrollIntoView-align-scrollport-covering-child.html]
[scrollIntoView scrolls scrollport-covering child in both axes]
expected: FAIL

View file

@ -1,15 +0,0 @@
[scrollIntoView-container.html]
[scrollIntoView() defaults to scrolling ancestors]
expected: FAIL
[scrollIntoView({container: 'all'}) scrolls ancestors]
expected: FAIL
[scrollIntoView({container: 'nearest'}) only scrolls nearest scroll container]
expected: FAIL
[scrollIntoView({container: 'nearest'}) doesn't stop at itself]
expected: FAIL
[scrollIntoView({container: 'nearest'}) doesn't propagate to outer frames]
expected: FAIL

View file

@ -1,4 +0,0 @@
[scrollIntoView-horizontal-partially-visible.html]
[scrollIntoView scrolls partially-visible child in both axes]
expected: FAIL

View file

@ -1,28 +0,0 @@
[scrollIntoView-horizontal-tb-writing-mode.html]
[scrollIntoView({"block":"center","inline":"center"})]
expected: FAIL
[scrollIntoView({"block":"end","inline":"start"})]
expected: FAIL
[scrollIntoView({"block":"start","inline":"center"})]
expected: FAIL
[scrollIntoView({"block":"center","inline":"start"})]
expected: FAIL
[scrollIntoView({"block":"start","inline":"start"})]
expected: FAIL
[scrollIntoView({"block":"end","inline":"center"})]
expected: FAIL
[scrollIntoView({"block":"end","inline":"end"})]
expected: FAIL
[scrollIntoView({"block":"start","inline":"end"})]
expected: FAIL
[scrollIntoView({"block":"center","inline":"end"})]
expected: FAIL

View file

@ -1,4 +0,0 @@
[scrollIntoView-inline-image.html]
[Scrolling an inline element with a large line height uses the bounding rect]
expected: FAIL

View file

@ -1,12 +1,13 @@
[scrollIntoView-multiple-nested.html]
expected: TIMEOUT
[Simultaneous smooth scrollIntoViews run to completion]
expected: FAIL
expected: TIMEOUT
[Simultaneous smooth,instant scrollIntoViews run to completion]
expected: FAIL
expected: NOTRUN
[Simultaneous instant,smooth scrollIntoViews run to completion]
expected: FAIL
expected: NOTRUN
[Simultaneous instant scrollIntoViews run to completion]
expected: FAIL
expected: NOTRUN

View file

@ -1,12 +1,13 @@
[scrollIntoView-multiple.html]
expected: TIMEOUT
[Simultaneous smooth scrollIntoViews run to completion]
expected: FAIL
expected: TIMEOUT
[Simultaneous smooth,instant scrollIntoViews run to completion]
expected: FAIL
expected: NOTRUN
[Simultaneous instant,smooth scrollIntoViews run to completion]
expected: FAIL
expected: NOTRUN
[Simultaneous instant scrollIntoViews run to completion]
expected: FAIL
expected: NOTRUN

View file

@ -1,4 +0,0 @@
[scrollIntoView-shadow.html]
[scrollIntoView should behave correctly if applies to shadow dom elements]
expected: FAIL

View file

@ -1,13 +1,13 @@
[scrollIntoView-smooth.html]
expected: TIMEOUT
[Smooth scrollIntoView should scroll the element to the 'center' position]
expected: FAIL
expected: NOTRUN
[Smooth scrollIntoView should scroll the element to the 'end' position]
expected: FAIL
expected: NOTRUN
[Smooth scrollIntoView should scroll the element to the 'nearest' position]
expected: FAIL
expected: TIMEOUT
[Smooth scrollIntoView should scroll the element to the 'start' position]
expected: FAIL
expected: NOTRUN

View file

@ -1,7 +1,4 @@
[scrollIntoView-vertical-lr-writing-mode.html]
[scrollIntoView({"block":"center","inline":"center"})]
expected: FAIL
[scrollIntoView({"block":"end","inline":"start"})]
expected: FAIL
@ -11,18 +8,11 @@
[scrollIntoView({"block":"center","inline":"start"})]
expected: FAIL
[scrollIntoView({"block":"start","inline":"start"})]
expected: FAIL
[scrollIntoView({"block":"end","inline":"center"})]
expected: FAIL
[scrollIntoView({"block":"end","inline":"end"})]
expected: FAIL
[scrollIntoView({"block":"start","inline":"end"})]
expected: FAIL
[scrollIntoView({"block":"center","inline":"end"})]
expected: FAIL

View file

@ -1,3 +0,0 @@
[scrollintoview-containingblock-chain.html]
[scrollIntoView should not scroll ancestor overflow:scroll elements that are not containing block ancestors]
expected: FAIL

View file

@ -1,121 +0,0 @@
[scrollintoview.html]
[scrollIntoView(null) starting at right,top]
expected: FAIL
[scrollIntoView({block: "start", inline: "start"}) starting at right,top]
expected: FAIL
[scrollIntoView({block: "nearest", inline: "nearest"}) starting at left,top]
expected: FAIL
[scrollIntoView(false) starting at right,top]
expected: FAIL
[scrollIntoView({block: "end", inline: "end"}) starting at right,top]
expected: FAIL
[scrollIntoView() starting at right,top]
expected: FAIL
[scrollIntoView(undefined) starting at left,bottom]
expected: FAIL
[scrollIntoView(false) starting at left,bottom]
expected: FAIL
[scrollIntoView({}) starting at right,top]
expected: FAIL
[scrollIntoView({block: "end", inline: "end"}) starting at left,top]
expected: FAIL
[scrollIntoView() starting at right,bottom]
expected: FAIL
[scrollIntoView({block: "nearest", inline: "nearest"}) starting at right,top]
expected: FAIL
[scrollIntoView(undefined) starting at right,bottom]
expected: FAIL
[scrollIntoView(true) starting at left,top]
expected: FAIL
[scrollIntoView({block: "start", inline: "start"}) starting at left,top]
expected: FAIL
[scrollIntoView({block: "center", inline: "center"}) starting at left,bottom]
expected: FAIL
[scrollIntoView({block: "end", inline: "end"}) starting at left,bottom]
expected: FAIL
[scrollIntoView(true) starting at left,bottom]
expected: FAIL
[scrollIntoView({block: "center", inline: "center"}) starting at right,bottom]
expected: FAIL
[scrollIntoView(true) starting at right,bottom]
expected: FAIL
[scrollIntoView({block: "nearest", inline: "nearest"}) starting at right,bottom]
expected: FAIL
[scrollIntoView(false) starting at right,bottom]
expected: FAIL
[scrollIntoView({}) starting at right,bottom]
expected: FAIL
[scrollIntoView({block: "center", inline: "center"}) starting at right,top]
expected: FAIL
[scrollIntoView(false) starting at left,top]
expected: FAIL
[scrollIntoView() starting at left,top]
expected: FAIL
[scrollIntoView(undefined) starting at left,top]
expected: FAIL
[scrollIntoView({}) starting at left,top]
expected: FAIL
[scrollIntoView({block: "end", inline: "end"}) starting at right,bottom]
expected: FAIL
[scrollIntoView(null) starting at right,bottom]
expected: FAIL
[scrollIntoView(null) starting at left,top]
expected: FAIL
[scrollIntoView({block: "start", inline: "start"}) starting at right,bottom]
expected: FAIL
[scrollIntoView({block: "center", inline: "center"}) starting at left,top]
expected: FAIL
[scrollIntoView({block: "nearest", inline: "nearest"}) starting at left,bottom]
expected: FAIL
[scrollIntoView(null) starting at left,bottom]
expected: FAIL
[scrollIntoView({block: "start", inline: "start"}) starting at left,bottom]
expected: FAIL
[scrollIntoView(true) starting at right,top]
expected: FAIL
[scrollIntoView(undefined) starting at right,top]
expected: FAIL
[scrollIntoView() starting at left,bottom]
expected: FAIL
[scrollIntoView({}) starting at left,bottom]
expected: FAIL

View file

@ -1,3 +0,0 @@
[focus-centers-element.html]
[Element.focus() center in both directions]
expected: FAIL

View file

@ -1,4 +0,0 @@
[scroll-matches-focus.html]
expected: TIMEOUT
[:focus applies before scrolling into view]
expected: TIMEOUT

View file

@ -1,2 +1,2 @@
[hidden-until-found-001.html]
expected: TIMEOUT
expected: FAIL

View file

@ -0,0 +1,3 @@
[preventScroll-nested-scroll-elements.html]
[focus(options) - preventScroll on nested scroll elements]
expected: FAIL

View file

@ -0,0 +1,3 @@
[preventScroll-textarea.html]
[preventScroll: true on a textarea element]
expected: FAIL

View file

@ -1,18 +1,3 @@
[preventScroll.html]
[Sanity test]
expected: FAIL
[elm.focus() without arguments]
expected: FAIL
[elm.focus(undefined)]
expected: FAIL
[elm.focus(null)]
expected: FAIL
[elm.focus({})]
expected: FAIL
[elm.focus({preventScroll: false})]
[elm.focus({preventScroll: true})]
expected: FAIL

View file

@ -1,4 +0,0 @@
[textarea-scroll-selection.html]
[programatic focus() scrolls selection into view including ancestors]
expected: FAIL

View file

@ -1,5 +1,4 @@
[iframe-loading-lazy.html]
expected: ERROR
[Below-viewport srcdoc iframes load lazily]
expected: FAIL

View file

@ -1,4 +1,3 @@
[move-element-and-scroll.html]
expected: ERROR
[Test that <img> below viewport is not loaded when moved to another document and then scrolled to]
expected: FAIL

View file

@ -1,4 +1,3 @@
[remove-element-and-scroll.html]
expected: ERROR
[Test that <img> below viewport is not loaded when removed from the document and then scrolled to]
expected: FAIL

View file

@ -1,3 +0,0 @@
[scrolling-below-viewport-image-lazy-loading-in-iframe.html]
[Scrolling a lazy loaded image into view in an iframe]
expected: FAIL