Bug 586683 - Part 1 - Add resolution handling to BasicLayers. r=roc a=blocking2.0

This commit is contained in:
Matt Woodrow 2011-02-09 09:35:54 +13:00
parent 3a7d2f48c0
commit c0ff9d37e2
7 changed files with 93 additions and 2 deletions

View File

@ -554,8 +554,9 @@ BasicThebesLayer::Paint(gfxContext* aContext,
}
{
float paintXRes = BasicManager()->XResolution();
float paintYRes = BasicManager()->YResolution();
gfxSize scale = aContext->CurrentMatrix().ScaleFactors(PR_TRUE);
float paintXRes = gfxUtils::ClampToScaleFactor(BasicManager()->XResolution() * scale.width);
float paintYRes = gfxUtils::ClampToScaleFactor(BasicManager()->YResolution() * scale.height);
Buffer::PaintState state =
mBuffer.BeginPaint(this, contentType, paintXRes, paintYRes);
mValidRegion.Sub(mValidRegion, state.mRegionToInvalidate);
@ -566,6 +567,7 @@ BasicThebesLayer::Paint(gfxContext* aContext,
// from RGB to RGBA, because we might need to repaint with
// subpixel AA)
state.mRegionToInvalidate.And(state.mRegionToInvalidate, mVisibleRegion);
state.mRegionToDraw.ExtendForScaling(paintXRes, paintYRes);
mXResolution = paintXRes;
mYResolution = paintYRes;
SetAntialiasingFlags(this, state.mContext);

View File

@ -205,6 +205,32 @@ nsRect& nsRect::ScaleRoundOut(float aXScale, float aYScale)
return *this;
}
static bool IsFloatInteger(float aFloat)
{
return fabs(aFloat - NS_round(aFloat)) < 1e-6;
}
nsRect& nsRect::ExtendForScaling(float aXMult, float aYMult)
{
NS_ASSERTION((IsFloatInteger(aXMult) || IsFloatInteger(1/aXMult)) &&
(IsFloatInteger(aYMult) || IsFloatInteger(1/aYMult)),
"Multiplication factors must be integers or 1/integer");
// Scale rect by multiplier, snap outwards to integers and then unscale.
// We round the results to the nearest integer to prevent floating point errors.
if (aXMult < 1) {
nscoord right = NSToCoordRound(ceil(float(XMost()) * aXMult) / aXMult);
x = NSToCoordRound(floor(float(x) * aXMult) / aXMult);
width = right - x;
}
if (aYMult < 1) {
nscoord bottom = NSToCoordRound(ceil(float(YMost()) * aYMult) / aYMult);
y = NSToCoordRound(floor(float(y) * aYMult) / aYMult);
height = bottom - y;
}
return *this;
}
#ifdef DEBUG
// Diagnostics

View File

@ -183,6 +183,11 @@ struct NS_GFX nsRect {
nsRect& ScaleRoundOut(float aScale) { return ScaleRoundOut(aScale, aScale); }
nsRect& ScaleRoundOut(float aXScale, float aYScale);
// Extend the rect outwards such that the edges are on integer boundaries
// and the edges scaled by aXMult/aYMult are also on integer boundaries.
// aXMult/aYMult must be N or 1/N for integer N.
nsRect& ExtendForScaling(float aXMult, float aYMult);
// Converts this rect from aFromAPP, an appunits per pixel ratio, to aToAPP.
// In the RoundOut version we make the rect the smallest rect containing the
// unrounded result. In the RoundIn version we make the rect the largest rect

View File

@ -1301,6 +1301,22 @@ void nsRegion::MoveBy (nsPoint aPt)
}
}
nsRegion& nsRegion::ExtendForScaling (float aXMult, float aYMult)
{
nsRegion region;
nsRegionRectIterator iter(*this);
for (;;) {
const nsRect* r = iter.Next();
if (!r)
break;
nsRect rect = *r;
rect.ExtendForScaling(aXMult, aYMult);
region.Or(region, rect);
}
*this = region;
return *this;
}
nsRegion nsRegion::ConvertAppUnitsRoundOut (PRInt32 aFromAPP, PRInt32 aToAPP) const
{
if (aFromAPP == aToAPP) {

View File

@ -185,6 +185,8 @@ public:
nsRegion ConvertAppUnitsRoundOut (PRInt32 aFromAPP, PRInt32 aToAPP) const;
nsRegion ConvertAppUnitsRoundIn (PRInt32 aFromAPP, PRInt32 aToAPP) const;
nsIntRegion ToOutsidePixels (nscoord aAppUnitsPerPixel) const;
nsRegion& ExtendForScaling (float aXMult, float aYMult);
/**
* Gets the largest rectangle contained in the region.
* @param aContainingRect if non-empty, we choose a rectangle that
@ -437,6 +439,12 @@ public:
return FromRect (mImpl.GetLargestRectangle( ToRect(aContainingRect) ));
}
nsIntRegion& ExtendForScaling (float aXMult, float aYMult)
{
mImpl.ExtendForScaling(aXMult, aYMult);
return *this;
}
/**
* Make sure the region has at most aMaxRects by adding area to it
* if necessary. The simplified region will be a superset of the

View File

@ -467,6 +467,35 @@ gfxUtils::ClipToRegionSnapped(gfxContext* aContext, const nsIntRegion& aRegion)
ClipToRegionInternal(aContext, aRegion, PR_TRUE);
}
/*static*/ gfxFloat
gfxUtils::ClampToScaleFactor(gfxFloat aVal)
{
// Arbitary scale factor limitation. We can increase this
// for better scaling performance at the cost of worse
// quality.
static const gfxFloat kScaleResolution = 2;
// Negative scaling is just a flip and irrelevant to
// our resolution calculation.
if (aVal < 0.0) {
aVal = -aVal;
}
gfxFloat power = log(aVal)/log(kScaleResolution);
// If power is within 1e-6 of an integer, round to nearest to
// prevent floating point errors, otherwise round up to the
// next integer value.
if (fabs(power - NS_round(power)) < 1e-6) {
power = NS_round(power);
} else {
power = NS_ceil(power);
}
return pow(kScaleResolution, power);
}
/*static*/ void
gfxUtils::PathFromRegion(gfxContext* aContext, const nsIntRegion& aRegion)
{

View File

@ -117,6 +117,11 @@ public:
* set aOut to that rectangle, otherwise return failure.
*/
static PRBool GfxRectToIntRect(const gfxRect& aIn, nsIntRect* aOut);
/**
* Clamp aVal to a power of kScaleResolution.
*/
static gfxFloat ClampToScaleFactor(gfxFloat aVal);
};
#endif