Title: [246057] trunk
Revision
246057
Author
[email protected]
Date
2019-06-04 00:38:17 -0700 (Tue, 04 Jun 2019)

Log Message

JS wrapper of target in ResizeObserverEntry/ResizeObserver shouldn't get collected ahead
https://bugs.webkit.org/show_bug.cgi?id=197457

Patch by Cathie Chen <[email protected]> on 2019-06-04
Reviewed by Ryosuke Niwa.

Source/WebCore:

Add JSCustomMarkFunction to make sure JS wrappers wouldn't be collected when JSResizeObserverEntry live.

For ResizeObserver, if targets are removed, it will get fired for the last time. We also need to keep these JS
wrappers live. So add these targets to a GCReachableRef list once they're observed.

Add element-leak.html to test the targets with `entry.target.myEntry = entry` could be released properly.

Tests: resize-observer/element-leak.html
       resize-observer/resize-observer-entry-keeps-js-wrapper-of-target-alive.html
       resize-observer/resize-observer-keeps-js-wrapper-of-target-alive.html

* Sources.txt:
* WebCore.xcodeproj/project.pbxproj:
* bindings/js/JSResizeObserverEntryCustom.cpp: Added.
(WebCore::JSResizeObserverEntry::visitAdditionalChildren):
* page/ResizeObserver.cpp:
(WebCore::ResizeObserver::observe):
(WebCore::ResizeObserver::removeAllTargets):
(WebCore::ResizeObserver::removeObservation):
(WebCore::ResizeObserver::stop):
* page/ResizeObserver.h:
* page/ResizeObserverEntry.idl:

LayoutTests:

* platform/win/TestExpectations:
* resize-observer/element-leak-expected.txt: Added.
* resize-observer/element-leak.html: Added.
* resize-observer/resize-observer-entry-keeps-js-wrapper-of-target-alive-expected.txt: Added.
* resize-observer/resize-observer-entry-keeps-js-wrapper-of-target-alive.html: Added.
* resize-observer/resize-observer-keeps-js-wrapper-of-target-alive-expected.txt: Added.
* resize-observer/resize-observer-keeps-js-wrapper-of-target-alive.html: Added.
* resize-observer/resources/element-leak-frame.html: Added.

Modified Paths

Added Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (246056 => 246057)


--- trunk/LayoutTests/ChangeLog	2019-06-04 06:36:05 UTC (rev 246056)
+++ trunk/LayoutTests/ChangeLog	2019-06-04 07:38:17 UTC (rev 246057)
@@ -1,3 +1,19 @@
+2019-06-04  Cathie Chen  <[email protected]>
+
+        JS wrapper of target in ResizeObserverEntry/ResizeObserver shouldn't get collected ahead
+        https://bugs.webkit.org/show_bug.cgi?id=197457
+
+        Reviewed by Ryosuke Niwa.
+
+        * platform/win/TestExpectations:
+        * resize-observer/element-leak-expected.txt: Added.
+        * resize-observer/element-leak.html: Added.
+        * resize-observer/resize-observer-entry-keeps-js-wrapper-of-target-alive-expected.txt: Added.
+        * resize-observer/resize-observer-entry-keeps-js-wrapper-of-target-alive.html: Added.
+        * resize-observer/resize-observer-keeps-js-wrapper-of-target-alive-expected.txt: Added.
+        * resize-observer/resize-observer-keeps-js-wrapper-of-target-alive.html: Added.
+        * resize-observer/resources/element-leak-frame.html: Added.
+
 2019-06-03  Youenn Fablet  <[email protected]>
 
         Allow resizing of camera video feeds to very small resolutions

Modified: trunk/LayoutTests/platform/win/TestExpectations (246056 => 246057)


--- trunk/LayoutTests/platform/win/TestExpectations	2019-06-04 06:36:05 UTC (rev 246056)
+++ trunk/LayoutTests/platform/win/TestExpectations	2019-06-04 07:38:17 UTC (rev 246057)
@@ -4401,3 +4401,7 @@
 webkit.org/b/195623 http/tests/cache/link-prefetch-main-resource-iframe.html [ Skip ]
 
 webkit.org/b/198112 http/tests/security/showModalDialog-sync-cross-origin-page-load2.html [ Skip ]
+
+# The removed elements couldn't be released properly in Win.
+# The relevant bug is https://bugs.webkit.org/show_bug.cgi?id=197908
+resize-observer/element-leak.html [ Skip ]

Added: trunk/LayoutTests/resize-observer/element-leak-expected.txt (0 => 246057)


