[IntersectionObserver] Fire an initial dummy notification
authorajuma@chromium.org <ajuma@chromium.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sat, 18 Aug 2018 23:45:07 +0000 (23:45 +0000)
committerajuma@chromium.org <ajuma@chromium.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sat, 18 Aug 2018 23:45:07 +0000 (23:45 +0000)
https://bugs.webkit.org/show_bug.cgi?id=188670

Reviewed by Simon Fraser.

LayoutTests/imported/w3c:

Rebaseline tests now that an initial notification is fired.

* web-platform-tests/intersection-observer/bounding-box-expected.txt:
* web-platform-tests/intersection-observer/client-rect-expected.txt:
* web-platform-tests/intersection-observer/containing-block-expected.txt:
* web-platform-tests/intersection-observer/cross-origin-iframe-expected.txt:
* web-platform-tests/intersection-observer/disconnect-expected.txt:
* web-platform-tests/intersection-observer/display-none-expected.txt:
* web-platform-tests/intersection-observer/edge-inclusive-intersection-expected.txt:
* web-platform-tests/intersection-observer/iframe-no-root-expected.txt:
* web-platform-tests/intersection-observer/inline-client-rect-expected.txt:
* web-platform-tests/intersection-observer/isIntersecting-change-events-expected.txt:
* web-platform-tests/intersection-observer/multiple-targets-expected.txt:
* web-platform-tests/intersection-observer/multiple-thresholds-expected.txt:
* web-platform-tests/intersection-observer/observer-without-js-reference-expected.txt:
* web-platform-tests/intersection-observer/remove-element-expected.txt:
* web-platform-tests/intersection-observer/root-margin-expected.txt:
* web-platform-tests/intersection-observer/same-document-no-root-expected.txt:
* web-platform-tests/intersection-observer/same-document-root-expected.txt:
* web-platform-tests/intersection-observer/same-document-zero-size-target-expected.txt:
* web-platform-tests/intersection-observer/shadow-content-expected.txt:
* web-platform-tests/intersection-observer/text-target-expected.txt:
* web-platform-tests/intersection-observer/timestamp-expected.txt:
* web-platform-tests/intersection-observer/unclipped-root-expected.txt:
* web-platform-tests/intersection-observer/zero-area-element-hidden-expected.txt:
* web-platform-tests/intersection-observer/zero-area-element-visible-expected.txt:

Source/WebCore:

Add logic to track ongoing intersection observations. Create an IntersectionObserverRegistration
and fire a single dummy notification for each one.

Test: intersection-observer/root-element-moved.html
Also tested by existing tests in imported/w3c/web-platform-tests/intersection-observer.

* dom/Document.cpp:
(WebCore::Document::~Document):
(WebCore::Document::addIntersectionObserver):
(WebCore::Document::removeIntersectionObserver):
(WebCore::Document::updateIntersectionObservations):
(WebCore::Document::notifyIntersectionObserversTimerFired):
* dom/Document.h:
(WebCore::Document::numberOfIntersectionObservers const):
* dom/Element.cpp:
(WebCore::Element::didMoveToNewDocument):
(WebCore::Element::disconnectFromIntersectionObservers):
* page/IntersectionObserver.cpp:
(WebCore::IntersectionObserver::create):
(WebCore::IntersectionObserver::IntersectionObserver):
(WebCore::IntersectionObserver::~IntersectionObserver):
(WebCore::IntersectionObserver::observe):
(WebCore::IntersectionObserver::unobserve):
(WebCore::IntersectionObserver::disconnect):
(WebCore::IntersectionObserver::takeRecords):
(WebCore::IntersectionObserver::targetDestroyed):
(WebCore::IntersectionObserver::removeTargetRegistration):
(WebCore::IntersectionObserver::removeAllTargets):
(WebCore::IntersectionObserver::rootDestroyed):
(WebCore::IntersectionObserver::appendQueuedEntry):
(WebCore::IntersectionObserver::notify):
* page/IntersectionObserver.h:
(WebCore::IntersectionObserver::trackingDocument):
(WebCore::IntersectionObserver:: const):
(WebCore::IntersectionObserver::hasObservationTargets const):
* page/IntersectionObserver.idl:
* testing/Internals.cpp:
(WebCore::Internals::numberOfIntersectionObservers const):
* testing/Internals.h:
* testing/Internals.idl:

LayoutTests:

* intersection-observer/root-element-deleted.html: Add additional assertions.
* intersection-observer/root-element-moved-expected.txt: Added.
* intersection-observer/root-element-moved.html: Added.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@235014 268f45cc-cd09-0410-ab3c-d52691b4dbfc

39 files changed:
LayoutTests/ChangeLog
LayoutTests/imported/w3c/ChangeLog
LayoutTests/imported/w3c/web-platform-tests/intersection-observer/bounding-box-expected.txt
LayoutTests/imported/w3c/web-platform-tests/intersection-observer/client-rect-expected.txt
LayoutTests/imported/w3c/web-platform-tests/intersection-observer/containing-block-expected.txt
LayoutTests/imported/w3c/web-platform-tests/intersection-observer/cross-origin-iframe-expected.txt
LayoutTests/imported/w3c/web-platform-tests/intersection-observer/disconnect-expected.txt
LayoutTests/imported/w3c/web-platform-tests/intersection-observer/display-none-expected.txt
LayoutTests/imported/w3c/web-platform-tests/intersection-observer/edge-inclusive-intersection-expected.txt
LayoutTests/imported/w3c/web-platform-tests/intersection-observer/iframe-no-root-expected.txt
LayoutTests/imported/w3c/web-platform-tests/intersection-observer/inline-client-rect-expected.txt
LayoutTests/imported/w3c/web-platform-tests/intersection-observer/isIntersecting-change-events-expected.txt
LayoutTests/imported/w3c/web-platform-tests/intersection-observer/multiple-targets-expected.txt
LayoutTests/imported/w3c/web-platform-tests/intersection-observer/multiple-thresholds-expected.txt
LayoutTests/imported/w3c/web-platform-tests/intersection-observer/observer-without-js-reference-expected.txt
LayoutTests/imported/w3c/web-platform-tests/intersection-observer/remove-element-expected.txt
LayoutTests/imported/w3c/web-platform-tests/intersection-observer/root-margin-expected.txt
LayoutTests/imported/w3c/web-platform-tests/intersection-observer/same-document-no-root-expected.txt
LayoutTests/imported/w3c/web-platform-tests/intersection-observer/same-document-root-expected.txt
LayoutTests/imported/w3c/web-platform-tests/intersection-observer/same-document-zero-size-target-expected.txt
LayoutTests/imported/w3c/web-platform-tests/intersection-observer/shadow-content-expected.txt
LayoutTests/imported/w3c/web-platform-tests/intersection-observer/text-target-expected.txt
LayoutTests/imported/w3c/web-platform-tests/intersection-observer/timestamp-expected.txt
LayoutTests/imported/w3c/web-platform-tests/intersection-observer/unclipped-root-expected.txt
LayoutTests/imported/w3c/web-platform-tests/intersection-observer/zero-area-element-hidden-expected.txt
LayoutTests/imported/w3c/web-platform-tests/intersection-observer/zero-area-element-visible-expected.txt
LayoutTests/intersection-observer/root-element-deleted.html
LayoutTests/intersection-observer/root-element-moved-expected.txt [new file with mode: 0644]
LayoutTests/intersection-observer/root-element-moved.html [new file with mode: 0644]
Source/WebCore/ChangeLog
Source/WebCore/dom/Document.cpp
Source/WebCore/dom/Document.h
Source/WebCore/dom/Element.cpp
Source/WebCore/page/IntersectionObserver.cpp
Source/WebCore/page/IntersectionObserver.h
Source/WebCore/page/IntersectionObserver.idl
Source/WebCore/testing/Internals.cpp
Source/WebCore/testing/Internals.h
Source/WebCore/testing/Internals.idl

