Backed out changeset 8681fc7a918b (bug 997014)

This commit is contained in:
Carsten "Tomcat" Book 2014-04-17 08:43:38 +02:00
parent c3cc67ccbe
commit 7d7feda648
7 changed files with 125 additions and 42 deletions

View File

@ -14,8 +14,8 @@
#include "mozilla/RefPtr.h"
#define NS_ICANVASRENDERINGCONTEXTINTERNAL_IID \
{ 0x06166dd1, 0xd540, 0x4f29, \
{ 0x91, 0x5c, 0x08, 0x7d, 0xce, 0x1f, 0x79, 0x59 } }
{ 0xf74397d9, 0x25d9, 0x43ed, \
{ 0xb4, 0x6a, 0xf5, 0x4e, 0xa1, 0x17, 0xae, 0x6e } }
class gfxContext;
class gfxASurface;
@ -41,6 +41,10 @@ public:
NS_DECLARE_STATIC_IID_ACCESSOR(NS_ICANVASRENDERINGCONTEXTINTERNAL_IID)
enum {
RenderFlagPremultAlpha = 0x1
};
void SetCanvasElement(mozilla::dom::HTMLCanvasElement* aParentCanvas)
{
mCanvasElement = aParentCanvas;
@ -62,6 +66,11 @@ public:
NS_IMETHOD InitializeWithSurface(nsIDocShell *docShell, gfxASurface *surface, int32_t width, int32_t height) = 0;
// Render the canvas at the origin of the given gfxContext
NS_IMETHOD Render(gfxContext *ctx,
GraphicsFilter aFilter,
uint32_t aFlags = RenderFlagPremultAlpha) = 0;
// Creates an image buffer. Returns null on failure.
virtual void GetImageBuffer(uint8_t** aImageBuffer, int32_t* aFormat) = 0;

View File

@ -1053,6 +1053,51 @@ CanvasRenderingContext2D::SetIsIPC(bool isIPC)
return NS_OK;
}
NS_IMETHODIMP
CanvasRenderingContext2D::Render(gfxContext *ctx, GraphicsFilter aFilter, uint32_t aFlags)
{
nsresult rv = NS_OK;
EnsureTarget();
if (!IsTargetValid()) {
return NS_ERROR_FAILURE;
}
nsRefPtr<gfxASurface> surface;
if (NS_FAILED(GetThebesSurface(getter_AddRefs(surface)))) {
return NS_ERROR_FAILURE;
}
nsRefPtr<gfxPattern> pat = new gfxPattern(surface);
pat->SetFilter(aFilter);
pat->SetExtend(gfxPattern::EXTEND_PAD);
gfxContext::GraphicsOperator op = ctx->CurrentOperator();
if (mOpaque)
ctx->SetOperator(gfxContext::OPERATOR_SOURCE);
// XXX I don't want to use PixelSnapped here, but layout doesn't guarantee
// pixel alignment for this stuff!
ctx->NewPath();
ctx->PixelSnappedRectangleAndSetPattern(gfxRect(0, 0, mWidth, mHeight), pat);
ctx->Fill();
if (mOpaque)
ctx->SetOperator(op);
if (!(aFlags & RenderFlagPremultAlpha)) {
nsRefPtr<gfxASurface> curSurface = ctx->CurrentSurface();
nsRefPtr<gfxImageSurface> gis = curSurface->GetAsImageSurface();
MOZ_ASSERT(gis, "If non-premult alpha, must be able to get image surface!");
gfxUtils::UnpremultiplyImageSurface(gis);
}
return rv;
}
NS_IMETHODIMP
CanvasRenderingContext2D::SetContextOptions(JSContext* aCx, JS::Handle<JS::Value> aOptions)
{

View File

@ -457,6 +457,9 @@ public:
NS_IMETHOD SetDimensions(int32_t width, int32_t height) MOZ_OVERRIDE;
NS_IMETHOD InitializeWithSurface(nsIDocShell *shell, gfxASurface *surface, int32_t width, int32_t height) MOZ_OVERRIDE;
NS_IMETHOD Render(gfxContext *ctx,
GraphicsFilter aFilter,
uint32_t aFlags = RenderFlagPremultAlpha) MOZ_OVERRIDE;
NS_IMETHOD GetInputStream(const char* aMimeType,
const char16_t* aEncoderOptions,
nsIInputStream **aStream) MOZ_OVERRIDE;

View File

@ -625,6 +625,48 @@ WebGLContext::SetDimensions(int32_t width, int32_t height)
return NS_OK;
}
NS_IMETHODIMP
WebGLContext::Render(gfxContext *ctx, GraphicsFilter f, uint32_t aFlags)
{
if (!gl)
return NS_OK;
nsRefPtr<gfxImageSurface> surf = new gfxImageSurface(gfxIntSize(mWidth, mHeight),
gfxImageFormat::ARGB32);
if (surf->CairoStatus() != 0)
return NS_ERROR_FAILURE;
gl->MakeCurrent();
ReadScreenIntoImageSurface(gl, surf);
bool srcPremultAlpha = mOptions.premultipliedAlpha;
bool dstPremultAlpha = aFlags & RenderFlagPremultAlpha;
if (!srcPremultAlpha && dstPremultAlpha) {
gfxUtils::PremultiplyImageSurface(surf);
} else if (srcPremultAlpha && !dstPremultAlpha) {
gfxUtils::UnpremultiplyImageSurface(surf);
}
surf->MarkDirty();
nsRefPtr<gfxPattern> pat = new gfxPattern(surf);
pat->SetFilter(f);
// Pixels from ReadPixels will be "upside down" compared to
// what cairo wants, so draw with a y-flip and a translte to
// flip them.
gfxMatrix m;
m.Translate(gfxPoint(0.0, mHeight));
m.Scale(1.0, -1.0);
pat->SetMatrix(m);
ctx->NewPath();
ctx->PixelSnappedRectangleAndSetPattern(gfxRect(0, 0, mWidth, mHeight), pat);
ctx->Fill();
return NS_OK;
}
void WebGLContext::LoseOldestWebGLContextIfLimitExceeded()
{
#ifdef MOZ_GFX_OPTIMIZE_MOBILE
@ -716,31 +758,25 @@ WebGLContext::GetImageBuffer(uint8_t** aImageBuffer, int32_t* aFormat)
*aImageBuffer = nullptr;
*aFormat = 0;
// Use GetSurfaceSnapshot() to make sure that appropriate y-flip gets applied
bool premult;
RefPtr<SourceSurface> snapshot =
GetSurfaceSnapshot(mOptions.premultipliedAlpha ? nullptr : &premult);
if (!snapshot) {
return;
}
MOZ_ASSERT(mOptions.premultipliedAlpha || !premult, "We must get unpremult when we ask for it!");
nsRefPtr<gfxImageSurface> imgsurf =
new gfxImageSurface(gfxIntSize(mWidth, mHeight),
gfxImageFormat::ARGB32);
RefPtr<DataSourceSurface> dataSurface = snapshot->GetDataSurface();
DataSourceSurface::MappedSurface map;
if (!dataSurface->Map(DataSourceSurface::MapType::READ, &map)) {
if (!imgsurf || imgsurf->CairoStatus()) {
return;
}
static const fallible_t fallible = fallible_t();
uint8_t* imageBuffer = new (fallible) uint8_t[mWidth * mHeight * 4];
if (!imageBuffer) {
dataSurface->Unmap();
nsRefPtr<gfxContext> ctx = new gfxContext(imgsurf);
if (!ctx || ctx->HasError()) {
return;
}
memcpy(imageBuffer, map.mData, mWidth * mHeight * 4);
dataSurface->Unmap();
// 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) {
@ -749,10 +785,17 @@ WebGLContext::GetImageBuffer(uint8_t** aImageBuffer, int32_t* aFormat)
// 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(imageBuffer, mWidth * mHeight * 4);
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;
}
@ -1339,8 +1382,7 @@ WebGLContext::GetSurfaceSnapshot(bool* aPremultAlpha)
return nullptr;
nsRefPtr<gfxImageSurface> surf = new gfxImageSurface(gfxIntSize(mWidth, mHeight),
gfxImageFormat::ARGB32,
mWidth * 4, 0, false);
gfxImageFormat::ARGB32);
if (surf->CairoStatus() != 0) {
return nullptr;
}

View File

@ -165,6 +165,9 @@ public:
{ return NS_ERROR_NOT_IMPLEMENTED; }
NS_IMETHOD Reset() MOZ_OVERRIDE
{ /* (InitializeWithSurface) */ return NS_ERROR_NOT_IMPLEMENTED; }
NS_IMETHOD Render(gfxContext *ctx,
GraphicsFilter f,
uint32_t aFlags = RenderFlagPremultAlpha) MOZ_OVERRIDE;
virtual void GetImageBuffer(uint8_t** aImageBuffer, int32_t* aFormat);
NS_IMETHOD GetInputStream(const char* aMimeType,
const char16_t* aEncoderOptions,

View File

@ -246,24 +246,6 @@ gfxUtils::ConvertBGRAtoRGBA(gfxImageSurface *aSourceSurface,
}
}
void
gfxUtils::ConvertBGRAtoRGBA(uint8_t* aData, uint32_t aLength)
{
uint8_t *src = aData;
uint8_t *srcEnd = src + aLength;
uint8_t buffer[4];
for (; src != srcEnd; src += 4) {
buffer[0] = src[2];
buffer[1] = src[1];
buffer[2] = src[0];
src[0] = buffer[0];
src[1] = buffer[1];
src[2] = buffer[2];
}
}
static bool
IsSafeImageTransformComponent(gfxFloat aValue)
{

View File

@ -48,7 +48,6 @@ public:
static void ConvertBGRAtoRGBA(gfxImageSurface *aSourceSurface,
gfxImageSurface *aDestSurface = nullptr);
static void ConvertBGRAtoRGBA(uint8_t* aData, uint32_t aLength);
/**
* Draw something drawable while working around limitations like bad support