mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2026-06-27 19:51:03 +00:00
Treat a scoped `@import` rule as a scope descriptor while traversing style-producing rules from imported stylesheets. Imported rules now inherit an outer scope for unscoped imports and replace it when the import itself carries scope(...). Scope resolution was generalized to handle both CSSScopeRule and CSSImportRule descriptors. Import-scope boundaries are matched using the stylesheet that parsed the `@import` rule, while normal imported selectors keep using the imported stylesheet context. This lets implicit scopes, nested `@scope` rules, :scope, and top-level `&` behave as the Cascade 6 model requires.
89 lines
3.1 KiB
C++
89 lines
3.1 KiB
C++
/*
|
|
* Copyright (c) 2021, the SerenityOS developers.
|
|
* Copyright (c) 2021-2026, Sam Atkins <sam@ladybird.org>
|
|
* Copyright (c) 2022, Andreas Kling <andreas@ladybird.org>
|
|
*
|
|
* SPDX-License-Identifier: BSD-2-Clause
|
|
*/
|
|
|
|
#pragma once
|
|
|
|
#include <LibWeb/CSS/CSSRule.h>
|
|
#include <LibWeb/CSS/CSSStyleSheet.h>
|
|
#include <LibWeb/CSS/Selector.h>
|
|
#include <LibWeb/CSS/URL.h>
|
|
#include <LibWeb/Export.h>
|
|
#include <LibWeb/Forward.h>
|
|
|
|
namespace Web::CSS {
|
|
|
|
class WEB_API CSSImportRule final
|
|
: public CSSRule
|
|
, public CSSStyleSheet::Subresource {
|
|
WEB_PLATFORM_OBJECT(CSSImportRule, CSSRule);
|
|
GC_DECLARE_ALLOCATOR(CSSImportRule);
|
|
|
|
public:
|
|
struct ImportScope {
|
|
Optional<SelectorList> start_selectors;
|
|
Optional<SelectorList> end_selectors;
|
|
};
|
|
|
|
[[nodiscard]] static GC::Ref<CSSImportRule> create(JS::Realm&, URL, GC::Ptr<DOM::Document>, Optional<FlyString> layer, Optional<ImportScope>&& scope, RefPtr<Supports>, GC::Ref<MediaList>);
|
|
|
|
virtual ~CSSImportRule() override;
|
|
|
|
URL const& url() const { return m_url; }
|
|
String href() const { return m_url.url(); }
|
|
|
|
CSSStyleSheet* loaded_style_sheet() { return m_style_sheet; }
|
|
CSSStyleSheet const* loaded_style_sheet() const { return m_style_sheet; }
|
|
GC::Ref<MediaList> media() const;
|
|
CSSStyleSheet* style_sheet_for_bindings() { return m_style_sheet; }
|
|
|
|
Optional<FlyString> layer_name() const;
|
|
Optional<String> supports_text() const;
|
|
|
|
bool matches() const;
|
|
bool has_scope() const { return m_scope.has_value(); }
|
|
Optional<SelectorList> const& scope_start_selectors() const;
|
|
Optional<SelectorList> const& scope_end_selectors() const;
|
|
Optional<SelectorList> const& scope_start_selectors_for_matching() const;
|
|
Optional<SelectorList> const& scope_end_selectors_for_matching() const;
|
|
|
|
Optional<FlyString> internal_layer_name() const { return m_layer_internal; }
|
|
Optional<FlyString> internal_qualified_layer_name(Badge<StyleScope>) const;
|
|
|
|
private:
|
|
CSSImportRule(JS::Realm&, URL, GC::Ptr<DOM::Document>, Optional<FlyString>, Optional<ImportScope>&&, RefPtr<Supports>, GC::Ref<MediaList>);
|
|
|
|
virtual void initialize(JS::Realm&) override;
|
|
virtual void visit_edges(Cell::Visitor&) override;
|
|
virtual void clear_caches() override;
|
|
virtual void dump(StringBuilder&, int indent_levels) const override;
|
|
|
|
virtual void set_parent_style_sheet(CSSStyleSheet*) override;
|
|
|
|
virtual GC::Ptr<CSSStyleSheet> parent_style_sheet_for_subresource() override { return m_parent_style_sheet; }
|
|
|
|
virtual String serialized() const override;
|
|
|
|
void fetch();
|
|
void set_style_sheet(GC::Ref<CSSStyleSheet>);
|
|
|
|
URL m_url;
|
|
GC::Ptr<DOM::Document> m_document;
|
|
Optional<FlyString> m_layer;
|
|
Optional<FlyString> m_layer_internal;
|
|
Optional<ImportScope> m_scope;
|
|
mutable Optional<SelectorList> m_cached_scope_start_selectors_for_matching;
|
|
mutable Optional<SelectorList> m_cached_scope_end_selectors_for_matching;
|
|
RefPtr<Supports> m_supports;
|
|
GC::Ref<MediaList> m_media;
|
|
GC::Ptr<CSSStyleSheet> m_style_sheet;
|
|
};
|
|
|
|
template<>
|
|
inline bool CSSRule::fast_is<CSSImportRule>() const { return type() == CSSRule::Type::Import; }
|
|
|
|
}
|