index 45f048a..3ac24c3 100644 (file)
@@ -1,3 +1,14 @@
+2018-08-18  Ali Juma  <ajuma@chromium.org>
+
+        [IntersectionObserver] Fire an initial dummy notification
+        https://bugs.webkit.org/show_bug.cgi?id=188670
+
+        Reviewed by Simon Fraser.
+
+        * intersection-observer/root-element-deleted.html: Add additional assertions.
+        * intersection-observer/root-element-moved-expected.txt: Added.
+        * intersection-observer/root-element-moved.html: Added.
+
 2018-08-17  John Wilander  <wilander@apple.com>
 
         Resource Load Statistics: Add layout test for web workers importing cross-site scripts
index f82e8fd..7cb688b 100644 (file)
@@ -1,3 +1,37 @@
+2018-08-18  Ali Juma  <ajuma@chromium.org>
+
+        [IntersectionObserver] Fire an initial dummy notification
+        https://bugs.webkit.org/show_bug.cgi?id=188670
+
+        Reviewed by Simon Fraser.
+
+        Rebaseline tests now that an initial notification is fired.
+
+        * web-platform-tests/intersection-observer/bounding-box-expected.txt:
+        * web-platform-tests/intersection-observer/client-rect-expected.txt:
+        * web-platform-tests/intersection-observer/containing-block-expected.txt:
+        * web-platform-tests/intersection-observer/cross-origin-iframe-expected.txt:
+        * web-platform-tests/intersection-observer/disconnect-expected.txt:
+        * web-platform-tests/intersection-observer/display-none-expected.txt:
+        * web-platform-tests/intersection-observer/edge-inclusive-intersection-expected.txt:
+        * web-platform-tests/intersection-observer/iframe-no-root-expected.txt:
+        * web-platform-tests/intersection-observer/inline-client-rect-expected.txt:
+        * web-platform-tests/intersection-observer/isIntersecting-change-events-expected.txt:
+        * web-platform-tests/intersection-observer/multiple-targets-expected.txt:
+        * web-platform-tests/intersection-observer/multiple-thresholds-expected.txt:
+        * web-platform-tests/intersection-observer/observer-without-js-reference-expected.txt:
+        * web-platform-tests/intersection-observer/remove-element-expected.txt:
+        * web-platform-tests/intersection-observer/root-margin-expected.txt:
+        * web-platform-tests/intersection-observer/same-document-no-root-expected.txt:
+        * web-platform-tests/intersection-observer/same-document-root-expected.txt:
+        * web-platform-tests/intersection-observer/same-document-zero-size-target-expected.txt:
+        * web-platform-tests/intersection-observer/shadow-content-expected.txt:
+        * web-platform-tests/intersection-observer/text-target-expected.txt:
+        * web-platform-tests/intersection-observer/timestamp-expected.txt:
+        * web-platform-tests/intersection-observer/unclipped-root-expected.txt:
+        * web-platform-tests/intersection-observer/zero-area-element-hidden-expected.txt:
+        * web-platform-tests/intersection-observer/zero-area-element-visible-expected.txt:
+
 2018-08-16  Ryosuke Niwa  <rniwa@webkit.org>
 
         Custom element constructor doesn't use HTMLElement in new.target's realm
index 50762b6..2a30215 100644 (file)
@@ -1,5 +1,5 @@
 
 PASS Test that the target's border bounding box is used to calculate intersection. 
-FAIL First rAF. assert_equals: entries.length expected 1 but got 0
-FAIL target.style.transform = 'translateY(195px)' assert_equals: entries.length expected 2 but got 0
+FAIL First rAF. assert_equals: entries[0].boundingClientRect.left expected 25 but got 0
+FAIL target.style.transform = 'translateY(195px)' assert_equals: entries.length expected 2 but got 1
 
index 08fc2c4..2d27f67 100644 (file)
@@ -1,4 +1,4 @@
 
 PASS IntersectionObserverEntry.boundingClientRect should match target.boundingClientRect() 
-FAIL First rAF should generate notification. assert_equals: One notification. expected 1 but got 0
+FAIL First rAF should generate notification. assert_equals: entries[0].boundingClientRect.left expected 8 but got 0
 
index 9eeb18e..73be024 100644 (file)
@@ -1,7 +1,7 @@
 
 PASS IntersectionObserver should only report intersections if root is a containing block ancestor of target. 
-FAIL In containing block and intersecting. assert_equals: entries.length expected 1 but got 0
-FAIL In containing block and not intersecting. assert_equals: entries.length expected 2 but got 0
-FAIL Not in containing block and intersecting. assert_equals: entries.length expected 2 but got 0
-FAIL Not in containing block and not intersecting. assert_equals: entries.length expected 2 but got 0
+FAIL In containing block and intersecting. assert_equals: entries[0].boundingClientRect.left expected 58 but got 0
+FAIL In containing block and not intersecting. assert_equals: entries.length expected 2 but got 1
+FAIL Not in containing block and intersecting. assert_equals: entries.length expected 2 but got 1
+FAIL Not in containing block and not intersecting. assert_equals: entries.length expected 2 but got 1
 
index f26709b..95c52cb 100644 (file)
@@ -1,7 +1,7 @@
 
 
 PASS Intersection observer test with no explicit root and target in a cross-origin iframe. 
