Bug 846901 - Support prerendering elements with animated transforms that are offscreen but only by a small amount. r=mattwoodrow

This commit is contained in:
Robert O'Callahan 2013-03-19 09:08:29 -04:00
parent f935d48612
commit c35d68c457
4 changed files with 45 additions and 8 deletions

View File

@ -2136,7 +2136,8 @@ ContainerState::ProcessDisplayItems(const nsDisplayList& aList,
// Note that items without their own layers can't be skipped this
// way, since their ThebesLayer may decide it wants to draw them
// into its buffer even if they're currently covered.
if (itemVisibleRect.IsEmpty() && layerState != LAYER_ACTIVE_EMPTY) {
if (itemVisibleRect.IsEmpty() &&
!item->ShouldBuildLayerEvenIfInvisible(mBuilder)) {
continue;
}
@ -2192,7 +2193,9 @@ ContainerState::ProcessDisplayItems(const nsDisplayList& aList,
data->mDrawAboveRegion.SimplifyOutward(4);
}
itemVisibleRect.MoveBy(mParameters.mOffset);
RestrictVisibleRegionForLayer(ownLayer, itemVisibleRect);
if (!nsDisplayTransform::IsLayerPrerendered(ownLayer)) {
RestrictVisibleRegionForLayer(ownLayer, itemVisibleRect);
}
// rounded rectangle clipping using mask layers
// (must be done after visible rect is set on layer)

View File

@ -570,12 +570,24 @@ void nsDisplayListBuilder::MarkOutOfFlowFrameForDisplay(nsIFrame* aDirtyFrame,
nsRect dirty = aDirtyRect - aFrame->GetOffsetTo(aDirtyFrame);
nsRect overflowRect = aFrame->GetVisualOverflowRect();
if (aFrame->IsTransformed() &&
nsLayoutUtils::HasAnimationsForCompositor(aFrame->GetContent(),
eCSSProperty_transform)) {
/**
* Add a fuzz factor to the overflow rectangle so that elements only just
* out of view are pulled into the display list, so they can be
* prerendered if necessary.
*/
overflowRect.Inflate(nsPresContext::CSSPixelsToAppUnits(32));
}
if (mHasDisplayPort && IsFixedFrame(aFrame)) {
dirty = overflowRect;
}
if (!dirty.IntersectRect(dirty, overflowRect))
return;
aFrame->Properties().Set(nsDisplayListBuilder::OutOfFlowDirtyRectProperty(),
new nsRect(dirty));
@ -3891,7 +3903,14 @@ nsDisplayTransform::ShouldPrerenderTransformedContent(nsDisplayListBuilder* aBui
nsIFrame* aFrame,
bool aLogAnimations)
{
if (!aFrame->AreLayersMarkedActive(nsChangeHint_UpdateTransformLayer)) {
// Elements whose transform has been modified recently, or which
// have a compositor-animated transform, can be prerendered. An element
// might have only just had its transform animated in which case
// nsChangeHint_UpdateTransformLayer will not be present yet.
if (!aFrame->AreLayersMarkedActive(nsChangeHint_UpdateTransformLayer) &&
(!aFrame->GetContent() ||
!nsLayoutUtils::HasAnimationsForCompositor(aFrame->GetContent(),
eCSSProperty_transform))) {
if (aLogAnimations) {
nsCString message;
message.AppendLiteral("Performance warning: Async animation disabled because frame was not marked active for transform animation");
@ -3978,6 +3997,12 @@ nsDisplayTransform::GetTransform(float aAppUnitsPerPixel)
return mTransform;
}
bool
nsDisplayTransform::ShouldBuildLayerEvenIfInvisible(nsDisplayListBuilder* aBuilder)
{
return ShouldPrerenderTransformedContent(aBuilder, mFrame, false);
}
already_AddRefed<Layer> nsDisplayTransform::BuildLayer(nsDisplayListBuilder *aBuilder,
LayerManager *aManager,
const ContainerParameters& aContainerParameters)

View File

@ -966,6 +966,12 @@ public:
LayerManager* aManager,
const ContainerParameters& aParameters)
{ return mozilla::LAYER_NONE; }
/**
* Return true to indicate the layer should be constructed even if it's
* completely invisible.
*/
virtual bool ShouldBuildLayerEvenIfInvisible(nsDisplayListBuilder* aBuilder)
{ return false; }
/**
* Actually paint this item to some rendering context.
* Content outside mVisibleRect need not be painted.
@ -2533,7 +2539,8 @@ public:
virtual LayerState GetLayerState(nsDisplayListBuilder* aBuilder,
LayerManager* aManager,
const ContainerParameters& aParameters) MOZ_OVERRIDE;
virtual bool ShouldBuildLayerEvenIfInvisible(nsDisplayListBuilder* aBuilder) MOZ_OVERRIDE
{ return true; }
virtual bool TryMerge(nsDisplayListBuilder* aBuilder,
nsDisplayItem* aItem) MOZ_OVERRIDE;
@ -2789,6 +2796,7 @@ public:
virtual already_AddRefed<Layer> BuildLayer(nsDisplayListBuilder* aBuilder,
LayerManager* aManager,
const ContainerParameters& aContainerParameters) MOZ_OVERRIDE;
virtual bool ShouldBuildLayerEvenIfInvisible(nsDisplayListBuilder* aBuilder) MOZ_OVERRIDE;
virtual bool ComputeVisibility(nsDisplayListBuilder *aBuilder,
nsRegion *aVisibleRegion,
const nsRect& aAllowVisibleRegionExpansion) MOZ_OVERRIDE;
@ -2940,6 +2948,11 @@ public:
bool aLogAnimations = false);
bool CanUseAsyncAnimations(nsDisplayListBuilder* aBuilder) MOZ_OVERRIDE;
static bool IsLayerPrerendered(Layer* aLayer)
{
return aLayer->HasUserData(nsIFrame::LayerIsPrerenderedDataKey());
}
private:
static gfx3DMatrix GetResultingTransformMatrixInternal(const FrameTransformProperties& aProperties,
const nsPoint& aOrigin,

View File

@ -130,10 +130,6 @@ PrintDisplayListTo(nsDisplayListBuilder* aBuilder, const nsDisplayList& aList,
}
for (nsDisplayItem* i = aList.GetBottom(); i != nullptr; i = i->GetAbove()) {
#ifdef DEBUG
if (aList.DidComputeVisibility() && i->GetVisibleRect().IsEmpty())
continue;
#endif
if (aDumpHtml) {
fprintf(aOutput, "<li>");
} else {