LibWeb: Make EventTarget::activation_behavior a virtual function

(Instead of using an AK::Function on EventTarget). This shaves 48 bytes
off of every EventTarget instance.
This commit is contained in:
Andreas Kling 2023-11-18 10:48:09 +01:00
parent 84eecbb10e
commit a71eaefdf6
Notes: sideshowbarker 2024-07-18 08:59:31 +09:00
11 changed files with 108 additions and 64 deletions

View File

@ -242,7 +242,7 @@ bool EventDispatcher::dispatch(JS::NonnullGCPtr<EventTarget> target, Event& even
bool is_activation_event = is<UIEvents::MouseEvent>(event) && event.type() == HTML::EventNames::click;
// 5. If isActivationEvent is true and target has activation behavior, then set activationTarget to target.
if (is_activation_event && target->activation_behavior)
if (is_activation_event && target->has_activation_behavior())
activation_target = target;
// 6. Let slottable be target, if target is a slottable and is assigned, and null otherwise.
@ -293,7 +293,7 @@ bool EventDispatcher::dispatch(JS::NonnullGCPtr<EventTarget> target, Event& even
if (is<HTML::Window>(parent)
|| (is<Node>(parent) && verify_cast<Node>(*target).root().is_shadow_including_inclusive_ancestor_of(verify_cast<Node>(*parent)))) {
// 1. If isActivationEvent is true, events bubbles attribute is true, activationTarget is null, and parent has activation behavior, then set activationTarget to parent.
if (is_activation_event && event.bubbles() && !activation_target && parent->activation_behavior)
if (is_activation_event && event.bubbles() && !activation_target && parent->has_activation_behavior())
activation_target = parent;
// 2. Append to an event path with event, parent, null, relatedTarget, touchTargets, and slot-in-closed-tree.
@ -309,7 +309,7 @@ bool EventDispatcher::dispatch(JS::NonnullGCPtr<EventTarget> target, Event& even
target = *parent;
// 1. If isActivationEvent is true, activationTarget is null, and target has activation behavior, then set activationTarget to target.
if (is_activation_event && !activation_target && target->activation_behavior)
if (is_activation_event && !activation_target && target->has_activation_behavior())
activation_target = target;
// 2. Append to an event path with event, parent, target, relatedTarget, touchTargets, and slot-in-closed-tree.

View File

@ -816,4 +816,13 @@ bool EventTarget::has_event_listeners() const
return !m_event_listener_list.is_empty();
}
bool EventTarget::has_activation_behavior() const
{
return false;
}
void EventTarget::activation_behavior(Event const&)
{
}
}

View File

@ -45,7 +45,8 @@ public:
Vector<JS::Handle<DOMEventListener>> event_listener_list();
Function<void(Event const&)> activation_behavior;
virtual bool has_activation_behavior() const;
virtual void activation_behavior(Event const&);
// NOTE: These only exist for checkbox and radio input elements.
virtual void legacy_pre_activation_behavior() { }

View File

@ -16,9 +16,6 @@ JS_DEFINE_ALLOCATOR(HTMLAnchorElement);
HTMLAnchorElement::HTMLAnchorElement(DOM::Document& document, DOM::QualifiedName qualified_name)
: HTMLElement(document, move(qualified_name))
{
activation_behavior = [this](auto const& event) {
run_activation_behavior(event);
};
}
HTMLAnchorElement::~HTMLAnchorElement() = default;
@ -47,7 +44,12 @@ WebIDL::ExceptionOr<void> HTMLAnchorElement::set_hyperlink_element_utils_href(St
return set_attribute(HTML::AttributeNames::href, move(href));
}
void HTMLAnchorElement::run_activation_behavior(Web::DOM::Event const&)
bool HTMLAnchorElement::has_activation_behavior() const
{
return true;
}
void HTMLAnchorElement::activation_behavior(Web::DOM::Event const&)
{
// The activation behavior of an a element element given an event event is:

View File

@ -41,7 +41,8 @@ private:
virtual void initialize(JS::Realm&) override;
void run_activation_behavior(Web::DOM::Event const&);
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& value) override;

View File

@ -15,40 +15,6 @@ JS_DEFINE_ALLOCATOR(HTMLButtonElement);
HTMLButtonElement::HTMLButtonElement(DOM::Document& document, DOM::QualifiedName qualified_name)
: HTMLElement(document, move(qualified_name))
{
// https://html.spec.whatwg.org/multipage/form-elements.html#the-button-element:activation-behaviour
activation_behavior = [this](auto&) {
// 1. If element is disabled, then return.
if (!enabled())
return;
// 2. If element does not have a form owner, then return.
if (!form())
return;
// 3. If element's node document is not fully active, then return.
if (!this->document().is_fully_active())
return;
// 4. Switch on element's type attribute's state:
switch (type_state()) {
case TypeAttributeState::Submit:
// Submit Button
// Submit element's form owner from element.
form()->submit_form(*this).release_value_but_fixme_should_propagate_errors();
break;
case TypeAttributeState::Reset:
// Reset Button
// Reset element's form owner.
form()->reset_form();
break;
case TypeAttributeState::Button:
// Button
// Do nothing.
break;
default:
VERIFY_NOT_REACHED();
}
};
}
HTMLButtonElement::~HTMLButtonElement() = default;
@ -101,4 +67,45 @@ DeprecatedString HTMLButtonElement::value() const
return deprecated_attribute(AttributeNames::value);
}
bool HTMLButtonElement::has_activation_behavior() const
{
return true;
}
void HTMLButtonElement::activation_behavior(DOM::Event const&)
{
// https://html.spec.whatwg.org/multipage/form-elements.html#the-button-element:activation-behaviour
// 1. If element is disabled, then return.
if (!enabled())
return;
// 2. If element does not have a form owner, then return.
if (!form())
return;
// 3. If element's node document is not fully active, then return.
if (!this->document().is_fully_active())
return;
// 4. Switch on element's type attribute's state:
switch (type_state()) {
case TypeAttributeState::Submit:
// Submit Button
// Submit element's form owner from element.
form()->submit_form(*this).release_value_but_fixme_should_propagate_errors();
break;
case TypeAttributeState::Reset:
// Reset Button
// Reset element's form owner.
form()->reset_form();
break;
case TypeAttributeState::Button:
// Button
// Do nothing.
break;
default:
VERIFY_NOT_REACHED();
}
}
}