-FAIL First rAF assert_equals: expected 1 but got 0
+PASS First rAF 
 PASS topDocument.scrollingElement.scrollTop = 200 
 FAIL iframeDocument.scrollingElement.scrollTop = 250 assert_equals: expected 1 but got 0
 FAIL topDocument.scrollingElement.scrollTop = 100 assert_equals: expected 1 but got 0
index 41df6e7..f88c12c 100644 (file)
@@ -1,5 +1,5 @@
 
 PASS IntersectionObserver should not deliver pending notifications after disconnect(). 
-FAIL First rAF. assert_equals: Initial notification. expected 1 but got 0
-FAIL observer.disconnect() assert_equals: No new notifications. expected 1 but got 0
+PASS First rAF. 
+PASS observer.disconnect() 
 
index 372a41f..967db20 100644 (file)
@@ -1,6 +1,6 @@
 
 PASS IntersectionObserver should send a not-intersecting notification for a target that gets display:none. 
-FAIL Intersecting notification after first rAF. assert_equals: entries.length expected 1 but got 0
-FAIL Not-intersecting notification after setting display:none on target. assert_equals: entries.length expected 2 but got 0
-FAIL Intersecting notification after removing display:none on target. assert_equals: entries.length expected 3 but got 0
+FAIL Intersecting notification after first rAF. assert_equals: entries[0].boundingClientRect.left expected 8 but got 0
+FAIL Not-intersecting notification after setting display:none on target. assert_equals: entries.length expected 2 but got 1
+FAIL Intersecting notification after removing display:none on target. assert_equals: entries.length expected 3 but got 1
 
index 6fd199f..c8595b0 100644 (file)
@@ -1,7 +1,7 @@
 
 PASS IntersectionObserver should detect and report edge-adjacent and zero-area intersections. 
-FAIL First rAF. assert_equals: entries.length expected 1 but got 0
-FAIL Set transform=translateY(200px) on target. assert_equals: entries.length expected 2 but got 0
-FAIL Set transform=translateY(201px) on target. assert_equals: entries.length expected 3 but got 0
-FAIL Set transform=translateY(185px) on target. assert_equals: entries.length expected 4 but got 0
+FAIL First rAF. assert_equals: entries[0].boundingClientRect.left expected 8 but got 0
+FAIL Set transform=translateY(200px) on target. assert_equals: entries.length expected 2 but got 1
+FAIL Set transform=translateY(201px) on target. assert_equals: entries.length expected 3 but got 1
+FAIL Set transform=translateY(185px) on target. assert_equals: entries.length expected 4 but got 1
 
index 9137bee..5daefcc 100644 (file)
@@ -1,8 +1,8 @@
 
 
 PASS Observer with the implicit root; target in a same-origin iframe. 
-FAIL First rAF. assert_equals: entries.length expected 1 but got 0
-FAIL document.scrollingElement.scrollTop = 200 assert_equals: entries.length == 1 expected 1 but got 0
-FAIL iframe.contentDocument.scrollingElement.scrollTop = 250 assert_equals: entries.length expected 2 but got 0
-FAIL document.scrollingElement.scrollTop = 100 assert_equals: entries.length expected 3 but got 0
+FAIL First rAF. assert_equals: entries[0].boundingClientRect.left expected 8 but got 0
+PASS document.scrollingElement.scrollTop = 200 
+FAIL iframe.contentDocument.scrollingElement.scrollTop = 250 assert_equals: entries.length expected 2 but got 1
+FAIL document.scrollingElement.scrollTop = 100 assert_equals: entries.length expected 3 but got 1
 
index 1ccadf0..eda4736 100644 (file)
@@ -1,6 +1,6 @@
 1 2 3 4 5
 
 PASS Inline target 
-FAIL First rAF assert_equals: entries.length expected 1 but got 0
-FAIL scroller.scrollLeft = 90 assert_equals: entries.length expected 2 but got 0
+FAIL First rAF assert_equals: entries[0].boundingClientRect.left expected 320 but got 0
+FAIL scroller.scrollLeft = 90 assert_equals: entries.length expected 2 but got 1
 
index 07d48f2..6669559 100644 (file)
@@ -1,4 +1,4 @@
 
 PASS isIntersecting changes should trigger notifications. 
-FAIL Rects in initial notifications should report initial positions. assert_equals: Has 3 initial notifications. expected 3 but got 0
+FAIL Rects in initial notifications should report initial positions. assert_equals: Check 1st entry rect.right expected 100 but got 0
 
index 4d1482c..acebac2 100644 (file)
@@ -1,7 +1,7 @@
 
 PASS One observer with multiple targets. 
-FAIL First rAF. assert_equals: Three initial notifications. expected 3 but got 0
-FAIL document.scrollingElement.scrollTop = 150 assert_equals: Four notifications. expected 4 but got 0
-FAIL document.scrollingElement.scrollTop = 10000 assert_equals: Six notifications. expected 6 but got 0
-FAIL document.scrollingElement.scrollTop = 0 assert_equals: Nine notifications. expected 9 but got 0
+PASS First rAF. 
+FAIL document.scrollingElement.scrollTop = 150 assert_equals: Four notifications. expected 4 but got 3
+FAIL document.scrollingElement.scrollTop = 10000 assert_equals: Six notifications. expected 6 but got 3
+FAIL document.scrollingElement.scrollTop = 0 assert_equals: Nine notifications. expected 9 but got 3
 
index f4a66f8..305679f 100644 (file)
@@ -1,11 +1,11 @@
 
 PASS Observer with multiple thresholds. 
-FAIL First rAF. assert_equals: entries.length expected 1 but got 0
-FAIL document.scrollingElement.scrollTop = 120 assert_equals: entries.length expected 2 but got 0
-FAIL document.scrollingElement.scrollTop = 160 assert_equals: entries.length expected 3 but got 0
-FAIL document.scrollingElement.scrollTop = 200 assert_equals: entries.length expected 4 but got 0
-FAIL document.scrollingElement.scrollTop = 240 assert_equals: entries.length expected 5 but got 0
-FAIL document.scrollingElement.scrollTop = window.innerHeight + 140 assert_equals: entries.length expected 6 but got 0
-FAIL document.scrollingElement.scrollTop = window.innerHeight + 160 assert_equals: entries.length expected 7 but got 0
-FAIL document.scrollingElement.scrollTop = window.innerHeight + 200 assert_equals: entries.length expected 8 but got 0
+FAIL First rAF. assert_equals: entries[0].boundingClientRect.left expected 8 but got 0
+FAIL document.scrollingElement.scrollTop = 120 assert_equals: entries.length expected 2 but got 1
+FAIL document.scrollingElement.scrollTop = 160 assert_equals: entries.length expected 3 but got 1
+FAIL document.scrollingElement.scrollTop = 200 assert_equals: entries.length expected 4 but got 1
+FAIL document.scrollingElement.scrollTop = 240 assert_equals: entries.length expected 5 but got 1
+FAIL document.scrollingElement.scrollTop = window.innerHeight + 140 assert_equals: entries.length expected 6 but got 1
+FAIL document.scrollingElement.scrollTop = window.innerHeight + 160 assert_equals: entries.length expected 7 but got 1
+FAIL document.scrollingElement.scrollTop = window.innerHeight + 200 assert_equals: entries.length expected 8 but got 1
 
