Bug 817700 - Make <canvas>.toBlob run asynchronously - canvas changes. r=roc,bz

This commit is contained in:
Stephen Pohl 2013-10-16 22:55:08 -04:00
parent 02e4a0f781
commit 6ca0edc205
9 changed files with 149 additions and 234 deletions

View File

@ -14,8 +14,8 @@
#include "mozilla/RefPtr.h" #include "mozilla/RefPtr.h"
#define NS_ICANVASRENDERINGCONTEXTINTERNAL_IID \ #define NS_ICANVASRENDERINGCONTEXTINTERNAL_IID \
{ 0x8b8da863, 0xd151, 0x4014, \ { 0x9a6a5bdf, 0x1261, 0x4057, \
{ 0x8b, 0xdc, 0x62, 0xb5, 0x0d, 0xc0, 0x2b, 0x62 } } { 0x85, 0xcc, 0xaf, 0x97, 0x6c, 0x36, 0x99, 0xa9 } }
class gfxContext; class gfxContext;
class gfxASurface; class gfxASurface;
@ -71,6 +71,9 @@ public:
GraphicsFilter aFilter, GraphicsFilter aFilter,
uint32_t aFlags = RenderFlagPremultAlpha) = 0; uint32_t aFlags = RenderFlagPremultAlpha) = 0;
// Creates an image buffer. Returns null on failure.
virtual void GetImageBuffer(uint8_t** aImageBuffer, int32_t* aFormat) = 0;
// Gives you a stream containing the image represented by this context. // Gives you a stream containing the image represented by this context.
// The format is given in aMimeTime, for example "image/png". // The format is given in aMimeTime, for example "image/png".
// //

View File

