mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-21 01:05:45 +00:00
Bug 1274962 - Part 6: Make preserve-3d frames only contribute to the overflow area of the preserve-3d root frame. r=dbaron
This commit is contained in:
parent
421203143a
commit
7fb4a7ee36
@ -2249,7 +2249,7 @@ nsIFrame::BuildDisplayListForStackingContext(nsDisplayListBuilder* aBuilder,
|
||||
this)) {
|
||||
dirtyRect = overflow;
|
||||
} else {
|
||||
if (overflow.IsEmpty()) {
|
||||
if (overflow.IsEmpty() && !Extend3DContext()) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -8118,30 +8118,49 @@ nsIFrame::FinishAndStoreOverflow(nsOverflowAreas& aOverflowAreas,
|
||||
bool hasTransform = IsTransformed();
|
||||
nsSize oldSize = aOldSize ? *aOldSize : mRect.Size();
|
||||
bool sizeChanged = (oldSize != aNewSize);
|
||||
|
||||
if (ChildrenHavePerspective() && sizeChanged) {
|
||||
nsRect newBounds(nsPoint(0, 0), aNewSize);
|
||||
RecomputePerspectiveChildrenOverflow(this, &newBounds);
|
||||
}
|
||||
|
||||
if (hasTransform) {
|
||||
Properties().Set(nsIFrame::PreTransformOverflowAreasProperty(),
|
||||
new nsOverflowAreas(aOverflowAreas));
|
||||
/* Since our size might not actually have been computed yet, we need to make sure that we use the
|
||||
* correct dimensions by overriding the stored bounding rectangle with the value the caller has
|
||||
* ensured us we'll use.
|
||||
*/
|
||||
nsRect newBounds(nsPoint(0, 0), aNewSize);
|
||||
// Transform affects both overflow areas.
|
||||
NS_FOR_FRAME_OVERFLOW_TYPES(otype) {
|
||||
nsRect& o = aOverflowAreas.Overflow(otype);
|
||||
o = nsDisplayTransform::TransformRect(o, this, &newBounds);
|
||||
}
|
||||
if (Extend3DContext()) {
|
||||
ComputePreserve3DChildrenOverflow(aOverflowAreas, newBounds);
|
||||
} else if (sizeChanged && ChildrenHavePerspective()) {
|
||||
RecomputePerspectiveChildrenOverflow(this, &newBounds);
|
||||
|
||||
if (Combines3DTransformWithAncestors()) {
|
||||
/* If we're a preserve-3d leaf frame, then our pre-transform overflow should be correct. Our
|
||||
* post-transform overflow is empty though, because we only contribute to the overflow area
|
||||
* of the preserve-3d root frame.
|
||||
* If we're an intermediate frame then the pre-transform overflow should contain all our
|
||||
* non-preserve-3d children, which is what we want. Again we have no post-transform overflow.
|
||||
*/
|
||||
aOverflowAreas.SetAllTo(nsRect());
|
||||
} else {
|
||||
/* Since our size might not actually have been computed yet, we need to make sure that we use the
|
||||
* correct dimensions by overriding the stored bounding rectangle with the value the caller has
|
||||
* ensured us we'll use.
|
||||
*/
|
||||
SetSize(aNewSize);
|
||||
|
||||
NS_FOR_FRAME_OVERFLOW_TYPES(otype) {
|
||||
nsRect& o = aOverflowAreas.Overflow(otype);
|
||||
o = nsDisplayTransform::TransformRect(o, this);
|
||||
}
|
||||
|
||||
/* If we're the root of the 3d context, then we want to include the overflow areas of all
|
||||
* the participants. This won't have happened yet as the code above set their overflow
|
||||
* area to empty. Manually collect these overflow areas now.
|
||||
*/
|
||||
if (Extend3DContext()) {
|
||||
ComputePreserve3DChildrenOverflow(aOverflowAreas);
|
||||
}
|
||||
|
||||
/* Revert the size change in case some caller is depending on this. */
|
||||
SetSize(oldSize);
|
||||
}
|
||||
} else {
|
||||
Properties().Delete(nsIFrame::PreTransformOverflowAreasProperty());
|
||||
if (ChildrenHavePerspective() && sizeChanged) {
|
||||
nsRect newBounds(nsPoint(0, 0), aNewSize);
|
||||
RecomputePerspectiveChildrenOverflow(this, &newBounds);
|
||||
}
|
||||
}
|
||||
|
||||
bool anyOverflowChanged;
|
||||
@ -8199,79 +8218,13 @@ nsIFrame::RecomputePerspectiveChildrenOverflow(const nsIFrame* aStartFrame, cons
|
||||
SetSize(oldSize);
|
||||
}
|
||||
|
||||
/* The overflow rects for leaf nodes in a preserve-3d hierarchy depends on
|
||||
* the mRect value for their parents (since we use their transform, and transform
|
||||
* depends on this for transform-origin etc). These weren't necessarily correct
|
||||
* when we reflowed initially, so walk over all preserve-3d children and repeat the
|
||||
* overflow calculation.
|
||||
*/
|
||||
static void
|
||||
RecomputePreserve3DChildrenOverflow(nsIFrame* aFrame, const nsRect* aBounds)
|
||||
{
|
||||
// Children may check our size when getting our transform, make sure it's valid.
|
||||
nsSize oldSize = aFrame->GetSize();
|
||||
if (aBounds) {
|
||||
aFrame->SetSize(aBounds->Size());
|
||||
}
|
||||
nsIFrame::ChildListIterator lists(aFrame);
|
||||
for (; !lists.IsDone(); lists.Next()) {
|
||||
nsFrameList::Enumerator childFrames(lists.CurrentList());
|
||||
for (; !childFrames.AtEnd(); childFrames.Next()) {
|
||||
nsIFrame* child = childFrames.get();
|
||||
if (!child->FrameMaintainsOverflow()) {
|
||||
continue; // frame does not maintain overflow rects
|
||||
}
|
||||
if (child->Extend3DContext()) {
|
||||
RecomputePreserve3DChildrenOverflow(child, nullptr);
|
||||
} else if (child->Combines3DTransformWithAncestors()) {
|
||||
nsOverflowAreas* overflow =
|
||||
static_cast<nsOverflowAreas*>(child->Properties().Get(nsIFrame::InitialOverflowProperty()));
|
||||
nsRect bounds(nsPoint(0, 0), child->GetSize());
|
||||
if (overflow) {
|
||||
nsOverflowAreas overflowCopy = *overflow;
|
||||
child->FinishAndStoreOverflow(overflowCopy, bounds.Size());
|
||||
} else {
|
||||
nsOverflowAreas boundsOverflow;
|
||||
boundsOverflow.SetAllTo(bounds);
|
||||
child->FinishAndStoreOverflow(boundsOverflow, bounds.Size());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Restore our old size just in case something depends on this elesewhere.
|
||||
aFrame->SetSize(oldSize);
|
||||
|
||||
// Only repeat computing our overflow in recursive calls since the initial caller is still
|
||||
// in the middle of doing this and we don't want an infinite loop.
|
||||
if (!aBounds) {
|
||||
nsOverflowAreas* overflow =
|
||||
static_cast<nsOverflowAreas*>(aFrame->Properties().Get(nsIFrame::InitialOverflowProperty()));
|
||||
nsRect bounds(nsPoint(0, 0), aFrame->GetSize());
|
||||
if (overflow) {
|
||||
nsOverflowAreas overflowCopy = *overflow;
|
||||
overflowCopy.UnionAllWith(bounds);
|
||||
aFrame->FinishAndStoreOverflow(overflowCopy, bounds.Size());
|
||||
} else {
|
||||
nsOverflowAreas boundsOverflow;
|
||||
boundsOverflow.SetAllTo(bounds);
|
||||
aFrame->FinishAndStoreOverflow(boundsOverflow, bounds.Size());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsIFrame::ComputePreserve3DChildrenOverflow(nsOverflowAreas& aOverflowAreas, const nsRect& aBounds)
|
||||
nsIFrame::ComputePreserve3DChildrenOverflow(nsOverflowAreas& aOverflowAreas)
|
||||
{
|
||||
// When we are preserving 3d we need to iterate over all children separately.
|
||||
// If the child also preserves 3d then their overflow will already been in our
|
||||
// coordinate space, otherwise we need to transform.
|
||||
|
||||
// If we're the top frame in a preserve 3d chain then we need to recalculate the overflow
|
||||
// areas of all our children since they will have used our size/offset which was invalid at
|
||||
// the time.
|
||||
if (!Combines3DTransformWithAncestors()) {
|
||||
RecomputePreserve3DChildrenOverflow(this, &aBounds);
|
||||
}
|
||||
// Find all descendants that participate in the 3d context, and include their overflow.
|
||||
// These descendants have an empty overflow, so won't have been included in the normal
|
||||
// overflow calculation. Any children that don't participate have normal overflow,
|
||||
// so will have been included already.
|
||||
|
||||
nsRect childVisual;
|
||||
nsRect childScrollable;
|
||||
@ -8280,27 +8233,28 @@ nsIFrame::ComputePreserve3DChildrenOverflow(nsOverflowAreas& aOverflowAreas, con
|
||||
nsFrameList::Enumerator childFrames(lists.CurrentList());
|
||||
for (; !childFrames.AtEnd(); childFrames.Next()) {
|
||||
nsIFrame* child = childFrames.get();
|
||||
nsPoint offset = child->GetPosition();
|
||||
nsRect visual = child->GetVisualOverflowRect();
|
||||
nsRect scrollable = child->GetScrollableOverflowRect();
|
||||
visual.MoveBy(offset);
|
||||
scrollable.MoveBy(offset);
|
||||
|
||||
// If this child participates in the 3d context, then take the pre-transform
|
||||
// region (which contains all descendants that aren't participating in the 3d context)
|
||||
// and transform it into the 3d context root coordinate space.
|
||||
if (child->Combines3DTransformWithAncestors()) {
|
||||
childVisual = childVisual.Union(visual);
|
||||
childScrollable = childScrollable.Union(scrollable);
|
||||
} else {
|
||||
childVisual =
|
||||
childVisual.Union(nsDisplayTransform::TransformRect(visual,
|
||||
this, &aBounds));
|
||||
childScrollable =
|
||||
childScrollable.Union(nsDisplayTransform::TransformRect(scrollable,
|
||||
this, &aBounds));
|
||||
nsOverflowAreas childOverflow = child->GetOverflowAreasRelativeToSelf();
|
||||
|
||||
NS_FOR_FRAME_OVERFLOW_TYPES(otype) {
|
||||
nsRect& o = childOverflow.Overflow(otype);
|
||||
o = nsDisplayTransform::TransformRect(o, child);
|
||||
}
|
||||
|
||||
aOverflowAreas.UnionWith(childOverflow);
|
||||
|
||||
// If this child also extends the 3d context, then recurse into it
|
||||
// looking for more participants.
|
||||
if (child->Extend3DContext()) {
|
||||
child->ComputePreserve3DChildrenOverflow(aOverflowAreas);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
aOverflowAreas.Overflow(eVisualOverflow) = aOverflowAreas.Overflow(eVisualOverflow).Union(childVisual);
|
||||
aOverflowAreas.Overflow(eScrollableOverflow) = aOverflowAreas.Overflow(eScrollableOverflow).Union(childScrollable);
|
||||
}
|
||||
|
||||
uint32_t
|
||||
|
@ -1431,8 +1431,11 @@ public:
|
||||
|
||||
bool ChildrenHavePerspective() const;
|
||||
|
||||
// Calculate the overflow size of all child frames, taking preserve-3d into account
|
||||
void ComputePreserve3DChildrenOverflow(nsOverflowAreas& aOverflowAreas, const nsRect& aBounds);
|
||||
/**
|
||||
* Includes the overflow area of all descendants that participate in the current
|
||||
* 3d context into aOverflowAreas.
|
||||
*/
|
||||
void ComputePreserve3DChildrenOverflow(nsOverflowAreas& aOverflowAreas);
|
||||
|
||||
void RecomputePerspectiveChildrenOverflow(const nsIFrame* aStartFrame, const nsRect* aBounds);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user