WebRenderScrollData.cpp (19614B)
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 #include "mozilla/layers/WebRenderScrollData.h" 8 9 #include <ostream> 10 11 #include "Units.h" 12 #include "mozilla/layers/LayersMessageUtils.h" 13 #include "mozilla/layers/WebRenderLayerManager.h" 14 #include "mozilla/ScrollContainerFrame.h" 15 #include "nsDisplayList.h" 16 #include "nsTArray.h" 17 #include "UnitTransforms.h" 18 19 namespace mozilla { 20 namespace layers { 21 22 WebRenderLayerScrollData::WebRenderLayerScrollData() 23 : mDescendantCount(-1), 24 mAncestorTransformId(ScrollableLayerGuid::NULL_SCROLL_ID), 25 mTransformIsPerspective(false), 26 mEventRegionsOverride(EventRegionsOverride::NoOverride), 27 mFixedPositionSides(mozilla::SideBits::eNone), 28 mFixedPosScrollContainerId(ScrollableLayerGuid::NULL_SCROLL_ID), 29 mStickyPosScrollContainerId(ScrollableLayerGuid::NULL_SCROLL_ID) {} 30 31 WebRenderLayerScrollData::~WebRenderLayerScrollData() = default; 32 33 void WebRenderLayerScrollData::InitializeRoot(int32_t aDescendantCount) { 34 mDescendantCount = aDescendantCount; 35 } 36 37 void WebRenderLayerScrollData::InitializeForTest(int32_t aDescendantCount) { 38 mDescendantCount = aDescendantCount; 39 } 40 41 void WebRenderLayerScrollData::Initialize( 42 WebRenderScrollData& aOwner, nsDisplayItem* aItem, int32_t aDescendantCount, 43 const ActiveScrolledRoot* aStopAtAsr, 44 const Maybe<gfx::Matrix4x4>& aAncestorTransform, 45 const ViewID& aAncestorTransformId) { 46 MOZ_ASSERT(aDescendantCount >= 0); // Ensure value is valid 47 MOZ_ASSERT(mDescendantCount == 48 -1); // Don't allow re-setting an already set value 49 mDescendantCount = aDescendantCount; 50 51 #if defined(DEBUG) || defined(MOZ_DUMP_PAINTING) 52 mInitializedFrom = aItem; 53 #endif 54 55 MOZ_ASSERT(aItem); 56 aItem->UpdateScrollData(&aOwner, this); 57 58 const ActiveScrolledRoot* asr = aItem->GetActiveScrolledRoot(); 59 if (ActiveScrolledRoot::IsAncestor(asr, aStopAtAsr)) { 60 // If the item's ASR is an ancestor of the stop-at ASR, then we don't need 61 // any more metrics information because we'll end up duplicating what the 62 // ancestor WebRenderLayerScrollData already has. 63 asr = nullptr; 64 } 65 66 while (asr && asr != aStopAtAsr) { 67 MOZ_ASSERT(aOwner.GetManager()); 68 if (asr->mKind != ActiveScrolledRoot::ASRKind::Scroll) { 69 asr = asr->mParent; 70 continue; 71 } 72 ScrollableLayerGuid::ViewID scrollId = asr->GetViewId(); 73 if (Maybe<size_t> index = aOwner.HasMetadataFor(scrollId)) { 74 mScrollIds.AppendElement(index.ref()); 75 } else { 76 Maybe<ScrollMetadata> metadata = 77 asr->ScrollFrame()->ComputeScrollMetadata( 78 aOwner.GetManager(), aItem->Frame(), aItem->ToReferenceFrame()); 79 aOwner.GetBuilder()->AddScrollContainerFrameToNotify(asr->ScrollFrame()); 80 if (metadata) { 81 MOZ_ASSERT(metadata->GetMetrics().GetScrollId() == scrollId); 82 mScrollIds.AppendElement(aOwner.AddMetadata(metadata.ref())); 83 } else { 84 MOZ_ASSERT_UNREACHABLE("Expected scroll metadata to be available!"); 85 } 86 } 87 asr = asr->mParent; 88 } 89 90 #ifdef DEBUG 91 // Sanity check: if we have an ancestor transform, its scroll id should 92 // match one of the scroll metadatas on this node (WebRenderScrollDataWrapper 93 // will then use the ancestor transform at the level of that scroll metadata). 94 // One exception to this is if we have no scroll metadatas, which can happen 95 // if the scroll id of the transform is on an enclosing node. 96 if (aAncestorTransformId != ScrollableLayerGuid::NULL_SCROLL_ID && 97 !mScrollIds.IsEmpty()) { 98 bool seenAncestorTransformId = false; 99 for (size_t scrollIdIndex : mScrollIds) { 100 if (aAncestorTransformId == 101 aOwner.GetScrollMetadata(scrollIdIndex).GetMetrics().GetScrollId()) { 102 seenAncestorTransformId = true; 103 } 104 } 105 MOZ_ASSERT( 106 seenAncestorTransformId, 107 "The ancestor transform's view ID should match one of the metrics " 108 "on this node"); 109 } 110 #endif 111 112 // See the comments on StackingContextHelper::mDeferredTransformItem for an 113 // overview of what deferred transforms are. 114 // aAncestorTransform, if present, is the transform from a deferred transform 115 // item that is an ancestor of |aItem|. We store this transform value 116 // separately from mTransform because in the case where we have multiple 117 // scroll metadata on this layer item, the mAncestorTransform is associated 118 // with the "topmost" scroll metadata, and the mTransform is associated with 119 // the "bottommost" scroll metadata. The code in 120 // WebRenderScrollDataWrapper::GetTransform() is responsible for combining 121 // these transforms and exposing them appropriately. Also, we don't save the 122 // ancestor transform for thumb layers, because those are a special case in 123 // APZ; we need to keep the ancestor transform for the scrollable content that 124 // the thumb scrolls, but not for the thumb itself, as it will result in 125 // incorrect visual positioning of the thumb. 126 if (aAncestorTransform && 127 mScrollbarData.mScrollbarLayerType != ScrollbarLayerType::Thumb) { 128 mAncestorTransform = *aAncestorTransform; 129 mAncestorTransformId = aAncestorTransformId; 130 } 131 } 132 133 int32_t WebRenderLayerScrollData::GetDescendantCount() const { 134 MOZ_ASSERT(mDescendantCount >= 0); // check that it was set 135 return mDescendantCount; 136 } 137 138 size_t WebRenderLayerScrollData::GetScrollMetadataCount() const { 139 return mScrollIds.Length(); 140 } 141 142 void WebRenderLayerScrollData::AppendScrollMetadata( 143 WebRenderScrollData& aOwner, const ScrollMetadata& aData) { 144 mScrollIds.AppendElement(aOwner.AddMetadata(aData)); 145 } 146 147 const ScrollMetadata& WebRenderLayerScrollData::GetScrollMetadata( 148 const WebRenderScrollData& aOwner, size_t aIndex) const { 149 MOZ_ASSERT(aIndex < mScrollIds.Length()); 150 return aOwner.GetScrollMetadata(mScrollIds[aIndex]); 151 } 152 153 ScrollMetadata& WebRenderLayerScrollData::GetScrollMetadataMut( 154 WebRenderScrollData& aOwner, size_t aIndex) { 155 MOZ_ASSERT(aIndex < mScrollIds.Length()); 156 return aOwner.GetScrollMetadataMut(mScrollIds[aIndex]); 157 } 158 159 CSSTransformMatrix WebRenderLayerScrollData::GetTransformTyped() const { 160 return ViewAs<CSSTransformMatrix>(GetTransform()); 161 } 162 163 void WebRenderLayerScrollData::Dump(std::ostream& aOut, 164 const WebRenderScrollData& aOwner) const { 165 aOut << "WebRenderLayerScrollData(" << this 166 << "), descendantCount=" << mDescendantCount; 167 #if defined(DEBUG) || defined(MOZ_DUMP_PAINTING) 168 if (mInitializedFrom) { 169 aOut << ", item=" << (void*)mInitializedFrom; 170 } 171 #endif 172 if (mAsyncZoomContainerId) { 173 aOut << ", asyncZoomContainer"; 174 } 175 for (size_t i = 0; i < mScrollIds.Length(); i++) { 176 aOut << ", metadata" << i << "=" << aOwner.GetScrollMetadata(mScrollIds[i]); 177 } 178 if (!mAncestorTransform.IsIdentity()) { 179 aOut << ", ancestorTransform=" << mAncestorTransform 180 << " (asr=" << mAncestorTransformId << ")"; 181 } 182 if (!mTransform.IsIdentity()) { 183 aOut << ", transform=" << mTransform; 184 if (mTransformIsPerspective) { 185 aOut << ", transformIsPerspective"; 186 } 187 } 188 aOut << ", visible=" << mVisibleRect; 189 if (mReferentId) { 190 aOut << ", refLayersId=" << *mReferentId; 191 } 192 if (mEventRegionsOverride) { 193 aOut << std::hex << ", eventRegionsOverride=0x" 194 << (int)mEventRegionsOverride << std::dec; 195 } 196 if (mScrollbarData.mScrollbarLayerType != ScrollbarLayerType::None) { 197 aOut << ", scrollbarType=" << (int)mScrollbarData.mScrollbarLayerType 198 << std::hex << ", scrollbarAnimationId=0x" 199 << mScrollbarAnimationId.valueOr(0) << std::dec; 200 } 201 if (mFixedPosScrollContainerId != ScrollableLayerGuid::NULL_SCROLL_ID) { 202 aOut << ", fixedContainer=" << mFixedPosScrollContainerId << std::hex 203 << ", fixedAnimation=0x" << mFixedPositionAnimationId.valueOr(0) 204 << ", sideBits=0x" << (int)mFixedPositionSides << std::dec; 205 } 206 if (mStickyPosScrollContainerId != ScrollableLayerGuid::NULL_SCROLL_ID) { 207 aOut << ", stickyContainer=" << mStickyPosScrollContainerId << std::hex 208 << ", stickyAnimation=" << mStickyPositionAnimationId.valueOr(0) 209 << std::dec << ", stickyInner=" << mStickyScrollRangeInner 210 << ", stickyOuter=" << mStickyScrollRangeOuter; 211 } 212 } 213 214 WebRenderScrollData::WebRenderScrollData() 215 : mManager(nullptr), 216 mBuilder(nullptr), 217 mIsFirstPaint(false), 218 mPaintSequenceNumber(0) {} 219 220 WebRenderScrollData::WebRenderScrollData(WebRenderLayerManager* aManager, 221 nsDisplayListBuilder* aBuilder) 222 : mManager(aManager), 223 mBuilder(aBuilder), 224 mIsFirstPaint(false), 225 mPaintSequenceNumber(0) {} 226 227 bool WebRenderScrollData::Validate() const { 228 // Attempt to traverse the tree structure encoded by the descendant counts, 229 // validating as we go that everything is within bounds and properly nested. 230 // In addition, check that the traversal visits every node exactly once. 231 std::vector<size_t> visitCounts(mLayerScrollData.Length(), 0); 232 if (mLayerScrollData.Length() > 0) { 233 if (!mLayerScrollData[0].ValidateSubtree(*this, visitCounts, 0)) { 234 return false; 235 } 236 } 237 for (size_t visitCount : visitCounts) { 238 if (visitCount != 1) { 239 return false; 240 } 241 } 242 return true; 243 } 244 245 WebRenderLayerManager* WebRenderScrollData::GetManager() const { 246 return mManager; 247 } 248 249 nsDisplayListBuilder* WebRenderScrollData::GetBuilder() const { 250 return mBuilder; 251 } 252 253 size_t WebRenderScrollData::AddMetadata(const ScrollMetadata& aMetadata) { 254 ScrollableLayerGuid::ViewID scrollId = aMetadata.GetMetrics().GetScrollId(); 255 auto p = mScrollIdMap.lookupForAdd(scrollId); 256 if (!p) { 257 // It's a scrollId we hadn't seen before 258 bool ok = mScrollIdMap.add(p, scrollId, mScrollMetadatas.Length()); 259 MOZ_RELEASE_ASSERT(ok); 260 mScrollMetadatas.AppendElement(aMetadata); 261 } // else we didn't insert, because it already existed 262 return p->value(); 263 } 264 265 size_t WebRenderScrollData::AddLayerData(WebRenderLayerScrollData&& aData) { 266 mLayerScrollData.AppendElement(std::move(aData)); 267 return mLayerScrollData.Length() - 1; 268 } 269 270 size_t WebRenderScrollData::GetLayerCount() const { 271 return mLayerScrollData.Length(); 272 } 273 274 bool WebRenderLayerScrollData::ValidateSubtree( 275 const WebRenderScrollData& aParent, std::vector<size_t>& aVisitCounts, 276 size_t aCurrentIndex) const { 277 ++aVisitCounts[aCurrentIndex]; 278 279 // All scroll ids must be in bounds. 280 for (size_t scrollMetadataIndex : mScrollIds) { 281 if (scrollMetadataIndex >= aParent.mScrollMetadatas.Length()) { 282 return false; 283 } 284 } 285 286 // Descendant count must be nonnegative. 287 if (mDescendantCount < 0) { 288 return false; 289 } 290 size_t descendantCount = static_cast<size_t>(mDescendantCount); 291 292 // Bounds check: for every layer, its index + its mDescendantCount 293 // must be within bounds. 294 if (aCurrentIndex + descendantCount >= aParent.mLayerScrollData.Length()) { 295 return false; 296 } 297 298 // Recurse over our children, accumulating a count of our children 299 // and their descendants as we go. 300 size_t childCount = 0; 301 size_t childDescendantCounts = 0; 302 size_t currentChildIndex = aCurrentIndex + 1; 303 while (currentChildIndex < (aCurrentIndex + descendantCount + 1)) { 304 ++childCount; 305 306 const WebRenderLayerScrollData* currentChild = 307 &aParent.mLayerScrollData[currentChildIndex]; 308 childDescendantCounts += currentChild->mDescendantCount; 309 currentChild->ValidateSubtree(aParent, aVisitCounts, currentChildIndex); 310 311 // The current child's descendants come first in the array, and the next 312 // element after that is our next child. 313 currentChildIndex += (currentChild->mDescendantCount + 1); 314 } 315 316 // For a given layer, its descendant count must equal the number of 317 // children + the descendant counts of its children added together. 318 return descendantCount == (childCount + childDescendantCounts); 319 } 320 321 const WebRenderLayerScrollData* WebRenderScrollData::GetLayerData( 322 size_t aIndex) const { 323 if (aIndex >= mLayerScrollData.Length()) { 324 return nullptr; 325 } 326 return &(mLayerScrollData.ElementAt(aIndex)); 327 } 328 329 WebRenderLayerScrollData* WebRenderScrollData::GetLayerData(size_t aIndex) { 330 if (aIndex >= mLayerScrollData.Length()) { 331 return nullptr; 332 } 333 return &(mLayerScrollData.ElementAt(aIndex)); 334 } 335 336 const ScrollMetadata& WebRenderScrollData::GetScrollMetadata( 337 size_t aIndex) const { 338 MOZ_ASSERT(aIndex < mScrollMetadatas.Length()); 339 return mScrollMetadatas[aIndex]; 340 } 341 342 ScrollMetadata& WebRenderScrollData::GetScrollMetadataMut(size_t aIndex) { 343 MOZ_ASSERT(aIndex < mScrollMetadatas.Length()); 344 return mScrollMetadatas[aIndex]; 345 } 346 347 Maybe<size_t> WebRenderScrollData::HasMetadataFor( 348 const ScrollableLayerGuid::ViewID& aScrollId) const { 349 auto ptr = mScrollIdMap.lookup(aScrollId); 350 return (ptr ? Some(ptr->value()) : Nothing()); 351 } 352 353 void WebRenderScrollData::SetIsFirstPaint(bool aValue) { 354 mIsFirstPaint = aValue; 355 } 356 357 bool WebRenderScrollData::IsFirstPaint() const { return mIsFirstPaint; } 358 359 void WebRenderScrollData::SetPaintSequenceNumber( 360 uint32_t aPaintSequenceNumber) { 361 mPaintSequenceNumber = aPaintSequenceNumber; 362 } 363 364 uint32_t WebRenderScrollData::GetPaintSequenceNumber() const { 365 return mPaintSequenceNumber; 366 } 367 368 void WebRenderScrollData::ApplyUpdates(ScrollUpdatesMap&& aUpdates, 369 uint32_t aPaintSequenceNumber) { 370 for (auto it = aUpdates.Iter(); !it.Done(); it.Next()) { 371 if (Maybe<size_t> index = HasMetadataFor(it.Key())) { 372 mScrollMetadatas[*index].UpdatePendingScrollInfo(std::move(it.Data())); 373 } 374 } 375 mPaintSequenceNumber = aPaintSequenceNumber; 376 } 377 378 void WebRenderScrollData::PrependUpdates( 379 const WebRenderScrollData& aPreviousData) { 380 for (auto previousMetadata : aPreviousData.mScrollMetadatas) { 381 const nsTArray<ScrollPositionUpdate>& previousUpdates = 382 previousMetadata.GetScrollUpdates(); 383 if (previousUpdates.IsEmpty()) { 384 continue; 385 } 386 387 if (Maybe<size_t> index = 388 HasMetadataFor(previousMetadata.GetMetrics().GetScrollId())) { 389 mScrollMetadatas[*index].PrependUpdates(previousUpdates); 390 } 391 } 392 } 393 394 void WebRenderScrollData::DumpSubtree(std::ostream& aOut, size_t aIndex, 395 const std::string& aIndent) const { 396 aOut << aIndent; 397 mLayerScrollData.ElementAt(aIndex).Dump(aOut, *this); 398 aOut << std::endl; 399 400 int32_t descendants = mLayerScrollData.ElementAt(aIndex).GetDescendantCount(); 401 if (descendants == 0) { 402 return; 403 } 404 405 // Build a stack of indices at which this aIndex's children live. We do 406 // this because we want to dump them first-to-last but they are stored 407 // last-to-first. 408 std::stack<size_t> childIndices; 409 size_t childIndex = aIndex + 1; 410 while (descendants > 0) { 411 childIndices.push(childIndex); 412 // "1" for the child itelf, plus whatever descendants it has 413 int32_t subtreeSize = 414 1 + mLayerScrollData.ElementAt(childIndex).GetDescendantCount(); 415 childIndex += subtreeSize; 416 descendants -= subtreeSize; 417 MOZ_ASSERT(descendants >= 0); 418 } 419 420 std::string indent = aIndent + " "; 421 while (!childIndices.empty()) { 422 size_t child = childIndices.top(); 423 childIndices.pop(); 424 DumpSubtree(aOut, child, indent); 425 } 426 } 427 428 std::ostream& operator<<(std::ostream& aOut, const WebRenderScrollData& aData) { 429 aOut << "--- WebRenderScrollData (firstPaint=" << aData.mIsFirstPaint 430 << ") ---" << std::endl; 431 432 if (aData.mLayerScrollData.Length() > 0) { 433 aData.DumpSubtree(aOut, 0, std::string()); 434 } 435 return aOut; 436 } 437 438 bool WebRenderScrollData::RepopulateMap() { 439 MOZ_ASSERT(mScrollIdMap.empty()); 440 for (size_t i = 0; i < mScrollMetadatas.Length(); i++) { 441 ScrollableLayerGuid::ViewID scrollId = 442 mScrollMetadatas[i].GetMetrics().GetScrollId(); 443 bool ok = mScrollIdMap.putNew(scrollId, i); 444 MOZ_RELEASE_ASSERT(ok); 445 } 446 return true; 447 } 448 449 } // namespace layers 450 } // namespace mozilla 451 452 namespace IPC { 453 454 void ParamTraits<mozilla::layers::WebRenderLayerScrollData>::Write( 455 MessageWriter* aWriter, const paramType& aParam) { 456 WriteParam(aWriter, aParam.mDescendantCount); 457 WriteParam(aWriter, aParam.mScrollIds); 458 WriteParam(aWriter, aParam.mAncestorTransform); 459 WriteParam(aWriter, aParam.mAncestorTransformId); 460 WriteParam(aWriter, aParam.mTransform); 461 WriteParam(aWriter, aParam.mTransformIsPerspective); 462 WriteParam(aWriter, aParam.mVisibleRect); 463 WriteParam(aWriter, aParam.mRemoteDocumentSize); 464 WriteParam(aWriter, aParam.mReferentId); 465 WriteParam(aWriter, aParam.mEventRegionsOverride); 466 WriteParam(aWriter, aParam.mScrollbarData); 467 WriteParam(aWriter, aParam.mScrollbarAnimationId); 468 WriteParam(aWriter, aParam.mFixedPositionAnimationId); 469 WriteParam(aWriter, aParam.mFixedPositionSides); 470 WriteParam(aWriter, aParam.mFixedPosScrollContainerId); 471 WriteParam(aWriter, aParam.mStickyPosScrollContainerId); 472 WriteParam(aWriter, aParam.mStickyScrollRangeOuter); 473 WriteParam(aWriter, aParam.mStickyScrollRangeInner); 474 WriteParam(aWriter, aParam.mStickyPositionAnimationId); 475 WriteParam(aWriter, aParam.mZoomAnimationId); 476 WriteParam(aWriter, aParam.mAsyncZoomContainerId); 477 // Do not write |mInitializedFrom|, the pointer wouldn't be valid 478 // on the compositor side. 479 } 480 481 bool ParamTraits<mozilla::layers::WebRenderLayerScrollData>::Read( 482 MessageReader* aReader, paramType* aResult) { 483 return ReadParam(aReader, &aResult->mDescendantCount) && 484 ReadParam(aReader, &aResult->mScrollIds) && 485 ReadParam(aReader, &aResult->mAncestorTransform) && 486 ReadParam(aReader, &aResult->mAncestorTransformId) && 487 ReadParam(aReader, &aResult->mTransform) && 488 ReadParam(aReader, &aResult->mTransformIsPerspective) && 489 ReadParam(aReader, &aResult->mVisibleRect) && 490 ReadParam(aReader, &aResult->mRemoteDocumentSize) && 491 ReadParam(aReader, &aResult->mReferentId) && 492 ReadParam(aReader, &aResult->mEventRegionsOverride) && 493 ReadParam(aReader, &aResult->mScrollbarData) && 494 ReadParam(aReader, &aResult->mScrollbarAnimationId) && 495 ReadParam(aReader, &aResult->mFixedPositionAnimationId) && 496 ReadParam(aReader, &aResult->mFixedPositionSides) && 497 ReadParam(aReader, &aResult->mFixedPosScrollContainerId) && 498 ReadParam(aReader, &aResult->mStickyPosScrollContainerId) && 499 ReadParam(aReader, &aResult->mStickyScrollRangeOuter) && 500 ReadParam(aReader, &aResult->mStickyScrollRangeInner) && 501 ReadParam(aReader, &aResult->mStickyPositionAnimationId) && 502 ReadParam(aReader, &aResult->mZoomAnimationId) && 503 ReadParam(aReader, &aResult->mAsyncZoomContainerId); 504 } 505 506 void ParamTraits<mozilla::layers::WebRenderScrollData>::Write( 507 MessageWriter* aWriter, const paramType& aParam) { 508 WriteParam(aWriter, aParam.mScrollMetadatas); 509 WriteParam(aWriter, aParam.mLayerScrollData); 510 WriteParam(aWriter, aParam.mIsFirstPaint); 511 WriteParam(aWriter, aParam.mPaintSequenceNumber); 512 } 513 514 bool ParamTraits<mozilla::layers::WebRenderScrollData>::Read( 515 MessageReader* aReader, paramType* aResult) { 516 return ReadParam(aReader, &aResult->mScrollMetadatas) && 517 ReadParam(aReader, &aResult->mLayerScrollData) && 518 ReadParam(aReader, &aResult->mIsFirstPaint) && 519 ReadParam(aReader, &aResult->mPaintSequenceNumber) && 520 aResult->RepopulateMap(); 521 } 522 523 } // namespace IPC