--- trunk/LayoutTests/resize-observer/element-leak-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/resize-observer/element-leak-expected.txt	2019-06-04 07:38:17 UTC (rev 246057)
@@ -0,0 +1,4 @@
+
+PASS ResizeObserver implemented 
+PASS Test elements leak 
+

Added: trunk/LayoutTests/resize-observer/element-leak.html (0 => 246057)


--- trunk/LayoutTests/resize-observer/element-leak.html	                        (rev 0)
+++ trunk/LayoutTests/resize-observer/element-leak.html	2019-06-04 07:38:17 UTC (rev 246057)
@@ -0,0 +1,42 @@
+<!DOCTYPE html><!-- webkit-test-runner [ experimental:ResizeObserverEnabled=true ] -->
+<html>
+<meta name="timeout" content="long">
+<head>
+<script src=""
+<script src=""
+<script src=""
+</head>
+<body>
+<iframe id="testFrame" src=""
+<script>
+
+test(_ => {
+    assert_own_property(window, "ResizeObserver");
+}, "ResizeObserver implemented");
+
+promise_test(async () => {
+    return new Promise(function(resolve, reject) {
+        window.addEventListener('message', event => {
+            switch(event.data) {
+            case 'Notified':
+                var testFrame = document.getElementById("testFrame");
+                let frameDocumentIdentifier = internals.documentIdentifier(testFrame.contentDocument);
+                testFrame.remove();
+
+                handle = setInterval(function() {
+                    gc();
+                    if (internals && !internals.isDocumentAlive(frameDocumentIdentifier)) {
+                        clearInterval(handle);
+                        resolve();
+                    }
+                }, 10);
+            break;
+            }
+         }, false);
+        setTimeout(() => reject("Test timed out"), 5000);
+    });
+}, 'Test elements leak');
+
+</script>
+</body>
+</html>

Added: trunk/LayoutTests/resize-observer/resize-observer-entry-keeps-js-wrapper-of-target-alive-expected.txt (0 => 246057)


--- trunk/LayoutTests/resize-observer/resize-observer-entry-keeps-js-wrapper-of-target-alive-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/resize-observer/resize-observer-entry-keeps-js-wrapper-of-target-alive-expected.txt	2019-06-04 07:38:17 UTC (rev 246057)
@@ -0,0 +1,22 @@
+CONSOLE MESSAGE: ResizeObserver loop completed with undelivered notifications.
+CONSOLE MESSAGE: ResizeObserver loop completed with undelivered notifications.
+CONSOLE MESSAGE: ResizeObserver loop completed with undelivered notifications.
+CONSOLE MESSAGE: ResizeObserver loop completed with undelivered notifications.
+CONSOLE MESSAGE: ResizeObserver loop completed with undelivered notifications.
+CONSOLE MESSAGE: ResizeObserver loop completed with undelivered notifications.
+CONSOLE MESSAGE: ResizeObserver loop completed with undelivered notifications.
+CONSOLE MESSAGE: ResizeObserver loop completed with undelivered notifications.
+CONSOLE MESSAGE: ResizeObserver loop completed with undelivered notifications.
+This tests that JS wrappers of targets in an ResizeObserverEntry do not get collected.
+
+PASS
+PASS
+PASS
+PASS
+PASS
+PASS
+PASS
+PASS
+PASS
+PASS
+

Added: trunk/LayoutTests/resize-observer/resize-observer-entry-keeps-js-wrapper-of-target-alive.html (0 => 246057)


--- trunk/LayoutTests/resize-observer/resize-observer-entry-keeps-js-wrapper-of-target-alive.html	                        (rev 0)
+++ trunk/LayoutTests/resize-observer/resize-observer-entry-keeps-js-wrapper-of-target-alive.html	2019-06-04 07:38:17 UTC (rev 246057)
@@ -0,0 +1,60 @@
+<!DOCTYPE html><!-- webkit-test-runner [ experimental:ResizeObserverEnabled=true ] -->
+<html>
+<body>
+<p>This tests that JS wrappers of targets in an ResizeObserverEntry do not get collected.</p>
+<pre id="log"></pre>
+<script src=""
+<script>
+
+if (window.testRunner)
+    testRunner.dumpAsText();
+
+const targetCount = 5;
+const iterationCount = 10;
+
+async function observe() {
+    for (let i = 0; i < targetCount; ++i) {
+        let target = document.createElement('div');
+        target.myState = 'live';
+        document.body.appendChild(target);
+    }
+
+    return new Promise((resolve) => {
+        const observer = new ResizeObserver(entries => {
+            resolve(entries);
+            observer.disconnect();
+        });
+        document.querySelectorAll('div').forEach(target => observer.observe(target));
+    });
+}
+
+function check(entries) {
+    let deadCount = 0;
+    for (const entry of entries) {
+        if (entry.target.myState != 'live')
+            deadCount++;
+    }
+    document.getElementById('log').textContent += (deadCount ? `FAIL - ${deadCount} targets lost JS wrappers` : 'PASS') + '\n';
+}
+
+async function runAll() {
+    if (window.testRunner)
+        testRunner.waitUntilDone();
+
+    for (let j = 0; j < iterationCount; ++j) {
+        const entries = await observe();
+        document.querySelectorAll('div').forEach(target => target.remove());
+        await Promise.resolve();
+        gc();
+        check(entries);
+    }
+
+    if (window.testRunner)
+        testRunner.notifyDone();
+}
+
+runAll();
+
+</script>
+</body>
+</html>

