mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-24 21:31:04 +00:00
Bug 722603 - Improve dirty rect calculation with 3d transforms and preserve-3d. r=roc
This commit is contained in:
parent
8d9f67b892
commit
15509fccd0
@ -394,6 +394,29 @@ nsDisplayListBuilder::MarkFramesForDisplayList(nsIFrame* aDirtyFrame,
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsDisplayListBuilder::MarkPreserve3DFramesForDisplayList(nsIFrame* aDirtyFrame, const nsRect& aDirtyRect)
|
||||
{
|
||||
nsAutoTArray<nsIFrame::ChildList,4> childListArray;
|
||||
aDirtyFrame->GetChildLists(&childListArray);
|
||||
nsIFrame::ChildListArrayIterator lists(childListArray);
|
||||
for (; !lists.IsDone(); lists.Next()) {
|
||||
nsFrameList::Enumerator childFrames(lists.CurrentList());
|
||||
for (; !childFrames.AtEnd(); childFrames.Next()) {
|
||||
nsIFrame *child = childFrames.get();
|
||||
if (child->Preserves3D()) {
|
||||
mFramesMarkedForDisplay.AppendElement(child);
|
||||
nsRect dirty = aDirtyRect - child->GetOffsetTo(aDirtyFrame);
|
||||
|
||||
child->Properties().Set(nsDisplayListBuilder::Preserve3DDirtyRectProperty(),
|
||||
new nsRect(dirty));
|
||||
|
||||
MarkFrameForDisplay(child, aDirtyFrame);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void*
|
||||
nsDisplayListBuilder::Allocate(size_t aSize) {
|
||||
void *tmp;
|
||||
|
@ -354,6 +354,12 @@ public:
|
||||
void MarkFramesForDisplayList(nsIFrame* aDirtyFrame,
|
||||
const nsFrameList& aFrames,
|
||||
const nsRect& aDirtyRect);
|
||||
/**
|
||||
* Mark all child frames that Preserve3D() as needing display.
|
||||
* Because these frames include transforms set on their parent, dirty rects
|
||||
* for intermediate frames may be empty, yet child frames could still be visible.
|
||||
*/
|
||||
void MarkPreserve3DFramesForDisplayList(nsIFrame* aDirtyFrame, const nsRect& aDirtyRect);
|
||||
|
||||
/**
|
||||
* Return the FrameLayerBuilder.
|
||||
@ -481,6 +487,7 @@ public:
|
||||
void SetCurrentTableItem(nsDisplayTableItem* aTableItem) { mCurrentTableItem = aTableItem; }
|
||||
|
||||
NS_DECLARE_FRAME_PROPERTY(OutOfFlowDirtyRectProperty, nsIFrame::DestroyRect)
|
||||
NS_DECLARE_FRAME_PROPERTY(Preserve3DDirtyRectProperty, nsIFrame::DestroyRect)
|
||||
|
||||
nsPresContext* CurrentPresContext() {
|
||||
return CurrentPresShellState()->mPresShell->GetPresContext();
|
||||
|
@ -1772,23 +1772,40 @@ nsIFrame::BuildDisplayListForStackingContext(nsDisplayListBuilder* aBuilder,
|
||||
bool inTransform = aBuilder->IsInTransform();
|
||||
if ((mState & NS_FRAME_MAY_BE_TRANSFORMED) &&
|
||||
disp->HasTransform()) {
|
||||
if (nsDisplayTransform::ShouldPrerenderTransformedContent(aBuilder, this) ||
|
||||
Preserves3DChildren()) {
|
||||
if (aBuilder->IsForPainting() &&
|
||||
nsDisplayTransform::ShouldPrerenderTransformedContent(aBuilder, this)) {
|
||||
dirtyRect = GetVisualOverflowRectRelativeToSelf();
|
||||
} else {
|
||||
// Transform dirtyRect into our frame's local coordinate space. Note that
|
||||
// the new value is the bounds of the old value's transformed vertices, so
|
||||
// the area covered by dirtyRect may increase here.
|
||||
//
|
||||
// Although we don't bother to check for and maintain the 1x1 size of the
|
||||
// magic rect indicating a hit test point, in reality this is extremely
|
||||
// unlikely to matter. The rect starts off with dimensions of 1x1 *app*
|
||||
// units, and it would require a very large number of elements with
|
||||
// transforms along a parent chain to noticably expand this by an entire
|
||||
// device pixel.
|
||||
if (!nsDisplayTransform::UntransformRect(dirtyRect, this, nsPoint(0, 0), &dirtyRect)) {
|
||||
// we have a singular transform - just grab the entire overflow rect
|
||||
dirtyRect = GetVisualOverflowRectRelativeToSelf();
|
||||
if (Preserves3D()) {
|
||||
// Preserve3D frames are difficult. Trying to back-transform arbitrary rects
|
||||
// gives us really weird results. I believe this is from points that lie beyond the
|
||||
// vanishing point. As a workaround we transform the overflow rect into screen space
|
||||
// and compare in that coordinate system.
|
||||
|
||||
// Transform the overflow rect into screen space
|
||||
nsRect overflow = GetVisualOverflowRectRelativeToSelf();
|
||||
nsPoint offset = aBuilder->ToReferenceFrame(this);
|
||||
overflow += offset;
|
||||
overflow = nsDisplayTransform::TransformRect(overflow, this, offset);
|
||||
|
||||
dirtyRect += offset;
|
||||
|
||||
if (dirtyRect.Intersects(overflow)) {
|
||||
dirtyRect = GetVisualOverflowRectRelativeToSelf();
|
||||
} else {
|
||||
dirtyRect.SetEmpty();
|
||||
}
|
||||
} else {
|
||||
// Transform dirtyRect into our frame's local coordinate space. Note that
|
||||
// the new value is the bounds of the old value's transformed vertices, so
|
||||
// the area covered by dirtyRect may increase here.
|
||||
if (!nsDisplayTransform::UntransformRect(dirtyRect, this, nsPoint(0, 0), &dirtyRect)) {
|
||||
// we have a singular transform - surely we must be drawing nothing.
|
||||
dirtyRect.SetEmpty();
|
||||
}
|
||||
}
|
||||
if (!Preserves3DChildren() && !dirtyRect.Intersects(GetVisualOverflowRectRelativeToSelf())) {
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
inTransform = true;
|
||||
@ -1807,6 +1824,11 @@ nsIFrame::BuildDisplayListForStackingContext(nsDisplayListBuilder* aBuilder,
|
||||
|
||||
// Mark the display list items for absolutely positioned children
|
||||
MarkAbsoluteFramesForDisplayList(aBuilder, dirtyRect);
|
||||
// Preserve3DChildren() also guarantees that applyAbsPosClipping and usingSVGEffects are false
|
||||
// We only modify the preserve-3d rect if we are the top of a preserve-3d heirarchy
|
||||
if (Preserves3DChildren()) {
|
||||
aBuilder->MarkPreserve3DFramesForDisplayList(this, aDirtyRect);
|
||||
}
|
||||
|
||||
nsDisplayListCollection set;
|
||||
nsresult rv;
|
||||
@ -2007,6 +2029,15 @@ nsIFrame::BuildDisplayListForChild(nsDisplayListBuilder* aBuilder,
|
||||
}
|
||||
pseudoStackingContext = true;
|
||||
}
|
||||
if (child->Preserves3D()) {
|
||||
nsRect* savedDirty = static_cast<nsRect*>
|
||||
(child->Properties().Get(nsDisplayListBuilder::Preserve3DDirtyRectProperty()));
|
||||
if (savedDirty) {
|
||||
dirty = *savedDirty;
|
||||
} else {
|
||||
dirty.SetEmpty();
|
||||
}
|
||||
}
|
||||
|
||||
// Mark the display list items for absolutely positioned children
|
||||
child->MarkAbsoluteFramesForDisplayList(aBuilder, dirty);
|
||||
|
Loading…
Reference in New Issue
Block a user