index 4935ea6..2e7607f 100644 (file)
@@ -1,5 +1,5 @@
 
 PASS IntersectionObserver that is unreachable in js should still generate notifications. 
-FAIL First rAF assert_equals: One notification. expected 1 but got 0
-FAIL document.scrollingElement.scrollTop = 300 assert_equals: Two notifications. expected 2 but got 0
+PASS First rAF 
+FAIL document.scrollingElement.scrollTop = 300 assert_equals: Two notifications. expected 2 but got 1
 
index dd4186c..fc1b4a2 100644 (file)
@@ -1,8 +1,8 @@
 
 PASS Verify that not-intersecting notifications are sent when a target is removed from the DOM tree. 
-FAIL First rAF assert_equals: entries.length expected 1 but got 0
-FAIL root.scrollTop = 150 assert_equals: entries.length expected 2 but got 0
-FAIL root.removeChild(target). assert_equals: entries.length expected 3 but got 0
-FAIL root.insertBefore(target, trailingSpace). assert_equals: entries.length expected 3 but got 0
-FAIL root.scrollTop = 150 after reinserting target. assert_equals: entries.length expected 4 but got 0
+FAIL First rAF assert_equals: entries[0].boundingClientRect.left expected 11 but got 0
+FAIL root.scrollTop = 150 assert_equals: entries.length expected 2 but got 1
+FAIL root.removeChild(target). assert_equals: entries.length expected 3 but got 1
+FAIL root.insertBefore(target, trailingSpace). assert_equals: entries.length expected 3 but got 1
+FAIL root.scrollTop = 150 after reinserting target. assert_equals: entries.length expected 4 but got 1
 
index 5d1e48f..f396e95 100644 (file)
@@ -1,8 +1,8 @@
   
 
 PASS Root margin tests 
-FAIL First rAF. assert_equals: entries.length expected 1 but got 0
-FAIL document.scrollingElement.scrollLeft = 100 assert_equals: entries.length expected 2 but got 0
-FAIL document.scrollingElement.scrollTop = document.documentElement.clientHeight + 200 assert_equals: entries.length expected 2 but got 0
-FAIL document.scrollingElement.scrollTop = document.documentElement.clientHeight + 300 assert_equals: entries.length expected 3 but got 0
+FAIL First rAF. assert_equals: entries[0].boundingClientRect.left expected 972 but got 0
+FAIL document.scrollingElement.scrollLeft = 100 assert_equals: entries.length expected 2 but got 1
+FAIL document.scrollingElement.scrollTop = document.documentElement.clientHeight + 200 assert_equals: entries.length expected 2 but got 1
+FAIL document.scrollingElement.scrollTop = document.documentElement.clientHeight + 300 assert_equals: entries.length expected 3 but got 1
 
index 30c7a88..7bdff40 100644 (file)
@@ -1,6 +1,6 @@
 
 PASS IntersectionObserver in a single document using the implicit root. 
-FAIL First rAF. assert_equals: entries.length expected 1 but got 0
-FAIL document.scrollingElement.scrollTop = 300 assert_equals: entries.length expected 2 but got 0
-FAIL document.scrollingElement.scrollTop = 100 assert_equals: entries.length expected 3 but got 0
+FAIL First rAF. assert_equals: entries[0].boundingClientRect.left expected 8 but got 0
+FAIL document.scrollingElement.scrollTop = 300 assert_equals: entries.length expected 2 but got 1
+FAIL document.scrollingElement.scrollTop = 100 assert_equals: entries.length expected 3 but got 1
 
index 6a18d4d..1cc6978 100644 (file)
@@ -1,9 +1,9 @@
 
 PASS IntersectionObserver in a single document with explicit root. 
-FAIL First rAF assert_equals: entries.length expected 1 but got 0
-FAIL document.scrollingElement.scrollTop = window.innerHeight. assert_equals: No notifications after scrolling frame. expected 1 but got 0
-FAIL root.scrollTop = 150 with root scrolled into view. assert_equals: entries.length expected 2 but got 0
-FAIL document.scrollingElement.scrollTop = 0. assert_equals: entries.length expected 2 but got 0
-FAIL root.scrollTop = 0 assert_equals: entries.length expected 3 but got 0
-FAIL root.scrollTop = 150 with root scrolled out of view. assert_equals: entries.length expected 4 but got 0
+FAIL First rAF assert_equals: entries[0].boundingClientRect.left expected 11 but got 0
+PASS document.scrollingElement.scrollTop = window.innerHeight. 
+FAIL root.scrollTop = 150 with root scrolled into view. assert_equals: entries.length expected 2 but got 1
+FAIL document.scrollingElement.scrollTop = 0. assert_equals: entries.length expected 2 but got 1
+FAIL root.scrollTop = 0 assert_equals: entries.length expected 3 but got 1
+FAIL root.scrollTop = 150 with root scrolled out of view. assert_equals: entries.length expected 4 but got 1
 
index 40b11a6..a6f5470 100644 (file)
@@ -1,6 +1,6 @@
 
 PASS Observing a zero-area target. 
-FAIL First rAF assert_equals: entries.length expected 1 but got 0
-FAIL document.scrollingElement.scrollTop = 300 assert_equals: entries.length expected 2 but got 0
-FAIL document.scrollingElement.scrollTop = 100 assert_equals: entries.length expected 3 but got 0
+FAIL First rAF assert_equals: entries[0].boundingClientRect.left expected 8 but got 0
+FAIL document.scrollingElement.scrollTop = 300 assert_equals: entries.length expected 2 but got 1
+FAIL document.scrollingElement.scrollTop = 100 assert_equals: entries.length expected 3 but got 1
 
index bd01798..c739577 100644 (file)
@@ -1,4 +1,4 @@
 
 PASS Observing a target inside shadow DOM. 
-FAIL First rAF after creating shadow DOM. assert_equals: entries.length expected 1 but got 0
+FAIL First rAF after creating shadow DOM. assert_equals: entries[0].boundingClientRect.left expected 8 but got 0
 
index a713ec2..6d7b211 100644 (file)
@@ -1,7 +1,7 @@
 
 
 PASS IntersectionObserver observing a br element. 
