LibWeb: Dispatch pointer events to ::backdrop originating element

This commit is contained in:
Gingeh 2025-04-07 19:33:53 +10:00 committed by Sam Atkins
parent 4b9f5c6fb8
commit 972547635f
Notes: github-actions[bot] 2025-04-09 11:11:42 +00:00
7 changed files with 47 additions and 13 deletions

View file

@ -1002,13 +1002,9 @@
ladybird.sendMessage("restoreDefaultSettings");
});
// FIXME: Once we support `dialog::backdrop`, this event listener should be on `siteSettings`.
document.addEventListener("click", event => {
const close = dialog => {
if (!dialog.open) {
return;
}
// FIXME: This should be replaced once we support popover light dismissal.
document.querySelectorAll("dialog").forEach((dialog) =>
dialog.addEventListener("click", event => {
const rect = dialog.getBoundingClientRect();
if (
@ -1019,10 +1015,8 @@
) {
dialog.close();
}
};
document.querySelectorAll("dialog").forEach(close);
});
}
));
document.addEventListener("WebUILoaded", () => {
ladybird.sendMessage("loadAvailableEngines");

View file

@ -34,7 +34,8 @@
"is-generated": true
},
"backdrop": {
"spec": "https://drafts.csswg.org/css-position-4/#selectordef-backdrop"
"spec": "https://drafts.csswg.org/css-position-4/#selectordef-backdrop",
"is-generated": true
},
"before": {
"spec": "https://drafts.csswg.org/css-pseudo-4/#selectordef-before",

View file

@ -48,6 +48,7 @@ public:
bool is_generated() const { return m_generated_for.has_value(); }
bool is_generated_for_before_pseudo_element() const { return m_generated_for == CSS::GeneratedPseudoElement::Before; }
bool is_generated_for_after_pseudo_element() const { return m_generated_for == CSS::GeneratedPseudoElement::After; }
bool is_generated_for_backdrop_pseudo_element() const { return m_generated_for == CSS::GeneratedPseudoElement::Backdrop; }
void set_generated_for(CSS::GeneratedPseudoElement type, DOM::Element& element)
{
m_generated_for = type;

View file

@ -584,6 +584,7 @@ void TreeBuilder::update_layout_tree(DOM::Node& dom_node, TreeBuilder::Context&
return;
top_layer_element->set_pseudo_element_node({}, CSS::PseudoElement::Backdrop, pseudo_element_node);
pseudo_element_node->set_generated_for(CSS::GeneratedPseudoElement::Backdrop, top_layer_element);
insert_node_into_inline_or_block_ancestor(*pseudo_element_node, pseudo_element_display, AppendOrPrepend::Append);
}();
update_layout_tree(top_layer_element, context, should_create_layout_node ? MustCreateSubtree::Yes : MustCreateSubtree::No);

View file

@ -66,6 +66,12 @@ static DOM::Node* input_control_associated_with_ancestor_label_element(Painting:
static bool parent_element_for_event_dispatch(Painting::Paintable& paintable, GC::Ptr<DOM::Node>& node, Layout::Node*& layout_node)
{
layout_node = &paintable.layout_node();
if (layout_node->is_generated_for_backdrop_pseudo_element()) {
node = layout_node->pseudo_element_generator();
layout_node = node->layout_node();
}
auto* current_ancestor_node = node.ptr();
do {
if (is<HTML::FormAssociatedElement>(current_ancestor_node) && !dynamic_cast<HTML::FormAssociatedElement*>(current_ancestor_node)->enabled()) {
@ -73,7 +79,6 @@ static bool parent_element_for_event_dispatch(Painting::Paintable& paintable, GC
}
} while ((current_ancestor_node = current_ancestor_node->parent()));
layout_node = &paintable.layout_node();
while (layout_node && node && !node->is_element() && layout_node->parent()) {
layout_node = layout_node->parent();
if (layout_node->is_anonymous())

View file

@ -0,0 +1 @@
PASS

View file

@ -0,0 +1,31 @@
<!DOCTYPE html>
<script src="include.js"></script>
<!-- Adapted from https://wpt.live/html/semantics/interactive-elements/the-dialog-element/backdrop-receives-element-events.html -->
<style>
/* ::backdrop takes up whole screen, actual <dialog> is hidden */
dialog {
visibility: hidden;
pointer-events: none;
}
dialog::backdrop {
visibility: visible;
pointer-events: initial;
top: 0;
bottom: 0;
left: 0;
right: 0;
}
</style>
<dialog></dialog>
<script>
asyncTest((done) => {
const dialog = document.querySelector("dialog");
dialog.showModal();
dialog.addEventListener("click", () => {
println("PASS");
done();
});
internals.click(0, 0);
});
</script>