diff --git a/content/canvas/src/CanvasRenderingContext2D.cpp b/content/canvas/src/CanvasRenderingContext2D.cpp index 35c50594a54..eda89dfb323 100644 --- a/content/canvas/src/CanvasRenderingContext2D.cpp +++ b/content/canvas/src/CanvasRenderingContext2D.cpp @@ -75,6 +75,7 @@ #include "mozilla/dom/TypedArray.h" #include "mozilla/gfx/2D.h" #include "mozilla/gfx/PathHelpers.h" +#include "mozilla/gfx/DataSurfaceHelpers.h" #include "mozilla/ipc/DocumentRendererParent.h" #include "mozilla/ipc/PDocumentRendererParent.h" #include "mozilla/MathAlgorithms.h" @@ -1060,40 +1061,20 @@ CanvasRenderingContext2D::GetImageBuffer(uint8_t** aImageBuffer, *aImageBuffer = nullptr; *aFormat = 0; - nsRefPtr surface; - nsresult rv = GetThebesSurface(getter_AddRefs(surface)); - if (NS_FAILED(rv)) { + EnsureTarget(); + RefPtr snapshot = mTarget->Snapshot(); + if (!snapshot) { return; } - static const fallible_t fallible = fallible_t(); - uint8_t* imageBuffer = new (fallible) uint8_t[mWidth * mHeight * 4]; - if (!imageBuffer) { + RefPtr data = snapshot->GetDataSurface(); + if (!data) { return; } - nsRefPtr imgsurf = - new gfxImageSurface(imageBuffer, - gfxIntSize(mWidth, mHeight), - mWidth * 4, - gfxImageFormatARGB32); + MOZ_ASSERT(data->GetSize() == IntSize(mWidth, mHeight)); - if (!imgsurf || imgsurf->CairoStatus()) { - delete[] imageBuffer; - return; - } - - nsRefPtr ctx = new gfxContext(imgsurf); - if (!ctx || ctx->HasError()) { - delete[] imageBuffer; - return; - } - - ctx->SetOperator(gfxContext::OPERATOR_SOURCE); - ctx->SetSource(surface, gfxPoint(0, 0)); - ctx->Paint(); - - *aImageBuffer = imageBuffer; + *aImageBuffer = SurfaceToPackedBGRA(data); *aFormat = imgIEncoder::INPUT_FORMAT_HOSTARGB; } diff --git a/gfx/2d/DataSurfaceHelpers.h b/gfx/2d/DataSurfaceHelpers.h new file mode 100644 index 00000000000..ca4f758a8fd --- /dev/null +++ b/gfx/2d/DataSurfaceHelpers.h @@ -0,0 +1,81 @@ +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#pragma once + +#include "2D.h" +#include "mozilla/mozalloc.h" + +namespace mozilla { +namespace gfx { + +static inline void +ConvertBGRXToBGRA(uint8_t* aData, const IntSize &aSize, int32_t aStride) +{ + uint32_t* pixel = reinterpret_cast(aData); + + for (int row = 0; row < aSize.height; ++row) { + for (int column = 0; column < aSize.width; ++column) { +#ifdef IS_BIG_ENDIAN + pixel[column] |= 0x000000FF; +#else + pixel[column] |= 0xFF000000; +#endif + } + pixel += (aStride/4); + } +} + +/* + * Convert aSurface to a packed buffer in BGRA format. The pixel data is + * returned in a buffer allocated with new uint8_t[]. + */ +inline uint8_t * +SurfaceToPackedBGRA(SourceSurface *aSurface) +{ + RefPtr data = aSurface->GetDataSurface(); + if (!data) { + return nullptr; + } + + SurfaceFormat format = data->GetFormat(); + if (format != FORMAT_B8G8R8A8 && format != FORMAT_B8G8R8X8) { + return nullptr; + } + + IntSize size = data->GetSize(); + static const fallible_t fallible = fallible_t(); + uint8_t* imageBuffer = new (fallible) uint8_t[size.width * size.height * sizeof(uint32_t)]; + if (!imageBuffer) { + return nullptr; + } + + size_t stride = data->Stride(); + + uint32_t* src = reinterpret_cast(data->GetData()); + uint32_t* dst = reinterpret_cast(imageBuffer); + + if (stride == size.width * sizeof(uint32_t)) { + // DataSourceSurface is already packed. We can use memcpy. + memcpy(dst, src, size.width * size.height * sizeof(uint32_t)); + } else { + for (int row = 0; row < size.height; ++row) { + for (int column = 0; column < size.width; ++column) { + *dst++ = src[column]; + } + src += (stride/4); + } + } + + if (format == FORMAT_B8G8R8X8) { + // Convert BGRX to BGRA by setting a to 255. + ConvertBGRXToBGRA(reinterpret_cast(imageBuffer), size, size.width * sizeof(uint32_t)); + } + + return imageBuffer; +} + +} +} diff --git a/gfx/2d/DrawTargetSkia.cpp b/gfx/2d/DrawTargetSkia.cpp index 2c90a1ede33..cdbdc07c6ce 100644 --- a/gfx/2d/DrawTargetSkia.cpp +++ b/gfx/2d/DrawTargetSkia.cpp @@ -25,6 +25,7 @@ #include "Logging.h" #include "HelpersSkia.h" #include "Tools.h" +#include "DataSurfaceHelpers.h" #include namespace mozilla { diff --git a/gfx/2d/HelpersSkia.h b/gfx/2d/HelpersSkia.h index d2cfd6b8538..19b6962c25e 100644 --- a/gfx/2d/HelpersSkia.h +++ b/gfx/2d/HelpersSkia.h @@ -154,19 +154,6 @@ StrokeOptionsToPaint(SkPaint& aPaint, const StrokeOptions &aOptions) return true; } -static inline void -ConvertBGRXToBGRA(unsigned char* aData, const IntSize &aSize, int32_t aStride) -{ - uint32_t* pixel = reinterpret_cast(aData); - - for (int row = 0; row < aSize.height; ++row) { - for (int column = 0; column < aSize.width; ++column) { - pixel[column] |= 0xFF000000; - } - pixel += (aStride/4); - } -} - static inline SkXfermode::Mode GfxOpToSkiaOp(CompositionOp op) { diff --git a/gfx/2d/SourceSurfaceSkia.cpp b/gfx/2d/SourceSurfaceSkia.cpp index c3302f0862a..9e04541c8aa 100644 --- a/gfx/2d/SourceSurfaceSkia.cpp +++ b/gfx/2d/SourceSurfaceSkia.cpp @@ -10,6 +10,7 @@ #include "skia/SkDevice.h" #include "HelpersSkia.h" #include "DrawTargetSkia.h" +#include "DataSurfaceHelpers.h" namespace mozilla { namespace gfx { diff --git a/gfx/2d/moz.build b/gfx/2d/moz.build index 82278ae035d..362996824da 100644 --- a/gfx/2d/moz.build +++ b/gfx/2d/moz.build @@ -20,6 +20,7 @@ EXPORTS.mozilla.gfx += [ 'BaseSize.h', 'Blur.h', 'BorrowedContext.h', + 'DataSurfaceHelpers.h', 'Matrix.h', 'PathHelpers.h', 'Point.h',