script: Modify Element::determine_scroll_into_view_position to take a ScrollingBox (#39107)

There is no need to separate the two kinds of scrolling boxes into
`Element` and `Viewport` more than once. This also eliminates a
potentially panicking `unwrap()`. 

Testing: This doesn't change behavior and is thus covered by existing
tests.

Signed-off-by: Martin Robinson <mrobinson@igalia.com>
This commit is contained in:
Martin Robinson 2025-09-04 01:44:57 -07:00 committed by GitHub
parent dab195ca80
commit fa7d6d4004
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -899,7 +899,7 @@ impl Element {
// determine the scroll-into-view position of `target` with `behavior` as the scroll // determine the scroll-into-view position of `target` with `behavior` as the scroll
// behavior, `block` as the block flow position, `inline` as the inline base direction // behavior, `block` as the block flow position, `inline` as the inline base direction
// position and `scrolling box` as the scrolling box. // position and `scrolling box` as the scrolling box.
let position = self.determine_scroll_into_view_position(&node, block, inline); let position = self.determine_scroll_into_view_position(&scrolling_box, block, inline);
// Step 1.3: If `position` is not the same as `scrolling box`s current scroll position, or // Step 1.3: If `position` is not the same as `scrolling box`s current scroll position, or
// `scrolling box` has an ongoing smooth scroll, // `scrolling box` has an ongoing smooth scroll,
@ -942,7 +942,7 @@ impl Element {
/// <https://drafts.csswg.org/cssom-view/#element-scrolling-members> /// <https://drafts.csswg.org/cssom-view/#element-scrolling-members>
fn determine_scroll_into_view_position( fn determine_scroll_into_view_position(
&self, &self,
scrolling_node: &Node, scrolling_box: &ScrollingBox,
block: ScrollLogicalPosition, block: ScrollLogicalPosition,
inline: ScrollLogicalPosition, inline: ScrollLogicalPosition,
) -> LayoutVector2D { ) -> LayoutVector2D {
@ -975,156 +975,150 @@ impl Element {
let element_right = element_left + element_width; let element_right = element_left + element_width;
let element_bottom = element_top + element_height; let element_bottom = element_top + element_height;
let (target_x, target_y) = if scrolling_node.is::<Document>() { let (target_x, target_y) = match scrolling_box {
// Handle document-specific scrolling ScrollingBox::Viewport(document) => {
// Viewport bounds and current scroll position let window = document.window();
let owner_doc = self.upcast::<Node>().owner_doc(); let viewport_width = window.InnerWidth() as f32;
let window = owner_doc.window(); let viewport_height = window.InnerHeight() as f32;
let viewport_width = window.InnerWidth() as f32; let current_scroll_x = window.ScrollX() as f32;
let viewport_height = window.InnerHeight() as f32; let current_scroll_y = window.ScrollY() as f32;
let current_scroll_x = window.ScrollX() as f32;
let current_scroll_y = window.ScrollY() as f32;
// For viewport scrolling, we need to add current scroll to get document-relative positions // 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_left = element_left + current_scroll_x;
let document_element_top = element_top + current_scroll_y; let document_element_top = element_top + current_scroll_y;
let document_element_right = element_right + current_scroll_x; let document_element_right = element_right + current_scroll_x;
let document_element_bottom = element_bottom + current_scroll_y; let document_element_bottom = element_bottom + current_scroll_y;
( (
self.calculate_scroll_position_one_axis( self.calculate_scroll_position_one_axis(
inline, inline,
document_element_left, document_element_left,
document_element_right, document_element_right,
element_width, element_width,
viewport_width, viewport_width,
current_scroll_x, current_scroll_x,
), ),
self.calculate_scroll_position_one_axis( self.calculate_scroll_position_one_axis(
block, block,
document_element_top, document_element_top,
document_element_bottom, document_element_bottom,
element_height, element_height,
viewport_height, viewport_height,
current_scroll_y, current_scroll_y,
), ),
) )
} else { },
// Handle element-specific scrolling ScrollingBox::Element(scrolling_element) => {
// Scrolling box bounds and current scroll position let scrolling_node = scrolling_element.upcast::<Node>();
let scrolling_box = scrolling_node.border_box().unwrap_or_default(); let scrolling_box = scrolling_node.border_box().unwrap_or_default();
let scrolling_left = scrolling_box.origin.x.to_nearest_pixel(device_pixel_ratio); let scrolling_left = scrolling_box.origin.x.to_nearest_pixel(device_pixel_ratio);
let scrolling_top = scrolling_box.origin.y.to_nearest_pixel(device_pixel_ratio); let scrolling_top = scrolling_box.origin.y.to_nearest_pixel(device_pixel_ratio);
let scrolling_width = scrolling_box let scrolling_width = scrolling_box
.size .size
.width .width
.to_nearest_pixel(device_pixel_ratio); .to_nearest_pixel(device_pixel_ratio);
let scrolling_height = scrolling_box let scrolling_height = scrolling_box
.size .size
.height .height
.to_nearest_pixel(device_pixel_ratio); .to_nearest_pixel(device_pixel_ratio);
// TODO: This function should accept `Element` and not `Node`. // Calculate element position in scroller's content coordinate system
let scrolling_element = scrolling_node // Element's viewport position relative to scroller, then add scroll offset to get content position
.downcast::<Element>() let viewport_relative_left = element_left - scrolling_left;
.expect("Should be provided an Element."); let viewport_relative_top = element_top - scrolling_top;
let current_scroll_x = scrolling_element.ScrollLeft() as f32; let viewport_relative_right = element_right - scrolling_left;
let current_scroll_y = scrolling_element.ScrollTop() as f32; let viewport_relative_bottom = element_bottom - scrolling_top;
// Calculate element position in scroller's content coordinate system // For absolutely positioned elements, we need to account for the positioning context
// Element's viewport position relative to scroller, then add scroll offset to get content position // If the element is positioned relative to an ancestor that's within the scrolling container,
let viewport_relative_left = element_left - scrolling_left; // we need to adjust coordinates accordingly
let viewport_relative_top = element_top - scrolling_top; let (
let viewport_relative_right = element_right - scrolling_left; adjusted_relative_left,
let viewport_relative_bottom = element_bottom - scrolling_top; 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,
);
// For absolutely positioned elements, we need to account for the positioning context while let Some(node) = current_node {
// If the element is positioned relative to an ancestor that's within the scrolling container, // Stop if we reach the scrolling container
// we need to adjust coordinates accordingly if &*node == scrolling_node {
let ( break;
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 { // Check if this node establishes a positioning context and has position relative/absolute
// Stop if we reach the scrolling container if let Some(element) = node.downcast::<Element>() {
if &*node == scrolling_node { if let Some(computed_style) = element.style() {
break; let position = computed_style.get_box().position;
}
// Check if this node establishes a positioning context and has position relative/absolute if matches!(position, Position::Relative | Position::Absolute) {
if let Some(element) = node.downcast::<Element>() { // If this element establishes a positioning context,
if let Some(computed_style) = element.style() { // Get its bounding box to calculate the offset
let position = computed_style.get_box().position; let positioning_box = node.border_box().unwrap_or_default();
let positioning_left = positioning_box
.origin
.x
.to_nearest_pixel(device_pixel_ratio);
let positioning_top = positioning_box
.origin
.y
.to_nearest_pixel(device_pixel_ratio);
if matches!(position, Position::Relative | Position::Absolute) { // Calculate the offset of the positioning context relative to the scrolling container
// If this element establishes a positioning context, let offset_left = positioning_left - scrolling_left;
// Get its bounding box to calculate the offset let offset_top = positioning_top - scrolling_top;
let positioning_box = node.border_box().unwrap_or_default();
let positioning_left = positioning_box
.origin
.x
.to_nearest_pixel(device_pixel_ratio);
let positioning_top = positioning_box
.origin
.y
.to_nearest_pixel(device_pixel_ratio);
// Calculate the offset of the positioning context relative to the scrolling container // Adjust the coordinates by subtracting the positioning context offset
let offset_left = positioning_left - scrolling_left; final_coords = (
let offset_top = positioning_top - scrolling_top; viewport_relative_left - offset_left,
viewport_relative_top - offset_top,
// Adjust the coordinates by subtracting the positioning context offset viewport_relative_right - offset_left,
final_coords = ( viewport_relative_bottom - offset_top,
viewport_relative_left - offset_left, );
viewport_relative_top - offset_top, break;
viewport_relative_right - offset_left, }
viewport_relative_bottom - offset_top,
);
break;
} }
} }
current_node = node.GetParentNode();
} }
current_node = node.GetParentNode(); final_coords
} };
final_coords let current_scroll_x = scrolling_element.ScrollLeft() as f32;
}; let current_scroll_y = scrolling_element.ScrollTop() as f32;
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;
let content_element_left = adjusted_relative_left + current_scroll_x; (
let content_element_top = adjusted_relative_top + current_scroll_y; self.calculate_scroll_position_one_axis(
let content_element_right = adjusted_relative_right + current_scroll_x; inline,
let content_element_bottom = adjusted_relative_bottom + current_scroll_y; content_element_left,
content_element_right,
( element_width,
self.calculate_scroll_position_one_axis( scrolling_width,
inline, current_scroll_x,
content_element_left, ),
content_element_right, self.calculate_scroll_position_one_axis(
element_width, block,
scrolling_width, content_element_top,
current_scroll_x, content_element_bottom,
), element_height,
self.calculate_scroll_position_one_axis( scrolling_height,
block, current_scroll_y,
content_element_top, ),
content_element_bottom, )
element_height, },
scrolling_height,
current_scroll_y,
),
)
}; };
Vector2D::new(target_x, target_y) Vector2D::new(target_x, target_y)