Repository: WebKit/WebKit
Pull request #45100: [css-anchor-position-1] Style resolution should visit children of anchor-positioned elements after it's resolved
Author: login: tuankiet65
Created: 2025-05-08T06:31:15Z | Merged: 2025-05-14T20:30:47Z

#### 8c48c1a274e9c031298fce6c195974f85c056c9d
<pre>
[css-anchor-position-1] Style resolution should visit children of anchor-positioned elements after it&apos;s resolved
<a href="https://rdar.apple.com/148608785">rdar://148608785</a>
<a href="https://bugs.webkit.org/show_bug.cgi?id=291065">https://bugs.webkit.org/show_bug.cgi?id=291065</a>

Reviewed by Antti Koivisto.

There&apos;s an optimization in Style::TreeResolver::resolveComposedTree that
defers visiting children of a query container or anchor-positioned element
until it can be resolved (e.g an anchor-positioned element waiting for its
anchor dependencies to be laid out):
* On initial style resolution, save the element change and which descendants
  to resolve (the &quot;state&quot;), and skip visiting the children
* On subsequent style resolutions, restore the state and continue as usual.
  The code gets &quot;tricked&quot; into resuming visiting into its children, where
  the previous resolution left off.

This is implemented for query containers, but not for anchor-positioned
elements. This leads to a subtle bug: if an anchor-positioned element is
initially hidden (`display: none`, `visibility: hidden` or hidden popover),
and then shown (`display` other than none, `visibility: visible`, or shown
popover), style resolution will **not** visit its children:
* On initial style resolution after the visibility change, the code indicates all
  descendents must be visited. Since the parent can&apos;t be resolved until subsequent
  resolutions, we skip visiting the children but **doesn&apos;t** save the state.
* On subsequent style resolutions, the parent can be resolved, so we can resume
  visiting the children. But we don&apos;t restore the state to &quot;trick&quot; the code into
  thinking it has to do so, so it skips visiting the children.

The results is the style resolution/layout/render code never sees the children,
and therefore won&apos;t layout/render them.

The solution is to implement the state save and restore for anchor-positioned
elements. However, this logic is currently tightly coupled with query
containers, so make it generic so it can be use for both purposes.

* LayoutTests/TestExpectations:
* LayoutTests/imported/w3c/web-platform-tests/css/css-anchor-position/anchor-center-visibility-change-expected.html:
* LayoutTests/imported/w3c/web-platform-tests/css/css-anchor-position/anchor-center-visibility-change-ref.html:
* LayoutTests/imported/w3c/web-platform-tests/css/css-anchor-position/anchor-center-visibility-change.html:
    - Add cases where the anchor-center element is hidden using
      `visibility: hidden` or popover, then shown.

* LayoutTests/imported/w3c/web-platform-tests/css/css-anchor-position/position-area-visibility-change-expected.html: Added.
* LayoutTests/imported/w3c/web-platform-tests/css/css-anchor-position/position-area-visibility-change.html: Added.
    - Add test that checks that an initially hidden anchor-positioned element
      using `position-area` properly renders when shown.

* LayoutTests/imported/w3c/web-platform-tests/css/css-anchor-position/reference/position-area-visibility-change-ref.html: Added.
* Source/WebCore/style/StyleTreeResolver.cpp:
(WebCore::Style::TreeResolver::resolveComposedTree):
    - Before checking whether to visit children or not, call
      resumeDescendantResolutionIfNeeded.
    - If deferring descendant resolution because of query containers or
      anchor-positioned elements, call deferDescendantResolution.

(WebCore::Style::TreeResolver::deferDescendantResolution):
    - New function that saves the state necessary to defer descendant resolution.

(WebCore::Style::TreeResolver::resumeDescendantResolutionIfNeeded):
    - New function that restores the state necessary to resume descendant resolution.

(WebCore::Style::TreeResolver::updateStateForQueryContainer):
    - Move the state saving and restore logic into separate methods
      (deferDescendantResolution, resumeDescendantResolutionIfNeeded)

(WebCore::Style::TreeResolver::resolve):
* Source/WebCore/style/StyleTreeResolver.h:
    - Move states relevant to descendant resolution deferral in QueryContainerState
      into DeferredDescendantResolutionState.

Canonical link: <a href="https://commits.webkit.org/294924@main">https://commits.webkit.org/294924@main</a>
</pre>
<!--EWS-Status-Bubble-Start-->
https://github.com/WebKit/WebKit/commit/c9b20fcc5040f43fe12707918e5510a96ca98117

