tor-browser

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

WebRenderScrollDataWrapper.h (19030B)


      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
      5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      6 
      7 #ifndef GFX_WEBRENDERSCROLLDATAWRAPPER_H
      8 #define GFX_WEBRENDERSCROLLDATAWRAPPER_H
      9 
     10 #include "FrameMetrics.h"
     11 #include "mozilla/layers/APZUpdater.h"
     12 #include "mozilla/layers/CompositorBridgeParent.h"
     13 #include "mozilla/layers/WebRenderBridgeParent.h"
     14 #include "mozilla/layers/WebRenderScrollData.h"
     15 
     16 namespace mozilla {
     17 namespace layers {
     18 
     19 /**
     20 * A wrapper class around a target WebRenderLayerScrollData (henceforth,
     21 * "layer") that allows user code to walk through the ScrollMetadata objects
     22 * on the layer the same way it would walk through a layer tree.
     23 * Consider the following layer tree:
     24 *
     25 *                    +---+
     26 *                    | A |
     27 *                    +---+
     28 *                   /  |  \
     29 *                  /   |   \
     30 *                 /    |    \
     31 *            +---+  +-----+  +---+
     32 *            | B |  |  C  |  | D |
     33 *            +---+  +-----+  +---+
     34 *                   | SMn |
     35 *                   |  .  |
     36 *                   |  .  |
     37 *                   |  .  |
     38 *                   | SM1 |
     39 *                   | SM0 |
     40 *                   +-----+
     41 *                   /     \
     42 *                  /       \
     43 *             +---+         +---+
     44 *             | E |         | F |
     45 *             +---+         +---+
     46 *
     47 * In this layer tree, there are six layers with A being the root and B,D,E,F
     48 * being leaf nodes. Layer C is in the middle and has n+1 ScrollMetadata,
     49 * labelled SM0...SMn. SM0 is the ScrollMetadata you get by calling
     50 * c->GetScrollMetadata(0) and SMn is the ScrollMetadata you can obtain by
     51 * calling c->GetScrollMetadata(c->GetScrollMetadataCount() - 1). This layer
     52 * tree is conceptually equivalent to this one below:
     53 *
     54 *                    +---+
     55 *                    | A |
     56 *                    +---+
     57 *                   /  |  \
     58 *                  /   |   \
     59 *                 /    |    \
     60 *            +---+  +-----+  +---+
     61 *            | B |  | Cn  |  | D |
     62 *            +---+  +-----+  +---+
     63 *                      |
     64 *                      .
     65 *                      .
     66 *                      .
     67 *                      |
     68 *                   +-----+
     69 *                   | C1  |
     70 *                   +-----+
     71 *                      |
     72 *                   +-----+
     73 *                   | C0  |
     74 *                   +-----+
     75 *                   /     \
     76 *                  /       \
     77 *             +---+         +---+
     78 *             | E |         | F |
     79 *             +---+         +---+
     80 *
     81 * In this layer tree, the layer C has been expanded into a stack of layers
     82 * C1...Cn, where C1 has ScrollMetadata SM1 and Cn has ScrollMetdata Fn.
     83 *
     84 * The WebRenderScrollDataWrapper class allows client code to treat the first
     85 * layer tree as though it were the second. That is, instead of client code
     86 * having to iterate through the ScrollMetadata objects directly, it can use a
     87 * WebRenderScrollDataWrapper to encapsulate that aspect of the layer tree and
     88 * just walk the tree as if it were a stack of layers.
     89 *
     90 * The functions on this class do different things depending on which
     91 * simulated layer is being wrapped. For example, if the
     92 * WebRenderScrollDataWrapper is pretending to be C0, the GetPrevSibling()
     93 * function will return null even though the underlying layer C does actually
     94 * have a prev sibling. The WebRenderScrollDataWrapper pretending to be Cn will
     95 * return B as the prev sibling.
     96 *
     97 * Implementation notes:
     98 *
     99 * The AtTopLayer() and AtBottomLayer() functions in this class refer to
    100 * Cn and C0 in the second layer tree above; that is, they are predicates
    101 * to test if the wrapper is simulating the topmost or bottommost layer, as
    102 * those can have special behaviour.
    103 *
    104 * It is possible to wrap a nullptr in a WebRenderScrollDataWrapper, in which
    105 * case the IsValid() function will return false. This is required to allow
    106 * WebRenderScrollDataWrapper to be a MOZ_STACK_CLASS (desirable because it is
    107 * used in loops and recursion).
    108 *
    109 * This class purposely does not expose the wrapped layer directly to avoid
    110 * user code from accidentally calling functions directly on it. Instead
    111 * any necessary functions should be wrapped in this class. It does expose
    112 * the wrapped layer as a void* for printf purposes.
    113 *
    114 * The implementation may look like it special-cases mIndex == 0 and/or
    115 * GetScrollMetadataCount() == 0. This is an artifact of the fact that both
    116 * mIndex and GetScrollMetadataCount() are uint32_t and GetScrollMetadataCount()
    117 * can return 0 but mIndex cannot store -1. This seems better than the
    118 * alternative of making mIndex a int32_t that can store -1, but then having
    119 * to cast to uint32_t all over the place.
    120 *
    121 * Note that WebRenderLayerScrollData objects are owned by WebRenderScrollData,
    122 * which stores them in a flattened representation. The field mData,
    123 * mLayerIndex, and mContainingSubtreeIndex are used to move around the "layers"
    124 * given the flattened representation. The mMetadataIndex is used to move around
    125 * the ScrollMetadata within a single layer.
    126 *
    127 * One important note here is that this class holds a pointer to the "owning"
    128 * WebRenderScrollData. The caller must ensure that this class does not outlive
    129 * the owning WebRenderScrollData, or this may result in use-after-free errors.
    130 * This class being declared a MOZ_STACK_CLASS should help with that.
    131 */
    132 class MOZ_STACK_CLASS WebRenderScrollDataWrapper final {
    133 public:
    134  // Basic constructor for external callers. Starts the walker at the root of
    135  // the tree.
    136  explicit WebRenderScrollDataWrapper(
    137      const APZUpdater& aUpdater, const WebRenderScrollData* aData = nullptr)
    138      : mUpdater(&aUpdater),
    139        mData(aData),
    140        mLayerIndex(0),
    141        mContainingSubtreeLastIndex(0),
    142        mLayer(nullptr),
    143        mMetadataIndex(0) {
    144    if (!mData) {
    145      return;
    146    }
    147    mLayer = mData->GetLayerData(mLayerIndex);
    148    if (!mLayer) {
    149      return;
    150    }
    151 
    152    // sanity check on the data
    153    MOZ_ASSERT(mData->GetLayerCount() ==
    154               (size_t)(1 + mLayer->GetDescendantCount()));
    155    mContainingSubtreeLastIndex = mData->GetLayerCount();
    156 
    157    // See documentation in LayerMetricsWrapper.h about this. mMetadataIndex
    158    // in this class is equivalent to mIndex in that class.
    159    mMetadataIndex = mLayer->GetScrollMetadataCount();
    160    if (mMetadataIndex > 0) {
    161      mMetadataIndex--;
    162    }
    163  }
    164 
    165 private:
    166  // Internal constructor for walking from one WebRenderLayerScrollData to
    167  // another. In this case we need to recompute the mMetadataIndex to be the
    168  // "topmost" scroll metadata on the new layer.
    169  WebRenderScrollDataWrapper(const APZUpdater* aUpdater,
    170                             const WebRenderScrollData* aData,
    171                             size_t aLayerIndex,
    172                             size_t aContainingSubtreeLastIndex)
    173      : mUpdater(aUpdater),
    174        mData(aData),
    175        mLayerIndex(aLayerIndex),
    176        mContainingSubtreeLastIndex(aContainingSubtreeLastIndex),
    177        mLayer(nullptr),
    178        mMetadataIndex(0) {
    179    MOZ_ASSERT(mData);
    180    mLayer = mData->GetLayerData(mLayerIndex);
    181    MOZ_ASSERT(mLayer);
    182 
    183    // See documentation in LayerMetricsWrapper.h about this. mMetadataIndex
    184    // in this class is equivalent to mIndex in that class.
    185    mMetadataIndex = mLayer->GetScrollMetadataCount();
    186    if (mMetadataIndex > 0) {
    187      mMetadataIndex--;
    188    }
    189  }
    190 
    191  // Internal constructor for walking from one metadata to another metadata on
    192  // the same WebRenderLayerScrollData.
    193  WebRenderScrollDataWrapper(const APZUpdater* aUpdater,
    194                             const WebRenderScrollData* aData,
    195                             size_t aLayerIndex,
    196                             size_t aContainingSubtreeLastIndex,
    197                             const WebRenderLayerScrollData* aLayer,
    198                             uint32_t aMetadataIndex)
    199      : mUpdater(aUpdater),
    200        mData(aData),
    201        mLayerIndex(aLayerIndex),
    202        mContainingSubtreeLastIndex(aContainingSubtreeLastIndex),
    203        mLayer(aLayer),
    204        mMetadataIndex(aMetadataIndex) {
    205    MOZ_ASSERT(mData);
    206    MOZ_ASSERT(mLayer);
    207    MOZ_ASSERT(mLayer == mData->GetLayerData(mLayerIndex));
    208    MOZ_ASSERT(mMetadataIndex == 0 ||
    209               mMetadataIndex < mLayer->GetScrollMetadataCount());
    210  }
    211 
    212 public:
    213  bool IsValid() const { return mLayer != nullptr; }
    214 
    215  explicit operator bool() const { return IsValid(); }
    216 
    217  WebRenderScrollDataWrapper GetLastChild() const {
    218    MOZ_ASSERT(IsValid());
    219 
    220    if (!AtBottomLayer()) {
    221      // If we're still walking around in the virtual container layers created
    222      // by the ScrollMetadata array, we just need to update the metadata index
    223      // and that's it.
    224      return WebRenderScrollDataWrapper(mUpdater, mData, mLayerIndex,
    225                                        mContainingSubtreeLastIndex, mLayer,
    226                                        mMetadataIndex - 1);
    227    }
    228 
    229    // Otherwise, we need to walk to a different WebRenderLayerScrollData in
    230    // mData.
    231 
    232    // Since mData contains the layer in depth-first, last-to-first order,
    233    // the index after mLayerIndex must be mLayerIndex's last child, if it
    234    // has any children (indicated by GetDescendantCount() > 0). Furthermore
    235    // we compute the first index outside the subtree rooted at this node
    236    // (in |subtreeLastIndex|) and pass that in to the child wrapper to use as
    237    // its mContainingSubtreeLastIndex.
    238    if (mLayer->GetDescendantCount() > 0) {
    239      size_t prevSiblingIndex = mLayerIndex + 1 + mLayer->GetDescendantCount();
    240      // TODO(botond): Replace the min() with just prevSiblingIndex (which
    241      // should be <= mContainingSubtreeLastIndex).
    242      MOZ_ASSERT(prevSiblingIndex <= mContainingSubtreeLastIndex);
    243      size_t subtreeLastIndex =
    244          std::min(mContainingSubtreeLastIndex, prevSiblingIndex);
    245      return WebRenderScrollDataWrapper(mUpdater, mData, mLayerIndex + 1,
    246                                        subtreeLastIndex);
    247    }
    248 
    249    // We've run out of descendants. But! If the original layer was a RefLayer,
    250    // then it connects to another layer tree and we need to traverse that too.
    251    // So return a WebRenderScrollDataWrapper for the root of the child layer
    252    // tree.
    253    if (mLayer->GetReferentId()) {
    254      return WebRenderScrollDataWrapper(
    255          *mUpdater, mUpdater->GetScrollData(*mLayer->GetReferentId()));
    256    }
    257 
    258    return WebRenderScrollDataWrapper(*mUpdater);
    259  }
    260 
    261  WebRenderScrollDataWrapper GetPrevSibling() const {
    262    MOZ_ASSERT(IsValid());
    263 
    264    if (!AtTopLayer()) {
    265      // The virtual container layers don't have siblings
    266      return WebRenderScrollDataWrapper(*mUpdater);
    267    }
    268 
    269    // Skip past the descendants to get to the previous sibling. However, we
    270    // might be at the last sibling already.
    271    size_t prevSiblingIndex = mLayerIndex + 1 + mLayer->GetDescendantCount();
    272    if (prevSiblingIndex < mContainingSubtreeLastIndex) {
    273      return WebRenderScrollDataWrapper(mUpdater, mData, prevSiblingIndex,
    274                                        mContainingSubtreeLastIndex);
    275    }
    276    return WebRenderScrollDataWrapper(*mUpdater);
    277  }
    278 
    279  const ScrollMetadata& Metadata() const {
    280    MOZ_ASSERT(IsValid());
    281 
    282    if (mMetadataIndex >= mLayer->GetScrollMetadataCount()) {
    283      return *ScrollMetadata::sNullMetadata;
    284    }
    285    return mLayer->GetScrollMetadata(*mData, mMetadataIndex);
    286  }
    287 
    288  const FrameMetrics& Metrics() const { return Metadata().GetMetrics(); }
    289 
    290  AsyncPanZoomController* GetApzc() const { return nullptr; }
    291 
    292  void SetApzc(AsyncPanZoomController* aApzc) const {}
    293 
    294  const char* Name() const { return "WebRenderScrollDataWrapper"; }
    295 
    296  gfx::Matrix4x4 GetTransform() const {
    297    MOZ_ASSERT(IsValid());
    298 
    299    // See WebRenderLayerScrollData::Initialize for more context.
    300    //  * The ancestor transform is associated with whichever layer has scroll
    301    //    id matching GetAncestorTransformId().
    302    //  * The transform is associated with the "bottommost" layer.
    303    // Multiple transforms may apply to the same layer (e.g. if there is only
    304    // one scrollmetadata on the layer, then it is both "topmost" and
    305    // "bottommost"), so we may need to combine the transforms.
    306 
    307    gfx::Matrix4x4 transform;
    308    // The ancestor transform is usually emitted at the layer with the
    309    // matching scroll id. However, sometimes the transform ends up on
    310    // a node with no scroll metadata at all. In such cases we generate
    311    // a single layer, and the ancestor transform needs to be on that layer,
    312    // otherwise it will be lost.
    313    bool emitAncestorTransform =
    314        !Metrics().IsScrollable() ||
    315        Metrics().GetScrollId() == mLayer->GetAncestorTransformId();
    316    if (emitAncestorTransform) {
    317      transform = mLayer->GetAncestorTransform();
    318    }
    319    if (AtBottomLayer()) {
    320      transform = mLayer->GetTransform() * transform;
    321    }
    322    return transform;
    323  }
    324 
    325  CSSTransformMatrix GetTransformTyped() const {
    326    return ViewAs<CSSTransformMatrix>(GetTransform());
    327  }
    328 
    329  bool TransformIsPerspective() const {
    330    MOZ_ASSERT(IsValid());
    331 
    332    // mLayer->GetTransformIsPerspective() tells us whether
    333    // mLayer->GetTransform() is a perspective transform. Since
    334    // mLayer->GetTransform() is only used at the bottom layer, we only
    335    // need to check GetTransformIsPerspective() at the bottom layer too.
    336    if (AtBottomLayer()) {
    337      return mLayer->GetTransformIsPerspective();
    338    }
    339    return false;
    340  }
    341 
    342  LayerIntRect GetVisibleRect() const {
    343    MOZ_ASSERT(IsValid());
    344 
    345    if (AtBottomLayer()) {
    346      return mLayer->GetVisibleRect();
    347    }
    348 
    349    return ViewAs<LayerPixel>(
    350        TransformBy(mLayer->GetTransformTyped(), mLayer->GetVisibleRect()),
    351        PixelCastJustification::MovingDownToChildren);
    352  }
    353 
    354  LayerIntSize GetRemoteDocumentSize() const {
    355    MOZ_ASSERT(IsValid());
    356 
    357    if (mLayer->GetReferentId().isNothing()) {
    358      return LayerIntSize();
    359    }
    360 
    361    if (AtBottomLayer()) {
    362      return mLayer->GetRemoteDocumentSize();
    363    }
    364 
    365    return ViewAs<LayerPixel>(mLayer->GetRemoteDocumentSize(),
    366                              PixelCastJustification::MovingDownToChildren);
    367  }
    368 
    369  Maybe<LayersId> GetReferentId() const {
    370    MOZ_ASSERT(IsValid());
    371 
    372    if (AtBottomLayer()) {
    373      return mLayer->GetReferentId();
    374    }
    375    return Nothing();
    376  }
    377 
    378  EventRegionsOverride GetEventRegionsOverride() const {
    379    MOZ_ASSERT(IsValid());
    380    // Only ref layers can have an event regions override.
    381    if (GetReferentId()) {
    382      return mLayer->GetEventRegionsOverride();
    383    }
    384    return EventRegionsOverride::NoOverride;
    385  }
    386 
    387  const ScrollbarData& GetScrollbarData() const {
    388    MOZ_ASSERT(IsValid());
    389    return mLayer->GetScrollbarData();
    390  }
    391 
    392  Maybe<uint64_t> GetScrollbarAnimationId() const {
    393    MOZ_ASSERT(IsValid());
    394    return mLayer->GetScrollbarAnimationId();
    395  }
    396 
    397  Maybe<uint64_t> GetFixedPositionAnimationId() const {
    398    MOZ_ASSERT(IsValid());
    399 
    400    if (AtBottomLayer()) {
    401      return mLayer->GetFixedPositionAnimationId();
    402    }
    403    return Nothing();
    404  }
    405 
    406  ScrollableLayerGuid::ViewID GetFixedPositionScrollContainerId() const {
    407    MOZ_ASSERT(IsValid());
    408 
    409    if (AtBottomLayer()) {
    410      return mLayer->GetFixedPositionScrollContainerId();
    411    }
    412    return ScrollableLayerGuid::NULL_SCROLL_ID;
    413  }
    414 
    415  SideBits GetFixedPositionSides() const {
    416    MOZ_ASSERT(IsValid());
    417 
    418    if (AtBottomLayer()) {
    419      return mLayer->GetFixedPositionSides();
    420    }
    421    return SideBits::eNone;
    422  }
    423 
    424  ScrollableLayerGuid::ViewID GetStickyScrollContainerId() const {
    425    MOZ_ASSERT(IsValid());
    426 
    427    if (AtBottomLayer()) {
    428      return mLayer->GetStickyPositionScrollContainerId();
    429    }
    430    return ScrollableLayerGuid::NULL_SCROLL_ID;
    431  }
    432 
    433  const LayerRectAbsolute& GetStickyScrollRangeOuter() const {
    434    MOZ_ASSERT(IsValid());
    435 
    436    if (AtBottomLayer()) {
    437      return mLayer->GetStickyScrollRangeOuter();
    438    }
    439 
    440    static const LayerRectAbsolute empty;
    441    return empty;
    442  }
    443 
    444  const LayerRectAbsolute& GetStickyScrollRangeInner() const {
    445    MOZ_ASSERT(IsValid());
    446 
    447    if (AtBottomLayer()) {
    448      return mLayer->GetStickyScrollRangeInner();
    449    }
    450 
    451    static const LayerRectAbsolute empty;
    452    return empty;
    453  }
    454 
    455  Maybe<uint64_t> GetStickyPositionAnimationId() const {
    456    MOZ_ASSERT(IsValid());
    457 
    458    if (AtBottomLayer()) {
    459      return mLayer->GetStickyPositionAnimationId();
    460    }
    461    return Nothing();
    462  }
    463 
    464  Maybe<uint64_t> GetZoomAnimationId() const {
    465    MOZ_ASSERT(IsValid());
    466    return mLayer->GetZoomAnimationId();
    467  }
    468 
    469  Maybe<ScrollableLayerGuid::ViewID> GetAsyncZoomContainerId() const {
    470    MOZ_ASSERT(IsValid());
    471    return mLayer->GetAsyncZoomContainerId();
    472  }
    473 
    474  // Expose an opaque pointer to the layer. Mostly used for printf
    475  // purposes. This is not intended to be a general-purpose accessor
    476  // for the underlying layer.
    477  const void* GetLayer() const {
    478    MOZ_ASSERT(IsValid());
    479    return mLayer;
    480  }
    481 
    482  template <int Level>
    483  size_t Dump(gfx::TreeLog<Level>& aOut) const {
    484    std::string result = "(invalid)";
    485    if (!IsValid()) {
    486      aOut << result;
    487      return result.length();
    488    }
    489    if (AtBottomLayer()) {
    490      if (mData != nullptr) {
    491        const WebRenderLayerScrollData* layerData =
    492            mData->GetLayerData(mLayerIndex);
    493        if (layerData != nullptr) {
    494          std::stringstream ss;
    495          layerData->Dump(ss, *mData);
    496          result = ss.str();
    497          aOut << result;
    498          return result.length();
    499        }
    500      }
    501    }
    502    return 0;
    503  }
    504 
    505  bool IsFirstPaint() const { return mData ? mData->IsFirstPaint() : false; }
    506 
    507 private:
    508  bool AtBottomLayer() const { return mMetadataIndex == 0; }
    509 
    510  bool AtTopLayer() const {
    511    return mLayer->GetScrollMetadataCount() == 0 ||
    512           mMetadataIndex == mLayer->GetScrollMetadataCount() - 1;
    513  }
    514 
    515 private:
    516  const APZUpdater* mUpdater;
    517  const WebRenderScrollData* mData;
    518  // The index (in mData->mLayerScrollData) of the WebRenderLayerScrollData this
    519  // wrapper is pointing to.
    520  size_t mLayerIndex;
    521  // The upper bound on the set of valid indices inside the subtree rooted at
    522  // the parent of this "layer". That is, any layer index |i| in the range
    523  // mLayerIndex <= i < mContainingSubtreeLastIndex is guaranteed to point to
    524  // a layer that is a descendant of "parent", where "parent" is the parent
    525  // layer of the layer at mLayerIndex. This is needed in order to implement
    526  // GetPrevSibling() correctly.
    527  size_t mContainingSubtreeLastIndex;
    528  // The WebRenderLayerScrollData this wrapper is pointing to.
    529  const WebRenderLayerScrollData* mLayer;
    530  // The index of the scroll metadata within mLayer that this wrapper is
    531  // pointing to.
    532  uint32_t mMetadataIndex;
    533 };
    534 
    535 }  // namespace layers
    536 }  // namespace mozilla
    537 
    538 #endif /* GFX_WEBRENDERSCROLLDATAWRAPPER_H */