mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-10-03 14:50:02 +00:00
LibWeb: Give DOM Elements a CountersSet
This represents each element's set of CSS counters. https://drafts.csswg.org/css-lists-3/#css-counters-set Counters are resolved while building the tree. Most elements will not have any counters to keep track of, so as an optimization, we don't create a CountersSet object until the element actually needs one. In order to properly support counters on pseudo-elements, the CountersSet needs to go somewhere else. However, my experiments with placing it on the Layout::Node kept hitting a wall. For now, this is fairly simple at least.
This commit is contained in:
parent
a744a9ebe7
commit
708f49d906
Notes:
github-actions[bot]
2024-07-26 10:06:00 +00:00
Author: https://github.com/AtkinsSJ
Commit: 708f49d906
Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/720
Reviewed-by: https://github.com/tcl3
6 changed files with 253 additions and 0 deletions
|
@ -2696,4 +2696,92 @@ WebIDL::ExceptionOr<void> Element::set_html_unsafe(StringView html)
|
|||
return {};
|
||||
}
|
||||
|
||||
Optional<CSS::CountersSet const&> Element::counters_set()
|
||||
{
|
||||
if (!m_counters_set)
|
||||
return {};
|
||||
return *m_counters_set;
|
||||
}
|
||||
|
||||
CSS::CountersSet& Element::ensure_counters_set()
|
||||
{
|
||||
if (!m_counters_set)
|
||||
m_counters_set = make<CSS::CountersSet>();
|
||||
return *m_counters_set;
|
||||
}
|
||||
|
||||
// https://drafts.csswg.org/css-lists-3/#auto-numbering
|
||||
void Element::resolve_counters(CSS::StyleProperties&)
|
||||
{
|
||||
// Resolving counter values on a given element is a multi-step process:
|
||||
|
||||
// 1. Existing counters are inherited from previous elements.
|
||||
inherit_counters();
|
||||
|
||||
// TODO: 2. New counters are instantiated (counter-reset).
|
||||
// TODO: 3. Counter values are incremented (counter-increment).
|
||||
// TODO: 4. Counter values are explicitly set (counter-set).
|
||||
|
||||
// 5. Counter values are used (counter()/counters()).
|
||||
// NOTE: This happens when we process the `content` property.
|
||||
}
|
||||
|
||||
// https://drafts.csswg.org/css-lists-3/#inherit-counters
|
||||
void Element::inherit_counters()
|
||||
{
|
||||
// 1. If element is the root of its document tree, the element has an initially-empty CSS counters set.
|
||||
// Return.
|
||||
auto* parent = parent_element();
|
||||
if (parent == nullptr) {
|
||||
// NOTE: We represent an empty counters set with `m_counters_set = nullptr`.
|
||||
m_counters_set = nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
// 2. Let element counters, representing element’s own CSS counters set, be a copy of the CSS counters
|
||||
// set of element’s parent element.
|
||||
OwnPtr<CSS::CountersSet> element_counters;
|
||||
// OPTIMIZATION: If parent has a set, we create a copy. Otherwise, we avoid allocating one until we need
|
||||
// to add something to it.
|
||||
auto ensure_element_counters = [&]() {
|
||||
if (!element_counters)
|
||||
element_counters = make<CSS::CountersSet>();
|
||||
};
|
||||
if (parent->has_non_empty_counters_set()) {
|
||||
element_counters = make<CSS::CountersSet>();
|
||||
*element_counters = *parent_element()->counters_set();
|
||||
}
|
||||
|
||||
// 3. Let sibling counters be the CSS counters set of element’s preceding sibling (if it has one),
|
||||
// or an empty CSS counters set otherwise.
|
||||
// For each counter of sibling counters, if element counters does not already contain a counter with
|
||||
// the same name, append a copy of counter to element counters.
|
||||
if (auto* const sibling = previous_sibling_of_type<Element>(); sibling && sibling->has_non_empty_counters_set()) {
|
||||
auto& sibling_counters = sibling->counters_set().release_value();
|
||||
ensure_element_counters();
|
||||
for (auto const& counter : sibling_counters.counters()) {
|
||||
if (!element_counters->last_counter_with_name(counter.name).has_value())
|
||||
element_counters->append_copy(counter);
|
||||
}
|
||||
}
|
||||
|
||||
// 4. Let value source be the CSS counters set of the element immediately preceding element in tree order.
|
||||
// For each source counter of value source, if element counters contains a counter with the same name
|
||||
// and creator, then set the value of that counter to source counter’s value.
|
||||
if (auto* const previous = previous_element_in_pre_order(); previous && previous->has_non_empty_counters_set()) {
|
||||
// NOTE: If element_counters is empty (AKA null) then we can skip this since nothing will match.
|
||||
if (element_counters) {
|
||||
auto& value_source = previous->counters_set().release_value();
|
||||
for (auto const& source_counter : value_source.counters()) {
|
||||
auto maybe_existing_counter = element_counters->counter_with_same_name_and_creator(source_counter.name, source_counter.originating_element_id);
|
||||
if (maybe_existing_counter.has_value())
|
||||
maybe_existing_counter->value = source_counter.value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
VERIFY(!element_counters || !element_counters->is_empty());
|
||||
m_counters_set = move(element_counters);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#include <LibWeb/Bindings/ElementPrototype.h>
|
||||
#include <LibWeb/Bindings/Intrinsics.h>
|
||||
#include <LibWeb/Bindings/ShadowRootPrototype.h>
|
||||
#include <LibWeb/CSS/CountersSet.h>
|
||||
#include <LibWeb/CSS/Selector.h>
|
||||
#include <LibWeb/CSS/StyleInvalidation.h>
|
||||
#include <LibWeb/CSS/StyleProperty.h>
|
||||
|
@ -399,6 +400,12 @@ public:
|
|||
void set_in_top_layer(bool in_top_layer) { m_in_top_layer = in_top_layer; }
|
||||
bool in_top_layer() const { return m_in_top_layer; }
|
||||
|
||||
bool has_non_empty_counters_set() const { return m_counters_set; }
|
||||
Optional<CSS::CountersSet const&> counters_set();
|
||||
CSS::CountersSet& ensure_counters_set();
|
||||
void resolve_counters(CSS::StyleProperties&);
|
||||
void inherit_counters();
|
||||
|
||||
protected:
|
||||
Element(Document&, DOM::QualifiedName);
|
||||
virtual void initialize(JS::Realm&) override;
|
||||
|
@ -476,6 +483,8 @@ private:
|
|||
Array<CSSPixelPoint, 3> m_scroll_offset;
|
||||
|
||||
bool m_in_top_layer { false };
|
||||
|
||||
OwnPtr<CSS::CountersSet> m_counters_set;
|
||||
};
|
||||
|
||||
template<>
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue