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. WebRenderScrollDataWrapper(const APZUpdater * aUpdater,const WebRenderScrollData * aData,size_t aLayerIndex,size_t aContainingSubtreeLastIndex)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. WebRenderScrollDataWrapper(const APZUpdater * aUpdater,const WebRenderScrollData * aData,size_t aLayerIndex,size_t aContainingSubtreeLastIndex,const WebRenderLayerScrollData * aLayer,uint32_t aMetadataIndex)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: IsValid()213 bool IsValid() const { return mLayer != nullptr; } 214 215 explicit operator bool() const { return IsValid(); } 216 GetLastChild()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 size_t subtreeLastIndex = 241 std::min(mContainingSubtreeLastIndex, prevSiblingIndex); 242 return WebRenderScrollDataWrapper(mUpdater, mData, mLayerIndex + 1, 243 subtreeLastIndex); 244 } 245 246 // We've run out of descendants. But! If the original layer was a RefLayer, 247 // then it connects to another layer tree and we need to traverse that too. 248 // So return a WebRenderScrollDataWrapper for the root of the child layer 249 // tree. 250 if (mLayer->GetReferentId()) { 251 return WebRenderScrollDataWrapper( 252 *mUpdater, mUpdater->GetScrollData(*mLayer->GetReferentId())); 253 } 254 255 return WebRenderScrollDataWrapper(*mUpdater); 256 } 257 GetPrevSibling()258 WebRenderScrollDataWrapper GetPrevSibling() const { 259 MOZ_ASSERT(IsValid()); 260 261 if (!AtTopLayer()) { 262 // The virtual container layers don't have siblings 263 return WebRenderScrollDataWrapper(*mUpdater); 264 } 265 266 // Skip past the descendants to get to the previous sibling. However, we 267 // might be at the last sibling already. 268 size_t prevSiblingIndex = mLayerIndex + 1 + mLayer->GetDescendantCount(); 269 if (prevSiblingIndex < mContainingSubtreeLastIndex) { 270 return WebRenderScrollDataWrapper(mUpdater, mData, prevSiblingIndex, 271 mContainingSubtreeLastIndex); 272 } 273 return WebRenderScrollDataWrapper(*mUpdater); 274 } 275 Metadata()276 const ScrollMetadata& Metadata() const { 277 MOZ_ASSERT(IsValid()); 278 279 if (mMetadataIndex >= mLayer->GetScrollMetadataCount()) { 280 return *ScrollMetadata::sNullMetadata; 281 } 282 return mLayer->GetScrollMetadata(*mData, mMetadataIndex); 283 } 284 Metrics()285 const FrameMetrics& Metrics() const { return Metadata().GetMetrics(); } 286 GetApzc()287 AsyncPanZoomController* GetApzc() const { return nullptr; } 288 SetApzc(AsyncPanZoomController * aApzc)289 void SetApzc(AsyncPanZoomController* aApzc) const {} 290 Name()291 const char* Name() const { return "WebRenderScrollDataWrapper"; } 292 GetTransform()293 gfx::Matrix4x4 GetTransform() const { 294 MOZ_ASSERT(IsValid()); 295 296 // See WebRenderLayerScrollData::Initialize for more context. 297 // * The ancestor transform is associated with whichever layer has scroll 298 // id matching GetAncestorTransformId(). 299 // * The resolution is associated with the "topmost" layer. 300 // * The transform is associated with the "bottommost" layer. 301 // Multiple transforms may apply to the same layer (e.g. if there is only 302 // one scrollmetadata on the layer, then it is both "topmost" and 303 // "bottommost"), so we may need to combine the transforms. 304 305 gfx::Matrix4x4 transform; 306 // The ancestor transform is usually emitted at the layer with the 307 // matching scroll id. However, sometimes the transform ends up on 308 // a node with no scroll metadata at all. In such cases we generate 309 // a single layer, and the ancestor transform needs to be on that layer, 310 // otherwise it will be lost. 311 bool emitAncestorTransform = 312 !Metrics().IsScrollable() || 313 Metrics().GetScrollId() == mLayer->GetAncestorTransformId(); 314 if (emitAncestorTransform) { 315 transform = mLayer->GetAncestorTransform(); 316 } 317 if (AtTopLayer()) { 318 float resolution = mLayer->GetResolution(); 319 transform = 320 transform * gfx::Matrix4x4::Scaling(resolution, resolution, 1.f); 321 } 322 if (AtBottomLayer()) { 323 transform = mLayer->GetTransform() * transform; 324 } 325 return transform; 326 } 327 GetTransformTyped()328 CSSTransformMatrix GetTransformTyped() const { 329 return ViewAs<CSSTransformMatrix>(GetTransform()); 330 } 331 TransformIsPerspective()332 bool TransformIsPerspective() const { 333 MOZ_ASSERT(IsValid()); 334 335 // mLayer->GetTransformIsPerspective() tells us whether 336 // mLayer->GetTransform() is a perspective transform. Since 337 // mLayer->GetTransform() is only used at the bottom layer, we only 338 // need to check GetTransformIsPerspective() at the bottom layer too. 339 if (AtBottomLayer()) { 340 return mLayer->GetTransformIsPerspective(); 341 } 342 return false; 343 } 344 GetVisibleRegion()345 LayerIntRegion GetVisibleRegion() const { 346 MOZ_ASSERT(IsValid()); 347 348 if (AtBottomLayer()) { 349 return mLayer->GetVisibleRegion(); 350 } 351 352 return ViewAs<LayerPixel>( 353 TransformBy(mLayer->GetTransformTyped(), mLayer->GetVisibleRegion()), 354 PixelCastJustification::MovingDownToChildren); 355 } 356 GetRemoteDocumentSize()357 LayerIntSize GetRemoteDocumentSize() const { 358 MOZ_ASSERT(IsValid()); 359 360 if (mLayer->GetReferentId().isNothing()) { 361 return LayerIntSize(); 362 } 363 364 if (AtBottomLayer()) { 365 return mLayer->GetRemoteDocumentSize(); 366 } 367 368 return ViewAs<LayerPixel>(mLayer->GetRemoteDocumentSize(), 369 PixelCastJustification::MovingDownToChildren); 370 } 371 GetReferentId()372 Maybe<LayersId> GetReferentId() const { 373 MOZ_ASSERT(IsValid()); 374 375 if (AtBottomLayer()) { 376 return mLayer->GetReferentId(); 377 } 378 return Nothing(); 379 } 380 GetEventRegionsOverride()381 EventRegionsOverride GetEventRegionsOverride() const { 382 MOZ_ASSERT(IsValid()); 383 // Only ref layers can have an event regions override. 384 if (GetReferentId()) { 385 return mLayer->GetEventRegionsOverride(); 386 } 387 return EventRegionsOverride::NoOverride; 388 } 389 GetScrollbarData()390 const ScrollbarData& GetScrollbarData() const { 391 MOZ_ASSERT(IsValid()); 392 return mLayer->GetScrollbarData(); 393 } 394 GetScrollbarAnimationId()395 Maybe<uint64_t> GetScrollbarAnimationId() const { 396 MOZ_ASSERT(IsValid()); 397 return mLayer->GetScrollbarAnimationId(); 398 } 399 GetFixedPositionAnimationId()400 Maybe<uint64_t> GetFixedPositionAnimationId() const { 401 MOZ_ASSERT(IsValid()); 402 403 if (AtBottomLayer()) { 404 return mLayer->GetFixedPositionAnimationId(); 405 } 406 return Nothing(); 407 } 408 GetFixedPositionScrollContainerId()409 ScrollableLayerGuid::ViewID GetFixedPositionScrollContainerId() const { 410 MOZ_ASSERT(IsValid()); 411 412 if (AtBottomLayer()) { 413 return mLayer->GetFixedPositionScrollContainerId(); 414 } 415 return ScrollableLayerGuid::NULL_SCROLL_ID; 416 } 417 GetFixedPositionSides()418 SideBits GetFixedPositionSides() const { 419 MOZ_ASSERT(IsValid()); 420 421 if (AtBottomLayer()) { 422 return mLayer->GetFixedPositionSides(); 423 } 424 return SideBits::eNone; 425 } 426 GetStickyScrollContainerId()427 ScrollableLayerGuid::ViewID GetStickyScrollContainerId() const { 428 MOZ_ASSERT(IsValid()); 429 430 if (AtBottomLayer()) { 431 return mLayer->GetStickyPositionScrollContainerId(); 432 } 433 return ScrollableLayerGuid::NULL_SCROLL_ID; 434 } 435 GetStickyScrollRangeOuter()436 const LayerRectAbsolute& GetStickyScrollRangeOuter() const { 437 MOZ_ASSERT(IsValid()); 438 439 if (AtBottomLayer()) { 440 return mLayer->GetStickyScrollRangeOuter(); 441 } 442 443 static const LayerRectAbsolute empty; 444 return empty; 445 } 446 GetStickyScrollRangeInner()447 const LayerRectAbsolute& GetStickyScrollRangeInner() const { 448 MOZ_ASSERT(IsValid()); 449 450 if (AtBottomLayer()) { 451 return mLayer->GetStickyScrollRangeInner(); 452 } 453 454 static const LayerRectAbsolute empty; 455 return empty; 456 } 457 GetStickyPositionAnimationId()458 Maybe<uint64_t> GetStickyPositionAnimationId() const { 459 MOZ_ASSERT(IsValid()); 460 461 if (AtBottomLayer()) { 462 return mLayer->GetStickyPositionAnimationId(); 463 } 464 return Nothing(); 465 } 466 GetZoomAnimationId()467 Maybe<uint64_t> GetZoomAnimationId() const { 468 MOZ_ASSERT(IsValid()); 469 return mLayer->GetZoomAnimationId(); 470 } 471 GetAsyncZoomContainerId()472 Maybe<ScrollableLayerGuid::ViewID> GetAsyncZoomContainerId() const { 473 MOZ_ASSERT(IsValid()); 474 return mLayer->GetAsyncZoomContainerId(); 475 } 476 477 // Expose an opaque pointer to the layer. Mostly used for printf 478 // purposes. This is not intended to be a general-purpose accessor 479 // for the underlying layer. GetLayer()480 const void* GetLayer() const { 481 MOZ_ASSERT(IsValid()); 482 return mLayer; 483 } 484 485 private: AtBottomLayer()486 bool AtBottomLayer() const { return mMetadataIndex == 0; } 487 AtTopLayer()488 bool AtTopLayer() const { 489 return mLayer->GetScrollMetadataCount() == 0 || 490 mMetadataIndex == mLayer->GetScrollMetadataCount() - 1; 491 } 492 493 private: 494 const APZUpdater* mUpdater; 495 const WebRenderScrollData* mData; 496 // The index (in mData->mLayerScrollData) of the WebRenderLayerScrollData this 497 // wrapper is pointing to. 498 size_t mLayerIndex; 499 // The upper bound on the set of valid indices inside the subtree rooted at 500 // the parent of this "layer". That is, any layer index |i| in the range 501 // mLayerIndex <= i < mContainingSubtreeLastIndex is guaranteed to point to 502 // a layer that is a descendant of "parent", where "parent" is the parent 503 // layer of the layer at mLayerIndex. This is needed in order to implement 504 // GetPrevSibling() correctly. 505 size_t mContainingSubtreeLastIndex; 506 // The WebRenderLayerScrollData this wrapper is pointing to. 507 const WebRenderLayerScrollData* mLayer; 508 // The index of the scroll metadata within mLayer that this wrapper is 509 // pointing to. 510 uint32_t mMetadataIndex; 511 }; 512 513 } // namespace layers 514 } // namespace mozilla 515 516 #endif /* GFX_WEBRENDERSCROLLDATAWRAPPER_H */ 517