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_LAYERMETRICSWRAPPER_H 8 #define GFX_LAYERMETRICSWRAPPER_H 9 10 #include "Layers.h" 11 #include "UnitTransforms.h" 12 13 namespace mozilla { 14 namespace layers { 15 16 /** 17 * A wrapper class around a target Layer with that allows user code to 18 * walk through the FrameMetrics objects on the layer the same way it 19 * would walk through a ContainerLayer hierarchy. Consider the following 20 * layer tree: 21 * 22 * +---+ 23 * | A | 24 * +---+ 25 * / | \ 26 * / | \ 27 * / | \ 28 * +---+ +-----+ +---+ 29 * | B | | C | | D | 30 * +---+ +-----+ +---+ 31 * | FMn | 32 * | . | 33 * | . | 34 * | . | 35 * | FM1 | 36 * | FM0 | 37 * +-----+ 38 * / \ 39 * / \ 40 * +---+ +---+ 41 * | E | | F | 42 * +---+ +---+ 43 * 44 * In this layer tree, there are six layers with A being the root and B,D,E,F 45 * being leaf nodes. Layer C is in the middle and has n+1 FrameMetrics, labelled 46 * FM0...FMn. FM0 is the FrameMetrics you get by calling c->GetFrameMetrics(0) 47 * and FMn is the FrameMetrics you can obtain by calling 48 * c->GetFrameMetrics(c->GetScrollMetadataCount() - 1). This layer tree is 49 * conceptually equivalent to this one below: 50 * 51 * +---+ 52 * | A | 53 * +---+ 54 * / | \ 55 * / | \ 56 * / | \ 57 * +---+ +-----+ +---+ 58 * | B | | Cn | | D | 59 * +---+ +-----+ +---+ 60 * | 61 * . 62 * . 63 * . 64 * | 65 * +-----+ 66 * | C1 | 67 * +-----+ 68 * | 69 * +-----+ 70 * | C0 | 71 * +-----+ 72 * / \ 73 * / \ 74 * +---+ +---+ 75 * | E | | F | 76 * +---+ +---+ 77 * 78 * In this layer tree, the layer C has been expanded into a stack of container 79 * layers C1...Cn, where C1 has FrameMetrics FM1 and Cn has FrameMetrics Fn. 80 * Although in this example C (in the first layer tree) and C0 (in the second 81 * layer tree) are both ContainerLayers (because they have children), they 82 * do not have to be. They may just be PaintedLayers or ColorLayers, for 83 * example, which do not have any children. However, the type of C will always 84 * be the same as the type of C0. 85 * 86 * The LayerMetricsWrapper class allows client code to treat the first layer 87 * tree as though it were the second. That is, instead of client code having 88 * to iterate through the FrameMetrics objects directly, it can use a 89 * LayerMetricsWrapper to encapsulate that aspect of the layer tree and just 90 * walk the tree as if it were a stack of ContainerLayers. 91 * 92 * The functions on this class do different things depending on which 93 * simulated ContainerLayer is being wrapped. For example, if the 94 * LayerMetricsWrapper is pretending to be C0, the GetNextSibling() function 95 * will return null even though the underlying layer C does actually have 96 * a next sibling. The LayerMetricsWrapper pretending to be Cn will return 97 * D as the next sibling. 98 * 99 * Implementation notes: 100 * 101 * The AtTopLayer() and AtBottomLayer() functions in this class refer to 102 * Cn and C0 in the second layer tree above; that is, they are predicates 103 * to test if the LayerMetricsWrapper is simulating the topmost or bottommost 104 * layer, as those will have special behaviour. 105 * 106 * It is possible to wrap a nullptr in a LayerMetricsWrapper, in which case 107 * the IsValid() function will return false. This is required to allow 108 * LayerMetricsWrapper to be a MOZ_STACK_CLASS (desirable because it is used 109 * in loops and recursion). 110 * 111 * This class purposely does not expose the wrapped layer directly to avoid 112 * user code from accidentally calling functions directly on it. Instead 113 * any necessary functions should be wrapped in this class. It does expose 114 * the wrapped layer as a void* for printf purposes. 115 * 116 * The implementation may look like it special-cases mIndex == 0 and/or 117 * GetScrollMetadataCount() == 0. This is an artifact of the fact that both 118 * mIndex and GetScrollMetadataCount() are uint32_t and GetScrollMetadataCount() 119 * can return 0 but mIndex cannot store -1. This seems better than the 120 * alternative of making mIndex a int32_t that can store -1, but then having 121 * to cast to uint32_t all over the place. 122 */ 123 class MOZ_STACK_CLASS LayerMetricsWrapper final { 124 public: 125 enum StartAt { 126 TOP, 127 BOTTOM, 128 }; 129 LayerMetricsWrapper()130 LayerMetricsWrapper() : mLayer(nullptr), mIndex(0) {} 131 132 explicit LayerMetricsWrapper(Layer* aRoot, StartAt aStart = StartAt::TOP) mLayer(aRoot)133 : mLayer(aRoot), mIndex(0) { 134 if (!mLayer) { 135 return; 136 } 137 138 switch (aStart) { 139 case StartAt::TOP: 140 mIndex = mLayer->GetScrollMetadataCount(); 141 if (mIndex > 0) { 142 mIndex--; 143 } 144 break; 145 case StartAt::BOTTOM: 146 mIndex = 0; 147 break; 148 default: 149 MOZ_ASSERT_UNREACHABLE("Unknown startAt value"); 150 break; 151 } 152 } 153 LayerMetricsWrapper(Layer * aLayer,uint32_t aMetricsIndex)154 explicit LayerMetricsWrapper(Layer* aLayer, uint32_t aMetricsIndex) 155 : mLayer(aLayer), mIndex(aMetricsIndex) { 156 MOZ_ASSERT(mLayer); 157 MOZ_ASSERT(mIndex == 0 || mIndex < mLayer->GetScrollMetadataCount()); 158 } 159 IsValid()160 bool IsValid() const { return mLayer != nullptr; } 161 162 explicit operator bool() const { return IsValid(); } 163 GetParent()164 LayerMetricsWrapper GetParent() const { 165 MOZ_ASSERT(IsValid()); 166 167 if (!AtTopLayer()) { 168 return LayerMetricsWrapper(mLayer, mIndex + 1); 169 } 170 if (mLayer->GetParent()) { 171 return LayerMetricsWrapper(mLayer->GetParent(), StartAt::BOTTOM); 172 } 173 return LayerMetricsWrapper(nullptr); 174 } 175 GetFirstChild()176 LayerMetricsWrapper GetFirstChild() const { 177 MOZ_ASSERT(IsValid()); 178 179 if (!AtBottomLayer()) { 180 return LayerMetricsWrapper(mLayer, mIndex - 1); 181 } 182 return LayerMetricsWrapper(mLayer->GetFirstChild()); 183 } 184 GetLastChild()185 LayerMetricsWrapper GetLastChild() const { 186 MOZ_ASSERT(IsValid()); 187 188 if (!AtBottomLayer()) { 189 return LayerMetricsWrapper(mLayer, mIndex - 1); 190 } 191 return LayerMetricsWrapper(mLayer->GetLastChild()); 192 } 193 GetPrevSibling()194 LayerMetricsWrapper GetPrevSibling() const { 195 MOZ_ASSERT(IsValid()); 196 197 if (AtTopLayer()) { 198 return LayerMetricsWrapper(mLayer->GetPrevSibling()); 199 } 200 return LayerMetricsWrapper(nullptr); 201 } 202 GetNextSibling()203 LayerMetricsWrapper GetNextSibling() const { 204 MOZ_ASSERT(IsValid()); 205 206 if (AtTopLayer()) { 207 return LayerMetricsWrapper(mLayer->GetNextSibling()); 208 } 209 return LayerMetricsWrapper(nullptr); 210 } 211 Metadata()212 const ScrollMetadata& Metadata() const { 213 MOZ_ASSERT(IsValid()); 214 215 if (mIndex >= mLayer->GetScrollMetadataCount()) { 216 return *ScrollMetadata::sNullMetadata; 217 } 218 return mLayer->GetScrollMetadata(mIndex); 219 } 220 Metrics()221 const FrameMetrics& Metrics() const { return Metadata().GetMetrics(); } 222 GetApzc()223 AsyncPanZoomController* GetApzc() const { 224 MOZ_ASSERT(IsValid()); 225 226 if (mIndex >= mLayer->GetScrollMetadataCount()) { 227 return nullptr; 228 } 229 return mLayer->GetAsyncPanZoomController(mIndex); 230 } 231 SetApzc(AsyncPanZoomController * aApzc)232 void SetApzc(AsyncPanZoomController* aApzc) const { 233 MOZ_ASSERT(IsValid()); 234 235 if (mLayer->GetScrollMetadataCount() == 0) { 236 MOZ_ASSERT(mIndex == 0); 237 MOZ_ASSERT(aApzc == nullptr); 238 return; 239 } 240 MOZ_ASSERT(mIndex < mLayer->GetScrollMetadataCount()); 241 mLayer->SetAsyncPanZoomController(mIndex, aApzc); 242 } 243 Name()244 const char* Name() const { 245 MOZ_ASSERT(IsValid()); 246 247 if (AtBottomLayer()) { 248 return mLayer->Name(); 249 } 250 return "DummyContainerLayer"; 251 } 252 Manager()253 LayerManager* Manager() const { 254 MOZ_ASSERT(IsValid()); 255 256 return mLayer->Manager(); 257 } 258 GetTransform()259 gfx::Matrix4x4 GetTransform() const { 260 MOZ_ASSERT(IsValid()); 261 262 if (AtBottomLayer()) { 263 return mLayer->GetTransform(); 264 } 265 return gfx::Matrix4x4(); 266 } 267 GetTransformTyped()268 CSSTransformMatrix GetTransformTyped() const { 269 return ViewAs<CSSTransformMatrix>(GetTransform()); 270 } 271 TransformIsPerspective()272 bool TransformIsPerspective() const { 273 MOZ_ASSERT(IsValid()); 274 275 // mLayer->GetTransformIsPerspective() tells us whether 276 // mLayer->GetTransform() is a perspective transform. Since 277 // mLayer->GetTransform() is only used at the bottom layer, we only 278 // need to check GetTransformIsPerspective() at the bottom layer too. 279 if (AtBottomLayer()) { 280 return mLayer->GetTransformIsPerspective(); 281 } 282 return false; 283 } 284 Combines3DTransformWithAncestors()285 bool Combines3DTransformWithAncestors() const { 286 MOZ_ASSERT(IsValid()); 287 288 return mLayer->Combines3DTransformWithAncestors(); 289 } 290 GetEventRegions()291 EventRegions GetEventRegions() const { 292 MOZ_ASSERT(IsValid()); 293 294 if (AtBottomLayer()) { 295 return mLayer->GetEventRegions(); 296 } 297 return EventRegions(); 298 } 299 GetVisibleRegion()300 LayerIntRegion GetVisibleRegion() const { 301 MOZ_ASSERT(IsValid()); 302 303 if (AtBottomLayer()) { 304 return mLayer->GetVisibleRegion(); 305 } 306 307 return ViewAs<LayerPixel>( 308 TransformBy(mLayer->GetTransformTyped(), mLayer->GetVisibleRegion()), 309 PixelCastJustification::MovingDownToChildren); 310 } 311 GetRemoteDocumentSize()312 LayerIntSize GetRemoteDocumentSize() const { 313 MOZ_ASSERT(IsValid()); 314 315 return AsRefLayer() ? AsRefLayer()->GetRemoteDocumentSize() 316 : LayerIntSize(); 317 } 318 HasTransformAnimation()319 bool HasTransformAnimation() const { 320 MOZ_ASSERT(IsValid()); 321 322 if (AtBottomLayer()) { 323 return mLayer->HasTransformAnimation(); 324 } 325 return false; 326 } 327 AsRefLayer()328 RefLayer* AsRefLayer() const { 329 MOZ_ASSERT(IsValid()); 330 331 if (AtBottomLayer()) { 332 return mLayer->AsRefLayer(); 333 } 334 return nullptr; 335 } 336 GetReferentId()337 Maybe<LayersId> GetReferentId() const { 338 MOZ_ASSERT(IsValid()); 339 340 if (AtBottomLayer()) { 341 return mLayer->AsRefLayer() ? Some(mLayer->AsRefLayer()->GetReferentId()) 342 : Nothing(); 343 } 344 return Nothing(); 345 } 346 GetClipRect()347 Maybe<ParentLayerIntRect> GetClipRect() const { 348 MOZ_ASSERT(IsValid()); 349 350 Maybe<ParentLayerIntRect> result; 351 352 // The layer can have a clip rect and a scrolled clip, which are considered 353 // to apply only to the bottommost LayerMetricsWrapper. 354 // TODO: These actually apply in a different coordinate space than the 355 // scroll clip of the bottommost metrics, so we shouldn't be intersecting 356 // them with the scroll clip; bug 1269537 tracks fixing this. 357 if (AtBottomLayer()) { 358 result = mLayer->GetClipRect(); 359 result = IntersectMaybeRects(result, mLayer->GetScrolledClipRect()); 360 } 361 362 // The scroll metadata can have a clip rect as well. 363 result = IntersectMaybeRects(result, Metadata().GetClipRect()); 364 365 return result; 366 } 367 GetPresShellResolution()368 float GetPresShellResolution() const { 369 MOZ_ASSERT(IsValid()); 370 371 if (AtTopLayer() && mLayer->AsContainerLayer()) { 372 return mLayer->AsContainerLayer()->GetPresShellResolution(); 373 } 374 375 return 1.0f; 376 } 377 GetEventRegionsOverride()378 EventRegionsOverride GetEventRegionsOverride() const { 379 MOZ_ASSERT(IsValid()); 380 381 if (AsRefLayer()) { 382 return AsRefLayer()->GetEventRegionsOverride(); 383 } 384 return EventRegionsOverride::NoOverride; 385 } 386 GetScrollbarData()387 const ScrollbarData& GetScrollbarData() const { 388 MOZ_ASSERT(IsValid()); 389 390 return mLayer->GetScrollbarData(); 391 } 392 GetScrollbarAnimationId()393 Maybe<uint64_t> GetScrollbarAnimationId() const { 394 MOZ_ASSERT(IsValid()); 395 // This function is only really needed for template-compatibility with 396 // WebRenderScrollDataWrapper. Although it will be called, the return 397 // value is not used. 398 return Nothing(); 399 } 400 GetFixedPositionAnimationId()401 Maybe<uint64_t> GetFixedPositionAnimationId() const { 402 MOZ_ASSERT(IsValid()); 403 // This function is only really needed for template-compatibility with 404 // WebRenderScrollDataWrapper. Although it will be called, the return 405 // value is not used. 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() && mLayer->GetIsStickyPosition()) { 431 return mLayer->GetStickyScrollContainerId(); 432 } 433 return ScrollableLayerGuid::NULL_SCROLL_ID; 434 } 435 GetStickyScrollRangeOuter()436 const LayerRectAbsolute& GetStickyScrollRangeOuter() const { 437 MOZ_ASSERT(IsValid()); 438 439 if (AtBottomLayer() && mLayer->GetIsStickyPosition()) { 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() && mLayer->GetIsStickyPosition()) { 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 // This function is only really needed for template-compatibility with 461 // WebRenderScrollDataWrapper. Although it will be called, the return 462 // value is not used. 463 return Nothing(); 464 } 465 GetZoomAnimationId()466 Maybe<uint64_t> GetZoomAnimationId() const { 467 MOZ_ASSERT(IsValid()); 468 // This function is only really needed for template-compatibility with 469 // WebRenderScrollDataWrapper. Although it will be called, the return 470 // value is not used. 471 return Nothing(); 472 } 473 IsBackfaceHidden()474 bool IsBackfaceHidden() const { 475 MOZ_ASSERT(IsValid()); 476 477 return mLayer->IsBackfaceHidden(); 478 } 479 GetAsyncZoomContainerId()480 Maybe<ScrollableLayerGuid::ViewID> GetAsyncZoomContainerId() const { 481 MOZ_ASSERT(IsValid()); 482 483 return mLayer->GetAsyncZoomContainerId(); 484 } 485 486 // Expose an opaque pointer to the layer. Mostly used for printf 487 // purposes. This is not intended to be a general-purpose accessor 488 // for the underlying layer. GetLayer()489 const void* GetLayer() const { 490 MOZ_ASSERT(IsValid()); 491 492 return (void*)mLayer; 493 } 494 495 bool operator==(const LayerMetricsWrapper& aOther) const { 496 return mLayer == aOther.mLayer && mIndex == aOther.mIndex; 497 } 498 499 bool operator!=(const LayerMetricsWrapper& aOther) const { 500 return !(*this == aOther); 501 } 502 503 private: AtBottomLayer()504 bool AtBottomLayer() const { return mIndex == 0; } 505 AtTopLayer()506 bool AtTopLayer() const { 507 return mLayer->GetScrollMetadataCount() == 0 || 508 mIndex == mLayer->GetScrollMetadataCount() - 1; 509 } 510 511 private: 512 Layer* mLayer; 513 uint32_t mIndex; 514 }; 515 516 } // namespace layers 517 } // namespace mozilla 518 519 #endif /* GFX_LAYERMETRICSWRAPPER_H */ 520