1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90
|
// 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/layout/IntersectionGeometry.h"
namespace blink {
IntersectionObservation::IntersectionObservation(IntersectionObserver& observer,
Element& target,
bool shouldReportRootBounds)
: m_observer(observer),
m_target(&target),
m_shouldReportRootBounds(shouldReportRootBounds),
m_lastThresholdIndex(0) {}
void IntersectionObservation::computeIntersectionObservations(
DOMHighResTimeStamp timestamp) {
DCHECK(observer());
if (!m_target)
return;
Vector<Length> rootMargin(4);
rootMargin[0] = m_observer->topMargin();
rootMargin[1] = m_observer->rightMargin();
rootMargin[2] = m_observer->bottomMargin();
rootMargin[3] = m_observer->leftMargin();
IntersectionGeometry geometry(m_observer->root(), *target(), rootMargin,
m_shouldReportRootBounds);
geometry.computeGeometry();
// Some corner cases for threshold index:
// - If target rect is zero area, because it has zero width and/or zero
// height,
// only two states are recognized:
// - 0 means not intersecting.
// - 1 means intersecting.
// No other threshold crossings are possible.
// - Otherwise:
// - If root and target do not intersect, the threshold index is 0.
// - If root and target intersect but the intersection has zero-area
// (i.e., they have a coincident edge or corner), we consider the
// intersection to have "crossed" a zero threshold, but not crossed
// any non-zero threshold.
unsigned newThresholdIndex;
float newVisibleRatio;
if (geometry.doesIntersect()) {
if (geometry.targetRect().isEmpty()) {
newVisibleRatio = 1;
} else {
float intersectionArea =
geometry.intersectionRect().size().width().toFloat() *
geometry.intersectionRect().size().height().toFloat();
float targetArea = geometry.targetRect().size().width().toFloat() *
geometry.targetRect().size().height().toFloat();
newVisibleRatio = intersectionArea / targetArea;
}
newThresholdIndex = observer()->firstThresholdGreaterThan(newVisibleRatio);
} else {
newVisibleRatio = 0;
newThresholdIndex = 0;
}
if (m_lastThresholdIndex != newThresholdIndex) {
IntRect snappedRootBounds = geometry.rootIntRect();
IntRect* rootBoundsPointer =
m_shouldReportRootBounds ? &snappedRootBounds : nullptr;
IntersectionObserverEntry* newEntry = new IntersectionObserverEntry(
timestamp, newVisibleRatio, geometry.targetIntRect(), rootBoundsPointer,
geometry.intersectionIntRect(), target());
observer()->enqueueIntersectionObserverEntry(*newEntry);
setLastThresholdIndex(newThresholdIndex);
}
}
void IntersectionObservation::disconnect() {
DCHECK(observer());
if (m_target)
target()->ensureIntersectionObserverData().removeObservation(*observer());
m_observer.clear();
}
DEFINE_TRACE(IntersectionObservation) {
visitor->trace(m_observer);
visitor->trace(m_target);
}
} // namespace blink
|