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 */