b=430873; avoid copy when doing canvas-canvas drawImage ops ; r+sr=roc,a=damon

This commit is contained in:
vladimir@pobox.com 2008-04-28 20:49:50 -07:00
Родитель 47bc7d7c61
Коммит bcc2c936d6
4 изменённых файлов: 83 добавлений и 20 удалений

Просмотреть файл

@ -50,6 +50,8 @@ class nsIFrame;
class nsIRenderingContext; class nsIRenderingContext;
class nsICanvasRenderingContextInternal;
struct _cairo_surface; struct _cairo_surface;
class nsICanvasElement : public nsISupports { class nsICanvasElement : public nsISupports {
@ -92,6 +94,13 @@ public:
* is relative to the origin of the canvas frame. * is relative to the origin of the canvas frame.
*/ */
NS_IMETHOD InvalidateFrameSubrect (const nsRect& damageRect) = 0; NS_IMETHOD InvalidateFrameSubrect (const nsRect& damageRect) = 0;
/*
* Get the number of contexts in this canvas, and request a context at
* an index.
*/
virtual PRInt32 CountContexts () = 0;
virtual nsICanvasRenderingContextInternal *GetContextAtIndex (PRInt32 index) = 0;
}; };
NS_DEFINE_STATIC_IID_ACCESSOR(nsICanvasElement, NS_ICANVASELEMENT_IID) NS_DEFINE_STATIC_IID_ACCESSOR(nsICanvasElement, NS_ICANVASELEMENT_IID)

Просмотреть файл

