Bug 1202029 - Use the containing block for determining perspective for transformed elements. r=dbaron

This commit is contained in:
Matt Woodrow 2015-09-14 14:17:40 -04:00
parent 4f06c92098
commit a00e502e96
5 changed files with 57 additions and 50 deletions

View File

@ -4811,19 +4811,12 @@ nsDisplayTransform::GetDeltaToPerspectiveOrigin(const nsIFrame* aFrame,
//TODO: Should this be using our bounds or the parent's bounds?
// How do we handle aBoundsOverride in the latter case?
nsIFrame* parent;
nsStyleContext* psc = aFrame->GetParentStyleContext(&parent);
if (!psc) {
nsIFrame* cbFrame = aFrame->GetContainingBlock(nsIFrame::SKIP_SCROLLED_FRAME);
if (!cbFrame) {
return Point3D();
}
if (!parent) {
parent = aFrame->GetParent();
if (!parent) {
return Point3D();
}
}
const nsStyleDisplay* display = psc->StyleDisplay();
TransformReferenceBox refBox(parent);
const nsStyleDisplay* display = cbFrame->StyleDisplay();
TransformReferenceBox refBox(cbFrame);
/* Allows us to access named variables by index. */
Point3D result;
@ -4854,7 +4847,7 @@ nsDisplayTransform::GetDeltaToPerspectiveOrigin(const nsIFrame* aFrame,
}
}
nsPoint parentOffset = aFrame->GetOffsetTo(parent);
nsPoint parentOffset = aFrame->GetOffsetTo(cbFrame);
Point3D gfxOffset(
NSAppUnitsToFloatPixels(parentOffset.x, aAppUnitsPerPixel),
NSAppUnitsToFloatPixels(parentOffset.y, aAppUnitsPerPixel),
@ -4871,17 +4864,16 @@ nsDisplayTransform::FrameTransformProperties::FrameTransformProperties(const nsI
, mToTransformOrigin(GetDeltaToTransformOrigin(aFrame, aAppUnitsPerPixel, aBoundsOverride))
, mChildPerspective(0)
{
const nsStyleDisplay* parentDisp = nullptr;
nsStyleContext* parentStyleContext = aFrame->StyleContext()->GetParent();
if (parentStyleContext) {
parentDisp = parentStyleContext->StyleDisplay();
}
if (parentDisp && parentDisp->mChildPerspective.GetUnit() == eStyleUnit_Coord) {
mChildPerspective = parentDisp->mChildPerspective.GetCoordValue();
// Calling GetDeltaToPerspectiveOrigin can be expensive, so we avoid
// calling it unnecessarily.
if (mChildPerspective > 0.0) {
mToPerspectiveOrigin = GetDeltaToPerspectiveOrigin(aFrame, aAppUnitsPerPixel);
nsIFrame* cbFrame = aFrame->GetContainingBlock(nsIFrame::SKIP_SCROLLED_FRAME);
if (cbFrame) {
const nsStyleDisplay* display = cbFrame->StyleDisplay();
if (display->mChildPerspective.GetUnit() == eStyleUnit_Coord) {
mChildPerspective = display->mChildPerspective.GetCoordValue();
// Calling GetDeltaToPerspectiveOrigin can be expensive, so we avoid
// calling it unnecessarily.
if (mChildPerspective > 0.0) {
mToPerspectiveOrigin = GetDeltaToPerspectiveOrigin(aFrame, aAppUnitsPerPixel);
}
}
}
}

View File

@ -4190,19 +4190,15 @@ GetPercentBSize(const nsStyleCoord& aStyle,
MOZ_ASSERT(!aStyle.IsCalcUnit() || aStyle.CalcHasPercent(),
"GetAbsoluteCoord should have handled this");
nsIFrame *f = aFrame->GetContainingBlock();
if (!f) {
NS_NOTREACHED("top of frame tree not a containing block");
return false;
}
// During reflow, nsHTMLScrollFrame::ReflowScrolledFrame uses
// SetComputedHeight on the reflow state for its child to propagate its
// computed height to the scrolled content. So here we skip to the scroll
// frame that contains this scrolled content in order to get the same
// behavior as layout when computing percentage heights.
if (f->StyleContext()->GetPseudo() == nsCSSAnonBoxes::scrolledContent) {
f = f->GetParent();
nsIFrame *f = aFrame->GetContainingBlock(nsIFrame::SKIP_SCROLLED_FRAME);
if (!f) {
NS_NOTREACHED("top of frame tree not a containing block");
return false;
}
WritingMode wm = f->GetWritingMode();

View File

@ -1143,12 +1143,11 @@ nsIFrame::HasPerspective() const
if (!IsTransformed()) {
return false;
}
nsStyleContext* parentStyleContext = StyleContext()->GetParent();
if (!parentStyleContext) {
nsIFrame* containingBlock = GetContainingBlock(SKIP_SCROLLED_FRAME);
if (!containingBlock) {
return false;
}
const nsStyleDisplay* parentDisp = parentStyleContext->StyleDisplay();
return parentDisp->mChildPerspective.GetUnit() == eStyleUnit_Coord;
return containingBlock->ChildrenHavePerspective();
}
bool
@ -5705,16 +5704,27 @@ GetNearestBlockContainer(nsIFrame* frame)
}
nsIFrame*
nsIFrame::GetContainingBlock() const
nsIFrame::GetContainingBlock(uint32_t aFlags) const
{
if (!GetParent()) {
return nullptr;
}
// MathML frames might have absolute positioning style, but they would
// still be in-flow. So we have to check to make sure that the frame
// is really out-of-flow too.
nsIFrame* f;
if (IsAbsolutelyPositioned() &&
(GetStateBits() & NS_FRAME_OUT_OF_FLOW)) {
return GetParent(); // the parent is always the containing block
f = GetParent(); // the parent is always the containing block
} else {
f = GetNearestBlockContainer(GetParent());
}
return GetNearestBlockContainer(GetParent());
if (aFlags & SKIP_SCROLLED_FRAME && f &&
f->StyleContext()->GetPseudo() == nsCSSAnonBoxes::scrolledContent) {
f = f->GetParent();
}
return f;
}
#ifdef DEBUG_FRAME_DUMP
@ -7632,7 +7642,7 @@ nsIFrame::FinishAndStoreOverflow(nsOverflowAreas& aOverflowAreas,
nsRect bounds(nsPoint(0, 0), aNewSize);
// Store the passed in overflow area if we are a preserve-3d frame or we have
// a transform, and it's not just the frame bounds.
if (Preserves3D() || HasPerspective() || IsTransformed()) {
if (Preserves3D() || IsTransformed()) {
if (!aOverflowAreas.VisualOverflow().IsEqualEdges(bounds) ||
!aOverflowAreas.ScrollableOverflow().IsEqualEdges(bounds)) {
nsOverflowAreas* initial =
@ -7748,13 +7758,13 @@ nsIFrame::FinishAndStoreOverflow(nsOverflowAreas& aOverflowAreas,
if (Preserves3DChildren()) {
ComputePreserve3DChildrenOverflow(aOverflowAreas, newBounds);
} else if (sizeChanged && ChildrenHavePerspective()) {
RecomputePerspectiveChildrenOverflow(this->StyleContext(), &newBounds);
RecomputePerspectiveChildrenOverflow(this, &newBounds);
}
} else {
Properties().Delete(nsIFrame::PreTransformOverflowAreasProperty());
if (ChildrenHavePerspective() && sizeChanged) {
nsRect newBounds(nsPoint(0, 0), aNewSize);
RecomputePerspectiveChildrenOverflow(this->StyleContext(), &newBounds);
RecomputePerspectiveChildrenOverflow(this, &newBounds);
}
}
@ -7772,7 +7782,7 @@ nsIFrame::FinishAndStoreOverflow(nsOverflowAreas& aOverflowAreas,
}
void
nsIFrame::RecomputePerspectiveChildrenOverflow(const nsStyleContext* aStartStyle, const nsRect* aBounds)
nsIFrame::RecomputePerspectiveChildrenOverflow(const nsIFrame* aStartFrame, const nsRect* aBounds)
{
// Children may check our size when getting our transform, make sure it's valid.
nsSize oldSize = GetSize();
@ -7799,14 +7809,13 @@ nsIFrame::RecomputePerspectiveChildrenOverflow(const nsStyleContext* aStartStyle
boundsOverflow.SetAllTo(bounds);
child->FinishAndStoreOverflow(boundsOverflow, bounds.Size());
}
} else if (child->StyleContext()->GetParent() == aStartStyle ||
child->StyleContext() == aStartStyle) {
} else if (child->GetContainingBlock(SKIP_SCROLLED_FRAME) == aStartFrame) {
// If a frame is using perspective, then the size used to compute
// perspective-origin is the size of the frame belonging to its parent
// style context. We must find any descendant frames using our size
// (by recurse into frames with the same style context, or a direct
// child style context) to update their overflow rects too.
child->RecomputePerspectiveChildrenOverflow(aStartStyle, nullptr);
// (by recursing into frames that have the same containing block)
// to update their overflow rects too.
child->RecomputePerspectiveChildrenOverflow(aStartFrame, nullptr);
}
}
}

View File

@ -2471,7 +2471,7 @@ ScrollFrameHelper::ScrollToImpl(nsPoint aPt, const nsRect& aRange, nsIAtom* aOri
if (mOuter->ChildrenHavePerspective()) {
// The overflow areas of descendants may depend on the scroll position,
// so ensure they get updated.
mOuter->RecomputePerspectiveChildrenOverflow(mOuter->StyleContext(), nullptr);
mOuter->RecomputePerspectiveChildrenOverflow(mOuter, nullptr);
}
ScheduleSyntheticMouseMove();

View File

@ -1267,7 +1267,7 @@ public:
// Calculate the overflow size of all child frames, taking preserve-3d into account
void ComputePreserve3DChildrenOverflow(nsOverflowAreas& aOverflowAreas, const nsRect& aBounds);
void RecomputePerspectiveChildrenOverflow(const nsStyleContext* aStartStyle, const nsRect* aBounds);
void RecomputePerspectiveChildrenOverflow(const nsIFrame* aStartFrame, const nsRect* aBounds);
/**
* Returns the number of ancestors between this and the root of our frame tree
@ -2116,8 +2116,18 @@ public:
*
* NOTE: This is guaranteed to return a non-null pointer when invoked on any
* frame other than the root frame.
*
* Requires SKIP_SCROLLED_FRAME to get behaviour matching the spec, otherwise
* it can return anonymous inner scrolled frames. Bug 1204044 is filed for
* investigating whether any of the callers actually require the default
* behaviour.
*/
nsIFrame* GetContainingBlock() const;
enum {
// If the containing block is an anonymous scrolled frame, then skip over
// this and return the outer scroll frame.
SKIP_SCROLLED_FRAME = 0x01
};
nsIFrame* GetContainingBlock(uint32_t aFlags = 0) const;
/**
* Is this frame a containing block for floating elements?