| // Copyright 2016 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #ifndef THIRD_PARTY_BLINK_RENDERER_CORE_INTERSECTION_OBSERVER_INTERSECTION_OBSERVATION_H_ |
| #define THIRD_PARTY_BLINK_RENDERER_CORE_INTERSECTION_OBSERVER_INTERSECTION_OBSERVATION_H_ |
| |
| #include <optional> |
| |
| #include "base/time/time.h" |
| #include "third_party/blink/renderer/core/core_export.h" |
| #include "third_party/blink/renderer/core/dom/dom_high_res_time_stamp.h" |
| #include "third_party/blink/renderer/core/intersection_observer/intersection_geometry.h" |
| #include "third_party/blink/renderer/platform/heap/collection_support/heap_vector.h" |
| #include "third_party/blink/renderer/platform/heap/garbage_collected.h" |
| |
| namespace blink { |
| |
| class ComputeIntersectionsContext; |
| class Element; |
| class IntersectionObserver; |
| class IntersectionObserverEntry; |
| |
| // IntersectionObservation represents the result of calling |
| // IntersectionObserver::observe(target) for some target element; it tracks the |
| // intersection between a single target element and the IntersectionObserver's |
| // root. It is an implementation-internal class without any exposed interface. |
| class CORE_EXPORT IntersectionObservation final |
| : public GarbageCollected<IntersectionObservation> { |
| public: |
| // Flags that drive the behavior of the ComputeIntersections() method. For an |
| // explanation of implicit vs. explicit root, see intersection_observer.h. |
| enum ComputeFlags { |
| // If this bit is set, and observer_->RootIsImplicit() is true, then the |
| // root bounds (i.e., size of the top document's viewport) should be |
| // included in any IntersectionObserverEntry objects created by Compute(). |
| kReportImplicitRootBounds = 1 << 0, |
| // If this bit is set, and observer_->RootIsImplicit() is false, then |
| // Compute() should update the observation. |
| kExplicitRootObserversNeedUpdate = 1 << 1, |
| // If this bit is set, and observer_->RootIsImplicit() is true, then |
| // Compute() should update the observation. |
| kImplicitRootObserversNeedUpdate = 1 << 2, |
| // If this bit is set, it indicates that at least one LocalFrameView |
| // ancestor is detached from the LayoutObject tree of its parent. Usually, |
| // this is unnecessary -- if an ancestor FrameView is detached, then all |
| // descendant frames are detached. There is, however, at least one exception |
| // to this rule; see crbug.com/749737 for details. |
| kAncestorFrameIsDetachedFromLayout = 1 << 3, |
| // If this bit is set, then the observer.delay parameter is ignored; i.e., |
| // the computation will run even if the previous run happened within the |
| // delay parameter. |
| kIgnoreDelay = 1 << 4, |
| // If this bit is set, we can skip tracking the sticky frame during |
| // UpdateViewportIntersectionsForSubtree. |
| kCanSkipStickyFrameTracking = 1 << 5, |
| // If this bit is set, we only process intersection observations that |
| // require post-layout delivery. |
| kPostLayoutDeliveryOnly = 1 << 6, |
| // Corresponding to LocalFrameView::kScrollAndVisibilityOnly. |
| kScrollAndVisibilityOnly = 1 << 7, |
| // If set, any accumulated_scroll_delta passed to ComputeIntersection() will |
| // be applied to cached_rects_.min_scroll_delta_to_update. |
| kConsumeScrollDelta = 1 << 8, |
| // Remove outdated entries from IntersectionObserverController. |
| kUpdateTracking = 1 << 9, |
| }; |
| |
| IntersectionObservation(IntersectionObserver&, Element&); |
| |
| IntersectionObserver* Observer() const { return observer_.Get(); } |
| Element* Target() const { return target_.Get(); } |
| // Returns true if root and target are valid, connected, and have the required |
| // DOM hierarchy to compute an intersection. |
| bool CanCompute() const; |
| // Returns 1 if the geometry was recalculated, otherwise 0. This could be a |
| // bool, but int64_t matches IntersectionObserver::ComputeIntersections(). |
| int64_t ComputeIntersection( |
| unsigned flags, |
| gfx::Vector2dF accumulated_scroll_delta_since_last_update, |
| ComputeIntersectionsContext&); |
| gfx::Vector2dF MinScrollDeltaToUpdate() const; |
| void TakeRecords(HeapVector<Member<IntersectionObserverEntry>>&); |
| void Disconnect(); |
| |
| void Trace(Visitor*) const; |
| |
| bool CanUseCachedRectsForTesting(bool scroll_and_visibility_only) const; |
| bool HasPendingUpdateForTesting() const { return needs_update_; } |
| |
| private: |
| bool ShouldCompute(unsigned flags) const; |
| bool MaybeDelayAndReschedule(unsigned flags, ComputeIntersectionsContext&); |
| unsigned GetIntersectionGeometryFlags(unsigned compute_flags) const; |
| // Inspect the geometry to see if there has been a transition event; if so, |
| // generate a notification and schedule it for delivery. |
| void ProcessIntersectionGeometry(const IntersectionGeometry& geometry, |
| ComputeIntersectionsContext&); |
| |
| Member<IntersectionObserver> observer_; |
| WeakMember<Element> target_; |
| HeapVector<Member<IntersectionObserverEntry>> entries_; |
| base::TimeTicks last_run_time_; |
| |
| IntersectionGeometry::CachedRects cached_rects_; |
| |
| wtf_size_t last_threshold_index_ = kNotFound; |
| bool last_is_visible_ = false; |
| |
| // Ensures update even if kExplicitRootObserversNeedUpdate or |
| // kImplicitRootObserversNeedUpdate is not specified in flags. |
| // It ensures the initial update, and if a needed update is skipped for some |
| // reason, the flag will be true until the update is done. |
| bool needs_update_ = true; |
| }; |
| |
| } // namespace blink |
| |
| #endif // THIRD_PARTY_BLINK_RENDERER_CORE_INTERSECTION_OBSERVER_INTERSECTION_OBSERVATION_H_ |