fune/gfx/layers/wr/WebRenderScrollData.cpp
Kartikaya Gupta 11b43679d8 Bug 1421825 - Fix crash and re-enable crashtest. r=jrmuizel
In some cases we get a gecko display list that looks like this:

WrapList with asr(<A>, <B>)
  Item with asr (<B>) and clipchain(<something> [A])

In this case, we would initialize the WebRenderLayerScrollData for the
nested item using a stop-at ancestor of A (because that was the leafmost
ASR from the containing WrapList) but the item itself has an ASR of B,
which is an ancestor of A. So when walking up from B we'd never hit the
stop-at ancestor, and so we'd end up duplicating metrics from the
containing WRLSD onto the nested WRLSD. This generated an assertion
failure in the APZ code.

This patch detects this scenario and skips adding metrics on the nested
WRLSD. This produces an APZ tree equivalent to what the non-WebRender
path would produce.

MozReview-Commit-ID: 8eo6pzXXKBd

--HG--
extra : rebase_source : 0581c54c4d9fa6ca08249e42b306c7155022bec7
2018-07-10 09:37:40 -04:00

290 lines
8.8 KiB
C++

/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "mozilla/layers/WebRenderScrollData.h"
#include "Layers.h"
#include "LayersLogging.h"
#include "mozilla/layers/WebRenderLayerManager.h"
#include "mozilla/layout/RenderFrameParent.h"
#include "mozilla/Unused.h"
#include "nsDisplayList.h"
#include "nsTArray.h"
#include "UnitTransforms.h"
namespace mozilla {
namespace layers {
WebRenderLayerScrollData::WebRenderLayerScrollData()
: mDescendantCount(-1)
, mTransformIsPerspective(false)
, mEventRegionsOverride(EventRegionsOverride::NoOverride)
, mScrollbarAnimationId(0)
, mFixedPosScrollContainerId(FrameMetrics::NULL_SCROLL_ID)
{
}
WebRenderLayerScrollData::~WebRenderLayerScrollData()
{
}
void
WebRenderLayerScrollData::InitializeRoot(int32_t aDescendantCount)
{
mDescendantCount = aDescendantCount;
}
void
WebRenderLayerScrollData::Initialize(WebRenderScrollData& aOwner,
nsDisplayItem* aItem,
int32_t aDescendantCount,
const ActiveScrolledRoot* aStopAtAsr,
const Maybe<gfx::Matrix4x4>& aAncestorTransform)
{
MOZ_ASSERT(aDescendantCount >= 0); // Ensure value is valid
MOZ_ASSERT(mDescendantCount == -1); // Don't allow re-setting an already set value
mDescendantCount = aDescendantCount;
MOZ_ASSERT(aItem);
aItem->UpdateScrollData(&aOwner, this);
const ActiveScrolledRoot* asr = aItem->GetActiveScrolledRoot();
if (ActiveScrolledRoot::IsAncestor(asr, aStopAtAsr)) {
// If the item's ASR is an ancestor of the stop-at ASR, then we don't need
// any more metrics information because we'll end up duplicating what the
// ancestor WebRenderLayerScrollData already has.
asr = nullptr;
}
while (asr && asr != aStopAtAsr) {
MOZ_ASSERT(aOwner.GetManager());
FrameMetrics::ViewID scrollId = asr->GetViewId();
if (Maybe<size_t> index = aOwner.HasMetadataFor(scrollId)) {
mScrollIds.AppendElement(index.ref());
} else {
Maybe<ScrollMetadata> metadata = asr->mScrollableFrame->ComputeScrollMetadata(
aOwner.GetManager(), aItem->ReferenceFrame(),
ContainerLayerParameters(), nullptr);
MOZ_ASSERT(metadata);
MOZ_ASSERT(metadata->GetMetrics().GetScrollId() == scrollId);
mScrollIds.AppendElement(aOwner.AddMetadata(metadata.ref()));
}
asr = asr->mParent;
}
// aAncestorTransform, if present, is the transform from an ancestor
// nsDisplayTransform that was stored on the stacking context in order to
// propagate it downwards in the tree. (i.e. |aItem| is a strict descendant of
// the nsDisplayTranform which produced aAncestorTransform). We store this
// separately from mTransform because in the case where we have multiple
// scroll metadata on this layer item, the mAncestorTransform is associated
// with the "topmost" scroll metadata, and the mTransform is associated with
// the "bottommost" scroll metadata. The code in
// WebRenderScrollDataWrapper::GetTransform() is responsible for combining
// these transforms and exposing them appropriately. Also, we don't save the
// ancestor transform for thumb layers, because those are a special case in
// APZ; we need to keep the ancestor transform for the scrollable content that
// the thumb scrolls, but not for the thumb itself, as it will result in
// incorrect visual positioning of the thumb.
if (aAncestorTransform && mScrollbarData.mScrollbarLayerType != ScrollbarLayerType::Thumb) {
mAncestorTransform = *aAncestorTransform;
}
}
int32_t
WebRenderLayerScrollData::GetDescendantCount() const
{
MOZ_ASSERT(mDescendantCount >= 0); // check that it was set
return mDescendantCount;
}
size_t
WebRenderLayerScrollData::GetScrollMetadataCount() const
{
return mScrollIds.Length();
}
void
WebRenderLayerScrollData::AppendScrollMetadata(WebRenderScrollData& aOwner,
const ScrollMetadata& aData)
{
mScrollIds.AppendElement(aOwner.AddMetadata(aData));
}
const ScrollMetadata&
WebRenderLayerScrollData::GetScrollMetadata(const WebRenderScrollData& aOwner,
size_t aIndex) const
{
MOZ_ASSERT(aIndex < mScrollIds.Length());
return aOwner.GetScrollMetadata(mScrollIds[aIndex]);
}
CSSTransformMatrix
WebRenderLayerScrollData::GetTransformTyped() const
{
return ViewAs<CSSTransformMatrix>(GetTransform());
}
void
WebRenderLayerScrollData::Dump(const WebRenderScrollData& aOwner) const
{
printf_stderr("LayerScrollData(%p) descendants %d\n", this, mDescendantCount);
for (size_t i : mScrollIds) {
printf_stderr(" metadata: %s\n", Stringify(aOwner.GetScrollMetadata(i)).c_str());
}
printf_stderr(" ancestor transform: %s\n", Stringify(mAncestorTransform).c_str());
printf_stderr(" transform: %s perspective: %d visible: %s\n",
Stringify(mTransform).c_str(), mTransformIsPerspective,
Stringify(mVisibleRegion).c_str());
printf_stderr(" event regions: %s override: 0x%x\n",
Stringify(mEventRegions).c_str(), mEventRegionsOverride);
if (mReferentId) {
printf_stderr(" ref layers id: 0x%" PRIx64 "\n", uint64_t(*mReferentId));
}
printf_stderr(" scrollbar type: %d animation: %" PRIx64 "\n",
(int)mScrollbarData.mScrollbarLayerType, mScrollbarAnimationId);
printf_stderr(" fixed pos container: %" PRIu64 "\n",
mFixedPosScrollContainerId);
}
WebRenderScrollData::WebRenderScrollData()
: mManager(nullptr)
, mIsFirstPaint(false)
, mPaintSequenceNumber(0)
{
}
WebRenderScrollData::WebRenderScrollData(WebRenderLayerManager* aManager)
: mManager(aManager)
, mIsFirstPaint(false)
, mPaintSequenceNumber(0)
{
}
WebRenderScrollData::~WebRenderScrollData()
{
}
WebRenderLayerManager*
WebRenderScrollData::GetManager() const
{
return mManager;
}
size_t
WebRenderScrollData::AddMetadata(const ScrollMetadata& aMetadata)
{
FrameMetrics::ViewID scrollId = aMetadata.GetMetrics().GetScrollId();
auto insertResult = mScrollIdMap.insert(std::make_pair(scrollId, 0));
if (insertResult.second) {
// Insertion took place, therefore it's a scrollId we hadn't seen before
insertResult.first->second = mScrollMetadatas.Length();
mScrollMetadatas.AppendElement(aMetadata);
} // else we didn't insert, because it already existed
return insertResult.first->second;
}
size_t
WebRenderScrollData::AddLayerData(const WebRenderLayerScrollData& aData)
{
mLayerScrollData.AppendElement(aData);
return mLayerScrollData.Length() - 1;
}
size_t
WebRenderScrollData::GetLayerCount() const
{
return mLayerScrollData.Length();
}
const WebRenderLayerScrollData*
WebRenderScrollData::GetLayerData(size_t aIndex) const
{
if (aIndex >= mLayerScrollData.Length()) {
return nullptr;
}
return &(mLayerScrollData.ElementAt(aIndex));
}
const ScrollMetadata&
WebRenderScrollData::GetScrollMetadata(size_t aIndex) const
{
MOZ_ASSERT(aIndex < mScrollMetadatas.Length());
return mScrollMetadatas[aIndex];
}
Maybe<size_t>
WebRenderScrollData::HasMetadataFor(const FrameMetrics::ViewID& aScrollId) const
{
auto it = mScrollIdMap.find(aScrollId);
return (it == mScrollIdMap.end() ? Nothing() : Some(it->second));
}
void
WebRenderScrollData::SetFocusTarget(const FocusTarget& aFocusTarget)
{
mFocusTarget = aFocusTarget;
}
void
WebRenderScrollData::SetIsFirstPaint()
{
mIsFirstPaint = true;
}
bool
WebRenderScrollData::IsFirstPaint() const
{
return mIsFirstPaint;
}
void
WebRenderScrollData::SetPaintSequenceNumber(uint32_t aPaintSequenceNumber)
{
mPaintSequenceNumber = aPaintSequenceNumber;
}
uint32_t
WebRenderScrollData::GetPaintSequenceNumber() const
{
return mPaintSequenceNumber;
}
void
WebRenderScrollData::ApplyUpdates(const ScrollUpdatesMap& aUpdates,
uint32_t aPaintSequenceNumber)
{
for (const auto& update : aUpdates) {
if (Maybe<size_t> index = HasMetadataFor(update.first)) {
mScrollMetadatas[*index].GetMetrics().UpdatePendingScrollInfo(update.second);
}
}
mPaintSequenceNumber = aPaintSequenceNumber;
}
void
WebRenderScrollData::Dump() const
{
printf_stderr("WebRenderScrollData with %zu layers firstpaint: %d\n",
mLayerScrollData.Length(), mIsFirstPaint);
for (size_t i = 0; i < mLayerScrollData.Length(); i++) {
mLayerScrollData.ElementAt(i).Dump(*this);
}
}
bool
WebRenderScrollData::RepopulateMap()
{
MOZ_ASSERT(mScrollIdMap.empty());
for (size_t i = 0; i < mScrollMetadatas.Length(); i++) {
FrameMetrics::ViewID scrollId = mScrollMetadatas[i].GetMetrics().GetScrollId();
mScrollIdMap.emplace(scrollId, i);
}
return true;
}
} // namespace layers
} // namespace mozilla