mirror of
https://github.com/RGBCube/serenity
synced 2025-07-25 19:37:35 +00:00
LibWeb: Cache state of the contenteditable attribute on HTMLElement
Instead of recomputing the state whenever someone asks for it, we now cache it when the attribute is added/changed/removed. Before this change, HTMLElement::is_editable() was 6.5% of CPU time when furiously resizing Hacker News. After, it's less than 0.5%. :^)
This commit is contained in:
parent
990e7219d6
commit
20e2c9a7dd
2 changed files with 25 additions and 16 deletions
|
@ -77,22 +77,9 @@ void HTMLElement::set_dir(DeprecatedString const& dir)
|
||||||
MUST(set_attribute(HTML::AttributeNames::dir, dir));
|
MUST(set_attribute(HTML::AttributeNames::dir, dir));
|
||||||
}
|
}
|
||||||
|
|
||||||
HTMLElement::ContentEditableState HTMLElement::content_editable_state() const
|
|
||||||
{
|
|
||||||
auto contenteditable = attribute(HTML::AttributeNames::contenteditable);
|
|
||||||
// "true", an empty string or a missing value map to the "true" state.
|
|
||||||
if ((!contenteditable.is_null() && contenteditable.is_empty()) || contenteditable.equals_ignoring_ascii_case("true"sv))
|
|
||||||
return ContentEditableState::True;
|
|
||||||
// "false" maps to the "false" state.
|
|
||||||
if (contenteditable.equals_ignoring_ascii_case("false"sv))
|
|
||||||
return ContentEditableState::False;
|
|
||||||
// Having no such attribute or an invalid value maps to the "inherit" state.
|
|
||||||
return ContentEditableState::Inherit;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool HTMLElement::is_editable() const
|
bool HTMLElement::is_editable() const
|
||||||
{
|
{
|
||||||
switch (content_editable_state()) {
|
switch (m_content_editable_state) {
|
||||||
case ContentEditableState::True:
|
case ContentEditableState::True:
|
||||||
return true;
|
return true;
|
||||||
case ContentEditableState::False:
|
case ContentEditableState::False:
|
||||||
|
@ -106,7 +93,7 @@ bool HTMLElement::is_editable() const
|
||||||
|
|
||||||
DeprecatedString HTMLElement::content_editable() const
|
DeprecatedString HTMLElement::content_editable() const
|
||||||
{
|
{
|
||||||
switch (content_editable_state()) {
|
switch (m_content_editable_state) {
|
||||||
case ContentEditableState::True:
|
case ContentEditableState::True:
|
||||||
return "true";
|
return "true";
|
||||||
case ContentEditableState::False:
|
case ContentEditableState::False:
|
||||||
|
@ -242,6 +229,19 @@ void HTMLElement::parse_attribute(DeprecatedFlyString const& name, DeprecatedStr
|
||||||
{
|
{
|
||||||
Element::parse_attribute(name, value);
|
Element::parse_attribute(name, value);
|
||||||
|
|
||||||
|
if (name == HTML::AttributeNames::contenteditable) {
|
||||||
|
if ((!value.is_null() && value.is_empty()) || value.equals_ignoring_ascii_case("true"sv)) {
|
||||||
|
// "true", an empty string or a missing value map to the "true" state.
|
||||||
|
m_content_editable_state = ContentEditableState::True;
|
||||||
|
} else if (value.equals_ignoring_ascii_case("false"sv)) {
|
||||||
|
// "false" maps to the "false" state.
|
||||||
|
m_content_editable_state = ContentEditableState::False;
|
||||||
|
} else {
|
||||||
|
// Having no such attribute or an invalid value maps to the "inherit" state.
|
||||||
|
m_content_editable_state = ContentEditableState::Inherit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 1. If namespace is not null, or localName is not the name of an event handler content attribute on element, then return.
|
// 1. If namespace is not null, or localName is not the name of an event handler content attribute on element, then return.
|
||||||
// FIXME: Add the namespace part once we support attribute namespaces.
|
// FIXME: Add the namespace part once we support attribute namespaces.
|
||||||
#undef __ENUMERATE
|
#undef __ENUMERATE
|
||||||
|
@ -253,6 +253,14 @@ void HTMLElement::parse_attribute(DeprecatedFlyString const& name, DeprecatedStr
|
||||||
#undef __ENUMERATE
|
#undef __ENUMERATE
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void HTMLElement::did_remove_attribute(DeprecatedFlyString const& name)
|
||||||
|
{
|
||||||
|
Base::did_remove_attribute(name);
|
||||||
|
if (name == HTML::AttributeNames::contenteditable) {
|
||||||
|
m_content_editable_state = ContentEditableState::Inherit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// https://html.spec.whatwg.org/multipage/interaction.html#dom-focus
|
// https://html.spec.whatwg.org/multipage/interaction.html#dom-focus
|
||||||
void HTMLElement::focus()
|
void HTMLElement::focus()
|
||||||
{
|
{
|
||||||
|
|
|
@ -67,6 +67,7 @@ protected:
|
||||||
virtual JS::ThrowCompletionOr<void> initialize(JS::Realm&) override;
|
virtual JS::ThrowCompletionOr<void> initialize(JS::Realm&) override;
|
||||||
|
|
||||||
virtual void parse_attribute(DeprecatedFlyString const& name, DeprecatedString const& value) override;
|
virtual void parse_attribute(DeprecatedFlyString const& name, DeprecatedString const& value) override;
|
||||||
|
virtual void did_remove_attribute(DeprecatedFlyString const& name) override;
|
||||||
|
|
||||||
virtual void visit_edges(Cell::Visitor&) override;
|
virtual void visit_edges(Cell::Visitor&) override;
|
||||||
|
|
||||||
|
@ -81,7 +82,7 @@ private:
|
||||||
False,
|
False,
|
||||||
Inherit,
|
Inherit,
|
||||||
};
|
};
|
||||||
ContentEditableState content_editable_state() const;
|
ContentEditableState m_content_editable_state { ContentEditableState::Inherit };
|
||||||
|
|
||||||
JS::GCPtr<DOMStringMap> m_dataset;
|
JS::GCPtr<DOMStringMap> m_dataset;
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue