diff --git a/Libraries/LibWeb/HTML/HTMLElement.cpp b/Libraries/LibWeb/HTML/HTMLElement.cpp index 95974a4f6e9..af9b3c8828d 100644 --- a/Libraries/LibWeb/HTML/HTMLElement.cpp +++ b/Libraries/LibWeb/HTML/HTMLElement.cpp @@ -461,6 +461,47 @@ String HTMLElement::outer_text() return get_the_text_steps(); } +// https://drafts.csswg.org/cssom-view/#dom-htmlelement-scrollparent +GC::Ptr HTMLElement::scroll_parent() const +{ + // 1. If any of the following holds true, return null and terminate this algorithm: + // - The element does not have an associated box. + // - The element is the root element. + // - The element is the body element. + // - FIXME: The element’s computed value of the position property is fixed and no ancestor establishes a fixed position containing block. + if (!layout_node()) + return nullptr; + if (is_document_element()) + return nullptr; + if (is_html_body_element()) + return nullptr; + + // 2. Let ancestor be the containing block of the element in the flat tree and repeat these substeps: + auto ancestor = layout_node()->containing_block(); + while (true) { + // 1. 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 return null. + if (ancestor->is_viewport()) { + auto const scrolling_element = document().scrolling_element(); + if (scrolling_element && !scrolling_element->is_closed_shadow_hidden_from(*this)) + return const_cast(scrolling_element.ptr()); + return nullptr; + } + + // 2. If ancestor is not closed-shadow-hidden from the element, and is a scroll container, terminate this + // algorithm and return ancestor. + if (!ancestor->dom_node()->is_closed_shadow_hidden_from(*this) && ancestor->is_scroll_container()) { + return const_cast(static_cast(ancestor->dom_node())); + } + + // FIXME: 3. If the computed value of the position property of ancestor is fixed, and no ancestor establishes a fixed + // position containing block, terminate this algorithm and return null. + + // 4. Let ancestor be the containing block of ancestor in the flat tree. + ancestor = layout_node()->containing_block(); + } +} + // https://www.w3.org/TR/cssom-view-1/#dom-htmlelement-offsetparent GC::Ptr HTMLElement::offset_parent() const { diff --git a/Libraries/LibWeb/HTML/HTMLElement.h b/Libraries/LibWeb/HTML/HTMLElement.h index bb26b36afd8..405f26faa57 100644 --- a/Libraries/LibWeb/HTML/HTMLElement.h +++ b/Libraries/LibWeb/HTML/HTMLElement.h @@ -105,6 +105,7 @@ public: int offset_width() const; int offset_height() const; GC::Ptr offset_parent() const; + GC::Ptr scroll_parent() const; bool cannot_navigate() const; diff --git a/Libraries/LibWeb/HTML/HTMLElement.idl b/Libraries/LibWeb/HTML/HTMLElement.idl index 9df48602a0a..f8f6e8d6f20 100644 --- a/Libraries/LibWeb/HTML/HTMLElement.idl +++ b/Libraries/LibWeb/HTML/HTMLElement.idl @@ -40,6 +40,7 @@ interface HTMLElement : Element { [CEReactions] attribute DOMString? popover; // https://drafts.csswg.org/cssom-view/#extensions-to-the-htmlelement-interface + readonly attribute Element? scrollParent; readonly attribute Element? offsetParent; readonly attribute long offsetTop; readonly attribute long offsetLeft;