-FAIL First rAF. assert_equals: entries.length expected 1 but got 0
-FAIL document.scrollingElement.scrollTop = 300 assert_equals: entries.length expected 2 but got 0
-FAIL document.scrollingElement.scrollTop = 100 assert_equals: entries.length expected 3 but got 0
+FAIL First rAF. assert_equals: entries[0].boundingClientRect.left expected 8 but got 0
+FAIL document.scrollingElement.scrollTop = 300 assert_equals: entries.length expected 2 but got 1
+FAIL document.scrollingElement.scrollTop = 100 assert_equals: entries.length expected 3 but got 1
 
index c8e1135..fd25cbf 100644 (file)
@@ -1,6 +1,6 @@
 
 
 PASS Check that timestamps correspond to the to execution context that created the observer. 
-FAIL First rAF after iframe is loaded. assert_equals: One notification to top window observer. expected 1 but got 0
+PASS First rAF after iframe is loaded. 
 FAIL Generate notifications. undefined is not an object (evaluating 'topWindowEntries[1].time')
 
index eabc577..af52e04 100644 (file)
@@ -1,5 +1,5 @@
 
 PASS Test that border bounding box is used to calculate intersection with a non-scrolling root. 
-FAIL First rAF. assert_equals: entries.length expected 1 but got 0
-FAIL target.style.transform = 'translateY(195px)' assert_equals: entries.length expected 2 but got 0
+FAIL First rAF. assert_equals: entries[0].boundingClientRect.left expected 15 but got 0
+FAIL target.style.transform = 'translateY(195px)' assert_equals: entries.length expected 2 but got 1
 
index 2507ee2..28aa490 100644 (file)
@@ -1,4 +1,4 @@
 
 PASS A zero-area hidden target should not be intersecting. 
-FAIL First rAF. assert_equals: entries.length expected 1 but got 0
+FAIL First rAF. assert_equals: entries[0].boundingClientRect.left expected 8 but got 0
 
index d4ba444..c118fdf 100644 (file)
@@ -1,4 +1,4 @@
 
 PASS Ensure that a zero-area target intersecting root generates a notification with intersectionRatio == 1 
-FAIL First rAF should generate a notification. assert_equals: One notification. expected 1 but got 0
+FAIL First rAF should generate a notification. assert_equals: intersectionRatio == 1 expected 1 but got 0
 
index 114d9ac..c35493a 100644 (file)
         var target = document.getElementById('target');
         assert_equals(observer.root, root, 'Observer starts out with non-null root');
         observer.observe(target);
+        assert_equals(internals.numberOfIntersectionObservers(document), 1);
         root.parentNode.removeChild(root);
         root = null;
         target = null;
         requestAnimationFrame(t.step_func_done(function() {
             GCController.collect();
             assert_equals(observer.root, null, 'Observer has null root after root element is destroyed');
+            assert_equals(internals.numberOfIntersectionObservers(document), 0);
         }));
     }, "IntersectionObserver doesn't keep unreachable root alive");
 </script>
diff --git a/LayoutTests/intersection-observer/root-element-moved-expected.txt b/LayoutTests/intersection-observer/root-element-moved-expected.txt
new file mode 100644 (file)
index 0000000..6552be4
--- /dev/null
@@ -0,0 +1,3 @@
+
+PASS Document's active intersection observers get updated 
+
diff --git a/LayoutTests/intersection-observer/root-element-moved.html b/LayoutTests/intersection-observer/root-element-moved.html
new file mode 100644 (file)
index 0000000..d51c815
--- /dev/null
@@ -0,0 +1,31 @@
+<!DOCTYPE html><!-- webkit-test-runner [ enableIntersectionObserver=true ] -->
+<head>
+<script src="../resources/testharness.js"></script>
+<script src="../resources/testharnessreport.js"></script>
+<body>
+
+<div id="root" style="position:absolute">
+    <div id="target" style="width: 100px; height: 100px; background-color: green"></div>
+</div>
+
+<script>
+    var observer;
+    var root = document.getElementById('root');
+    var target = document.getElementById('target');
+    test(function() {
+        observer = new IntersectionObserver(function() {}, { root: document.getElementById('root') });;
+        assert_equals(observer.root, root);
+        observer.observe(target);
+        assert_equals(internals.numberOfIntersectionObservers(document), 1);
+        document.body.appendChild(target);
+        var newDoc = document.implementation.createHTMLDocument('New document');
+        newDoc.body.appendChild(root);
+        assert_equals(internals.numberOfIntersectionObservers(document), 0);
+        assert_equals(internals.numberOfIntersectionObservers(newDoc), 1);
+        document.body.appendChild(root);
+        assert_equals(internals.numberOfIntersectionObservers(document), 1);
+        assert_equals(internals.numberOfIntersectionObservers(newDoc), 0);
+    },"Document's active intersection observers get updated");
+</script>
+</body>
+</html>
index a518c8f..eb1d1be 100644 (file)
@@ -1,3 +1,51 @@
+2018-08-18  Ali Juma  <ajuma@chromium.org>
+
+        [IntersectionObserver] Fire an initial dummy notification
+        https://bugs.webkit.org/show_bug.cgi?id=188670
+
+        Reviewed by Simon Fraser.
+
+        Add logic to track ongoing intersection observations. Create an IntersectionObserverRegistration
+        and fire a single dummy notification for each one.
+
+        Test: intersection-observer/root-element-moved.html
+        Also tested by existing tests in imported/w3c/web-platform-tests/intersection-observer.
+
+        * dom/Document.cpp:
+        (WebCore::Document::~Document):
+        (WebCore::Document::addIntersectionObserver):
+        (WebCore::Document::removeIntersectionObserver):
+        (WebCore::Document::updateIntersectionObservations):
+        (WebCore::Document::notifyIntersectionObserversTimerFired):
+        * dom/Document.h:
+        (WebCore::Document::numberOfIntersectionObservers const):
+        * dom/Element.cpp:
+        (WebCore::Element::didMoveToNewDocument):
+        (WebCore::Element::disconnectFromIntersectionObservers):
+        * page/IntersectionObserver.cpp:
+        (WebCore::IntersectionObserver::create):
+        (WebCore::IntersectionObserver::IntersectionObserver):
+        (WebCore::IntersectionObserver::~IntersectionObserver):
+        (WebCore::IntersectionObserver::observe):
+        (WebCore::IntersectionObserver::unobserve):
+        (WebCore::IntersectionObserver::disconnect):
+        (WebCore::IntersectionObserver::takeRecords):
+        (WebCore::IntersectionObserver::targetDestroyed):
+        (WebCore::IntersectionObserver::removeTargetRegistration):
+        (WebCore::IntersectionObserver::removeAllTargets):
+        (WebCore::IntersectionObserver::rootDestroyed):
+        (WebCore::IntersectionObserver::appendQueuedEntry):
+        (WebCore::IntersectionObserver::notify):
+        * page/IntersectionObserver.h:
+        (WebCore::IntersectionObserver::trackingDocument):
+        (WebCore::IntersectionObserver:: const):
+        (WebCore::IntersectionObserver::hasObservationTargets const):
+        * page/IntersectionObserver.idl:
+        * testing/Internals.cpp:
+        (WebCore::Internals::numberOfIntersectionObservers const):
+        * testing/Internals.h:
+        * testing/Internals.idl:
+
 2018-08-18  Wenson Hsieh  <wenson_hsieh@apple.com>
 
         [iOS] Paste is missing from callout bar when pasteboard only contains custom data
