tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

DOMIntersectionObserver.h (8575B)


      1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
      3 /* This Source Code Form is subject to the terms of the Mozilla Public
      4 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
      5 * You can obtain one at http://mozilla.org/MPL/2.0/. */
      6 
      7 #ifndef DOMIntersectionObserver_h
      8 #define DOMIntersectionObserver_h
      9 
     10 #include "mozilla/Attributes.h"
     11 #include "mozilla/ServoStyleConsts.h"
     12 #include "mozilla/Variant.h"
     13 #include "mozilla/dom/IntersectionObserverBinding.h"
     14 #include "nsDOMNavigationTiming.h"
     15 #include "nsTArray.h"
     16 #include "nsTHashSet.h"
     17 
     18 namespace mozilla::dom {
     19 
     20 class DOMIntersectionObserver;
     21 
     22 class DOMIntersectionObserverEntry final : public nsISupports,
     23                                           public nsWrapperCache {
     24  ~DOMIntersectionObserverEntry() = default;
     25 
     26 public:
     27  DOMIntersectionObserverEntry(nsISupports* aOwner, DOMHighResTimeStamp aTime,
     28                               RefPtr<DOMRect> aRootBounds,
     29                               RefPtr<DOMRect> aBoundingClientRect,
     30                               RefPtr<DOMRect> aIntersectionRect,
     31                               bool aIsIntersecting, Element* aTarget,
     32                               double aIntersectionRatio)
     33      : mOwner(aOwner),
     34        mTime(aTime),
     35        mRootBounds(std::move(aRootBounds)),
     36        mBoundingClientRect(std::move(aBoundingClientRect)),
     37        mIntersectionRect(std::move(aIntersectionRect)),
     38        mIsIntersecting(aIsIntersecting),
     39        mTarget(aTarget),
     40        mIntersectionRatio(aIntersectionRatio) {}
     41  NS_DECL_CYCLE_COLLECTING_ISUPPORTS
     42  NS_DECL_CYCLE_COLLECTION_WRAPPERCACHE_CLASS(DOMIntersectionObserverEntry)
     43 
     44  nsISupports* GetParentObject() const { return mOwner; }
     45 
     46  JSObject* WrapObject(JSContext* aCx,
     47                       JS::Handle<JSObject*> aGivenProto) override {
     48    return IntersectionObserverEntry_Binding::Wrap(aCx, this, aGivenProto);
     49  }
     50 
     51  DOMHighResTimeStamp Time() const { return mTime; }
     52 
     53  DOMRect* GetRootBounds() { return mRootBounds; }
     54 
     55  DOMRect* BoundingClientRect() { return mBoundingClientRect; }
     56 
     57  DOMRect* IntersectionRect() { return mIntersectionRect; }
     58 
     59  bool IsIntersecting() const { return mIsIntersecting; }
     60 
     61  double IntersectionRatio() const { return mIntersectionRatio; }
     62 
     63  Element* Target() { return mTarget; }
     64 
     65 protected:
     66  nsCOMPtr<nsISupports> mOwner;
     67  DOMHighResTimeStamp mTime;
     68  RefPtr<DOMRect> mRootBounds;
     69  RefPtr<DOMRect> mBoundingClientRect;
     70  RefPtr<DOMRect> mIntersectionRect;
     71  bool mIsIntersecting;
     72  RefPtr<Element> mTarget;
     73  double mIntersectionRatio;
     74 };
     75 
     76 #define NS_DOM_INTERSECTION_OBSERVER_IID \
     77  {0x8570a575, 0xe303, 0x4d18, {0xb6, 0xb1, 0x4d, 0x2b, 0x49, 0xd8, 0xef, 0x94}}
     78 
     79 using IntersectionObserverMargin = StyleRect<LengthPercentage>;
     80 
     81 // An input suitable to compute intersections with multiple targets.
     82 struct IntersectionInput {
     83  // Whether the root is implicit (null, originally).
     84  const bool mIsImplicitRoot = false;
     85  // The computed root node. For the implicit root, this will be the in-process
     86  // root document we can compute coordinates against (along with the remote
     87  // document visible rect if appropriate).
     88  const nsINode* mRootNode = nullptr;
     89  nsIFrame* mRootFrame = nullptr;
     90  // The rect of mRootFrame in client coordinates.
     91  nsRect mRootRect;
     92  // The root margin computed against the root rect.
     93  nsMargin mRootMargin;
     94  // The scroll margin computed against the root rect.
     95  IntersectionObserverMargin mScrollMargin;
     96  // If this is in an OOP iframe, the visible rect of the OOP frame.
     97  Maybe<nsRect> mRemoteDocumentVisibleRect;
     98 };
     99 
    100 struct IntersectionOutput {
    101  const bool mIsSimilarOrigin;
    102  const nsRect mRootBounds;
    103  const nsRect mTargetRect;
    104  const Maybe<nsRect> mIntersectionRect;
    105  // See aPreservesAxisAlignedRectangles of
    106  // nsLayoutUtils::TransformFrameRectToAncestor().
    107  // https://searchfox.org/firefox-main/rev/e2cbda2dd0f622553b5c825f319832db4863f6a4/layout/base/nsLayoutUtils.h#829-830
    108  const bool mPreservesAxisAlignedRectangles;
    109 
    110  bool Intersects() const { return mIntersectionRect.isSome(); }
    111 };
    112 
    113 class DOMIntersectionObserver final : public nsISupports,
    114                                      public nsWrapperCache {
    115  virtual ~DOMIntersectionObserver() { Disconnect(); }
    116 
    117  using NativeCallback = void (*)(
    118      const Sequence<OwningNonNull<DOMIntersectionObserverEntry>>& aEntries);
    119  DOMIntersectionObserver(Document&, NativeCallback);
    120 
    121 public:
    122  DOMIntersectionObserver(already_AddRefed<nsPIDOMWindowInner>&& aOwner,
    123                          dom::IntersectionCallback& aCb);
    124  NS_DECL_CYCLE_COLLECTING_ISUPPORTS
    125  NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(DOMIntersectionObserver)
    126  NS_INLINE_DECL_STATIC_IID(NS_DOM_INTERSECTION_OBSERVER_IID)
    127 
    128  static already_AddRefed<DOMIntersectionObserver> Constructor(
    129      const GlobalObject&, dom::IntersectionCallback&, ErrorResult&);
    130  static already_AddRefed<DOMIntersectionObserver> Constructor(
    131      const GlobalObject&, dom::IntersectionCallback&,
    132      const IntersectionObserverInit&, ErrorResult&);
    133 
    134  JSObject* WrapObject(JSContext* aCx,
    135                       JS::Handle<JSObject*> aGivenProto) override {
    136    return IntersectionObserver_Binding::Wrap(aCx, this, aGivenProto);
    137  }
    138 
    139  nsISupports* GetParentObject() const;
    140 
    141  nsINode* GetRoot() const { return mRoot; }
    142 
    143  void GetRootMargin(nsACString&);
    144  bool SetRootMargin(const nsACString&);
    145 
    146  void GetScrollMargin(nsACString&);
    147  bool SetScrollMargin(const nsACString&);
    148 
    149  void GetThresholds(nsTArray<double>& aRetVal);
    150  void Observe(Element& aTarget);
    151  void Unobserve(Element& aTarget);
    152 
    153  void UnlinkTarget(Element& aTarget);
    154  void Disconnect();
    155 
    156  void TakeRecords(nsTArray<RefPtr<DOMIntersectionObserverEntry>>& aRetVal);
    157 
    158  static IntersectionInput ComputeInputForIframeThrottling(const Document&);
    159  static IntersectionInput ComputeInput(
    160      const Document& aDocument, const nsINode* aRoot,
    161      const StyleRect<LengthPercentage>* aRootMargin,
    162      const StyleRect<LengthPercentage>* aScrollMargin);
    163 
    164  enum class IsForProximityToViewport : bool { No, Yes };
    165  enum class BoxToUse : uint8_t {
    166    Content,
    167    Border,
    168    OverflowClip,
    169  };
    170  static IntersectionOutput Intersect(
    171      const IntersectionInput&, const Element&, BoxToUse = BoxToUse::Border,
    172      IsForProximityToViewport = IsForProximityToViewport::No);
    173  static IntersectionOutput Intersect(
    174      const IntersectionInput&, nsIFrame*, BoxToUse = BoxToUse::Border,
    175      IsForProximityToViewport = IsForProximityToViewport::No);
    176  // Intersects with a given rect, already relative to the root frame.
    177  static IntersectionOutput Intersect(const IntersectionInput&, const nsRect&);
    178 
    179  void Update(Document& aDocument, DOMHighResTimeStamp time);
    180  MOZ_CAN_RUN_SCRIPT void Notify();
    181 
    182  static already_AddRefed<DOMIntersectionObserver> CreateLazyLoadObserver(
    183      Document&);
    184 
    185  static Maybe<nsRect> EdgeInclusiveIntersection(const nsRect& aRect,
    186                                                 const nsRect& aOtherRect);
    187 
    188 protected:
    189  void Connect();
    190  void QueueIntersectionObserverEntry(Element* aTarget,
    191                                      DOMHighResTimeStamp time,
    192                                      const Maybe<nsRect>& aRootRect,
    193                                      const nsRect& aTargetRect,
    194                                      const Maybe<nsRect>& aIntersectionRect,
    195                                      bool aIsIntersecting,
    196                                      double aIntersectionRatio);
    197 
    198  nsCOMPtr<nsPIDOMWindowInner> mOwner;
    199  RefPtr<Document> mDocument;
    200  Variant<RefPtr<dom::IntersectionCallback>, NativeCallback> mCallback;
    201  RefPtr<nsINode> mRoot;
    202  StyleRect<LengthPercentage> mRootMargin;
    203  StyleRect<LengthPercentage> mScrollMargin;
    204  AutoTArray<double, 1> mThresholds;
    205 
    206  // These hold raw pointers which are explicitly cleared by UnlinkTarget().
    207  //
    208  // We keep a set and an array because we need ordered access, but also
    209  // constant time lookup.
    210  nsTArray<Element*> mObservationTargets;
    211 
    212  // Value can be:
    213  //   -2:   Makes sure next calculated threshold always differs, leading to a
    214  //         notification task being scheduled.
    215  //   -1:   Non-intersecting.
    216  //   >= 0: Intersecting, valid index of aObserver->mThresholds.
    217  enum ObservationState : int32_t { Uninitialized = -2, NotIntersecting = -1 };
    218  nsTHashMap<Element*, int32_t> mObservationTargetMap;
    219 
    220  nsTArray<RefPtr<DOMIntersectionObserverEntry>> mQueuedEntries;
    221  bool mConnected = false;
    222 };
    223 
    224 }  // namespace mozilla::dom
    225 
    226 #endif