WebKit Bugzilla
Attachment 347684 Details for
Bug 188809
: [IntersectionObserver] Implement intersection logic for the explicit root case
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Requests
|
Help
|
New Account
|
Log In
Remember
[x]
|
Forgot Password
Login:
[x]
[patch]
Patch
bug-188809-20180821163909.patch (text/plain), 21.28 KB, created by
Ali Juma
on 2018-08-21 13:39:10 PDT
(
hide
)
Description:
Patch
Filename:
MIME Type:
Creator:
Ali Juma
Created:
2018-08-21 13:39:10 PDT
Size:
21.28 KB
patch
obsolete
>Subversion Revision: 235015 >diff --git a/Source/WebCore/ChangeLog b/Source/WebCore/ChangeLog >index 2195422db9aba4b42b2a1f68c13807b5f8c21d2c..dcac5566a8269517e7f82d7c57fe48ed1a78d5fc 100644 >--- a/Source/WebCore/ChangeLog >+++ b/Source/WebCore/ChangeLog >@@ -1,3 +1,33 @@ >+2018-08-21 Ali Juma <ajuma@chromium.org> >+ >+ [IntersectionObserver] Implement intersection logic for the explicit root case >+ https://bugs.webkit.org/show_bug.cgi?id=188809 >+ >+ Reviewed by NOBODY (OOPS!). >+ >+ Add logic to Document::updateIntersectionObservations to compute the intersection >+ between the target and root elements, for the case where an IntersectionObserver >+ has a root element. >+ >+ There are no changes to the scheduling of intersection observations in this patch, >+ so observations are still only computed once for each observer. >+ >+ * dom/Document.cpp: >+ (WebCore::computeIntersectionObservation): >+ (WebCore::Document::updateIntersectionObservations): >+ * page/FrameView.cpp: >+ (WebCore::FrameView::absoluteToClientRect const): >+ * page/FrameView.h: >+ * page/IntersectionObserver.cpp: >+ (WebCore::IntersectionObserver::IntersectionObserver): >+ (WebCore::IntersectionObserver::createTimestamp const): >+ * page/IntersectionObserver.h: >+ * platform/graphics/FloatRect.h: >+ (WebCore::FloatRect::area const): >+ * rendering/RenderBlock.cpp: >+ (WebCore::RenderBlock::isContainingBlockAncestorFor const): >+ * rendering/RenderBlock.h: >+ > 2018-08-18 David Kilzer <ddkilzer@apple.com> > > Let Xcode have its way with the WebCore project >diff --git a/Source/WebCore/dom/Document.cpp b/Source/WebCore/dom/Document.cpp >index 39b5342858a57e455f2cea8892dbdabf2842cdb3..578f13b453020daeb262932c98455846fce2ed9e 100644 >--- a/Source/WebCore/dom/Document.cpp >+++ b/Source/WebCore/dom/Document.cpp >@@ -152,7 +152,9 @@ > #include "PublicSuffix.h" > #include "RealtimeMediaSourceCenter.h" > #include "RenderChildIterator.h" >+#include "RenderInline.h" > #include "RenderLayerCompositor.h" >+#include "RenderLineBreak.h" > #include "RenderTreeUpdater.h" > #include "RenderView.h" > #include "RenderWidget.h" >@@ -7438,10 +7440,62 @@ RefPtr<IntersectionObserver> Document::removeIntersectionObserver(IntersectionOb > return observerRef; > } > >+static void computeIntersectionObservation(IntersectionObserver& observer, Element* target, FloatRect& absTargetRect, FloatRect& absIntersectionRect, FloatRect& absRootBounds) >+{ >+ // FIXME: Implement intersection computation for the case of an implicit root. >+ if (!observer.root()) >+ return; >+ >+ if (observer.root()->document() != target->document()) >+ return; >+ >+ if (!observer.root()->renderer() || !is<RenderBlock>(observer.root()->renderer())) >+ return; >+ RenderBlock* rootRenderer = downcast<RenderBlock>(observer.root()->renderer()); >+ >+ auto* targetRenderer = target->renderer(); >+ if (!targetRenderer) >+ return; >+ >+ if (!rootRenderer->isContainingBlockAncestorFor(*targetRenderer)) >+ return; >+ >+ // FIXME: Expand localRootBounds using the observer's rootMargin. >+ FloatRect localRootBounds; >+ if (rootRenderer->hasOverflowClip()) >+ localRootBounds = rootRenderer->contentBoxRect(); >+ else >+ localRootBounds = { FloatPoint(), rootRenderer->size() }; >+ >+ LayoutRect localTargetBounds; >+ if (is<RenderBox>(*targetRenderer)) >+ localTargetBounds = downcast<RenderBox>(targetRenderer)->borderBoundingBox(); >+ else if (is<RenderInline>(targetRenderer)) >+ localTargetBounds = downcast<RenderInline>(targetRenderer)->linesBoundingBox(); >+ else if (is<RenderLineBreak>(targetRenderer)) >+ localTargetBounds = downcast<RenderLineBreak>(targetRenderer)->linesBoundingBox(); >+ >+ FloatRect rootLocalIntersectionRect = targetRenderer->computeRectForRepaint(localTargetBounds, rootRenderer); >+ rootLocalIntersectionRect.intersect(localRootBounds); >+ >+ if (!rootLocalIntersectionRect.isEmpty()) >+ absIntersectionRect = rootRenderer->localToAbsoluteQuad(rootLocalIntersectionRect).boundingBox(); >+ >+ absTargetRect = targetRenderer->localToAbsoluteQuad(FloatRect(localTargetBounds)).boundingBox(); >+ absRootBounds = rootRenderer->localToAbsoluteQuad(localRootBounds).boundingBox(); >+} >+ > void Document::updateIntersectionObservations() > { >+ auto* frameView = view(); >+ if (!frameView) >+ return; >+ > for (auto observer : m_intersectionObservers) { > bool needNotify = false; >+ DOMHighResTimeStamp timestamp; >+ if (!observer->createTimestamp(timestamp)) >+ continue; > for (Element* target : observer->observationTargets()) { > auto& targetRegistrations = target->intersectionObserverData()->registrations; > auto index = targetRegistrations.findMatching([observer](auto& registration) { >@@ -7450,20 +7504,40 @@ void Document::updateIntersectionObservations() > ASSERT(index != notFound); > auto& registration = targetRegistrations[index]; > >- // FIXME: Compute intersection of target and observer's root. >+ FloatRect absTargetRect; >+ FloatRect absIntersectionRect; >+ FloatRect absRootBounds; >+ computeIntersectionObservation(*observer, target, absTargetRect, absIntersectionRect, absRootBounds); >+ >+ // FIXME: Handle zero-area intersections (e.g., intersections involving zero-area targets). >+ bool isIntersecting = absIntersectionRect.area(); >+ float intersectionRatio = isIntersecting ? absIntersectionRect.area() / absTargetRect.area() : 0; > size_t thresholdIndex = 0; >- double timestamp = 0; >- std::optional<DOMRectInit> rootBounds; >- DOMRectInit targetBoundingClientRect; >- DOMRectInit intersectionRect; >- double intersectionRatio = 0; >- bool isIntersecting = false; >+ if (isIntersecting) { >+ auto& thresholds = observer->thresholds(); >+ while (thresholdIndex < thresholds.size() && thresholds[thresholdIndex] <= intersectionRatio) >+ ++thresholdIndex; >+ } >+ > if (!registration.previousThresholdIndex || thresholdIndex != registration.previousThresholdIndex) { >+ FloatRect targetBoundingClientRect = frameView->absoluteToClientRect(absTargetRect); >+ FloatRect clientIntersectionRect = frameView->absoluteToClientRect(absIntersectionRect); >+ >+ // FIXME: Once cross-document observation is implemented, only report root bounds if the target document and >+ // the root document are similar-origin. >+ FloatRect clientRootBounds = frameView->absoluteToClientRect(absRootBounds); >+ std::optional<DOMRectInit> reportedRootBounds = DOMRectInit({ >+ clientRootBounds.x(), >+ clientRootBounds.y(), >+ clientRootBounds.width(), >+ clientRootBounds.height() >+ }); >+ > observer->appendQueuedEntry(IntersectionObserverEntry::create({ > timestamp, >- rootBounds, >- targetBoundingClientRect, >- intersectionRect, >+ reportedRootBounds, >+ { targetBoundingClientRect.x(), targetBoundingClientRect.y(), targetBoundingClientRect.width(), targetBoundingClientRect.height() }, >+ { clientIntersectionRect.x(), clientIntersectionRect.y(), clientIntersectionRect.width(), clientIntersectionRect.height() }, > intersectionRatio, > target, > isIntersecting, >diff --git a/Source/WebCore/page/FrameView.cpp b/Source/WebCore/page/FrameView.cpp >index eec77f773f370d3646732417325b2f0bd26534b5..8df45e94ed51b15f018f8ab590a6df66c7fdd42d 100644 >--- a/Source/WebCore/page/FrameView.cpp >+++ b/Source/WebCore/page/FrameView.cpp >@@ -4657,6 +4657,11 @@ FloatPoint FrameView::absoluteToDocumentPoint(FloatPoint p, std::optional<float> > return p.scaled(absoluteToDocumentScaleFactor(effectiveZoom)); > } > >+FloatRect FrameView::absoluteToClientRect(FloatRect rect, std::optional<float> effectiveZoom) const >+{ >+ return documentToClientRect(absoluteToDocumentRect(rect, effectiveZoom)); >+} >+ > FloatSize FrameView::documentToClientOffset() const > { > FloatSize clientOrigin = -toFloatSize(visibleContentRect().location()); >diff --git a/Source/WebCore/page/FrameView.h b/Source/WebCore/page/FrameView.h >index f592c833c7c5cc7f923fda8ab62e3df26e0fc00b..f50cde6ae90b235d8138abd08de4acf85a0d7990 100644 >--- a/Source/WebCore/page/FrameView.h >+++ b/Source/WebCore/page/FrameView.h >@@ -473,6 +473,8 @@ public: > FloatRect absoluteToDocumentRect(FloatRect, std::optional<float> effectiveZoom = std::nullopt) const; > FloatPoint absoluteToDocumentPoint(FloatPoint, std::optional<float> effectiveZoom = std::nullopt) const; > >+ FloatRect absoluteToClientRect(FloatRect, std::optional<float> effectiveZoom = std::nullopt) const; >+ > FloatSize documentToClientOffset() const; > FloatRect documentToClientRect(FloatRect) const; > FloatPoint documentToClientPoint(FloatPoint) const; >diff --git a/Source/WebCore/page/IntersectionObserver.cpp b/Source/WebCore/page/IntersectionObserver.cpp >index 9082f841944579f7963c7a241d2be025da3ad459..4bbe1926cd810baa755585af217e97d73565ebe6 100644 >--- a/Source/WebCore/page/IntersectionObserver.cpp >+++ b/Source/WebCore/page/IntersectionObserver.cpp >@@ -34,6 +34,7 @@ > #include "Element.h" > #include "IntersectionObserverCallback.h" > #include "IntersectionObserverEntry.h" >+#include "Performance.h" > #include <wtf/Vector.h> > > namespace WebCore { >@@ -114,6 +115,8 @@ IntersectionObserver::IntersectionObserver(Document& document, Ref<IntersectionO > observerData.observers.append(makeWeakPtr(this)); > } else if (auto* frame = document.frame()) > m_implicitRootDocument = makeWeakPtr(frame->mainFrame().document()); >+ >+ std::sort(m_thresholds.begin(), m_thresholds.end()); > } > > IntersectionObserver::~IntersectionObserver() >@@ -226,6 +229,22 @@ void IntersectionObserver::rootDestroyed() > } > } > >+bool IntersectionObserver::createTimestamp(DOMHighResTimeStamp& timestamp) const >+{ >+ auto* context = m_callback->scriptExecutionContext(); >+ if (!context) >+ return false; >+ ASSERT(context->isDocument()); >+ auto& document = downcast<Document>(*context); >+ if (auto* window = document.domWindow()) { >+ if (auto* performance = window->performance()) { >+ timestamp = performance->now(); >+ return true; >+ } >+ } >+ return false; >+} >+ > void IntersectionObserver::appendQueuedEntry(Ref<IntersectionObserverEntry>&& entry) > { > m_queuedEntries.append(WTFMove(entry)); >diff --git a/Source/WebCore/page/IntersectionObserver.h b/Source/WebCore/page/IntersectionObserver.h >index ba2d18ab87e48e3515637b29478c0259c24064d6..70abc4930546e76e51075b5dbc59d6c1a45a5495 100644 >--- a/Source/WebCore/page/IntersectionObserver.h >+++ b/Source/WebCore/page/IntersectionObserver.h >@@ -84,6 +84,8 @@ public: > bool hasObservationTargets() const { return m_observationTargets.size(); } > void rootDestroyed(); > >+ bool createTimestamp(DOMHighResTimeStamp&) const; >+ > void appendQueuedEntry(Ref<IntersectionObserverEntry>&&); > void notify(); > >diff --git a/Source/WebCore/platform/graphics/FloatRect.h b/Source/WebCore/platform/graphics/FloatRect.h >index 4f3576610afb13c0716ec33ac9bbe7c852fafcb5..8d19f7f862ef4adc6b754cdce16072ebd3fe200e 100644 >--- a/Source/WebCore/platform/graphics/FloatRect.h >+++ b/Source/WebCore/platform/graphics/FloatRect.h >@@ -89,6 +89,8 @@ public: > float width() const { return m_size.width(); } > float height() const { return m_size.height(); } > >+ float area() const { return m_size.area(); } >+ > void setX(float x) { m_location.setX(x); } > void setY(float y) { m_location.setY(y); } > void setWidth(float width) { m_size.setWidth(width); } >diff --git a/Source/WebCore/rendering/RenderBlock.cpp b/Source/WebCore/rendering/RenderBlock.cpp >index 8f53f7d5f11a72a20e9c9cd613e40556f3650b50..12927c47c1991ac61914417e2af796f5ec81ebca 100644 >--- a/Source/WebCore/rendering/RenderBlock.cpp >+++ b/Source/WebCore/rendering/RenderBlock.cpp >@@ -1828,6 +1828,15 @@ void RenderBlock::clearPercentHeightDescendantsFrom(RenderBox& parent) > } > } > >+bool RenderBlock::isContainingBlockAncestorFor(RenderObject& renderer) const >+{ >+ for (const auto* ancestor = renderer.containingBlock(); ancestor; ancestor = ancestor->containingBlock()) { >+ if (ancestor == this) >+ return true; >+ } >+ return false; >+} >+ > LayoutUnit RenderBlock::textIndentOffset() const > { > LayoutUnit cw = 0; >diff --git a/Source/WebCore/rendering/RenderBlock.h b/Source/WebCore/rendering/RenderBlock.h >index ef1e7e389824a44977f71795700c2fb27e7e8775..8e806ed02abc3a23e3e19626e8aa7e67f651c539 100644 >--- a/Source/WebCore/rendering/RenderBlock.h >+++ b/Source/WebCore/rendering/RenderBlock.h >@@ -101,6 +101,8 @@ public: > static void clearPercentHeightDescendantsFrom(RenderBox&); > static void removePercentHeightDescendantIfNeeded(RenderBox&); > >+ bool isContainingBlockAncestorFor(RenderObject&) const; >+ > void setHasMarginBeforeQuirk(bool b) { setRenderBlockHasMarginBeforeQuirk(b); } > void setHasMarginAfterQuirk(bool b) { setRenderBlockHasMarginAfterQuirk(b); } > void setShouldForceRelayoutChildren(bool b) { setRenderBlockShouldForceRelayoutChildren(b); } >diff --git a/LayoutTests/imported/w3c/ChangeLog b/LayoutTests/imported/w3c/ChangeLog >index 7cb688b85e0fb9deca88402f658274cf276a0f72..31a28843a8274e4bc6980b065cd17b2a02036807 100644 >--- a/LayoutTests/imported/w3c/ChangeLog >+++ b/LayoutTests/imported/w3c/ChangeLog >@@ -1,3 +1,20 @@ >+2018-08-21 Ali Juma <ajuma@chromium.org> >+ >+ [IntersectionObserver] Implement intersection logic for the explicit root case >+ https://bugs.webkit.org/show_bug.cgi?id=188809 >+ >+ Reviewed by NOBODY (OOPS!). >+ >+ Rebaseline tests now that some intersection logic has been implemented. >+ >+ * web-platform-tests/intersection-observer/bounding-box-expected.txt: >+ * web-platform-tests/intersection-observer/containing-block-expected.txt: >+ * web-platform-tests/intersection-observer/edge-inclusive-intersection-expected.txt: >+ * web-platform-tests/intersection-observer/isIntersecting-change-events-expected.txt: >+ * web-platform-tests/intersection-observer/remove-element-expected.txt: >+ * web-platform-tests/intersection-observer/same-document-root-expected.txt: >+ * web-platform-tests/intersection-observer/unclipped-root-expected.txt: >+ > 2018-08-18 Ali Juma <ajuma@chromium.org> > > [IntersectionObserver] Fire an initial dummy notification >diff --git a/LayoutTests/imported/w3c/web-platform-tests/intersection-observer/bounding-box-expected.txt b/LayoutTests/imported/w3c/web-platform-tests/intersection-observer/bounding-box-expected.txt >index 2a30215c484e4cb70824d011678ce29347e90430..865f24bd1b1587d2941ce4e8b1ec7d8eedd9d231 100644 >--- a/LayoutTests/imported/w3c/web-platform-tests/intersection-observer/bounding-box-expected.txt >+++ b/LayoutTests/imported/w3c/web-platform-tests/intersection-observer/bounding-box-expected.txt >@@ -1,5 +1,5 @@ > > PASS Test that the target's border bounding box is used to calculate intersection. >-FAIL First rAF. assert_equals: entries[0].boundingClientRect.left expected 25 but got 0 >+PASS First rAF. > FAIL target.style.transform = 'translateY(195px)' assert_equals: entries.length expected 2 but got 1 > >diff --git a/LayoutTests/imported/w3c/web-platform-tests/intersection-observer/containing-block-expected.txt b/LayoutTests/imported/w3c/web-platform-tests/intersection-observer/containing-block-expected.txt >index 73be024490b156e37b0d2e8d1cae773b10669cf7..7499738da3056f5f0cac8eab9e3a987ffdb280bd 100644 >--- a/LayoutTests/imported/w3c/web-platform-tests/intersection-observer/containing-block-expected.txt >+++ b/LayoutTests/imported/w3c/web-platform-tests/intersection-observer/containing-block-expected.txt >@@ -1,6 +1,6 @@ > > PASS IntersectionObserver should only report intersections if root is a containing block ancestor of target. >-FAIL In containing block and intersecting. assert_equals: entries[0].boundingClientRect.left expected 58 but got 0 >+FAIL In containing block and intersecting. assert_equals: entries[0].boundingClientRect.top expected 18 but got 258 > 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 >diff --git a/LayoutTests/imported/w3c/web-platform-tests/intersection-observer/edge-inclusive-intersection-expected.txt b/LayoutTests/imported/w3c/web-platform-tests/intersection-observer/edge-inclusive-intersection-expected.txt >index c8595b0cba5a722fe506d676f06ee5127306b51f..0764338166015b4a8f556ef13872ef6a3a254699 100644 >--- a/LayoutTests/imported/w3c/web-platform-tests/intersection-observer/edge-inclusive-intersection-expected.txt >+++ b/LayoutTests/imported/w3c/web-platform-tests/intersection-observer/edge-inclusive-intersection-expected.txt >@@ -1,6 +1,6 @@ > > PASS IntersectionObserver should detect and report edge-adjacent and zero-area intersections. >-FAIL First rAF. assert_equals: entries[0].boundingClientRect.left expected 8 but got 0 >+PASS First rAF. > 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 >diff --git a/LayoutTests/imported/w3c/web-platform-tests/intersection-observer/isIntersecting-change-events-expected.txt b/LayoutTests/imported/w3c/web-platform-tests/intersection-observer/isIntersecting-change-events-expected.txt >index 666955928ce3700720d0bf91989d2b8a3306b9ab..998e0fa60d0b6a65e9886bd50cd89b3c472922f5 100644 >--- a/LayoutTests/imported/w3c/web-platform-tests/intersection-observer/isIntersecting-change-events-expected.txt >+++ b/LayoutTests/imported/w3c/web-platform-tests/intersection-observer/isIntersecting-change-events-expected.txt >@@ -1,4 +1,4 @@ > > PASS isIntersecting changes should trigger notifications. >-FAIL Rects in initial notifications should report initial positions. assert_equals: Check 1st entry rect.right expected 100 but got 0 >+FAIL Rects in initial notifications should report initial positions. assert_equals: entries[2].target.isIntersecting equals true expected true but got false > >diff --git a/LayoutTests/imported/w3c/web-platform-tests/intersection-observer/remove-element-expected.txt b/LayoutTests/imported/w3c/web-platform-tests/intersection-observer/remove-element-expected.txt >index fc1b4a2bcbaaf9b113d8ac7a87fd52dddc517435..9f9575dce60c263ca4a7aec4399e0cb0459acde2 100644 >--- a/LayoutTests/imported/w3c/web-platform-tests/intersection-observer/remove-element-expected.txt >+++ b/LayoutTests/imported/w3c/web-platform-tests/intersection-observer/remove-element-expected.txt >@@ -1,6 +1,6 @@ > > PASS Verify that not-intersecting notifications are sent when a target is removed from the DOM tree. >-FAIL First rAF assert_equals: entries[0].boundingClientRect.left expected 11 but got 0 >+PASS First rAF > 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 >diff --git a/LayoutTests/imported/w3c/web-platform-tests/intersection-observer/same-document-root-expected.txt b/LayoutTests/imported/w3c/web-platform-tests/intersection-observer/same-document-root-expected.txt >index 1cc69784199d7d690874064eb17348fb138e00cb..35ccde794bdc28c114128b16377273bae8287bed 100644 >--- a/LayoutTests/imported/w3c/web-platform-tests/intersection-observer/same-document-root-expected.txt >+++ b/LayoutTests/imported/w3c/web-platform-tests/intersection-observer/same-document-root-expected.txt >@@ -1,6 +1,6 @@ > > PASS IntersectionObserver in a single document with explicit root. >-FAIL First rAF assert_equals: entries[0].boundingClientRect.left expected 11 but got 0 >+PASS First rAF > 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 >diff --git a/LayoutTests/imported/w3c/web-platform-tests/intersection-observer/unclipped-root-expected.txt b/LayoutTests/imported/w3c/web-platform-tests/intersection-observer/unclipped-root-expected.txt >index af52e04b8bb6a4967cdaae8496def8b0f756320b..75223f295cfd98230a2e3268f2277f03fd6dce41 100644 >--- a/LayoutTests/imported/w3c/web-platform-tests/intersection-observer/unclipped-root-expected.txt >+++ b/LayoutTests/imported/w3c/web-platform-tests/intersection-observer/unclipped-root-expected.txt >@@ -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[0].boundingClientRect.left expected 15 but got 0 >+PASS First rAF. > FAIL target.style.transform = 'translateY(195px)' assert_equals: entries.length expected 2 but got 1 >
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 188809
:
347684
|
347712