mirror of
https://github.com/servo/servo.git
synced 2025-09-27 15:20:09 +01:00
script: Use HTMLElement.scrollParent
to implement Element.scrollIntoView
(#39144)
To find scrolling ancestors, we need to walk up the flat tree and only consider the elements that are in the chain of containing block ancestors of an element. `scrollParent` now does this so we can use it to properly implement `scrollIntoView`. Testing: There are WPT tests for this change. --------- Signed-off-by: Martin Robinson <mrobinson@igalia.com> Co-authored-by: Oriol Brufau <obrufau@igalia.com>
This commit is contained in:
parent
286bbe6cb1
commit
9f4f598f44
9 changed files with 141 additions and 71 deletions
|
@ -29,8 +29,8 @@ use layout_api::wrapper_traits::LayoutNode;
|
|||
use layout_api::{
|
||||
BoxAreaType, IFrameSizes, Layout, LayoutConfig, LayoutDamage, LayoutFactory,
|
||||
OffsetParentResponse, PropertyRegistration, QueryMsg, ReflowGoal, ReflowPhasesRun,
|
||||
ReflowRequest, ReflowRequestRestyle, ReflowResult, RegisterPropertyError, ScrollParentResponse,
|
||||
TrustedNodeAddress,
|
||||
ReflowRequest, ReflowRequestRestyle, ReflowResult, RegisterPropertyError,
|
||||
ScrollContainerQueryType, ScrollContainerResponse, TrustedNodeAddress,
|
||||
};
|
||||
use log::{debug, error, warn};
|
||||
use malloc_size_of::{MallocConditionalSizeOf, MallocSizeOf, MallocSizeOfOps};
|
||||
|
@ -92,8 +92,8 @@ use crate::display_list::{DisplayListBuilder, HitTest, StackingContextTree};
|
|||
use crate::query::{
|
||||
get_the_text_steps, process_box_area_request, process_box_areas_request,
|
||||
process_client_rect_request, process_node_scroll_area_request, process_offset_parent_query,
|
||||
process_resolved_font_style_query, process_resolved_style_request, process_scroll_parent_query,
|
||||
process_text_index_request,
|
||||
process_resolved_font_style_query, process_resolved_style_request,
|
||||
process_scroll_container_query, process_text_index_request,
|
||||
};
|
||||
use crate::traversal::{RecalcStyle, compute_damage_and_repair_style};
|
||||
use crate::{BoxTree, FragmentTree};
|
||||
|
@ -326,9 +326,13 @@ impl Layout for LayoutThread {
|
|||
}
|
||||
|
||||
#[servo_tracing::instrument(skip_all)]
|
||||
fn query_scroll_parent(&self, node: TrustedNodeAddress) -> Option<ScrollParentResponse> {
|
||||
fn query_scroll_container(
|
||||
&self,
|
||||
node: TrustedNodeAddress,
|
||||
query_type: ScrollContainerQueryType,
|
||||
) -> Option<ScrollContainerResponse> {
|
||||
let node = unsafe { ServoLayoutNode::new(&node) };
|
||||
process_scroll_parent_query(node)
|
||||
process_scroll_container_query(node, query_type)
|
||||
}
|
||||
|
||||
#[servo_tracing::instrument(skip_all)]
|
||||
|
|
|
@ -12,7 +12,8 @@ use euclid::{SideOffsets2D, Size2D};
|
|||
use itertools::Itertools;
|
||||
use layout_api::wrapper_traits::{LayoutNode, ThreadSafeLayoutElement, ThreadSafeLayoutNode};
|
||||
use layout_api::{
|
||||
BoxAreaType, LayoutElementType, LayoutNodeType, OffsetParentResponse, ScrollParentResponse,
|
||||
BoxAreaType, LayoutElementType, LayoutNodeType, OffsetParentResponse, ScrollContainerQueryType,
|
||||
ScrollContainerResponse,
|
||||
};
|
||||
use script::layout_dom::{ServoLayoutNode, ServoThreadSafeLayoutNode};
|
||||
use servo_arc::Arc as ServoArc;
|
||||
|
@ -647,12 +648,14 @@ pub fn process_offset_parent_query(node: ServoLayoutNode<'_>) -> Option<OffsetPa
|
|||
})
|
||||
}
|
||||
|
||||
/// This is an implementation of
|
||||
/// An implementation of `scrollParent` that can also be used to for `scrollIntoView`:
|
||||
/// <https://drafts.csswg.org/cssom-view/#dom-htmlelement-scrollparent>.
|
||||
///
|
||||
#[inline]
|
||||
pub(crate) fn process_scroll_parent_query(
|
||||
pub(crate) fn process_scroll_container_query(
|
||||
node: ServoLayoutNode<'_>,
|
||||
) -> Option<ScrollParentResponse> {
|
||||
query_type: ScrollContainerQueryType,
|
||||
) -> Option<ScrollContainerResponse> {
|
||||
let layout_data = node.to_threadsafe().inner_layout_data()?;
|
||||
|
||||
// 1. If any of the following holds true, return null and terminate this algorithm:
|
||||
|
@ -665,14 +668,22 @@ pub(crate) fn process_scroll_parent_query(
|
|||
|
||||
// - The element is the root element.
|
||||
// - The element is the body element.
|
||||
// - The element’s computed value of the position property is fixed and no ancestor
|
||||
// establishes a fixed position containing block.
|
||||
if flags.intersects(
|
||||
FragmentFlags::IS_ROOT_ELEMENT | FragmentFlags::IS_BODY_ELEMENT_OF_HTML_ELEMENT_ROOT,
|
||||
) {
|
||||
//
|
||||
// Note: We only do this for `scrollParent`, which needs to be null. But `scrollIntoView` on the
|
||||
// `<body>` or root element should still bring it into view by scrolling the viewport.
|
||||
if query_type == ScrollContainerQueryType::ForScrollParent &&
|
||||
flags.intersects(
|
||||
FragmentFlags::IS_ROOT_ELEMENT | FragmentFlags::IS_BODY_ELEMENT_OF_HTML_ELEMENT_ROOT,
|
||||
)
|
||||
{
|
||||
return None;
|
||||
}
|
||||
|
||||
// - The element’s computed value of the position property is fixed and no ancestor
|
||||
// establishes a fixed position containing block.
|
||||
//
|
||||
// This is handled below in step 2.
|
||||
|
||||
// 2. Let ancestor be the containing block of the element in the flat tree and repeat these substeps:
|
||||
// - If ancestor is the initial containing block, return the scrollingElement for the
|
||||
// element’s document if it is not closed-shadow-hidden from the element, otherwise
|
||||
|
@ -721,7 +732,7 @@ pub(crate) fn process_scroll_parent_query(
|
|||
}
|
||||
|
||||
if ancestor_style.establishes_scroll_container(ancestor_flags) {
|
||||
return Some(ScrollParentResponse::Element(
|
||||
return Some(ScrollContainerResponse::Element(
|
||||
ancestor.as_node().opaque().into(),
|
||||
));
|
||||
}
|
||||
|
@ -731,7 +742,7 @@ pub(crate) fn process_scroll_parent_query(
|
|||
|
||||
match current_position_value {
|
||||
Position::Fixed => None,
|
||||
_ => Some(ScrollParentResponse::DocumentScrollingElement),
|
||||
_ => Some(ScrollContainerResponse::Viewport),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue