From 55d094a8716b29a9475283547ec45147cfa32b80 Mon Sep 17 00:00:00 2001 From: Martin Robinson Date: Sat, 27 Sep 2025 15:32:26 +0200 Subject: [PATCH] script: Make stylesheets loaded via `` elements block the rendering (#39536) Stylesheets loaded via the `` element should block the rendering of the page according to the HTML specification [1]. This change makes it so that they do this and, in addition, we do not take reftest screenshots until all no element is blocking the rendering. This change does not add support for the `blocking` attribute of ``, but that can be added in a follow change. In addition to fixing a few tests, this change likely makes other tests no longer intermittent. We will need to watch CI runs after this lands in order to verify that though. Testing: This change fixes at least two WPT tests. Fixes: #26424. Signed-off-by: Martin Robinson --- components/script/dom/document.rs | 25 ++++++++++++++++++- components/script/dom/window.rs | 4 +++ components/script/stylesheet_loader.rs | 18 +++++++++++++ .../parser-inserted-stylesheet-link.html.ini | 3 --- ...tr-stylesheet-link-keeps-blocking.html.ini | 3 --- 5 files changed, 46 insertions(+), 7 deletions(-) delete mode 100644 tests/wpt/meta/html/dom/render-blocking/parser-inserted-stylesheet-link.html.ini delete mode 100644 tests/wpt/meta/html/dom/render-blocking/remove-attr-stylesheet-link-keeps-blocking.html.ini diff --git a/components/script/dom/document.rs b/components/script/dom/document.rs index 69919fe31c9..0d60bd5906d 100644 --- a/components/script/dom/document.rs +++ b/components/script/dom/document.rs @@ -350,6 +350,9 @@ pub(crate) struct Document { pending_parsing_blocking_script: DomRefCell>, /// Number of stylesheets that block executing the next parser-inserted script script_blocking_stylesheets_count: Cell, + /// Number of elements that block the rendering of the page. + /// + render_blocking_element_count: Cell, /// deferred_scripts: PendingInOrderScriptVec, /// @@ -1728,6 +1731,21 @@ impl Document { count_cell.set(count_cell.get() - 1); } + pub(crate) fn render_blocking_element_count(&self) -> u32 { + self.render_blocking_element_count.get() + } + + pub(crate) fn increment_render_blocking_element_count(&self) { + let count_cell = &self.render_blocking_element_count; + count_cell.set(count_cell.get() + 1); + } + + pub(crate) fn decrement_render_blocking_element_count(&self) { + let count_cell = &self.render_blocking_element_count; + assert!(count_cell.get() > 0); + count_cell.set(count_cell.get() - 1); + } + pub(crate) fn invalidate_stylesheets(&self) { self.stylesheets.borrow_mut().force_dirty(OriginSet::all()); @@ -2705,6 +2723,10 @@ impl Document { // // Returns the set of reflow phases run as a [`ReflowPhasesRun`]. pub(crate) fn update_the_rendering(&self) -> ReflowPhasesRun { + if self.render_blocking_element_count() > 0 { + return Default::default(); + } + if self.has_pending_animated_image_update.get() { self.image_animation_manager .borrow() @@ -3389,7 +3411,8 @@ impl Document { has_focus: Cell::new(has_focus), current_script: Default::default(), pending_parsing_blocking_script: Default::default(), - script_blocking_stylesheets_count: Cell::new(0u32), + script_blocking_stylesheets_count: Default::default(), + render_blocking_element_count: Default::default(), deferred_scripts: Default::default(), asap_in_order_scripts_list: Default::default(), asap_scripts_set: Default::default(), diff --git a/components/script/dom/window.rs b/components/script/dom/window.rs index faa60d66b7d..bbfcc635aaa 100644 --- a/components/script/dom/window.rs +++ b/components/script/dom/window.rs @@ -2347,6 +2347,10 @@ impl Window { return; } + if document.render_blocking_element_count() > 0 { + return; + } + // Checks if the html element has reftest-wait attribute present. // See http://testthewebforward.org/docs/reftests.html // and https://web-platform-tests.org/writing-tests/crashtest.html diff --git a/components/script/stylesheet_loader.rs b/components/script/stylesheet_loader.rs index 7744d0790f3..e921e757779 100644 --- a/components/script/stylesheet_loader.rs +++ b/components/script/stylesheet_loader.rs @@ -277,6 +277,15 @@ impl FetchResponseListener for StylesheetContext { document.decrement_script_blocking_stylesheet_count(); } + // From : + // > A link element of this type is implicitly potentially render-blocking if the element + // > was created by its node document's parser. + if matches!(self.source, StylesheetContextSource::LinkElement { .. }) && + owner.parser_inserted() + { + document.decrement_render_blocking_element_count(); + } + document.finish_load(LoadType::Stylesheet(self.url.clone()), CanGc::note()); if let Some(any_failed) = owner.load_finished(successful) { @@ -377,6 +386,15 @@ impl ElementStylesheetLoader<'_> { document.increment_script_blocking_stylesheet_count(); } + // From : + // > A link element of this type is implicitly potentially render-blocking if the element + // > was created by its node document's parser. + if matches!(context.source, StylesheetContextSource::LinkElement { .. }) && + owner.parser_inserted() + { + document.increment_render_blocking_element_count(); + } + // https://html.spec.whatwg.org/multipage/#default-fetch-and-process-the-linked-resource let global = self.element.global(); let request = create_a_potential_cors_request( diff --git a/tests/wpt/meta/html/dom/render-blocking/parser-inserted-stylesheet-link.html.ini b/tests/wpt/meta/html/dom/render-blocking/parser-inserted-stylesheet-link.html.ini deleted file mode 100644 index c12f72cf6f6..00000000000 --- a/tests/wpt/meta/html/dom/render-blocking/parser-inserted-stylesheet-link.html.ini +++ /dev/null @@ -1,3 +0,0 @@ -[parser-inserted-stylesheet-link.html] - [Rendering is blocked before render-blocking resources are loaded] - expected: FAIL diff --git a/tests/wpt/meta/html/dom/render-blocking/remove-attr-stylesheet-link-keeps-blocking.html.ini b/tests/wpt/meta/html/dom/render-blocking/remove-attr-stylesheet-link-keeps-blocking.html.ini deleted file mode 100644 index 1b6bb9f669d..00000000000 --- a/tests/wpt/meta/html/dom/render-blocking/remove-attr-stylesheet-link-keeps-blocking.html.ini +++ /dev/null @@ -1,3 +0,0 @@ -[remove-attr-stylesheet-link-keeps-blocking.html] - [Rendering is blocked before render-blocking resources are loaded] - expected: FAIL