LibWeb: Apply scroll margin in IntersectionObserver compute_intersection
Per the spec, the observer's [[scrollMargin]] should be applied to each scroll container's scrollport when walking the containing block chain. This expands the effective clip rect, allowing targets to be detected as intersecting before they actually enter the visible area of the scroll container. Add a scroll_margin_values() accessor to IntersectionObserver so the raw LengthPercentage values can be used during intersection computation. The scroll margin is applied by inflating the scroll container's padding box rect before clipping the intersection rect against it.
This commit is contained in:
parent
c871c56178
commit
9abb7e4517
3 changed files with 17 additions and 2 deletions
|
|
@ -5217,7 +5217,9 @@ static CSSPixelRect compute_intersection(GC::Ref<Element> target, IntersectionOb
|
|||
// unnecessary here because get_bounding_client_rect() and transform_rect_to_viewport()
|
||||
// already produce viewport-relative coordinates.
|
||||
|
||||
// 3.3. If container has a content clip or a css clip-path property, update intersectionRect
|
||||
// 3.3. If container is a scroll container, apply the observer’s [[scrollMargin]]
|
||||
// to the container’s clip rect.
|
||||
// 3.4. If container has a content clip or a css clip-path property, update intersectionRect
|
||||
// by applying container’s clip.
|
||||
// FIXME: Handle clip-path.
|
||||
auto overflow_x = container->computed_values().overflow_x();
|
||||
|
|
@ -5225,6 +5227,18 @@ static CSSPixelRect compute_intersection(GC::Ref<Element> target, IntersectionOb
|
|||
bool has_content_clip = overflow_x != CSS::Overflow::Visible || overflow_y != CSS::Overflow::Visible;
|
||||
if (has_content_clip) {
|
||||
auto clip_rect = container->transform_rect_to_viewport(container->absolute_padding_box_rect());
|
||||
|
||||
// Apply scroll margin to expand the scrollport for scroll containers.
|
||||
auto& scroll_margin = observer.scroll_margin_values();
|
||||
auto const& layout_node = container->layout_node_with_style_and_box_metrics();
|
||||
if (layout_node.is_scroll_container() && !scroll_margin.is_empty()) {
|
||||
clip_rect.inflate(
|
||||
scroll_margin[0].to_px(layout_node, clip_rect.height()),
|
||||
scroll_margin[1].to_px(layout_node, clip_rect.width()),
|
||||
scroll_margin[2].to_px(layout_node, clip_rect.height()),
|
||||
scroll_margin[3].to_px(layout_node, clip_rect.width()));
|
||||
}
|
||||
|
||||
intersection_rect.intersect(clip_rect);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -45,6 +45,7 @@ public:
|
|||
Variant<GC::Root<DOM::Element>, GC::Root<DOM::Document>, Empty> root() const;
|
||||
String root_margin() const;
|
||||
String scroll_margin() const;
|
||||
Vector<CSS::LengthPercentage> const& scroll_margin_values() const { return m_scroll_margin; }
|
||||
Vector<double> const& thresholds() const { return m_thresholds; }
|
||||
long delay() const { return m_delay; }
|
||||
bool track_visibility() const { return m_track_visibility; }
|
||||
|
|
|
|||
|
|
@ -1,2 +1,2 @@
|
|||
no-margin: ratio=0.1875
|
||||
with-margin: ratio=0.1875
|
||||
with-margin: ratio=1
|
||||
|
|
|
|||
Loading…
Reference in a new issue