@ -41,7 +41,7 @@
#include "nsTArray.h" #include "nsTArray.h"
#include "imgIEncoder.h" #include "ImageEncoder.h"
#include "gfxContext.h" #include "gfxContext.h"
#include "gfxASurface.h" #include "gfxASurface.h"
@ -1052,71 +1052,71 @@ CanvasRenderingContext2D::Render(gfxContext *ctx, GraphicsFilter aFilter, uint32
return rv; return rv;
} }
NS_IMETHODIMP void
CanvasRenderingContext2D::GetInputStream(const char *aMimeType, CanvasRenderingContext2D::GetImageBuffer(uint8_t** aImageBuffer,
const PRUnichar *aEncoderOptions, int32_t* aFormat)
nsIInputStream **aStream)
{ {
EnsureTarget(); *aImageBuffer = nullptr;
if (!IsTargetValid()) { *aFormat = 0;
return NS_ERROR_FAILURE;
}
nsRefPtr<gfxASurface> surface; nsRefPtr<gfxASurface> surface;
nsresult rv = GetThebesSurface(getter_AddRefs(surface));
if (NS_FAILED(GetThebesSurface(getter_AddRefs(surface)))) { if (NS_FAILED(rv)) {
return NS_ERROR_FAILURE; return;
} }
nsresult rv;
const char encoderPrefix[] = "@mozilla.org/image/encoder;2?type=";
static const fallible_t fallible = fallible_t(); static const fallible_t fallible = fallible_t();
nsAutoArrayPtr<char> conid(new (fallible) char[strlen(encoderPrefix) + strlen(aMimeType) + 1]); uint8_t* imageBuffer = new (fallible) uint8_t[mWidth * mHeight * 4];
if (!conid) {
return NS_ERROR_OUT_OF_MEMORY;
}
strcpy(conid, encoderPrefix);
strcat(conid, aMimeType);
nsCOMPtr<imgIEncoder> encoder = do_CreateInstance(conid);
if (!encoder) {
return NS_ERROR_FAILURE;
}
nsAutoArrayPtr<uint8_t> imageBuffer(new (fallible) uint8_t[mWidth * mHeight * 4]);
if (!imageBuffer) { if (!imageBuffer) {
return NS_ERROR_OUT_OF_MEMORY; return;
} }
nsRefPtr<gfxImageSurface> imgsurf = nsRefPtr<gfxImageSurface> imgsurf =
new gfxImageSurface(imageBuffer.get(), new gfxImageSurface(imageBuffer,
gfxIntSize(mWidth, mHeight), gfxIntSize(mWidth, mHeight),
mWidth * 4, mWidth * 4,
gfxImageFormatARGB32); gfxImageFormatARGB32);
if (!imgsurf || imgsurf->CairoStatus()) { if (!imgsurf || imgsurf->CairoStatus()) {
return NS_ERROR_FAILURE; delete[] imageBuffer;
return;
} }
nsRefPtr<gfxContext> ctx = new gfxContext(imgsurf); nsRefPtr<gfxContext> ctx = new gfxContext(imgsurf);
if (!ctx || ctx->HasError()) { if (!ctx || ctx->HasError()) {
return NS_ERROR_FAILURE; delete[] imageBuffer;
return;
} }
ctx->SetOperator(gfxContext::OPERATOR_SOURCE); ctx->SetOperator(gfxContext::OPERATOR_SOURCE);
ctx->SetSource(surface, gfxPoint(0, 0)); ctx->SetSource(surface, gfxPoint(0, 0));
ctx->Paint(); ctx->Paint();
rv = encoder->InitFromData(imageBuffer.get(), *aImageBuffer = imageBuffer;
mWidth * mHeight * 4, mWidth, mHeight, mWidth * 4, *aFormat = imgIEncoder::INPUT_FORMAT_HOSTARGB;
imgIEncoder::INPUT_FORMAT_HOSTARGB, }
nsDependentString(aEncoderOptions));
NS_ENSURE_SUCCESS(rv, rv);
return CallQueryInterface(encoder, aStream); NS_IMETHODIMP
CanvasRenderingContext2D::GetInputStream(const char *aMimeType,
const PRUnichar *aEncoderOptions,
nsIInputStream **aStream)
{
uint8_t* imageBuffer = nullptr;
int32_t format = 0;
GetImageBuffer(&imageBuffer, &format);
if (!imageBuffer) {
return NS_ERROR_FAILURE;
}
nsCString enccid("@mozilla.org/image/encoder;2?type=");
enccid += aMimeType;
nsCOMPtr<imgIEncoder> encoder = do_CreateInstance(enccid.get());
if (!encoder) {
return NS_ERROR_FAILURE;
}
return ImageEncoder::GetInputStream(mWidth, mHeight, imageBuffer, format,
encoder, aEncoderOptions, aStream);
} }
SurfaceFormat SurfaceFormat
@ -3817,6 +3817,9 @@ NS_IMETHODIMP
CanvasRenderingContext2D::GetThebesSurface(gfxASurface **surface) CanvasRenderingContext2D::GetThebesSurface(gfxASurface **surface)
{ {
EnsureTarget(); EnsureTarget();
if (!IsTargetValid()) {
return NS_ERROR_FAILURE;
}
nsRefPtr<gfxASurface> thebesSurface = nsRefPtr<gfxASurface> thebesSurface =
gfxPlatform::GetPlatform()->GetThebesSurfaceForDrawTarget(mTarget); gfxPlatform::GetPlatform()->GetThebesSurfaceForDrawTarget(mTarget);

View File

@ -22,6 +22,7 @@
#include "mozilla/gfx/Rect.h" #include "mozilla/gfx/Rect.h"
#include "mozilla/gfx/2D.h" #include "mozilla/gfx/2D.h"
#include "gfx2DGlue.h" #include "gfx2DGlue.h"
#include "imgIEncoder.h"
class nsXULElement; class nsXULElement;
@ -460,6 +461,8 @@ public:
friend class CanvasRenderingContext2DUserData; friend class CanvasRenderingContext2DUserData;
virtual void GetImageBuffer(uint8_t** aImageBuffer, int32_t* aFormat);
protected: protected:
nsresult GetImageDataArray(JSContext* aCx, int32_t aX, int32_t aY, nsresult GetImageDataArray(JSContext* aCx, int32_t aX, int32_t aY,
uint32_t aWidth, uint32_t aHeight, uint32_t aWidth, uint32_t aHeight,

View File

@ -22,5 +22,6 @@ INCLUDES += \
-I$(srcdir)/../../html/content/src \ -I$(srcdir)/../../html/content/src \
-I$(srcdir)/../../../js/xpconnect/src \ -I$(srcdir)/../../../js/xpconnect/src \
-I$(srcdir)/../../../dom/base \ -I$(srcdir)/../../../dom/base \
-I$(srcdir)/../../../image/src \
-I$(topsrcdir)/content/xul/content/src \ -I$(topsrcdir)/content/xul/content/src \
$(NULL) $(NULL)

View File

@ -27,7 +27,7 @@
#include "nsIVariant.h" #include "nsIVariant.h"
#include "imgIEncoder.h" #include "ImageEncoder.h"
#include "gfxContext.h" #include "gfxContext.h"
#include "gfxPattern.h" #include "gfxPattern.h"
@ -735,6 +735,54 @@ void WebGLContext::LoseOldestWebGLContextIfLimitExceeded()
} }
} }
void
WebGLContext::GetImageBuffer(uint8_t** aImageBuffer, int32_t* aFormat)
{
*aImageBuffer = nullptr;
*aFormat = 0;
nsRefPtr<gfxImageSurface> imgsurf =
new gfxImageSurface(gfxIntSize(mWidth, mHeight),
gfxImageFormatARGB32);
if (!imgsurf || imgsurf->CairoStatus()) {
return;
}
nsRefPtr<gfxContext> ctx = new gfxContext(imgsurf);
if (!ctx || ctx->HasError()) {
return;
}
// Use Render() to make sure that appropriate y-flip gets applied
uint32_t flags = mOptions.premultipliedAlpha ? RenderFlagPremultAlpha : 0;
nsresult rv = Render(ctx, GraphicsFilter::FILTER_NEAREST, flags);
if (NS_FAILED(rv)) {
return;
}
int32_t format = imgIEncoder::INPUT_FORMAT_HOSTARGB;
if (!mOptions.premultipliedAlpha) {
// We need to convert to INPUT_FORMAT_RGBA, otherwise
// we are automatically considered premult, and unpremult'd.
// Yes, it is THAT silly.
// Except for different lossy conversions by color,
// we could probably just change the label, and not change the data.
gfxUtils::ConvertBGRAtoRGBA(imgsurf);
format = imgIEncoder::INPUT_FORMAT_RGBA;
}
static const fallible_t fallible = fallible_t();
uint8_t* imageBuffer = new (fallible) uint8_t[mWidth * mHeight * 4];
if (!imageBuffer) {
return;
}
memcpy(imageBuffer, imgsurf->Data(), mWidth * mHeight * 4);
*aImageBuffer = imageBuffer;
*aFormat = format;
}
NS_IMETHODIMP NS_IMETHODIMP
WebGLContext::GetInputStream(const char* aMimeType, WebGLContext::GetInputStream(const char* aMimeType,
const PRUnichar* aEncoderOptions, const PRUnichar* aEncoderOptions,
@ -744,48 +792,22 @@ WebGLContext::GetInputStream(const char* aMimeType,
if (!gl) if (!gl)
return NS_ERROR_FAILURE; return NS_ERROR_FAILURE;
nsRefPtr<gfxImageSurface> surf = new gfxImageSurface(gfxIntSize(mWidth, mHeight), uint8_t* imageBuffer = nullptr;
gfxImageFormatARGB32); int32_t format = 0;
if (surf->CairoStatus() != 0) GetImageBuffer(&imageBuffer, &format);
if (!imageBuffer) {
return NS_ERROR_FAILURE; return NS_ERROR_FAILURE;
nsRefPtr<gfxContext> tmpcx = new gfxContext(surf);
// Use Render() to make sure that appropriate y-flip gets applied
uint32_t flags = mOptions.premultipliedAlpha ? RenderFlagPremultAlpha : 0;
nsresult rv = Render(tmpcx, GraphicsFilter::FILTER_NEAREST, flags);
if (NS_FAILED(rv))
return rv;
const char encoderPrefix[] = "@mozilla.org/image/encoder;2?type=";
nsAutoArrayPtr<char> conid(new char[strlen(encoderPrefix) + strlen(aMimeType) + 1]);
strcpy(conid, encoderPrefix);
strcat(conid, aMimeType);
nsCOMPtr<imgIEncoder> encoder = do_CreateInstance(conid);
if (!encoder)
return NS_ERROR_FAILURE;
int format = imgIEncoder::INPUT_FORMAT_HOSTARGB;
if (!mOptions.premultipliedAlpha) {
// We need to convert to INPUT_FORMAT_RGBA, otherwise
// we are automatically considered premult, and unpremult'd.
// Yes, it is THAT silly.
// Except for different lossy conversions by color,
// we could probably just change the label, and not change the data.
gfxUtils::ConvertBGRAtoRGBA(surf);
format = imgIEncoder::INPUT_FORMAT_RGBA;
} }
rv = encoder->InitFromData(surf->Data(), nsCString enccid("@mozilla.org/image/encoder;2?type=");
mWidth * mHeight * 4, enccid += aMimeType;
mWidth, mHeight, nsCOMPtr<imgIEncoder> encoder = do_CreateInstance(enccid.get());
surf->Stride(), if (!encoder) {
format, return NS_ERROR_FAILURE;
nsDependentString(aEncoderOptions)); }
NS_ENSURE_SUCCESS(rv, rv);
return CallQueryInterface(encoder, aStream); return ImageEncoder::GetInputStream(mWidth, mHeight, imageBuffer, format,
encoder, aEncoderOptions, aStream);
} }
NS_IMETHODIMP NS_IMETHODIMP

View File

@ -167,6 +167,7 @@ public:
NS_IMETHOD Render(gfxContext *ctx, NS_IMETHOD Render(gfxContext *ctx,
GraphicsFilter f, GraphicsFilter f,
uint32_t aFlags = RenderFlagPremultAlpha) MOZ_OVERRIDE; uint32_t aFlags = RenderFlagPremultAlpha) MOZ_OVERRIDE;
virtual void GetImageBuffer(uint8_t** aImageBuffer, int32_t* aFormat);
NS_IMETHOD GetInputStream(const char* aMimeType, NS_IMETHOD GetInputStream(const char* aMimeType,
const PRUnichar* aEncoderOptions, const PRUnichar* aEncoderOptions,
nsIInputStream **aStream) MOZ_OVERRIDE; nsIInputStream **aStream) MOZ_OVERRIDE;

View File

@ -227,10 +227,9 @@ protected:
const JS::Value& aEncoderOptions, const JS::Value& aEncoderOptions,
nsAString& aParams, nsAString& aParams,
bool* usingCustomParseOptions); bool* usingCustomParseOptions);
nsresult ExtractData(const nsAString& aType, nsresult ExtractData(nsAString& aType,
const nsAString& aOptions, const nsAString& aOptions,
nsIInputStream** aStream, nsIInputStream** aStream);
bool& aFellBackToPNG);
nsresult ToDataURLImpl(JSContext* aCx, nsresult ToDataURLImpl(JSContext* aCx,
const nsAString& aMimeType, const nsAString& aMimeType,
const JS::Value& aEncoderOptions, const JS::Value& aEncoderOptions,

View File

@ -5,11 +5,11 @@
#include "mozilla/dom/HTMLCanvasElement.h" #include "mozilla/dom/HTMLCanvasElement.h"
#include "Layers.h" #include "ImageEncoder.h"
#include "imgIEncoder.h"
#include "jsapi.h" #include "jsapi.h"
#include "jsfriendapi.h" #include "jsfriendapi.h"
#include "gfxImageSurface.h" #include "gfxImageSurface.h"
#include "Layers.h"
#include "mozilla/Base64.h" #include "mozilla/Base64.h"
#include "mozilla/CheckedInt.h" #include "mozilla/CheckedInt.h"
#include "mozilla/dom/CanvasRenderingContext2D.h" #include "mozilla/dom/CanvasRenderingContext2D.h"
@ -23,6 +23,7 @@
#include "nsContentUtils.h" #include "nsContentUtils.h"
#include "nsDisplayList.h" #include "nsDisplayList.h"
#include "nsDOMFile.h" #include "nsDOMFile.h"
#include "nsDOMJSUtils.h"
#include "nsFrameManager.h" #include "nsFrameManager.h"
#include "nsIScriptSecurityManager.h" #include "nsIScriptSecurityManager.h"
#include "nsITimer.h" #include "nsITimer.h"
@ -46,29 +47,6 @@ namespace {
typedef mozilla::dom::HTMLImageElementOrHTMLCanvasElementOrHTMLVideoElement typedef mozilla::dom::HTMLImageElementOrHTMLCanvasElementOrHTMLVideoElement
HTMLImageOrCanvasOrVideoElement; HTMLImageOrCanvasOrVideoElement;
class ToBlobRunnable : public nsRunnable
{
public:
ToBlobRunnable(mozilla::dom::FileCallback& aCallback,
nsIDOMBlob* aBlob)
: mCallback(&aCallback),
mBlob(aBlob)
{
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
}
NS_IMETHOD Run()
{
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
mozilla::ErrorResult rv;
mCallback->Call(mBlob, rv);
return rv.ErrorCode();
}
private:
nsRefPtr<mozilla::dom::FileCallback> mCallback;
nsCOMPtr<nsIDOMBlob> mBlob;
};
} // anonymous namespace } // anonymous namespace
namespace mozilla { namespace mozilla {
@ -369,10 +347,10 @@ HTMLCanvasElement::MozFetchAsStream(nsIInputStreamCallback *aCallback,
return NS_ERROR_FAILURE; return NS_ERROR_FAILURE;
nsresult rv; nsresult rv;
bool fellBackToPNG = false;
nsCOMPtr<nsIInputStream> inputData; nsCOMPtr<nsIInputStream> inputData;
rv = ExtractData(aType, EmptyString(), getter_AddRefs(inputData), fellBackToPNG); nsAutoString type(aType);
rv = ExtractData(type, EmptyString(), getter_AddRefs(inputData));
NS_ENSURE_SUCCESS(rv, rv); NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIAsyncInputStream> asyncData = do_QueryInterface(inputData, &rv); nsCOMPtr<nsIAsyncInputStream> asyncData = do_QueryInterface(inputData, &rv);
@ -404,68 +382,15 @@ HTMLCanvasElement::GetMozPrintCallback() const
} }
nsresult nsresult
HTMLCanvasElement::ExtractData(const nsAString& aType, HTMLCanvasElement::ExtractData(nsAString& aType,
const nsAString& aOptions, const nsAString& aOptions,
nsIInputStream** aStream, nsIInputStream** aStream)
bool& aFellBackToPNG)
{ {
// note that if we don't have a current context, the spec says we're return ImageEncoder::ExtractData(aType,
// supposed to just return transparent black pixels of the canvas aOptions,
// dimensions. GetSize(),
nsRefPtr<gfxImageSurface> emptyCanvas; mCurrentContext,
nsIntSize size = GetWidthHeight(); aStream);
if (!mCurrentContext) {
emptyCanvas = new gfxImageSurface(gfxIntSize(size.width, size.height), gfxImageFormatARGB32);
if (emptyCanvas->CairoStatus()) {
return NS_ERROR_INVALID_ARG;
}
}
nsresult rv;
// get image bytes
nsCOMPtr<nsIInputStream> imgStream;
NS_ConvertUTF16toUTF8 encoderType(aType);
try_again:
if (mCurrentContext) {
rv = mCurrentContext->GetInputStream(encoderType.get(),
nsPromiseFlatString(aOptions).get(),
getter_AddRefs(imgStream));
} else {
// no context, so we have to encode the empty image we created above
nsCString enccid("@mozilla.org/image/encoder;2?type=");
enccid += encoderType;
nsCOMPtr<imgIEncoder> encoder = do_CreateInstance(enccid.get(), &rv);
if (NS_SUCCEEDED(rv) && encoder) {
rv = encoder->InitFromData(emptyCanvas->Data(),
size.width * size.height * 4,
size.width,
size.height,
size.width * 4,
imgIEncoder::INPUT_FORMAT_HOSTARGB,
aOptions);
if (NS_SUCCEEDED(rv)) {
imgStream = do_QueryInterface(encoder);
}
} else {
rv = NS_ERROR_FAILURE;
}
}
if (NS_FAILED(rv) && !aFellBackToPNG) {
// Try image/png instead.
// XXX ERRMSG we need to report an error to developers here! (bug 329026)
aFellBackToPNG = true;
encoderType.AssignLiteral("image/png");
goto try_again;
}
NS_ENSURE_SUCCESS(rv, rv);
imgStream.forget(aStream);
return NS_OK;
} }
nsresult nsresult
@ -516,8 +441,6 @@ HTMLCanvasElement::ToDataURLImpl(JSContext* aCx,
const JS::Value& aEncoderOptions, const JS::Value& aEncoderOptions,
nsAString& aDataURL) nsAString& aDataURL)
{ {
bool fallbackToPNG = false;
nsIntSize size = GetWidthHeight(); nsIntSize size = GetWidthHeight();
if (size.height == 0 || size.width == 0) { if (size.height == 0 || size.width == 0) {
aDataURL = NS_LITERAL_STRING("data:,"); aDataURL = NS_LITERAL_STRING("data:,");
@ -538,23 +461,18 @@ HTMLCanvasElement::ToDataURLImpl(JSContext* aCx,
} }
nsCOMPtr<nsIInputStream> stream; nsCOMPtr<nsIInputStream> stream;
rv = ExtractData(type, params, getter_AddRefs(stream), fallbackToPNG); rv = ExtractData(type, params, getter_AddRefs(stream));
// If there are unrecognized custom parse options, we should fall back to // If there are unrecognized custom parse options, we should fall back to
// the default values for the encoder without any options at all. // the default values for the encoder without any options at all.
if (rv == NS_ERROR_INVALID_ARG && usingCustomParseOptions) { if (rv == NS_ERROR_INVALID_ARG && usingCustomParseOptions) {
fallbackToPNG = false; rv = ExtractData(type, EmptyString(), getter_AddRefs(stream));
rv = ExtractData(type, EmptyString(), getter_AddRefs(stream), fallbackToPNG);
} }
NS_ENSURE_SUCCESS(rv, rv); NS_ENSURE_SUCCESS(rv, rv);
// build data URL string // build data URL string
if (fallbackToPNG) aDataURL = NS_LITERAL_STRING("data:") + type + NS_LITERAL_STRING(";base64,");
aDataURL = NS_LITERAL_STRING("data:image/png;base64,");
else
aDataURL = NS_LITERAL_STRING("data:") + type +
NS_LITERAL_STRING(";base64,");
uint64_t count; uint64_t count;
rv = stream->Available(&count); rv = stream->Available(&count);
@ -564,7 +482,6 @@ HTMLCanvasElement::ToDataURLImpl(JSContext* aCx,
return Base64EncodeInputStream(stream, aDataURL, (uint32_t)count, aDataURL.Length()); return Base64EncodeInputStream(stream, aDataURL, (uint32_t)count, aDataURL.Length());
} }
// XXXkhuey the encoding should be off the main thread, but we're lazy.
void void
HTMLCanvasElement::ToBlob(JSContext* aCx, HTMLCanvasElement::ToBlob(JSContext* aCx,
FileCallback& aCallback, FileCallback& aCallback,
@ -608,52 +525,24 @@ HTMLCanvasElement::ToBlob(JSContext* aCx,
} }
#endif #endif
bool fallbackToPNG = false; nsCOMPtr<nsIScriptContext> scriptContext =
GetScriptContextFromJSContext(nsContentUtils::GetCurrentJSContext());
nsCOMPtr<nsIInputStream> stream; uint8_t* imageBuffer = nullptr;
aRv = ExtractData(type, params, getter_AddRefs(stream), fallbackToPNG); int32_t format = 0;
// If there are unrecognized custom parse options, we should fall back to if (mCurrentContext) {
// the default values for the encoder without any options at all. mCurrentContext->GetImageBuffer(&imageBuffer, &format);
if (aRv.ErrorCode() == NS_ERROR_INVALID_ARG && usingCustomParseOptions) {
fallbackToPNG = false;
aRv = ExtractData(type, EmptyString(), getter_AddRefs(stream), fallbackToPNG);
} }
if (aRv.Failed()) { aRv = ImageEncoder::ExtractDataAsync(type,
return; params,
} usingCustomParseOptions,
imageBuffer,
if (fallbackToPNG) { format,
type.AssignLiteral("image/png"); GetSize(),
} mCurrentContext,
scriptContext,
uint64_t imgSize; aCallback);
aRv = stream->Available(&imgSize);
if (aRv.Failed()) {
return;
}
if (imgSize > UINT32_MAX) {
aRv.Throw(NS_ERROR_FILE_TOO_BIG);
return;
}
void* imgData = nullptr;
aRv = NS_ReadInputStreamToBuffer(stream, &imgData, imgSize);
if (aRv.Failed()) {
return;
}
// The DOMFile takes ownership of the buffer
nsRefPtr<nsDOMMemoryFile> blob =
new nsDOMMemoryFile(imgData, imgSize, type);
JSContext* cx = nsContentUtils::GetCurrentJSContext();
if (cx) {
JS_updateMallocCounter(cx, imgSize);
}
nsRefPtr<ToBlobRunnable> runnable = new ToBlobRunnable(aCallback, blob);
aRv = NS_DispatchToCurrentThread(runnable);
} }
already_AddRefed<nsIDOMFile> already_AddRefed<nsIDOMFile>
@ -687,17 +576,10 @@ HTMLCanvasElement::MozGetAsFileImpl(const nsAString& aName,
const nsAString& aType, const nsAString& aType,
nsIDOMFile** aResult) nsIDOMFile** aResult)
{ {
bool fallbackToPNG = false;
nsCOMPtr<nsIInputStream> stream; nsCOMPtr<nsIInputStream> stream;
nsresult rv = ExtractData(aType, EmptyString(), getter_AddRefs(stream),
fallbackToPNG);
NS_ENSURE_SUCCESS(rv, rv);
nsAutoString type(aType); nsAutoString type(aType);
if (fallbackToPNG) { nsresult rv = ExtractData(type, EmptyString(), getter_AddRefs(stream));
type.AssignLiteral("image/png"); NS_ENSURE_SUCCESS(rv, rv);
}
uint64_t imgSize; uint64_t imgSize;
rv = stream->Available(&imgSize); rv = stream->Available(&imgSize);

View File

@ -22,6 +22,7 @@ INCLUDES += \
-I$(srcdir)/../../../../editor/libeditor/text \ -I$(srcdir)/../../../../editor/libeditor/text \
-I$(srcdir)/../../../../editor/txmgr/src \ -I$(srcdir)/../../../../editor/txmgr/src \
-I$(srcdir)/../../../../netwerk/base/src \ -I$(srcdir)/../../../../netwerk/base/src \
-I$(srcdir)/../../../../content/canvas/src \
-I$(srcdir) \ -I$(srcdir) \
-I$(topsrcdir)/xpcom/ds \ -I$(topsrcdir)/xpcom/ds \
-I$(topsrcdir)/content/media/ \ -I$(topsrcdir)/content/media/ \