Files
ladybird/Libraries/LibWeb/CSS/CascadedProperties.h
Andreas Kling 11c75a2ffb LibWeb: Fix @keyframes resolution for slotted elements
A @keyframes rule scoped to a shadow root was not reliably reached
from an animated slotted light-DOM element: the keyframes lookup
walked the element's own root first, then fell back to the document,
but slotted elements can pick up animation-name from a ::slotted(...)
rule that lives in an ancestor shadow root rather than in the
element's own tree.

Track the shadow-root scope that supplied each winning cascaded
declaration, and use that scope to resolve the matching @keyframes
when processing animation definitions. A shared constructable
stylesheet can be adopted into several scopes at once, so the
declaration object alone is too weak as a key; the per-entry
shadow-root pointer disambiguates which adoption actually contributed.

Also refresh running CSS animations' keyframe sets when style is
recomputed. Previously only the first animation creation path set a
keyframe set, so an existing animation never picked up newly inserted
@keyframes rules.
2026-04-22 20:59:00 +02:00

61 lines
2.1 KiB
C++

/*
* Copyright (c) 2024, Andreas Kling <andreas@ladybird.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#pragma once
#include <AK/FixedBitmap.h>
#include <LibGC/CellAllocator.h>
#include <LibJS/Heap/Cell.h>
#include <LibWeb/CSS/CascadeOrigin.h>
#include <LibWeb/CSS/PropertyID.h>
#include <LibWeb/CSS/Selector.h>
#include <LibWeb/CSS/StyleProperty.h>
#include <LibWeb/CSS/StyleValues/StyleValue.h>
#include <LibWeb/Forward.h>
namespace Web::CSS {
class CascadedProperties final : public JS::Cell {
GC_CELL(CascadedProperties, JS::Cell);
GC_DECLARE_ALLOCATOR(CascadedProperties);
public:
virtual ~CascadedProperties() override;
[[nodiscard]] RefPtr<StyleValue const> property(PropertyID) const;
[[nodiscard]] PropertyID property_with_higher_priority(PropertyID, PropertyID) const;
[[nodiscard]] GC::Ptr<CSSStyleDeclaration const> property_source(PropertyID) const;
[[nodiscard]] GC::Ptr<DOM::ShadowRoot const> property_source_shadow_root(PropertyID) const;
[[nodiscard]] Optional<StyleProperty> style_property(PropertyID) const;
void set_property(PropertyID, NonnullRefPtr<StyleValue const>, Important, CascadeOrigin, Optional<FlyString> layer_name, GC::Ptr<CSS::CSSStyleDeclaration const> source, GC::Ptr<DOM::ShadowRoot const> source_shadow_root);
void set_property_from_presentational_hint(PropertyID, NonnullRefPtr<StyleValue const>);
void revert_property(PropertyID, Important, CascadeOrigin);
void revert_layer_property(PropertyID, Important, Optional<FlyString> layer_name);
void resolve_unresolved_properties(DOM::AbstractElement);
private:
CascadedProperties();
virtual void visit_edges(Visitor&) override;
struct Entry {
StyleProperty property;
size_t cascade_index { 0 };
CascadeOrigin origin;
Optional<FlyString> layer_name;
GC::Ptr<CSS::CSSStyleDeclaration const> source;
GC::Ptr<DOM::ShadowRoot const> source_shadow_root;
};
HashMap<PropertyID, Vector<Entry>> m_properties;
size_t m_next_cascade_index { 0 };
AK::FixedBitmap<to_underlying(last_longhand_property_id) + 1> m_contained_properties_cache { false };
};
}