Added: trunk/LayoutTests/resize-observer/resize-observer-keeps-js-wrapper-of-target-alive-expected.txt (0 => 246057)


--- trunk/LayoutTests/resize-observer/resize-observer-keeps-js-wrapper-of-target-alive-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/resize-observer/resize-observer-keeps-js-wrapper-of-target-alive-expected.txt	2019-06-04 07:38:17 UTC (rev 246057)
@@ -0,0 +1,4 @@
+This tests that JS wrappers of targets removed from document to be delivered to an resize observer do not get collected.
+
+PASS
+

Added: trunk/LayoutTests/resize-observer/resize-observer-keeps-js-wrapper-of-target-alive.html (0 => 246057)


--- trunk/LayoutTests/resize-observer/resize-observer-keeps-js-wrapper-of-target-alive.html	                        (rev 0)
+++ trunk/LayoutTests/resize-observer/resize-observer-keeps-js-wrapper-of-target-alive.html	2019-06-04 07:38:17 UTC (rev 246057)
@@ -0,0 +1,55 @@
+<!DOCTYPE html><!-- webkit-test-runner [ experimental:ResizeObserverEnabled=true ] -->
+<html>
+<body>
+<p>This tests that JS wrappers of targets removed from document to be delivered to an resize observer do not get collected.</p>
+<pre id="log"></pre>
+<script src=""
+<script>
+
+if (window.testRunner)
+    testRunner.dumpAsText();
+
+const targetCount = 5;
+const iterationCount = 10;
+var deadCount = 0;
+
+async function runAll() {
+    if (window.testRunner)
+        testRunner.waitUntilDone();
+
+    for (let i = 0; i < iterationCount; ++i) {
+        runTest();
+        gc();
+        await new Promise((resolve) => requestAnimationFrame(resolve))
+    }
+
+    document.getElementById('log').textContent = (deadCount ? `FAIL - ${deadCount} targets lost JS wrappers` : 'PASS') + '\n';
+
+    if (window.testRunner)
+        testRunner.notifyDone();
+}
+
+function runTest() {
+    document.querySelectorAll('div').forEach(target => target.remove());
+
+    for (let i = 0; i < targetCount; ++i) {
+        let target = document.createElement('div');
+        target.myState = 'live';
+        document.body.appendChild(target);
+    }
+
+    document.querySelectorAll('div').forEach(target => observer.observe(target));
+}
+
+const observer = new ResizeObserver(entries => {
+    for (const entry of entries) {
+        if (entry.target.myState != 'live')
+            deadCount++;
+    }
+});
+
+runAll();
+
+</script>
+</body>
+</html>

Added: trunk/LayoutTests/resize-observer/resources/element-leak-frame.html (0 => 246057)


--- trunk/LayoutTests/resize-observer/resources/element-leak-frame.html	                        (rev 0)
+++ trunk/LayoutTests/resize-observer/resources/element-leak-frame.html	2019-06-04 07:38:17 UTC (rev 246057)
@@ -0,0 +1,26 @@
+<!DOCTYPE html>
+<body></body>
+<script src=""
+<script type="text/_javascript_">
+
+const targetCount = 1000;
+var resizeObserver = new ResizeObserver( entries => {
+    for (let entry of entries)
+        entry.target.myEntry = entry;
+
+    resizeObserver.disconnect();
+    document.querySelectorAll('div').forEach(target => target.remove());
+    // Make sure targets be added to m_opaqueRoots.
+    gc();
+    parent.postMessage('Notified', '*');
+});
+
+for (let i = 0; i < targetCount; ++i) {
+    var target = document.createElement('div');
+    document.body.appendChild(target);
+}
+
+document.querySelectorAll('div').forEach(target => resizeObserver.observe(target));
+
+</script>
+</html>
\ No newline at end of file

