ladybird/Libraries/LibWeb/HTML/HTMLAnchorElement.h
Andreas Kling 99b1780d57 LibWeb: Reject non-rendered elements as focus targets
Do not let elements inside display:none subtrees become focus targets.
The HTML focusable-area model only allows elements to be focusable when
they are rendered, delegate rendering to their children, or are relevant
canvas fallback content.

Preserve blur for the current focused area after script hides it, since
the unfocusing steps operate on the old focus target. Check display:none
through the flat-tree style parent chain, so slotted controls inside
hidden slot subtrees cannot become focused.

Cover hidden ancestors with materialized computed style, display:none
controls, display:contents, hidden focused controls, and slotted cases
inside hidden and visible shadow-tree subtrees.
2026-05-21 08:56:05 +02:00

76 lines
2.4 KiB
C++

/*
* Copyright (c) 2018-2020, Andreas Kling <andreas@ladybird.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#pragma once
#include <LibWeb/HTML/HTMLElement.h>
#include <LibWeb/HTML/HTMLHyperlinkElementUtils.h>
namespace Web::HTML {
class HTMLAnchorElement final
: public HTMLElement
, public HTMLHyperlinkElementUtils {
WEB_PLATFORM_OBJECT(HTMLAnchorElement, HTMLElement);
GC_DECLARE_ALLOCATOR(HTMLAnchorElement);
public:
virtual ~HTMLAnchorElement() override;
virtual Optional<URL::Origin> extract_an_origin() const override { return hyperlink_element_utils_extract_an_origin(); }
String rel() const { return get_attribute_value(HTML::AttributeNames::rel); }
String target() const { return get_attribute_value(HTML::AttributeNames::target); }
String download() const { return get_attribute_value(HTML::AttributeNames::download); }
GC::Ref<DOM::DOMTokenList> rel_list();
Utf16String text() const;
void set_text(Utf16String const&);
// ^EventTarget
// https://html.spec.whatwg.org/multipage/interaction.html#the-tabindex-attribute:the-a-element
virtual bool is_focusable() const override
{
return (Base::is_focusable() || has_attribute(HTML::AttributeNames::href))
&& meets_focusable_area_rendering_requirements();
}
virtual bool is_html_anchor_element() const override { return true; }
private:
HTMLAnchorElement(DOM::Document&, DOM::QualifiedName);
bool has_download_preference() const;
virtual void initialize(JS::Realm&) override;
virtual void visit_edges(Cell::Visitor&) override;
// ^DOM::EventTarget
virtual bool has_activation_behavior() const override;
virtual void activation_behavior(Web::DOM::Event const&) override;
// ^DOM::Element
virtual void attribute_changed(FlyString const& name, Optional<String> const& old_value, Optional<String> const& value, Optional<FlyString> const& namespace_) override;
virtual i32 default_tab_index_value() const override;
// ^HTML::HTMLHyperlinkElementUtils
virtual DOM::Element& hyperlink_element_utils_element() override { return *this; }
virtual DOM::Element const& hyperlink_element_utils_element() const override { return *this; }
virtual Optional<ARIA::Role> default_role() const override;
GC::Ptr<DOM::DOMTokenList> m_rel_list;
};
}
namespace Web::DOM {
template<>
inline bool Node::fast_is<HTML::HTMLAnchorElement>() const { return is_html_anchor_element(); }
}