Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(712)

Unified Diff: third_party/WebKit/Source/core/dom/IntersectionObservation.cpp

Issue 1449623002: IntersectionObserver: second cut. (Closed) Base URL: https://chromium.googlesource.com/chromium/src@master
Patch Set: Add RuntimeEnabled flags to all idl's, fix test expectations. Created 4 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: third_party/WebKit/Source/core/dom/IntersectionObservation.cpp
diff --git a/third_party/WebKit/Source/core/dom/IntersectionObservation.cpp b/third_party/WebKit/Source/core/dom/IntersectionObservation.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..705a1bf4b3c529ff2b9d531f295e25f9658e7ff0
--- /dev/null
+++ b/third_party/WebKit/Source/core/dom/IntersectionObservation.cpp
@@ -0,0 +1,162 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "core/dom/IntersectionObservation.h"
+
+#include "core/dom/ElementRareData.h"
+#include "core/dom/IntersectionObserver.h"
+#include "core/frame/FrameView.h"
+#include "core/layout/LayoutBox.h"
+#include "core/layout/LayoutText.h"
+#include "core/layout/LayoutView.h"
+#include "core/paint/PaintLayer.h"
+
+namespace blink {
+
+IntersectionObservation::IntersectionObservation(IntersectionObserver& observer, Element& target, bool shouldReportRootBounds)
+ : m_observer(observer)
+ , m_target(target.ensureIntersectionObserverData().createWeakPtr(&target))
+ , m_active(true)
+ , m_shouldReportRootBounds(shouldReportRootBounds)
+ , m_lastThresholdIndex(0)
+{
+}
+
+void IntersectionObservation::initializeGeometry(IntersectionGeometry& geometry)
+{
+ LayoutObject* targetLayoutObject = m_target->layoutObject();
+ if (targetLayoutObject->isBoxModelObject())
+ geometry.targetRect = toLayoutBoxModelObject(targetLayoutObject)->visualOverflowRect();
+ else
+ geometry.targetRect = toLayoutText(targetLayoutObject)->visualOverflowRect();
+ geometry.intersectionRect = geometry.targetRect;
+}
+
+void IntersectionObservation::clipToRoot(LayoutRect& rect)
+{
+ // Map and clip rect into root element coordinates.
+ // TODO(szager): the writing mode flipping needs a test.
+ LayoutObject* rootLayoutObject = m_observer->rootLayoutObject();
+ LayoutObject* targetLayoutObject = m_target->layoutObject();
+ targetLayoutObject->mapToVisibleRectInAncestorSpace(toLayoutBoxModelObject(rootLayoutObject), rect, nullptr);
+ if (rootLayoutObject->hasOverflowClip()) {
+ LayoutBox* rootLayoutBox = toLayoutBox(rootLayoutObject);
+ LayoutRect clipRect(LayoutPoint(), LayoutSize(rootLayoutBox->layer()->size()));
+ rootLayoutBox->flipForWritingMode(rect);
+ rect.intersect(clipRect);
+ rootLayoutBox->flipForWritingMode(rect);
+ }
+}
+
+void IntersectionObservation::clipToFrameView(IntersectionGeometry& geometry)
+{
+ Element* rootElement = m_observer->root();
+ LayoutObject* rootLayoutObject = m_observer->rootLayoutObject();
+ if (rootElement == rootElement->document().documentElement()) {
+ geometry.rootRect = LayoutRect(rootElement->document().view()->visibleContentRect());
+ geometry.intersectionRect.intersect(geometry.rootRect);
+ } else {
+ if (rootLayoutObject->isBox())
+ geometry.rootRect = LayoutRect(toLayoutBox(rootLayoutObject)->absoluteContentBox());
+ else
+ geometry.rootRect = LayoutRect(rootLayoutObject->absoluteBoundingBoxRect());
+ }
+
+ LayoutPoint scrollPosition(rootElement->document().view()->scrollPosition());
+ geometry.targetRect.moveBy(-scrollPosition);
+ geometry.intersectionRect.moveBy(-scrollPosition);
+ geometry.rootRect.moveBy(-scrollPosition);
+}
+
+static void mapRectToDocumentCoordinates(LayoutObject& layoutObject, LayoutRect& rect)
+{
+ rect = LayoutRect(layoutObject.localToAbsoluteQuad(FloatQuad(FloatRect(rect)), UseTransforms | ApplyContainerFlip | TraverseDocumentBoundaries).boundingBox());
+}
+
+bool IntersectionObservation::computeGeometry(IntersectionGeometry& geometry)
+{
+ LayoutObject* rootLayoutObject = m_observer->rootLayoutObject();
+ LayoutObject* targetLayoutObject = m_target->layoutObject();
haraken 2016/01/10 12:22:28 Given that m_target is a WeakMember, it can be cle
szager1 2016/01/10 17:18:26 All of the un-checked uses of m_target are in priv
+ if (!rootLayoutObject->isBoxModelObject())
+ return false;
+ if (!targetLayoutObject->isBoxModelObject() && !targetLayoutObject->isText())
+ return false;
+
+ // Initialize targetRect and intersectionRect to bounds of target, in target's coordinate space.
+ initializeGeometry(geometry);
+
+ // TODO(szager): Support intersection observations for zero-area targets. For now, we just
+ // punt on the observation.
+ if (!geometry.targetRect.size().width() || !geometry.targetRect.size().height())
+ return false;
+
+ // Clip intersectionRect to the root, and map it to root coordinates.
+ clipToRoot(geometry.intersectionRect);
+
+ // Map targetRect into document coordinates.
+ mapRectToDocumentCoordinates(*targetLayoutObject, geometry.targetRect);
+
+ // Map intersectionRect into document coordinates.
+ mapRectToDocumentCoordinates(*rootLayoutObject, geometry.intersectionRect);
+
+ // Clip intersectionRect to FrameView visible area if necessary, and map all geometry to frame coordinates.
+ clipToFrameView(geometry);
+
+ if (geometry.intersectionRect.size().isZero())
+ geometry.intersectionRect = LayoutRect();
+ if (!m_shouldReportRootBounds)
+ geometry.rootRect = LayoutRect();
+
+ return true;
+}
+
+void IntersectionObservation::computeIntersectionObservations(double timestamp)
+{
+ Element* targetElement = target();
+ if (!targetElement || !isActive())
+ return;
+ LayoutObject* targetLayoutObject = targetElement->layoutObject();
+ // TODO(szager): Support SVG
+ if (!targetLayoutObject || (!targetLayoutObject->isBox() && !targetLayoutObject->isInline()))
+ return;
+
+ IntersectionGeometry geometry;
+ if (!computeGeometry(geometry))
+ return;
+
+ float intersectionArea = geometry.intersectionRect.size().width().toFloat() * geometry.intersectionRect.size().height().toFloat();
+ float targetArea = geometry.targetRect.size().width().toFloat() * geometry.targetRect.size().height().toFloat();
+ if (!targetArea)
+ return;
+ float newVisibleRatio = intersectionArea / targetArea;
+ unsigned newThresholdIndex = observer().firstThresholdGreaterThan(newVisibleRatio);
+ if (m_lastThresholdIndex != newThresholdIndex) {
+ IntersectionObserverEntry* newEntry = new IntersectionObserverEntry(
+ timestamp / 1000.0,
+ pixelSnappedIntRect(geometry.targetRect),
+ pixelSnappedIntRect(geometry.rootRect),
+ pixelSnappedIntRect(geometry.intersectionRect),
+ targetElement);
+ observer().enqueueIntersectionObserverEntry(*newEntry);
+ }
+ setLastThresholdIndex(newThresholdIndex);
+}
+
+void IntersectionObservation::disconnect()
+{
+ if (m_target) {
+ m_target->ensureIntersectionObserverData().removeObservation(this->observer());
+ m_target.clear();
+ }
+ m_observer->removeObservation(*this);
+ m_observer.clear();
+}
+
+DEFINE_TRACE(IntersectionObservation)
+{
+ visitor->trace(m_observer);
+ visitor->trace(m_target);
+}
+
+} // namespace blink

Powered by Google App Engine
This is Rietveld 408576698