WebKit Bugzilla
Attachment 360291 Details for
Bug 157743
: Implement ResizeObserver
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Requests
|
Help
|
New Account
|
Log In
Remember
[x]
|
Forgot Password
Login:
[x]
[patch]
WIP-004
ro-004.diff (text/plain), 80.91 KB, created by
cathiechen
on 2019-01-27 04:13:28 PST
(
hide
)
Description:
WIP-004
Filename:
MIME Type:
Creator:
cathiechen
Created:
2019-01-27 04:13:28 PST
Size:
80.91 KB
patch
obsolete
>diff --git a/LayoutTests/imported/w3c/resources/import-expectations.json b/LayoutTests/imported/w3c/resources/import-expectations.json >index d6ee94121c..3a0def66b0 100644 >--- a/LayoutTests/imported/w3c/resources/import-expectations.json >+++ b/LayoutTests/imported/w3c/resources/import-expectations.json >@@ -296,6 +296,7 @@ > "web-platform-tests/remote-playback": "skip", > "web-platform-tests/requestidlecallback": "skip", > "web-platform-tests/resize-observer": "skip", >+ "web-platform-tests/resize-observer/": "import", > "web-platform-tests/resource-timing": "import", > "web-platform-tests/resources": "import", > "web-platform-tests/screen-orientation": "skip", >diff --git a/LayoutTests/imported/w3c/web-platform-tests/resize-observer/META.yml b/LayoutTests/imported/w3c/web-platform-tests/resize-observer/META.yml >new file mode 100644 >index 0000000000..ef6685622b >--- /dev/null >+++ b/LayoutTests/imported/w3c/web-platform-tests/resize-observer/META.yml >@@ -0,0 +1,4 @@ >+spec: https://wicg.github.io/ResizeObserver/ >+suggested_reviewers: >+ - atotic >+ - dholbert >diff --git a/LayoutTests/imported/w3c/web-platform-tests/resize-observer/eventloop-expected.txt b/LayoutTests/imported/w3c/web-platform-tests/resize-observer/eventloop-expected.txt >new file mode 100644 >index 0000000000..e39d53828a >--- /dev/null >+++ b/LayoutTests/imported/w3c/web-platform-tests/resize-observer/eventloop-expected.txt >@@ -0,0 +1,10 @@ >+ResizeObserver notification event loop tests >+ >+t1 >+ >+Harness Error (TIMEOUT), message = null >+ >+PASS ResizeObserver implemented >+NOTRUN guard >+FAIL test0: multiple notifications inside same event loop assert_unreached: Timed out waiting for notification. (100ms) Reached unreachable code >+ >diff --git a/LayoutTests/imported/w3c/web-platform-tests/resize-observer/eventloop.html b/LayoutTests/imported/w3c/web-platform-tests/resize-observer/eventloop.html >new file mode 100644 >index 0000000000..622d724a19 >--- /dev/null >+++ b/LayoutTests/imported/w3c/web-platform-tests/resize-observer/eventloop.html >@@ -0,0 +1,259 @@ >+<!doctype html><!-- webkit-test-runner [ experimental:ResizeObserverEnabled=true ] --> >+<script src="/resources/testharness.js"></script> >+<script src="/resources/testharnessreport.js"></script> >+<script src="./resources/resizeTestHelper.js"></script> >+<style> >+ div { >+ border: 1px dotted gray >+ } >+</style> >+<p>ResizeObserver notification event loop tests</p> >+<div id="target1" style="width:100px;height:100px;">t1 >+</div> >+<div id="container"> >+ <div id="a1" style="width:100px;height:100px"> >+ <div id="a2" style="width:100px;height:100px"> >+ </div> >+ </div> >+ <div id="b1" style="width:100px;height:100px"> >+ <div id="b2" style="width:100px;height:100px"> >+ </div> >+ </div> >+</div> >+<script> >+'use strict'; >+ >+let t1 = document.querySelector('#target1'); >+ >+// allow uncaught exception because ResizeObserver posts exceptions >+// to window error handler when limit is exceeded. >+// This codepath is tested in this file. >+ >+setup({allow_uncaught_exception: true}); >+ >+function template() { >+ let helper = new ResizeTestHelper( >+ "test0: title", >+ [ >+ { >+ setup: observer => { >+ }, >+ notify: (entries, observer) => { >+ return true; // Delay next step >+ } >+ } >+ ]); >+ return helper.start(); >+} >+ >+var onErrorCalled = false; >+ >+window.onerror = err => { >+ onErrorCalled = true; >+} >+ >+function test0() { >+ >+ let divs = [t1]; >+ let rAF = 0; >+ let helper = new ResizeTestHelper( >+ "test0: multiple notifications inside same event loop", >+ [ >+ { >+ setup: observer => { >+ onErrorCalled = false; >+ let t2 = document.createElement('div'); >+ let t3 = document.createElement('div'); >+ t2.appendChild(t3); >+ t1.appendChild(t2); >+ divs.push(t2); >+ divs.push(t3); >+ observer.observe(t1); >+ observer.observe(t2); >+ observer.observe(t3); >+ }, >+ notify: (entries, observer) => { >+ assert_equals(entries.length, 3, "3 notifications"); >+ } >+ }, >+ { >+ setup: observer => { >+ helper.startCountingRaf(); >+ divs.forEach( el => { el.style.width = "101px";}); >+ }, >+ notify: (entries, observer) => { >+ // t1 is not delivered >+ assert_equals(entries.length, 2, "2 notifications"); >+ assert_equals(helper.rafCount, 0, "still in same loop"); >+ } >+ }, >+ { >+ setup: observer => { >+ divs.forEach( el => { el.style.width = "102px";}); >+ }, >+ notify: (entries, observer) => { >+ assert_equals(entries.length, 1, "1 notifications"); >+ assert_equals(helper.rafCount, 0, "same loop"); >+ } >+ }, >+ { // t1 and t2 get notified >+ setup: observer => { >+ }, >+ notify: (entries, observer) => { >+ assert_equals(entries.length, 2, "2 notifications"); >+ assert_equals(helper.rafCount, 1, "new loop"); >+ assert_equals(onErrorCalled, true, "error was fired"); >+ observer.disconnect(); >+ while (t1.childNodes.length > 0) >+ t1.removeChild(t1.childNodes[0]); >+ } >+ } >+ ]); >+ return helper.start(); >+} >+ >+function test1() { >+ >+ var resizers = [t1]; >+ // Testing depths of shadow roots >+ // DOM: t1 <- t2 <- t3 <-shadow- t4 <- t5 >+ let helper = new ResizeTestHelper( >+ "test1: depths of shadow roots", >+ [ >+ { >+ setup: observer => { >+ onErrorCalled = false; >+ let t2 = document.createElement('div'); >+ t1.appendChild(t2); >+ resizers.push(t2); >+ let t3 = document.createElement('div'); >+ resizers.push(t3); >+ t2.appendChild(t3); >+ let shadow = t3.attachShadow({ mode: "open" }); >+ let t4 = document.createElement('div'); >+ resizers.push(t4); >+ shadow.appendChild(t4); >+ let t5 = document.createElement('div'); >+ resizers.push(t5); >+ t4.appendChild(t5); >+ resizers.forEach( el => observer.observe(el) ); >+ }, >+ notify: (entries, observer) => { >+ assert_equals(entries.length, 5, "all entries resized"); >+ } >+ }, >+ { >+ setup: observer => { >+ resizers.forEach( el => el.style.width = "111px" ); >+ }, >+ notify: (entries, observer) => { >+ assert_equals(entries.length, 4, "depth limited"); >+ } >+ }, >+ { >+ setup: observer => { >+ resizers.forEach( el => el.style.width = "112px" ); >+ }, >+ notify: (entries, observer) => { >+ assert_equals(entries.length, 3, "depth limited"); >+ } >+ }, >+ { >+ setup: observer => { >+ resizers.forEach( el => el.style.width = "113px" ); >+ }, >+ notify: (entries, observer) => { >+ assert_equals(entries.length, 2, "depth limited"); >+ } >+ }, >+ { >+ setup: observer => { >+ resizers.forEach( el => el.style.width = "114px" ); >+ }, >+ notify: (entries, observer) => { >+ assert_equals(entries.length, 1, "depth limited"); >+ } >+ }, >+ { >+ setup: observer => { >+ }, >+ notify: (entries, observer) => { >+ assert_equals(entries.length, 4, "limit notifications"); >+ assert_equals(onErrorCalled, true, "breached limit"); >+ observer.disconnect(); >+ t1.removeChild(t1.firstChild); >+ } >+ }, >+ ]); >+ return helper.start(); >+} >+ >+function test2() { >+ let container = document.querySelector('#container'); >+ let a1 = document.querySelector('#a1'); >+ let a2 = document.querySelector('#a2'); >+ let b1 = document.querySelector('#b1'); >+ let b2 = document.querySelector('#b2'); >+ let targets = [a1, a2, b1, b2]; >+ >+ let helper = new ResizeTestHelper( >+ "test2: move target in dom while inside event loop", >+ [ >+ { >+ setup: observer => { >+ for (let t of targets) >+ observer.observe(t); >+ }, >+ notify: (entries, observer) => { >+ return true; // delay next observation >+ } >+ }, >+ { // resize them all >+ setup: observer => { >+ for (let t of targets) >+ t.style.width = "110px"; >+ }, >+ notify: (entries, observer) => { >+ assert_equals(entries.length, targets.length, "all targets observed"); >+ } >+ }, >+ { // resize all, move dom upwards >+ setup: observer => { >+ for (let t of targets) >+ t.style.width = "130px"; >+ container.appendChild(b2); >+ }, >+ notify: (entries, observer) => { >+ assert_equals(entries.length, 1, "b2 moved upwards"); >+ assert_equals(entries[0].target, a2); >+ } >+ }, >+ { // resize all, move dom downwards >+ setup: observer => { >+ for (let t of targets) >+ t.style.width = "130px"; >+ a2.appendChild(b2); >+ }, >+ notify: (entries, observer) => { >+ assert_equals(entries.length, 1, "b2 moved downwards"); >+ assert_equals(entries[0].target, b2); >+ a1.appendChild(a2); >+ } >+ }, >+ ]); >+ return helper.start(); >+} >+ >+let guard; >+test(_ => { >+ assert_own_property(window, "ResizeObserver"); >+ guard = async_test('guard'); >+}, "ResizeObserver implemented") >+ >+test0() >+ .then(() => { return test1(); }) >+ .then(() => { return test2(); }) >+ .then(() => { guard.done(); }); >+ >+</script> >+ >diff --git a/LayoutTests/imported/w3c/web-platform-tests/resize-observer/idlharness.window-expected.txt b/LayoutTests/imported/w3c/web-platform-tests/resize-observer/idlharness.window-expected.txt >new file mode 100644 >index 0000000000..a7ea32791c >--- /dev/null >+++ b/LayoutTests/imported/w3c/web-platform-tests/resize-observer/idlharness.window-expected.txt >@@ -0,0 +1,30 @@ >+ >+FAIL idl_test setup promise_test: Unhandled rejection with value: object "Got an error before parsing any named definition: Unrecognised tokens, line 1 (tokens: "{\"error\": {\"message\"") >+[ >+ { >+ "type": "{", >+ "value": "{", >+ "trivia": "" >+ }, >+ { >+ "type": "string", >+ "value": "\"error\"", >+ "trivia": "" >+ }, >+ { >+ "type": ":", >+ "value": ":", >+ "trivia": "" >+ }, >+ { >+ "type": "{", >+ "value": "{", >+ "trivia": " " >+ }, >+ { >+ "type": "string", >+ "value": "\"message\"", >+ "trivia": "" >+ } >+]" >+ >diff --git a/LayoutTests/imported/w3c/web-platform-tests/resize-observer/idlharness.window.html b/LayoutTests/imported/w3c/web-platform-tests/resize-observer/idlharness.window.html >new file mode 100644 >index 0000000000..479d78c5ac >--- /dev/null >+++ b/LayoutTests/imported/w3c/web-platform-tests/resize-observer/idlharness.window.html >@@ -0,0 +1,2 @@ >+<!-- This file is required for WebKit test infrastructure to run the templated test --> >+<!-- webkit-test-runner [ experimental:ResizeObserverEnabled=true ] --> >diff --git a/LayoutTests/imported/w3c/web-platform-tests/resize-observer/idlharness.window.js b/LayoutTests/imported/w3c/web-platform-tests/resize-observer/idlharness.window.js >new file mode 100644 >index 0000000000..592af2e0c0 >--- /dev/null >+++ b/LayoutTests/imported/w3c/web-platform-tests/resize-observer/idlharness.window.js >@@ -0,0 +1,37 @@ >+// META: script=/resources/WebIDLParser.js >+// META: script=/resources/idlharness.js >+// META: script=resources/resizeTestHelper.js >+ >+'use strict'; >+ >+// https://wicg.github.io/ResizeObserver/ >+ >+idl_test( >+ ['ResizeObserver'], >+ ['dom', 'geometry'], >+ async idl_array => { >+ idl_array.add_objects({ >+ ResizeObserver: ['observer'], >+ ResizeObserverEntry: ['entry'], >+ }); >+ >+ const div = document.createElement('div'); >+ document.body.appendChild(div); >+ let helper = new ResizeTestHelper( >+ "ResizeObserverEntry creator", >+ [ >+ { >+ setup: observer => { >+ self.observer = observer; >+ observer.observe(div); >+ div.style.width = "5px"; >+ }, >+ notify: entries => { >+ self.entry = entries[0]; >+ assert_equals(entries[0].contentRect.width, 5, "target width"); >+ } >+ } >+ ]); >+ await helper.start(); >+ } >+); >diff --git a/LayoutTests/imported/w3c/web-platform-tests/resize-observer/notify-expected.txt b/LayoutTests/imported/w3c/web-platform-tests/resize-observer/notify-expected.txt >new file mode 100644 >index 0000000000..0ea83587d1 >--- /dev/null >+++ b/LayoutTests/imported/w3c/web-platform-tests/resize-observer/notify-expected.txt >@@ -0,0 +1,12 @@ >+ResizeObserver tests >+ >+t1 >+t2 >+t3 inline >+ >+Harness Error (TIMEOUT), message = null >+ >+PASS ResizeObserver implemented >+NOTRUN guard >+FAIL test0: notification ordering assert_unreached: Timed out waiting for notification. (100ms) Reached unreachable code >+ >diff --git a/LayoutTests/imported/w3c/web-platform-tests/resize-observer/notify.html b/LayoutTests/imported/w3c/web-platform-tests/resize-observer/notify.html >new file mode 100644 >index 0000000000..b1038a3cb6 >--- /dev/null >+++ b/LayoutTests/imported/w3c/web-platform-tests/resize-observer/notify.html >@@ -0,0 +1,351 @@ >+<!doctype html><!-- webkit-test-runner [ experimental:ResizeObserverEnabled=true ] --> >+<script src="/resources/testharness.js"></script> >+<script src="/resources/testharnessreport.js"></script> >+<script src="./resources/resizeTestHelper.js"></script> >+<style> >+ div { >+ border: 1px dotted gray >+ } >+ .transform { >+ transform: scale(2,2) rotate(90deg) >+ } >+</style> >+<p>ResizeObserver tests</p> >+<div id="target1" style="width:100px;height:100px;">t1 >+ <div id="target2" style="width:100px;height:100px;">t2 >+ <div id="target3" style="width:100px;height:100px;">t3 >+ <span id="inline">inline</span> >+ </div> >+ </div> >+</div> >+<div id="absolute" style="width:100.5px;height:100.5px;position:absolute;top:10.3px;left:10.3px"></div> >+<script> >+'use strict'; >+ >+let t1 = document.querySelector('#target1'); >+let t2 = document.querySelector('#target2'); >+let t3 = document.querySelector('#target3'); >+let abs = document.querySelector('#absolute'); >+let inline = document.querySelector('#inline'); >+ >+function test0() { >+ let helper = new ResizeTestHelper( >+ "test0: notification ordering", >+ [ >+ { >+ setup: observer => { >+ observer.observe(t3); >+ observer.observe(t2); >+ observer.observe(t1); >+ t1.style.width = "5px"; >+ t3.style.width = "5px"; >+ t2.style.width = "5px"; >+ }, >+ notify: (entries, observer) => { >+ assert_equals(entries.length, 3, "3 resizes"); >+ assert_equals(entries[0].target, t3, "ordering"); >+ assert_equals(entries[1].target, t2, "ordering"); >+ assert_equals(entries[2].target, t1, "ordering"); >+ observer.disconnect(); >+ t1.style.width = "100px"; >+ t2.style.width = "100px"; >+ t3.style.width = "100px"; >+ } >+ } >+ ]); >+ return helper.start(); >+} >+ >+function test1() { >+ let helper = new ResizeTestHelper( >+ "test1: display:none triggers notification", >+ [ >+ { >+ setup: observer => { >+ observer.observe(t1); >+ }, >+ notify: (entries, observer) => { >+ return true; // Delay next step >+ } >+ }, >+ { >+ setup: observer => { >+ t1.style.display = "none"; >+ }, >+ notify: (entries, observer) => { >+ t1.style.display = ""; >+ } >+ } >+ ]); >+ return helper.start(); >+} >+ >+ >+function test2() { >+ let helper = new ResizeTestHelper( >+ "test2: remove/appendChild trigger notification", >+ [ >+ { >+ setup: observer => { >+ observer.observe(t1); >+ }, >+ notify: (entries, observer) => { >+ return true; // Delay next step >+ } >+ }, >+ { // "removeChild triggers notification" >+ setup: observer => { >+ t1.parentNode.removeChild(t1); >+ }, >+ notify: (entries, observer) => { >+ assert_equals(entries[0].target, t1); >+ return true; // Delay next step >+ } >+ }, >+ { // "appendChild triggers notification", >+ setup: observer => { >+ document.body.appendChild(t1); >+ }, >+ notify: (entries, observer) => { >+ assert_equals(entries[0].target, t1) >+ } >+ } >+ ]); >+ return helper.start(); >+} >+ >+ >+function test3() { >+ let helper = new ResizeTestHelper( >+ "test3: dimensions match", >+ [ >+ { >+ setup: observer => { >+ observer.observe(t1); >+ t1.style.width = "200.5px"; >+ t1.style.height = "100px"; >+ t1.style.paddingLeft = "20px"; >+ t1.style.paddingTop = "10px"; >+ }, >+ notify: (entries, observer) => { >+ assert_equals(entries[0].contentRect.left,20); >+ assert_equals(entries[0].contentRect.top,10); >+ assert_between_inclusive(entries[0].contentRect.width, 200.4, 200.6, "width is not rounded"); >+ assert_equals(entries[0].contentRect.height, 100); >+ } >+ } >+ ]); >+ return helper.start(); >+} >+ >+function test4() { >+ let helper = new ResizeTestHelper( >+ "test4: transform do not cause notifications", >+ [ >+ { >+ setup: observer => { >+ observer.observe(t2); >+ }, >+ notify: (entries, observer) => { >+ return true; // Delay next step >+ } >+ }, >+ { >+ setup: observer => { >+ t2.classList.add("transform"); >+ }, >+ notify: (entries, observer) => { >+ assert_unreached("transform must not trigger notifications"); >+ }, >+ timeout: () => { >+ t2.classList.remove("transform"); >+ } >+ } >+ ]); >+ return helper.start(); >+} >+ >+function test5() { >+ let helper = new ResizeTestHelper( >+ "test5: moving an element does not trigger notifications", >+ [ >+ { >+ setup: observer => { >+ observer.observe(abs); >+ }, >+ notify: (entries, observer) => { >+ return true; // Delay next step >+ } >+ }, >+ { >+ setup: observer => { >+ abs.style.top = "20.33px"; >+ abs.style.left = "20.33px"; >+ }, >+ notify: (entries, observer) => { >+ assert_unreached("movement should not cause resize notifications"); >+ }, >+ timeout: () => { >+ } >+ } >+ ]); >+ return helper.start(); >+} >+ >+function test6() { >+ let helper = new ResizeTestHelper( >+ "test6: inline element does not notify", >+ [ >+ { >+ setup: observer => { >+ observer.observe(inline); >+ observer.observe(t1); >+ t1.style.width = "66px"; >+ inline.style.width = "66px"; >+ }, >+ notify: (entries, observer) => { >+ assert_equals(entries.length, 1, "inline elements must not trigger notifications"); >+ assert_equals(entries[0].target, t1, "inline elements must not trigger notifications"); >+ return true; // Delay next step >+ } >+ }, >+ { // "inline element that becomes block should notify", >+ setup: observer => { >+ inline.style.display = "block"; >+ }, >+ notify: (entries, observer) => { >+ assert_equals(entries[0].target, inline); >+ } >+ } >+ ]); >+ return helper.start(); >+} >+ >+function test7() { >+ let helper = new ResizeTestHelper( >+ "test7: unobserve inside notify callback", >+ [ >+ { >+ setup: observer => { >+ observer.observe(t1); >+ observer.observe(t2); >+ }, >+ notify: (entries, observer) => { >+ t1.style.width = "777px"; >+ t2.style.width = "777px"; >+ observer.unobserve(t1); >+ return true; // Delay next step >+ } >+ }, >+ { >+ setup: observer => { >+ }, >+ notify: (entries, observer) => { >+ assert_equals(entries.length, 1, "only t2 is observed"); >+ assert_equals(entries[0].target, t2, "only t2 is observed"); >+ } >+ } >+ ]); >+ return helper.start(); >+} >+ >+function test8() { >+ let helper = new ResizeTestHelper( >+ "test8: observe inside notify callback", >+ [ >+ { >+ setup: observer => { >+ observer.observe(t1); >+ }, >+ notify: (entries, observer) => { >+ observer.observe(t2); >+ t2.style.width = "888px"; >+ return true; // Delay next step >+ } >+ }, >+ { >+ setup: observer => { >+ }, >+ notify: (entries, observer) => { >+ assert_equals(entries.length, 1, "only t2 is observed"); >+ assert_equals(entries[0].target, t2, "only t2 is observed"); >+ } >+ } >+ ]); >+ return helper.start(); >+} >+ >+function test9() { >+ let helper = new ResizeTestHelper( >+ "test9: disconnect inside notify callback", >+ [ >+ { >+ setup: observer => { >+ observer.observe(t1); >+ }, >+ notify: (entries, observer) => { >+ t1.style.width = "999px"; >+ observer.disconnect(); >+ return true; // Delay next step >+ } >+ }, >+ { >+ setup: observer => { >+ }, >+ notify: (entries, observer) => { >+ assert_unreached("there should be no notifications after disconnect"); >+ }, >+ timeout: () => { >+ } >+ } >+ ]); >+ return helper.start(); >+} >+ >+function test10() { >+ var parent = t1.parentNode; >+ let helper = new ResizeTestHelper( >+ "test10: element notifies when parent removed", >+ [ >+ { >+ setup: observer => { >+ observer.observe(t3); >+ }, >+ notify: (entries, observer) => { >+ return true; // Delay next step >+ } >+ }, >+ { >+ setup: observer => { >+ t1.parentNode.removeChild(t1); >+ }, >+ notify: (entries, observer) => { >+ assert_equals(entries.length, 1); >+ assert_equals(entries[0].target, t3); >+ parent.appendChild(t1); >+ } >+ } >+ ]); >+ return helper.start(); >+} >+ >+let guard; >+test(_ => { >+ assert_own_property(window, "ResizeObserver"); >+ guard = async_test('guard'); >+}, "ResizeObserver implemented") >+ >+test0() >+ .then(() => { return test1(); }) >+ .then(() => { return test2(); }) >+ .then(() => { return test3(); }) >+ .then(() => { return test4(); }) >+ .then(() => { return test5(); }) >+ .then(() => { return test6(); }) >+ .then(() => { return test7(); }) >+ .then(() => { return test8(); }) >+ .then(() => { return test9(); }) >+ .then(() => { return test10(); }) >+ .then(() => { guard.done(); }); >+ >+</script> >diff --git a/LayoutTests/imported/w3c/web-platform-tests/resize-observer/observe-expected.txt b/LayoutTests/imported/w3c/web-platform-tests/resize-observer/observe-expected.txt >new file mode 100644 >index 0000000000..d3e0b513a8 >--- /dev/null >+++ b/LayoutTests/imported/w3c/web-platform-tests/resize-observer/observe-expected.txt >@@ -0,0 +1,12 @@ >+ResizeObserver tests >+ >+t1 >+t2 >+ >+ >+Harness Error (TIMEOUT), message = null >+ >+PASS ResizeObserver implemented >+NOTRUN guard >+FAIL test0: simple observation assert_unreached: Timed out waiting for notification. (100ms) Reached unreachable code >+ >diff --git a/LayoutTests/imported/w3c/web-platform-tests/resize-observer/observe.html b/LayoutTests/imported/w3c/web-platform-tests/resize-observer/observe.html >new file mode 100644 >index 0000000000..fc4592d459 >--- /dev/null >+++ b/LayoutTests/imported/w3c/web-platform-tests/resize-observer/observe.html >@@ -0,0 +1,207 @@ >+<!doctype html><!-- webkit-test-runner [ experimental:ResizeObserverEnabled=true ] --> >+<script src="/resources/testharness.js"></script> >+<script src="/resources/testharnessreport.js"></script> >+<script src="./resources/resizeTestHelper.js"></script> >+<p>ResizeObserver tests</p> >+<div id="target1" style="width:100px;height:100px;">t1</div> >+<div id="target2" style="width:100px;height:100px;">t2</div> >+<img id="target3" style="width:100px;height:100px;"> >+<iframe src="./resources/iframe.html" width="300px" height="100px" style="display:block"></iframe> >+<script> >+'use strict'; >+ >+let t1 = document.querySelector('#target1'); >+let t2 = document.querySelector('#target2'); >+ >+// allow uncaught exception because ResizeObserver posts exceptions >+// to window error handler when limit is exceeded. >+setup({allow_uncaught_exception: true}); >+ >+function test0() { >+ let helper = new ResizeTestHelper( >+ "test0: simple observation", >+ [ >+ { >+ setup: observer => { >+ observer.observe(t1); >+ t1.style.width = "5px"; >+ }, >+ notify: entries => { >+ assert_equals(entries.length, 1, "1 pending notification"); >+ assert_equals(entries[0].target, t1, "target is t1"); >+ assert_equals(entries[0].contentRect.width, 5, "target width"); >+ } >+ } >+ ]); >+ return helper.start(); >+} >+ >+function test1() { >+ let helper = new ResizeTestHelper( >+ "test1: multiple observation on same element trigger only one", >+ [ >+ { >+ setup: observer => { >+ observer.observe(t1); >+ observer.observe(t1); >+ t1.style.width = "10px"; >+ }, >+ notify: entries => { >+ assert_equals(entries.length, 1, "1 pending notification"); >+ } >+ } >+ ]); >+ return helper.start(); >+} >+ >+function test2() { >+ test(() => { >+ assert_throws({name: "TypeError"}, _=> { >+ let ro = new ResizeObserver(() => {}); >+ ro.observe({}); >+ }); >+ }, >+ "test2: throw exception when observing non-element" >+ ); >+ return Promise.resolve(); >+} >+ >+function test3() { >+ let helper = new ResizeTestHelper( >+ "test3: disconnect stops all notifications", [ >+ { >+ setup: observer => { >+ observer.observe(t1); >+ observer.observe(t2); >+ observer.disconnect(); >+ t1.style.width = "30px"; >+ }, >+ notify: entries => { >+ assert_unreached("no entries should be observed"); >+ }, >+ timeout: () => { >+ // expected >+ } >+ } >+ ]); >+ return helper.start(); >+} >+ >+function test4() { >+ let helper = new ResizeTestHelper( >+ "test4: unobserve target stops notifications, unobserve non-observed does nothing", [ >+ { >+ setup: observer => { >+ observer.observe(t1); >+ observer.observe(t2); >+ observer.unobserve(t1); >+ observer.unobserve(document.body); >+ t1.style.width = "40px"; >+ t2.style.width = "40px"; >+ }, >+ notify: entries => { >+ assert_equals(entries.length, 1, "only t2"); >+ assert_equals(entries[0].target, t2, "t2 was observed"); >+ } >+ } >+ ]); >+ return helper.start(); >+} >+ >+function test5() { >+ let t3 = document.querySelector('#target3'); >+ var helper = new ResizeTestHelper("test5: observe img",[ >+ { >+ setup: observer => { >+ observer.observe(t3); >+ }, >+ notify: entries => { >+ } >+ }, >+ { >+ setup: observer => { >+ t3.style.width = "100.5px"; >+ }, >+ notify: entries => { >+ assert_equals(entries.length, 1); >+ assert_equals(entries[0].contentRect.width, 100.5); >+ } >+ } >+ ]); >+ return helper.start(); >+} >+ >+function test6() { >+ let resolvePromise; >+ let promise = new Promise((resolve) => { >+ resolvePromise = resolve; >+ }); >+ let test = async_test('test6: iframe notifications'); >+ let testRequested = false; >+ let iframe = document.querySelector('iframe'); >+ window.addEventListener('message', event => { >+ switch(event.data) { >+ case 'readyToTest': >+ if (!testRequested) { >+ iframe.contentWindow.postMessage('startTest', '*'); >+ testRequested = true; >+ } >+ break; >+ case 'success': >+ case 'fail': >+ window.requestAnimationFrame(() => { >+ test.step( () => { >+ assert_equals(event.data, 'success'); >+ test.done(); >+ resolvePromise(); >+ }); >+ }); >+ break; >+ } >+ }, false); >+ return promise; >+} >+ >+function test7() { >+ let harnessTest = async_test("test7: callback.this"); >+ let resolvePromise; >+ let ro = new ResizeObserver( function(entries, obs) { >+ let callbackThis = this; >+ resolvePromise(); >+ harnessTest.step(() => { >+ assert_equals(callbackThis, ro, "callback.this is ResizeObserver"); >+ assert_equals(obs, ro, "2nd argument is ResizeObserver"); >+ ro.disconnect(); >+ // every reference to RO must be null before test completes >+ // to avoid triggering test leak-detection >+ ro = null; >+ callbackThis = null; >+ obs = null; >+ harnessTest.done(); >+ }); >+ } >+ ); >+ ro.observe(t1); >+ >+ return new Promise( (resolve, reject) => { >+ resolvePromise = resolve; >+ }); >+} >+ >+let guard; >+test(_ => { >+ assert_own_property(window, "ResizeObserver"); >+ guard = async_test('guard'); >+}, "ResizeObserver implemented") >+ >+test0() >+ .then(() => { return test1(); }) >+ .then(() => { return test2(); }) >+ .then(() => { return test3(); }) >+ .then(() => { return test4(); }) >+ .then(() => { return test5(); }) >+ .then(() => { return test6(); }) >+ .then(() => { return test7(); }) >+ .then(() => { guard.done(); }); >+ >+</script> >diff --git a/LayoutTests/imported/w3c/web-platform-tests/resize-observer/resources/iframe.html b/LayoutTests/imported/w3c/web-platform-tests/resize-observer/resources/iframe.html >new file mode 100644 >index 0000000000..518317b520 >--- /dev/null >+++ b/LayoutTests/imported/w3c/web-platform-tests/resize-observer/resources/iframe.html >@@ -0,0 +1,38 @@ >+<!doctype html> >+<head> >+ <script src="./resizeTestHelper.js"></script> >+</head> >+<p>iframe test</p> >+<div id="itarget1" style="width:100px;height:100px;">t1</div> >+<script> >+'use strict'; >+let t1 = document.querySelector('#itarget1'); >+function test0() { >+ let timeoutId = window.setTimeout( () => { >+ window.parent.postMessage('fail', '*'); >+ }, ResizeTestHelper.TIMEOUT); >+ let ro = new ResizeObserver(function(entries) { >+ window.clearTimeout(timeoutId); >+ window.parent.postMessage('success', '*'); >+ }); >+ ro.observe(t1); >+} >+let testStarted = false; >+window.addEventListener('message', function(ev) { >+ switch(ev.data) { >+ case 'startTest': >+ testStarted = true; >+ test0(); >+ break; >+ } >+}); >+// How does parent know we've loaded problem is solved by >+// broadcasting readyToTest message repeatedly until test starts. >+function broadcastReady() { >+ if (!testStarted) { >+ window.parent.postMessage('readyToTest', '*'); >+ window.requestAnimationFrame(broadcastReady); >+ } >+} >+broadcastReady(); >+</script> >diff --git a/LayoutTests/imported/w3c/web-platform-tests/resize-observer/resources/resizeTestHelper.js b/LayoutTests/imported/w3c/web-platform-tests/resize-observer/resources/resizeTestHelper.js >new file mode 100644 >index 0000000000..60c681bd93 >--- /dev/null >+++ b/LayoutTests/imported/w3c/web-platform-tests/resize-observer/resources/resizeTestHelper.js >@@ -0,0 +1,148 @@ >+'use strict'; >+ >+/** >+ ResizeTestHelper is a framework to test ResizeObserver >+ notifications. Use it to make assertions about ResizeObserverEntries. >+ This framework is needed because ResizeObservations are >+ delivered asynchronously inside the event loop. >+ >+ Features: >+ - can queue multiple notification steps in a test >+ - handles timeouts >+ - returns Promise that is fullfilled when test completes. >+ Use to chain tests (since parallel async ResizeObserver tests >+ would conflict if reusing same DOM elements). >+ >+ Usage: >+ >+ create ResizeTestHelper for every test. >+ Make assertions inside notify, timeout callbacks. >+ Start tests with helper.start() >+ Chain tests with Promises. >+ Counts animation frames, see startCountingRaf >+*/ >+ >+/* >+ @param name: test name >+ @param steps: >+ { >+ setup: function(ResizeObserver) { >+ // called at the beginning of the test step >+ // your observe/resize code goes here >+ }, >+ notify: function(entries, observer) { >+ // ResizeObserver callback. >+ // Make assertions here. >+ // Return true if next step should start on the next event loop. >+ }, >+ timeout: function() { >+ // Define this if your test expects to time out. >+ // If undefined, timeout is assert_unreached. >+ } >+ } >+*/ >+function ResizeTestHelper(name, steps) >+{ >+ this._name = name; >+ this._steps = steps || []; >+ this._stepIdx = -1; >+ this._harnessTest = null; >+ this._observer = new ResizeObserver(this._handleNotification.bind(this)); >+ this._timeoutBind = this._handleTimeout.bind(this); >+ this._nextStepBind = this._nextStep.bind(this); >+} >+ >+ResizeTestHelper.TIMEOUT = 100; >+ >+ResizeTestHelper.prototype = { >+ get _currentStep() { >+ return this._steps[this._stepIdx]; >+ }, >+ >+ _nextStep: function() { >+ if (++this._stepIdx == this._steps.length) >+ return this._done(); >+ this._timeoutId = this._harnessTest.step_timeout( >+ this._timeoutBind, ResizeTestHelper.TIMEOUT); >+ try { >+ this._steps[this._stepIdx].setup(this._observer); >+ } >+ catch(err) { >+ this._harnessTest.step(() => { >+ assert_unreached("Caught a throw, possible syntax error"); >+ }); >+ } >+ }, >+ >+ _handleNotification: function(entries) { >+ if (this._timeoutId) { >+ window.clearTimeout(this._timeoutId); >+ delete this._timeoutId; >+ } >+ this._harnessTest.step(() => { >+ let rafDelay = this._currentStep.notify(entries, this._observer); >+ if (rafDelay) >+ window.requestAnimationFrame(this._nextStepBind); >+ else >+ this._nextStep(); >+ }); >+ }, >+ >+ _handleTimeout: function() { >+ delete this._timeoutId; >+ this._harnessTest.step(() => { >+ if (this._currentStep.timeout) { >+ this._currentStep.timeout(); >+ } >+ else { >+ assert_unreached("Timed out waiting for notification. (" + ResizeTestHelper.TIMEOUT + "ms)"); >+ } >+ this._nextStep(); >+ }); >+ }, >+ >+ _done: function() { >+ this._observer.disconnect(); >+ delete this._observer; >+ this._harnessTest.done(); >+ if (this._rafCountRequest) { >+ window.cancelAnimationFrame(this._rafCountRequest); >+ delete this._rafCountRequest; >+ } >+ window.requestAnimationFrame(() => { this._resolvePromise(); }); >+ }, >+ >+ start: function() { >+ this._harnessTest = async_test(this._name); >+ this._harnessTest.step(() => { >+ assert_equals(this._stepIdx, -1, "start can only be called once"); >+ this._nextStep(); >+ }); >+ return new Promise( (resolve, reject) => { >+ this._resolvePromise = resolve; >+ this._rejectPromise = reject; >+ }); >+ }, >+ >+ get rafCount() { >+ if (!this._rafCountRequest) >+ throw "rAF count is not active"; >+ return this._rafCount; >+ }, >+ >+ _incrementRaf: function() { >+ if (this._rafCountRequest) { >+ this._rafCount++; >+ this._rafCountRequest = window.requestAnimationFrame(this._incrementRafBind); >+ } >+ }, >+ >+ startCountingRaf: function() { >+ if (this._rafCountRequest) >+ window.cancelAnimationFrame(this._rafCountRequest); >+ if (!this._incrementRafBind) >+ this._incrementRafBind = this._incrementRaf.bind(this); >+ this._rafCount = 0; >+ this._rafCountRequest = window.requestAnimationFrame(this._incrementRafBind); >+ } >+} >diff --git a/LayoutTests/imported/w3c/web-platform-tests/resize-observer/resources/w3c-import.log b/LayoutTests/imported/w3c/web-platform-tests/resize-observer/resources/w3c-import.log >new file mode 100644 >index 0000000000..af37cea5fc >--- /dev/null >+++ b/LayoutTests/imported/w3c/web-platform-tests/resize-observer/resources/w3c-import.log >@@ -0,0 +1,18 @@ >+The tests in this directory were imported from the W3C repository. >+Do NOT modify these tests directly in WebKit. >+Instead, create a pull request on the WPT github: >+ https://github.com/web-platform-tests/wpt >+ >+Then run the Tools/Scripts/import-w3c-tests in WebKit to reimport >+ >+Do NOT modify or remove this file. >+ >+------------------------------------------------------------------------ >+Properties requiring vendor prefixes: >+None >+Property values requiring vendor prefixes: >+None >+------------------------------------------------------------------------ >+List of files: >+/LayoutTests/imported/w3c/web-platform-tests/resize-observer/resources/iframe.html >+/LayoutTests/imported/w3c/web-platform-tests/resize-observer/resources/resizeTestHelper.js >diff --git a/LayoutTests/imported/w3c/web-platform-tests/resize-observer/svg-expected.txt b/LayoutTests/imported/w3c/web-platform-tests/resize-observer/svg-expected.txt >new file mode 100644 >index 0000000000..c4483ea7ce >--- /dev/null >+++ b/LayoutTests/imported/w3c/web-platform-tests/resize-observer/svg-expected.txt >@@ -0,0 +1,12 @@ >+ResizeObserver svg tests >+ >+Here is a paragraph that requires word wrap >+ >+svg text tag >+ >+Harness Error (TIMEOUT), message = null >+ >+PASS ResizeObserver implemented >+NOTRUN guard >+FAIL test0: observe svg:circle assert_unreached: Timed out waiting for notification. (100ms) Reached unreachable code >+ >diff --git a/LayoutTests/imported/w3c/web-platform-tests/resize-observer/svg.html b/LayoutTests/imported/w3c/web-platform-tests/resize-observer/svg.html >new file mode 100644 >index 0000000000..49e5c1953e >--- /dev/null >+++ b/LayoutTests/imported/w3c/web-platform-tests/resize-observer/svg.html >@@ -0,0 +1,333 @@ >+<!doctype html><!-- webkit-test-runner [ experimental:ResizeObserverEnabled=true ] --> >+<script src="/resources/testharness.js"></script> >+<script src="/resources/testharnessreport.js"></script> >+<script src="./resources/resizeTestHelper.js"></script> >+<p>ResizeObserver svg tests</p> >+<svg height="430" width="500" > >+ <circle cx="10" cy="10" r="5" style="fill:orange;stroke:black;stroke-width:1" /> >+ <ellipse cx="10" cy="30" rx="5" ry="5" style="fill:orange;stroke:black;stroke-width:1"/> >+ <foreignObject cy="50" width="100" height="20"> >+ <body> >+ <p>Here is a paragraph that requires word wrap</p> >+ </body> >+ </foreignObject> >+ <image xlink:href="" x="0" y="100" height="30" width="100" /> >+ <line x1="0" y1="50" x2="20" y2="70" stroke="black" stroke-width="2"/> >+ <path d="M 0 100 L 100 100 L 50 150 z" >+ style="fill:orange;stroke:black;stroke-width:1" /> >+ <polygon points="0,200 100,200 50,250" style="fill:orange;stroke:black;stroke-width:1" /> >+ <polyline points="0,300 100,300 50,350" style="fill:orange;stroke:black;stroke-width:1"/> >+ <rect x="0" y="380" width="10" height="10" style="fill:orange; stroke:black; stroke-width:1" /> >+ <text x="0" y="400" font-size="20">svg text tag</text> >+</svg> >+<script> >+'use strict'; >+ >+setup({allow_uncaught_exception: true}); >+ >+function test0() { >+ let target = document.querySelector('circle'); >+ let helper = new ResizeTestHelper( >+ "test0: observe svg:circle", >+ [ >+ { >+ setup: observer => { >+ observer.observe(target); >+ }, >+ notify: (entries, observer) => { >+ return true; // Delay next step >+ } >+ }, >+ { >+ setup: observer => { >+ target.setAttribute('r', 10); >+ }, >+ notify: (entries, observer) => { >+ assert_equals(entries.length, 1); >+ } >+ } >+ ]); >+ return helper.start(); >+} >+ >+function test1() { >+ let target = document.querySelector('ellipse'); >+ let helper = new ResizeTestHelper( >+ "test1: observe svg:ellipse", >+ [ >+ { >+ setup: observer => { >+ observer.observe(target); >+ }, >+ notify: (entries, observer) => { >+ return true; // Delay next step >+ } >+ }, >+ { >+ setup: observer => { >+ target.setAttribute('rx', 10); >+ }, >+ notify: (entries, observer) => { >+ assert_equals(entries.length, 1); >+ assert_equals(entries[0].contentRect.width, 20); >+ assert_equals(entries[0].contentRect.height, 10); >+ } >+ } >+ ]); >+ return helper.start(); >+} >+ >+function test2() { >+ let target = document.querySelector('foreignObject'); >+ let helper = new ResizeTestHelper( >+ "test2: observe svg:foreignObject", >+ [ >+ { >+ setup: observer => { >+ observer.observe(target); >+ }, >+ notify: (entries, observer) => { >+ return true; // Delay next step >+ } >+ }, >+ { >+ setup: observer => { >+ target.setAttribute('width', 200); >+ }, >+ notify: (entries, observer) => { >+ assert_equals(entries.length, 1); >+ assert_equals(entries[0].contentRect.width, 200); >+ assert_equals(entries[0].contentRect.height, 20); >+ } >+ } >+ ]); >+ return helper.start(); >+} >+ >+function test3() { >+ let target = document.querySelector('image'); >+ let helper = new ResizeTestHelper( >+ "test3: observe svg:image", >+ [ >+ { >+ setup: observer => { >+ observer.observe(target); >+ }, >+ notify: (entries, observer) => { >+ return true; // Delay next step >+ } >+ }, >+ { >+ setup: observer => { >+ target.setAttribute('height', 40); >+ }, >+ notify: (entries, observer) => { >+ assert_equals(entries.length, 1); >+ assert_equals(entries[0].contentRect.width, 100); >+ assert_equals(entries[0].contentRect.height, 40); >+ } >+ } >+ ]); >+ return helper.start(); >+} >+ >+function test4() { >+ let target = document.querySelector('line'); >+ let helper = new ResizeTestHelper( >+ "test4: observe svg:line", >+ [ >+ { >+ setup: observer => { >+ observer.observe(target); >+ }, >+ notify: (entries, observer) => { >+ return true; // Delay next step >+ } >+ }, >+ { >+ setup: observer => { >+ target.setAttribute('y2', 80); >+ }, >+ notify: (entries, observer) => { >+ assert_equals(entries.length, 1); >+ assert_equals(entries[0].contentRect.width, 20); >+ assert_equals(entries[0].contentRect.height, 30); >+ } >+ } >+ ]); >+ return helper.start(); >+} >+ >+function test5() { >+ let target = document.querySelector('path'); >+ let helper = new ResizeTestHelper( >+ "test5: observe svg:path", >+ [ >+ { >+ setup: observer => { >+ observer.observe(target); >+ }, >+ notify: (entries, observer) => { >+ return true; // Delay next step >+ } >+ }, >+ { >+ setup: observer => { >+ target.setAttribute('d', "M 0 100 L 100 100 L 50 160 z"); >+ }, >+ notify: (entries, observer) => { >+ assert_equals(entries.length, 1); >+ assert_equals(entries[0].contentRect.width, 100); >+ assert_equals(entries[0].contentRect.height, 60); >+ } >+ } >+ ]); >+ return helper.start(); >+} >+ >+function test6() { >+ let target = document.querySelector('polygon'); >+ let helper = new ResizeTestHelper( >+ "test6: observe svg:path", >+ [ >+ { >+ setup: observer => { >+ observer.observe(target); >+ }, >+ notify: (entries, observer) => { >+ return true; // Delay next step >+ } >+ }, >+ { >+ setup: observer => { >+ target.setAttribute('points', "0,200 100,200 50,260"); >+ }, >+ notify: (entries, observer) => { >+ assert_equals(entries.length, 1); >+ assert_equals(entries[0].contentRect.width, 100); >+ assert_equals(entries[0].contentRect.height, 60); >+ } >+ } >+ ]); >+ return helper.start(); >+} >+ >+function test7() { >+ let target = document.querySelector('polyline'); >+ let helper = new ResizeTestHelper( >+ "test7: observe svg:polyline", >+ [ >+ { >+ setup: observer => { >+ observer.observe(target); >+ }, >+ notify: (entries, observer) => { >+ return true; // Delay next step >+ } >+ }, >+ { >+ setup: observer => { >+ target.setAttribute('points', "0,300 100,300 50,360"); >+ }, >+ notify: (entries, observer) => { >+ assert_equals(entries.length, 1); >+ assert_equals(entries[0].contentRect.width, 100); >+ assert_equals(entries[0].contentRect.height, 60); >+ } >+ } >+ ]); >+ return helper.start(); >+} >+ >+function test8() { >+ let target = document.querySelector('rect'); >+ let helper = new ResizeTestHelper( >+ "test8: observe svg:rect", >+ [ >+ { >+ setup: observer => { >+ observer.observe(target); >+ }, >+ notify: (entries, observer) => { >+ return true; // Delay next step >+ } >+ }, >+ { >+ setup: observer => { >+ target.setAttribute('width', "20"); >+ }, >+ notify: (entries, observer) => { >+ assert_equals(entries.length, 1); >+ assert_equals(entries[0].contentRect.width, 20); >+ assert_equals(entries[0].contentRect.height, 10); >+ } >+ } >+ ]); >+ return helper.start(); >+} >+ >+function test9() { >+ let target = document.querySelector('text'); >+ let helper = new ResizeTestHelper( >+ "test9: observe svg:text", >+ [ >+ { >+ setup: observer => { >+ observer.observe(target); >+ }, >+ notify: (entries, observer) => { >+ return true; // Delay next step >+ } >+ }, >+ { >+ setup: observer => { >+ target.setAttribute('font-size', "25"); >+ }, >+ notify: (entries, observer) => { >+ assert_equals(entries.length, 1); >+ } >+ } >+ ]); >+ return helper.start(); >+} >+ >+ >+function test10() { >+ let target = document.querySelector('svg'); >+ let helper = new ResizeTestHelper( >+ "test10: observe svg:svg, top/left is 0 even with padding", >+ [ >+ { >+ setup: observer => { >+ observer.observe(target); >+ }, >+ notify: (entries, observer) => { >+ assert_equals(entries.length, 1); >+ assert_equals(entries[0].contentRect.top, 0); >+ assert_equals(entries[0].contentRect.left, 0); >+ } >+ } >+ ]); >+ return helper.start(); >+} >+ >+let guard; >+test(_ => { >+ assert_own_property(window, "ResizeObserver"); >+ guard = async_test('guard'); >+}, "ResizeObserver implemented") >+ >+test0() >+ .then(() => { return test1(); }) >+ .then(() => { return test2(); }) >+ .then(() => { return test3(); }) >+ .then(() => { return test4(); }) >+ .then(() => { return test5(); }) >+ .then(() => { return test6(); }) >+ .then(() => { return test7(); }) >+ .then(() => { return test8(); }) >+ .then(() => { return test9(); }) >+ .then(() => { return test10(); }) >+ .then(() => { guard.done(); }); >+ >+</script> >diff --git a/LayoutTests/imported/w3c/web-platform-tests/resize-observer/w3c-import.log b/LayoutTests/imported/w3c/web-platform-tests/resize-observer/w3c-import.log >new file mode 100644 >index 0000000000..5641eec2c8 >--- /dev/null >+++ b/LayoutTests/imported/w3c/web-platform-tests/resize-observer/w3c-import.log >@@ -0,0 +1,22 @@ >+The tests in this directory were imported from the W3C repository. >+Do NOT modify these tests directly in WebKit. >+Instead, create a pull request on the WPT github: >+ https://github.com/web-platform-tests/wpt >+ >+Then run the Tools/Scripts/import-w3c-tests in WebKit to reimport >+ >+Do NOT modify or remove this file. >+ >+------------------------------------------------------------------------ >+Properties requiring vendor prefixes: >+None >+Property values requiring vendor prefixes: >+None >+------------------------------------------------------------------------ >+List of files: >+/LayoutTests/imported/w3c/web-platform-tests/resize-observer/META.yml >+/LayoutTests/imported/w3c/web-platform-tests/resize-observer/eventloop.html >+/LayoutTests/imported/w3c/web-platform-tests/resize-observer/idlharness.window.js >+/LayoutTests/imported/w3c/web-platform-tests/resize-observer/notify.html >+/LayoutTests/imported/w3c/web-platform-tests/resize-observer/observe.html >+/LayoutTests/imported/w3c/web-platform-tests/resize-observer/svg.html >diff --git a/Source/WebCore/CMakeLists.txt b/Source/WebCore/CMakeLists.txt >index 482cf6fd59..8147f7e771 100644 >--- a/Source/WebCore/CMakeLists.txt >+++ b/Source/WebCore/CMakeLists.txt >@@ -925,6 +925,9 @@ set(WebCore_NON_SVG_IDL_FILES > page/PerformanceServerTiming.idl > page/PerformanceTiming.idl > page/RemoteDOMWindow.idl >+ page/ResizeObserver.idl >+ page/ResizeObserverCallback.idl >+ page/ResizeObserverEntry.idl > page/Screen.idl > page/ScrollIntoViewOptions.idl > page/ScrollLogicalPosition.idl >diff --git a/Source/WebCore/DerivedSources.make b/Source/WebCore/DerivedSources.make >index cd6757664e..556629cb81 100644 >--- a/Source/WebCore/DerivedSources.make >+++ b/Source/WebCore/DerivedSources.make >@@ -873,6 +873,9 @@ JS_BINDING_IDLS = \ > $(WebCore)/page/PerformanceServerTiming.idl \ > $(WebCore)/page/PerformanceTiming.idl \ > $(WebCore)/page/RemoteDOMWindow.idl \ >+ $(WebCore)/page/ResizeObserver.idl \ >+ $(WebCore)/page/ResizeObserverCallback.idl \ >+ $(WebCore)/page/ResizeObserverEntry.idl \ > $(WebCore)/page/Screen.idl \ > $(WebCore)/page/ScrollIntoViewOptions.idl \ > $(WebCore)/page/ScrollLogicalPosition.idl \ >diff --git a/Source/WebCore/Sources.txt b/Source/WebCore/Sources.txt >index de5421f8f8..e98a855000 100644 >--- a/Source/WebCore/Sources.txt >+++ b/Source/WebCore/Sources.txt >@@ -1529,6 +1529,8 @@ page/ProcessWarming.cpp > page/Quirks.cpp > page/RemoteDOMWindow.cpp > page/RemoteFrame.cpp >+page/ResizeObservation.cpp >+page/ResizeObserver.cpp > page/ResourceUsageOverlay.cpp > page/ResourceUsageThread.cpp > page/RuntimeEnabledFeatures.cpp >diff --git a/Source/WebCore/bindings/js/WebCoreBuiltinNames.h b/Source/WebCore/bindings/js/WebCoreBuiltinNames.h >index 183fe8a885..a0a2265d6a 100644 >--- a/Source/WebCore/bindings/js/WebCoreBuiltinNames.h >+++ b/Source/WebCore/bindings/js/WebCoreBuiltinNames.h >@@ -145,6 +145,8 @@ namespace WebCore { > macro(PerformanceServerTiming) \ > macro(PointerEvent) \ > macro(PublicKeyCredential) \ >+ macro(ResizeObserver) \ >+ macro(ResizeObserverEntry) \ > macro(RTCCertificate) \ > macro(RTCDTMFSender) \ > macro(RTCDTMFToneChangeEvent) \ >diff --git a/Source/WebCore/dom/Document.cpp b/Source/WebCore/dom/Document.cpp >index 6d443e7866..91d9d2eb3e 100644 >--- a/Source/WebCore/dom/Document.cpp >+++ b/Source/WebCore/dom/Document.cpp >@@ -161,6 +161,7 @@ > #include "RenderView.h" > #include "RenderWidget.h" > #include "RequestAnimationFrameCallback.h" >+#include "ResizeObserver.h" > #include "ResourceLoadObserver.h" > #include "RuntimeApplicationChecks.h" > #include "RuntimeEnabledFeatures.h" >@@ -8035,6 +8036,19 @@ void Document::notifyIntersectionObserversTimerFired() > } > #endif > >+#if ENABLE(RESIZE_OBSERVER) >+void Document::addResizeObserver(ResizeObserver& observer) >+{ >+ ASSERT(m_resizeObservers.find(&observer) == notFound); >+ m_resizeObservers.append(makeWeakPtr(&observer)); >+} >+ >+void Document::removeResizeObserver(ResizeObserver& observer) >+{ >+ m_resizeObservers.removeFirst(&observer); >+} >+#endif >+ > const AtomicString& Document::dir() const > { > auto* documentElement = this->documentElement(); >diff --git a/Source/WebCore/dom/Document.h b/Source/WebCore/dom/Document.h >index 30f0ee67c9..fda1905380 100644 >--- a/Source/WebCore/dom/Document.h >+++ b/Source/WebCore/dom/Document.h >@@ -246,6 +246,10 @@ class HTMLAttachmentElement; > class IntersectionObserver; > #endif > >+#if ENABLE(RESIZE_OBSERVER) >+class ResizeObserver; >+#endif >+ > namespace Style { > class Scope; > }; >@@ -1416,6 +1420,11 @@ public: > void updateIntersectionObservations(); > #endif > >+#if ENABLE(RESIZE_OBSERVER) >+ void addResizeObserver(ResizeObserver&); >+ void removeResizeObserver(ResizeObserver&); >+#endif >+ > #if ENABLE(MEDIA_STREAM) > void setHasCaptureMediaStreamTrack() { m_hasHadCaptureMediaStreamTrack = true; } > bool hasHadCaptureMediaStreamTrack() const { return m_hasHadCaptureMediaStreamTrack; } >@@ -1862,6 +1871,10 @@ private: > Timer m_intersectionObserversNotifyTimer; > #endif > >+#if ENABLE(RESIZE_OBSERVER) >+ Vector<WeakPtr<ResizeObserver>> m_resizeObservers; >+#endif >+ > Timer m_loadEventDelayTimer; > > ViewportArguments m_viewportArguments; >diff --git a/Source/WebCore/dom/Element.cpp b/Source/WebCore/dom/Element.cpp >index ea5493a5a2..1d6cdf6245 100644 >--- a/Source/WebCore/dom/Element.cpp >+++ b/Source/WebCore/dom/Element.cpp >@@ -194,6 +194,10 @@ Element::~Element() > disconnectFromIntersectionObservers(); > #endif > >+#if ENABLE(RESIZE_OBSERVER) >+ disconnectFromResizeObservers(); >+#endif >+ > removeShadowRoot(); > > if (hasSyntheticAttrChildNodes()) >@@ -1837,6 +1841,10 @@ void Element::didMoveToNewDocument(Document& oldDocument, Document& newDocument) > } > } > #endif >+ >+#if ENABLE(RESIZE_OBSERVER) >+ disconnectFromResizeObservers(); >+#endif > } > > bool Element::hasAttributes() const >@@ -3470,6 +3478,32 @@ IntersectionObserverData* Element::intersectionObserverData() > } > #endif > >+#if ENABLE(RESIZE_OBSERVER) >+void Element::disconnectFromResizeObservers() >+{ >+ auto* observerData = resizeObserverData(); >+ if (!observerData) >+ return; >+ >+ for (const auto& observer : observerData->observers) >+ observer->targetDestroyed(*this); >+ observerData->observers.clear(); >+} >+ >+ResizeObserverData& Element::ensureResizeObserverData() >+{ >+ auto& rareData = ensureElementRareData(); >+ if (!rareData.resizeObserverData()) >+ rareData.setResizeObserverData(std::make_unique<ResizeObserverData>()); >+ return *rareData.resizeObserverData(); >+} >+ >+ResizeObserverData* Element::resizeObserverData() >+{ >+ return hasRareData() ? elementRareData()->resizeObserverData() : nullptr; >+} >+#endif >+ > SpellcheckAttributeState Element::spellcheckAttributeState() const > { > const AtomicString& value = attributeWithoutSynchronization(HTMLNames::spellcheckAttr); >diff --git a/Source/WebCore/dom/Element.h b/Source/WebCore/dom/Element.h >index c5eb6cb8c4..d080dd290c 100644 >--- a/Source/WebCore/dom/Element.h >+++ b/Source/WebCore/dom/Element.h >@@ -63,6 +63,10 @@ struct ScrollIntoViewOptions; > struct IntersectionObserverData; > #endif > >+#if ENABLE(RESIZE_OBSERVER) >+struct ResizeObserverData; >+#endif >+ > enum SpellcheckAttributeState { > SpellcheckAttributeTrue, > SpellcheckAttributeFalse, >@@ -583,6 +587,11 @@ public: > IntersectionObserverData* intersectionObserverData(); > #endif > >+#if ENABLE(RESIZE_OBSERVER) >+ ResizeObserverData& ensureResizeObserverData(); >+ ResizeObserverData* resizeObserverData(); >+#endif >+ > Element* findAnchorElementForLink(String& outAnchorName); > > ExceptionOr<Ref<WebAnimation>> animate(JSC::ExecState&, JSC::Strong<JSC::JSObject>&&, Optional<Variant<double, KeyframeAnimationOptions>>&&); >@@ -669,6 +678,10 @@ private: > void disconnectFromIntersectionObservers(); > #endif > >+#if ENABLE(RESIZE_OBSERVER) >+ void disconnectFromResizeObservers(); >+#endif >+ > // The cloneNode function is private so that non-virtual cloneElementWith/WithoutChildren are used instead. > Ref<Node> cloneNodeInternal(Document&, CloningOperation) override; > virtual Ref<Element> cloneElementWithoutAttributesAndChildren(Document&); >diff --git a/Source/WebCore/dom/ElementRareData.cpp b/Source/WebCore/dom/ElementRareData.cpp >index 4dd60eb84f..140b898900 100644 >--- a/Source/WebCore/dom/ElementRareData.cpp >+++ b/Source/WebCore/dom/ElementRareData.cpp >@@ -50,6 +50,9 @@ struct SameSizeAsElementRareData : NodeRareData { > #if ENABLE(CSS_TYPED_OM) > void* typedOMData; > #endif >+#if ENABLE(RESIZE_OBSERVER) >+ void* resizeObserverData; >+#endif > > }; > >diff --git a/Source/WebCore/dom/ElementRareData.h b/Source/WebCore/dom/ElementRareData.h >index fe80e331d5..8e106fb8a5 100644 >--- a/Source/WebCore/dom/ElementRareData.h >+++ b/Source/WebCore/dom/ElementRareData.h >@@ -29,6 +29,7 @@ > #include "NodeRareData.h" > #include "PseudoElement.h" > #include "RenderElement.h" >+#include "ResizeObserver.h" > #include "ShadowRoot.h" > #include "StylePropertyMap.h" > >@@ -128,6 +129,11 @@ public: > void setIntersectionObserverData(std::unique_ptr<IntersectionObserverData>&& data) { m_intersectionObserverData = WTFMove(data); } > #endif > >+#if ENABLE(RESIZE_OBSERVER) >+ ResizeObserverData* resizeObserverData() { return m_resizeObserverData.get(); } >+ void setResizeObserverData(std::unique_ptr<ResizeObserverData>&& data) { m_resizeObserverData = WTFMove(data); } >+#endif >+ > #if ENABLE(CSS_TYPED_OM) > StylePropertyMap* attributeStyleMap() { return m_attributeStyleMap.get(); } > void setAttributeStyleMap(Ref<StylePropertyMap>&& map) { m_attributeStyleMap = WTFMove(map); } >@@ -162,6 +168,8 @@ public: > result.add(UseType::AttributeMap); > if (m_intersectionObserverData) > result.add(UseType::InteractionObserver); >+ if (m_resizeObserverData) >+ result.add(UseType::ResizeObserver); > if (m_beforePseudoElement || m_afterPseudoElement) > result.add(UseType::PseudoElements); > return result; >@@ -205,6 +213,10 @@ private: > std::unique_ptr<IntersectionObserverData> m_intersectionObserverData; > #endif > >+#if ENABLE(RESIZE_OBSERVER) >+ std::unique_ptr<ResizeObserverData> m_resizeObserverData; >+#endif >+ > RefPtr<PseudoElement> m_beforePseudoElement; > RefPtr<PseudoElement> m_afterPseudoElement; > >diff --git a/Source/WebCore/page/ResizeObservation.cpp b/Source/WebCore/page/ResizeObservation.cpp >new file mode 100644 >index 0000000000..f0882d3d19 >--- /dev/null >+++ b/Source/WebCore/page/ResizeObservation.cpp >@@ -0,0 +1,50 @@ >+/* >+ * 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" >+ >+#if ENABLE(RESIZE_OBSERVER) >+#include "ResizeObservation.h" >+ >+namespace WebCore { >+ >+ResizeObservation::ResizeObservation(Element* element) >+ : m_target(element) >+ , m_observationSize(0, 0) >+{ >+} >+ >+ResizeObservation::~ResizeObservation() >+{ >+} >+ >+void ResizeObservation::setObservationSize(const LayoutSize& size) >+{ >+ m_observationSize = size; >+} >+ >+} // namespace WebCore >+ >+#endif // ENABLE(RESIZE_OBSERVER) >diff --git a/Source/WebCore/page/ResizeObservation.h b/Source/WebCore/page/ResizeObservation.h >new file mode 100644 >index 0000000000..789e6a3d71 >--- /dev/null >+++ b/Source/WebCore/page/ResizeObservation.h >@@ -0,0 +1,55 @@ >+/* >+ * 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. >+ */ >+ >+#pragma once >+ >+#if ENABLE(RESIZE_OBSERVER) >+#include "LayoutSize.h" >+ >+#include <wtf/RefCounted.h> >+ >+namespace WebCore { >+ >+class Element; >+ >+class ResizeObservation : public RefCounted<ResizeObservation> { >+ WTF_MAKE_FAST_ALLOCATED; >+public: >+ ResizeObservation(Element* target); >+ ~ResizeObservation(); >+ void setObservationSize(const LayoutSize&); >+ Element* target() { return m_target; } >+ LayoutSize observationSize() { return m_observationSize; } >+ >+private: >+ >+ Element* m_target; >+ // target size in last observation >+ LayoutSize m_observationSize; >+}; >+ >+} // namespace WebCore >+ >+#endif // ENABLE(RESIZE_OBSERVER) >diff --git a/Source/WebCore/page/ResizeObserver.cpp b/Source/WebCore/page/ResizeObserver.cpp >new file mode 100644 >index 0000000000..ead9861f40 >--- /dev/null >+++ b/Source/WebCore/page/ResizeObserver.cpp >@@ -0,0 +1,146 @@ >+/* >+ * 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" >+ >+#if ENABLE(RESIZE_OBSERVER) >+#include "ResizeObserver.h" >+ >+#include "Element.h" >+ >+namespace WebCore { >+Ref<ResizeObserver> ResizeObserver::create(Document& document, Ref<ResizeObserverCallback>&& callback) >+{ >+ return WTF::adoptRef(*new ResizeObserver(document, WTFMove(callback))); >+} >+ >+ResizeObserver::ResizeObserver(Document& document, Ref<ResizeObserverCallback>&& callback) >+ : ActiveDOMObject(downcast<Document>(callback->scriptExecutionContext())) >+ , m_callback(WTFMove(callback)) >+{ >+ m_document = makeWeakPtr(document); >+ suspendIfNeeded(); >+} >+ >+ResizeObserver::~ResizeObserver() >+{ >+ disconnect(); >+} >+ >+void ResizeObserver::observe(Element& target) >+{ >+ if (!m_callback) >+ return; >+ >+ for (auto observation : m_observations) { >+ if (observation->target() == &target) >+ return; >+ } >+ >+ auto& observerData = target.ensureResizeObserverData(); >+ observerData.observers.append(makeWeakPtr(this)); >+ if (!hasObservations()) >+ m_document->addResizeObserver(*this); >+ >+ m_observations.append(WTF::adoptRef(new ResizeObservation(&target))); >+ >+} >+ >+void ResizeObserver::unobserve(Element& target) >+{ >+ if (!removeTarget(target)) >+ return; >+ >+ removeObservation(target); >+ >+ if (!hasObservations()) >+ m_document->removeResizeObserver(*this); >+ >+} >+ >+void ResizeObserver::disconnect() >+{ >+ removeAllTargets(); >+ m_document->removeResizeObserver(*this); >+} >+ >+void ResizeObserver::removeAllTargets() >+{ >+ for (auto observation : m_observations) { >+ bool removed = removeTarget(*observation->target()); >+ ASSERT_UNUSED(removed, removed); >+ } >+ m_observations.clear(); >+} >+ >+bool ResizeObserver::removeTarget(Element& target) >+{ >+ auto* observerData = target.resizeObserverData(); >+ if (!observerData) >+ return false; >+ >+ auto& observers = observerData->observers; >+ return observers.removeFirst(this); >+} >+ >+void ResizeObserver::targetDestroyed(Element& target) >+{ >+ removeObservation(target); >+ if (!hasObservations()) >+ m_document->removeResizeObserver(*this); >+} >+ >+bool ResizeObserver::removeObservation(Element& target) >+{ >+ return m_observations.removeFirstMatching([&target](auto& observation) { >+ return observation->target() == ⌖ >+ }); >+} >+ >+bool ResizeObserver::hasPendingActivity() const >+{ >+ // TODO: cc. Need add the conditions when ResizeObserver is complete. >+ return hasObservations() && m_document; >+} >+ >+const char* ResizeObserver::activeDOMObjectName() const >+{ >+ return "ResizeObserver"; >+} >+ >+bool ResizeObserver::canSuspendForDocumentSuspension() const >+{ >+ return true; >+} >+ >+void ResizeObserver::stop() >+{ >+ disconnect(); >+ m_callback = nullptr; >+} >+ >+} // namespace WebCore >+ >+#endif // ENABLE(RESIZE_OBSERVER) >diff --git a/Source/WebCore/page/ResizeObserver.h b/Source/WebCore/page/ResizeObserver.h >new file mode 100644 >index 0000000000..c5e2eb12ed >--- /dev/null >+++ b/Source/WebCore/page/ResizeObserver.h >@@ -0,0 +1,80 @@ >+/* >+ * 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. >+ */ >+ >+#pragma once >+ >+#if ENABLE(RESIZE_OBSERVER) >+ >+#include "ActiveDOMObject.h" >+#include "ResizeObservation.h" >+#include "ResizeObserverCallback.h" >+#include <wtf/RefCounted.h> >+#include <wtf/WeakPtr.h> >+ >+namespace WebCore { >+ >+class Document; >+class Element; >+ >+struct ResizeObserverData { >+ Vector<WeakPtr<ResizeObserver>> observers; >+}; >+ >+class ResizeObserver : public RefCounted<ResizeObserver>, public ActiveDOMObject, public CanMakeWeakPtr<ResizeObserver> { >+ WTF_MAKE_FAST_ALLOCATED; >+public: >+ static Ref<ResizeObserver> create(Document&, Ref<ResizeObserverCallback>&&); >+ ~ResizeObserver(); >+ >+ const Vector<RefPtr<ResizeObservation>> observations() const { return m_observations; } >+ bool hasObservations() const { return m_observations.size(); } >+ >+ void observe(Element&); >+ void unobserve(Element&); >+ void disconnect(); >+ >+ void targetDestroyed(Element&); >+ >+ // ActiveDOMObject. >+ bool hasPendingActivity() const override; >+ const char* activeDOMObjectName() const override; >+ bool canSuspendForDocumentSuspension() const override; >+ void stop() override; >+ >+private: >+ ResizeObserver(Document&, Ref<ResizeObserverCallback>&&); >+ >+ void removeAllTargets(); >+ bool removeTarget(Element&); >+ bool removeObservation(Element&); >+ >+ WeakPtr<Document> m_document; >+ RefPtr<ResizeObserverCallback> m_callback; >+ Vector<RefPtr<ResizeObservation>> m_observations; >+}; >+ >+} // namespace WebCore >+ >+#endif // ENABLE(RESIZE_OBSERVER) >diff --git a/Source/WebCore/page/ResizeObserver.idl b/Source/WebCore/page/ResizeObserver.idl >new file mode 100644 >index 0000000000..87f80106ad >--- /dev/null >+++ b/Source/WebCore/page/ResizeObserver.idl >@@ -0,0 +1,38 @@ >+/* >+ * 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. >+ */ >+ >+// https://wicg.github.io/ResizeObserver/ >+ >+[ >+ ActiveDOMObject, >+ Conditional=RESIZE_OBSERVER, >+ Constructor(ResizeObserverCallback callback), >+ ConstructorCallWith=Document, >+ EnabledBySetting=ResizeObserver >+] interface ResizeObserver { >+ void observe(Element target); >+ void unobserve(Element target); >+ void disconnect(); >+}; >diff --git a/Source/WebCore/page/ResizeObserverCallback.h b/Source/WebCore/page/ResizeObserverCallback.h >new file mode 100644 >index 0000000000..b39d7626f6 >--- /dev/null >+++ b/Source/WebCore/page/ResizeObserverCallback.h >@@ -0,0 +1,47 @@ >+/* >+ * 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. >+ */ >+ >+#pragma once >+ >+#if ENABLE(RESIZE_OBSERVER) >+ >+#include "ActiveDOMCallback.h" >+#include "CallbackResult.h" >+#include <wtf/RefCounted.h> >+ >+namespace WebCore { >+ >+class ResizeObserver; >+class ResizeObserverEntry; >+ >+class ResizeObserverCallback : public RefCounted<ResizeObserverCallback>, public ActiveDOMCallback { >+public: >+ using ActiveDOMCallback::ActiveDOMCallback; >+ virtual CallbackResult<void> handleEvent(const Vector<Ref<ResizeObserverEntry>>&, ResizeObserver&) = 0; >+}; >+ >+} // namespace WebCore >+ >+#endif // ENABLE(RESIZE_OBSERVER) >diff --git a/Source/WebCore/page/ResizeObserverCallback.idl b/Source/WebCore/page/ResizeObserverCallback.idl >new file mode 100644 >index 0000000000..6fc9039235 >--- /dev/null >+++ b/Source/WebCore/page/ResizeObserverCallback.idl >@@ -0,0 +1,30 @@ >+/* >+ * 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. >+ */ >+ >+// https://wicg.github.io/ResizeObserver/ >+ >+[ >+ Conditional=RESIZE_OBSERVER >+] callback ResizeObserverCallback = void (sequence<ResizeObserverEntry> entries, ResizeObserver observer); >diff --git a/Source/WebCore/page/ResizeObserverEntry.h b/Source/WebCore/page/ResizeObserverEntry.h >new file mode 100644 >index 0000000000..bd6041ce62 >--- /dev/null >+++ b/Source/WebCore/page/ResizeObserverEntry.h >@@ -0,0 +1,62 @@ >+/* >+ * 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. >+ */ >+ >+#pragma once >+ >+#if ENABLE(RESIZE_OBSERVER) >+ >+#include "DOMRectReadOnly.h" >+#include "Element.h" >+#include "FloatRect.h" >+#include <wtf/RefCounted.h> >+ >+namespace WebCore { >+ >+class Element; >+ >+class ResizeObserverEntry : public RefCounted<ResizeObserverEntry> { >+ WTF_MAKE_FAST_ALLOCATED; >+public: >+ static Ref<ResizeObserverEntry> create(Element* target, const FloatRect& contentRect) >+ { >+ return WTF::adoptRef(*new ResizeObserverEntry(target, contentRect)); >+ } >+ >+ Element* target() { return m_target.get(); } >+ DOMRectReadOnly* contentRect() { return m_contentRect.get(); } >+ >+private: >+ ResizeObserverEntry(Element* target, const FloatRect& contentRect) >+ : m_target(target) >+ { >+ m_contentRect = DOMRectReadOnly::create(contentRect.x(), contentRect.y(), contentRect.width(), contentRect.height()); >+ } >+ >+ RefPtr<Element> m_target; >+ RefPtr<DOMRectReadOnly> m_contentRect; >+}; >+ >+} // namespace WebCore >+#endif // ENABLE(RESIZE_OBSERVER) >diff --git a/Source/WebCore/page/ResizeObserverEntry.idl b/Source/WebCore/page/ResizeObserverEntry.idl >new file mode 100644 >index 0000000000..b051bb57be >--- /dev/null >+++ b/Source/WebCore/page/ResizeObserverEntry.idl >@@ -0,0 +1,35 @@ >+/* >+ * 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. >+ */ >+ >+// https://wicg.github.io/ResizeObserver/ >+ >+[ >+ Conditional=RESIZE_OBSERVER, >+ ImplementationLacksVTable, >+ EnabledBySetting=ResizeObserver >+] interface ResizeObserverEntry { >+ readonly attribute Element target; >+ readonly attribute DOMRectReadOnly contentRect; >+}; >\ No newline at end of file >diff --git a/Source/WebCore/page/Settings.yaml b/Source/WebCore/page/Settings.yaml >index ca4c57c869..21f6058e53 100644 >--- a/Source/WebCore/page/Settings.yaml >+++ b/Source/WebCore/page/Settings.yaml >@@ -796,3 +796,7 @@ editableImagesEnabled: > > adClickAttributionEnabled: > initial: false >+ >+resizeObserverEnabled: >+ initial: false >+ conditional: RESIZE_OBSERVER >diff --git a/Source/WebKit/Shared/WebPreferences.yaml b/Source/WebKit/Shared/WebPreferences.yaml >index 9b0eacaa9b..146b856bbd 100644 >--- a/Source/WebKit/Shared/WebPreferences.yaml >+++ b/Source/WebKit/Shared/WebPreferences.yaml >@@ -1380,6 +1380,14 @@ ProcessSwapOnCrossSiteNavigationEnabled: > category: experimental > webcoreBinding: none > >+ResizeObserverEnabled: >+ type: bool >+ defaultValue: false >+ humanReadableName: "Resize Observer" >+ humanReadableDescription: "Enable Resize Observer support" >+ category: experimental >+ condition: ENABLE(RESIZE_OBSERVER) >+ > # For internal features: > # The type should be boolean. > # You must provide a humanReadableName and humanReadableDescription for all debug features. They >@@ -1551,3 +1559,11 @@ AdClickAttributionEnabled: > humanReadableDescription: "Enable Ad Click Attribution for Cross-Site Link Navigations" > webcoreBinding: RuntimeEnabledFeatures > category: internal >+ >+ResizeObserverEnabled: >+ type: bool >+ defaultValue: true >+ humanReadableName: "Resize Observer" >+ humanReadableDescription: "Enable Resize Observer support" >+ category: experimental >+ condition: ENABLE(RESIZE_OBSERVER) >diff --git a/Source/cmake/WebKitFeatures.cmake b/Source/cmake/WebKitFeatures.cmake >index f70b817312..ce2bc9e108 100644 >--- a/Source/cmake/WebKitFeatures.cmake >+++ b/Source/cmake/WebKitFeatures.cmake >@@ -183,6 +183,7 @@ macro(WEBKIT_OPTION_BEGIN) > WEBKIT_OPTION_DEFINE(ENABLE_PUBLIC_SUFFIX_LIST "Toggle public suffix list support" PRIVATE ON) > WEBKIT_OPTION_DEFINE(ENABLE_QUOTA "Toggle Quota support" PRIVATE OFF) > WEBKIT_OPTION_DEFINE(ENABLE_REMOTE_INSPECTOR "Toggle remote inspector support" PRIVATE ON) >+ WEBKIT_OPTION_DEFINE(ENABLE_RESIZE_OBSERVER "Enable Resize Observer support" PRIVATE ON) > WEBKIT_OPTION_DEFINE(ENABLE_RESOLUTION_MEDIA_QUERY "Toggle resolution media query support" PRIVATE OFF) > WEBKIT_OPTION_DEFINE(ENABLE_RESOURCE_LOAD_STATISTICS "Toggle resource load statistics support" PRIVATE OFF) > WEBKIT_OPTION_DEFINE(ENABLE_RESOURCE_USAGE "Toggle resource usage support" PRIVATE OFF) >diff --git a/Tools/DumpRenderTree/TestOptions.cpp b/Tools/DumpRenderTree/TestOptions.cpp >index c926612b1b..8215417a92 100644 >--- a/Tools/DumpRenderTree/TestOptions.cpp >+++ b/Tools/DumpRenderTree/TestOptions.cpp >@@ -111,6 +111,8 @@ TestOptions::TestOptions(const std::string& pathOrURL, const std::string& absolu > enableCSSLogical = parseBooleanTestHeaderValue(value); > else if (key == "internal:AdClickAttributionEnabled") > adClickAttributionEnabled = parseBooleanTestHeaderValue(value); >+ else if (key == "enableResizeObserver") >+ enableResizeObserver = parseBooleanTestHeaderValue(value); > pairStart = pairEnd + 1; > } > } >diff --git a/Tools/DumpRenderTree/TestOptions.h b/Tools/DumpRenderTree/TestOptions.h >index c27e842a48..d885edbdeb 100644 >--- a/Tools/DumpRenderTree/TestOptions.h >+++ b/Tools/DumpRenderTree/TestOptions.h >@@ -46,6 +46,7 @@ struct TestOptions { > bool enableWebGPU { false }; > bool enableCSSLogical { false }; > bool adClickAttributionEnabled { false }; >+ bool enableResizeObserver { false }; > std::string jscOptions; > > TestOptions(const std::string& pathOrURL, const std::string& absolutePath); >diff --git a/Tools/DumpRenderTree/mac/DumpRenderTree.mm b/Tools/DumpRenderTree/mac/DumpRenderTree.mm >index d3f58c77d2..e66c05f3fd 100644 >--- a/Tools/DumpRenderTree/mac/DumpRenderTree.mm >+++ b/Tools/DumpRenderTree/mac/DumpRenderTree.mm >@@ -1012,6 +1012,7 @@ static void setWebPreferencesForTestOptions(const TestOptions& options) > preferences.webGPUEnabled = options.enableWebGPU; > preferences.CSSLogicalEnabled = options.enableCSSLogical; > preferences.adClickAttributionEnabled = options.adClickAttributionEnabled; >+ preferences.resizeObserverEnabled = options.enableResizeObserver; > } > > // Called once on DumpRenderTree startup.
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Formatted Diff
|
Diff
Attachments on
bug 157743
:
359876
|
360287
|
360290
|
360291
|
361796
|
361805
|
361897
|
361903
|
361999
|
362000
|
362001
|
363087
|
363219
|
363505
|
363506
|
365042
|
365051
|
365064
|
365112
|
365120
|
365126
|
365128
|
365133
|
365144
|
365145
|
365146
|
365148
|
365149
|
365171
|
365187
|
365191
|
365209
|
365285
|
365301
|
365315
|
365319
|
365349
|
365479
|
365487
|
365493
|
365494
|
365510
|
365518
|
365522
|
365702
|
365711
|
365717
|
365720
|
365737
|
365953
|
365954
|
365969
|
365972
|
366015
|
366064
|
366073