tor-browser

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

HitTestingTreeNode.cpp (13258B)


      1 /* This Source Code Form is subject to the terms of the Mozilla Public
      2 * License, v. 2.0. If a copy of the MPL was not distributed with this
      3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      4 
      5 #include "HitTestingTreeNode.h"
      6 #include <stack>
      7 
      8 #include "AsyncPanZoomController.h"  // for AsyncPanZoomController
      9 #include "mozilla/StaticPrefs_layout.h"
     10 #include "mozilla/gfx/Point.h"        // for Point4D
     11 #include "mozilla/layers/APZUtils.h"  // for AsyncTransform, CompleteAsyncTransform
     12 #include "mozilla/layers/AsyncDragMetrics.h"  // for AsyncDragMetrics
     13 #include "mozilla/ToString.h"                 // for ToString
     14 #include "nsPrintfCString.h"                  // for nsPrintfCString
     15 #include "UnitTransforms.h"                   // for ViewAs
     16 
     17 static mozilla::LazyLogModule sApzMgrLog("apz.manager");
     18 
     19 namespace mozilla {
     20 namespace layers {
     21 
     22 using gfx::CompositorHitTestInfo;
     23 
     24 HitTestingTreeNode::HitTestingTreeNode(AsyncPanZoomController* aApzc,
     25                                       bool aIsPrimaryHolder,
     26                                       LayersId aLayersId)
     27    : mApzc(aApzc),
     28      mIsPrimaryApzcHolder(aIsPrimaryHolder),
     29      mLockCount(0),
     30      mLayersId(aLayersId),
     31      mFixedPosTarget(ScrollableLayerGuid::NULL_SCROLL_ID),
     32      mStickyPosTarget(ScrollableLayerGuid::NULL_SCROLL_ID),
     33      mOverride(EventRegionsOverride::NoOverride) {
     34  if (mIsPrimaryApzcHolder) {
     35    MOZ_ASSERT(mApzc);
     36  }
     37  MOZ_ASSERT(!mApzc || mApzc->GetLayersId() == mLayersId);
     38 }
     39 
     40 void HitTestingTreeNode::RecycleWith(
     41    const RecursiveMutexAutoLock& aProofOfTreeLock,
     42    AsyncPanZoomController* aApzc, LayersId aLayersId) {
     43  MOZ_ASSERT(IsRecyclable(aProofOfTreeLock));
     44  Destroy();  // clear out tree pointers
     45  mApzc = aApzc;
     46  mLayersId = aLayersId;
     47  MOZ_ASSERT(!mApzc || mApzc->GetLayersId() == mLayersId);
     48  // The caller is expected to call appropriate setters (SetHitTestData,
     49  // SetScrollbarData, SetFixedPosData, SetStickyPosData, etc.) to repopulate
     50  // all the data fields before using this node for "real work". Otherwise
     51  // those data fields may contain stale information from the previous use
     52  // of this node object.
     53 }
     54 
     55 HitTestingTreeNode::~HitTestingTreeNode() = default;
     56 
     57 void HitTestingTreeNode::Destroy() {
     58  // This runs on the updater thread, it's not worth passing around extra raw
     59  // pointers just to assert it.
     60 
     61  mPrevSibling = nullptr;
     62  mLastChild = nullptr;
     63  mParent = nullptr;
     64 
     65  if (mApzc) {
     66    if (mIsPrimaryApzcHolder) {
     67      mApzc->Destroy();
     68    }
     69    mApzc = nullptr;
     70  }
     71 }
     72 
     73 bool HitTestingTreeNode::IsRecyclable(
     74    const RecursiveMutexAutoLock& aProofOfTreeLock) {
     75  return !(IsPrimaryHolder() || (mLockCount > 0));
     76 }
     77 
     78 void HitTestingTreeNode::SetLastChild(HitTestingTreeNode* aChild) {
     79  mLastChild = aChild;
     80  if (aChild) {
     81    aChild->mParent = this;
     82 
     83    if (aChild->GetApzc()) {
     84      AsyncPanZoomController* parent = GetNearestContainingApzc();
     85      // We assume that HitTestingTreeNodes with an ancestor/descendant
     86      // relationship cannot both point to the same APZC instance. This
     87      // assertion only covers a subset of cases in which that might occur,
     88      // but it's better than nothing.
     89      MOZ_ASSERT(aChild->GetApzc() != parent);
     90      aChild->SetApzcParent(parent);
     91    }
     92  }
     93 }
     94 
     95 void HitTestingTreeNode::SetScrollbarData(
     96    const Maybe<uint64_t>& aScrollbarAnimationId,
     97    const ScrollbarData& aScrollbarData) {
     98  mScrollbarAnimationId = aScrollbarAnimationId;
     99  mScrollbarData = aScrollbarData;
    100 }
    101 
    102 bool HitTestingTreeNode::MatchesScrollDragMetrics(
    103    const AsyncDragMetrics& aDragMetrics, LayersId aLayersId) const {
    104  return IsScrollThumbNode() && mLayersId == aLayersId &&
    105         mScrollbarData.mDirection == aDragMetrics.mDirection &&
    106         mScrollbarData.mTargetViewId == aDragMetrics.mViewId;
    107 }
    108 
    109 bool HitTestingTreeNode::IsScrollThumbNode() const {
    110  return mScrollbarData.mScrollbarLayerType ==
    111         layers::ScrollbarLayerType::Thumb;
    112 }
    113 
    114 bool HitTestingTreeNode::IsScrollbarNode() const {
    115  return mScrollbarData.mScrollbarLayerType != layers::ScrollbarLayerType::None;
    116 }
    117 
    118 bool HitTestingTreeNode::IsScrollbarContainerNode() const {
    119  return mScrollbarData.mScrollbarLayerType ==
    120         layers::ScrollbarLayerType::Container;
    121 }
    122 
    123 ScrollDirection HitTestingTreeNode::GetScrollbarDirection() const {
    124  MOZ_ASSERT(IsScrollbarNode());
    125  MOZ_ASSERT(mScrollbarData.mDirection.isSome());
    126  return *mScrollbarData.mDirection;
    127 }
    128 
    129 ScrollableLayerGuid::ViewID HitTestingTreeNode::GetScrollTargetId() const {
    130  return mScrollbarData.mTargetViewId;
    131 }
    132 
    133 Maybe<uint64_t> HitTestingTreeNode::GetScrollbarAnimationId() const {
    134  return mScrollbarAnimationId;
    135 }
    136 
    137 const ScrollbarData& HitTestingTreeNode::GetScrollbarData() const {
    138  return mScrollbarData;
    139 }
    140 
    141 void HitTestingTreeNode::SetFixedPosData(
    142    ScrollableLayerGuid::ViewID aFixedPosTarget, SideBits aFixedPosSides,
    143    const Maybe<uint64_t>& aFixedPositionAnimationId) {
    144  mFixedPosTarget = aFixedPosTarget;
    145  mFixedPosSides = aFixedPosSides;
    146  mFixedPositionAnimationId = aFixedPositionAnimationId;
    147 }
    148 
    149 ScrollableLayerGuid::ViewID HitTestingTreeNode::GetFixedPosTarget() const {
    150  return mFixedPosTarget;
    151 }
    152 
    153 SideBits HitTestingTreeNode::GetFixedPosSides() const { return mFixedPosSides; }
    154 
    155 Maybe<uint64_t> HitTestingTreeNode::GetFixedPositionAnimationId() const {
    156  return mFixedPositionAnimationId;
    157 }
    158 
    159 void HitTestingTreeNode::SetPrevSibling(HitTestingTreeNode* aSibling) {
    160  mPrevSibling = aSibling;
    161  if (aSibling) {
    162    aSibling->mParent = mParent;
    163 
    164    if (aSibling->GetApzc()) {
    165      AsyncPanZoomController* parent =
    166          mParent ? mParent->GetNearestContainingApzc() : nullptr;
    167      aSibling->SetApzcParent(parent);
    168    }
    169  }
    170 }
    171 
    172 void HitTestingTreeNode::SetStickyPosData(
    173    ScrollableLayerGuid::ViewID aStickyPosTarget,
    174    const LayerRectAbsolute& aScrollRangeOuter,
    175    const LayerRectAbsolute& aScrollRangeInner,
    176    const Maybe<uint64_t>& aStickyPositionAnimationId) {
    177  mStickyPosTarget = aStickyPosTarget;
    178  mStickyScrollRangeOuter = aScrollRangeOuter;
    179  mStickyScrollRangeInner = aScrollRangeInner;
    180  mStickyPositionAnimationId = aStickyPositionAnimationId;
    181 }
    182 
    183 ScrollableLayerGuid::ViewID HitTestingTreeNode::GetStickyPosTarget() const {
    184  return mStickyPosTarget;
    185 }
    186 
    187 const LayerRectAbsolute& HitTestingTreeNode::GetStickyScrollRangeOuter() const {
    188  return mStickyScrollRangeOuter;
    189 }
    190 
    191 const LayerRectAbsolute& HitTestingTreeNode::GetStickyScrollRangeInner() const {
    192  return mStickyScrollRangeInner;
    193 }
    194 
    195 Maybe<uint64_t> HitTestingTreeNode::GetStickyPositionAnimationId() const {
    196  return mStickyPositionAnimationId;
    197 }
    198 
    199 void HitTestingTreeNode::MakeRoot() {
    200  mParent = nullptr;
    201 
    202  if (GetApzc()) {
    203    SetApzcParent(nullptr);
    204  }
    205 }
    206 
    207 HitTestingTreeNode* HitTestingTreeNode::GetFirstChild() const {
    208  HitTestingTreeNode* child = GetLastChild();
    209  while (child && child->GetPrevSibling()) {
    210    child = child->GetPrevSibling();
    211  }
    212  return child;
    213 }
    214 
    215 HitTestingTreeNode* HitTestingTreeNode::GetLastChild() const {
    216  return mLastChild;
    217 }
    218 
    219 HitTestingTreeNode* HitTestingTreeNode::GetPrevSibling() const {
    220  return mPrevSibling;
    221 }
    222 
    223 HitTestingTreeNode* HitTestingTreeNode::GetParent() const { return mParent; }
    224 
    225 bool HitTestingTreeNode::IsAncestorOf(const HitTestingTreeNode* aOther) const {
    226  for (const HitTestingTreeNode* cur = aOther; cur; cur = cur->GetParent()) {
    227    if (cur == this) {
    228      return true;
    229    }
    230  }
    231  return false;
    232 }
    233 
    234 AsyncPanZoomController* HitTestingTreeNode::GetApzc() const { return mApzc; }
    235 
    236 AsyncPanZoomController* HitTestingTreeNode::GetNearestContainingApzc() const {
    237  for (const HitTestingTreeNode* n = this; n; n = n->GetParent()) {
    238    if (n->GetApzc()) {
    239      return n->GetApzc();
    240    }
    241  }
    242  return nullptr;
    243 }
    244 
    245 bool HitTestingTreeNode::IsPrimaryHolder() const {
    246  return mIsPrimaryApzcHolder;
    247 }
    248 
    249 LayersId HitTestingTreeNode::GetLayersId() const { return mLayersId; }
    250 
    251 void HitTestingTreeNode::SetHitTestData(
    252    const LayerIntRect& aVisibleRect, const LayerIntSize& aRemoteDocumentSize,
    253    const CSSTransformMatrix& aTransform, const EventRegionsOverride& aOverride,
    254    const Maybe<ScrollableLayerGuid::ViewID>& aAsyncZoomContainerId) {
    255  mVisibleRect = aVisibleRect;
    256  mRemoteDocumentSize = aRemoteDocumentSize;
    257  mTransform = aTransform;
    258  mOverride = aOverride;
    259  mAsyncZoomContainerId = aAsyncZoomContainerId;
    260 }
    261 
    262 EventRegionsOverride HitTestingTreeNode::GetEventRegionsOverride() const {
    263  return mOverride;
    264 }
    265 
    266 const CSSTransformMatrix& HitTestingTreeNode::GetTransform() const {
    267  return mTransform;
    268 }
    269 
    270 LayerToScreenMatrix4x4 HitTestingTreeNode::GetTransformToGecko(
    271    LayersId aRemoteLayersId) const {
    272  if (mParent) {
    273    LayerToParentLayerMatrix4x4 thisToParent =
    274        mTransform * AsyncTransformMatrix();
    275    if (mApzc) {
    276      thisToParent =
    277          thisToParent * ViewAs<AsyncTransformComponentMatrix>(
    278                             mApzc->GetTransformToLastDispatchedPaint(
    279                                 LayoutAndVisual, aRemoteLayersId));
    280    }
    281    ParentLayerToScreenMatrix4x4 parentToRoot =
    282        ViewAs<ParentLayerToScreenMatrix4x4>(
    283            mParent->GetTransformToGecko(aRemoteLayersId),
    284            PixelCastJustification::MovingDownToChildren);
    285    return thisToParent * parentToRoot;
    286  }
    287 
    288  return ViewAs<LayerToScreenMatrix4x4>(
    289      mTransform * AsyncTransformMatrix(),
    290      PixelCastJustification::ScreenIsParentLayerForRoot);
    291 }
    292 
    293 const LayerIntRect& HitTestingTreeNode::GetVisibleRect() const {
    294  return mVisibleRect;
    295 }
    296 
    297 ScreenRect HitTestingTreeNode::GetRemoteDocumentScreenRect(
    298    LayersId aRemoteDocumentLayersId) const {
    299  ScreenRect result = TransformBy(
    300      GetTransformToGecko(aRemoteDocumentLayersId),
    301      IntRectToRect(LayerIntRect(LayerIntPoint(), mRemoteDocumentSize)));
    302 
    303  for (const HitTestingTreeNode* node = this; node; node = node->GetParent()) {
    304    if (!node->GetApzc()) {
    305      continue;
    306    }
    307 
    308    ParentLayerRect compositionBounds = node->GetApzc()->GetCompositionBounds();
    309    if (compositionBounds.IsEmpty()) {
    310      return ScreenRect();
    311    }
    312 
    313    ScreenRect scrollPortOnScreenCoordinate = TransformBy(
    314        node->GetParent()
    315            ? node->GetParent()->GetTransformToGecko(node->GetLayersId())
    316            : LayerToScreenMatrix4x4(),
    317        ViewAs<LayerPixel>(compositionBounds,
    318                           PixelCastJustification::MovingDownToChildren));
    319    if (scrollPortOnScreenCoordinate.IsEmpty()) {
    320      return ScreenRect();
    321    }
    322 
    323    result = result.Intersect(scrollPortOnScreenCoordinate);
    324    if (result.IsEmpty()) {
    325      return ScreenRect();
    326    }
    327  }
    328  return result;
    329 }
    330 
    331 Maybe<ScrollableLayerGuid::ViewID> HitTestingTreeNode::GetAsyncZoomContainerId()
    332    const {
    333  return mAsyncZoomContainerId;
    334 }
    335 
    336 void HitTestingTreeNode::Dump(const char* aPrefix) const {
    337  MOZ_LOG(
    338      sApzMgrLog, LogLevel::Debug,
    339      ("%sHitTestingTreeNode (%p) APZC (%p) g=(%s) %s%s%s t=(%s) "
    340       "%s%s\n",
    341       aPrefix, this, mApzc.get(),
    342       mApzc ? ToString(mApzc->GetGuid()).c_str()
    343             : nsPrintfCString("l=0x%" PRIx64, uint64_t(mLayersId)).get(),
    344       (mOverride & EventRegionsOverride::ForceDispatchToContent) ? "fdtc "
    345                                                                  : "",
    346       (mOverride & EventRegionsOverride::ForceEmptyHitRegion) ? "fehr " : "",
    347       (mFixedPosTarget != ScrollableLayerGuid::NULL_SCROLL_ID)
    348           ? nsPrintfCString("fixed=%" PRIu64 " ", mFixedPosTarget).get()
    349           : "",
    350       ToString(mTransform).c_str(),
    351       mScrollbarData.mDirection.isSome() ? " scrollbar" : "",
    352       IsScrollThumbNode() ? " scrollthumb" : ""));
    353 
    354  if (!mLastChild) {
    355    return;
    356  }
    357 
    358  // Dump the children in order from first child to last child
    359  std::stack<HitTestingTreeNode*> children;
    360  for (HitTestingTreeNode* child = mLastChild.get(); child;
    361       child = child->mPrevSibling) {
    362    children.push(child);
    363  }
    364  nsPrintfCString childPrefix("%s  ", aPrefix);
    365  while (!children.empty()) {
    366    children.top()->Dump(childPrefix.get());
    367    children.pop();
    368  }
    369 }
    370 
    371 void HitTestingTreeNode::SetApzcParent(AsyncPanZoomController* aParent) {
    372  // precondition: GetApzc() is non-null
    373  MOZ_ASSERT(GetApzc() != nullptr);
    374  if (IsPrimaryHolder()) {
    375    GetApzc()->SetParent(aParent);
    376  } else {
    377    MOZ_ASSERT(GetApzc()->GetParent() == aParent);
    378  }
    379 }
    380 
    381 void HitTestingTreeNode::Lock(const RecursiveMutexAutoLock& aProofOfTreeLock) {
    382  mLockCount++;
    383 }
    384 
    385 void HitTestingTreeNode::Unlock(
    386    const RecursiveMutexAutoLock& aProofOfTreeLock) {
    387  MOZ_ASSERT(mLockCount > 0);
    388  mLockCount--;
    389 }
    390 
    391 HitTestingTreeNodeAutoLock::HitTestingTreeNodeAutoLock()
    392    : mTreeMutex(nullptr) {}
    393 
    394 HitTestingTreeNodeAutoLock::~HitTestingTreeNodeAutoLock() { Clear(); }
    395 
    396 void HitTestingTreeNodeAutoLock::Initialize(
    397    const RecursiveMutexAutoLock& aProofOfTreeLock,
    398    already_AddRefed<HitTestingTreeNode> aNode, RecursiveMutex& aTreeMutex) {
    399  MOZ_ASSERT(!mNode);
    400 
    401  mNode = aNode;
    402  mTreeMutex = &aTreeMutex;
    403 
    404  mNode->Lock(aProofOfTreeLock);
    405 }
    406 
    407 void HitTestingTreeNodeAutoLock::Clear() {
    408  if (!mNode) {
    409    return;
    410  }
    411  MOZ_ASSERT(mTreeMutex);
    412 
    413  {  // scope lock
    414    RecursiveMutexAutoLock lock(*mTreeMutex);
    415    mNode->Unlock(lock);
    416  }
    417  mNode = nullptr;
    418  mTreeMutex = nullptr;
    419 }
    420 
    421 }  // namespace layers
    422 }  // namespace mozilla