Bug 591358 - Delay creation of canvases until we actually draw to them. r=roc

This commit is contained in:
Matt Woodrow 2011-08-31 14:03:31 +12:00
parent 5bdf386f72
commit 9759f6564b

View File

@ -339,7 +339,9 @@ public:
// nsICanvasRenderingContextInternal
NS_IMETHOD SetCanvasElement(nsHTMLCanvasElement* aParentCanvas);
NS_IMETHOD SetDimensions(PRInt32 width, PRInt32 height);
void Initialize(nsIDocShell *shell, PRInt32 width, PRInt32 height);
NS_IMETHOD InitializeWithSurface(nsIDocShell *shell, gfxASurface *surface, PRInt32 width, PRInt32 height);
PRBool EnsureSurface();
NS_IMETHOD Render(gfxContext *ctx, gfxPattern::GraphicsFilter aFilter);
NS_IMETHOD GetInputStream(const char* aMimeType,
const PRUnichar* aEncoderOptions,
@ -380,7 +382,7 @@ public:
{
public:
PathAutoSaveRestore(nsCanvasRenderingContext2D* aCtx) :
mContext(aCtx->mThebes)
mContext(aCtx->mThebes)
{
if (aCtx->mHasPath) {
mPath = mContext->CopyPath();
@ -460,12 +462,16 @@ protected:
return static_cast<nsHTMLCanvasElement*>(mCanvasElement.get());
}
// Initialize the Thebes rendering context
void CreateThebes();
// If mCanvasElement is not provided, then a docshell is
nsCOMPtr<nsIDocShell> mDocShell;
// our drawing surfaces, contexts, and layers
nsRefPtr<gfxContext> mThebes;
nsRefPtr<gfxASurface> mSurface;
PRPackedBool mSurfaceCreated;
PRUint32 mSaveCount;
@ -527,6 +533,11 @@ protected:
*/
PRBool NeedToUseIntermediateSurface()
{
if (!mThebes) {
// Haven't created a surface yet, default is OVER.
return OperatorAffectsUncoveredAreas(gfxContext::OPERATOR_OVER);
}
// certain operators always need an intermediate surface, except
// with quartz since quartz does compositing differently than cairo
return OperatorAffectsUncoveredAreas(mThebes->CurrentOperator());
@ -541,6 +552,11 @@ protected:
*/
void ClearSurfaceForUnboundedSource()
{
if (!mThebes) {
// Haven't created a surface yet, default is OVER.
return;
}
gfxContext::GraphicsOperator current = mThebes->CurrentOperator();
if (current != gfxContext::OPERATOR_SOURCE)
return;
@ -964,6 +980,10 @@ nsCanvasRenderingContext2D::ApplyStyle(Style aWhichStyle,
return;
}
if (!EnsureSurface()) {
return;
}
// if not using global alpha, don't optimize with dirty bit
if (aUseGlobalAlpha)
mDirtyStyle[aWhichStyle] = PR_FALSE;
@ -1058,16 +1078,100 @@ nsCanvasRenderingContext2D::RedrawUser(const gfxRect& r)
NS_IMETHODIMP
nsCanvasRenderingContext2D::SetDimensions(PRInt32 width, PRInt32 height)
{
Initialize(NULL, width, height);
return NS_OK;
}
void
nsCanvasRenderingContext2D::Initialize(nsIDocShell *docShell, PRInt32 width, PRInt32 height)
{
Reset();
NS_ASSERTION(!docShell ^ !mCanvasElement, "Cannot set both docshell and canvas element");
mDocShell = docShell;
mWidth = width;
mHeight = height;
mResetLayer = PR_TRUE;
mValid = PR_TRUE;
mSurfaceCreated = PR_FALSE;
// set up the initial canvas defaults
mStyleStack.Clear();
mSaveCount = 0;
ContextState *state = mStyleStack.AppendElement();
state->globalAlpha = 1.0;
state->colorStyles[STYLE_FILL] = NS_RGB(0,0,0);
state->colorStyles[STYLE_STROKE] = NS_RGB(0,0,0);
state->colorStyles[STYLE_SHADOW] = NS_RGBA(0,0,0,0);
DirtyAllStyles();
// always force a redraw, because if the surface dimensions were reset
// then the surface became cleared, and we need to redraw everything.
Redraw();
return;
}
void
nsCanvasRenderingContext2D::CreateThebes()
{
mThebes = new gfxContext(mSurface);
mSurfaceCreated = PR_TRUE;
mThebes->SetOperator(gfxContext::OPERATOR_CLEAR);
mThebes->NewPath();
mThebes->Rectangle(gfxRect(0, 0, mWidth, mHeight));
mThebes->Fill();
mThebes->SetLineWidth(1.0);
mThebes->SetOperator(gfxContext::OPERATOR_OVER);
mThebes->SetMiterLimit(10.0);
mThebes->SetLineCap(gfxContext::LINE_CAP_BUTT);
mThebes->SetLineJoin(gfxContext::LINE_JOIN_MITER);
mThebes->NewPath();
}
NS_IMETHODIMP
nsCanvasRenderingContext2D::InitializeWithSurface(nsIDocShell *docShell,
gfxASurface *surface,
PRInt32 width,
PRInt32 height)
{
Initialize(docShell, width, height);
mSurface = surface;
CreateThebes();
return mValid ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
}
PRBool
nsCanvasRenderingContext2D::EnsureSurface()
{
if (!mValid) {
return PR_FALSE;
}
if (mSurface && mThebes && mSurfaceCreated) {
if (mSurface->CairoStatus()) {
return PR_FALSE;
}
return PR_TRUE;
}
nsRefPtr<gfxASurface> surface;
// Check that the dimensions are sane
gfxIntSize size(width, height);
if (gfxASurface::CheckSurfaceSize(size, 0xffff)) {
if (gfxASurface::CheckSurfaceSize(gfxIntSize(mWidth, mHeight), 0xffff)) {
// Zero sized surfaces have problems, so just use a 1 by 1.
if (height == 0 || width == 0) {
if (mHeight == 0 || mWidth == 0) {
mZero = PR_TRUE;
height = 1;
width = 1;
mHeight = 1;
mWidth = 1;
} else {
mZero = PR_FALSE;
}
@ -1086,10 +1190,10 @@ nsCanvasRenderingContext2D::SetDimensions(PRInt32 width, PRInt32 height)
nsContentUtils::PersistentLayerManagerForDocument(ownerDoc);
if (layerManager) {
surface = layerManager->CreateOptimalSurface(gfxIntSize(width, height), format);
surface = layerManager->CreateOptimalSurface(gfxIntSize(mWidth, mHeight), format);
} else {
surface = gfxPlatform::GetPlatform()->
CreateOffscreenSurface(gfxIntSize(width, height), gfxASurface::ContentFromFormat(format));
CreateOffscreenSurface(gfxIntSize(mWidth, mHeight), gfxASurface::ContentFromFormat(format));
}
}
@ -1097,7 +1201,7 @@ nsCanvasRenderingContext2D::SetDimensions(PRInt32 width, PRInt32 height)
// If we couldn't create a surface of the type we want, fall back
// to an image surface. This lets us handle surface sizes that
// the underlying cairo backend might not handle.
surface = new gfxImageSurface(gfxIntSize(width, height), format);
surface = new gfxImageSurface(gfxIntSize(mWidth, mHeight), format);
if (!surface || surface->CairoStatus()) {
surface = nsnull;
}
@ -1109,71 +1213,22 @@ nsCanvasRenderingContext2D::SetDimensions(PRInt32 width, PRInt32 height)
NS_RegisterMemoryReporter(gCanvasMemoryReporter);
}
gCanvasMemoryUsed += width * height * 4;
gCanvasMemoryUsed += mWidth * mHeight * 4;
JSContext* context = nsContentUtils::GetCurrentJSContext();
if (context) {
JS_updateMallocCounter(context, width * height * 4);
JS_updateMallocCounter(context, mWidth * mHeight * 4);
}
} else {
return PR_FALSE;
}
return InitializeWithSurface(NULL, surface, width, height);
}
NS_IMETHODIMP
nsCanvasRenderingContext2D::InitializeWithSurface(nsIDocShell *docShell, gfxASurface *surface, PRInt32 width, PRInt32 height) {
Reset();
NS_ASSERTION(!docShell ^ !mCanvasElement, "Cannot set both docshell and canvas element");
mDocShell = docShell;
mWidth = width;
mHeight = height;
mSurface = surface;
mThebes = surface ? new gfxContext(mSurface) : nsnull;
mResetLayer = PR_TRUE;
CreateThebes();
/* Create dummy surfaces here */
if (mSurface == nsnull || mSurface->CairoStatus() != 0 ||
mThebes == nsnull || mThebes->HasError())
{
mSurface = new gfxImageSurface(gfxIntSize(1,1), gfxASurface::ImageFormatARGB32);
mThebes = new gfxContext(mSurface);
} else {
mValid = PR_TRUE;
if (mSurface->CairoStatus()) {
return PR_FALSE;
}
// set up the initial canvas defaults
mStyleStack.Clear();
mSaveCount = 0;
ContextState *state = mStyleStack.AppendElement();
state->globalAlpha = 1.0;
state->colorStyles[STYLE_FILL] = NS_RGB(0,0,0);
state->colorStyles[STYLE_STROKE] = NS_RGB(0,0,0);
state->colorStyles[STYLE_SHADOW] = NS_RGBA(0,0,0,0);
DirtyAllStyles();
mThebes->SetOperator(gfxContext::OPERATOR_CLEAR);
mThebes->NewPath();
mThebes->Rectangle(gfxRect(0, 0, mWidth, mHeight));
mThebes->Fill();
mThebes->SetLineWidth(1.0);
mThebes->SetOperator(gfxContext::OPERATOR_OVER);
mThebes->SetMiterLimit(10.0);
mThebes->SetLineCap(gfxContext::LINE_CAP_BUTT);
mThebes->SetLineJoin(gfxContext::LINE_JOIN_MITER);
mThebes->SetFillRule(gfxContext::FILL_RULE_WINDING);
mThebes->NewPath();
// always force a redraw, because if the surface dimensions were reset
// then the surface became cleared, and we need to redraw everything.
Redraw();
return mValid ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
return PR_TRUE;
}
NS_IMETHODIMP
@ -1217,9 +1272,7 @@ nsCanvasRenderingContext2D::Render(gfxContext *ctx, gfxPattern::GraphicsFilter a
{
nsresult rv = NS_OK;
if (!mValid || !mSurface ||
mSurface->CairoStatus() ||
mThebes->HasError())
if (!EnsureSurface())
return NS_ERROR_FAILURE;
nsRefPtr<gfxPattern> pat = new gfxPattern(mSurface);
@ -1248,9 +1301,7 @@ nsCanvasRenderingContext2D::GetInputStream(const char *aMimeType,
const PRUnichar *aEncoderOptions,
nsIInputStream **aStream)
{
if (!mValid || !mSurface ||
mSurface->CairoStatus() ||
mThebes->HasError())
if (!EnsureSurface())
return NS_ERROR_FAILURE;
nsresult rv;
@ -1335,6 +1386,9 @@ nsCanvasRenderingContext2D::GetCanvas(nsIDOMHTMLCanvasElement **canvas)
NS_IMETHODIMP
nsCanvasRenderingContext2D::Save()
{
if (!EnsureSurface())
return NS_ERROR_FAILURE;
ContextState state = CurrentState();
mStyleStack.AppendElement(state);
mThebes->Save();
@ -1345,6 +1399,9 @@ nsCanvasRenderingContext2D::Save()
NS_IMETHODIMP
nsCanvasRenderingContext2D::Restore()
{
if (!EnsureSurface())
return NS_ERROR_FAILURE;
if (mSaveCount == 0)
return NS_OK;
@ -1365,6 +1422,9 @@ nsCanvasRenderingContext2D::Restore()
NS_IMETHODIMP
nsCanvasRenderingContext2D::Scale(float x, float y)
{
if (!EnsureSurface())
return NS_ERROR_FAILURE;
if (!FloatValidate(x,y))
return NS_OK;
@ -1375,6 +1435,9 @@ nsCanvasRenderingContext2D::Scale(float x, float y)
NS_IMETHODIMP
nsCanvasRenderingContext2D::Rotate(float angle)
{
if (!EnsureSurface())
return NS_ERROR_FAILURE;
if (!FloatValidate(angle))
return NS_OK;
@ -1385,6 +1448,9 @@ nsCanvasRenderingContext2D::Rotate(float angle)
NS_IMETHODIMP
nsCanvasRenderingContext2D::Translate(float x, float y)
{
if (!EnsureSurface())
return NS_ERROR_FAILURE;
if (!FloatValidate(x,y))
return NS_OK;
@ -1395,6 +1461,9 @@ nsCanvasRenderingContext2D::Translate(float x, float y)
NS_IMETHODIMP
nsCanvasRenderingContext2D::Transform(float m11, float m12, float m21, float m22, float dx, float dy)
{
if (!EnsureSurface())
return NS_ERROR_FAILURE;
if (!FloatValidate(m11,m12,m21,m22,dx,dy))
return NS_OK;
@ -1407,6 +1476,9 @@ nsCanvasRenderingContext2D::Transform(float m11, float m12, float m21, float m22
NS_IMETHODIMP
nsCanvasRenderingContext2D::SetTransform(float m11, float m12, float m21, float m22, float dx, float dy)
{
if (!EnsureSurface())
return NS_ERROR_FAILURE;
if (!FloatValidate(m11,m12,m21,m22,dx,dy))
return NS_OK;
@ -1422,6 +1494,9 @@ nsCanvasRenderingContext2D::SetMozCurrentTransform(JSContext* cx,
{
nsresult rv;
gfxMatrix newCTM;
if (!EnsureSurface())
return NS_ERROR_FAILURE;
if (!JSValToMatrix(cx, matrix, &newCTM, &rv)) {
return rv;
@ -1436,6 +1511,9 @@ NS_IMETHODIMP
nsCanvasRenderingContext2D::GetMozCurrentTransform(JSContext* cx,
jsval* matrix)
{
if (!EnsureSurface())
return NS_ERROR_FAILURE;
return MatrixToJSVal(mThebes->CurrentMatrix(), cx, matrix);
}
@ -1445,6 +1523,9 @@ nsCanvasRenderingContext2D::SetMozCurrentTransformInverse(JSContext* cx,
{
nsresult rv;
gfxMatrix newCTMInverse;
if (!EnsureSurface())
return NS_ERROR_FAILURE;
if (!JSValToMatrix(cx, matrix, &newCTMInverse, &rv)) {
return rv;
@ -1646,6 +1727,9 @@ NS_IMETHODIMP
nsCanvasRenderingContext2D::SetMozFillRule(const nsAString& aString)
{
gfxContext::FillRule rule;
if (!EnsureSurface())
return NS_ERROR_FAILURE;
if (aString.EqualsLiteral("evenodd"))
rule = gfxContext::FILL_RULE_EVEN_ODD;
@ -1662,6 +1746,9 @@ nsCanvasRenderingContext2D::SetMozFillRule(const nsAString& aString)
NS_IMETHODIMP
nsCanvasRenderingContext2D::GetMozFillRule(nsAString& aString)
{
if (!EnsureSurface())
return NS_ERROR_FAILURE;
switch (mThebes->CurrentFillRule()) {
case gfxContext::FILL_RULE_WINDING:
aString.AssignLiteral("nonzero"); break;
@ -1886,6 +1973,9 @@ nsCanvasRenderingContext2D::ShadowInitialize(const gfxRect& extents, gfxAlphaBox
void
nsCanvasRenderingContext2D::ShadowFinalize(gfxAlphaBoxBlur& blur)
{
if (!EnsureSurface())
return;
ApplyStyle(STYLE_SHADOW);
// canvas matrix was already applied, don't apply it twice, but do
// apply the shadow offset
@ -1900,6 +1990,9 @@ nsCanvasRenderingContext2D::ShadowFinalize(gfxAlphaBoxBlur& blur)
nsresult
nsCanvasRenderingContext2D::DrawPath(Style style, gfxRect *dirtyRect)
{
if (!EnsureSurface())
return NS_ERROR_FAILURE;
PRBool doUseIntermediateSurface = PR_FALSE;
if (mSurface->GetType() == gfxASurface::SurfaceTypeD2D) {
@ -2027,6 +2120,9 @@ nsCanvasRenderingContext2D::DrawPath(Style style, gfxRect *dirtyRect)
NS_IMETHODIMP
nsCanvasRenderingContext2D::ClearRect(float x, float y, float w, float h)
{
if (!mSurfaceCreated)
return NS_OK;
if (!FloatValidate(x,y,w,h))
return NS_OK;
@ -2044,6 +2140,9 @@ nsCanvasRenderingContext2D::ClearRect(float x, float y, float w, float h)
nsresult
nsCanvasRenderingContext2D::DrawRect(const gfxRect& rect, Style style)
{
if (!EnsureSurface())
return NS_ERROR_FAILURE;
if (!FloatValidate(rect.X(), rect.Y(), rect.Width(), rect.Height()))
return NS_OK;
@ -2082,6 +2181,9 @@ nsCanvasRenderingContext2D::StrokeRect(float x, float y, float w, float h)
NS_IMETHODIMP
nsCanvasRenderingContext2D::BeginPath()
{
if (!EnsureSurface())
return NS_ERROR_FAILURE;
mHasPath = PR_FALSE;
mThebes->NewPath();
return NS_OK;
@ -2090,6 +2192,9 @@ nsCanvasRenderingContext2D::BeginPath()
NS_IMETHODIMP
nsCanvasRenderingContext2D::ClosePath()
{
if (!EnsureSurface())
return NS_ERROR_FAILURE;
mThebes->ClosePath();
return NS_OK;
}
@ -2117,6 +2222,9 @@ nsCanvasRenderingContext2D::Stroke()
NS_IMETHODIMP
nsCanvasRenderingContext2D::Clip()
{
if (!EnsureSurface())
return NS_ERROR_FAILURE;
mThebes->Clip();
return NS_OK;
}
@ -2124,6 +2232,9 @@ nsCanvasRenderingContext2D::Clip()
NS_IMETHODIMP
nsCanvasRenderingContext2D::MoveTo(float x, float y)
{
if (!EnsureSurface())
return NS_ERROR_FAILURE;
if (!FloatValidate(x,y))
return NS_OK;
@ -2135,6 +2246,9 @@ nsCanvasRenderingContext2D::MoveTo(float x, float y)
NS_IMETHODIMP
nsCanvasRenderingContext2D::LineTo(float x, float y)
{
if (!EnsureSurface())
return NS_ERROR_FAILURE;
if (!FloatValidate(x,y))
return NS_OK;
@ -2146,6 +2260,9 @@ nsCanvasRenderingContext2D::LineTo(float x, float y)
NS_IMETHODIMP
nsCanvasRenderingContext2D::QuadraticCurveTo(float cpx, float cpy, float x, float y)
{
if (!EnsureSurface())
return NS_ERROR_FAILURE;
if (!FloatValidate(cpx,cpy,x,y))
return NS_OK;
@ -2166,6 +2283,9 @@ nsCanvasRenderingContext2D::BezierCurveTo(float cp1x, float cp1y,
float cp2x, float cp2y,
float x, float y)
{
if (!EnsureSurface())
return NS_ERROR_FAILURE;
if (!FloatValidate(cp1x,cp1y,cp2x,cp2y,x,y))
return NS_OK;
@ -2180,6 +2300,9 @@ nsCanvasRenderingContext2D::BezierCurveTo(float cp1x, float cp1y,
NS_IMETHODIMP
nsCanvasRenderingContext2D::ArcTo(float x1, float y1, float x2, float y2, float radius)
{
if (!EnsureSurface())
return NS_ERROR_FAILURE;
if (!FloatValidate(x1,y1,x2,y2,radius))
return NS_OK;
@ -2239,6 +2362,9 @@ nsCanvasRenderingContext2D::ArcTo(float x1, float y1, float x2, float y2, float
NS_IMETHODIMP
nsCanvasRenderingContext2D::Arc(float x, float y, float r, float startAngle, float endAngle, PRBool ccw)
{
if (!EnsureSurface())
return NS_ERROR_FAILURE;
if (!FloatValidate(x,y,r,startAngle,endAngle))
return NS_OK;
@ -2258,6 +2384,9 @@ nsCanvasRenderingContext2D::Arc(float x, float y, float r, float startAngle, flo
NS_IMETHODIMP
nsCanvasRenderingContext2D::Rect(float x, float y, float w, float h)
{
if (!EnsureSurface())
return NS_ERROR_FAILURE;
if (!FloatValidate(x,y,w,h))
return NS_OK;
@ -2770,7 +2899,13 @@ nsCanvasRenderingContext2D::DrawOrMeasureText(const nsAString& aRawText,
GetAppUnitsValues(&processor.mAppUnitsPerDevPixel, NULL);
processor.mPt = gfxPoint(aX, aY);
processor.mThebes = mThebes;
nsRefPtr<nsRenderingContext> ctx;
if (mThebes) {
processor.mThebes = mThebes;
} else {
ctx = presShell->GetReferenceRenderingContext();
processor.mThebes = ctx->ThebesContext();
}
processor.mOp = aOp;
processor.mBoundingBox = gfxRect(0, 0, 0, 0);
processor.mDoMeasureBoundingBox = doDrawShadow || !mIsEntireFrameInvalid;
@ -2804,6 +2939,11 @@ nsCanvasRenderingContext2D::DrawOrMeasureText(const nsAString& aRawText,
if (aOp==TEXT_DRAW_OPERATION_MEASURE)
return NS_OK;
if (!EnsureSurface())
return NS_ERROR_FAILURE;
processor.mThebes = mThebes;
// offset pt.x based on text align
gfxFloat anchorX;
@ -3024,6 +3164,9 @@ nsCanvasRenderingContext2D::MakeTextRun(const PRUnichar* aText,
NS_IMETHODIMP
nsCanvasRenderingContext2D::SetLineWidth(float width)
{
if (!EnsureSurface())
return NS_ERROR_FAILURE;
if (!FloatValidate(width) || width <= 0.0)
return NS_OK;
@ -3034,6 +3177,9 @@ nsCanvasRenderingContext2D::SetLineWidth(float width)
NS_IMETHODIMP
nsCanvasRenderingContext2D::GetLineWidth(float *width)
{
if (!EnsureSurface())
return NS_ERROR_FAILURE;
gfxFloat d = mThebes->CurrentLineWidth();
*width = static_cast<float>(d);
return NS_OK;
@ -3042,6 +3188,9 @@ nsCanvasRenderingContext2D::GetLineWidth(float *width)
NS_IMETHODIMP
nsCanvasRenderingContext2D::SetLineCap(const nsAString& capstyle)
{
if (!EnsureSurface())
return NS_ERROR_FAILURE;
gfxContext::GraphicsLineCap cap;
if (capstyle.EqualsLiteral("butt"))
@ -3061,6 +3210,9 @@ nsCanvasRenderingContext2D::SetLineCap(const nsAString& capstyle)
NS_IMETHODIMP
nsCanvasRenderingContext2D::GetLineCap(nsAString& capstyle)
{
if (!EnsureSurface())
return NS_ERROR_FAILURE;
gfxContext::GraphicsLineCap cap = mThebes->CurrentLineCap();
if (cap == gfxContext::LINE_CAP_BUTT)
@ -3078,6 +3230,9 @@ nsCanvasRenderingContext2D::GetLineCap(nsAString& capstyle)
NS_IMETHODIMP
nsCanvasRenderingContext2D::SetLineJoin(const nsAString& joinstyle)
{
if (!EnsureSurface())
return NS_ERROR_FAILURE;
gfxContext::GraphicsLineJoin j;
if (joinstyle.EqualsLiteral("round"))
@ -3097,6 +3252,9 @@ nsCanvasRenderingContext2D::SetLineJoin(const nsAString& joinstyle)
NS_IMETHODIMP
nsCanvasRenderingContext2D::GetLineJoin(nsAString& joinstyle)
{
if (!EnsureSurface())
return NS_ERROR_FAILURE;
gfxContext::GraphicsLineJoin j = mThebes->CurrentLineJoin();
if (j == gfxContext::LINE_JOIN_ROUND)
@ -3114,6 +3272,9 @@ nsCanvasRenderingContext2D::GetLineJoin(nsAString& joinstyle)
NS_IMETHODIMP
nsCanvasRenderingContext2D::SetMiterLimit(float miter)
{
if (!EnsureSurface())
return NS_ERROR_FAILURE;
if (!FloatValidate(miter) || miter <= 0.0)
return NS_OK;
@ -3124,6 +3285,9 @@ nsCanvasRenderingContext2D::SetMiterLimit(float miter)
NS_IMETHODIMP
nsCanvasRenderingContext2D::GetMiterLimit(float *miter)
{
if (!EnsureSurface())
return NS_ERROR_FAILURE;
gfxFloat d = mThebes->CurrentMiterLimit();
*miter = static_cast<float>(d);
return NS_OK;
@ -3132,6 +3296,9 @@ nsCanvasRenderingContext2D::GetMiterLimit(float *miter)
NS_IMETHODIMP
nsCanvasRenderingContext2D::SetMozDash(JSContext *cx, const jsval& patternArray)
{
if (!EnsureSurface())
return NS_ERROR_FAILURE;
AutoFallibleTArray<gfxFloat, 10> dashes;
nsresult rv = JSValToDashArray(cx, patternArray, dashes);
if (NS_SUCCEEDED(rv)) {
@ -3144,6 +3311,9 @@ nsCanvasRenderingContext2D::SetMozDash(JSContext *cx, const jsval& patternArray)
NS_IMETHODIMP
nsCanvasRenderingContext2D::GetMozDash(JSContext* cx, jsval* dashArray)
{
if (!EnsureSurface())
return NS_ERROR_FAILURE;
AutoFallibleTArray<gfxFloat, 10> dashes;
if (!mThebes->CurrentDash(dashes, nsnull)) {
dashes.SetLength(0);
@ -3154,6 +3324,9 @@ nsCanvasRenderingContext2D::GetMozDash(JSContext* cx, jsval* dashArray)
NS_IMETHODIMP
nsCanvasRenderingContext2D::SetMozDashOffset(float offset)
{
if (!EnsureSurface())
return NS_ERROR_FAILURE;
if (!FloatValidate(offset)) {
return NS_ERROR_ILLEGAL_VALUE;
}
@ -3178,6 +3351,9 @@ nsCanvasRenderingContext2D::SetMozDashOffset(float offset)
NS_IMETHODIMP
nsCanvasRenderingContext2D::GetMozDashOffset(float* offset)
{
if (!EnsureSurface())
return NS_ERROR_FAILURE;
*offset = float(mThebes->CurrentDashOffset());
return NS_OK;
}
@ -3185,6 +3361,9 @@ nsCanvasRenderingContext2D::GetMozDashOffset(float* offset)
NS_IMETHODIMP
nsCanvasRenderingContext2D::IsPointInPath(float x, float y, PRBool *retVal)
{
if (!EnsureSurface())
return NS_ERROR_FAILURE;
if (!FloatValidate(x,y)) {
*retVal = PR_FALSE;
return NS_OK;
@ -3212,6 +3391,9 @@ nsCanvasRenderingContext2D::DrawImage(nsIDOMElement *imgElt, float a1,
float a6, float a7, float a8,
PRUint8 optional_argc)
{
if (!EnsureSurface())
return NS_ERROR_FAILURE;
if (!imgElt) {
return NS_ERROR_DOM_TYPE_MISMATCH_ERR;
}
@ -3396,6 +3578,9 @@ nsCanvasRenderingContext2D::DrawImage(nsIDOMElement *imgElt, float a1,
NS_IMETHODIMP
nsCanvasRenderingContext2D::SetGlobalCompositeOperation(const nsAString& op)
{
if (!EnsureSurface())
return NS_ERROR_FAILURE;
gfxContext::GraphicsOperator thebes_op;
#define CANVAS_OP_TO_THEBES_OP(cvsop,thebesop) \
@ -3425,6 +3610,9 @@ nsCanvasRenderingContext2D::SetGlobalCompositeOperation(const nsAString& op)
NS_IMETHODIMP
nsCanvasRenderingContext2D::GetGlobalCompositeOperation(nsAString& op)
{
if (!EnsureSurface())
return NS_ERROR_FAILURE;
gfxContext::GraphicsOperator thebes_op = mThebes->CurrentOperator();
#define CANVAS_OP_TO_THEBES_OP(cvsop,thebesop) \
@ -3455,6 +3643,9 @@ nsCanvasRenderingContext2D::DrawWindow(nsIDOMWindow* aWindow, float aX, float aY
const nsAString& aBGColor,
PRUint32 flags)
{
if (!EnsureSurface())
return NS_ERROR_FAILURE;
NS_ENSURE_ARG(aWindow != nsnull);
// protect against too-large surfaces that will cause allocation
@ -3545,6 +3736,9 @@ nsCanvasRenderingContext2D::AsyncDrawXULElement(nsIDOMXULElement* aElem, float a
const nsAString& aBGColor,
PRUint32 flags)
{
if (!EnsureSurface())
return NS_ERROR_FAILURE;
NS_ENSURE_ARG(aElem != nsnull);
// We can't allow web apps to call this until we fix at least the
@ -3658,7 +3852,7 @@ NS_IMETHODIMP
nsCanvasRenderingContext2D::GetImageData_explicit(PRInt32 x, PRInt32 y, PRUint32 w, PRUint32 h,
PRUint8 *aData, PRUint32 aDataLen)
{
if (!mValid)
if (!EnsureSurface())
return NS_ERROR_FAILURE;
if (!mCanvasElement && !mDocShell) {
@ -3790,7 +3984,7 @@ nsCanvasRenderingContext2D::PutImageData_explicit(PRInt32 x, PRInt32 y, PRUint32
PRBool hasDirtyRect, PRInt32 dirtyX, PRInt32 dirtyY,
PRInt32 dirtyWidth, PRInt32 dirtyHeight)
{
if (!mValid)
if (!EnsureSurface())
return NS_ERROR_FAILURE;
if (w == 0 || h == 0)
@ -3896,7 +4090,7 @@ nsCanvasRenderingContext2D::PutImageData_explicit(PRInt32 x, PRInt32 y, PRUint32
NS_IMETHODIMP
nsCanvasRenderingContext2D::GetThebesSurface(gfxASurface **surface)
{
if (!mSurface) {
if (!EnsureSurface()) {
*surface = nsnull;
return NS_ERROR_NOT_AVAILABLE;
}
@ -3952,7 +4146,7 @@ nsCanvasRenderingContext2D::GetCanvasLayer(nsDisplayListBuilder* aBuilder,
CanvasLayer *aOldLayer,
LayerManager *aManager)
{
if (!mValid)
if (!EnsureSurface())
return nsnull;
if (!mResetLayer && aOldLayer &&