@ -47,6 +47,7 @@
{ 0xeab854fd, 0xaa5e, 0x44bb, { 0x8c, 0xc5, 0x8d, 0x02, 0xf8, 0x4b, 0x02, 0x16 } } { 0xeab854fd, 0xaa5e, 0x44bb, { 0x8c, 0xc5, 0x8d, 0x02, 0xf8, 0x4b, 0x02, 0x16 } }
class gfxContext; class gfxContext;
class gfxASurface;
class nsICanvasRenderingContextInternal : public nsISupports { class nsICanvasRenderingContextInternal : public nsISupports {
public: public:
@ -72,6 +73,10 @@ public:
NS_IMETHOD GetInputStream(const char *aMimeType, NS_IMETHOD GetInputStream(const char *aMimeType,
const PRUnichar *aEncoderOptions, const PRUnichar *aEncoderOptions,
nsIInputStream **aStream) = 0; nsIInputStream **aStream) = 0;
// If this canvas context can be represented with a simple Thebes surface,
// return the surface. Otherwise returns an error.
NS_IMETHOD GetThebesSurface(gfxASurface **surface) = 0;
}; };
NS_DEFINE_STATIC_IID_ACCESSOR(nsICanvasRenderingContextInternal, NS_DEFINE_STATIC_IID_ACCESSOR(nsICanvasRenderingContextInternal,

Просмотреть файл

@ -295,6 +295,7 @@ public:
NS_IMETHOD GetInputStream(const char* aMimeType, NS_IMETHOD GetInputStream(const char* aMimeType,
const PRUnichar* aEncoderOptions, const PRUnichar* aEncoderOptions,
nsIInputStream **aStream); nsIInputStream **aStream);
NS_IMETHOD GetThebesSurface(gfxASurface **surface);
// nsISupports interface // nsISupports interface
NS_DECL_ISUPPORTS NS_DECL_ISUPPORTS
@ -411,8 +412,8 @@ protected:
// cairo helpers // cairo helpers
nsresult CairoSurfaceFromElement(nsIDOMElement *imgElt, nsresult CairoSurfaceFromElement(nsIDOMElement *imgElt,
PRBool forceCopy,
cairo_surface_t **aCairoSurface, cairo_surface_t **aCairoSurface,
PRUint8 **imgDataOut,
PRInt32 *widthOut, PRInt32 *heightOut, PRInt32 *widthOut, PRInt32 *heightOut,
nsIPrincipal **prinOut, nsIPrincipal **prinOut,
PRBool *forceWriteOnlyOut); PRBool *forceWriteOnlyOut);
@ -1089,12 +1090,11 @@ nsCanvasRenderingContext2D::CreatePattern(nsIDOMHTMLElement *image,
} }
cairo_surface_t *imgSurf = nsnull; cairo_surface_t *imgSurf = nsnull;
PRUint8 *imgData = nsnull;
PRInt32 imgWidth, imgHeight; PRInt32 imgWidth, imgHeight;
nsCOMPtr<nsIPrincipal> principal; nsCOMPtr<nsIPrincipal> principal;
PRBool forceWriteOnly = PR_FALSE; PRBool forceWriteOnly = PR_FALSE;
rv = CairoSurfaceFromElement(image, &imgSurf, &imgData, rv = CairoSurfaceFromElement(image, PR_TRUE,
&imgWidth, &imgHeight, &imgSurf, &imgWidth, &imgHeight,
getter_AddRefs(principal), &forceWriteOnly); getter_AddRefs(principal), &forceWriteOnly);
if (NS_FAILED(rv)) if (NS_FAILED(rv))
return rv; return rv;
@ -1918,12 +1918,11 @@ nsCanvasRenderingContext2D::DrawImage()
cairo_matrix_t surfMat; cairo_matrix_t surfMat;
cairo_pattern_t *pat; cairo_pattern_t *pat;
cairo_path_t *old_path; cairo_path_t *old_path;
PRUint8 *imgData = nsnull;
PRInt32 imgWidth, imgHeight; PRInt32 imgWidth, imgHeight;
nsCOMPtr<nsIPrincipal> principal; nsCOMPtr<nsIPrincipal> principal;
PRBool forceWriteOnly = PR_FALSE; PRBool forceWriteOnly = PR_FALSE;
rv = CairoSurfaceFromElement(imgElt, &imgSurf, &imgData, rv = CairoSurfaceFromElement(imgElt, PR_FALSE,
&imgWidth, &imgHeight, &imgSurf, &imgWidth, &imgHeight,
getter_AddRefs(principal), &forceWriteOnly); getter_AddRefs(principal), &forceWriteOnly);
if (NS_FAILED(rv)) if (NS_FAILED(rv))
return rv; return rv;
@ -2154,12 +2153,15 @@ nsCanvasRenderingContext2D::ConvertJSValToXPCObject(nsISupports** aSupports, REF
/* cairo ARGB32 surfaces are ARGB stored as a packed 32-bit integer; on little-endian /* cairo ARGB32 surfaces are ARGB stored as a packed 32-bit integer; on little-endian
* platforms, they appear as BGRA bytes in the surface data. The color values are also * platforms, they appear as BGRA bytes in the surface data. The color values are also
* stored with premultiplied alpha. * stored with premultiplied alpha.
*
* If forceCopy is FALSE, a surface may be returned that's only valid during the current
* operation. If it's TRUE, a copy will always be made that can safely be retained.
*/ */
nsresult nsresult
nsCanvasRenderingContext2D::CairoSurfaceFromElement(nsIDOMElement *imgElt, nsCanvasRenderingContext2D::CairoSurfaceFromElement(nsIDOMElement *imgElt,
PRBool forceCopy,
cairo_surface_t **aCairoSurface, cairo_surface_t **aCairoSurface,
PRUint8 **imgData,
PRInt32 *widthOut, PRInt32 *widthOut,
PRInt32 *heightOut, PRInt32 *heightOut,
nsIPrincipal **prinOut, nsIPrincipal **prinOut,
@ -2198,24 +2200,37 @@ nsCanvasRenderingContext2D::CairoSurfaceFromElement(nsIDOMElement *imgElt,
nsCOMPtr<nsICanvasElement> canvas = do_QueryInterface(imgElt); nsCOMPtr<nsICanvasElement> canvas = do_QueryInterface(imgElt);
nsCOMPtr<nsINode> node = do_QueryInterface(imgElt); nsCOMPtr<nsINode> node = do_QueryInterface(imgElt);
if (canvas && node) { if (canvas && node) {
if (canvas->CountContexts() == 0)
return NS_ERROR_NOT_AVAILABLE;
PRUint32 w, h; PRUint32 w, h;
rv = canvas->GetSize(&w, &h); rv = canvas->GetSize(&w, &h);
NS_ENSURE_SUCCESS(rv, rv); NS_ENSURE_SUCCESS(rv, rv);
nsRefPtr<gfxImageSurface> surf = nsRefPtr<gfxASurface> sourceSurface;
new gfxImageSurface (gfxIntSize(w, h), gfxASurface::ImageFormatARGB32);
if (!forceCopy && canvas->CountContexts() == 1) {
nsICanvasRenderingContextInternal *srcCanvas = canvas->GetContextAtIndex(0);
rv = srcCanvas->GetThebesSurface(getter_AddRefs(sourceSurface));
if (NS_FAILED(rv))
sourceSurface = nsnull;
}
if (sourceSurface == nsnull) {
nsRefPtr<gfxASurface> surf =
gfxPlatform::GetPlatform()->CreateOffscreenSurface
(gfxIntSize(w, h), gfxASurface::ImageFormatARGB32);
nsRefPtr<gfxContext> ctx = new gfxContext(surf); nsRefPtr<gfxContext> ctx = new gfxContext(surf);
ctx->SetOperator(gfxContext::OPERATOR_CLEAR);
ctx->Paint();
ctx->SetOperator(gfxContext::OPERATOR_OVER); ctx->SetOperator(gfxContext::OPERATOR_OVER);
rv = canvas->RenderContexts(ctx); rv = canvas->RenderContexts(ctx);
if (NS_FAILED(rv)) if (NS_FAILED(rv))
return rv; return rv;
sourceSurface = surf;
}
*aCairoSurface = surf->CairoSurface(); *aCairoSurface = sourceSurface->CairoSurface();
cairo_surface_reference(*aCairoSurface); cairo_surface_reference(*aCairoSurface);
*imgData = surf->Data();
*widthOut = w; *widthOut = w;
*heightOut = h; *heightOut = h;
@ -2264,7 +2279,6 @@ nsCanvasRenderingContext2D::CairoSurfaceFromElement(nsIDOMElement *imgElt,
*aCairoSurface = gfxsurf->CairoSurface(); *aCairoSurface = gfxsurf->CairoSurface();
cairo_surface_reference (*aCairoSurface); cairo_surface_reference (*aCairoSurface);
*imgData = nsnull;
return NS_OK; return NS_OK;
} }
@ -2647,3 +2661,18 @@ nsCanvasRenderingContext2D::PutImageData()
return Redraw(); return Redraw();
} }
NS_IMETHODIMP
nsCanvasRenderingContext2D::GetThebesSurface(gfxASurface **surface)
{
if (!mThebesSurface) {
*surface = nsnull;
return NS_ERROR_NOT_AVAILABLE;
}
*surface = mThebesSurface.get();
NS_ADDREF(*surface);
return NS_OK;
}

Просмотреть файл

@ -93,6 +93,8 @@ public:
virtual void SetWriteOnly(); virtual void SetWriteOnly();
NS_IMETHOD InvalidateFrame (); NS_IMETHOD InvalidateFrame ();
NS_IMETHOD InvalidateFrameSubrect (const nsRect& damageRect); NS_IMETHOD InvalidateFrameSubrect (const nsRect& damageRect);
virtual PRInt32 CountContexts();
virtual nsICanvasRenderingContextInternal *GetContextAtIndex (PRInt32 index);
NS_IMETHOD_(PRBool) IsAttributeMapped(const nsIAtom* aAttribute) const; NS_IMETHOD_(PRBool) IsAttributeMapped(const nsIAtom* aAttribute) const;
nsMapRuleToAttributesFunc GetAttributeMappingFunction() const; nsMapRuleToAttributesFunc GetAttributeMappingFunction() const;
@ -553,3 +555,21 @@ nsHTMLCanvasElement::InvalidateFrameSubrect(const nsRect& damageRect)
return NS_OK; return NS_OK;
} }
PRInt32
nsHTMLCanvasElement::CountContexts()
{
if (mCurrentContext)
return 1;
return 0;
}
nsICanvasRenderingContextInternal *
nsHTMLCanvasElement::GetContextAtIndex (PRInt32 index)
{
if (mCurrentContext && index == 0)
return mCurrentContext.get();
return NULL;
}