зеркало из https://github.com/mozilla/gecko-dev.git
Bug 817700 - Make <canvas>.toBlob run asynchronously - canvas changes. r=roc,bz
This commit is contained in:
Родитель
02e4a0f781
Коммит
6ca0edc205
|
@ -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".
|
||||||
//
|
//
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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/ \
|
||||||
|
|
Загрузка…
Ссылка в новой задаче