| Misc | iOS, visionOS, tvOS & watchOS  | macOS  | Linux |  Windows |
| ----- | ---------------------- | ------- |  ----- |  --------- |
| [✅ 🧪 style](https://ews-build.webkit.org/#/builders/38/builds/103348 "Passed style check") | [✅ 🛠 ios](https://ews-build.webkit.org/#/builders/131/builds/23024 "Built successfully") | [✅ 🛠 mac](https://ews-build.webkit.org/#/builders/138/builds/13345 "Built successfully") | [✅ 🛠 wpe](https://ews-build.webkit.org/#/builders/5/builds/108521 "Built successfully") | [✅ 🛠 win](https://ews-build.webkit.org/#/builders/59/builds/53991 "Built successfully") 
| [✅ 🧪 bindings](https://ews-build.webkit.org/#/builders/9/builds/105387 "Passed tests") | [✅ 🛠 ios-sim](https://ews-build.webkit.org/#/builders/130/builds/23364 "Built successfully") | [✅ 🛠 mac-AS-debug](https://ews-build.webkit.org/#/builders/123/builds/31575 "Built successfully") | [✅ 🧪 wpe-wk2](https://ews-build.webkit.org/#/builders/34/builds/78540 "Passed tests") | [✅ 🧪 win-tests](https://ews-build.webkit.org/#/builders/60/builds/35490 "Passed tests") 
| [✅ 🧪 webkitperl](https://ews-build.webkit.org/#/builders/11/builds/106354 "Passed tests") | [✅ 🧪 ios-wk2](https://ews-build.webkit.org/#/builders/132/builds/18114 "Passed tests") | [✅ 🧪 api-mac](https://ews-build.webkit.org/#/builders/18/builds/93233 "Passed tests") | [✅ 🧪 api-wpe](https://ews-build.webkit.org/#/builders/41/builds/58873 "Passed tests") | 
| | [✅ 🧪 ios-wk2-wpt](https://ews-build.webkit.org/#/builders/133/builds/18001 "Passed tests") | [✅ 🧪 mac-wk1](https://ews-build.webkit.org/#/builders/135/builds/11274 "Passed tests") | [✅ 🛠 wpe-cairo](https://ews-build.webkit.org/#/builders/65/builds/53348 "Built successfully") | 
| | [✅ 🧪 api-ios](https://ews-build.webkit.org/#/builders/13/builds/87752 "Passed tests") | [✅ 🧪 mac-wk2](https://ews-build.webkit.org/#/builders/136/builds/11336 "Passed tests") | [✅ 🛠 gtk](https://ews-build.webkit.org/#/builders/2/builds/110898 "Built successfully") | 
| | [✅ 🛠 vision](https://ews-build.webkit.org/#/builders/128/builds/30486 "Built successfully") | [✅ 🧪 mac-AS-debug-wk2](https://ews-build.webkit.org/#/builders/122/builds/22509 "Passed tests") | [✅ 🧪 gtk-wk2](https://ews-build.webkit.org/#/builders/1/builds/87537 "Passed tests") | 
| | [✅ 🛠 vision-sim](https://ews-build.webkit.org/#/builders/121/builds/30851 "Built successfully") | [✅ 🧪 mac-wk2-stress](https://ews-build.webkit.org/#/builders/8/builds/89430 "Passed tests") | [✅ 🧪 api-gtk](https://ews-build.webkit.org/#/builders/21/builds/87174 "Passed tests") | 
| [✅ 🛠 🧪 merge](https://ews-build.webkit.org/#/builders/19/builds/22224 "Built successfully and passed tests") | [✅ 🧪 vision-wk2](https://ews-build.webkit.org/#/builders/126/builds/32037 "Passed tests") | [✅ 🧪 mac-intel-wk2](https://ews-build.webkit.org/#/builders/137/builds/9757 "Passed tests") | [✅ 🛠 playstation](https://ews-build.webkit.org/#/builders/134/builds/24820 "Built successfully") | 
| | [✅ 🛠 tv](https://ews-build.webkit.org/#/builders/127/builds/30415 "Built successfully") | [✅ 🛠 mac-safer-cpp](https://ews-build.webkit.org/#/builders/120/builds/35780 "Built successfully") | | 
| | [✅ 🛠 tv-sim](https://ews-build.webkit.org/#/builders/125/builds/30223 "Built successfully") | | | 
| | [✅ 🛠 watch](https://ews-build.webkit.org/#/builders/129/builds/33548 "Built successfully") | | | 
| | [✅ 🛠 watch-sim](https://ews-build.webkit.org/#/builders/124/builds/31784 "Built successfully") | | | 
<!--EWS-Status-Bubble-End-->


Diff:
diff --git a/LayoutTests/TestExpectations b/LayoutTests/TestExpectations
index 948a9a2ccb17..de70eb64b3bc 100644
--- a/LayoutTests/TestExpectations
+++ b/LayoutTests/TestExpectations
@@ -7672,7 +7672,6 @@ webkit.org/b/282024 fast/text/text-box-edge-with-margin-padding-border-simple.ht
 # -- Anchor Positioning -- #
 
 # general failures
-webkit.org/b/291260 imported/w3c/web-platform-tests/css/css-anchor-position/anchor-center-visibility-change.html [ ImageOnlyFailure ]
 webkit.org/b/289743 imported/w3c/web-platform-tests/css/css-anchor-position/anchor-position-multicol-007.html [ ImageOnlyFailure ]
 webkit.org/b/289743 imported/w3c/web-platform-tests/css/css-anchor-position/anchor-position-multicol-008.html [ ImageOnlyFailure ]
 imported/w3c/web-platform-tests/css/css-anchor-position/anchor-position-top-layer-001.html [ ImageOnlyFailure ]
diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-anchor-position/anchor-center-visibility-change-expected.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-anchor-position/anchor-center-visibility-change-expected.html
index 66bf9083c3a2..bc9872a90936 100644
--- a/LayoutTests/imported/w3c/web-platform-tests/css/css-anchor-position/anchor-center-visibility-change-expected.html
+++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-anchor-position/anchor-center-visibility-change-expected.html
@@ -17,16 +17,43 @@
   background: lime;
 }
 
+.target-inner {
+  width: 30px;
+  height: 20px;
+}
+
 .target {
-  position: fixed;
+  position: absolute;
+}
+
+#target-1 {
   background: cyan;
-  left: 111px;
+  left: 50px;
+}
+
+#target-2 {
+  top: 20px;
+  left: 0;
+  background: blue;
 }
+
+#target-3 {
+  top: 20px;
+  left: 50px;
+  background: magenta;
+}
+
 </style>
 
 <div class="container">
   <div class="anchor"></div>
-  <div class="target">
-    <div style="width:30px;height:20px;"></div>
+  <div id="target-1" class="target">
+    <div class="target-inner"></div>
+  </div>
+  <div id="target-2" class="target">
+    <div class="target-inner"></div>
+  </div>
+  <div id="target-3" class="target">
+    <div class="target-inner"></div>
   </div>
 </div>
diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-anchor-position/anchor-center-visibility-change-ref.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-anchor-position/anchor-center-visibility-change-ref.html
index 66bf9083c3a2..bc9872a90936 100644
--- a/LayoutTests/imported/w3c/web-platform-tests/css/css-anchor-position/anchor-center-visibility-change-ref.html
+++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-anchor-position/anchor-center-visibility-change-ref.html
@@ -17,16 +17,43 @@
   background: lime;
 }
 
+.target-inner {
+  width: 30px;
+  height: 20px;
+}
+
 .target {
-  position: fixed;
+  position: absolute;
+}
+
+#target-1 {
   background: cyan;
-  left: 111px;
+  left: 50px;
+}
+
+#target-2 {
+  top: 20px;
+  left: 0;
+  background: blue;
 }
+
+#target-3 {
+  top: 20px;
+  left: 50px;
+  background: magenta;
+}
+
 </style>
 
 <div class="container">
   <div class="anchor"></div>
-  <div class="target">
-    <div style="width:30px;height:20px;"></div>
+  <div id="target-1" class="target">
+    <div class="target-inner"></div>
+  </div>
+  <div id="target-2" class="target">
+    <div class="target-inner"></div>
+  </div>
+  <div id="target-3" class="target">
+    <div class="target-inner"></div>
   </div>
 </div>
diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-anchor-position/anchor-center-visibility-change.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-anchor-position/anchor-center-visibility-change.html
index 0f7d805844f0..e55594332067 100644
--- a/LayoutTests/imported/w3c/web-platform-tests/css/css-anchor-position/anchor-center-visibility-change.html
+++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-anchor-position/anchor-center-visibility-change.html
@@ -1,8 +1,9 @@
 <!DOCTYPE html>
 <html class=reftest-wait>
-<title>Tests 'anchor-center' value when target visibility changes</title>
+<title>Tests 'anchor-center' value when target visibility changes (by changing 'display', 'visibility', or popover trigger)</title>
 <link rel="help" href="https://drafts.csswg.org/css-anchor-position-1/#valdef-justify-self-anchor-center">
 <link rel="author" href="mailto:plampe@igalia.com">
+<link rel="author" href="mailto:kiet.ho@apple.com">
 <link rel="match" href="anchor-center-visibility-change-ref.html">
 <script src="/common/reftest-wait.js"></script>
 <script src="/common/rendering-utils.js"></script>
@@ -27,27 +28,61 @@
 
 .target {
   position-anchor: --anchor;
-  position: fixed;
-  background: cyan;
+  position: absolute;
+}
+
+.target-inner {
+  width: 30px;
+  height: 20px;
+}
+
+#target-1 {
   justify-self: anchor-center;
+  background: cyan;
   display: none;
 }
+
+#target-2 {
+  align-self: anchor-center;
+  background: blue;
+  visibility: hidden;
+}
+
+#target-3 {
+  align-self: anchor-center;
+  justify-self: anchor-center;
+  background: magenta;
+
+  /* Override default popover style */
+  margin: 0;
+  padding: 0;
+  border: none;
+}
 </style>
 
 <div class="container">
   <div class="anchor"></div>
-  <div id="target" class="target">
-    <div style="width:30px;height:20px;"></div>
+  <div id="target-1" class="target">
+    <div class="target-inner"></div>
+  </div>
+  <div id="target-2" class="target">
+    <div class="target-inner"></div>
+  </div>
+  <div id="target-3" class="target" popover>
+    <div class="target-inner"></div>
   </div>
 </div>
 
 <script>
-  // #target should be invisible initially.
+  // Targets should be invisible initially.
   waitForAtLeastOneFrame().then(() => {
-    // Change #target to be visible.
-    document.getElementById('target').style.display = 'flow';
+    // Change targets to be visible.
+    document.getElementById('target-1').style.display = 'flow';
+    document.getElementById('target-2').style.visibility = 'visible';
+    document.getElementById('target-3').showPopover();
+
     waitForAtLeastOneFrame().then(() => {
-      // #target should be visible and anchor-centered now.
+      // Targets should be visible now.
       takeScreenshot();
     });
   });
diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-anchor-position/position-area-visibility-change-expected.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-anchor-position/position-area-visibility-change-expected.html
new file mode 100644
index 000000000000..87e180494090
--- /dev/null
+++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-anchor-position/position-area-visibility-change-expected.html
@@ -0,0 +1,72 @@
+<!DOCTYPE html>
+
+<style>
+  .containing-block {
+    position: relative;
+    width: 150px;
+    height: 150px;
+    outline: 2px black solid;
+  }
+
+  .cell {
+    width: 50px;
+    height: 50px;
+  }
+
+  #anchor-cell {
+    position: absolute;
+    top: 50px;
+    left: 50px;
+
+    background: green;
+  }
+
+  .anchor-positioned-cell {
+    position: absolute;
+  }
+
+  #target-1 {
+    top: 0;
+    right: 0;
+  }
+
+  #target-2 {
+    bottom: 0;
+    left: 0;
+  }
+
+  #target-3 {
+    bottom: 0;
+    right: 0;
+  }
+
+  .blue-background {
+    background: blue;
+  }
+
+  .magenta-background {
+    background: magenta;
+  }
+
+  .cyan-background {
+    background: cyan;
+  }
+</style>
+
+<body>
+  <div class="containing-block">
+    <div class="cell" id="anchor-cell"></div>
+
+    <div class="cell anchor-positioned-cell" id="target-1">
+      <div class="cell blue-background"></div>
+    </div>
+
+    <div class="cell anchor-positioned-cell" id="target-2">
+      <div class="cell magenta-background"></div>
+    </div>
+
+    <div class="cell anchor-positioned-cell" id="target-3">
+      <div class="cell cyan-background"></div>
+    </div>
+  </div>
+</body>
\ No newline at end of file
diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-anchor-position/position-area-visibility-change.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-anchor-position/position-area-visibility-change.html
new file mode 100644
index 000000000000..61d8ab50284a
--- /dev/null
+++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-anchor-position/position-area-visibility-change.html
@@ -0,0 +1,113 @@
+<!DOCTYPE html>
+
+<html class="reftest-wait">
+
+<head>
+  <title>Tests that an element positioned using position-area renders when it's initially hidden, then shown</title>
+
+  <link rel="help" href="https://drafts.csswg.org/css-anchor-position-1/#position-area">
+  <link rel="author" href="mailto:kiet.ho@apple.com">
+  <link rel="match" href="reference/position-area-visibility-change-ref.html">
+
+  <script src="/common/reftest-wait.js"></script>
+  <script src="/common/rendering-utils.js"></script>
+
+  <style>
+    .containing-block {
+      position: relative;
+      width: 150px;
+      height: 150px;
+      outline: 2px black solid;
+    }
+
+    .cell {
+      width: 50px;
+      height: 50px;
+    }
+
+    #anchor-cell {
+      position: absolute;
+      top: 50px;
+      left: 50px;
+
+      anchor-name: --anchor;
+
+      background: green;
+    }
+
+    .anchor-positioned-cell {
+      position: absolute;
+      position-anchor: --anchor;
+    }
+
+    #target-1 {
+      position-area: top right;
+
+      /* Will be changed to 'block' */
+      display: none;
+    }
+
+    #target-2 {
+      position-area: bottom left;
+
+      /* Will be changed to 'visible' */
+      visibility: hidden;
+    }
+
+    #target-3 {
+      position-area: bottom right;
+
+      /* Override default popover style */
+      margin: 0;
+      padding: 0;
+      border: none;
+    }
+
+    .blue-background {
+      background: blue;
+    }
+
+    .magenta-background {
+      background: magenta;
+    }
+
+    .cyan-background {
+      background: cyan;
+    }
+  </style>
+</head>
+
+<body>
+  <div class="containing-block">
+    <div class="cell" id="anchor-cell"></div>
+
+    <div class="cell anchor-positioned-cell" id="target-1">
+      <div class="cell blue-background"></div>
+    </div>
+
+    <div class="cell anchor-positioned-cell" id="target-2">
+      <div class="cell magenta-background"></div>
+    </div>
+
+    <div class="cell anchor-positioned-cell" id="target-3" popover>
+      <div class="cell cyan-background"></div>
+    </div>
+  </div>
+
+  <script>
+    // All targets should initially be hidden.
+    waitForAtLeastOneFrame().then(() => {
+      // Change targets to be visible.
+      document.getElementById('target-1').style.display = 'block';
+      document.getElementById('target-2').style.visibility = 'visible';
+      document.getElementById('target-3').showPopover();
+
+      waitForAtLeastOneFrame().then(() => {
+        // All targets should be visible now.
+        takeScreenshot();
+      });
+    });
+  </script>
+</body>
+
+</html>
\ No newline at end of file
diff --git a/LayoutTests/imported/w3c/web-platform-tests/css/css-anchor-position/reference/position-area-visibility-change-ref.html b/LayoutTests/imported/w3c/web-platform-tests/css/css-anchor-position/reference/position-area-visibility-change-ref.html
new file mode 100644
index 000000000000..87e180494090
--- /dev/null
+++ b/LayoutTests/imported/w3c/web-platform-tests/css/css-anchor-position/reference/position-area-visibility-change-ref.html
@@ -0,0 +1,72 @@
+<!DOCTYPE html>
+
+<style>
+  .containing-block {
+    position: relative;
+    width: 150px;
+    height: 150px;
+    outline: 2px black solid;
+  }
+
+  .cell {
+    width: 50px;
+    height: 50px;
+  }
+
+  #anchor-cell {
+    position: absolute;
+    top: 50px;
+    left: 50px;
+
+    background: green;
+  }
+
+  .anchor-positioned-cell {
+    position: absolute;
+  }
+
+  #target-1 {
+    top: 0;
+    right: 0;
+  }
+
+  #target-2 {
+    bottom: 0;
+    left: 0;
+  }
+
+  #target-3 {
+    bottom: 0;
+    right: 0;
+  }
+
+  .blue-background {
+    background: blue;
+  }
+
+  .magenta-background {
+    background: magenta;
+  }
+
+  .cyan-background {
+    background: cyan;
+  }
+</style>
+
+<body>
+  <div class="containing-block">
+    <div class="cell" id="anchor-cell"></div>
+
+    <div class="cell anchor-positioned-cell" id="target-1">
+      <div class="cell blue-background"></div>
+    </div>
+
+    <div class="cell anchor-positioned-cell" id="target-2">
+      <div class="cell magenta-background"></div>
+    </div>
+
+    <div class="cell anchor-positioned-cell" id="target-3">
+      <div class="cell cyan-background"></div>
+    </div>
+  </div>
+</body>
\ No newline at end of file
diff --git a/Source/WebCore/style/StyleTreeResolver.cpp b/Source/WebCore/style/StyleTreeResolver.cpp
index cabe30889d40..ce3b1320b448 100644
--- a/Source/WebCore/style/StyleTreeResolver.cpp
+++ b/Source/WebCore/style/StyleTreeResolver.cpp
@@ -1197,23 +1197,25 @@ void TreeResolver::resolveComposedTree()
         if (!style)
             resetStyleForNonRenderedDescendants(element);
 