Modified: trunk/Source/WebCore/ChangeLog (246056 => 246057)


--- trunk/Source/WebCore/ChangeLog	2019-06-04 06:36:05 UTC (rev 246056)
+++ trunk/Source/WebCore/ChangeLog	2019-06-04 07:38:17 UTC (rev 246057)
@@ -1,3 +1,33 @@
+2019-06-04  Cathie Chen  <[email protected]>
+
+        JS wrapper of target in ResizeObserverEntry/ResizeObserver shouldn't get collected ahead
+        https://bugs.webkit.org/show_bug.cgi?id=197457
+
+        Reviewed by Ryosuke Niwa.
+
+        Add JSCustomMarkFunction to make sure JS wrappers wouldn't be collected when JSResizeObserverEntry live.
+
+        For ResizeObserver, if targets are removed, it will get fired for the last time. We also need to keep these JS
+        wrappers live. So add these targets to a GCReachableRef list once they're observed.
+
+        Add element-leak.html to test the targets with `entry.target.myEntry = entry` could be released properly.
+
+        Tests: resize-observer/element-leak.html
+               resize-observer/resize-observer-entry-keeps-js-wrapper-of-target-alive.html
+               resize-observer/resize-observer-keeps-js-wrapper-of-target-alive.html
+
+        * Sources.txt:
+        * WebCore.xcodeproj/project.pbxproj:
+        * bindings/js/JSResizeObserverEntryCustom.cpp: Added.
+        (WebCore::JSResizeObserverEntry::visitAdditionalChildren):
+        * page/ResizeObserver.cpp:
+        (WebCore::ResizeObserver::observe):
+        (WebCore::ResizeObserver::removeAllTargets):
+        (WebCore::ResizeObserver::removeObservation):
+        (WebCore::ResizeObserver::stop):
+        * page/ResizeObserver.h:
+        * page/ResizeObserverEntry.idl:
+
 2019-06-03  Andy Estes  <[email protected]>
 
         [Apple Pay] Disable script injection when canMakePayment APIs are called and return true

Modified: trunk/Source/WebCore/Sources.txt (246056 => 246057)


--- trunk/Source/WebCore/Sources.txt	2019-06-04 06:36:05 UTC (rev 246056)
+++ trunk/Source/WebCore/Sources.txt	2019-06-04 07:38:17 UTC (rev 246057)
@@ -533,6 +533,7 @@
 bindings/js/JSReadableStreamSourceCustom.cpp
 bindings/js/JSRemoteDOMWindowBase.cpp
 bindings/js/JSRemoteDOMWindowCustom.cpp
+bindings/js/JSResizeObserverEntryCustom.cpp
 bindings/js/JSSVGPathSegCustom.cpp
 bindings/js/JSSVGViewSpecCustom.cpp
 bindings/js/JSStyleSheetCustom.cpp

Modified: trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj (246056 => 246057)


--- trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj	2019-06-04 06:36:05 UTC (rev 246056)
+++ trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj	2019-06-04 07:38:17 UTC (rev 246057)
@@ -8793,6 +8793,7 @@
 		585D6DFB1A15355600FA4F12 /* SimpleLineLayoutResolver.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SimpleLineLayoutResolver.cpp; sourceTree = "<group>"; };
 		585D6E011A1A792E00FA4F12 /* SimpleLineLayoutFlowContents.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SimpleLineLayoutFlowContents.cpp; sourceTree = "<group>"; };
 		585D6E021A1A792E00FA4F12 /* SimpleLineLayoutFlowContents.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SimpleLineLayoutFlowContents.h; sourceTree = "<group>"; };
+		5884FE5622813E2D0040AFF6 /* JSResizeObserverEntryCustom.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSResizeObserverEntryCustom.cpp; sourceTree = "<group>"; };
 		589556EC18D4A44000764B03 /* BorderEdge.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BorderEdge.h; sourceTree = "<group>"; };
 		58AEE2F318D4BCCF0022E7FE /* BorderEdge.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = BorderEdge.cpp; sourceTree = "<group>"; };
 		58B2F9EA2232D43B00938D63 /* ResizeObserverEntry.idl */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = ResizeObserverEntry.idl; sourceTree = "<group>"; };
@@ -20690,6 +20691,7 @@
 				CB38FD551CD21D5B00592A3F /* JSPerformanceEntryCustom.cpp */,
 				833CF70F20DB3F5F00141BCC /* JSPerformanceObserverCustom.cpp */,
 				A4A69B8BB91B49D0A804C31D /* JSPromiseRejectionEventCustom.cpp */,
