8000 layout: Add a first pass at incremental box tree construction by mrobinson · Pull Request #37751 · servo/servo · GitHub
[go: up one dir, main page]

Skip to content

Conversation

mrobinson
Copy link
Member
@mrobinson mrobinson commented Jun 27, 2025

This change:

  • Adds a new type of LayoutDamage that signifies that a box needs its
    children recollected, because one or more of them need to be rebuilt.
  • During restyle damage propagation, propagate this new damage upward in
    the tree. Then box tree construction should be able to preserve any
    still-valid box tree nodes from box slots.
  • During BlockLevelBox job finalization, if a box slot is valid and
    there is not LayoutDamage to the element, use the old box slot,
    ensuring that its fragment cache is invalidated.

Testing: This should not change observable behavior and thus is covered
by existing WPT tests.

@mrobinson mrobinson added the T-linux-wpt Do a try run of the WPT label Jun 27, 2025
@github-actions github-actions bot removed the T-linux-wpt Do a try run of the WPT label Jun 27, 2025
Copy link

🔨 Triggering try run (#15928552071) for Linux (WPT)

@mrobinson mrobinson force-pushed the incremental-box-tree-update branch from d03ecc1 to 226770f Compare June 27, 2025 14:21
@mrobinson mrobinson added the T-linux-wpt Do a try run of the WPT label Jun 27, 2025
@github-actions github-actions bot removed the T-linux-wpt Do a try run of the WPT label Jun 27, 2025
Copy link

🔨 Triggering try run (#15928578749) for Linux (WPT)

Copy link

⚠️ Try run (#15928578749) failed.

@mrobinson mrobinson force-pushed the incremental-box-tree-update branch from 226770f to d48db54 Compare June 27, 2025 15:00
@mrobinson mrobinson added the T-linux-wpt Do a try run of the WPT label Jun 27, 2025
@github-actions github-actions bot removed the T-linux-wpt Do a try run of the WPT label Jun 27, 2025
Copy link

🔨 Triggering try run (#15929400204) for Linux (WPT)

Copy link

Test results for linux-wpt from try job (#15929400204):

Flaky unexpected result (13)
  • OK /FileAPI/url/url-with-fetch.any.worker.html (#21517)
    • FAIL [expected PASS] subtest: Revoke blob URL after calling fetch, fetch should succeed

      promise_test: Unhandled rejection with value: object "TypeError: Network error occurred"
      

  • OK /css/css-fonts/variations/at-font-face-font-matching.html (#20684)
    • FAIL [expected PASS] subtest: Matching font-weight: '399' should prefer '450 460' over '500 501'

      assert_equals: Unexpected font on test element expected 487 but got 532
      

    • FAIL [expected PASS] subtest: Matching font-style: 'oblique 0deg' should prefer 'oblique 0deg' over 'oblique 5deg'

      assert_equals: Unexpected font on test element expected 487 but got 532
      

  • OK /fetch/content-length/api-and-duplicate-headers.any.html (#35873)
    • FAIL [expected PASS] subtest: fetch() and duplicate Content-Length/Content-Type headers

      promise_test: Unhandled rejection with value: object "TypeError: Network error occurred"
      

  • TIMEOUT [expected ERROR] /fetch/fetch-later/quota/cross-origin-iframe/max-payload.tentative.https.window.html (#37749)
  • OK /html/browsers/browsing-the-web/navigating-across-documents/005.html (#27062)
    • PASS [expected FAIL] subtest: Link with onclick navigation and href navigation
  • OK /html/browsers/windows/browsing-context-names/duplicate-name-order.html (#34623)
    • PASS [expected FAIL] subtest: Duplicate name lookup order
  • CRASH [expected TIMEOUT] /html/semantics/embedded-content/the-iframe-element/iframe_sandbox_popups_escaping-2.html (#22667)
  • OK /html/semantics/scripting-1/the-script-element/module/dynamic-import/blob-url.any.worker.html (#33909)
    • FAIL [expected PASS] subtest: Revoking a blob URL immediately after calling import will not fail

      promise_test: Unhandled rejection with value: object "TypeError: Dynamic import failed"
      

  • OK /resize-observer/eventloop.html (#33599)
    • PASS [expected FAIL] subtest: test0: multiple notifications inside same event loop
  • TIMEOUT [expected OK] /resource-timing/nested-context-navigations-iframe.html (#24311)
    • TIMEOUT [expected PASS] subtest: Test that crossorigin iframe navigations are not observable by the parent, even after history navigations by the parent

      Test timed out
      

    • NOTRUN [expected PASS] subtest: Test that cross-site iframe navigations are not observable by the parent, even after history navigations by the parent
    • NOTRUN [expected PASS] subtest: Test that iframe navigations are not observable by the parent
    • NOTRUN [expected PASS] subtest: Test that crossorigin iframe navigations are not observable by the parent
    • NOTRUN [expected PASS] subtest: Test that cross-site iframe navigations are not observable by the parent
    • NOTRUN [expected PASS] subtest: Test that iframe refreshes are not observable by the parent
    • NOTRUN [expected PASS] subtest: Test that crossorigin iframe refreshes are not observable by the parent
    • NOTRUN [expected PASS] subtest: Test that cross-site iframe refreshes are not observable by the parent
  • TIMEOUT /resource-timing/test_resource_timing.https.html (#25216)
    • PASS [expected FAIL] subtest: PerformanceEntry has correct name, initiatorType, startTime, and duration (img)
  • OK [expected TIMEOUT] /webmessaging/without-ports/017.html (#24486)
    • PASS [expected TIMEOUT] subtest: origin of the script that invoked the method, about:blank
  • OK [expected TIMEOUT] /webmessaging/without-ports/018.html (#24485)
    • PASS [expected TIMEOUT] subtest: origin of the script that invoked the method, javascript:
Stable unexpected results that are known to be intermittent (18)
  • TIMEOUT /FileAPI/url/url-in-tags-revoke.window.html (#19978)
    • PASS [expected TIMEOUT] subtest: Fetching a blob URL immediately before revoking it works in <script> tags.
  • FAIL [expected PASS] /_mozilla/mozilla/sslfail.html (#10760)
  • TIMEOUT [expected OK] /_mozilla/mozilla/window_resizeTo.html (#36741)
    • TIMEOUT [expected PASS] subtest: Popup onresize event fires after resizeTo

      Test timed out
      

  • OK /css/css-align/blocks/align-content-block-002.html (#37361)
    • PASS [expected FAIL] subtest: .test 1: start
    • PASS [expected FAIL] subtest: .test 4: baseline
    • PASS [expected FAIL] subtest: .test 6: flex-start
    • PASS [expected FAIL] subtest: .test 8: unsafe start
    • PASS [expected FAIL] subtest: .test 11: safe start
    • PASS [expected FAIL] subtest: .test 15: space-between
    • PASS [expected FAIL] subtest: .test 17: normal
  • OK /css/css-align/blocks/align-content-block-003.html (#37360)
    • FAIL [expected PASS] subtest: .test 1: start

      assert_equals: 
      <div class="test" style="align-content: start" title="start">
          <div class="in-flow" data-offset-y="35"></div>
          <div class="in-flow">
            <span class="label">START</span>
            <span class="abspos" data-offset-y="20">ABS</span>
            <span class="relpos" data-offset-y="20">REL</span>
            <div class="overflow">OVERFLOW</div>
          </div>
        </div>
      offsetTop expected 20 but got 19
      

    • FAIL [expected PASS] subtest: .test 2: center

      assert_equals: 
      <div class="test" style="align-content: center" title="center">
          <div class="in-flow" data-offset-y="35"></div>
          <div class="in-flow">
            <span class="label">CENTER</span>
            <span class="abspos" data-offset-y="20">ABS</span>
            <span class="relpos" data-offset-y="20">REL</span>
            <div class="overflow">OVERFLOW</div>
          </div>
        </div>
      offsetTop expected 20 but got 19
      

    • FAIL [expected PASS] subtest: .test 3: end

      assert_equals: 
      <div class="test" style="align-content: end" title="end">
          <div class="in-flow" data-offset-y="35"></div>
          <div class="in-flow">
            <span class="label">END</span>
            <span class="abspos" data-offset-y="20">ABS</span>
            <span class="relpos" data-offset-y="20">REL</span>
            <div class="overflow">OVERFLOW</div>
          </div>
        </div>
      offsetTop expected 20 but got 19
      

    • FAIL [expected PASS] subtest: .test 4: baseline

      assert_equals: 
      <div class="test" style="align-content: baseline" title="baseline">
          <div class="in-flow" data-offset-y="35"></div>
          <div class="in-flow">
            <span class="label">BASELINE</span>
            <span class="abspos" data-offset-y="20">ABS</span>
            <span class="relpos" data-offset-y="20">REL</span>
            <div class="overflow">OVERFLOW</div>
          </div>
        </div>
      offsetTop expected 20 but got 19
      

    • FAIL [expected PASS] subtest: .test 5: last baseline

      assert_equals: 
      <div class="test" style="align-content: last baseline" title="last baseline">
          <div class="in-flow" data-offset-y="35"></div>
          <div class="in-flow">
            <span class="label">LAST BASELINE</span>
            <span class="abspos" data-offset-y="20">ABS</span>
            <span class="relpos" data-offset-y="20">REL</span>
            <div class="overflow">OVERFLOW</div>
          </div>
        </div>
      offsetTop expected 20 but got 19
      

    • FAIL [expected PASS] subtest: .test 6: flex-start

      assert_equals: 
      <div class="test" style="align-content: flex-start" title="flex-start">
          <div class="in-flow" data-offset-y="35"></div>
          <div class="in-flow">
            <span class="label">FLEX-START</span>
            <span class="abspos" data-offset-y="20">ABS</span>
            <span class="relpos" data-offset-y="20">REL</span>
            <div class="overflow">OVERFLOW</div>
          </div>
        </div>
      offsetTop expected 20 but got 19
      

    • FAIL [expected PASS] subtest: .test 7: flex-end

      assert_equals: 
      <div class="test" style="align-content: flex-end" title="flex-end">
          <div class="in-flow" data-offset-y="35"></div>
          <div class="in-flow">
            <span class="label">FLEX-END</span>
            <span class="abspos" data-offset-y="20">ABS</span>
            <span class="relpos" data-offset-y="20">REL</span>
            <div class="overflow">OVERFLOW</div>
          </div>
        </div>
      offsetTop expected 20 but got 19
      

    • FAIL [expected PASS] subtest: .test 8: unsafe start

      assert_equals: 
      <div class="test" style="align-content: unsafe start" title="unsafe start">
          <div class="in-flow" data-offset-y="35"></div>
          <div class="in-flow">
            <span class="label">UNSAFE START</span>
            <span class="abspos" data-offset-y="20">ABS</span>
            <span class="relpos" data-offset-y="20">REL</span>
            <div class="overflow">OVERFLOW</div>
          </div>
        </div>
      offsetTop expected 20 but got 19
      

    • FAIL [expected PASS] subtest: .test 11: safe start

      assert_equals: 
      <div class="test" style="align-content: safe start" title="safe start">
          <div class="in-flow" data-offset-y="35"></div>
          <div class="in-flow">
            <span class="label">SAFE START</span>
            <span class="abspos" data-offset-y="20">ABS</span>
            <span class="relpos" data-offset-y="20">REL</span>
            <div class="overflow">OVERFLOW</div>
          </div>
        </div>
      offsetTop expected 20 but got 19
      

    • FAIL [expected PASS] subtest: .test 12: safe center

      assert_equals: 
      <div class="test" style="align-content: safe center" title="safe center">
          <div class="in-flow" data-offset-y="35"></div>
          <div class="in-flow">
            <span class="label">SAFE CENTER</span>
            <span class="abspos" data-offset-y="20">ABS</span>
            <span class="relpos" data-offset-y="20">REL</span>
            <div class="overflow">OVERFLOW</div>
          </div>
        </div>
      offsetTop expected 20 but got 19
      

    • And 5 more unexpected results...
  • FAIL [expected PASS] /css/css-grid/grid-items/grid-auto-margin-and-replaced-item-001.html (#37162)
  • OK /fetch/metadata/generated/css-font-face.https.sub.tentative.html (#32732)
    • PASS [expected FAIL] subtest: sec-fetch-user
  • OK /html/browsers/browsing-the-web/navigating-across-documents/initial-empty-document/iframe-nosrc.html (#34819)
    • FAIL [expected PASS] subtest: form submission

      assert_equals: expected "http://web-platform.test:8000/common/blank.html?1=" but got "about:blank"
      

  • OK /html/browsers/browsing-the-web/navigating-across-documents/initial-empty-document/load-pageshow-events-iframe-contentWindow.html (#28681)
    • PASS [expected FAIL] subtest: load & pageshow events do not fire on contentWindow of <iframe> element created with src=''
  • OK /html/browsers/browsing-the-web/navigating-across-documents/replace-before-load/a-click.html (#28697)
    • FAIL [expected PASS] subtest: aElement.click() before the load event must NOT replace

      assert_equals: expected "http://web-platform.test:8000/common/blank.html?thereplacement" but got "http://web-platform.test:8000/html/browsers/browsing-the-web/navigating-across-documents/replace-before-load/resources/code-injector.html?pipe=sub(none)&code=%0A%20%20%20%20const%20a%20%3D%20document.createElement(%22a%22)%3B%0A%20%20%20%20a.href%20%3D%20%22%2Fcommon%2Fblank.html%3Fthereplacement%22%3B%0A%20%20%20%20document.currentScript.before(a)%3B%0A%20%20%20%20a.click()%3B%0A%20%20"
      

  • TIMEOUT /html/interaction/focus/the-autofocus-attribute/supported-elements.html (#24145)
    • FAIL [expected TIMEOUT] subtest: Element with tabindex should support autofocus

      assert_equals: expected "SPAN" but got "BODY"
      

    • PASS [expected NOTRUN] subtest: Non-HTMLElement should not support autofocus
    • FAIL [expected NOTRUN] subtest: Host element with delegatesFocus should support autofocus

      assert_equals: expected Element node <div autofocus=""></div> but got Element node <body><div autofocus=""></div></body>
      

    • TIMEOUT [expected NOTRUN] subtest: Host element with delegatesFocus including no focusable descendants should be skipped

      Test timed out
      

  • CRASH [expected TIMEOUT] /html/semantics/embedded-content/the-iframe-element/iframe_sandbox_popups_escaping-1.html (#22647)
  • OK [expected TIMEOUT] /html/semantics/embedded-content/the-iframe-element/iframe_sandbox_popups_escaping-3.html (#24057)
    • FAIL [expected TIMEOUT] subtest: Check that popups from a sandboxed iframe escape the sandbox if allow-popups-to-escape-sandbox is used

      assert_equals: It came from a sandboxed iframe expected "null" but got "http://web-platform.test:8000"
      

  • OK [expected TIMEOUT] /html/semantics/embedded-content/the-iframe-element/iframe_sandbox_popups_nonescaping-1.html (#24066)
    • FAIL [expected NOTRUN] subtest: Check that popups from a sandboxed iframe do not escape the sandbox

      assert_equals: It came from a sandboxed iframe expected "null" but got "http://web-platform.test:8000"
      

  • CRASH [expected TIMEOUT] /html/semantics/embedded-content/the-iframe-element/iframe_sandbox_popups_nonescaping-2.html (#22154)
  • OK /navigation-timing/test-navigation-type-reload.html (#33334)
    • FAIL [expected PASS] subtest: Reload domComplete > Original domComplete

      assert_true: Reload domComplete > Original domComplete expected true got false
      

    • FAIL [expected PASS] subtest: Reload loadEventEnd > Original loadEventEnd

      assert_true: Reload loadEventEnd > Original loadEventEnd expected true got false
      

    • FAIL [expected PASS] subtest: Reload loadEventStart > Original loadEventStart

      assert_true: Reload loadEventStart > Original loadEventStart expected true got false
      

  • OK /preload/preload-error.sub.html (#37177)
    • PASS [expected FAIL] subtest: success (style): main
    • PASS [expected FAIL] subtest: success (script): main
    • PASS [expected FAIL] subtest: success (xhr): main
    • PASS [expected FAIL] subtest: 404 (xhr): main
    • FAIL [expected PASS] subtest: MIME-error (script): main

      assert_greater_than: http://web-platform.test:8000/preload/resources/dummy.css?pipe=header%28Content-Type%2Ctext%2Fnotjavascript%29&label=script should be loaded expected a number greater than 0 but got 0
      

  • OK /webaudio/the-audio-api/the-audiobuffersourcenode-interface/sub-sample-buffer-stitching.html (#22849)
    • FAIL [expected PASS] subtest: X Stitched sine-wave buffers at sample rate 43800 does not equal [0,0.06264832615852356,0.12505052983760834,0.18696144223213196,0.24813786149024963,0.308339387178421,0.36732959747314453,0.4248766601085663,0.480754554271698,0.5347436666488647,0.5866320133209229,0.6362156271934509,0.6832997798919678,0.7276994585990906,0.7692402601242065,0.8077589869499207...] with an element-wise tolerance of {"absoluteThreshold":0.0038986,"relativeThreshold":0}. Index Actual Expected AbsError RelError Test threshold [14650] 2.1191254980451701e+24 8.6956524848937988e-1 2.1191254980451701e+24 2.4369942355982401e+24 3.8985999999999999e-3 [14651] 3.0547976493835449e-1 8.9879405498504639e-1 5.9331429004669189e-1 6.6012262403823208e-1 3.8985999999999999e-3 Max AbsError of 2.1191254980451701e+24 at index of 14650. Max RelError of 2.4369942355982401e+24 at index of 14650.

      assert_true: expected true got false
      

    • FAIL [expected PASS] subtest: X SNR (-443.0890475978605 dB) is not greater than or equal to 65.737. Got -443.0890475978605.

      assert_true: expected true got false
      

Stable unexpected results (5)
  • FAIL [expected PASS] /css/CSS2/positioning/dynamic-top-change-002.xht
  • FAIL [expected PASS] /css/CSS2/positioning/dynamic-top-change-003.xht
  • FAIL [expected PASS] /css/CSS2/text/word-spacing-applies-to-014.xht
  • FAIL [expected PASS] /css/css-flexbox/flexbox_stf-table-singleline-2.html
  • FAIL [expected PASS] /css/css-flexbox/flexbox_stf-table-singleline.html

Copy link

⚠️ Try run (#15929400204) failed.

8000
//
// TODO: This isn't going to be good enough for incremental fragment tree
// reconstruction, as fragment tree damage might extend further up the tree.
parent_node.clear_restyle_damage();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The damage of the dirty node itself has not been cleaned

},
}

element.clear_restyle_damage();
Copy link
Contributor
@coding-joedow coding-joedow Jun 29, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because the check whether a old block level box can be reused is delayed until the BlockLevelJob finished, clear the restyle damage at here maybe too early if a element need to be traversed one more times, such as the block level child element of a table. I have already tried it at my local and that the failed test case pass. Can we clear the restyle damage within the LayoutBoxBase new function? Or add logic at the BlockLevelJob:new to correct the damage for children element

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In my original PR: 37130, the "box repair" and "box rebuild" is two separate process, so the invariance can always be kept: If the parent node 's box is rebuilt, then all its descendent are also rebuilt.


// If this `BlockLevelBox` is undamaged and it has been laid out before, reuse
// the old one, while being sure to clear the layout cache.
if !self.damage.has_box_damage() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Only reuse the whole box for the node which has no box damage. However, for those node with only RECOLLECT_CHILDREN_BOX, nothing is reused. With current increment layout, it is enough. However, is it meaningful to preserve the LayoutBoxBase in order to preserve some layout cache for the incremental layout , such as cached_inline_content_size.

},
None => None,
} {
block_level_box.borrow().invalidate_cached_fragment();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With current incremental layout, only clear cached fragment maybe not enough. When the incremental box tree update is extended to reuse flex/taffy level box, some incorrect layout maybe appear. So clear the all cached layout result for this node's subtree should be necessary.

@coding-joedow
Copy link
Contributor
coding-joedow commented Jun 30, 2025

If you need it, you can use the following changes to fix the failing test case.

diff from your diff
diff --git a/components/layout/flow/construct.rs b/components/layout/flow/construct.rs
index f6ed4908b7..65883b5e3e 100644
--- a/components/layout/flow/construct.rs
+++ b/components/layout/flow/construct.rs
@@ -50,6 +50,22 @@ impl BlockFormattingContext {
         ))
     }
 
+    pub(crate) fn construct_without_recollect_children(
+        context: &LayoutContext,
+        info: &NodeAndStyleInfo<'_>,
+        contents: NonReplacedContents,
+        propagated_data: PropagatedBoxTreeData,
+        is_list_item: bool,
+    ) -> Self {
+        Self::from_block_container(BlockContainer::construct_without_recollect_children(
+            context,
+            info,
+            contents,
+            propagated_data,
+            is_list_item,
+        ))
+    }
+
     pub(crate) fn from_block_container(contents: BlockContainer) -> Self {
         let contains_floats = contents.contains_floats();
         Self {
@@ -158,6 +174,11 @@ pub(crate) struct BlockContainerBuilder<'dom, 'style> {
     /// ancestors that have been processed. This `Vec` allows passing those into new
     /// [`InlineFormattingContext`]s that we create.
     display_contents_shared_styles: Vec<SharedInlineStyles>,
+
+    /// A flag indicates whether this builder can collect box tree children which can be
+    /// reused due to that their originating nodes have no box damage. This is a workround
+    /// for constructing [`BlockFormattingContext`] in [`Table`].
+    allow_recollect_children: bool,
 }
 
 impl BlockContainer {
@@ -168,25 +189,19 @@ impl BlockContainer {
         propagated_data: PropagatedBoxTreeData,
         is_list_item: bool,
     ) -> BlockContainer {
-        let mut builder = BlockContainerBuilder::new(context, info, propagated_data);
-        if is_list_item {
-            if let Some((marker_info, marker_contents)) = crate::lists::make_marker(context, info) {
-                match marker_info.style.clone_list_style_position() {
-                    ListStylePosition::Inside => {
-                        builder.handle_list_item_marker_inside(&marker_info, info, marker_contents)
-                    },
-                    ListStylePosition::Outside => builder.handle_list_item_marker_outside(
-                        &marker_info,
-                        info,
-                        marker_contents,
-                        info.style.clone(),
-                    ),
-                }
-            }
-        }
+        let builder = BlockContainerBuilder::new(context, info, propagated_data, true);
+        builder.build(contents, is_list_item)
+    }
 
-        contents.traverse(context, info, &mut builder);
-        builder.finish()
+    pub fn construct_without_recollect_children(
+        context: &LayoutContext,
+        info: &NodeAndStyleInfo<'_>,
+        contents: NonReplacedContents,
+        propagated_data: PropagatedBoxTreeData,
+        is_list_item: bool,
+    ) -> BlockContainer {
+        let builder = BlockContainerBuilder::new(context, info, propagated_data, false);
+        builder.build(contents, is_list_item)
     }
 }
 
@@ -195,6 +210,7 @@ impl<'dom, 'style> BlockContainerBuilder<'dom, 'style> {
         context: &'style LayoutContext,
         info: &'style NodeAndStyleInfo<'dom>,
         propagated_data: PropagatedBoxTreeData,
+        allow_recollect_children: bool,
     ) -> Self {
         BlockContainerBuilder {
             context,
@@ -206,9 +222,35 @@ impl<'dom, 'style> BlockContainerBuilder<'dom, 'style> {
             anonymous_table_content: Vec::new(),
             inline_formatting_context_builder: None,
             display_contents_shared_styles: Vec::new(),
+            allow_recollect_children,
         }
     }
 
+    fn build(mut self, contents: NonReplacedContents, is_list_item: bool) -> BlockContainer {
+        if is_list_item {
+            if let Some((marker_info, marker_contents)) =
+                crate::lists::make_marker(self.context, self.info)
+            {
+                match marker_info.style.clone_list_style_position() {
+                    ListStylePosition::Inside => self.handle_list_item_marker_inside(
+                        &marker_info,
+                        self.info,
+                        marker_contents,
+                    ),
+                    ListStylePosition::Outside => self.handle_list_item_marker_outside(
+                        &marker_info,
+                        self.info,
+                        marker_contents,
+                        self.info.style.clone(),
+                    ),
+                }
+            }
+        }
+
+        contents.traverse(self.context, self.info, &mut self);
+        self.finish()
+    }
+
     fn currently_processing_inline_box(&self) -> bool {
         self.inline_formatting_context_builder
             .as_ref()
@@ -306,6 +348,7 @@ impl<'dom, 'style> BlockContainerBuilder<'dom, 'style> {
                 BoxSlot::dummy(),
                 self.propagated_data,
                 BlockLevelCreator::AnonymousTable { table_block },
+                self.allow_recollect_children,
             ));
         }
 
@@ -455,6 +498,7 @@ impl<'dom> BlockContainerBuilder<'dom, '_> {
                 contents,
                 list_item_style,
             },
+            self.allow_recollect_children,
         ));
     }
 
@@ -583,6 +627,7 @@ impl<'dom> BlockContainerBuilder<'dom, '_> {
             box_slot,
             propagated_data,
             kind,
+            self.allow_recollect_children,
         ));
 
         // Any block also counts as the first line for the purposes of text indent. Even if
@@ -620,6 +665,7 @@ impl<'dom> BlockContainerBuilder<'dom, '_> {
             box_slot,
             self.propagated_data,
             kind,
+            self.allow_recollect_children,
         ));
     }
 
@@ -653,6 +699,7 @@ impl<'dom> BlockContainerBuilder<'dom, '_> {
             box_slot,
             self.propagated_data,
             kind,
+            self.allow_recollect_children,
         ));
     }
 
@@ -680,6 +727,7 @@ impl<'dom> BlockContainerBuilder<'dom, '_> {
                     BlockContainer::InlineFormattingContext(inline_formatting_context),
                 ),
             ),
+            self.allow_recollect_children,
         ));
 
         self.have_already_seen_first_line_for_text_indent = true;
@@ -692,8 +740,14 @@ impl<'dom> BlockLevelJob<'dom> {
         box_slot: BoxSlot<'dom>,
         propagated_data: PropagatedBoxTreeData,
         kind: BlockLevelCreator,
+        container_allow_recollect_children: bool,
     ) -> Self {
-        let damage = info.restyle_damage();
+        let damage = if container_allow_recollect_children {
+            info.restyle_damage()
+        } else {
+            LayoutDamage::REBUILD_BOX
+        };
+
         Self {
             info,
             box_slot,
diff --git a/components/layout/table/construct.rs b/components/layout/table/construct.rs
index 191faaa77c..bcc9ae68bf 100644
--- a/components/layout/table/construct.rs
+++ b/components/layout/table/construct.rs
@@ -857,13 +857,15 @@ impl<'dom> TraversalHandler<'dom> for TableBuilderTraversal<'_, 'dom> {
                 DisplayLayoutInternal::TableCaption => {
                     let contents = match contents.try_into() {
                         Ok(non_replaced_contents) => {
-                            IndependentNonReplacedContents::Flow(BlockFormattingContext::construct(
-                                self.context,
-                                info,
-                                non_replaced_contents,
-                                self.current_propagated_data,
-                                false, /* is_list_item */
-                            ))
+                            IndependentNonReplacedContents::Flow(
+                                BlockFormattingContext::construct_without_recollect_children(
+                                    self.context,
+                                    info,
+                                    non_replaced_contents,
+                                    self.current_propagated_data,
+                                    false, /* is_list_item */
+                                ),
+                            )
                         },
                         Err(_replaced) => {
                             unreachable!("Replaced should not have a LayoutInternal display type.");
@@ -949,7 +951,8 @@ impl<'style, 'builder, 'dom, 'a> TableRowBuilder<'style, 'builder, 'dom, 'a> {
             .pseudo(context, PseudoElement::ServoAnonymousTableCell)
             .expect("Should never fail to create anonymous table cell info");
         let propagated_data = self.propagated_data.disallowing_percentage_table_columns();
-        let mut builder = BlockContainerBuilder::new(context, &anonymous_info, propagated_data);
+        let mut builder =
+            BlockContainerBuilder::new(context, &anonymous_info, propagated_data, false);
 
         for cell_content in self.current_anonymous_cell_content.drain(..) {
             match cell_content {
@@ -1018,7 +1021,7 @@ impl<'dom> TraversalHandler<'dom> for TableRowBuilder<'_, '_, 'dom, '_> {
                         self.propagated_data.disallowing_percentage_table_columns();
                     let contents = match contents.try_into() {
                         Ok(non_replaced_contents) => {
-                            BlockFormattingContext::construct(
+                            BlockFormattingContext::construct_without_recollect_children(
                                 self.table_traversal.context,
                                 info,
                                 non_replaced_contents,

This PR is looks good to me, thank you for split this change from my original PR. After this PR merged, i will immediately commit the support for reusing flex/taffy level box.

@mrobinson mrobinson added the T-linux-wpt Do a try run of the WPT label Jul 1, 2025
@github-actions github-actions bot removed the T-linux-wpt Do a try run of the WPT label Jul 1, 2025
Copy link
github-actions bot commented Jul 1, 2025

🔨 Triggering try run (#15996293014) for Linux (WPT)

Copy link
github-actions bot commented Jul 1, 2025

Test results for linux-wpt from try job (#15996293014):

Flaky unexpected result (16)
  • OK /_mozilla/mozilla/getBoundingClientRect.html
    • FAIL [expected PASS] subtest: getBoundingClientRect 1

      assert_equals: expected 62 but got 60.35
      

  • OK /css/css-cascade/layer-cssom-order-reverse.html (#36094)
    • PASS [expected FAIL] subtest: Delete layer invalidates @font-face
  • TIMEOUT [expected ERROR] /fetch/fetch-later/quota/cross-origin-iframe/max-payload.tentative.https.window.html (#37749)
  • ERROR /fetch/metadata/generated/serviceworker.https.sub.html (#36247)
    • PASS [expected FAIL] subtest: sec-fetch-site - Same origin, no options - registration
  • OK /html/browsers/browsing-the-web/navigating-across-documents/008.html (#24456)
    • PASS [expected FAIL] subtest: Link with onclick form submit to javascript url and href navigation
  • OK /html/browsers/browsing-the-web/navigating-across-documents/navigation-unload-cross-origin.sub.window.html (#29056)
    • PASS [expected FAIL] subtest: Cross-origin navigation started from unload handler must be ignored
  • OK /html/browsers/browsing-the-web/navigating-across-documents/refresh/same-document-refresh.html (#34597)
    • FAIL [expected PASS] subtest: Same-Document Referrer from Refresh

      assert_equals: original page loads expected "http://web-platform.test:8000/html/browsers/browsing-the-web/navigating-across-documents/refresh/resources/refresh-with-section.sub.html?url=%23section" but got "http://web-platform.test:8000/html/browsers/browsing-the-web/navigating-across-documents/refresh/resources/refresh-with-section.sub.html?url=%23section#section"
      

  • OK /html/browsers/history/the-history-interface/traverse_the_history_2.html (#21383)
    • PASS [expected FAIL] subtest: Multiple history traversals, last would be aborted
  • OK /html/browsers/history/the-history-interface/traverse_the_history_4.html (#21383)
    • PASS [expected FAIL] subtest: Multiple history traversals, last would be aborted
  • TIMEOUT [expected OK] /html/browsers/sandboxing/sandbox-initial-empty-document-toward-same-origin.html (#35948)
  • PASS [expected FAIL] /html/canvas/element/manual/drawing-text-to-the-canvas/canvas.2d.disconnected-font-size-math.html (#30063)
  • FAIL [expected PASS] /html/canvas/element/manual/text/canvas.2d.disconnected.html (#30063)
  • TIMEOUT [expected OK] /html/interaction/focus/the-autofocus-attribute/autofocus-dialog.html (#29087)
    • TIMEOUT [expected FAIL] subtest: &lt;dialog&gt;-contained autofocus element gets focused when the dialog is shown

      Test timed out
      

  • TIMEOUT [expected OK] /html/interaction/focus/the-autofocus-attribute/document-with-fragment-top.html (#28259)
    • TIMEOUT [expected FAIL] subtest: Autofocus elements in top-level browsing context's documents with "top" fragments should work.

      Test timed out
      

  • TIMEOUT /preload/preload-resource-match.https.html
    • TIMEOUT [expected FAIL] subtest: Loading script (use-credentials) with link (no-cors) should discard the preloaded response

      Test timed out
      

    • NOTRUN [expected TIMEOUT] subtest: Loading script (use-credentials) with link (anonymous) should discard the preloaded response
  • OK [expected ERROR] /workers/constructors/Worker/Worker-constructor.html (#22991)
Stable unexpected results that are known to be intermittent (27)
  • TIMEOUT /FileAPI/url/url-in-tags-revoke.window.html (#19978)
    • PASS [expected TIMEOUT] subtest: Fetching a blob URL immediately before revoking it works in &lt;script&gt; tags.
  • FAIL [expected PASS] /_mozilla/mozilla/sslfail.html (#10760)
  • TIMEOUT [expected OK] /_mozilla/mozilla/window_resizeTo.html (#36741)
    • TIMEOUT [expected PASS] subtest: Popup onresize event fires after resizeTo

      Test timed out
      

  • OK /_webgl/conformance/textures/misc/texture-upload-size.html (#21770)
    • FAIL [expected PASS] subtest: WebGL test #53

      assert_true: Texture was smaller than the expected size 2x2 expected true got false
      

    • FAIL [expected PASS] subtest: WebGL test #55

      assert_true: getError expected: INVALID_VALUE. Was NO_ERROR : when calling texSubImage2D with the same texture upload with offset 1, 1 expected true got false
      

    • FAIL [expected PASS] subtest: WebGL test #57

      assert_true: Texture was smaller than the expected size 2x2 expected true got false
      

    • FAIL [expected PASS] subtest: WebGL test #59

      assert_true: getError expected: INVALID_VALUE. Was NO_ERROR : when calling texSubImage2D with the same texture upload with offset 1, 1 expected true got false
      

    • PASS [expected FAIL] subtest: WebGL test #61
    • PASS [expected FAIL] subtest: WebGL test #63
    • PASS [expected FAIL] subtest: WebGL test #65
    • PASS [expected FAIL] subtest: WebGL test #67
  • OK /content-security-policy/frame-ancestors/frame-ancestors-path-ignored.window.html (#36468)
    • PASS [expected FAIL] subtest: A 'frame-ancestors' CSP directive with a URL that includes a path should be ignored.
  • OK /css/css-fonts/variations/at-font-face-font-matching.html (#20684)
    • FAIL [expected PASS] subtest: Matching font-weight: '501' should prefer '450 460' over '390 410'

      assert_equals: Unexpected font on test element expected 487 but got 532
      

    • FAIL [expected PASS] subtest: Matching font-style: 'oblique 20deg' should prefer 'oblique 30deg 60deg' over 'oblique 40deg 50deg'

      assert_equals: Unexpected font on test element expected 487 but got 532
      

  • FAIL [expected PASS] /css/css-grid/grid-items/grid-auto-margin-and-replaced-item-001.html (#37162)
  • OK /fetch/metadata/generated/css-font-face.https.sub.tentative.html (#32732)
    • PASS [expected FAIL] subtest: sec-fetch-site - Cross-Site -&gt; Same Origin
    • PASS [expected FAIL] subtest: sec-fetch-dest
  • OK /html/browsers/browsing-the-web/navigating-across-documents/initial-empty-document/iframe-nosrc.html (#34819)
    • FAIL [expected PASS] subtest: form submission

      assert_equals: expected "http://web-platform.test:8000/common/blank.html?1=" but got "about:blank"
      

  • OK /html/browsers/browsing-the-web/navigating-across-documents/initial-empty-document/iframe-src-aboutblank-navigate-immediately.html (#29048)
    • PASS [expected FAIL] subtest: Navigating to a different document with form submission
  • OK /html/browsers/browsing-the-web/navigating-across-documents/initial-empty-document/load-pageshow-events-iframe-contentWindow.html (#28681)
    • PASS [expected FAIL] subtest: load &amp; pageshow events do not fire on contentWindow of &lt;iframe&gt; element created with src='about:blank'
  • OK /html/browsers/browsing-the-web/navigating-across-documents/initial-empty-document/load-pageshow-events-window-open.html (#28691)
    • PASS [expected FAIL] subtest: load event does not fire on window.open('about:blank')
  • OK /html/browsers/history/the-history-interface/traverse_the_history_5.html (#21383)
    • PASS [expected FAIL] subtest: Multiple history traversals, last would be aborted
  • TIMEOUT /html/interaction/focus/the-autofocus-attribute/supported-elements.html (#24145)
    • FAIL [expected TIMEOUT] subtest: Element with tabindex should support autofocus

      assert_equals: expected "SPAN" but got "BODY"
      

    • PASS [expected NOTRUN] subtest: Non-HTMLElement should not support autofocus
    • FAIL [expected NOTRUN] subtest: Host element with delegatesFocus should support autofocus

      assert_equals: expected Element node &lt;div autofocus=""&gt;&lt;/div&gt; but got Element node &lt;body&gt;&lt;div autofocus=""&gt;&lt;/div&gt;&lt;/body&gt;
      

    • TIMEOUT [expected NOTRUN] subtest: Host element with delegatesFocus including no focusable descendants should be skipped

      Test timed out
      

  • OK [expected TIMEOUT] /html/interaction/focus/the-autofocus-attribute/update-the-rendering.html (#24145)
    • FAIL [expected TIMEOUT] subtest: "Flush autofocus candidates" should be happen before a scroll event and animation frame callbacks

      assert_array_equals: animationFrame lengths differ, expected array ["autofocus", "scroll", "animationFrame"] length 3, got ["animationFrame"] length 1
      

  • CRASH [expected TIMEOUT] /html/semantics/embedded-content/the-iframe-element/iframe_sandbox_popups_escaping-1.html (#22647)
  • OK [expected TIMEOUT] /html/semantics/embedded-content/the-iframe-element/iframe_sandbox_popups_escaping-2.html (#22667)
    • FAIL [expected TIMEOUT] subtest: Check that popups from a sandboxed iframe escape the sandbox if allow-popups-to-escape-sandbox is used

      assert_equals: It came from a sandboxed iframe expected "null" but got "http://web-platform.test:8000"
      

  • CRASH [expected TIMEOUT] /html/semantics/embedded-content/the-iframe-element/iframe_sandbox_popups_escaping-3.html (#24057)
  • OK [expected TIMEOUT] /html/semantics/embedded-content/the-iframe-element/iframe_sandbox_popups_nonescaping-1.html (#24066)
    • FAIL [expected NOTRUN] subtest: Check that popups from a sandboxed iframe do not escape the sandbox

      assert_equals: It came from a sandboxed iframe expected "null" but got "http://web-platform.test:8000"
      

  • OK [expected TIMEOUT] /html/semantics/embedded-content/the-iframe-element/iframe_sandbox_popups_nonescaping-2.html (#22154)
  • OK [expected TIMEOUT] /html/semantics/embedded-content/the-iframe-element/iframe_sandbox_popups_nonescaping-3.html (#24066)
    • FAIL [expected NOTRUN] subtest: Check that popups from a sandboxed iframe do not escape the sandbox

      assert_equals: It came from a sandboxed iframe expected "null" but got "http://web-platform.test:8000"
      

  • OK /html/semantics/scripting-1/the-script-element/module/dynamic-import/blob-url.any.html (#33948)
    • FAIL [expected PASS] subtest: Revoking a blob URL immediately after calling import will not fail

      promise_test: Unhandled rejection with value: object "TypeError: Dynamic import failed"
      

  • OK /navigation-timing/test-navigation-type-reload.html (#33334)
    • FAIL [expected PASS] subtest: Reload domComplete &gt; Original domComplete

      assert_true: Reload domComplete &gt; Original domComplete expected true got false
      

    • FAIL [expected PASS] subtest: Reload loadEventEnd &gt; Original loadEventEnd

      assert_true: Reload loadEventEnd &gt; Original loadEventEnd expected true got false
      

    • FAIL [expected PASS] subtest: Reload loadEventStart &gt; Original loadEventStart

      assert_true: Reload loadEventStart &gt; Original loadEventStart expected true got false
      

  • OK /preload/preload-error.sub.html (#37177)
    • PASS [expected FAIL] subtest: success (style): main
    • FAIL [expected PASS] subtest: 404 (style): main

      assert_greater_than: http://web-platform.test:8000/preload/resources/dummy.css?pipe=status%28404%29&amp;label=style should be loaded expected a number greater than 0 but got 0
      

    • PASS [expected FAIL] subtest: CORS (style): main
    • PASS [expected FAIL] subtest: success (script): main
    • PASS [expected FAIL] subtest: 404 (script): main
    • PASS [expected FAIL] subtest: 404 (xhr): main
    • PASS [expected FAIL] subtest: CORS (xhr): main
    • PASS [expected FAIL] subtest: Decode-error (style): main
    • FAIL [expected PASS] subtest: MIME-error (script): main

      assert_greater_than: http://web-platform.test:8000/preload/resources/dummy.css?pipe=header%28Content-Type%2Ctext%2Fnotjavascript%29&amp;label=script should be loaded expected a number greater than 0 but got 0
      

  • OK /resize-observer/eventloop.html (#33599)
    • PASS [expected FAIL] subtest: test0: multiple notifications inside same event loop
  • ERROR /service-workers/idlharness.https.any.html (#36250)
    • PASS [expected TIMEOUT] subtest: ServiceWorkerContainer interface: operation register((TrustedScriptURL or USVString), optional RegistrationOptions)
    • PASS [expected TIMEOUT] subtest: NavigationPreloadManager interface: operation enable()
    • PASS [expected TIMEOUT] subtest: NavigationPreloadManager interface: operation disable()
    • PASS [expected TIMEOUT] subtest: NavigationPreloadManager interface: operation setHeaderValue(ByteString)
    • PASS [expected TIMEOUT] subtest: NavigationPreloadManager interface: operation getState()
  • OK /webaudio/the-audio-api/the-audiobuffersourcenode-interface/sub-sample-buffer-stitching.html (#22849)
    • FAIL [expected PASS] subtest: X Stitched sine-wave buffers at sample rate 43800 does not equal [0,0.06264832615852356,0.12505052983760834,0.18696144223213196,0.24813786149024963,0.308339387178421,0.36732959747314453,0.4248766601085663,0.480754554271698,0.5347436666488647,0.5866320133209229,0.6362156271934509,0.6832997798919678,0.7276994585990906,0.7692402601242065,0.8077589869499207...] with an element-wise tolerance of {"absoluteThreshold":0.0038986,"relativeThreshold":0}. Index Actual Expected AbsError RelError Test threshold [14650] 2.4318193492940305e-17 8.6956524848937988e-1 8.6956524848937988e-1 1.0000000000000000e+0 3.8985999999999999e-3 [14651] 3.0547976493835449e-1 8.9879405498504639e-1 5.9331429004669189e-1 6.6012262403823208e-1 3.8985999999999999e-3 Max AbsError of 8.6956524848937988e-1 at index of 14650. Max RelError of 1.0000000000000000e+0 at index of 14650.

      assert_true: expected true got false
      

Stable unexpected results (5)
  • FAIL [expected PASS] /css/CSS2/positioning/dynamic-top-change-002.xht
  • FAIL [expected PASS] /css/CSS2/positioning/dynamic-top-change-003.xht
  • FAIL [expected PASS] /css/CSS2/text/word-spacing-applies-to-014.xht
  • FAIL [expected PASS] /css/css-flexbox/flexbox_stf-table-singleline-2.html
  • FAIL [expected PASS] /css/css-flexbox/flexbox_stf-table-singleline.html

Copy link
github-actions bot commented Jul 1, 2025

⚠️ Try run (#15996293014) failed.

@mrobinson mrobinson force-pushed the incremental-box-tree-update branch from d48db54 to d467934 Compare July 1, 2025 11:15
@mrobinson mrobinson added the T-linux-wpt Do a try run of the WPT label Jul 1, 2025
@github-actions github-actions bot removed the T-linux-wpt Do a try run of the WPT label Jul 1, 2025
Copy link
github-actions bot commented Jul 1, 2025

🔨 Triggering try run (#15997757388) for Linux (WPT)

Copy link
github-actions bot commented Jul 1, 2025

Test results for linux-wpt from try job (#15997757388):

Flaky unexpected result (13)
  • TIMEOUT /FileAPI/url/url-in-tags-revoke.window.html (#19978)
    • TIMEOUT [expected PASS] subtest: Fetching a blob URL immediately before revoking it works in &lt;script&gt; tags.

      Test timed out
      

  • OK /css/css-cascade/layer-cssom-order-reverse.html (#36094)
    • PASS [expected FAIL] subtest: Delete layer invalidates @font-face
  • OK /css/css-cascade/layer-font-face-override.html (#35935)
    • PASS [expected FAIL] subtest: @font-face override update with appended sheet 1
    • PASS [expected FAIL] subtest: @font-face override update with appended sheet 2
  • OK /html/browsers/browsing-the-web/navigating-across-documents/008.html (#24456)
    • PASS [expected FAIL] subtest: Link with onclick form submit to javascript url and href navigation
  • TIMEOUT [expected OK] /html/browsers/browsing-the-web/navigating-across-documents/anchor-fragment-form-submit-longfragment.html
  • OK /html/browsers/browsing-the-web/navigating-across-documents/initial-empty-document/load-pageshow-events-window-open.html (#28691)
    • PASS [expected FAIL] subtest: load event does not fire on window.open('about:blank')
  • OK /html/browsers/browsing-the-web/navigating-across-documents/navigation-unload-same-origin.window.html (#29049)
    • PASS [expected FAIL] subtest: Same-origin navigation started from unload handler must be ignored
  • OK /html/browsers/browsing-the-web/navigating-across-documents/refresh/same-document-refresh.html (#34597)
    • FAIL [expected PASS] subtest: Same-Document Referrer from Refresh

      assert_equals: original page loads expected "http://web-platform.test:8000/html/browsers/browsing-the-web/navigating-across-documents/refresh/resources/refresh-with-section.sub.html?url=%23section" but got "http://web-platform.test:8000/html/browsers/browsing-the-web/navigating-across-documents/refresh/resources/refresh-with-section.sub.html?url=%23section#section"
      

  • OK /html/browsers/browsing-the-web/navigating-across-documents/replace-before-load/a-click.html (#28697)
    • PASS [expected FAIL] subtest: aElement.click() before the load event must NOT replace
  • OK /html/semantics/embedded-content/the-video-element/intrinsic_sizes.htm (#37173)
    • FAIL [expected PASS] subtest: default object size after src is removed

      assert_equals: expected "300px" but got "320px"
      

  • OK /html/semantics/forms/form-submission-0/form-submit-iframe-then-location-navigate.html (#29634)
    • PASS [expected FAIL] subtest: Verifies that location navigations take precedence when following form submissions.
  • TIMEOUT [expected OK] /html/semantics/forms/form-submission-0/reparent-form-during-planned-navigation-task.html (#29724)
    • TIMEOUT [expected PASS] subtest: reparent-form-during-planned-navigation-task

      Test timed out
      

  • TIMEOUT /preload/preload-resource-match.https.html
    • TIMEOUT [expected FAIL] subtest: Loading script (use-credentials) with link (no-cors) should discard the preloaded response

      Test timed out
      

    • NOTRUN [expected TIMEOUT] subtest: Loading script (use-credentials) with link (anonymous) should discard the preloaded response
Stable unexpected results that are known to be intermittent (17)
  • FAIL [expected PASS] /_mozilla/mozilla/sslfail.html (#10760)
  • OK /css/css-fonts/variations/at-font-face-font-matching.html (#20684)
    • FAIL [expected PASS] subtest: Matching font-style: 'oblique -21deg' should prefer 'oblique 30deg 60deg' over 'oblique 40deg 50deg'

      assert_equals: Unexpected font on test element expected 487 but got 
      9E88
      532
      

  • OK /fetch/metadata/generated/css-font-face.https.sub.tentative.html (#32732)
    • PASS [expected FAIL] subtest: sec-fetch-dest
    • PASS [expected FAIL] subtest: sec-fetch-user
  • OK /fetch/metadata/generated/css-font-face.sub.tentative.html (#34624)
    • FAIL [expected PASS] subtest: sec-fetch-storage-access - Not sent to non-trustworthy cross-site destination

      promise_test: Unhandled rejection with value: object "Error: Failed to query for recorded headers."
      

  • OK /html/browsers/browsing-the-web/navigating-across-documents/initial-empty-document/iframe-src-aboutblank-navigate-immediately.html (#29048)
    • PASS [expected FAIL] subtest: Navigating to a different document with form submission
  • OK /html/browsers/browsing-the-web/navigating-across-documents/initial-empty-document/load-pageshow-events-iframe-contentWindow.html (#28681)
    • PASS [expected FAIL] subtest: load &amp; pageshow events do not fire on contentWindow of &lt;iframe&gt; element created with src='about:blank'
  • OK /html/browsers/history/the-history-interface/traverse_the_history_2.html (#21383)
    • PASS [expected FAIL] subtest: Multiple history traversals, last would be aborted
  • OK [expected TIMEOUT] /html/interaction/focus/the-autofocus-attribute/supported-elements.html (#24145)
    • PASS [expected NOTRUN] subtest: Non-HTMLElement should not support autofocus
    • FAIL [expected NOTRUN] subtest: Host element with delegatesFocus should support autofocus

      assert_equals: expected Element node &lt;div autofocus=""&gt;&lt;/div&gt; but got Element node &lt;body&gt;&lt;/body&gt;
      

    • FAIL [expected NOTRUN] subtest: Host element with delegatesFocus including no focusable descendants should be skipped

      assert_equals: expected Element node &lt;input autofocus=""&gt;&lt;/input&gt; but got Element node &lt;body&gt;&lt;div autofocus=""&gt;&lt;/div&gt;&lt;input autofocus=""&gt;&lt;/body&gt;
      

    • FAIL [expected NOTRUN] subtest: Area element should support autofocus

      promise_test: Unhandled rejection with value: object "TypeError: w.document.querySelector(...) is null"
      

  • TIMEOUT [expected CRASH] /html/semantics/embedded-content/the-iframe-element/iframe_sandbox_popups_escaping-1.html (#22647)
  • OK [expected TIMEOUT] /html/semantics/embedded-content/the-iframe-element/iframe_sandbox_popups_escaping-2.html (#22667)
    • FAIL [expected TIMEOUT] subtest: Check that popups from a sandboxed iframe escape the sandbox if allow-popups-to-escape-sandbox is used

      assert_equals: It came from a sandboxed iframe expected "null" but got "http://web-platform.test:8000"
      

  • CRASH [expected TIMEOUT] /html/semantics/embedded-content/the-iframe-element/iframe_sandbox_popups_escaping-3.html (#24057)
  • OK [expected TIMEOUT] /html/semantics/embedded-content/the-iframe-element/iframe_sandbox_popups_nonescaping-1.html (#24066)
  • OK [expected TIMEOUT] /html/semantics/embedded-content/the-iframe-element/iframe_sandbox_popups_nonescaping-2.html (#22154)
  • OK [expected TIMEOUT] /html/semantics/embedded-content/the-iframe-element/iframe_sandbox_popups_nonescaping-3.html (#24066)
  • OK /preload/prefetch-document.html (#37210)
    • FAIL [expected PASS] subtest: different-site document prefetch with 'as=document' should not be consumed

      assert_equals: expected 2 but got 1
      

  • OK /preload/preload-error.sub.html (#37177)
    • FAIL [expected PASS] subtest: success (style): main

      assert_greater_than: http://web-platform.test:8000/preload/resources/dummy.css?label=style should be loaded expected a number greater than 0 but got 0
      

    • FAIL [expected PASS] subtest: 404 (style): main

      assert_greater_than: http://web-platform.test:8000/preload/resources/dummy.css?pipe=status%28404%29&amp;label=style should be loaded expected a number greater than 0 but got 0
      

    • PASS [expected FAIL] subtest: CORS (style): main
    • FAIL [expected PASS] subtest: CORS (script): main

      assert_greater_than: http://not-web-platform.test:8000/preload/resources/dummy.js?pipe=header%28Access-Control-Allow-Origin%2C*%29&amp;label=script should be loaded expected a number greater than 0 but got 0
      

    • PASS [expected FAIL] subtest: success (xhr): main
    • FAIL [expected PASS] subtest: Decode-error (style): main

      assert_greater_than: http://web-platform.test:8000/preload/resources/dummy.xml?pipe=header%28Content-Type%2Ctext%2Fcss%29&amp;label=style should be loaded expected a number greater than 0 but got 0
      

    • PASS [expected FAIL] subtest: MIME-error (script): main
  • OK /webaudio/the-audio-api/the-audiobuffersourcenode-interface/sub-sample-buffer-stitching.html (#22849)
    • FAIL [expected PASS] subtest: X Stitched sine-wave buffers at sample rate 43800 does not equal [0,0.06264832615852356,0.12505052983760834,0.18696144223213196,0.24813786149024963,0.308339387178421,0.36732959747314453,0.4248766601085663,0.480754554271698,0.5347436666488647,0.5866320133209229,0.6362156271934509,0.6832997798919678,0.7276994585990906,0.7692402601242065,0.8077589869499207...] with an element-wise tolerance of {"absoluteThreshold":0.0038986,"relativeThreshold":0}. Index Actual Expected AbsError RelError Test threshold [14650] 3.5550678477869705e+31 8.6956524848937988e-1 3.5550678477869705e+31 4.0883278787450179e+31 3.8985999999999999e-3 [14651] 3.0547976493835449e-1 8.9879405498504639e-1 5.9331429004669189e-1 6.6012262403823208e-1 3.8985999999999999e-3 Max AbsError of 3.5550678477869705e+31 at index of 14650. Max RelError of 4.0883278787450179e+31 at index of 14650.

      assert_true: expected true got false
      

    • FAIL [expected PASS] subtest: X SNR (-587.5828719273889 dB) is not greater than or equal to 65.737. Got -587.5828719273889.

      assert_true: expected true got false
      

Copy link
github-actions bot commented Jul 1, 2025

✨ Try run (#15997757388) succeeded.

@mrobinson mrobinson requested a review from gterzian as a code owner July 1, 2025 12:07
@mrobinson mrobinson added the T-linux-wpt Do a try run of the WPT label Jul 1, 2025
@github-actions github-actions bot removed the T-linux-wpt Do a try run of the WPT label Jul 1, 2025
Copy link
github-actions bot commented Jul 1, 2025

🔨 Triggering try run (#15998842719) for Linux (WPT)

Copy link
github-actions bot commented Jul 1, 2025

Test results for linux-wpt from try job (#15998842719):

Flaky unexpected result (14)
  • FAIL [expected PASS] /_mozilla/css/dirty_viewport.html (#13731)
  • OK /css/css-fonts/variations/at-font-face-font-matching.html (#20684)
    • FAIL [expected PASS] subtest: Matching font-weight: '501' should prefer '450 460' over '390 410'

      assert_equals: Unexpected font on test element expected 487 but got 532
      

  • CRASH [expected PASS] /css/css-overflow/document-element-overflow-hidden-scroll.html
  • OK [expected ERROR] /fetch/fetch-later/quota/same-origin-iframe/empty-payload.tentative.https.window.html (#35176)
  • OK /html/browsers/browsing-the-web/navigating-across-documents/008.html (#24456)
    • PASS [expected FAIL] subtest: Link with onclick form submit to javascript url and href navigation
  • OK /html/browsers/browsing-the-web/navigating-across-documents/009.html (#24456)
    • PASS [expected FAIL] subtest: Link with onclick form submit to javascript url with document.write and href navigation
  • TIMEOUT [expected OK] /html/browsers/browsing-the-web/navigating-across-documents/anchor-fragment-form-submit-longfragment.html
  • OK /html/browsers/browsing-the-web/navigating-across-documents/navigation-unload-cross-origin.sub.window.html (#29056)
    • PASS [expected FAIL] subtest: Cross-origin navigation started from unload handler must be ignored
  • OK /html/browsers/browsing-the-web/navigating-across-documents/navigation-unload-same-origin.window.html (#29049)
    • PASS [expected FAIL] subtest: Same-origin navigation started from unload handler must be ignored
  • OK /html/browsers/browsing-the-web/navigating-across-documents/replace-before-load/a-click.html (#28697)
    • PASS [expected FAIL] subtest: aElement.click() before the load event must NOT replace
  • OK /html/semantics/embedded-content/the-iframe-element/iframe-loading-lazy-reload-location-reload.html (#32595)
    • FAIL [expected PASS] subtest: Reloading iframe loading='lazy' before it is loaded: location.reload

      uncaught exception: Error: assert_equals: expected "http://web-platform.test:8000/html/semantics/embedded-content/the-iframe-element/support/blank.htm?src" but got "about:blank"
      

  • OK /html/semantics/scripting-1/the-script-element/module/dynamic-import/blob-url.any.html (#33948)
    • FAIL [expected PASS] subtest: Revoking a blob URL immediately after calling import will not fail

      promise_test: Unhandled rejection with value: object "TypeError: Dynamic import failed"
      

  • ERROR /service-workers/idlharness.https.any.html (#36250)
    • PASS [expected TIMEOUT] subtest: ServiceWorkerContainer interface: operation register((TrustedScriptURL or USVString), optional RegistrationOptions)
    • PASS [expected TIMEOUT] subtest: NavigationPreloadManager interface: operation enable()
    • PASS [expected TIMEOUT] subtest: NavigationPreloadManager interface: operation disable()
    • PASS [expected TIMEOUT] subtest: NavigationPreloadManager interface: operation setHeaderValue(ByteString)
    • PASS [expected TIMEOUT] subtest: NavigationPreloadManager interface: operation getState()
  • OK /workers/dedicated-worker-from-blob-url.window.html (#22286)
    • PASS [expected FAIL] subtest: Creating a dedicated worker from a blob URL works immediately before revoking.
Stable unexpected results that are known to be intermittent (24)
  • FAIL [expected PASS] /_mozilla/mozilla/sslfail.html (#10760)
  • TIMEOUT [expected OK] /_mozilla/mozilla/window_resizeTo.html (#36741)
    • TIMEOUT [expected PASS] subtest: Popup onresize event fires after resizeTo

      Test timed out
      

  • OK /css/css-cascade/layer-cssom-order-reverse.html (#36094)
    • PASS [expected FAIL] subtest: Delete layer invalidates @font-face
  • OK /css/css-cascade/layer-font-face-override.html (#35935)
    • PASS [expected FAIL] subtest: @font-face override update with appended sheet 1
    • PASS [expected FAIL] subtest: @font-face override update with appended sheet 2
  • FAIL [expected PASS] /css/css-grid/grid-items/grid-auto-margin-and-replaced-item-001.html (#37162)
  • FAIL [expected PASS] /css/css-sizing/dynamic-available-size-iframe.html (#31559)
  • OK /css/cssom-view/scroll-behavior-smooth-navigation.html (#29564)
    • PASS [expected FAIL] subtest: Smooth scrolling while doing history navigation.
  • OK /fetch/metadata/generated/css-font-face.https.sub.tentative.html (#32732)
    • PASS [expected FAIL] subtest: sec-fetch-dest
    • PASS [expected FAIL] subtest: sec-fetch-storage-access - Same site
  • OK /fetch/metadata/generated/css-font-face.sub.tentative.html (#34624)
    • PASS [expected FAIL] subtest: sec-fetch-storage-access - Not sent to non-trustworthy same-site destination
    • FAIL [expected PASS] subtest: sec-fetch-storage-access - Not sent to non-trustworthy cross-site destination

      promise_test: Unhandled rejection with value: object "Error: Failed to query for recorded headers."
      

  • OK /html/browsers/browsing-the-web/navigating-across-documents/initial-empty-document/load-pageshow-events-iframe-contentWindow.html (#28681)
    • PASS [expected FAIL] subtest: load &amp; pageshow events do not fire on contentWindow of &lt;iframe&gt; element created with src=''
  • OK /html/browsers/browsing-the-web/navigating-across-documents/navigation-unload-same-origin-fragment.html (#20768)
    • PASS [expected FAIL] subtest: Tests that a fragment navigation in the unload handler will not block the initial navigation
  • OK /html/browsers/history/the-history-interface/traverse_the_history_5.html (#21383)
    • FAIL [expected PASS] subtest: Multiple history traversals, last would be aborted

      assert_array_equals: Pages opened during history navigation expected property 1 to be 5 but got 3 (expected array [6, 5] got [6, 3])
      

  • PASS [expected FAIL] /html/canvas/element/manual/text/canvas.2d.disconnected.html (#30063)
  • OK [expected TIMEOUT] /html/interaction/focus/the-autofocus-attribute/supported-elements.html (#24145)
    • PASS [expected NOTRUN] subtest: Non-HTMLElement should not support autofocus
    • FAIL [expected NOTRUN] subtest: Host element with delegatesFocus should support autofocus

      assert_equals: expected Element node &lt;div autofocus=""&gt;&lt;/div&gt; but got Element node &lt;body&gt;&lt;/body&gt;
      

    • FAIL [expected NOTRUN] subtest: Host element with delegatesFocus including no focusable descendants should be skipped

      assert_equals: expected Element node &lt;input autofocus=""&gt;&lt;/input&gt; but got Element node &lt;body&gt;&lt;div autofocus=""&gt;&lt;/div&gt;&lt;input autofocus=""&gt;&lt;/body&gt;
      

    • FAIL [expected NOTRUN] subtest: Area element should support autofocus

      promise_test: Unhandled rejection with value: object "TypeError: w.document.querySelector(...) is null"
      

  • OK [expected CRASH] /html/semantics/embedded-content/the-iframe-element/iframe_sandbox_popups_escaping-1.html (#22647)
    • FAIL [expected TIMEOUT] subtest: Check that popups from a sandboxed iframe escape the sandbox if allow-popups-to-escape-sandbox is used

      assert_equals: It came from a sandboxed iframe expected "null" but got "http://web-platform.test:8000"
      

  • OK [expected TIMEOUT] /html/semantics/embedded-content/the-iframe-element/iframe_sandbox_popups_escaping-2.html (#22667)
    • FAIL [expected TIMEOUT] subtest: Check that popups from a sandboxed iframe escape the sandbox if allow-popups-to-escape-sandbox is used

      assert_equals: It came from a sandboxed iframe expected "null" but got "http://web-platform.test:8000"
      

  • CRASH [expected TIMEOUT] /html/semantics/embedded-content/the-iframe-element/iframe_sandbox_popups_escaping-3.html (#24057)
  • OK [expected TIMEOUT] /html/semantics/embedded-content/the-iframe-element/iframe_sandbox_popups_nonescaping-1.html (#24066)
  • OK [expected TIMEOUT] /html/semantics/embedded-content/the-iframe-element/iframe_sandbox_popups_nonescaping-2.html (#22154)
  • OK [expected TIMEOUT] /html/semantics/embedded-content/the-iframe-element/iframe_sandbox_popups_nonescaping-3.html (#24066)
  • OK /navigation-timing/test-navigation-type-reload.html (#33334)
    • PASS [expected FAIL] subtest: Reload domComplete &gt; Original domComplete
    • PASS [expected FAIL] subtest: Reload domContentLoadedEventEnd &gt; Original domContentLoadedEventEnd
    • PASS [expected FAIL] subtest: Reload domContentLoadedEventStart &gt; Original domContentLoadedEventStart
    • PASS [expected FAIL] subtest: Reload fetchStart &gt; Original fetchStart
    • PASS [expected FAIL] subtest: Reload loadEventEnd &gt; Original loadEventEnd
    • PASS [expected FAIL] subtest: Reload loadEventStart &gt; Original loadEventStart
  • OK /preload/preload-error.sub.html (#37177)
    • FAIL [expected PASS] subtest: success (style): main

      assert_greater_than: http://web-platform.test:8000/preload/resources/dummy.css?label=style should be loaded expected a number greater than 0 but got 0
      

    • FAIL [expected PASS] subtest: 404 (style): main

      assert_greater_than: http://web-platform.test:8000/preload/resources/dummy.css?pipe=status%28404%29&amp;label=style should be loaded expected a number greater than 0 but got 0
      

    • PASS [expected FAIL] subtest: CORS (style): main
    • PASS [expected FAIL] subtest: success (script): main
    • PASS [expected FAIL] subtest: 404 (script): main
    • FAIL [expected PASS] subtest: CORS (script): main

      assert_greater_than: http://not-web-platform.test:8000/preload/resources/dummy.js?pipe=header%28Access-Control-Allow-Origin%2C*%29&amp;label=script should be loaded expected a number greater than 0 but got 0
      

    • PASS [expected FAIL] subtest: success (xhr): main
    • PASS [expected FAIL] subtest: Decode-error (script): main
    • PASS [expected FAIL] subtest: MIME-error (script): main
  • OK /webaudio/the-audio-api/the-audiobuffersourcenode-interface/sub-sample-buffer-stitching.html (#22849)
    • FAIL [expected PASS] subtest: X Stitched sine-wave buffers at sample rate 43800 does not equal [0,0.06264832615852356,0.12505052983760834,0.18696144223213196,0.24813786149024963,0.308339387178421,0.36732959747314453,0.4248766601085663,0.480754554271698,0.5347436666488647,0.5866320133209229,0.6362156271934509,0.6832997798919678,0.7276994585990906,0.7692402601242065,0.8077589869499207...] with an element-wise tolerance of {"absoluteThreshold":0.0038986,"relativeThreshold":0}. Index Actual Expected AbsError RelError Test threshold [14650] 1.7524137496948242e+0 8.6956524848937988e-1 8.8284850120544434e-1 1.0152757400771710e+0 3.8985999999999999e-3 [14651] 3.0547976493835449e-1 8.9879405498504639e-1 5.9331429004669189e-1 6.6012262403823208e-1 3.8985999999999999e-3 Max AbsError of 8.8284850120544434e-1 at index of 14650. Max RelError of 1.0152757400771710e+0 at index of 14650.

      assert_true: expected true got false
      

    • FAIL [expected PASS] subtest: X SNR (42.87543895898413 dB) is not greater than or equal to 65.737. Got 42.87543895898413.

      assert_true: expected true got false
      

  • OK [expected ERROR] /workers/constructors/Worker/Worker-constructor.html (#22991)
Stable unexpected results (21)
  • FAIL [expected PASS] /_mozilla/css/iframe/hide_layers2.html
  • FAIL [expected PASS] /css/CSS2/box-display/delete-block-in-inlines-beginning-001.xht
  • FAIL [expected PASS] /css/CSS2/box-display/delete-block-in-inlines-end-001.xht
  • FAIL [expected PASS] /css/CSS2/box-display/delete-block-in-inlines-middle-001.xht
  • FAIL [expected PASS] /css/CSS2/box-display/delete-inline-in-blocks-beginning-001.xht
  • FAIL [expected PASS] /css/CSS2/box-display/delete-inline-in-blocks-end-001.xht
  • FAIL [expected PASS] /css/CSS2/box-display/delete-inline-in-blocks-middle-001.xht
  • FAIL [expected PASS] /css/CSS2/box-display/delete-inline-in-blocks-middle-002.xht
  • FAIL [expected PASS] /css/CSS2/box-display/delete-inline-in-blocks-middle-003.xht
  • FAIL [expected PASS] /css/css-backgrounds/document-canvas-remove-body.html
  • FAIL [expected PASS] /css/css-flexbox/remove-wrapped-001.html
  • FAIL [expected PASS] /css/css-flexbox/remove-wrapped-002.html
  • FAIL [expected PASS] /css/css-overflow/line-clamp/webkit-line-clamp-023.html
  • FAIL [expected PASS] /css/css-position/sticky/position-sticky-scrolled-remove-sibling-002.html
  • OK /css/css-tables/col_removal.html
    • FAIL [expected PASS] subtest: Table grid syncs after COL removal

      assert_equals: table shrinks after column is removed expected 64 but got 162
      

  • FAIL [expected PASS] /css/css-tables/collapsed-border-remove-cell.html
  • FAIL [expected PASS] /css/css-tables/paint/row-background-paint-remove-last-cell.html
  • FAIL [expected PASS] /css/css-tables/remove-caption-from-anon-table.html
  • FAIL [expected PASS] /css/css-will-change/will-change-transform-add-content.html
  • FAIL [expected PASS] /dom/nodes/remove-from-shadow-host-and-adopt-into-iframe.html
  • OK /shadow-dom/scroll-to-the-fragment-in-shadow-tree.html
    • PASS [expected FAIL] subtest: The user agent scroll to the fragment when there is an anchor element with a name attribute exactly equal to the decoded fragid
    • PASS [expected FAIL] subtest: The user agent should not scroll to an element with an ID exactly equal to the decoded fragid in an open shadow tree
    • PASS [expected FAIL] subtest: The user agent should not scroll to an element with an ID exactly equal to the decoded fragid in a closed shadow tree
    • PASS [expected FAIL] subtest: The user agent should not scroll to an anchor element with a name attribute exactly equal to the decoded fragid in an open shadow tree
    • PASS [expected FAIL] subtest: The user agent should not scroll to an anchor element with a name attribute exactly equal to the decoded fragid in a closed shadow tree
    • PASS [expected FAIL] subtest: The user agent should scroll to an element with an ID exactly equal to the decoded fragid in the document tree even if there was another element with the same ID inside an open shadow tree earlier in tree order
    • PASS [expected FAIL] subtest: The user agent should scroll to an element with an ID exactly equal to the decoded fragid in the document tree even if there was another element with the same ID inside a closed shadow tree earlier in tree order
    • PASS [expected FAIL] subtest: The user agent should scroll to an anchor element with a name attribute exactly equal to the decoded fragid in the document tree even if there was another element with the same ID inside an open shadow tree earlier in tree order
    • PASS [expected FAIL] subtest: The user agent should scroll to an anchor element with a name attribute exactly equal to the decoded fragid in the document tree even if there was another element with the same ID inside a closed shadow tree earlier in tree order

Copy link
github-actions bot commented Jul 1, 2025

⚠️ Try run (#15998842719) failed.

doc.note_node_with_dirty_descendants(self.upcast());
restyle
.damage
.insert(LayoutDamage::recollect_box_tree_children());
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it should be insert(LayoutDamage::recollect_box_tree_children() | RestyleDamage::RELAYOUT) or the RestyleDamage::RELAYOUT bit is added into the return value of LayoutDamage::recollect_box_tree_children()

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

By the way, since it seems that we ready to support the NodeDamage::ContentOrHeritage, is it necessary to preserve the cached layout result in LayoutBoxBase for these boxes which have RecollectBoxTreeChildren damage but not REBUILD_BOX damage.

@mrobinson mrobinson force-pushed the incremental-box-tree-update branch from 285fd36 to 9958e7d Compare July 1, 2025 15:54
@mrobinson mrobinson added the T-linux-wpt Do a try run of the WPT label Jul 1, 2025
@github-actions github-actions bot removed the T-linux-wpt Do a try run of the WPT label Jul 1, 2025
Copy link
github-actions bot commented Jul 1, 2025

🔨 Triggering try run (#16004243835) for Linux (WPT)

@mrobinson mrobinson force-pushed the incremental-box-tree-update branch from 9958e7d to bdf2032 Compare July 1, 2025 16:09
Copy link
github-actions bot commented Jul 1, 2025

Test results for linux-wpt from try job (#16004243835):

Flaky unexpected result (22)
  • FAIL [expected PASS] /_mozilla/css/dirty_viewport.html (#13731)
  • TIMEOUT [expected OK] /_webgl/conformance/uniforms/out-of-bounds-uniform-array-access.html (#26225)
    • NOTRUN [expected PASS] subtest: Overall test
  • OK /content-security-policy/frame-ancestors/frame-ancestors-path-ignored.window.html (#36468)
    • PASS [expected FAIL] subtest: A 'frame-ancestors' CSP directive with a URL that includes a path should be ignored.
  • OK /css/css-fonts/generic-family-keywords-001.html (#37467)
    • PASS [expected FAIL] subtest: @font-face matching for quoted and unquoted generic(nastaliq)
  • OK /css/css-grid/alignment/grid-content-alignment-with-abspos-001.html (#34339)
    • FAIL [expected PASS] subtest: .grid 1

      assert_equals: 
      &lt;div class="grid" data-expected-width="800" data-expected-height="600"&gt;
          &lt;div class="a" id="item" data-offset-x="329" data-offset-y="269" data-expected-width="142" data-expected-height="62" style="place-self: center;"&gt;&lt;/div&gt;
        &lt;/div&gt;
      offsetLeft expected 329 but got 0
      

  • OK /custom-elements/form-associated/ElementInternals-setFormValue.html (#29174)
    • PASS [expected FAIL] subtest: Single value - name is missing
  • OK [expected ERROR] /fetch/fetch-later/quota/same-origin-iframe/multiple-iframes.tentative.https.window.html (#35176)
  • TIMEOUT /fetch/metadata/generated/css-images.sub.tentative.html (#29047)
    • TIMEOUT [expected PASS] subtest: background-image sec-fetch-dest - Not sent to non-trustworthy cross-site destination

      Test timed out
      

  • OK /html/browsers/browsing-the-web/navigating-across-documents/initial-empty-document/iframe-src-aboutblank-navigate-immediately.html (#29048)
    • PASS [expected FAIL] subtest: Navigating to a different document with form submission
  • TIMEOUT [expected OK] /html/browsers/browsing-the-web/navigating-across-documents/replace-before-load/form-requestsubmit.html (#28716)
    • TIMEOUT [expected FAIL] subtest: Replace before load, triggered by formElement.requestSubmit()

      Test timed out
      

  • TIMEOUT /html/browsers/history/the-history-interface/001.html (#12580)
    • FAIL [expected PASS] subtest: traversing history must also traverse hash changes

      assert_equals: (this could cause other failures later on) expected "" but got "test"
      

  • OK /html/browsers/history/the-history-interface/traverse_the_history_2.html (#21383)
    • PASS [expected FAIL] subtest: Multiple history traversals, last would be aborted
  • OK /html/browsers/history/the-history-interface/traverse_the_history_4.html (#21383)
    • PASS [expected FAIL] subtest: Multiple history traversals, last would be aborted
  • TIMEOUT [expected OK] /html/infrastructure/urls/base-url/document-base-url-window-initiator-is-not-opener.https.window.html (#30970)
  • TIMEOUT [expected OK] /html/interaction/focus/the-autofocus-attribute/document-with-fragment-empty.html (#28259)
    • TIMEOUT [expected FAIL] subtest: Autofocus elements in top-level browsing context's documents with empty fragments should work.

      Test timed out
      

  • TIMEOUT [expected OK] /html/interaction/focus/the-autofocus-attribute/document-with-fragment-nonexistent.html (#28259)
    • TIMEOUT [expected FAIL] subtest: Autofocus elements in top-level browsing context's documents with non-existent fragments should work.

      Test timed out
      

  • OK /html/semantics/embedded-content/the-video-element/intrinsic_sizes.htm (#37173)
    • FAIL [expected PASS] subtest: default object size after src is removed

      assert_equals: expected "300px" but got "320px"
      

  • OK /navigation-timing/test-navigation-type-reload.html (#33334)
    • PASS [expected FAIL] subtest: Reload domComplete &gt; Original domComplete
    • PASS [expected FAIL] subtest: Reload domContentLoadedEventEnd &gt; Original domContentLoadedEventEnd
    • PASS [expected FAIL] subtest: Reload domContentLoadedEventStart &gt; Original domContentLoadedEventStart
    • PASS [expected FAIL] subtest: Reload domInteractive &gt; Original domInteractive
    • PASS [expected FAIL] subtest: Reload fetchStart &gt; Original fetchStart
    • PASS [expected FAIL] subtest: Reload loadEventEnd &gt; Original loadEventEnd
    • PASS [expected FAIL] subtest: Reload loadEventStart &gt; Original loadEventStart
  • OK /resize-observer/change-layout-in-error.html (#32629)
    • PASS [expected FAIL] subtest: Changing layout in window error handler should not result in lifecyle loop when resize observer loop limit is reached.
  • TIMEOUT /resource-timing/test_resource_timing.html (#25720)
    • PASS [expected FAIL] subtest: PerformanceEntry has correct name, initiatorType, startTime, and duration (img)
  • TIMEOUT /resource-timing/test_resource_timing.https.html (#25216)
    • PASS [expected FAIL] subtest: PerformanceEntry has correct name, initiatorType, startTime, and duration (img)
  • OK [expected TIMEOUT] /webmessaging/with-ports/018.html (#24485)
    • PASS [expected TIMEOUT] subtest: origin of the script that invoked the method, javascript:
Stable unexpected results that are known to be intermittent (17)
  • FAIL [expected PASS] /_mozilla/mozilla/sslfail.html (#10760)
  • TIMEOUT [expected OK] /_mozilla/mozilla/window_resizeTo.html (#36741)
    • TIMEOUT [expected PASS] subtest: Popup onresize event fires after resizeTo

      Test timed out
      

  • FAIL [expected PASS] /css/css-grid/grid-items/grid-auto-margin-and-replaced-item-001.html (#37162)
  • OK /fetch/metadata/generated/css-font-face.https.sub.tentative.html (#32732)
    • PASS [expected FAIL] subtest: sec-fetch-storage-access - Same site
  • OK /html/browsers/browsing-the-web/navigating-across-documents/initial-empty-document/load-pageshow-events-iframe-contentWindow.html (#28681)
    • PASS [expected FAIL] subtest: load &amp; pageshow events do not fire on contentWindow of &lt;iframe&gt; element created with src=''
  • OK /html/browsers/browsing-the-web/navigating-across-documents/navigation-unload-same-origin-fragment.html (#20768)
    • PASS [expected FAIL] subtest: Tests that a fragment navigation in the unload handler will not block the initial navigation
  • PASS [expected FAIL] /html/canvas/element/manual/drawing-text-to-the-canvas/canvas.2d.disconnected-font-size-math.html (#30063)
  • TIMEOUT [expected OK] /html/interaction/focus/the-autofocus-attribute/autofocus-dialog.html (#29087)
    • TIMEOUT [expected FAIL] subtest: &lt;dialog&gt;-contained autofocus element gets focused when the dialog is shown

      Test timed out
      

  • TIMEOUT /html/interaction/focus/the-autofocus-attribute/supported-elements.html (#24145)
    • PASS [expected NOTRUN] subtest: Non-HTMLElement should not support autofocus
    • FAIL [expected NOTRUN] subtest: Host element with delegatesFocus should support autofocus

      assert_equals: expected Element node &lt;div autofocus=""&gt;&lt;/div&gt; but got Element node &lt;body&gt;&lt;div autofocus=""&gt;&lt;/div&gt;&lt;/body&gt;
      

    • TIMEOUT [expected NOTRUN] subtest: Host element with delegatesFocus including no focusable descendants should be skipped

      Test timed out
      

  • OK [expected CRASH] /html/semantics/embedded-content/the-iframe-element/iframe_sandbox_popups_escaping-1.html (#22647)
    • FAIL [expected TIMEOUT] subtest: Check that popups from a sandboxed iframe escape the sandbox if allow-popups-to-escape-sandbox is used

      assert_equals: It came from a sandboxed iframe expected "null" but got "http://web-platform.test:8000"
      

  • CRASH [expected TIMEOUT] /html/semantics/embedded-content/the-iframe-element/iframe_sandbox_popups_escaping-2.html (#22667)
  • OK [expected TIMEOUT] /html/semantics/embedded-content/the-iframe-element/iframe_sandbox_popups_nonescaping-1.html (#24066)
  • CRASH [expected TIMEOUT] /html/semantics/embedded-content/the-iframe-element/iframe_sandbox_popups_nonescaping-2.html (#22154)
  • OK [expected TIMEOUT] /html/semantics/embedded-content/the-iframe-element/iframe_sandbox_popups_nonescaping-3.html (#24066)
  • TIMEOUT [expected OK] /preload/preload-error.sub.html (#37177)
    • FAIL [expected PASS] subtest: success (style): main

      assert_greater_than: http://web-platform.test:8000/preload/resources/dummy.css?label=style should be loaded expected a number greater than 0 but got 0
      

    • PASS [expected FAIL] subtest: CORS (style): main
    • PASS [expected FAIL] subtest: 404 (script): main
    • FAIL [expected PASS] subtest: CORS (script): main

      assert_greater_than: http://not-web-platform.test:8000/preload/resources/dummy.js?pipe=header%28Access-Control-Allow-Origin%2C*%29&amp;label=script should be loaded expected a number greater than 0 but got 0
      

    • PASS [expected FAIL] subtest: CORS (xhr): main
    • PASS [expected FAIL] subtest: MIME-error (script): main
  • TIMEOUT [expected OK] /resource-timing/nested-context-navigations-iframe.html (#24311)
    • TIMEOUT [expected PASS] subtest: Test that crossorigin iframe navigations are not observable by the parent, even after history navigations by the parent

      Test timed out
      

    • NOTRUN [expected PASS] subtest: Test that cross-site iframe navigations are not observable by the parent, even after history navigations by the parent
    • NOTRUN [expected PASS] subtest: Test that iframe navigations are not observable by the parent
    • NOTRUN [expected PASS] subtest: Test that crossorigin iframe navigations are not observable by the parent
    • NOTRUN [expected PASS] subtest: Test that cross-site iframe navigations are not observable by the parent
    • NOTRUN [expected PASS] subtest: Test that iframe refreshes are not observable by the parent
    • NOTRUN [expected PASS] subtest: Test that crossorigin iframe refreshes are not observable by the parent
    • NOTRUN [expected PASS] subtest: Test that cross-site iframe refreshes are not observable by the parent
  • OK /webaudio/the-audio-api/the-audiobuffersourcenode-interface/sub-sample-buffer-stitching.html (#22849)
    • FAIL [expected PASS] subtest: X Stitched sine-wave buffers at sample rate 43800 does not equal [0,0.06264832615852356,0.12505052983760834,0.18696144223213196,0.24813786149024963,0.308339387178421,0.36732959747314453,0.4248766601085663,0.480754554271698,0.5347436666488647,0.5866320133209229,0.6362156271934509,0.6832997798919678,0.7276994585990906,0.7692402601242065,0.8077589869499207...] with an element-wise tolerance of {"absoluteThreshold":0.0038986,"relativeThreshold":0}. Index Actual Expected AbsError RelError Test threshold [14650] 2.7473577431859499e-39 8.6956524848937988e-1 8.6956524848937988e-1 1.0000000000000000e+0 3.8985999999999999e-3 [14651] 3.0547976493835449e-1 8.9879405498504639e-1 5.9331429004669189e-1 6.6012262403823208e-1 3.8985999999999999e-3 Max AbsError of 8.6956524848937988e-1 at index of 14650. Max RelError of 1.0000000000000000e+0 at index of 14650.

      assert_true: expected true got false
      

Copy link
github-actions bot commented Jul 1, 2025

✨ Try run (#16004243835) succeeded.

@mrobinson mrobinson changed the title layout: Add a first pass at incremental box layout layout: Add a first pass at incremental box tree construction Jul 2, 2025
This change:

- Adds a new type of LayoutDamage that signifies that a box needs its
  children recollected, because one or more of them need to be rebuilt.
- During restyle damage propagation, propagate this new damage upward in
  the tree. Then box tree construction should be able to preserve any
  still-valid box tree nodes from box slots.
- During BlockLevelBox job finalization, if a box slot is valid and
  there is not LayoutDamage to the element, use the old box slot,
  ensuring that its fragment cache is invalidated.

Signed-off-by: Martin Robinson <mrobinson@igalia.com>
Co-authored-by: Oriol Brufau <obrufau@igalia.com>
Co-authored-by: coding-joedow <ibluegalaxy_taoj@163.com>
@mrobinson mrobinson force-pushed the incremental-box-tree-update branch from bdf2032 to 3bb0170 Compare July 2, 2025 14:21
@mrobinson mrobinson added this pull request to the merge queue Jul 3, 2025
Merged via the queue into servo:main with commit 6dafeb7 Jul 3, 2025
21 checks passed
@mrobinson mrobinson deleted the incremental-box-tree-update branch July 3, 2025 08:41
@mrobinson
Copy link
Member Author

It seems that this change has likely caused #39439 and also #39548.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants
0