mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-21 09:15:35 +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)) {
|
this)) {
|
||||||
dirtyRect = overflow;
|
dirtyRect = overflow;
|
||||||
} else {
|
} else {
|
||||||
if (overflow.IsEmpty()) {
|
if (overflow.IsEmpty() && !Extend3DContext()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -8118,30 +8118,49 @@ nsIFrame::FinishAndStoreOverflow(nsOverflowAreas& aOverflowAreas,
|
|||||||
bool hasTransform = IsTransformed();
|
bool hasTransform = IsTransformed();
|
||||||
nsSize oldSize = aOldSize ? *aOldSize : mRect.Size();
|
nsSize oldSize = aOldSize ? *aOldSize : mRect.Size();
|
||||||
bool sizeChanged = (oldSize != aNewSize);
|
bool sizeChanged = (oldSize != aNewSize);
|
||||||
|
|
||||||
|
if (ChildrenHavePerspective() && sizeChanged) {
|
||||||
|
nsRect newBounds(nsPoint(0, 0), aNewSize);
|
||||||
|
RecomputePerspectiveChildrenOverflow(this, &newBounds);
|
||||||
|
}
|
||||||
|
|
||||||
if (hasTransform) {
|
if (hasTransform) {
|
||||||
Properties().Set(nsIFrame::PreTransformOverflowAreasProperty(),
|
Properties().Set(nsIFrame::PreTransformOverflowAreasProperty(),
|
||||||
new nsOverflowAreas(aOverflowAreas));
|
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
|
if (Combines3DTransformWithAncestors()) {
|
||||||
* ensured us we'll use.
|
/* 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
|
||||||
nsRect newBounds(nsPoint(0, 0), aNewSize);
|
* of the preserve-3d root frame.
|
||||||
// Transform affects both overflow areas.
|
* If we're an intermediate frame then the pre-transform overflow should contain all our
|
||||||
NS_FOR_FRAME_OVERFLOW_TYPES(otype) {
|
* non-preserve-3d children, which is what we want. Again we have no post-transform overflow.
|
||||||
nsRect& o = aOverflowAreas.Overflow(otype);
|
*/
|
||||||
o = nsDisplayTransform::TransformRect(o, this, &newBounds);
|
aOverflowAreas.SetAllTo(nsRect());
|
||||||
}
|
} else {
|
||||||
if (Extend3DContext()) {
|
/* Since our size might not actually have been computed yet, we need to make sure that we use the
|
||||||
ComputePreserve3DChildrenOverflow(aOverflowAreas, newBounds);
|
* correct dimensions by overriding the stored bounding rectangle with the value the caller has
|
||||||
} else if (sizeChanged && ChildrenHavePerspective()) {
|
* ensured us we'll use.
|
||||||
RecomputePerspectiveChildrenOverflow(this, &newBounds);
|
*/
|
||||||
|
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 {
|
} else {
|
||||||
Properties().Delete(nsIFrame::PreTransformOverflowAreasProperty());
|
Properties().Delete(nsIFrame::PreTransformOverflowAreasProperty());
|
||||||
if (ChildrenHavePerspective() && sizeChanged) {
|
|
||||||
nsRect newBounds(nsPoint(0, 0), aNewSize);
|
|
||||||
RecomputePerspectiveChildrenOverflow(this, &newBounds);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool anyOverflowChanged;
|
bool anyOverflowChanged;
|
||||||
@ -8199,79 +8218,13 @@ nsIFrame::RecomputePerspectiveChildrenOverflow(const nsIFrame* aStartFrame, cons
|
|||||||
SetSize(oldSize);
|
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
|
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.
|
// Find all descendants that participate in the 3d context, and include their overflow.
|
||||||
// If the child also preserves 3d then their overflow will already been in our
|
// These descendants have an empty overflow, so won't have been included in the normal
|
||||||
// coordinate space, otherwise we need to transform.
|
// overflow calculation. Any children that don't participate have normal overflow,
|
||||||
|
// so will have been included already.
|
||||||
// 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);
|
|
||||||
}
|
|
||||||
|
|
||||||
nsRect childVisual;
|
nsRect childVisual;
|
||||||
nsRect childScrollable;
|
nsRect childScrollable;
|
||||||
@ -8280,27 +8233,28 @@ nsIFrame::ComputePreserve3DChildrenOverflow(nsOverflowAreas& aOverflowAreas, con
|
|||||||
nsFrameList::Enumerator childFrames(lists.CurrentList());
|
nsFrameList::Enumerator childFrames(lists.CurrentList());
|
||||||
for (; !childFrames.AtEnd(); childFrames.Next()) {
|
for (; !childFrames.AtEnd(); childFrames.Next()) {
|
||||||
nsIFrame* child = childFrames.get();
|
nsIFrame* child = childFrames.get();
|
||||||
nsPoint offset = child->GetPosition();
|
|
||||||
nsRect visual = child->GetVisualOverflowRect();
|
// If this child participates in the 3d context, then take the pre-transform
|
||||||
nsRect scrollable = child->GetScrollableOverflowRect();
|
// region (which contains all descendants that aren't participating in the 3d context)
|
||||||
visual.MoveBy(offset);
|
// and transform it into the 3d context root coordinate space.
|
||||||
scrollable.MoveBy(offset);
|
|
||||||
if (child->Combines3DTransformWithAncestors()) {
|
if (child->Combines3DTransformWithAncestors()) {
|
||||||
childVisual = childVisual.Union(visual);
|
nsOverflowAreas childOverflow = child->GetOverflowAreasRelativeToSelf();
|
||||||
childScrollable = childScrollable.Union(scrollable);
|
|
||||||
} else {
|
NS_FOR_FRAME_OVERFLOW_TYPES(otype) {
|
||||||
childVisual =
|
nsRect& o = childOverflow.Overflow(otype);
|
||||||
childVisual.Union(nsDisplayTransform::TransformRect(visual,
|
o = nsDisplayTransform::TransformRect(o, child);
|
||||||
this, &aBounds));
|
}
|
||||||
childScrollable =
|
|
||||||
childScrollable.Union(nsDisplayTransform::TransformRect(scrollable,
|
aOverflowAreas.UnionWith(childOverflow);
|
||||||
this, &aBounds));
|
|
||||||
|
// 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
|
uint32_t
|
||||||
|
@ -1431,8 +1431,11 @@ public:
|
|||||||
|
|
||||||
bool ChildrenHavePerspective() const;
|
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);
|
void RecomputePerspectiveChildrenOverflow(const nsIFrame* aStartFrame, const nsRect* aBounds);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user