+				5884FE5622813E2D0040AFF6 /* JSResizeObserverEntryCustom.cpp */,
 				83F572941FA1066F003837BE /* JSServiceWorkerClientCustom.cpp */,
 				460D19441FCE21DD00C3DB85 /* JSServiceWorkerGlobalScopeCustom.cpp */,
 				BC98A27C0C0C9950004BEBF7 /* JSStyleSheetCustom.cpp */,

Copied: trunk/Source/WebCore/bindings/js/JSResizeObserverEntryCustom.cpp (from rev 246056, trunk/Source/WebCore/page/ResizeObserverEntry.idl) (0 => 246057)


--- trunk/Source/WebCore/bindings/js/JSResizeObserverEntryCustom.cpp	                        (rev 0)
+++ trunk/Source/WebCore/bindings/js/JSResizeObserverEntryCustom.cpp	2019-06-04 07:38:17 UTC (rev 246057)
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2019 Igalia S.L.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "JSResizeObserverEntry.h"
+
+#include "JSNodeCustom.h"
+
+namespace WebCore {
+
+void JSResizeObserverEntry::visitAdditionalChildren(JSC::SlotVisitor& visitor)
+{
+    visitor.addOpaqueRoot(root(wrapped().target()));
+    visitor.addOpaqueRoot(wrapped().contentRect());
+}
+
+}

Modified: trunk/Source/WebCore/page/ResizeObserver.cpp (246056 => 246057)


--- trunk/Source/WebCore/page/ResizeObserver.cpp	2019-06-04 06:36:05 UTC (rev 246056)
+++ trunk/Source/WebCore/page/ResizeObserver.cpp	2019-06-04 07:38:17 UTC (rev 246057)
@@ -69,6 +69,7 @@
     observerData.observers.append(makeWeakPtr(this));
 
     m_observations.append(ResizeObservation::create(&target));
+    m_pendingTargets.append(target);
 
     if (m_document) {
         m_document->addResizeObserver(*this);
@@ -140,11 +141,17 @@
         bool removed = removeTarget(*observation->target());
         ASSERT_UNUSED(removed, removed);
     }
+    m_pendingTargets.clear();
+    m_activeObservations.clear();
     m_observations.clear();
 }
 
 bool ResizeObserver::removeObservation(const Element& target)
 {
+    m_pendingTargets.removeFirstMatching([&target](auto& pendingTarget) {
+        return pendingTarget.ptr() == &target;
+    });
+
     m_activeObservations.removeFirstMatching([&target](auto& observation) {
         return observation->target() == &target;
     });
@@ -173,8 +180,6 @@
 {
     disconnect();
     m_callback = nullptr;
-    m_observations.clear();
-    m_activeObservations.clear();
 }
 
 } // namespace WebCore

Modified: trunk/Source/WebCore/page/ResizeObserver.h (246056 => 246057)


--- trunk/Source/WebCore/page/ResizeObserver.h	2019-06-04 06:36:05 UTC (rev 246056)
+++ trunk/Source/WebCore/page/ResizeObserver.h	2019-06-04 07:38:17 UTC (rev 246057)
@@ -28,6 +28,7 @@
 #if ENABLE(RESIZE_OBSERVER)
 
 #include "ActiveDOMObject.h"
+#include "GCReachableRef.h"
 #include "ResizeObservation.h"
 #include "ResizeObserverCallback.h"
 #include <wtf/RefCounted.h>
@@ -80,6 +81,7 @@
     Vector<Ref<ResizeObservation>> m_observations;
 
     Vector<Ref<ResizeObservation>> m_activeObservations;
+    Vector<GCReachableRef<Element>> m_pendingTargets;
     bool m_hasSkippedObservations { false };
 };
 

Modified: trunk/Source/WebCore/page/ResizeObserverEntry.idl (246056 => 246057)


--- trunk/Source/WebCore/page/ResizeObserverEntry.idl	2019-06-04 06:36:05 UTC (rev 246056)
+++ trunk/Source/WebCore/page/ResizeObserverEntry.idl	2019-06-04 07:38:17 UTC (rev 246057)
@@ -28,7 +28,8 @@
 [
     Conditional=RESIZE_OBSERVER,
     ImplementationLacksVTable,
-    EnabledBySetting=ResizeObserver
+    EnabledBySetting=ResizeObserver,
+    JSCustomMarkFunction
 ] interface ResizeObserverEntry {
     readonly attribute Element target;
     readonly attribute DOMRectReadOnly contentRect;
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to