View File

@ -67,6 +67,9 @@ public:
virtual DeprecatedString value() const override;
virtual bool has_activation_behavior() const override;
virtual void activation_behavior(DOM::Event const&) override;
private:
virtual bool is_html_button_element() const override { return true; }

View File

@ -38,14 +38,6 @@ HTMLInputElement::HTMLInputElement(DOM::Document& document, DOM::QualifiedName q
: HTMLElement(document, move(qualified_name))
, m_value(DeprecatedString::empty())
{
activation_behavior = [this](auto&) {
// The activation behavior for input elements are these steps:
// FIXME: 1. If this element is not mutable and is not in the Checkbox state and is not in the Radio state, then return.
// 2. Run this element's input activation behavior, if any, and do nothing otherwise.
run_input_activation_behavior().release_value_but_fixme_should_propagate_errors();
};
}
HTMLInputElement::~HTMLInputElement() = default;
@ -1284,4 +1276,20 @@ bool HTMLInputElement::is_submit_button() const
return type_state() == TypeAttributeState::SubmitButton
|| type_state() == TypeAttributeState::ImageButton;
}
bool HTMLInputElement::has_activation_behavior() const
{
return true;
}
void HTMLInputElement::activation_behavior(DOM::Event const&)
{
// The activation behavior for input elements are these steps:
// FIXME: 1. If this element is not mutable and is not in the Checkbox state and is not in the Radio state, then return.
// 2. Run this element's input activation behavior, if any, and do nothing otherwise.
run_input_activation_behavior().release_value_but_fixme_should_propagate_errors();
}
}

View File

@ -149,6 +149,9 @@ public:
JS::GCPtr<Element> placeholder_element() { return m_placeholder_element; }
JS::GCPtr<Element const> placeholder_element() const { return m_placeholder_element; }
virtual bool has_activation_behavior() const override;
virtual void activation_behavior(DOM::Event const&) override;
private:
HTMLInputElement(DOM::Document&, DOM::QualifiedName);

View File

@ -15,22 +15,29 @@ JS_DEFINE_ALLOCATOR(HTMLSummaryElement);
HTMLSummaryElement::HTMLSummaryElement(DOM::Document& document, DOM::QualifiedName qualified_name)
: HTMLElement(document, move(qualified_name))
{
activation_behavior = [this](auto&) {
// The activation behavior of summary elements is to run the following steps:
}
// 1. If this summary element is not the summary for its parent details, then return.
if (!is_summary_for_its_parent_details())
return;
bool HTMLSummaryElement::has_activation_behavior() const
{
return true;
}
// 2. Let parent be this summary element's parent.
auto* parent = this->parent_element();
void HTMLSummaryElement::activation_behavior(DOM::Event const&)
{
// The activation behavior of summary elements is to run the following steps:
// 3. If the open attribute is present on parent, then remove it. Otherwise, set parent's open attribute to the empty string.
if (parent->has_attribute(HTML::AttributeNames::open))
parent->remove_attribute(HTML::AttributeNames::open);
else
parent->set_attribute(HTML::AttributeNames::open, String {}).release_value_but_fixme_should_propagate_errors();
};
// 1. If this summary element is not the summary for its parent details, then return.
if (!is_summary_for_its_parent_details())
return;
// 2. Let parent be this summary element's parent.
auto* parent = this->parent_element();
// 3. If the open attribute is present on parent, then remove it. Otherwise, set parent's open attribute to the empty string.
if (parent->has_attribute(HTML::AttributeNames::open))
parent->remove_attribute(HTML::AttributeNames::open);
else
parent->set_attribute(HTML::AttributeNames::open, String {}).release_value_but_fixme_should_propagate_errors();
}
// https://html.spec.whatwg.org/multipage/interactive-elements.html#summary-for-its-parent-details

View File

@ -23,6 +23,9 @@ public:
bool is_summary_for_its_parent_details();
virtual bool has_activation_behavior() const override;
virtual void activation_behavior(DOM::Event const&) override;
private:
HTMLSummaryElement(DOM::Document&, DOM::QualifiedName);