-        auto queryContainerAction = updateStateForQueryContainer(element, style, changes, descendantsToResolve);
+        auto queryContainerAction = updateStateForQueryContainer(element, style, descendantsToResolve);
         auto anchorPositionedElementAction = updateAnchorPositioningState(element, style, changes);
 
+        resumeDescendantResolutionIfNeeded(element, changes, descendantsToResolve);
+
         bool shouldIterateChildren = [&] {
             // display::none, no need to resolve descendants.
             if (!style)
                 return false;
-            // Style resolution will be resumed after the container has been resolved.
-            if (queryContainerAction == LayoutInterleavingAction::SkipDescendants)
-                return false;
-            // Style resolution will be resumed after the anchor-positioned element has been resolved.
-            if (anchorPositionedElementAction == LayoutInterleavingAction::SkipDescendants)
+
+            // Style resolution will be resumed after the container or anchor-positioned element has been resolved.
+            if (queryContainerAction == LayoutInterleavingAction::SkipDescendants || anchorPositionedElementAction == LayoutInterleavingAction::SkipDescendants) {
+                deferDescendantResolution(element, changes, descendantsToResolve);
                 return false;
+            }
+
             return element.childNeedsStyleRecalc() || descendantsToResolve != DescendantsToResolve::None;
         }();
 
