Problem: Ref/input/css/images-load-relative-to-imported-style-sheet.html intermittently fails on the Linux Sanitizer with a deterministic 398px screenshot mismatch — the entire 20x20 background- image div is unpainted in the test pass, while the reference paints the checkerboard. Cause: CSSImportRule::fetch() added to the document’s render-blocking set (m_pending_css_import_rules) — but didn’t delay the load event. The load event could fire before the imported stylesheet had finished fetching — so the background image referenced from inside that sheet hadn’t even been requested yet when test-web’s on_load_finish callback ran wait_for_reftest_completion and proceeded to take the screenshot. By contrast, <link rel="stylesheet"> already delays the load event for its own duration via m_document_load_event_delayer in HTMLLinkElement — which is why the sibling test using <link> doesn’t flake. Fix: Hold a DocumentLoadEventDelayer in CSSImportRule for the duration of the import fetch, paralleling HTMLLinkElement. By the time the import rule’s delayer clears in the ScopeGuard, the imported sheet’s image fetches have already been kicked off via SharedResourceRequest, each of which takes over load-event delaying through its own delayer — so there’s no race between the two delayers releasing.
76 lines
2.5 KiB
C++
76 lines
2.5 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/URL.h>
|
|
#include <LibWeb/DOM/DocumentLoadEventDelayer.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:
|
|
[[nodiscard]] static GC::Ref<CSSImportRule> create(JS::Realm&, URL, GC::Ptr<DOM::Document>, Optional<FlyString> layer, 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;
|
|
|
|
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>, RefPtr<Supports>, GC::Ref<MediaList>);
|
|
|
|
virtual void initialize(JS::Realm&) override;
|
|
virtual void visit_edges(Cell::Visitor&) 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;
|
|
RefPtr<Supports> m_supports;
|
|
GC::Ref<MediaList> m_media;
|
|
GC::Ptr<CSSStyleSheet> m_style_sheet;
|
|
Optional<DOM::DocumentLoadEventDelayer> m_load_event_delayer;
|
|
};
|
|
|
|
template<>
|
|
inline bool CSSRule::fast_is<CSSImportRule>() const { return type() == CSSRule::Type::Import; }
|
|
|
|
}
|