index a351585..39b5342 100644 (file)
 #include "ImageBitmapRenderingContext.h"
 #include "ImageLoader.h"
 #include "InspectorInstrumentation.h"
+#include "IntersectionObserver.h"
 #include "JSCustomElementInterface.h"
 #include "JSDOMPromiseDeferred.h"
 #include "JSLazyEventListener.h"
@@ -503,6 +504,9 @@ Document::Document(Frame* frame, const URL& url, unsigned documentClasses, unsig
     , m_constantPropertyMap(std::make_unique<ConstantPropertyMap>(*this))
     , m_documentClasses(documentClasses)
     , m_eventQueue(*this)
+#if ENABLE(INTERSECTION_OBSERVER)
+    , m_intersectionObserversNotifyTimer(*this, &Document::notifyIntersectionObserversTimerFired)
+#endif
     , m_loadEventDelayTimer(*this, &Document::loadEventDelayTimerFired)
 #if PLATFORM(IOS)
 #if ENABLE(DEVICE_ORIENTATION)
@@ -639,7 +643,7 @@ Document::~Document()
     if (auto* platformMediaSessionManager = PlatformMediaSessionManager::sharedManagerIfExists())
         platformMediaSessionManager->stopAllMediaPlaybackForDocument(this);
 #endif
-    
+
     // We must call clearRareData() here since a Document class inherits TreeScope
     // as well as Node. See a comment on TreeScope.h for the reason.
     if (hasRareData())
@@ -7416,6 +7420,76 @@ void Document::removeViewportDependentPicture(HTMLPictureElement& picture)
     m_viewportDependentPictures.remove(&picture);
 }
 
+#if ENABLE(INTERSECTION_OBSERVER)
+void Document::addIntersectionObserver(RefPtr<IntersectionObserver>&& observer)
+{
+    ASSERT(m_intersectionObservers.find(observer) == notFound);
+    m_intersectionObservers.append(WTFMove(observer));
+}
+
+RefPtr<IntersectionObserver> Document::removeIntersectionObserver(IntersectionObserver& observer)
+{
+    RefPtr<IntersectionObserver> observerRef;
+    auto index = m_intersectionObservers.find(&observer);
+    if (index != notFound) {
+        observerRef = WTFMove(m_intersectionObservers[index]);
+        m_intersectionObservers.remove(index);
+    }
+    return observerRef;
+}
+
+void Document::updateIntersectionObservations()
+{
+    for (auto observer : m_intersectionObservers) {
+        bool needNotify = false;
+        for (Element* target : observer->observationTargets()) {
+            auto& targetRegistrations = target->intersectionObserverData()->registrations;
+            auto index = targetRegistrations.findMatching([observer](auto& registration) {
+                return registration.observer.get() == observer;
+            });
+            ASSERT(index != notFound);
+            auto& registration = targetRegistrations[index];
+
+            // FIXME: Compute intersection of target and observer's root.
+            size_t thresholdIndex = 0;
+            double timestamp = 0;
+            std::optional<DOMRectInit> rootBounds;
+            DOMRectInit targetBoundingClientRect;
+            DOMRectInit intersectionRect;
+            double intersectionRatio = 0;
+            bool isIntersecting = false;
+            if (!registration.previousThresholdIndex || thresholdIndex != registration.previousThresholdIndex) {
+                observer->appendQueuedEntry(IntersectionObserverEntry::create({
+                    timestamp,
+                    rootBounds,
+                    targetBoundingClientRect,
+                    intersectionRect,
+                    intersectionRatio,
+                    target,
+                    isIntersecting,
+                }));
+                needNotify = true;
+                registration.previousThresholdIndex = thresholdIndex;
+            }
+        }
+        if (needNotify)
+            m_intersectionObserversWithPendingNotifications.append(makeWeakPtr(observer.get()));
+    }
+
+    if (m_intersectionObserversWithPendingNotifications.size())
+        m_intersectionObserversNotifyTimer.startOneShot(0_s);
+}
+
+void Document::notifyIntersectionObserversTimerFired()
+{
+    for (auto observer : m_intersectionObserversWithPendingNotifications) {
+        if (observer)
+            observer->notify();
+    }
+    m_intersectionObserversWithPendingNotifications.clear();
+}
+#endif
+
 const AtomicString& Document::dir() const
 {
     auto* documentElement = this->documentElement();
index d79a44e..0a1d903 100644 (file)
@@ -235,6 +235,10 @@ class MediaSession;
 class HTMLAttachmentElement;
 #endif
 
+#if ENABLE(INTERSECTION_OBSERVER)
+class IntersectionObserver;
+#endif
+
 namespace Style {
 class Scope;
 };
@@ -1359,6 +1363,13 @@ public:
     void addViewportDependentPicture(HTMLPictureElement&);
     void removeViewportDependentPicture(HTMLPictureElement&);
 
+#if ENABLE(INTERSECTION_OBSERVER)
+    void addIntersectionObserver(RefPtr<IntersectionObserver>&&);
+    RefPtr<IntersectionObserver> removeIntersectionObserver(IntersectionObserver&);
+    unsigned numberOfIntersectionObservers() const { return m_intersectionObservers.size(); }
+    void updateIntersectionObservations();
+#endif
+
 #if ENABLE(MEDIA_STREAM)
     void setHasCaptureMediaStreamTrack() { m_hasHadCaptureMediaStreamTrack = true; }
     bool hasHadCaptureMediaStreamTrack() const { return m_hasHadCaptureMediaStreamTrack; }
@@ -1575,6 +1586,10 @@ private:
 
     void checkViewportDependentPictures();
 
+#if ENABLE(INTERSECTION_OBSERVER)
+    void notifyIntersectionObserversTimerFired();
+#endif
+
 #if USE(QUICK_LOOK)
     bool shouldEnforceQuickLookSandbox() const;
     void applyQuickLookSandbox();
@@ -1757,6 +1772,12 @@ private:
 
     HashSet<HTMLPictureElement*> m_viewportDependentPictures;
 
+#if ENABLE(INTERSECTION_OBSERVER)
+    Vector<RefPtr<IntersectionObserver>> m_intersectionObservers;
+    Vector<WeakPtr<IntersectionObserver>> m_intersectionObserversWithPendingNotifications;
+    Timer m_intersectionObserversNotifyTimer;
+#endif
+
     Timer m_loadEventDelayTimer;
 
     ViewportArguments m_viewportArguments;
index 7899b6d..c3ba8a7 100644 (file)
@@ -1649,6 +1649,15 @@ void Element::didMoveToNewDocument(Document& oldDocument, Document& newDocument)
 
     if (UNLIKELY(isDefinedCustomElement()))
         CustomElementReactionQueue::enqueueAdoptedCallbackIfNeeded(*this, oldDocument, newDocument);
+
+#if ENABLE(INTERSECTION_OBSERVER)
+    if (auto* observerData = intersectionObserverData()) {
+        for (auto observer : observerData->observers) {
+            if (observer->hasObservationTargets())
+                newDocument.addIntersectionObserver(oldDocument.removeIntersectionObserver(*observer));
+        }
+    }
+#endif
 }
 
 bool Element::hasAttributes() const