-
         if (!m_didSeePendingStylesheet)
             m_didSeePendingStylesheet = hasLoadingStylesheet(m_document->styleScope(), element, !shouldIterateChildren);
 
@@ -1253,30 +1255,45 @@ const RenderStyle* TreeResolver::existingStyle(const Element& element)
     return style;
 }
 
-auto TreeResolver::updateStateForQueryContainer(Element& element, const RenderStyle* style, OptionSet<Change>& changes, DescendantsToResolve& descendantsToResolve) -> LayoutInterleavingAction
+void TreeResolver::deferDescendantResolution(Element& element, OptionSet<Change> changes, DescendantsToResolve descendantsToResolve)
+{
+    m_deferredDescendantResolutionStates.add(element, DeferredDescendantResolutionState {
+        .changes = changes,
+        .descendantsToResolve = descendantsToResolve
+    });
+}
+
+void TreeResolver::resumeDescendantResolutionIfNeeded(Element& element, OptionSet<Change>& changes, DescendantsToResolve& descendantsToResolve)
+{
+    auto it = m_deferredDescendantResolutionStates.find(element);
+    if (it == m_deferredDescendantResolutionStates.end())
+        return;
+
+    const auto& state = it->value;
+
+    changes |= state.changes;
+    descendantsToResolve = std::max(descendantsToResolve, state.descendantsToResolve);
+
+    m_deferredDescendantResolutionStates.remove(it);
+}
+
+auto TreeResolver::updateStateForQueryContainer(Element& element, const RenderStyle* style, DescendantsToResolve& descendantsToResolve) -> LayoutInterleavingAction
 {
     if (!style)
         return LayoutInterleavingAction::None;
 
-    auto tryRestoreState = [&](auto& state) {
-        if (!state)
-            return;
-        changes |= state->changes;
-        descendantsToResolve = std::max(descendantsToResolve, state->descendantsToResolve);
-        state = { };
-    };
-
-    if (auto it = m_queryContainerStates.find(element); it != m_queryContainerStates.end()) {
-        tryRestoreState(it->value);
+    if (m_queryContainerStates.contains(element))
         return LayoutInterleavingAction::None;
-    }
 
     auto* existingStyle = element.renderOrDisplayContentsStyle();
     if (style->containerType() != ContainerType::Normal || (existingStyle && existingStyle->containerType() != ContainerType::Normal)) {
-        // If any of the queries use font-size relative units then a font size change may affect their evaluation.
+        // If any of the queries use font-size relative units then a font size change
+        // may affect their evaluation, so force re-evaluating all descendants.
         if (styleChangeAffectsRelativeUnits(*style, existingStyle))
             descendantsToResolve = DescendantsToResolve::All;
-        m_queryContainerStates.add(element, QueryContainerState { changes, descendantsToResolve });
+
+        m_queryContainerStates.add(element, QueryContainerState { });
+
         return LayoutInterleavingAction::SkipDescendants;
     }
 
@@ -1313,11 +1330,12 @@ std::unique_ptr<Update> TreeResolver::resolve()
     m_parentStack.clear();
     popScope();
 
-    for (auto& containerAndState : m_queryContainerStates) {
+    for (auto& [element, state] : m_queryContainerStates) {
         // Ensure that resumed resolution reaches the container.
-        if (containerAndState.value && !containerAndState.value->invalidated) {
-            containerAndState.key->invalidateForResumingQueryContainerResolution();
-            containerAndState.value->invalidated = true;
+        if (!state.invalidated) {
+            element->invalidateForResumingQueryContainerResolution();
+            state.invalidated = true;
+
             m_needsInterleavedLayout = true;
         }
     }
diff --git a/Source/WebCore/style/StyleTreeResolver.h b/Source/WebCore/style/StyleTreeResolver.h
index 19de13f251bc..7a1f4de84473 100644
--- a/Source/WebCore/style/StyleTreeResolver.h
+++ b/Source/WebCore/style/StyleTreeResolver.h
@@ -77,7 +77,17 @@ class TreeResolver {
     enum class LayoutInterleavingAction : uint8_t { None, SkipDescendants };
     enum class DescendantsToResolve : uint8_t { None, RebuildAllUsingExisting, ChildrenWithExplicitInherit, Children, All };
 
-    LayoutInterleavingAction updateStateForQueryContainer(Element&, const RenderStyle*, OptionSet<Change>&, DescendantsToResolve&);
+    LayoutInterleavingAction updateStateForQueryContainer(Element&, const RenderStyle*, DescendantsToResolve&);
+
+    // For elements requiring style/layout interleaving (anchor-positioned and query
+    // containers), descendant resolution is deferred on the first style resolution
+    // pass and resumed in subsequent passes.
+    // When deferral is needed, deferDescendantResolution saves the internal state
+    // relevant to which descendants should be resolved.
+    void deferDescendantResolution(Element&, OptionSet<Change>, DescendantsToResolve);
+    // When descendant resolution can be resumed, resumeDescendantResolutionIfNeeded
+    // restores the previously saved state (if there is)
+    void resumeDescendantResolutionIfNeeded(Element&, OptionSet<Change>&, DescendantsToResolve&);
 
     std::pair<ElementUpdate, DescendantsToResolve> resolveElement(Element&, const RenderStyle* existingStyle, ResolutionType);
 
@@ -170,12 +180,6 @@ class TreeResolver {
 
     bool hasUnresolvedAnchorPosition(const Element&) const;
 
-    struct QueryContainerState {
-        OptionSet<Change> changes;
-        DescendantsToResolve descendantsToResolve { DescendantsToResolve::None };
-        bool invalidated { false };
-    };
-
     CheckedRef<Document> m_document;
     std::unique_ptr<RenderStyle> m_documentElementStyle;
 
@@ -183,9 +187,20 @@ class TreeResolver {
     Vector<Parent, 32> m_parentStack;
     bool m_didSeePendingStylesheet { false };
 
-    UncheckedKeyHashMap<Ref<Element>, std::optional<QueryContainerState>> m_queryContainerStates;
+    // States relevant to deferring and resuming descendant resolution.
+    // Also see deferDescendantResolution and resumeDescendantResolutionIfNeeded.
+    struct DeferredDescendantResolutionState {
+        OptionSet<Change> changes;
+        DescendantsToResolve descendantsToResolve { DescendantsToResolve::None };
+    };
+    UncheckedKeyHashMap<Ref<Element>, DeferredDescendantResolutionState> m_deferredDescendantResolutionStates;
     bool m_needsInterleavedLayout { false };
 
+    struct QueryContainerState {
+        bool invalidated { false };
+    };
+    UncheckedKeyHashMap<Ref<Element>, QueryContainerState> m_queryContainerStates;
+
     // This state gets passes to the style builder and holds state for a single tree resolution, including over any interleaving.
     TreeResolutionState m_treeResolutionState;
     HashMap<Ref<const Element>, std::unique_ptr<RenderStyle>> m_savedBeforeResolutionStylesForInterleaving;


Reviews:
user: login: Scony
body: LGTM.

I very much like the changes in WPT tests as those cover more corner-cases. It would be nice to export those changes to WPT in the future.
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-09T08:46:38Z
user: login: anttijk
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-05-09T12:20:09Z
user: login: anttijk
body: Looks good
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-05-09T12:20:39Z
user: login: tuankiet65
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-05-13T19:48:45Z
user: login: tuankiet65
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-05-13T19:49:42Z
user: login: tuankiet65
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-05-13T19:49:49Z

Review comments:
diff_hunk: @@ -1233,30 +1236,45 @@ const RenderStyle* TreeResolver::existingStyle(const Element& element)
     return style;
 }
 
-auto TreeResolver::updateStateForQueryContainer(Element& element, const RenderStyle* style, OptionSet<Change>& changes, DescendantsToResolve& descendantsToResolve) -> LayoutInterleavingAction
+void TreeResolver::saveDescendantResolutionState(Element& element, OptionSet<Change> changes, DescendantsToResolve descendantsToResolve)
+{
+    m_styleLayoutInterleavedElementStates.add(element, StyleLayoutInterleavedElementState {
+        .changes = changes,
+        .descendantsToResolve = descendantsToResolve
+    });
+}
+
+void TreeResolver::restoreDescendantResolutionStateIfNeeded(Element& element, OptionSet<Change>& changes, DescendantsToResolve& descendantsToResolve)
+{
+    auto it = m_styleLayoutInterleavedElementStates.find(element);
+    if (it == m_styleLayoutInterleavedElementStates.end())
+        return;
+
+    auto& state = it->value;
path: Source/WebCore/style/StyleTreeResolver.cpp
user: login: Scony
body: perhaps could be `const`
created_at: 2025-05-09T08:40:18Z
author_association: CONTRIBUTOR
diff_hunk: @@ -160,22 +163,31 @@ class TreeResolver {
 
     bool hasUnresolvedAnchorPosition(const Element&) const;
 
-    struct QueryContainerState {
-        OptionSet<Change> changes;
-        DescendantsToResolve descendantsToResolve { DescendantsToResolve::None };
-        bool invalidated { false };
-    };
-
     CheckedRef<Document> m_document;
     std::unique_ptr<RenderStyle> m_documentElementStyle;
 
     Vector<Ref<Scope>, 4> m_scopeStack;
     Vector<Parent, 32> m_parentStack;
     bool m_didSeePendingStylesheet { false };
 
-    UncheckedKeyHashMap<Ref<Element>, std::optional<QueryContainerState>> m_queryContainerStates;
+    // For elements that require style/layout interleaving (anchor positioning and
+    // container queries), the first style pass will defer resolving descendants.
+    // This is resumed in subsequent style passes, when there are enough information
+    // to do so. This struct preserves internal resolution state when descendant
+    // resolution is deferred, so it could be restores when descendant resolution
path: Source/WebCore/style/StyleTreeResolver.h
user: login: Scony
body: ```suggestion
    // resolution is deferred, so it could be restored when descendant resolution
```
created_at: 2025-05-09T08:43:54Z
author_association: CONTRIBUTOR
diff_hunk: @@ -160,22 +163,31 @@ class TreeResolver {
 
     bool hasUnresolvedAnchorPosition(const Element&) const;
 
-    struct QueryContainerState {
-        OptionSet<Change> changes;
-        DescendantsToResolve descendantsToResolve { DescendantsToResolve::None };
-        bool invalidated { false };
-    };
-
     CheckedRef<Document> m_document;
     std::unique_ptr<RenderStyle> m_documentElementStyle;
 
     Vector<Ref<Scope>, 4> m_scopeStack;
     Vector<Parent, 32> m_parentStack;
     bool m_didSeePendingStylesheet { false };
 
-    UncheckedKeyHashMap<Ref<Element>, std::optional<QueryContainerState>> m_queryContainerStates;
+    // For elements that require style/layout interleaving (anchor positioning and
+    // container queries), the first style pass will defer resolving descendants.
+    // This is resumed in subsequent style passes, when there are enough information
+    // to do so. This struct preserves internal resolution state when descendant
+    // resolution is deferred, so it could be restores when descendant resolution
+    // resumes.
+    struct StyleLayoutInterleavedElementState {
+        OptionSet<Change> changes;
+        DescendantsToResolve descendantsToResolve { DescendantsToResolve::None };
+    };
+    UncheckedKeyHashMap<Ref<Element>, StyleLayoutInterleavedElementState> m_styleLayoutInterleavedElementStates;
     bool m_needsInterleavedLayout { false };
 
+    struct QueryContainerState {
+        bool invalidated { false };
+    };
+    UncheckedKeyHashMap<Ref<Element>, QueryContainerState> m_queryContainerStates;
path: Source/WebCore/style/StyleTreeResolver.h
user: login: anttijk
body: Maybe there is a way to merge this state too with the interleaved state in future.
created_at: 2025-05-09T12:18:19Z
author_association: CONTRIBUTOR
diff_hunk: @@ -160,22 +163,31 @@ class TreeResolver {
 
     bool hasUnresolvedAnchorPosition(const Element&) const;
 
-    struct QueryContainerState {
-        OptionSet<Change> changes;
-        DescendantsToResolve descendantsToResolve { DescendantsToResolve::None };
-        bool invalidated { false };
-    };
-
     CheckedRef<Document> m_document;
     std::unique_ptr<RenderStyle> m_documentElementStyle;
 
     Vector<Ref<Scope>, 4> m_scopeStack;
     Vector<Parent, 32> m_parentStack;
     bool m_didSeePendingStylesheet { false };
 
-    UncheckedKeyHashMap<Ref<Element>, std::optional<QueryContainerState>> m_queryContainerStates;
+    // For elements that require style/layout interleaving (anchor positioning and
+    // container queries), the first style pass will defer resolving descendants.
+    // This is resumed in subsequent style passes, when there are enough information
+    // to do so. This struct preserves internal resolution state when descendant
+    // resolution is deferred, so it could be restores when descendant resolution
+    // resumes.
+    struct StyleLayoutInterleavedElementState {
path: Source/WebCore/style/StyleTreeResolver.h
user: login: anttijk
body: I would leave out the word Style here as we are in Style namespace.
created_at: 2025-05-09T12:19:08Z
author_association: CONTRIBUTOR
diff_hunk: @@ -1233,30 +1236,45 @@ const RenderStyle* TreeResolver::existingStyle(const Element& element)
     return style;
 }
 
-auto TreeResolver::updateStateForQueryContainer(Element& element, const RenderStyle* style, OptionSet<Change>& changes, DescendantsToResolve& descendantsToResolve) -> LayoutInterleavingAction
+void TreeResolver::saveDescendantResolutionState(Element& element, OptionSet<Change> changes, DescendantsToResolve descendantsToResolve)
+{
+    m_styleLayoutInterleavedElementStates.add(element, StyleLayoutInterleavedElementState {
+        .changes = changes,
+        .descendantsToResolve = descendantsToResolve
+    });
+}
+
+void TreeResolver::restoreDescendantResolutionStateIfNeeded(Element& element, OptionSet<Change>& changes, DescendantsToResolve& descendantsToResolve)
+{
+    auto it = m_styleLayoutInterleavedElementStates.find(element);
+    if (it == m_styleLayoutInterleavedElementStates.end())
+        return;
+
+    auto& state = it->value;
path: Source/WebCore/style/StyleTreeResolver.cpp
user: login: tuankiet65
body: Fixed.
created_at: 2025-05-13T19:48:45Z
author_association: MEMBER
diff_hunk: @@ -160,22 +163,31 @@ class TreeResolver {
 
     bool hasUnresolvedAnchorPosition(const Element&) const;
 
-    struct QueryContainerState {
-        OptionSet<Change> changes;
-        DescendantsToResolve descendantsToResolve { DescendantsToResolve::None };
-        bool invalidated { false };
-    };
-
     CheckedRef<Document> m_document;
     std::unique_ptr<RenderStyle> m_documentElementStyle;
 
     Vector<Ref<Scope>, 4> m_scopeStack;
     Vector<Parent, 32> m_parentStack;
     bool m_didSeePendingStylesheet { false };
 
-    UncheckedKeyHashMap<Ref<Element>, std::optional<QueryContainerState>> m_queryContainerStates;
+    // For elements that require style/layout interleaving (anchor positioning and
+    // container queries), the first style pass will defer resolving descendants.
+    // This is resumed in subsequent style passes, when there are enough information
+    // to do so. This struct preserves internal resolution state when descendant
+    // resolution is deferred, so it could be restores when descendant resolution
+    // resumes.
+    struct StyleLayoutInterleavedElementState {
path: Source/WebCore/style/StyleTreeResolver.h
user: login: tuankiet65
body: I changed it to `DeferredDescendantResolutionState` which is a bit more relevant
created_at: 2025-05-13T19:49:42Z
author_association: MEMBER
diff_hunk: @@ -160,22 +163,31 @@ class TreeResolver {
 
     bool hasUnresolvedAnchorPosition(const Element&) const;
 
-    struct QueryContainerState {
-        OptionSet<Change> changes;
-        DescendantsToResolve descendantsToResolve { DescendantsToResolve::None };
-        bool invalidated { false };
-    };
-
     CheckedRef<Document> m_document;
     std::unique_ptr<RenderStyle> m_documentElementStyle;
 
     Vector<Ref<Scope>, 4> m_scopeStack;
     Vector<Parent, 32> m_parentStack;
     bool m_didSeePendingStylesheet { false };
 
-    UncheckedKeyHashMap<Ref<Element>, std::optional<QueryContainerState>> m_queryContainerStates;
+    // For elements that require style/layout interleaving (anchor positioning and
+    // container queries), the first style pass will defer resolving descendants.
+    // This is resumed in subsequent style passes, when there are enough information
+    // to do so. This struct preserves internal resolution state when descendant
+    // resolution is deferred, so it could be restores when descendant resolution
path: Source/WebCore/style/StyleTreeResolver.h
user: login: tuankiet65
body: Fixed.
created_at: 2025-05-13T19:49:49Z
author_association: MEMBER

PR comments:
user: login: webkit-early-warning-system
created_at: 2025-05-08T06:31:22Z
body: EWS run on previous version of this PR (hash https://github.com/WebKit/WebKit/commit/da66122a8762f95a29f88483105c4d985b0553b5)<details>

| Misc | iOS, visionOS, tvOS & watchOS  | macOS  | Linux |  Windows |
| ----- | ---------------------- | ------- |  ----- |  --------- |
| [✅ 🧪 style](https://ews-build.webkit.org/#/builders/38/builds/102600 "Passed style check") | [✅ 🛠 ios](https://ews-build.webkit.org/#/builders/131/builds/22269 "Built successfully") | [✅ 🛠 mac](https://ews-build.webkit.org/#/builders/138/builds/12583 "Built successfully") | [✅ 🛠 wpe](https://ews-build.webkit.org/#/builders/5/builds/107761 "Built successfully") | [✅ 🛠 win](https://ews-build.webkit.org/#/builders/59/builds/53237 "Built successfully") 
| [✅ 🧪 bindings](https://ews-build.webkit.org/#/builders/9/builds/104639 "Passed tests") | [✅ 🛠 ios-sim](https://ews-build.webkit.org/#/builders/130/builds/22577 "Built successfully") | [✅ 🛠 mac-AS-debug](https://ews-build.webkit.org/#/builders/123/builds/30775 "Built successfully") | [✅ 🧪 wpe-wk2](https://ews-build.webkit.org/#/builders/34/builds/78045 "Passed tests") | [✅ 🧪 win-tests](https://ews-build.webkit.org/#/builders/60/builds/35021 "Passed tests") 
| [✅ 🧪 webkitperl](https://ews-build.webkit.org/#/builders/11/builds/105606 "Passed tests") | [✅ 🧪 ios-wk2](https://ews-build.webkit.org/#/builders/132/builds/17493 "Passed tests") | [✅ 🧪 api-mac](https://ews-build.webkit.org/#/builders/18/builds/92599 "Passed tests") | [✅ 🧪 api-wpe](https://ews-build.webkit.org/#/builders/41/builds/58380 "Passed tests") | 
| | [✅ 🧪 ios-wk2-wpt](https://ews-build.webkit.org/#/builders/133/builds/17332 "Passed tests") | [✅ 🧪 mac-wk1](https://ews-build.webkit.org/#/builders/135/builds/10631 "Passed tests") | [✅ 🛠 wpe-cairo](https://ews-build.webkit.org/#/builders/65/builds/52594 "Built successfully") | 
| | [✅ 🧪 api-ios](https://ews-build.webkit.org/#/builders/13/builds/87143 "Passed tests") | [✅ 🧪 mac-wk2](https://ews-build.webkit.org/#/builders/136/builds/10699 "Passed tests") | [✅ 🛠 gtk](https://ews-build.webkit.org/#/builders/2/builds/110136 "Built successfully") | 
| | [✅ 🛠 vision](https://ews-build.webkit.org/#/builders/128/builds/29732 "Built successfully") | [✅ 🧪 mac-AS-debug-wk2](https://ews-build.webkit.org/#/builders/122/builds/21920 "Passed tests") | [✅ 🧪 gtk-wk2](https://ews-build.webkit.org/#/builders/1/builds/87022 "Passed tests") | 
| | [✅ 🛠 vision-sim](https://ews-build.webkit.org/#/builders/121/builds/30096 "Built successfully") | [✅ 🧪 mac-wk2-stress](https://ews-build.webkit.org/#/builders/8/builds/88796 "Passed tests") | [✅ 🧪 api-gtk](https://ews-build.webkit.org/#/builders/21/builds/86631 "Passed tests") | 
| | [✅ 🧪 vision-wk2](https://ews-build.webkit.org/#/builders/126/builds/31452 "Passed tests") | [✅ 🧪 mac-intel-wk2](https://ews-build.webkit.org/#/builders/137/builds/9181 "Passed tests") | [✅ 🛠 playstation](https://ews-build.webkit.org/#/builders/134/builds/23982 "Built successfully") | 
| | [✅ 🛠 tv](https://ews-build.webkit.org/#/builders/127/builds/29660 "Built successfully") | [✅ 🛠 mac-safer-cpp](https://ews-build.webkit.org/#/builders/120/builds/34972 "Built successfully") | | 
| | [✅ 🛠 tv-sim](https://ews-build.webkit.org/#/builders/125/builds/29471 "Built successfully") | | | 
| | [✅ 🛠 watch](https://ews-build.webkit.org/#/builders/129/builds/32794 "Built successfully") | | | 
| | [✅ 🛠 watch-sim](https://ews-build.webkit.org/#/builders/124/builds/31030 "Built successfully") | | | </details>
author_association: COLLABORATOR
user: login: webkit-early-warning-system
created_at: 2025-05-09T06:54:32Z
body: EWS run on previous version of this PR (hash https://github.com/WebKit/WebKit/commit/ed8955f0fc179be7e70fe0385fbf820e56398343)<details>

| Misc | iOS, visionOS, tvOS & watchOS  | macOS  | Linux |  Windows |
| ----- | ---------------------- | ------- |  ----- |  --------- |
| [✅ 🧪 style](https://ews-build.webkit.org/#/builders/38/builds/102783 "Passed style check") | [✅ 🛠 ios](https://ews-build.webkit.org/#/builders/131/builds/22456 "Built successfully") | [✅ 🛠 mac](https://ews-build.webkit.org/#/builders/138/builds/12776 "Built successfully") | [✅ 🛠 wpe](https://ews-build.webkit.org/#/builders/5/builds/107948 "Built successfully") | [✅ 🛠 win](https://ews-build.webkit.org/#/builders/59/builds/53424 "Built successfully") 
| [✅ 🧪 bindings](https://ews-build.webkit.org/#/builders/9/builds/104822 "Passed tests") | [✅ 🛠 ios-sim](https://ews-build.webkit.org/#/builders/130/builds/22774 "Built successfully") | [✅ 🛠 mac-AS-debug](https://ews-build.webkit.org/#/builders/123/builds/30958 "Built successfully") | [✅ 🧪 wpe-wk2](https://ews-build.webkit.org/#/builders/34/builds/78160 "Passed tests") | [✅ 🧪 win-tests](https://ews-build.webkit.org/#/builders/60/builds/35125 "Passed tests") 
| [✅ 🧪 webkitperl](https://ews-build.webkit.org/#/builders/11/builds/105789 "Passed tests") | [✅ 🧪 ios-wk2](https://ews-build.webkit.org/#/builders/132/builds/17637 "Passed tests") | [✅ 🧪 api-mac](https://ews-build.webkit.org/#/builders/18/builds/92758 "Passed tests") | [✅ 🧪 api-wpe](https://ews-build.webkit.org/#/builders/41/builds/58492 "Passed tests") | 
| | [✅ 🧪 ios-wk2-wpt](https://ews-build.webkit.org/#/builders/133/builds/17486 "Passed tests") | [❌ 🧪 mac-wk1](https://ews-build.webkit.org/#/builders/135/builds/10793 "Found 1 new test failure: imported/w3c/web-platform-tests/css/css-anchor-position/position-area-visibility-change.html (failure)") | [✅ 🛠 wpe-cairo](https://ews-build.webkit.org/#/builders/65/builds/52781 "Built successfully") | 
| | [✅ 🧪 api-ios](https://ews-build.webkit.org/#/builders/13/builds/87293 "Passed tests") | [❌ 🧪 mac-wk2](https://ews-build.webkit.org/#/builders/136/builds/10861 "Exiting early after 10 failures. 24 tests run. 1 flakes") | [✅ 🛠 gtk](https://ews-build.webkit.org/#/builders/2/builds/110324 "Built successfully") | 
| | [✅ 🛠 vision](https://ews-build.webkit.org/#/builders/128/builds/29920 "Built successfully") | [✅ 🧪 mac-AS-debug-wk2](https://ews-build.webkit.org/#/builders/122/builds/22046 "Passed tests") | [✅ 🧪 gtk-wk2](https://ews-build.webkit.org/#/builders/1/builds/87144 "Passed tests") | 
| | [✅ 🛠 vision-sim](https://ews-build.webkit.org/#/builders/121/builds/30284 "Built successfully") | [❌ 🧪 mac-wk2-stress](https://ews-build.webkit.org/#/builders/8/builds/88954 "Exiting early after 10 failures. 40 tests run. 1 flakes") | [✅ 🧪 api-gtk](https://ews-build.webkit.org/#/builders/21/builds/86760 "Passed tests") | 
| | [✅ 🧪 vision-wk2](https://ews-build.webkit.org/#/builders/126/builds/31593 "Passed tests") | [✅ 🧪 mac-intel-wk2](https://ews-build.webkit.org/#/builders/137/builds/9310 "Passed tests") | [✅ 🛠 playstation](https://ews-build.webkit.org/#/builders/134/builds/24176 "Built successfully") | 
| | [✅ 🛠 tv](https://ews-build.webkit.org/#/builders/127/builds/29847 "Built successfully") | [✅ 🛠 mac-safer-cpp](https://ews-build.webkit.org/#/builders/120/builds/35168 "Built successfully") | | 
| | [✅ 🛠 tv-sim](https://ews-build.webkit.org/#/builders/125/builds/29655 "Built successfully") | | | 
| | [✅ 🛠 watch](https://ews-build.webkit.org/#/builders/129/builds/32982 "Built successfully") | | | 
| | [✅ 🛠 watch-sim](https://ews-build.webkit.org/#/builders/124/builds/31217 "Built successfully") | | | </details>
author_association: COLLABORATOR
user: login: tuankiet65
created_at: 2025-05-09T08:01:42Z
body: Note for self: in the commit message, `style resolution will **not** its children` => `style resolution will **not** visit its children`
author_association: MEMBER
user: login: webkit-early-warning-system
created_at: 2025-05-13T19:48:35Z
body: EWS run on current version of this PR (hash https://github.com/WebKit/WebKit/commit/c9b20fcc5040f43fe12707918e5510a96ca98117)<details>

| Misc | iOS, visionOS, tvOS & watchOS  | macOS  | Linux |  Windows |
| ----- | ---------------------- | ------- |  ----- |  --------- |
| [✅ 🧪 style](https://ews-build.webkit.org/#/builders/38/builds/103348 "Passed style check") | [✅ 🛠 ios](https://ews-build.webkit.org/#/builders/131/builds/23024 "Built successfully") | [✅ 🛠 mac](https://ews-build.webkit.org/#/builders/138/builds/13345 "Built successfully") | [✅ 🛠 wpe](https://ews-build.webkit.org/#/builders/5/builds/108521 "Built successfully") | [✅ 🛠 win](https://ews-build.webkit.org/#/builders/59/builds/53991 "Built successfully") 
| [✅ 🧪 bindings](https://ews-build.webkit.org/#/builders/9/builds/105387 "Passed tests") | [✅ 🛠 ios-sim](https://ews-build.webkit.org/#/builders/130/builds/23364 "Built successfully") | [✅ 🛠 mac-AS-debug](https://ews-build.webkit.org/#/builders/123/builds/31575 "Built successfully") | [✅ 🧪 wpe-wk2](https://ews-build.webkit.org/#/builders/34/builds/78540 "Passed tests") | [✅ 🧪 win-tests](https://ews-build.webkit.org/#/builders/60/builds/35490 "Passed tests") 
| [✅ 🧪 webkitperl](https://ews-build.webkit.org/#/builders/11/builds/106354 "Passed tests") | [✅ 🧪 ios-wk2](https://ews-build.webkit.org/#/builders/132/builds/18114 "Passed tests") | [✅ 🧪 api-mac](https://ews-build.webkit.org/#/builders/18/builds/93233 "Passed tests") | [✅ 🧪 api-wpe](https://ews-build.webkit.org/#/builders/41/builds/58873 "Passed tests") | 
| | [✅ 🧪 ios-wk2-wpt](https://ews-build.webkit.org/#/builders/133/builds/18001 "Passed tests") | [✅ 🧪 mac-wk1](https://ews-build.webkit.org/#/builders/135/builds/11274 "Passed tests") | [✅ 🛠 wpe-cairo](https://ews-build.webkit.org/#/builders/65/builds/53348 "Built successfully") | 
| | [✅ 🧪 api-ios](https://ews-build.webkit.org/#/builders/13/builds/87752 "Passed tests") | [✅ 🧪 mac-wk2](https://ews-build.webkit.org/#/builders/136/builds/11336 "Passed tests") | [✅ 🛠 gtk](https://ews-build.webkit.org/#/builders/2/builds/110898 "Built successfully") | 
| | [✅ 🛠 vision](https://ews-build.webkit.org/#/builders/128/builds/30486 "Built successfully") | [✅ 🧪 mac-AS-debug-wk2](https://ews-build.webkit.org/#/builders/122/builds/22509 "Passed tests") | [✅ 🧪 gtk-wk2](https://ews-build.webkit.org/#/builders/1/builds/87537 "Passed tests") | 
| | [✅ 🛠 vision-sim](https://ews-build.webkit.org/#/builders/121/builds/30851 "Built successfully") | [✅ 🧪 mac-wk2-stress](https://ews-build.webkit.org/#/builders/8/builds/89430 "Passed tests") | [✅ 🧪 api-gtk](https://ews-build.webkit.org/#/builders/21/builds/87174 "Passed tests") | 
| [✅ 🛠 🧪 merge](https://ews-build.webkit.org/#/builders/19/builds/22224 "Built successfully and passed tests") | [✅ 🧪 vision-wk2](https://ews-build.webkit.org/#/builders/126/builds/32037 "Passed tests") | [✅ 🧪 mac-intel-wk2](https://ews-build.webkit.org/#/builders/137/builds/9757 "Passed tests") | [✅ 🛠 playstation](https://ews-build.webkit.org/#/builders/134/builds/24820 "Built successfully") | 
| | [✅ 🛠 tv](https://ews-build.webkit.org/#/builders/127/builds/30415 "Built successfully") | [✅ 🛠 mac-safer-cpp](https://ews-build.webkit.org/#/builders/120/builds/35780 "Built successfully") | | 
| | [✅ 🛠 tv-sim](https://ews-build.webkit.org/#/builders/125/builds/30223 "Built successfully") | | | 
| | [✅ 🛠 watch](https://ews-build.webkit.org/#/builders/129/builds/33548 "Built successfully") | | | 
| | [✅ 🛠 watch-sim](https://ews-build.webkit.org/#/builders/124/builds/31784 "Built successfully") | | | </details>
author_association: COLLABORATOR
user: login: webkit-commit-queue
created_at: 2025-05-14T20:30:47Z
body: Committed 294924@main (8c48c1a274e9): <https://commits.webkit.org/294924@main>

Reviewed commits have been landed. Closing PR #45100 and removing active labels.
author_association: COLLABORATOR