mirror of
https://github.com/servo/servo.git
synced 2025-09-10 15:08:21 +01:00
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:
parent
dab195ca80
commit
fa7d6d4004
1 changed files with 131 additions and 137 deletions
|
@ -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)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue