LibWeb/HTML: Add fastpath to skip selectedness update on children change

We can definitely expand on this a bunch more, but using the metadata
provided in the children change notification we are able to skip
runnning the expensive selectedness algorithm on the <select> element.

This removes children changed from appearing in the profile of:

https://wpt.live/html/select/options-length-too-large.html
This commit is contained in:
Shannon Booth 2025-01-27 13:11:06 +13:00 committed by Andrew Kaster
parent 903c8860f8
commit 075c7ea63e
Notes: github-actions[bot] 2025-01-30 20:56:44 +00:00
2 changed files with 29 additions and 0 deletions

View file

@ -2,6 +2,7 @@
* Copyright (c) 2020, the SerenityOS developers.
* Copyright (c) 2021-2022, Andreas Kling <andreas@ladybird.org>
* Copyright (c) 2023, Bastiaan van der Plaat <bastiaan.v.d.plaat@gmail.com>
* Copyright (c) 2025, Shannon Booth <shannon@serenityos.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
@ -292,9 +293,36 @@ i32 HTMLSelectElement::default_tab_index_value() const
return 0;
}
bool HTMLSelectElement::can_skip_children_changed_selectedness_update(ChildrenChangedMetadata const& metadata) const
{
// If the following criteria are met, there is no need to re-run the selectedness algorithm.
// FIXME: We can tighten up these conditions and skip even more work!
if (metadata.type != ChildrenChangedMetadata::Type::Inserted)
return false;
if (auto* option = as_if<HTMLOptionElement>(*metadata.node)) {
if (option->selected())
return false;
if (m_cached_number_of_selected_options >= 2)
return false;
if (display_size() == 1 && m_cached_number_of_selected_options == 0)
return false;
return true;
}
return false;
}
void HTMLSelectElement::children_changed(ChildrenChangedMetadata const* metadata)
{
Base::children_changed(metadata);
if (metadata && can_skip_children_changed_selectedness_update(*metadata))
return;
update_cached_list_of_options();
update_selectedness();
}

View file

@ -110,6 +110,7 @@ private:
virtual void computed_properties_changed() override;
virtual void children_changed(ChildrenChangedMetadata const*) override;
bool can_skip_children_changed_selectedness_update(ChildrenChangedMetadata const& metadata) const;
void update_cached_list_of_options() const;
void show_the_picker_if_applicable();