Bug 637852. Part 17: Tighten up AreLayersMarkedActive so we track exactly what properties are changing. Also, clamp resolution to power-of-2 only if the frame's transform has a scale. r=tnikkel

This lets us avoid clamping the scale in more situations. We should only clamp the scale when we think
the scale is changing due to a changing transform --- the goal of clamping is to not have to redraw the content
too often when the content is zooming in or out.
This commit is contained in:
Robert O'Callahan 2011-06-23 00:11:28 +12:00
parent c944a09c1f
commit 50a8bdee8e
7 changed files with 44 additions and 16 deletions

View File

@ -621,7 +621,7 @@ nsHTMLCanvasElement::InvalidateCanvasContent(const gfxRect* damageRect)
if (!frame)
return;
frame->MarkLayersActive();
frame->MarkLayersActive(nsChangeHint(0));
nsRect invalRect;
nsRect contentArea = frame->GetContentRect();

View File

@ -1666,14 +1666,16 @@ ChooseScaleAndSetTransform(FrameLayerBuilder* aLayerBuilder,
transform.Is2D(&transform2d)) {
//Scale factors are normalized to a power of 2 to reduce the number of resolution changes
scale = transform2d.ScaleFactors(PR_TRUE);
// For frames that aren't marked active (i.e. opacity/transform not
// changed recently), let them take their exact resolution. Otherwise
// round up to nearest power-of-2 boundary so that we don't keep having to
// redraw the content as it scales up and down. Rounding up to nearest
// For frames with a changing transform that's not just a translation,
// round scale factors up to nearest power-of-2 boundary so that we don't
// keep having to redraw the content as it scales up and down. Rounding up to nearest
// power-of-2 boundary ensures we never scale up, only down --- avoiding
// jaggies. It also ensures we never scale down by more than a factor of 2,
// avoiding bad downscaling quality.
if (aContainerFrame->AreLayersMarkedActive()) {
gfxMatrix frameTransform;
if (aContainerFrame->AreLayersMarkedActive(nsChangeHint_UpdateTransformLayer) &&
aTransform &&
(!aTransform->Is2D(&frameTransform) || frameTransform.HasNonTranslationOrFlip())) {
scale.width = gfxUtils::ClampToScaleFactor(scale.width);
scale.height = gfxUtils::ClampToScaleFactor(scale.height);
} else {

View File

@ -7689,13 +7689,13 @@ DoApplyRenderingChangeToTree(nsIFrame* aFrame,
}
}
if (aChange & nsChangeHint_UpdateOpacityLayer) {
aFrame->MarkLayersActive();
aFrame->MarkLayersActive(nsChangeHint_UpdateOpacityLayer);
aFrame->InvalidateLayer(aFrame->GetVisualOverflowRectRelativeToSelf(),
nsDisplayItem::TYPE_OPACITY);
}
if (aChange & nsChangeHint_UpdateTransformLayer) {
aFrame->MarkLayersActive();
aFrame->MarkLayersActive(nsChangeHint_UpdateTransformLayer);
// Invalidate the old transformed area. The new transformed area
// will be invalidated by nsFrame::FinishAndStoreOverflowArea.
aFrame->InvalidateTransformLayer();

View File

@ -1714,7 +1714,7 @@ nsDisplayOpacity::BuildLayer(nsDisplayListBuilder* aBuilder,
nsDisplayItem::LayerState
nsDisplayOpacity::GetLayerState(nsDisplayListBuilder* aBuilder,
LayerManager* aManager) {
if (mFrame->AreLayersMarkedActive())
if (mFrame->AreLayersMarkedActive(nsChangeHint_UpdateOpacityLayer))
return LAYER_ACTIVE;
nsIFrame* activeScrolledRoot =
nsLayoutUtils::GetActiveScrolledRootFor(mFrame, nsnull);
@ -2398,7 +2398,7 @@ already_AddRefed<Layer> nsDisplayTransform::BuildLayer(nsDisplayListBuilder *aBu
nsDisplayItem::LayerState
nsDisplayTransform::GetLayerState(nsDisplayListBuilder* aBuilder,
LayerManager* aManager) {
if (mFrame->AreLayersMarkedActive())
if (mFrame->AreLayersMarkedActive(nsChangeHint_UpdateTransformLayer))
return LAYER_ACTIVE;
nsIFrame* activeScrolledRoot =
nsLayoutUtils::GetActiveScrolledRootFor(mFrame, nsnull);

View File

@ -118,6 +118,7 @@
#include "nsExpirationTracker.h"
#include "nsSVGIntegrationUtils.h"
#include "nsSVGEffects.h"
#include "nsChangeHint.h"
#include "gfxContext.h"
#include "CSSCalc.h"
@ -4099,12 +4100,17 @@ nsIFrame::InvalidateTransformLayer()
class LayerActivity {
public:
LayerActivity(nsIFrame* aFrame) : mFrame(aFrame) {}
LayerActivity(nsIFrame* aFrame) : mFrame(aFrame), mChangeHint(nsChangeHint(0)) {}
~LayerActivity();
nsExpirationState* GetExpirationState() { return &mState; }
nsIFrame* mFrame;
nsExpirationState mState;
// mChangeHint can be some combination of nsChangeHint_UpdateOpacityLayer and
// nsChangeHint_UpdateTransformLayer (or neither)
// The presence of those bits indicates whether opacity or transform
// changes have been detected.
nsChangeHint mChangeHint;
};
class LayerActivityTracker : public nsExpirationTracker<LayerActivity,4> {
@ -4149,7 +4155,7 @@ LayerActivityTracker::NotifyExpired(LayerActivity* aObject)
}
void
nsIFrame::MarkLayersActive()
nsIFrame::MarkLayersActive(nsChangeHint aChangeHint)
{
FrameProperties properties = Properties();
LayerActivity* layerActivity =
@ -4164,6 +4170,7 @@ nsIFrame::MarkLayersActive()
gLayerActivityTracker->AddObject(layerActivity);
properties.Set(LayerActivityProperty(), layerActivity);
}
NS_UpdateHint(layerActivity->mChangeHint, aChangeHint);
}
PRBool
@ -4172,6 +4179,14 @@ nsIFrame::AreLayersMarkedActive()
return Properties().Get(LayerActivityProperty()) != nsnull;
}
PRBool
nsIFrame::AreLayersMarkedActive(nsChangeHint aChangeHint)
{
LayerActivity* layerActivity =
static_cast<LayerActivity*>(Properties().Get(LayerActivityProperty()));
return layerActivity && (layerActivity->mChangeHint & aChangeHint);
}
/* static */ void
nsFrame::ShutdownLayerActivityTimer()
{

View File

@ -133,7 +133,7 @@ nsHTMLCanvasFrame::Init(nsIContent* aContent,
// We can fill in the canvas before the canvas frame is created, in
// which case we never get around to marking the layer active. Therefore,
// we mark it active here when we create the frame.
MarkLayersActive();
MarkLayersActive(nsChangeHint(0));
return rv;
}

View File

@ -1997,14 +1997,25 @@ public:
* after a short period. This call does no immediate invalidation,
* but when the mark times out, we'll invalidate the frame's overflow
* area.
* @param aChangeHint nsChangeHint_UpdateTransformLayer or
* nsChangeHint_UpdateOpacityLayer or 0, depending on whether the change
* triggering the activity is a changing transform, changing opacity, or
* something else.
*/
void MarkLayersActive();
void MarkLayersActive(nsChangeHint aHint);
/**
* Return true if this frame is marked as needing active layers.
*/
PRBool AreLayersMarkedActive();
/**
* Return true if this frame is marked as needing active layers.
* @param aChangeHint nsChangeHint_UpdateTransformLayer or
* nsChangeHint_UpdateOpacityLayer. We return true only if
* a change in the transform or opacity has been recorded while layers have
* been marked active for this frame.
*/
PRBool AreLayersMarkedActive(nsChangeHint aChangeHint);
/**
* @param aFlags see InvalidateInternal below
*/