LibWeb: Add style invalidation for :target, :focus, :active and :link

This commit is contained in:
Andreas Kling 2024-11-06 18:00:18 +01:00 committed by Andreas Kling
parent 1045000c28
commit 92d9907f8f
Notes: github-actions[bot] 2024-11-06 20:43:56 +00:00
9 changed files with 39 additions and 23 deletions

View file

@ -6,18 +6,18 @@ Rerun
Found 12 tests
1 Pass
11 Fail
9 Pass
3 Fail
Details
Result Test Name MessagePass Initial State
Fail Focus 'target1'
Fail Focus 'target2'
Fail Focus 'target1' again
Fail Focus 'target2' again
Fail Focus 'target1' once again
Pass Focus 'target1'
Pass Focus 'target2'
Pass Focus 'target1' again
Pass Focus 'target2' again
Pass Focus 'target1' once again
Fail Detach 'container1' from the document
Fail Try to focus 'target1'
Fail Focus 'target2' once again
Fail Attach 'container1' in 'container2'
Fail Focus 'target1' for the last time
Pass Focus 'target2' once again
Pass Attach 'container1' in 'container2'
Pass Focus 'target1' for the last time
Fail Move 'target1' in 'container2'

View file

@ -6,6 +6,6 @@ Rerun
Found 1 tests
1 Fail
1 Pass
Details
Result Test Name MessageFail CSS Selectors Invalidation: :target pseudo-class in :has() argument
Result Test Name MessagePass CSS Selectors Invalidation: :target pseudo-class in :has() argument

View file

@ -2045,16 +2045,18 @@ void Document::set_focused_element(Element* element)
if (m_focused_element.ptr() == element)
return;
if (m_focused_element) {
m_focused_element->did_lose_focus();
m_focused_element->set_needs_style_update(true);
}
JS::GCPtr<Element> old_focused_element = move(m_focused_element);
if (old_focused_element)
old_focused_element->did_lose_focus();
m_focused_element = element;
if (auto* invalidation_target = find_common_ancestor(old_focused_element, m_focused_element) ?: this)
invalidation_target->invalidate_style(StyleInvalidationReason::FocusedElementChange);
if (m_focused_element) {
m_focused_element->did_receive_focus();
m_focused_element->set_needs_style_update(true);
}
if (paintable())
@ -2078,8 +2080,12 @@ void Document::set_active_element(Element* element)
if (m_active_element.ptr() == element)
return;
JS::GCPtr<Node> old_active_element = move(m_active_element);
m_active_element = element;
if (auto* invalidation_target = find_common_ancestor(old_active_element, m_active_element) ?: this)
invalidation_target->invalidate_style(StyleInvalidationReason::TargetElementChange);
if (paintable())
paintable()->set_needs_display();
}
@ -2089,13 +2095,11 @@ void Document::set_target_element(Element* element)
if (m_target_element.ptr() == element)
return;
if (m_target_element)
m_target_element->set_needs_style_update(true);
JS::GCPtr<Element> old_target_element = move(m_target_element);
m_target_element = element;
if (m_target_element)
m_target_element->set_needs_style_update(true);
if (auto* invalidation_target = find_common_ancestor(old_target_element, m_target_element) ?: this)
invalidation_target->invalidate_style(StyleInvalidationReason::TargetElementChange);
if (paintable())
paintable()->set_needs_display();

View file

@ -59,6 +59,7 @@ enum class IsDescendant {
};
#define ENUMERATE_STYLE_INVALIDATION_REASONS(X) \
X(ActiveElementChange) \
X(AdoptedStyleSheetsList) \
X(CSSFontLoaded) \
X(CSSImportRule) \
@ -68,6 +69,8 @@ enum class IsDescendant {
X(EditingInsertion) \
X(ElementAttributeChange) \
X(ElementSetShadowRoot) \
X(FocusedElementChange) \
X(HTMLHyperlinkElementHrefChange) \
X(HTMLInputElementSetChecked) \
X(HTMLObjectElementUpdateLayoutAndChildObjects) \
X(HTMLSelectElementSetIsOpen) \
@ -84,7 +87,8 @@ enum class IsDescendant {
X(StyleSheetDeleteRule) \
X(StyleSheetInsertRule) \
X(StyleSheetListAddSheet) \
X(StyleSheetListRemoveSheet)
X(StyleSheetListRemoveSheet) \
X(TargetElementChange)
enum class StyleInvalidationReason {
#define __ENUMERATE_STYLE_INVALIDATION_REASON(reason) reason,

View file

@ -51,6 +51,7 @@ private:
// ^HTML::HTMLHyperlinkElementUtils
virtual DOM::Document& hyperlink_element_utils_document() override { return document(); }
virtual DOM::Element& hyperlink_element_utils_element() override { return *this; }
virtual Optional<String> hyperlink_element_utils_href() const override;
virtual WebIDL::ExceptionOr<void> set_hyperlink_element_utils_href(String) override;
virtual Optional<String> hyperlink_element_utils_referrerpolicy() const override;

View file

@ -34,6 +34,7 @@ private:
// ^HTML::HTMLHyperlinkElementUtils
virtual DOM::Document& hyperlink_element_utils_document() override { return document(); }
virtual DOM::Element& hyperlink_element_utils_element() override { return *this; }
virtual Optional<String> hyperlink_element_utils_href() const override;
virtual WebIDL::ExceptionOr<void> set_hyperlink_element_utils_href(String) override;
virtual Optional<String> hyperlink_element_utils_referrerpolicy() const override;

View file

@ -31,12 +31,14 @@ void HTMLHyperlinkElementUtils::set_the_url()
auto href_content_attribute = hyperlink_element_utils_href();
if (!href_content_attribute.has_value()) {
m_url = {};
hyperlink_element_utils_element().invalidate_style(DOM::StyleInvalidationReason::HTMLHyperlinkElementHrefChange);
return;
}
// 2. Otherwise, parse this element's href content attribute value relative to this element's node document.
// If parsing is successful, set this element's url to the result; otherwise, set this element's url to null.
m_url = hyperlink_element_utils_document().parse_url(*href_content_attribute);
hyperlink_element_utils_element().invalidate_style(DOM::StyleInvalidationReason::HTMLHyperlinkElementHrefChange);
}
// https://html.spec.whatwg.org/multipage/links.html#dom-hyperlink-origin

View file

@ -52,6 +52,7 @@ public:
protected:
virtual DOM::Document& hyperlink_element_utils_document() = 0;
virtual DOM::Element& hyperlink_element_utils_element() = 0;
virtual Optional<String> hyperlink_element_utils_href() const = 0;
virtual WebIDL::ExceptionOr<void> set_hyperlink_element_utils_href(String) = 0;
virtual Optional<String> hyperlink_element_utils_referrerpolicy() const = 0;

View file

@ -37,6 +37,9 @@ void SVGAElement::visit_edges(Cell::Visitor& visitor)
void SVGAElement::attribute_changed(FlyString const& name, Optional<String> const& old_value, Optional<String> const& value)
{
Base::attribute_changed(name, old_value, value);
if (name == SVG::AttributeNames::href) {
invalidate_style(DOM::StyleInvalidationReason::HTMLHyperlinkElementHrefChange);
}
if (name == HTML::AttributeNames::rel) {
if (m_rel_list)
m_rel_list->associated_attribute_changed(value.value_or(String {}));