# HG changeset patch # Parent 388bdc46ba51ee31da8b8abe977e0ca38d117434 # User Thinker K.F. Li Bug 1226904 - Fix boundary checking for leaves collecting. r=roc diff --git a/layout/base/nsDisplayList.cpp b/layout/base/nsDisplayList.cpp --- a/layout/base/nsDisplayList.cpp +++ b/layout/base/nsDisplayList.cpp @@ -1885,21 +1885,19 @@ void FlushFramesArray(nsTArray *aOutFrames) const { nsDisplayItem* item; if (aState->mInPreserves3D) { // Collect leaves of the current 3D rendering context. for (item = GetBottom(); item; item = item->GetAbove()) { - MOZ_ASSERT(item->GetType() == nsDisplayTransform::TYPE_TRANSFORM || - item->GetType() == nsDisplayTransform::TYPE_PERSPECTIVE); - if (item->Frame()->Extend3DContext() && - (item->GetType() == nsDisplayTransform::TYPE_PERSPECTIVE || - !static_cast(item)->IsTransformSeparator())) { + auto itemType = item->GetType(); + if (itemType != nsDisplayItem::TYPE_TRANSFORM || + !static_cast(item)->IsLeafOf3DContext()) { item->HitTest(aBuilder, aRect, aState, aOutFrames); } else { // One of leaves in the current 3D rendering context. aState->mItemBuffer.AppendElement(item); } } return; } @@ -1913,43 +1911,43 @@ void nsDisplayList::HitTest(nsDisplayLis for (int32_t i = aState->mItemBuffer.Length() - 1; i >= itemBufferStart; --i) { // Pop element off the end of the buffer. We want to shorten the buffer // so that recursive calls to HitTest have more buffer space. item = aState->mItemBuffer[i]; aState->mItemBuffer.SetLength(i); bool snap; nsRect r = item->GetBounds(aBuilder, &snap).Intersect(aRect); + auto itemType = item->GetType(); bool alwaysIntersect = - item->GetType() == nsDisplayItem::TYPE_TRANSFORM && - (item->Frame()->Combines3DTransformWithAncestors() || - item->Frame()->Extend3DContext() || - static_cast(item)->IsTransformSeparator()); + (itemType == nsDisplayItem::TYPE_TRANSFORM && + static_cast(item)->IsParticipating3DContext()) || + (itemType == nsDisplayItem::TYPE_PERSPECTIVE && + static_cast(item)->Frame()->Extend3DContext()); + if (alwaysIntersect && + !static_cast(item)->IsLeafOf3DContext()) { + nsAutoTArray neverUsed; + // Start gethering leaves of the 3D rendering context, and + // append leaves at the end of mItemBuffer. Leaves are + // processed at following iterations. + aState->mInPreserves3D = true; + item->HitTest(aBuilder, aRect, aState, &neverUsed); + aState->mInPreserves3D = false; + i = aState->mItemBuffer.Length(); + continue; + } if (alwaysIntersect || item->GetClip().MayIntersect(r)) { nsAutoTArray outFrames; - if (item->Frame()->Extend3DContext() && - item->GetType() == nsDisplayItem::TYPE_TRANSFORM && - !static_cast(item)->IsTransformSeparator()) { - // Start gethering leaves of the 3D rendering context, and - // append leaves at the end of mItemBuffer. Leaves are - // processed at following iterations. - aState->mInPreserves3D = true; - item->HitTest(aBuilder, aRect, aState, &outFrames); - aState->mInPreserves3D = false; - i = aState->mItemBuffer.Length(); - continue; - } else { - item->HitTest(aBuilder, aRect, aState, &outFrames); - } + item->HitTest(aBuilder, aRect, aState, &outFrames); // For 3d transforms with preserve-3d we add hit frames into the temp list // so we can sort them later, otherwise we add them directly to the output list. nsTArray *writeFrames = aOutFrames; if (item->GetType() == nsDisplayItem::TYPE_TRANSFORM && - item->Frame()->Combines3DTransformWithAncestors()) { + static_cast(item)->IsLeafOf3DContext()) { if (outFrames.Length()) { nsDisplayTransform *transform = static_cast(item); nsPoint point = aRect.TopLeft(); // A 1x1 rect means a point, otherwise use the center of the rect if (aRect.width != 1 || aRect.height != 1) { point = aRect.Center(); } temp.AppendElement(FramesWithDepth(transform->GetHitDepthAtPoint(aBuilder, point))); @@ -5533,24 +5531,24 @@ nsDisplayTransform::GetTransformForRende // Don't include perspective transform, or the offset to origin, since // nsDisplayPerspective will handle both of those. return GetResultingTransformMatrix(mFrame, ToReferenceFrame(), scale, 0); } const Matrix4x4& nsDisplayTransform::GetAccumulatedPreserved3DTransform(nsDisplayListBuilder* aBuilder) { + MOZ_ASSERT(!mFrame->Extend3DContext() || IsLeafOf3DContext()); // XXX: should go back to fix mTransformGetter. if (!mTransformPreserves3DInited) { mTransformPreserves3DInited = true; - if (!mFrame->Combines3DTransformWithAncestors()) { + if (!IsLeafOf3DContext()) { mTransformPreserves3D = GetTransform(); return mTransformPreserves3D; } - MOZ_ASSERT(!mFrame->Extend3DContext() || IsTransformSeparator()); const nsIFrame* establisher; // Establisher of the 3D rendering context. for (establisher = nsLayoutUtils::GetCrossDocParentFrame(mFrame); establisher && establisher->Combines3DTransformWithAncestors(); establisher = nsLayoutUtils::GetCrossDocParentFrame(establisher)) { } establisher = nsLayoutUtils::GetCrossDocParentFrame(establisher); const nsIFrame* establisherReference = diff --git a/layout/base/nsDisplayList.h b/layout/base/nsDisplayList.h --- a/layout/base/nsDisplayList.h +++ b/layout/base/nsDisplayList.h @@ -4041,16 +4041,24 @@ public: * This item is the boundary between parent and child 3D rendering * context. */ bool IsLeafOf3DContext() { return (IsTransformSeparator() || (!mFrame->Extend3DContext() && mFrame->Combines3DTransformWithAncestors())); } + /** + * The backing frame of this item participates a 3D rendering + * context. + */ + bool IsParticipating3DContext() { + return mFrame->Extend3DContext() || + mFrame->Combines3DTransformWithAncestors(); + } private: void ComputeBounds(nsDisplayListBuilder* aBuilder); void SetReferenceFrameToAncestor(nsDisplayListBuilder* aBuilder); void Init(nsDisplayListBuilder* aBuilder); static Matrix4x4 GetResultingTransformMatrixInternal(const FrameTransformProperties& aProperties, const nsPoint& aOrigin, @@ -4155,16 +4163,21 @@ public: virtual nsDisplayList* GetChildren() override { return mList.GetChildren(); } virtual nsRect GetComponentAlphaBounds(nsDisplayListBuilder* aBuilder) override { return mList.GetComponentAlphaBounds(aBuilder); } nsIFrame* TransformFrame() { return mTransformFrame; } + virtual void + DoUpdateBoundsPreserves3D(nsDisplayListBuilder* aBuilder) override { + static_cast(mList.GetChildren()->GetTop())->DoUpdateBoundsPreserves3D(aBuilder); + } + private: nsDisplayWrapList mList; nsIFrame* mTransformFrame; uint32_t mIndex; }; /** * This class adds basic support for limiting the rendering (in the inline axis diff --git a/layout/base/tests/bug1226904.html b/layout/base/tests/bug1226904.html new file mode 100644 --- /dev/null +++ b/layout/base/tests/bug1226904.html @@ -0,0 +1,35 @@ + + + + + Test for Bug 684759 + + + +
+
+
+
+
+
+ + diff --git a/layout/base/tests/mochitest.ini b/layout/base/tests/mochitest.ini --- a/layout/base/tests/mochitest.ini +++ b/layout/base/tests/mochitest.ini @@ -261,8 +261,10 @@ support-files = bug1093686_inner.html [test_bug1120705.html] skip-if = buildapp == 'android' || buildapp == 'b2g' || buildapp == 'b2g-debug' || os == 'mac' || toolkit == 'gtk2' || toolkit == 'gtk3' # android and b2g do not have clickable scrollbars, mac does not have scrollbar down and up buttons, gtk may or may not have scrollbar buttons depending on theme [test_bug1153130.html] support-files = bug1153130_inner.html [test_bug1162990.html] support-files = bug1162990_inner_1.html bug1162990_inner_2.html +[test_bug1226904.html] +support-files = bug1226904.html diff --git a/layout/base/tests/test_bug1226904.html b/layout/base/tests/test_bug1226904.html new file mode 100644 --- /dev/null +++ b/layout/base/tests/test_bug1226904.html @@ -0,0 +1,44 @@ + + + + + Test for Bug 684759 + + + + +Mozilla Bug 1226904 + +
+
+
+ + diff --git a/layout/generic/nsFrame.cpp b/layout/generic/nsFrame.cpp --- a/layout/generic/nsFrame.cpp +++ b/layout/generic/nsFrame.cpp @@ -1917,16 +1917,19 @@ ItemParticipatesIn3DContext(nsIFrame* aA nsIFrame* transformFrame; if (aItem->GetType() == nsDisplayItem::TYPE_TRANSFORM) { transformFrame = aItem->Frame(); } else if (aItem->GetType() == nsDisplayItem::TYPE_PERSPECTIVE) { transformFrame = static_cast(aItem)->TransformFrame(); } else { return false; } + if (aAncestor == transformFrame) { + return true; + } return FrameParticipatesIn3DContext(aAncestor, transformFrame); } static void WrapSeparatorTransform(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame, nsRect& aDirtyRect, nsDisplayList* aSource, nsDisplayList* aTarget, int aIndex) {