Bug 639689. Part 5: Track whether the current path in the canvas context is empty. If it is, then optimize path save/restore to not make a copy of the current path. r=joe

This commit is contained in:
Robert O'Callahan 2011-03-24 16:13:59 +13:00
parent 6efae32538
commit 6880cc64d6

View File

@ -431,6 +431,29 @@ public:
STYLE_MAX
};
class PathAutoSaveRestore
{
public:
PathAutoSaveRestore(nsCanvasRenderingContext2D* aCtx) :
mContext(aCtx->mThebes)
{
if (aCtx->mHasPath) {
mPath = mContext->CopyPath();
}
}
~PathAutoSaveRestore()
{
mContext->NewPath();
if (mPath) {
mContext->AppendPath(mPath);
}
}
private:
gfxContext *mContext;
nsRefPtr<gfxPath> mPath;
};
friend class PathAutoSaveRestore;
protected:
/**
@ -512,6 +535,10 @@ protected:
* many more Redraw calls.
*/
PRPackedBool mPredictManyRedrawCalls;
/**
* This is set whenever there's a nonempty path set by the API user.
*/
PRPackedBool mHasPath;
/**
* Number of times we've invalidated before calling redraw
@ -830,7 +857,7 @@ nsCanvasRenderingContext2D::nsCanvasRenderingContext2D()
, mIPC(PR_FALSE)
, mCanvasElement(nsnull)
, mSaveCount(0), mIsEntireFrameInvalid(PR_FALSE)
, mPredictManyRedrawCalls(PR_FALSE), mInvalidateCount(0)
, mPredictManyRedrawCalls(PR_FALSE), mHasPath(PR_FALSE), mInvalidateCount(0)
, mLastStyle(STYLE_MAX), mStyleStack(20)
{
sNumLivingContexts++;
@ -1953,7 +1980,7 @@ nsCanvasRenderingContext2D::ClearRect(float x, float y, float w, float h)
if (!FloatValidate(x,y,w,h))
return NS_ERROR_DOM_SYNTAX_ERR;
gfxContextPathAutoSaveRestore pathSR(mThebes);
PathAutoSaveRestore pathSR(this);
gfxContextAutoSaveRestore autoSR(mThebes);
mThebes->SetOperator(gfxContext::OPERATOR_CLEAR);
@ -1970,7 +1997,7 @@ nsCanvasRenderingContext2D::DrawRect(const gfxRect& rect, Style style)
if (!FloatValidate(rect.pos.x, rect.pos.y, rect.size.width, rect.size.height))
return NS_ERROR_DOM_SYNTAX_ERR;
gfxContextPathAutoSaveRestore pathSR(mThebes);
PathAutoSaveRestore pathSR(this);
mThebes->NewPath();
mThebes->Rectangle(rect);
@ -2002,6 +2029,7 @@ nsCanvasRenderingContext2D::StrokeRect(float x, float y, float w, float h)
NS_IMETHODIMP
nsCanvasRenderingContext2D::BeginPath()
{
mHasPath = PR_FALSE;
mThebes->NewPath();
return NS_OK;
}
@ -2046,6 +2074,7 @@ nsCanvasRenderingContext2D::MoveTo(float x, float y)
if (!FloatValidate(x,y))
return NS_ERROR_DOM_SYNTAX_ERR;
mHasPath = PR_TRUE;
mThebes->MoveTo(gfxPoint(x, y));
return NS_OK;
}
@ -2056,6 +2085,7 @@ nsCanvasRenderingContext2D::LineTo(float x, float y)
if (!FloatValidate(x,y))
return NS_ERROR_DOM_SYNTAX_ERR;
mHasPath = PR_TRUE;
mThebes->LineTo(gfxPoint(x, y));
return NS_OK;
}
@ -2072,6 +2102,7 @@ nsCanvasRenderingContext2D::QuadraticCurveTo(float cpx, float cpy, float x, floa
gfxPoint p(x,y);
gfxPoint cp(cpx, cpy);
mHasPath = PR_TRUE;
mThebes->CurveTo((c+cp*2)/3.0, (p+cp*2)/3.0, p);
return NS_OK;
@ -2085,6 +2116,7 @@ nsCanvasRenderingContext2D::BezierCurveTo(float cp1x, float cp1y,
if (!FloatValidate(cp1x,cp1y,cp2x,cp2y,x,y))
return NS_ERROR_DOM_SYNTAX_ERR;
mHasPath = PR_TRUE;
mThebes->CurveTo(gfxPoint(cp1x, cp1y),
gfxPoint(cp2x, cp2y),
gfxPoint(x, y));
@ -2101,6 +2133,8 @@ nsCanvasRenderingContext2D::ArcTo(float x1, float y1, float x2, float y2, float
if (radius < 0)
return NS_ERROR_DOM_INDEX_SIZE_ERR;
mHasPath = PR_TRUE;
gfxPoint p0 = mThebes->CurrentPoint();
double dir, a2, b2, c2, cosx, sinx, d, anx, any, bnx, bny, x3, y3, x4, y4, cx, cy, angle0, angle1;
@ -2160,6 +2194,7 @@ nsCanvasRenderingContext2D::Arc(float x, float y, float r, float startAngle, flo
gfxPoint p(x,y);
mHasPath = PR_TRUE;
if (ccw)
mThebes->NegativeArc(p, r, startAngle, endAngle);
else
@ -2173,6 +2208,7 @@ nsCanvasRenderingContext2D::Rect(float x, float y, float w, float h)
if (!FloatValidate(x,y,w,h))
return NS_ERROR_DOM_SYNTAX_ERR;
mHasPath = PR_TRUE;
mThebes->Rectangle(gfxRect(x, y, w, h));
return NS_OK;
}
@ -3331,8 +3367,6 @@ nsCanvasRenderingContext2D::DrawImage(nsIDOMElement *imgElt, float a1,
{
NS_ENSURE_ARG(imgElt);
nsresult rv;
double sx,sy,sw,sh;
double dx,dy,dw,dh;
@ -3378,10 +3412,6 @@ nsCanvasRenderingContext2D::DrawImage(nsIDOMElement *imgElt, float a1,
}
}
gfxContextPathAutoSaveRestore pathSR(mThebes, PR_FALSE);
rv = NS_OK;
if (optional_argc == 0) {
dx = a1;
dy = a2;
@ -3407,20 +3437,17 @@ nsCanvasRenderingContext2D::DrawImage(nsIDOMElement *imgElt, float a1,
dh = a8;
} else {
// XXX ERRMSG we need to report an error to developers here! (bug 329026)
rv = NS_ERROR_INVALID_ARG;
goto FINISH;
return NS_ERROR_INVALID_ARG;
}
if (dw == 0.0 || dh == 0.0) {
rv = NS_OK;
// not really failure, but nothing to do --
// and noone likes a divide-by-zero
goto FINISH;
return NS_OK;
}
if (!FloatValidate(sx, sy, sw, sh) || !FloatValidate(dx, dy, dw, dh)) {
rv = NS_ERROR_DOM_SYNTAX_ERR;
goto FINISH;
return NS_ERROR_DOM_SYNTAX_ERR;
}
// check args
@ -3430,8 +3457,7 @@ nsCanvasRenderingContext2D::DrawImage(nsIDOMElement *imgElt, float a1,
dw < 0.0 || dh < 0.0)
{
// XXX ERRMSG we need to report an error to developers here! (bug 329026)
rv = NS_ERROR_DOM_INDEX_SIZE_ERR;
goto FINISH;
return NS_ERROR_DOM_INDEX_SIZE_ERR;
}
matrix.Translate(gfxPoint(sx, sy));
@ -3458,8 +3484,7 @@ nsCanvasRenderingContext2D::DrawImage(nsIDOMElement *imgElt, float a1,
if (opaque && unscaled) {
bitblt(surf, sx, sy, sw, sh, dx, dy);
rv = NS_OK;
goto FINISH;
return NS_OK;
}
}
}
@ -3474,7 +3499,7 @@ nsCanvasRenderingContext2D::DrawImage(nsIDOMElement *imgElt, float a1,
else
pattern->SetFilter(gfxPattern::FILTER_NEAREST);
pathSR.Save();
PathAutoSaveRestore pathSR(this);
// Clear the surface if we need to simulate unbounded SOURCE operator
ClearSurfaceForUnboundedSource();
@ -3535,8 +3560,7 @@ nsCanvasRenderingContext2D::DrawImage(nsIDOMElement *imgElt, float a1,
RedrawUser(clip);
}
FINISH:
return rv;
return NS_OK;
}
NS_IMETHODIMP
@ -4018,7 +4042,7 @@ nsCanvasRenderingContext2D::PutImageData_explicit(PRInt32 x, PRInt32 y, PRUint32
}
}
gfxContextPathAutoSaveRestore pathSR(mThebes);
PathAutoSaveRestore pathSR(this);
gfxContextAutoSaveRestore autoSR(mThebes);
// ignore clipping region, as per spec