@@ -3246,7 +3255,11 @@ void Element::disconnectFromIntersectionObservers()
     if (!observerData)
         return;
 
-    for (auto* observer : observerData->observers)
+    for (auto& registration : observerData->registrations)
+        registration.observer->targetDestroyed(*this);
+    observerData->registrations.clear();
+
+    for (auto observer : observerData->observers)
         observer->rootDestroyed();
     observerData->observers.clear();
 }
index 44f346d..9082f84 100644 (file)
@@ -81,7 +81,7 @@ static ExceptionOr<LengthBox> parseRootMargin(String& rootMargin)
     return LengthBox(WTFMove(margins[0]), WTFMove(margins[1]), WTFMove(margins[2]), WTFMove(margins[3]));
 }
 
-ExceptionOr<Ref<IntersectionObserver>> IntersectionObserver::create(Ref<IntersectionObserverCallback>&& callback, IntersectionObserver::Init&& init)
+ExceptionOr<Ref<IntersectionObserver>> IntersectionObserver::create(Document& document, Ref<IntersectionObserverCallback>&& callback, IntersectionObserver::Init&& init)
 {
     auto rootMarginOrException = parseRootMargin(init.rootMargin);
     if (rootMarginOrException.hasException())
@@ -100,10 +100,10 @@ ExceptionOr<Ref<IntersectionObserver>> IntersectionObserver::create(Ref<Intersec
             return Exception { RangeError, "Failed to construct 'IntersectionObserver': all thresholds must lie in the range [0.0, 1.0]." };
     }
 
-    return adoptRef(*new IntersectionObserver(WTFMove(callback), init.root, rootMarginOrException.releaseReturnValue(), WTFMove(thresholds)));
+    return adoptRef(*new IntersectionObserver(document, WTFMove(callback), init.root, rootMarginOrException.releaseReturnValue(), WTFMove(thresholds)));
 }
 
-IntersectionObserver::IntersectionObserver(Ref<IntersectionObserverCallback>&& callback, Element* root, LengthBox&& parsedRootMargin, Vector<double>&& thresholds)
+IntersectionObserver::IntersectionObserver(Document& document, Ref<IntersectionObserverCallback>&& callback, Element* root, LengthBox&& parsedRootMargin, Vector<double>&& thresholds)
     : m_root(root)
     , m_rootMargin(WTFMove(parsedRootMargin))
     , m_thresholds(WTFMove(thresholds))
@@ -111,14 +111,16 @@ IntersectionObserver::IntersectionObserver(Ref<IntersectionObserverCallback>&& c
 {
     if (m_root) {
         auto& observerData = m_root->ensureIntersectionObserverData();
-        observerData.observers.append(this);
-    }
+        observerData.observers.append(makeWeakPtr(this));
+    } else if (auto* frame = document.frame())
+        m_implicitRootDocument = makeWeakPtr(frame->mainFrame().document());
 }
 
 IntersectionObserver::~IntersectionObserver()
 {
     if (m_root)
         m_root->intersectionObserverData()->observers.removeFirst(this);
+    removeAllTargets();
 }
 
 String IntersectionObserver::rootMargin() const
@@ -138,28 +140,103 @@ String IntersectionObserver::rootMargin() const
     return stringBuilder.toString();
 }
 
-void IntersectionObserver::observe(Element&)
+void IntersectionObserver::observe(Element& target)
 {
+    if (!trackingDocument() || m_observationTargets.contains(&target))
+        return;
+
+    target.ensureIntersectionObserverData().registrations.append({ makeWeakPtr(this), std::nullopt });
+    bool hadObservationTargets = hasObservationTargets();
+    m_observationTargets.append(&target);
+    auto* document = trackingDocument();
+    if (!hadObservationTargets)
+        document->addIntersectionObserver(this);
+    document->postTask([document] (ScriptExecutionContext&) mutable {
+        document->updateIntersectionObservations();
+    });
 }
 
-void IntersectionObserver::unobserve(Element&)
+void IntersectionObserver::unobserve(Element& target)
 {
+    if (!removeTargetRegistration(target))
+        return;
+
+    bool removed = m_observationTargets.removeFirst(&target);
+    ASSERT_UNUSED(removed, removed);
+
+    if (!hasObservationTargets()) {
+        if (auto* document = trackingDocument())
+            document->removeIntersectionObserver(*this);
+    }
 }
 
 void IntersectionObserver::disconnect()
 {
+    if (!hasObservationTargets())
+        return;
+
+    removeAllTargets();
+    if (auto* document = trackingDocument())
+        document->removeIntersectionObserver(*this);
+}
+
+Vector<Ref<IntersectionObserverEntry>> IntersectionObserver::takeRecords()
+{
+    return WTFMove(m_queuedEntries);
 }
 
-Vector<RefPtr<IntersectionObserverEntry>> IntersectionObserver::takeRecords()
+void IntersectionObserver::targetDestroyed(Element& target)
 {
-    return { };
+    m_observationTargets.removeFirst(&target);
+    if (!hasObservationTargets()) {
+        if (auto* document = trackingDocument())
+            document->removeIntersectionObserver(*this);
+    }
+}
+
+bool IntersectionObserver::removeTargetRegistration(Element& target)
+{
+    auto* observerData = target.intersectionObserverData();
+    if (!observerData)
+        return false;
+
+    auto& registrations = observerData->registrations;
+    return registrations.removeFirstMatching([this](auto& registration) {
+        return registration.observer.get() == this;
+    });
+}
+
+void IntersectionObserver::removeAllTargets()
+{
+    for (auto* target : m_observationTargets) {
+        bool removed = removeTargetRegistration(*target);
+        ASSERT_UNUSED(removed, removed);
+    }
+    m_observationTargets.clear();
 }
 
 void IntersectionObserver::rootDestroyed()
 {
     ASSERT(m_root);
-    disconnect();
+    auto& document = m_root->document();
     m_root = nullptr;
+    if (hasObservationTargets()) {
+        removeAllTargets();
+        document.removeIntersectionObserver(*this);
+    }
+}
+
+void IntersectionObserver::appendQueuedEntry(Ref<IntersectionObserverEntry>&& entry)
+{
+    m_queuedEntries.append(WTFMove(entry));
+}
+
+void IntersectionObserver::notify()
+{
+    if (m_queuedEntries.isEmpty() || !m_callback->canInvokeCallback())
+        return;
+
+    m_callback->handleEvent(takeRecords(), *this);
 }
 
 } // namespace WebCore
index 7aac218..ba2d18a 100644 (file)
 #include "LengthBox.h"
 #include <wtf/RefCounted.h>
 #include <wtf/Variant.h>
+#include <wtf/WeakPtr.h>
 #include <wtf/text/WTFString.h>
 
 namespace WebCore {
 
+class Document;
 class Element;
 
+struct IntersectionObserverRegistration {
+    WeakPtr<IntersectionObserver> observer;
+    std::optional<size_t> previousThresholdIndex;
+};
+
 struct IntersectionObserverData {
     // IntersectionObservers for which the element that owns this IntersectionObserverData is the root.
-    // The IntersectionObservers are owned by JavaScript wrappers and by IntersectionObserverRegistrations
-    // for each target currently being observed.
-    Vector<IntersectionObserver*> observers;
+    // An IntersectionObserver without any targets is only owned by JavaScript wrappers. An
+    // IntersectionObserver with at least one target is also owned by its trackingDocument.
+    Vector<WeakPtr<IntersectionObserver>> observers;
 
-    // FIXME: Create and track IntersectionObserverRegistrations.
+    // IntersectionObserverRegistrations for which the element that owns this IntersectionObserverData is the target.
+    Vector<IntersectionObserverRegistration> registrations;
 };
 
-class IntersectionObserver : public RefCounted<IntersectionObserver> {
+class IntersectionObserver : public RefCounted<IntersectionObserver>, public CanMakeWeakPtr<IntersectionObserver> {
 public:
     struct Init {
         Element* root { nullptr };
@@ -55,29 +63,43 @@ public:
         Variant<double, Vector<double>> threshold;
     };
 
-    static ExceptionOr<Ref<IntersectionObserver>> create(Ref<IntersectionObserverCallback>&&, Init&&);
+    static ExceptionOr<Ref<IntersectionObserver>> create(Document&, Ref<IntersectionObserverCallback>&&, Init&&);
 
     ~IntersectionObserver();
 
+    Document* trackingDocument() { return m_root ? &m_root->document() : m_implicitRootDocument.get(); }
+
     Element* root() const { return m_root; }
     String rootMargin() const;
     const Vector<double>& thresholds() const { return m_thresholds; }
+    const Vector<Element*> observationTargets() const { return m_observationTargets; }
 
     void observe(Element&);
     void unobserve(Element&);
     void disconnect();
 
-    Vector<RefPtr<IntersectionObserverEntry>> takeRecords();
+    Vector<Ref<IntersectionObserverEntry>> takeRecords();
 
+    void targetDestroyed(Element&);
+    bool hasObservationTargets() const { return m_observationTargets.size(); }
     void rootDestroyed();
 
+    void appendQueuedEntry(Ref<IntersectionObserverEntry>&&);
+    void notify();
+
 private:
-    IntersectionObserver(Ref<IntersectionObserverCallback>&&, Element* root, LengthBox&& parsedRootMargin, Vector<double>&& thresholds);
-    
+    IntersectionObserver(Document&, Ref<IntersectionObserverCallback>&&, Element* root, LengthBox&& parsedRootMargin, Vector<double>&& thresholds);
+
+    bool removeTargetRegistration(Element&);
+    void removeAllTargets();
+
+    WeakPtr<Document> m_implicitRootDocument;
     Element* m_root;
     LengthBox m_rootMargin;
     Vector<double> m_thresholds;
     Ref<IntersectionObserverCallback> m_callback;
+    Vector<Element*> m_observationTargets;
+    Vector<Ref<IntersectionObserverEntry>> m_queuedEntries;
 };
 
 
index e6dbabf..f78772a 100644 (file)
@@ -27,6 +27,7 @@
 
 [
     Conditional=INTERSECTION_OBSERVER,
+    ConstructorCallWith=Document,
     ConstructorMayThrowException,
     Constructor(IntersectionObserverCallback callback, optional IntersectionObserverInit options),
     ImplementationLacksVTable,
index ee37039..d112ce0 100644 (file)
@@ -2310,6 +2310,13 @@ unsigned Internals::referencingNodeCount(const Document& document) const
     return document.referencingNodeCount();
 }
 
+#if ENABLE(INTERSECTION_OBSERVER)
+unsigned Internals::numberOfIntersectionObservers(const Document& document) const
+{
+    return document.numberOfIntersectionObservers();
+}
+#endif
+
 uint64_t Internals::documentIdentifier(const Document& document) const
 {
     return document.identifier().toUInt64();
index d0d2879..9c1cab9 100644 (file)
@@ -364,6 +364,10 @@ public:
     unsigned numberOfLiveDocuments() const;
     unsigned referencingNodeCount(const Document&) const;
 
+#if ENABLE(INTERSECTION_OBSERVER)
+    unsigned numberOfIntersectionObservers(const Document&) const;
+#endif
+
     uint64_t documentIdentifier(const Document&) const;
     bool isDocumentAlive(uint64_t documentIdentifier) const;
 
index 01148b9..2322663 100644 (file)
@@ -359,6 +359,7 @@ enum CompositingPolicy {
     unsigned long numberOfLiveNodes();
     unsigned long numberOfLiveDocuments();
     unsigned long referencingNodeCount(Document document);
+    [Conditional=INTERSECTION_OBSERVER] unsigned long numberOfIntersectionObservers(Document document);
     WindowProxy? openDummyInspectorFrontend(DOMString url);
     void closeDummyInspectorFrontend();
     [MayThrowException] void setInspectorIsUnderTest(boolean isUnderTest);