Bug 1526941 - Part 5: Rewrite nsDisplayTransform bounds calculations r=mattwoodrow

Differential Revision: https://phabricator.services.mozilla.com/D22333

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Miko Mynttinen 2019-03-07 17:13:45 +00:00
Родитель 2ab05c6458
Коммит 8625692016
2 изменённых файлов: 96 добавлений и 93 удалений

Просмотреть файл

@ -7330,7 +7330,6 @@ nsDisplayTransform::nsDisplayTransform(nsDisplayListBuilder* aBuilder,
MOZ_COUNT_CTOR(nsDisplayTransform);
MOZ_ASSERT(aFrame, "Must have a frame!");
Init(aBuilder, aList);
UpdateBoundsFor3D(aBuilder);
}
nsDisplayTransform::nsDisplayTransform(nsDisplayListBuilder* aBuilder,
@ -7350,7 +7349,6 @@ nsDisplayTransform::nsDisplayTransform(nsDisplayListBuilder* aBuilder,
MOZ_ASSERT(aFrame, "Must have a frame!");
SetReferenceFrameToAncestor(aBuilder);
Init(aBuilder, aList);
UpdateBoundsFor3D(aBuilder);
}
nsDisplayTransform::nsDisplayTransform(
@ -7409,9 +7407,8 @@ void nsDisplayTransform::SetReferenceFrameToAncestor(
void nsDisplayTransform::Init(nsDisplayListBuilder* aBuilder,
nsDisplayList* aChildren) {
mShouldFlatten = false;
mHasBounds = false;
mChildren.AppendToTop(aChildren);
UpdateUntransformedBounds(aBuilder);
UpdateBounds(aBuilder);
}
bool nsDisplayTransform::ShouldFlattenAway(nsDisplayListBuilder* aBuilder) {
@ -8173,6 +8170,59 @@ bool nsDisplayTransform::ComputeVisibility(nsDisplayListBuilder* aBuilder,
return true;
}
nsRect nsDisplayTransform::TransformUntransformedBounds(
nsDisplayListBuilder* aBuilder, const Matrix4x4Flagged& aMatrix) const {
bool snap;
const nsRect untransformedBounds = GetUntransformedBounds(aBuilder, &snap);
// GetTransform always operates in dev pixels.
const float factor = mFrame->PresContext()->AppUnitsPerDevPixel();
return nsLayoutUtils::MatrixTransformRect(untransformedBounds, aMatrix,
factor);
}
/**
* Returns the bounds for this transform. The bounds are calculated during
* display list building and merging, see |nsDisplayTransform::UpdateBounds()|.
*/
nsRect nsDisplayTransform::GetBounds(nsDisplayListBuilder* aBuilder,
bool* aSnap) const {
*aSnap = false;
return mBounds;
}
void nsDisplayTransform::ComputeBounds(nsDisplayListBuilder* aBuilder) {
MOZ_ASSERT(mFrame->Extend3DContext() || IsLeafOf3DContext());
/* Some transforms can get empty bounds in 2D, but might get transformed again
* and get non-empty bounds. A simple example of this would be a 180 degree
* rotation getting applied twice.
* We should not depend on transforming bounds level by level.
*
* This function collects the bounds of this transform and stores it in
* nsDisplayListBuilder. If this is not a leaf of a 3D context, we recurse
* down and include the bounds of the child transforms.
* The bounds are transformed with the accumulated transformation matrix up to
* the 3D context root coordinate space.
*/
nsDisplayListBuilder::AutoAccumulateTransform accTransform(aBuilder);
accTransform.Accumulate(GetTransform().GetMatrix());
// Do not dive into another 3D context.
if (!IsLeafOf3DContext()) {
for (nsDisplayItem* i = GetChildren()->GetBottom(); i; i = i->GetAbove()) {
i->DoUpdateBoundsPreserves3D(aBuilder);
}
}
/* The child transforms that extend 3D context further will have empty bounds,
* so the untransformed bounds here is the bounds of all the non-preserve-3d
* content under this transform.
*/
const nsRect rect = TransformUntransformedBounds(
aBuilder, accTransform.GetCurrentTransform());
aBuilder->AccumulateRect(rect);
}
void nsDisplayTransform::DoUpdateBoundsPreserves3D(
nsDisplayListBuilder* aBuilder) {
MOZ_ASSERT(mFrame->Combines3DTransformWithAncestors() ||
@ -8182,17 +8232,36 @@ void nsDisplayTransform::DoUpdateBoundsPreserves3D(
}
void nsDisplayTransform::UpdateBounds(nsDisplayListBuilder* aBuilder) {
mHasBounds = false;
UpdateUntransformedBounds(aBuilder, true);
UpdateBoundsFor3D(aBuilder);
UpdateUntransformedBounds(aBuilder);
if (IsTransformSeparator()) {
MOZ_ASSERT(GetTransform().IsIdentity());
mBounds = mChildBounds;
return;
}
if (!mFrame->Combines3DTransformWithAncestors()) {
if (mFrame->Extend3DContext()) {
// The transform establishes a 3D context. |UpdateBoundsFor3D()| will
// collect the bounds from the child transforms.
UpdateBoundsFor3D(aBuilder);
} else {
// A stand-alone transform.
mBounds = TransformUntransformedBounds(aBuilder, GetTransform());
}
return;
}
// With nested 3D transforms, the 2D bounds might not be useful.
MOZ_ASSERT(mFrame->Combines3DTransformWithAncestors());
mBounds = nsRect();
}
void nsDisplayTransform::UpdateBoundsFor3D(nsDisplayListBuilder* aBuilder) {
if (!mFrame->Extend3DContext() ||
mFrame->Combines3DTransformWithAncestors() || IsTransformSeparator()) {
// Not an establisher of a 3D rendering context.
return;
}
MOZ_ASSERT(mFrame->Extend3DContext() &&
!mFrame->Combines3DTransformWithAncestors() &&
!IsTransformSeparator());
// Always start updating from an establisher of a 3D rendering context.
nsDisplayListBuilder::AutoAccumulateRect accRect(aBuilder);
@ -8200,7 +8269,12 @@ void nsDisplayTransform::UpdateBoundsFor3D(nsDisplayListBuilder* aBuilder) {
accTransform.StartRoot();
ComputeBounds(aBuilder);
mBounds = aBuilder->GetAccumulatedRect();
mHasBounds = true;
}
void nsDisplayTransform::UpdateUntransformedBounds(
nsDisplayListBuilder* aBuilder) {
mChildBounds = GetChildren()->GetClippedBoundsWithRespectToASR(
aBuilder, mActiveScrolledRoot);
}
#ifdef DEBUG_HIT
@ -8318,67 +8392,6 @@ float nsDisplayTransform::GetHitDepthAtPoint(nsDisplayListBuilder* aBuilder,
return transformed.z;
}
/* The bounding rectangle for the object is the overflow rectangle translated
* by the reference point.
*/
nsRect nsDisplayTransform::GetBounds(nsDisplayListBuilder* aBuilder,
bool* aSnap) const {
*aSnap = false;
if (mHasBounds) {
return mBounds;
}
if (mFrame->Extend3DContext() && !mIsTransformSeparator) {
return nsRect();
}
bool snap;
nsRect untransformedBounds = GetUntransformedBounds(aBuilder, &snap);
// GetTransform always operates in dev pixels.
float factor = mFrame->PresContext()->AppUnitsPerDevPixel();
mBounds = nsLayoutUtils::MatrixTransformRect(untransformedBounds,
GetTransform(), factor);
mHasBounds = true;
return mBounds;
}
void nsDisplayTransform::ComputeBounds(nsDisplayListBuilder* aBuilder) {
MOZ_ASSERT(mFrame->Extend3DContext() || IsLeafOf3DContext());
/* For some cases, the transform would make an empty bounds, but it
* may be turned back again to get a non-empty bounds. We should
* not depend on transforming bounds level by level.
*
* Here, it applies accumulated transforms on the leaf frames of the
* 3d rendering context, and track and accmulate bounds at
* nsDisplayListBuilder.
*/
nsDisplayListBuilder::AutoAccumulateTransform accTransform(aBuilder);
accTransform.Accumulate(GetTransform().GetMatrix());
if (!IsLeafOf3DContext()) {
// Do not dive into another 3D context.
for (nsDisplayItem* i = GetChildren()->GetBottom(); i; i = i->GetAbove()) {
i->DoUpdateBoundsPreserves3D(aBuilder);
}
}
/* For Preserves3D, it is bounds of only children as leaf frames.
* For non-leaf frames, their bounds are accumulated and kept at
* nsDisplayListBuilder.
*/
bool snap;
nsRect untransformedBounds = GetUntransformedBounds(aBuilder, &snap);
// GetTransform always operates in dev pixels.
float factor = mFrame->PresContext()->AppUnitsPerDevPixel();
nsRect rect = nsLayoutUtils::MatrixTransformRect(
untransformedBounds, accTransform.GetCurrentTransform(), factor);
aBuilder->AccumulateRect(rect);
}
/* The transform is opaque iff the transform consists solely of scales and
* translations and if the underlying content is opaque. Thus if the transform
* is of the form

Просмотреть файл

@ -6513,22 +6513,13 @@ class nsDisplayTransform : public nsDisplayHitTestInfoItem {
nsRect GetUntransformedBounds(nsDisplayListBuilder* aBuilder,
bool* aSnap) const override {
*aSnap = false;
return *mChildBounds;
return mChildBounds;
}
const nsRect& GetUntransformedPaintRect() const override {
return mChildrenBuildingRect;
}
void UpdateUntransformedBounds(nsDisplayListBuilder* aBuilder,
bool aForce = false) {
if (!mChildBounds || aForce) {
mChildBounds =
mozilla::Some(GetChildren()->GetClippedBoundsWithRespectToASR(
aBuilder, mActiveScrolledRoot));
}
}
bool ShouldFlattenAway(nsDisplayListBuilder* aBuilder) override;
void HitTest(nsDisplayListBuilder* aBuilder, const nsRect& aRect,
@ -6768,7 +6759,7 @@ class nsDisplayTransform : public nsDisplayHitTestInfoItem {
* and child 3D rendering context.
* \see nsIFrame::BuildDisplayListForStackingContext().
*/
bool IsTransformSeparator() { return mIsTransformSeparator; }
bool IsTransformSeparator() const { return mIsTransformSeparator; }
/**
* This item is the boundary between parent and child 3D rendering
* context.
@ -6789,6 +6780,10 @@ class nsDisplayTransform : public nsDisplayHitTestInfoItem {
private:
void ComputeBounds(nsDisplayListBuilder* aBuilder);
nsRect TransformUntransformedBounds(nsDisplayListBuilder* aBuilder,
const Matrix4x4Flagged& aMatrix) const;
void UpdateUntransformedBounds(nsDisplayListBuilder* aBuilder);
void SetReferenceFrameToAncestor(nsDisplayListBuilder* aBuilder);
void Init(nsDisplayListBuilder* aBuilder, nsDisplayList* aChildren);
@ -6805,16 +6800,11 @@ class nsDisplayTransform : public nsDisplayHitTestInfoItem {
RefPtr<AnimatedGeometryRoot> mAnimatedGeometryRootForScrollMetadata;
nsRect mChildrenBuildingRect;
uint32_t mIndex;
// The transformed bounds of this display item.
mutable nsRect mBounds;
// True for mBounds is valid.
mutable bool mHasBounds;
mutable RetainedDisplayList mChildren;
// The untransformed bounds of |mChildren|.
mutable mozilla::Maybe<nsRect> mChildBounds;
nsRect mChildBounds;
// The transformed bounds of this display item.
nsRect mBounds;
// This item is a separator between 3D rendering contexts, and
// mTransform have been presetted by the constructor.
// This also forces us not to extend the 3D context. Since we don't create a