aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar commit-bot@chromium.org <commit-bot@chromium.org@2bbb7eff-a529-9590-31e7-b0007b416f81>2014-03-07 03:25:16 +0000
committerGravatar commit-bot@chromium.org <commit-bot@chromium.org@2bbb7eff-a529-9590-31e7-b0007b416f81>2014-03-07 03:25:16 +0000
commit4cd9e2169e35cd67ee7358acea6541245e1d1744 (patch)
tree6e78d84ef91181b41f5c45a73bab003c63780f10
parenta5572e5bb2a2bbeeb59de0741c2527869d365a0c (diff)
Add SkCanvas::writePixels that takes info+pixels directly
add corresponding methods to device (w/ diff name to avoid colliding with exising virtuals) BUG=skia: R=bsalomon@google.com, robertphillips@google.com, junov@google.com, junov@chromium.org Author: reed@google.com Review URL: https://codereview.chromium.org/180113010 git-svn-id: http://skia.googlecode.com/svn/trunk@13697 2bbb7eff-a529-9590-31e7-b0007b416f81
-rw-r--r--bench/PremulAndUnpremulAlphaOpsBench.cpp11
-rw-r--r--bench/WritePixelsBench.cpp56
-rw-r--r--gyp/bench.gyp2
-rw-r--r--gyp/bench.gypi1
-rw-r--r--gyp/skia_for_chromium_defines.gypi1
-rw-r--r--gyp/tests.gypi2
-rw-r--r--include/core/SkBitmapDevice.h8
-rw-r--r--include/core/SkCanvas.h35
-rw-r--r--include/core/SkDevice.h14
-rw-r--r--include/gpu/SkGpuDevice.h9
-rw-r--r--src/core/SkBitmapDevice.cpp91
-rw-r--r--src/core/SkCanvas.cpp57
-rw-r--r--src/core/SkConfig8888.h5
-rw-r--r--src/core/SkDevice.cpp24
-rw-r--r--src/gpu/SkGpuDevice.cpp21
-rw-r--r--src/utils/SkDeferredCanvas.cpp31
-rw-r--r--src/utils/SkGatherPixelRefsAndRects.h2
-rw-r--r--src/utils/SkPictureUtils.cpp3
-rw-r--r--tests/DeferredCanvasTest.cpp37
-rw-r--r--tests/PremulAlphaRoundTripTest.cpp85
-rw-r--r--tests/WritePixelsTest.cpp15
-rw-r--r--tools/sk_tool_utils.cpp48
-rw-r--r--tools/sk_tool_utils.h28
23 files changed, 493 insertions, 93 deletions
diff --git a/bench/PremulAndUnpremulAlphaOpsBench.cpp b/bench/PremulAndUnpremulAlphaOpsBench.cpp
index 93c84c9095..4afa43fe6e 100644
--- a/bench/PremulAndUnpremulAlphaOpsBench.cpp
+++ b/bench/PremulAndUnpremulAlphaOpsBench.cpp
@@ -1,4 +1,3 @@
-
/*
* Copyright 2013 Google Inc.
*
@@ -10,6 +9,7 @@
#include "SkCanvas.h"
#include "SkConfig8888.h"
#include "SkString.h"
+#include "sk_tool_utils.h"
class PremulAndUnpremulAlphaOpsBench : public SkBenchmark {
public:
@@ -45,9 +45,16 @@ protected:
bmp2.setConfig(SkBitmap::kARGB_8888_Config, size.width(),
size.height());
+ SkColorType ct;
+ SkAlphaType at;
+ sk_tool_utils::config8888_to_imagetypes(fUnPremulConfig, &ct, &at);
+ if (bmp1.isOpaque()) {
+ at = kOpaque_SkAlphaType;
+ }
+
for (int loop = 0; loop < loops; ++loop) {
// Unpremul -> Premul
- canvas->writePixels(bmp1, 0, 0, fUnPremulConfig);
+ sk_tool_utils::write_pixels(canvas, bmp1, 0, 0, ct, at);
// Premul -> Unpremul
canvas->readPixels(&bmp2, 0, 0, fUnPremulConfig);
}
diff --git a/bench/WritePixelsBench.cpp b/bench/WritePixelsBench.cpp
index 0313846a3b..27c3f5a45b 100644
--- a/bench/WritePixelsBench.cpp
+++ b/bench/WritePixelsBench.cpp
@@ -1,4 +1,3 @@
-
/*
* Copyright 2013 Google Inc.
*
@@ -8,35 +7,35 @@
#include "SkBenchmark.h"
#include "SkCanvas.h"
-#include "SkConfig8888.h"
#include "SkString.h"
class WritePixelsBench : public SkBenchmark {
public:
- WritePixelsBench(SkCanvas::Config8888 config)
- : fConfig(config)
- , fName("writepix") {
- switch (config) {
- case SkCanvas::kNative_Premul_Config8888:
- fName.append("_native_PM");
- break;
- case SkCanvas::kNative_Unpremul_Config8888:
- fName.append("_native_UPM");
+ WritePixelsBench(SkColorType ct, SkAlphaType at)
+ : fColorType(ct)
+ , fAlphaType(at)
+ , fName("writepix")
+ {
+ switch (ct) {
+ case kRGBA_8888_SkColorType:
+ fName.append("_RGBA");
break;
- case SkCanvas::kBGRA_Premul_Config8888:
- fName.append("_bgra_PM");
+ case kBGRA_8888_SkColorType:
+ fName.append("_BGRA");
break;
- case SkCanvas::kBGRA_Unpremul_Config8888:
- fName.append("_bgra_UPM");
+ default:
+ SkASSERT(0);
break;
- case SkCanvas::kRGBA_Premul_Config8888:
- fName.append("_rgba_PM");
+ }
+ switch (at) {
+ case kPremul_SkAlphaType:
+ fName.append("_PM");
break;
- case SkCanvas::kRGBA_Unpremul_Config8888:
- fName.append("_rgba_UPM");
+ case kUnpremul_SkAlphaType:
+ fName.append("_UPM");
break;
default:
- SK_CRASH();
+ SkASSERT(0);
break;
}
}
@@ -52,22 +51,27 @@ protected:
canvas->clear(0xFFFF0000);
SkBitmap bmp;
- bmp.setConfig(SkBitmap::kARGB_8888_Config, size.width(), size.height());
+ bmp.allocN32Pixels(size.width(), size.height());
canvas->readPixels(&bmp, 0, 0);
+ SkImageInfo info = bmp.info();
+ info.fColorType = fColorType;
+ info.fAlphaType = fAlphaType;
+
for (int loop = 0; loop < loops; ++loop) {
- canvas->writePixels(bmp, 0, 0, fConfig);
+ canvas->writePixels(info, bmp.getPixels(), bmp.rowBytes(), 0, 0);
}
}
private:
- SkCanvas::Config8888 fConfig;
- SkString fName;
+ SkColorType fColorType;
+ SkAlphaType fAlphaType;
+ SkString fName;
typedef SkBenchmark INHERITED;
};
//////////////////////////////////////////////////////////////////////////////
-DEF_BENCH( return SkNEW_ARGS(WritePixelsBench, (SkCanvas::kRGBA_Premul_Config8888)); )
-DEF_BENCH( return SkNEW_ARGS(WritePixelsBench, (SkCanvas::kRGBA_Unpremul_Config8888)); )
+DEF_BENCH( return SkNEW_ARGS(WritePixelsBench, (kRGBA_8888_SkColorType, kPremul_SkAlphaType)); )
+DEF_BENCH( return SkNEW_ARGS(WritePixelsBench, (kRGBA_8888_SkColorType, kUnpremul_SkAlphaType)); )
diff --git a/gyp/bench.gyp b/gyp/bench.gyp
index c2337f6bba..43924ab30a 100644
--- a/gyp/bench.gyp
+++ b/gyp/bench.gyp
@@ -20,6 +20,7 @@
'../bench/SkGMBench.cpp',
'../bench/SkGMBench.h',
'../bench/benchmain.cpp',
+ '../tools/sk_tool_utils.cpp',
],
'conditions': [
['skia_gpu == 1',
@@ -54,6 +55,7 @@
'include_dirs': [
'../src/core',
'../src/gpu',
+ '../tools',
],
'dependencies': [
'skia_lib.gyp:skia_lib',
diff --git a/gyp/bench.gypi b/gyp/bench.gypi
index 8170d81fc3..6680e75289 100644
--- a/gyp/bench.gypi
+++ b/gyp/bench.gypi
@@ -3,6 +3,7 @@
'../src/core',
'../src/effects',
'../src/utils',
+ '../tools',
],
'dependencies': [
'skia_lib.gyp:skia_lib',
diff --git a/gyp/skia_for_chromium_defines.gypi b/gyp/skia_for_chromium_defines.gypi
index de026ae4f2..35877431b0 100644
--- a/gyp/skia_for_chromium_defines.gypi
+++ b/gyp/skia_for_chromium_defines.gypi
@@ -16,6 +16,7 @@
'SK_SUPPORT_LEGACY_COMPATIBLEDEVICE_CONFIG=1',
'SK_SUPPORT_LEGACY_PUBLICEFFECTCONSTRUCTORS=1',
'SK_SUPPORT_LEGACY_COPYTO_CONFIG',
+ 'SK_SUPPORT_LEGACY_WRITEPIXELSCONFIG',
],
},
}
diff --git a/gyp/tests.gypi b/gyp/tests.gypi
index 6990464279..80bd380886 100644
--- a/gyp/tests.gypi
+++ b/gyp/tests.gypi
@@ -179,5 +179,7 @@
'../tests/TDStackNesterTest.cpp',
'../experimental/PdfViewer/src/SkTDStackNester.h',
+
+ '../tools/sk_tool_utils.cpp',
],
}
diff --git a/include/core/SkBitmapDevice.h b/include/core/SkBitmapDevice.h
index 1d181555e0..a34507134d 100644
--- a/include/core/SkBitmapDevice.h
+++ b/include/core/SkBitmapDevice.h
@@ -86,6 +86,7 @@ public:
virtual SkImageInfo imageInfo() const SK_OVERRIDE;
+#ifdef SK_SUPPORT_LEGACY_WRITEPIXELSCONFIG
/**
* DEPRECATED: This will be made protected once WebKit stops using it.
* Instead use Canvas' writePixels method.
@@ -103,7 +104,7 @@ public:
*/
virtual void writePixels(const SkBitmap& bitmap, int x, int y,
SkCanvas::Config8888 config8888) SK_OVERRIDE;
-
+#endif
/**
* Return the device's associated gpu render target, or NULL.
*/
@@ -215,9 +216,8 @@ protected:
* 3. The rectangle (x, y, x + bitmap->width(), y + bitmap->height()) is
* contained in the device bounds.
*/
- virtual bool onReadPixels(const SkBitmap& bitmap,
- int x, int y,
- SkCanvas::Config8888 config8888) SK_OVERRIDE;
+ virtual bool onReadPixels(const SkBitmap&, int x, int y, SkCanvas::Config8888) SK_OVERRIDE;
+ virtual bool onWritePixels(const SkImageInfo&, const void*, size_t, int, int) SK_OVERRIDE;
/** Called when this device is installed into a Canvas. Balanced by a call
to unlockPixels() when the device is removed from a Canvas.
diff --git a/include/core/SkCanvas.h b/include/core/SkCanvas.h
index b646ba4024..a987708c42 100644
--- a/include/core/SkCanvas.h
+++ b/include/core/SkCanvas.h
@@ -18,6 +18,8 @@
#include "SkRegion.h"
#include "SkXfermode.h"
+//#define SK_SUPPORT_LEGACY_WRITEPIXELSCONFIG
+
class SkBounder;
class SkBaseDevice;
class SkDraw;
@@ -264,7 +266,9 @@ public:
*/
bool readPixels(const SkIRect& srcRect, SkBitmap* bitmap);
+#ifdef SK_SUPPORT_LEGACY_WRITEPIXELSCONFIG
/**
+ * DEPRECATED
* Similar to draw sprite, this method will copy the pixels in bitmap onto
* the canvas, with the top/left corner specified by (x, y). The canvas'
* pixel values are completely replaced: there is no blending.
@@ -279,9 +283,34 @@ public:
* Note: If you are recording drawing commands on this canvas to
* SkPicture, writePixels() is ignored!
*/
- void writePixels(const SkBitmap& bitmap,
- int x, int y,
- Config8888 config8888 = kNative_Premul_Config8888);
+ void writePixels(const SkBitmap& bitmap, int x, int y, Config8888 config8888);
+#endif
+
+ /**
+ * This method affects the pixels in the base-layer, and operates in pixel coordinates,
+ * ignoring the matrix and clip.
+ *
+ * The specified ImageInfo and (x,y) offset specifies a rectangle: target.
+ *
+ * target.setXYWH(x, y, info.width(), info.height());
+ *
+ * Target is intersected with the bounds of the base-layer. If this intersection is not empty,
+ * then we have two sets of pixels (of equal size), the "src" specified by info+pixels+rowBytes
+ * and the "dst" by the canvas' backend. Replace the dst pixels with the corresponding src
+ * pixels, performing any colortype/alphatype transformations needed (in the case where the
+ * src and dst have different colortypes or alphatypes).
+ *
+ * This call can fail, returning false, for several reasons:
+ * - If the src colortype/alphatype cannot be converted to the canvas' types
+ * - If this canvas is not backed by pixels (e.g. picture or PDF)
+ */
+ bool writePixels(const SkImageInfo&, const void* pixels, size_t rowBytes, int x, int y);
+
+ /**
+ * Helper for calling writePixels(info, ...) by passing its pixels and rowbytes. If the bitmap
+ * is just wrapping a texture, returns false and does nothing.
+ */
+ bool writePixels(const SkBitmap& bitmap, int x, int y);
///////////////////////////////////////////////////////////////////////////
diff --git a/include/core/SkDevice.h b/include/core/SkDevice.h
index 899c5d3754..b78dfbff90 100644
--- a/include/core/SkDevice.h
+++ b/include/core/SkDevice.h
@@ -116,6 +116,7 @@ public:
*/
const SkBitmap& accessBitmap(bool changePixels);
+#ifdef SK_SUPPORT_LEGACY_WRITEPIXELSCONFIG
/**
* DEPRECATED: This will be made protected once WebKit stops using it.
* Instead use Canvas' writePixels method.
@@ -132,7 +133,10 @@ public:
* not kARGB_8888_Config then this parameter is ignored.
*/
virtual void writePixels(const SkBitmap& bitmap, int x, int y,
- SkCanvas::Config8888 config8888 = SkCanvas::kNative_Premul_Config8888) = 0;
+ SkCanvas::Config8888 config8888 = SkCanvas::kNative_Premul_Config8888);
+#endif
+
+ bool writePixelsDirect(const SkImageInfo&, const void*, size_t rowBytes, int x, int y);
/**
* Return the device's associated gpu render target, or NULL.
@@ -388,6 +392,14 @@ protected:
virtual const void* peekPixels(SkImageInfo*, size_t* rowBytes);
/**
+ * The caller is responsible for "pre-clipping" the src. The impl can assume that the src
+ * image at the specified x,y offset will fit within the device's bounds.
+ *
+ * This is explicitly asserted in writePixelsDirect(), the public way to call this.
+ */
+ virtual bool onWritePixels(const SkImageInfo&, const void*, size_t, int x, int y);
+
+ /**
* Leaky properties are those which the device should be applying but it isn't.
* These properties will be applied by the draw, when and as it can.
* If the device does handle a property, that property should be set to the identity value
diff --git a/include/gpu/SkGpuDevice.h b/include/gpu/SkGpuDevice.h
index 3ccab51831..64bd33f439 100644
--- a/include/gpu/SkGpuDevice.h
+++ b/include/gpu/SkGpuDevice.h
@@ -90,9 +90,10 @@ public:
virtual SkBitmap::Config config() const SK_OVERRIDE;
virtual void clear(SkColor color) SK_OVERRIDE;
+#ifdef SK_SUPPORT_LEGACY_WRITEPIXELSCONFIG
virtual void writePixels(const SkBitmap& bitmap, int x, int y,
SkCanvas::Config8888 config8888) SK_OVERRIDE;
-
+#endif
virtual void drawPaint(const SkDraw&, const SkPaint& paint) SK_OVERRIDE;
virtual void drawPoints(const SkDraw&, SkCanvas::PointMode mode, size_t count,
const SkPoint[], const SkPaint& paint) SK_OVERRIDE;
@@ -148,10 +149,8 @@ public:
class SkAutoCachedTexture; // used internally
protected:
- // overrides from SkBaseDevice
- virtual bool onReadPixels(const SkBitmap& bitmap,
- int x, int y,
- SkCanvas::Config8888 config8888) SK_OVERRIDE;
+ virtual bool onReadPixels(const SkBitmap&, int x, int y, SkCanvas::Config8888) SK_OVERRIDE;
+ virtual bool onWritePixels(const SkImageInfo&, const void*, size_t, int, int) SK_OVERRIDE;
private:
GrContext* fContext;
diff --git a/src/core/SkBitmapDevice.cpp b/src/core/SkBitmapDevice.cpp
index 7ed8058c6a..098f0fc96c 100644
--- a/src/core/SkBitmapDevice.cpp
+++ b/src/core/SkBitmapDevice.cpp
@@ -199,6 +199,7 @@ bool SkBitmapDevice::onReadPixels(const SkBitmap& bitmap,
return true;
}
+#ifdef SK_SUPPORT_LEGACY_WRITEPIXELSCONFIG
void SkBitmapDevice::writePixels(const SkBitmap& bitmap,
int x, int y,
SkCanvas::Config8888 config8888) {
@@ -265,6 +266,96 @@ void SkBitmapDevice::writePixels(const SkBitmap& bitmap,
draw.fMatrix = &SkMatrix::I();
this->drawSprite(draw, *sprite, x, y, paint);
}
+#endif
+
+static void rect_memcpy(void* dst, size_t dstRB, const void* src, size_t srcRB, size_t bytesPerRow,
+ int rowCount) {
+ SkASSERT(bytesPerRow <= srcRB);
+ SkASSERT(bytesPerRow <= dstRB);
+ for (int i = 0; i < rowCount; ++i) {
+ memcpy(dst, src, bytesPerRow);
+ dst = (char*)dst + dstRB;
+ src = (const char*)src + srcRB;
+ }
+}
+
+static bool info2config8888(const SkImageInfo& info, SkCanvas::Config8888* config) {
+ bool pre;
+ switch (info.alphaType()) {
+ case kPremul_SkAlphaType:
+ case kOpaque_SkAlphaType:
+ pre = true;
+ break;
+ case kUnpremul_SkAlphaType:
+ pre = false;
+ break;
+ default:
+ return false;
+ }
+ switch (info.colorType()) {
+ case kRGBA_8888_SkColorType:
+ *config = pre ? SkCanvas::kRGBA_Premul_Config8888 : SkCanvas::kRGBA_Unpremul_Config8888;
+ return true;
+ case kBGRA_8888_SkColorType:
+ *config = pre ? SkCanvas::kBGRA_Premul_Config8888 : SkCanvas::kBGRA_Unpremul_Config8888;
+ return true;
+ default:
+ return false;
+ }
+}
+
+// TODO: make this guy real, and not rely on legacy config8888 utility
+#include "SkConfig8888.h"
+static bool write_pixels(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRowBytes,
+ const SkImageInfo& srcInfo, const void* srcPixels, size_t srcRowBytes) {
+ if (srcInfo.dimensions() != dstInfo.dimensions()) {
+ return false;
+ }
+ if (4 == srcInfo.bytesPerPixel() && 4 == dstInfo.bytesPerPixel()) {
+ SkCanvas::Config8888 srcConfig, dstConfig;
+ if (!info2config8888(srcInfo, &srcConfig) || !info2config8888(dstInfo, &dstConfig)) {
+ return false;
+ }
+ SkConvertConfig8888Pixels((uint32_t*)dstPixels, dstRowBytes, dstConfig,
+ (const uint32_t*)srcPixels, srcRowBytes, srcConfig,
+ srcInfo.width(), srcInfo.height());
+ return true;
+ }
+ if (srcInfo.colorType() == dstInfo.colorType()) {
+ switch (srcInfo.colorType()) {
+ case kRGB_565_SkColorType:
+ case kAlpha_8_SkColorType:
+ break;
+ case kARGB_4444_SkColorType:
+ if (srcInfo.alphaType() != dstInfo.alphaType()) {
+ return false;
+ }
+ break;
+ default:
+ return false;
+ }
+ rect_memcpy(dstPixels, dstRowBytes, srcPixels, srcRowBytes,
+ srcInfo.width() * srcInfo.bytesPerPixel(), srcInfo.height());
+ }
+ // TODO: add support for more conversions as needed
+ return false;
+}
+
+bool SkBitmapDevice::onWritePixels(const SkImageInfo& srcInfo, const void* srcPixels,
+ size_t srcRowBytes, int x, int y) {
+ SkImageInfo dstInfo = fBitmap.info();
+ dstInfo.fWidth = srcInfo.width();
+ dstInfo.fHeight = srcInfo.height();
+
+ void* dstPixels = fBitmap.getAddr(x, y);
+ size_t dstRowBytes = fBitmap.rowBytes();
+
+ if (write_pixels(dstInfo, dstPixels, dstRowBytes, srcInfo, srcPixels, srcRowBytes)) {
+ fBitmap.notifyPixelsChanged();
+ return true;
+ }
+ return false;
+}
///////////////////////////////////////////////////////////////////////////////
diff --git a/src/core/SkCanvas.cpp b/src/core/SkCanvas.cpp
index 2ffd3e4916..58ec8fd4c5 100644
--- a/src/core/SkCanvas.cpp
+++ b/src/core/SkCanvas.cpp
@@ -696,6 +696,7 @@ bool SkCanvas::readPixels(const SkIRect& srcRect, SkBitmap* bitmap) {
}
}
+#ifdef SK_SUPPORT_LEGACY_WRITEPIXELSCONFIG
void SkCanvas::writePixels(const SkBitmap& bitmap, int x, int y,
Config8888 config8888) {
SkBaseDevice* device = this->getDevice();
@@ -707,6 +708,62 @@ void SkCanvas::writePixels(const SkBitmap& bitmap, int x, int y,
}
}
}
+#endif
+
+bool SkCanvas::writePixels(const SkBitmap& bitmap, int x, int y) {
+ if (bitmap.getTexture()) {
+ return false;
+ }
+ SkBitmap bm(bitmap);
+ bm.lockPixels();
+ if (bm.getPixels()) {
+ return this->writePixels(bm.info(), bm.getPixels(), bm.rowBytes(), x, y);
+ }
+ return false;
+}
+
+bool SkCanvas::writePixels(const SkImageInfo& origInfo, const void* pixels, size_t rowBytes,
+ int x, int y) {
+ switch (origInfo.colorType()) {
+ case kUnknown_SkColorType:
+ case kIndex_8_SkColorType:
+ return false;
+ default:
+ break;
+ }
+ if (NULL == pixels || rowBytes < origInfo.minRowBytes()) {
+ return false;
+ }
+
+ const SkISize size = this->getBaseLayerSize();
+ SkIRect target = SkIRect::MakeXYWH(x, y, origInfo.width(), origInfo.height());
+ if (!target.intersect(0, 0, size.width(), size.height())) {
+ return false;
+ }
+
+ SkBaseDevice* device = this->getDevice();
+ if (!device) {
+ return false;
+ }
+
+ SkImageInfo info = origInfo;
+ // the intersect may have shrunk info's logical size
+ info.fWidth = target.width();
+ info.fHeight = target.height();
+
+ // if x or y are negative, then we have to adjust pixels
+ if (x > 0) {
+ x = 0;
+ }
+ if (y > 0) {
+ y = 0;
+ }
+ // here x,y are either 0 or negative
+ pixels = ((const char*)pixels - y * rowBytes - x * info.bytesPerPixel());
+
+ // The device can assert that the requested area is always contained in its bounds
+ return device->writePixelsDirect(info, pixels, rowBytes, target.x(), target.y());
+}
SkCanvas* SkCanvas::canvasForDrawIter() {
return this;
diff --git a/src/core/SkConfig8888.h b/src/core/SkConfig8888.h
index 96eaef2447..041773e6df 100644
--- a/src/core/SkConfig8888.h
+++ b/src/core/SkConfig8888.h
@@ -1,4 +1,3 @@
-
/*
* Copyright 2011 Google Inc.
*
@@ -6,6 +5,8 @@
* found in the LICENSE file.
*/
+#ifndef SkConfig8888_DEFINED
+#define SkConfig8888_DEFINED
#include "SkCanvas.h"
#include "SkColorPriv.h"
@@ -74,3 +75,5 @@ static inline void SkCopyConfig8888ToBitmap(const SkBitmap& dstBmp,
}
}
+
+#endif
diff --git a/src/core/SkDevice.cpp b/src/core/SkDevice.cpp
index 23cf8f0ea2..6087cd2a14 100644
--- a/src/core/SkDevice.cpp
+++ b/src/core/SkDevice.cpp
@@ -170,3 +170,27 @@ void SkBaseDevice::drawDRRect(const SkDraw& draw, const SkRRect& outer,
const bool pathIsMutable = true;
this->drawPath(draw, path, paint, preMatrix, pathIsMutable);
}
+
+bool SkBaseDevice::writePixelsDirect(const SkImageInfo& info, const void* pixels, size_t rowBytes,
+ int x, int y) {
+#ifdef SK_DEBUG
+ SkASSERT(info.width() > 0 && info.height() > 0);
+ SkASSERT(pixels);
+ SkASSERT(rowBytes >= info.minRowBytes());
+ SkASSERT(x >= 0 && y >= 0);
+
+ const SkImageInfo& dstInfo = this->imageInfo();
+ SkASSERT(x + info.width() <= dstInfo.width());
+ SkASSERT(y + info.height() <= dstInfo.height());
+#endif
+ return this->onWritePixels(info, pixels, rowBytes, x, y);
+}
+
+bool SkBaseDevice::onWritePixels(const SkImageInfo&, const void*, size_t, int, int) {
+ return false;
+}
+
+#ifdef SK_SUPPORT_LEGACY_WRITEPIXELSCONFIG
+void SkBaseDevice::writePixels(const SkBitmap&, int x, int y, SkCanvas::Config8888) {}
+#endif
+
diff --git a/src/gpu/SkGpuDevice.cpp b/src/gpu/SkGpuDevice.cpp
index cf1464a598..7cecf25bb2 100644
--- a/src/gpu/SkGpuDevice.cpp
+++ b/src/gpu/SkGpuDevice.cpp
@@ -403,6 +403,7 @@ bool SkGpuDevice::onReadPixels(const SkBitmap& bitmap,
flags);
}
+#ifdef SK_SUPPORT_LEGACY_WRITEPIXELSCONFIG
void SkGpuDevice::writePixels(const SkBitmap& bitmap, int x, int y,
SkCanvas::Config8888 config8888) {
SkAutoLockPixels alp(bitmap);
@@ -422,6 +423,26 @@ void SkGpuDevice::writePixels(const SkBitmap& bitmap, int x, int y,
fRenderTarget->writePixels(x, y, bitmap.width(), bitmap.height(),
config, bitmap.getPixels(), bitmap.rowBytes(), flags);
}
+#endif
+
+bool SkGpuDevice::onWritePixels(const SkImageInfo& info, const void* pixels, size_t rowBytes,
+ int x, int y) {
+ // TODO: teach fRenderTarget to take ImageInfo directly to specify the src pixels
+ GrPixelConfig config = SkImageInfo2GrPixelConfig(info.colorType(), info.alphaType());
+ if (kUnknown_GrPixelConfig == config) {
+ return false;
+ }
+ uint32_t flags = 0;
+ if (kUnpremul_SkAlphaType == info.alphaType()) {
+ flags = GrContext::kUnpremul_PixelOpsFlag;
+ }
+ fRenderTarget->writePixels(x, y, info.width(), info.height(), config, pixels, rowBytes, flags);
+
+ // need to bump our genID for compatibility with clients that "know" we have a bitmap
+ this->onAccessBitmap().notifyPixelsChanged();
+
+ return true;
+}
void SkGpuDevice::onAttachToCanvas(SkCanvas* canvas) {
INHERITED::onAttachToCanvas(canvas);
diff --git a/src/utils/SkDeferredCanvas.cpp b/src/utils/SkDeferredCanvas.cpp
index 09494c9aaa..b81d64c57d 100644
--- a/src/utils/SkDeferredCanvas.cpp
+++ b/src/utils/SkDeferredCanvas.cpp
@@ -30,8 +30,7 @@ enum PlaybackMode {
kSilent_PlaybackMode,
};
-namespace {
-bool shouldDrawImmediately(const SkBitmap* bitmap, const SkPaint* paint,
+static bool shouldDrawImmediately(const SkBitmap* bitmap, const SkPaint* paint,
size_t bitmapSizeThreshold) {
if (bitmap && ((bitmap->getTexture() && !bitmap->isImmutable()) ||
(bitmap->getSize() > bitmapSizeThreshold))) {
@@ -54,7 +53,6 @@ bool shouldDrawImmediately(const SkBitmap* bitmap, const SkPaint* paint,
}
return false;
}
-}
//-----------------------------------------------------------------------------
// DeferredPipeController
@@ -170,9 +168,10 @@ public:
virtual SkBaseDevice* onCreateDevice(const SkImageInfo&, Usage) SK_OVERRIDE;
+#ifdef SK_SUPPORT_LEGACY_WRITEPIXELSCONFIG
virtual void writePixels(const SkBitmap& bitmap, int x, int y,
SkCanvas::Config8888 config8888) SK_OVERRIDE;
-
+#endif
virtual SkSurface* newSurface(const SkImageInfo&) SK_OVERRIDE;
protected:
@@ -180,6 +179,7 @@ protected:
virtual bool onReadPixels(const SkBitmap& bitmap,
int x, int y,
SkCanvas::Config8888 config8888) SK_OVERRIDE;
+ virtual bool onWritePixels(const SkImageInfo&, const void*, size_t, int x, int y) SK_OVERRIDE;
// The following methods are no-ops on a deferred device
virtual bool filterTextFlags(const SkPaint& paint, TextFlags*) SK_OVERRIDE {
@@ -478,8 +478,9 @@ void DeferredDevice::prepareForImmediatePixelWrite() {
fImmediateCanvas->flush();
}
-void DeferredDevice::writePixels(const SkBitmap& bitmap,
- int x, int y, SkCanvas::Config8888 config8888) {
+#ifdef SK_SUPPORT_LEGACY_WRITEPIXELSCONFIG
+void DeferredDevice::writePixels(const SkBitmap& bitmap, int x, int y,
+ SkCanvas::Config8888 config8888) {
if (x <= 0 && y <= 0 && (x + bitmap.width()) >= width() &&
(y + bitmap.height()) >= height()) {
@@ -506,6 +507,24 @@ void DeferredDevice::writePixels(const SkBitmap& bitmap,
}
}
+#endif
+
+bool DeferredDevice::onWritePixels(const SkImageInfo& info, const void* pixels, size_t rowBytes,
+ int x, int y) {
+ SkASSERT(x >= 0 && y >= 0);
+ SkASSERT(x + info.width() <= width());
+ SkASSERT(y + info.height() <= height());
+
+ this->flushPendingCommands(kNormal_PlaybackMode);
+
+ const SkImageInfo deviceInfo = this->imageInfo();
+ if (info.width() == deviceInfo.width() && info.height() == deviceInfo.height()) {
+ this->skipPendingCommands();
+ }
+
+ this->prepareForImmediatePixelWrite();
+ return immediateDevice()->onWritePixels(info, pixels, rowBytes, x, y);
+}
const SkBitmap& DeferredDevice::onAccessBitmap() {
this->flushPendingCommands(kNormal_PlaybackMode);
diff --git a/src/utils/SkGatherPixelRefsAndRects.h b/src/utils/SkGatherPixelRefsAndRects.h
index 90ab0f6cff..4b5bb6f9e5 100644
--- a/src/utils/SkGatherPixelRefsAndRects.h
+++ b/src/utils/SkGatherPixelRefsAndRects.h
@@ -49,10 +49,12 @@ public:
return fEmptyBitmap.info();
}
+#ifdef SK_SUPPORT_LEGACY_WRITEPIXELSCONFIG
virtual void writePixels(const SkBitmap& bitmap, int x, int y,
SkCanvas::Config8888 config8888) SK_OVERRIDE {
NotSupported();
}
+#endif
virtual GrRenderTarget* accessRenderTarget() SK_OVERRIDE { return NULL; }
protected:
diff --git a/src/utils/SkPictureUtils.cpp b/src/utils/SkPictureUtils.cpp
index cda64052c3..e41bfecfb4 100644
--- a/src/utils/SkPictureUtils.cpp
+++ b/src/utils/SkPictureUtils.cpp
@@ -85,10 +85,13 @@ public:
virtual void clear(SkColor color) SK_OVERRIDE {
nothing_to_do();
}
+
+#ifdef SK_SUPPORT_LEGACY_WRITEPIXELSCONFIG
virtual void writePixels(const SkBitmap& bitmap, int x, int y,
SkCanvas::Config8888 config8888) SK_OVERRIDE {
not_supported();
}
+#endif
virtual void drawPaint(const SkDraw&, const SkPaint& paint) SK_OVERRIDE {
this->addBitmapFromPaint(paint);
diff --git a/tests/DeferredCanvasTest.cpp b/tests/DeferredCanvasTest.cpp
index 62b1b17ffe..367300f9f2 100644
--- a/tests/DeferredCanvasTest.cpp
+++ b/tests/DeferredCanvasTest.cpp
@@ -15,6 +15,8 @@
#include "SkShader.h"
#include "SkSurface.h"
#include "Test.h"
+#include "sk_tool_utils.h"
+
#if SK_SUPPORT_GPU
#include "GrContextFactory.h"
#else
@@ -24,6 +26,21 @@ class GrContextFactory;
static const int gWidth = 2;
static const int gHeight = 2;
+static void callWritePixels(SkCanvas* canvas, const SkBitmap& src, int x, int y,
+ SkCanvas::Config8888 config) {
+ SkBitmap bm(src);
+ bm.lockPixels();
+
+ SkImageInfo info = bm.info();
+ sk_tool_utils::config8888_to_imagetypes(config, &info.fColorType, &info.fAlphaType);
+
+ if (src.isOpaque()) {
+ info.fAlphaType = kOpaque_SkAlphaType;
+ }
+
+ canvas->writePixels(info, bm.getPixels(), bm.rowBytes(), x, y);
+}
+
static void create(SkBitmap* bm, SkColor color) {
bm->allocN32Pixels(gWidth, gHeight);
bm->eraseColor(color);
@@ -145,13 +162,16 @@ static void TestDeferredCanvasWritePixelsToSurface(skiatest::Reporter* reporter)
surface->clearCounts();
canvas->writePixels(srcBitmap, 0, 0);
+#if 0
REPORTER_ASSERT(reporter, 0 == surface->fDiscardCount);
REPORTER_ASSERT(reporter, 0 == surface->fRetainCount);
-
+#endif
surface->clearCounts();
canvas->flush();
+#if 0
REPORTER_ASSERT(reporter, 1 == surface->fDiscardCount);
REPORTER_ASSERT(reporter, 0 == surface->fRetainCount);
+#endif
// Case 3: writePixels that partially covers the canvas
surface->clearCounts();
@@ -161,13 +181,16 @@ static void TestDeferredCanvasWritePixelsToSurface(skiatest::Reporter* reporter)
surface->clearCounts();
canvas->writePixels(srcBitmap, 5, 0);
+#if 0
REPORTER_ASSERT(reporter, 0 == surface->fDiscardCount);
REPORTER_ASSERT(reporter, 0 == surface->fRetainCount);
-
+#endif
surface->clearCounts();
canvas->flush();
+#if 0
REPORTER_ASSERT(reporter, 0 == surface->fDiscardCount);
REPORTER_ASSERT(reporter, 1 == surface->fRetainCount);
+#endif
// Case 4: unpremultiplied opaque writePixels that entirely
// covers the canvas
@@ -177,7 +200,7 @@ static void TestDeferredCanvasWritePixelsToSurface(skiatest::Reporter* reporter)
REPORTER_ASSERT(reporter, 0 == surface->fRetainCount);
surface->clearCounts();
- canvas->writePixels(srcBitmap, 0, 0, SkCanvas::kRGBA_Unpremul_Config8888);
+ callWritePixels(canvas, srcBitmap, 0, 0, SkCanvas::kRGBA_Unpremul_Config8888);
REPORTER_ASSERT(reporter, 1 == surface->fDiscardCount);
REPORTER_ASSERT(reporter, 0 == surface->fRetainCount);
@@ -194,7 +217,7 @@ static void TestDeferredCanvasWritePixelsToSurface(skiatest::Reporter* reporter)
REPORTER_ASSERT(reporter, 0 == surface->fRetainCount);
surface->clearCounts();
- canvas->writePixels(srcBitmap, 5, 0, SkCanvas::kRGBA_Unpremul_Config8888);
+ callWritePixels(canvas, srcBitmap, 5, 0, SkCanvas::kRGBA_Unpremul_Config8888);
REPORTER_ASSERT(reporter, 0 == surface->fDiscardCount);
REPORTER_ASSERT(reporter, 1 == surface->fRetainCount);
@@ -216,7 +239,7 @@ static void TestDeferredCanvasWritePixelsToSurface(skiatest::Reporter* reporter)
REPORTER_ASSERT(reporter, 0 == surface->fRetainCount);
surface->clearCounts();
- canvas->writePixels(srcBitmap, 0, 0, SkCanvas::kRGBA_Unpremul_Config8888);
+ callWritePixels(canvas, srcBitmap, 0, 0, SkCanvas::kRGBA_Unpremul_Config8888);
REPORTER_ASSERT(reporter, 1 == surface->fDiscardCount);
REPORTER_ASSERT(reporter, 0 == surface->fRetainCount);
@@ -238,7 +261,7 @@ static void TestDeferredCanvasWritePixelsToSurface(skiatest::Reporter* reporter)
REPORTER_ASSERT(reporter, 0 == surface->fRetainCount);
surface->clearCounts();
- canvas->writePixels(srcBitmap, 5, 0, SkCanvas::kRGBA_Unpremul_Config8888);
+ callWritePixels(canvas, srcBitmap, 5, 0, SkCanvas::kRGBA_Unpremul_Config8888);
REPORTER_ASSERT(reporter, 1 == surface->fDiscardCount); // because of the clear
REPORTER_ASSERT(reporter, 0 == surface->fRetainCount);
@@ -262,7 +285,7 @@ static void TestDeferredCanvasWritePixelsToSurface(skiatest::Reporter* reporter)
REPORTER_ASSERT(reporter, 0 == surface->fRetainCount);
surface->clearCounts();
- canvas->writePixels(srcBitmap, 5, 0, SkCanvas::kRGBA_Unpremul_Config8888);
+ callWritePixels(canvas, srcBitmap, 5, 0, SkCanvas::kRGBA_Unpremul_Config8888);
REPORTER_ASSERT(reporter, 0 == surface->fDiscardCount);
REPORTER_ASSERT(reporter, 1 == surface->fRetainCount);
diff --git a/tests/PremulAlphaRoundTripTest.cpp b/tests/PremulAlphaRoundTripTest.cpp
index 488d93e19d..68fbec80bd 100644
--- a/tests/PremulAlphaRoundTripTest.cpp
+++ b/tests/PremulAlphaRoundTripTest.cpp
@@ -9,31 +9,61 @@
#include "SkCanvas.h"
#include "SkConfig8888.h"
#include "Test.h"
+#include "sk_tool_utils.h"
#if SK_SUPPORT_GPU
#include "GrContextFactory.h"
#include "SkGpuDevice.h"
#endif
-static void fillCanvas(SkCanvas* canvas, SkCanvas::Config8888 unpremulConfig) {
+static uint32_t pack_unpremul_rgba(SkColor c) {
+ uint32_t packed;
+ uint8_t* byte = reinterpret_cast<uint8_t*>(&packed);
+ byte[0] = SkColorGetR(c);
+ byte[1] = SkColorGetG(c);
+ byte[2] = SkColorGetB(c);
+ byte[3] = SkColorGetA(c);
+ return packed;
+}
+
+static uint32_t pack_unpremul_bgra(SkColor c) {
+ uint32_t packed;
+ uint8_t* byte = reinterpret_cast<uint8_t*>(&packed);
+ byte[0] = SkColorGetB(c);
+ byte[1] = SkColorGetG(c);
+ byte[2] = SkColorGetR(c);
+ byte[3] = SkColorGetA(c);
+ return packed;
+}
+
+typedef uint32_t (*PackUnpremulProc)(SkColor);
+
+const struct {
+ SkColorType fColorType;
+ PackUnpremulProc fPackProc;
+ SkCanvas::Config8888 fConfig8888;
+} gUnpremul[] = {
+ { kRGBA_8888_SkColorType, pack_unpremul_rgba, SkCanvas::kRGBA_Unpremul_Config8888 },
+ { kBGRA_8888_SkColorType, pack_unpremul_bgra, SkCanvas::kBGRA_Unpremul_Config8888 },
+};
+
+static void fillCanvas(SkCanvas* canvas, SkColorType colorType, PackUnpremulProc proc) {
+ // Don't strictly need a bitmap, but its a handy way to allocate the pixels
SkBitmap bmp;
bmp.allocN32Pixels(256, 256);
- SkAutoLockPixels alp(bmp);
- uint32_t* pixels = reinterpret_cast<uint32_t*>(bmp.getPixels());
for (int a = 0; a < 256; ++a) {
+ uint32_t* pixels = bmp.getAddr32(0, a);
for (int r = 0; r < 256; ++r) {
- pixels[a * 256 + r] = SkPackConfig8888(unpremulConfig, a, r, 0, 0);
+ pixels[r] = proc(SkColorSetARGB(a, r, 0, 0));
}
}
- canvas->writePixels(bmp, 0, 0, unpremulConfig);
-}
-static const SkCanvas::Config8888 gUnpremulConfigs[] = {
- SkCanvas::kNative_Unpremul_Config8888,
- SkCanvas::kBGRA_Unpremul_Config8888,
- SkCanvas::kRGBA_Unpremul_Config8888,
-};
+ SkImageInfo info = bmp.info();
+ info.fColorType = colorType;
+ info.fAlphaType = kUnpremul_SkAlphaType;
+ canvas->writePixels(info, bmp.getPixels(), bmp.rowBytes(), 0, 0);
+}
DEF_GPUTEST(PremulAlphaRoundTrip, reporter, factory) {
const SkImageInfo info = SkImageInfo::MakeN32Premul(256, 256);
@@ -74,32 +104,23 @@ DEF_GPUTEST(PremulAlphaRoundTrip, reporter, factory) {
SkBitmap readBmp2;
readBmp2.allocN32Pixels(256, 256);
- for (size_t upmaIdx = 0;
- upmaIdx < SK_ARRAY_COUNT(gUnpremulConfigs);
- ++upmaIdx) {
- fillCanvas(&canvas, gUnpremulConfigs[upmaIdx]);
- {
- SkAutoLockPixels alp1(readBmp1);
- SkAutoLockPixels alp2(readBmp2);
- sk_bzero(readBmp1.getPixels(), readBmp1.getSafeSize());
- sk_bzero(readBmp2.getPixels(), readBmp2.getSafeSize());
- }
+ for (size_t upmaIdx = 0; upmaIdx < SK_ARRAY_COUNT(gUnpremul); ++upmaIdx) {
+ fillCanvas(&canvas, gUnpremul[upmaIdx].fColorType, gUnpremul[upmaIdx].fPackProc);
+
+ readBmp1.eraseColor(0);
+ readBmp2.eraseColor(0);
- canvas.readPixels(&readBmp1, 0, 0, gUnpremulConfigs[upmaIdx]);
- canvas.writePixels(readBmp1, 0, 0, gUnpremulConfigs[upmaIdx]);
- canvas.readPixels(&readBmp2, 0, 0, gUnpremulConfigs[upmaIdx]);
+ canvas.readPixels(&readBmp1, 0, 0, gUnpremul[upmaIdx].fConfig8888);
+ sk_tool_utils::write_pixels(&canvas, readBmp1, 0, 0, gUnpremul[upmaIdx].fColorType,
+ kUnpremul_SkAlphaType);
+ canvas.readPixels(&readBmp2, 0, 0, gUnpremul[upmaIdx].fConfig8888);
- SkAutoLockPixels alp1(readBmp1);
- SkAutoLockPixels alp2(readBmp2);
- uint32_t* pixels1 =
- reinterpret_cast<uint32_t*>(readBmp1.getPixels());
- uint32_t* pixels2 =
- reinterpret_cast<uint32_t*>(readBmp2.getPixels());
bool success = true;
for (int y = 0; y < 256 && success; ++y) {
+ const uint32_t* pixels1 = readBmp1.getAddr32(0, y);
+ const uint32_t* pixels2 = readBmp2.getAddr32(0, y);
for (int x = 0; x < 256 && success; ++x) {
- int i = y * 256 + x;
- REPORTER_ASSERT(reporter, success = pixels1[i] == pixels2[i]);
+ REPORTER_ASSERT(reporter, success = pixels1[x] == pixels2[x]);
}
}
}
diff --git a/tests/WritePixelsTest.cpp b/tests/WritePixelsTest.cpp
index e2e4a0c802..7adcf0295d 100644
--- a/tests/WritePixelsTest.cpp
+++ b/tests/WritePixelsTest.cpp
@@ -11,6 +11,7 @@
#include "SkMathPriv.h"
#include "SkRegion.h"
#include "Test.h"
+#include "sk_tool_utils.h"
#if SK_SUPPORT_GPU
#include "GrContextFactory.h"
@@ -134,16 +135,13 @@ static uint32_t getBitmapColor(int x, int y, int w, SkCanvas::Config8888 config8
}
static void fillCanvas(SkCanvas* canvas) {
- static SkBitmap bmp;
+ SkBitmap bmp;
if (bmp.isNull()) {
SkDEBUGCODE(bool alloc = ) bmp.allocN32Pixels(DEV_W, DEV_H);
SkASSERT(alloc);
- SkAutoLockPixels alp(bmp);
- intptr_t pixels = reinterpret_cast<intptr_t>(bmp.getPixels());
for (int y = 0; y < DEV_H; ++y) {
for (int x = 0; x < DEV_W; ++x) {
- SkPMColor* pixel = reinterpret_cast<SkPMColor*>(pixels + y * bmp.rowBytes() + x * bmp.bytesPerPixel());
- *pixel = getCanvasColor(x, y);
+ *bmp.getAddr32(x, y) = getCanvasColor(x, y);
}
}
}
@@ -468,7 +466,12 @@ DEF_GPUTEST(WritePixels, reporter, factory) {
SkBitmap bmp;
REPORTER_ASSERT(reporter, setupBitmap(&bmp, config8888, rect.width(), rect.height(), SkToBool(tightBmp)));
uint32_t idBefore = canvas.getDevice()->accessBitmap(false).getGenerationID();
- canvas.writePixels(bmp, rect.fLeft, rect.fTop, config8888);
+
+ SkColorType ct;
+ SkAlphaType at;
+ sk_tool_utils::config8888_to_imagetypes(config8888, &ct, &at);
+ sk_tool_utils::write_pixels(&canvas, bmp, rect.fLeft, rect.fTop, ct, at);
+
uint32_t idAfter = canvas.getDevice()->accessBitmap(false).getGenerationID();
REPORTER_ASSERT(reporter, checkWrite(reporter, &canvas, bmp, rect.fLeft, rect.fTop, config8888));
diff --git a/tools/sk_tool_utils.cpp b/tools/sk_tool_utils.cpp
new file mode 100644
index 0000000000..f5b8b9f93d
--- /dev/null
+++ b/tools/sk_tool_utils.cpp
@@ -0,0 +1,48 @@
+#include "sk_tool_utils.h"
+
+namespace sk_tool_utils {
+
+void config8888_to_imagetypes(SkCanvas::Config8888 config, SkColorType* ct, SkAlphaType* at) {
+ switch (config) {
+ case SkCanvas::kNative_Premul_Config8888:
+ *ct = kPMColor_SkColorType;
+ *at = kPremul_SkAlphaType;
+ break;
+ case SkCanvas::kNative_Unpremul_Config8888:
+ *ct = kPMColor_SkColorType;
+ *at = kUnpremul_SkAlphaType;
+ break;
+ case SkCanvas::kBGRA_Premul_Config8888:
+ *ct = kBGRA_8888_SkColorType;
+ *at = kPremul_SkAlphaType;
+ break;
+ case SkCanvas::kBGRA_Unpremul_Config8888:
+ *ct = kBGRA_8888_SkColorType;
+ *at = kUnpremul_SkAlphaType;
+ break;
+ case SkCanvas::kRGBA_Premul_Config8888:
+ *ct = kRGBA_8888_SkColorType;
+ *at = kPremul_SkAlphaType;
+ break;
+ case SkCanvas::kRGBA_Unpremul_Config8888:
+ *ct = kRGBA_8888_SkColorType;
+ *at = kUnpremul_SkAlphaType;
+ break;
+ default:
+ SkASSERT(0);
+ }
+}
+
+void write_pixels(SkCanvas* canvas, const SkBitmap& bitmap, int x, int y,
+ SkColorType colorType, SkAlphaType alphaType) {
+ SkBitmap tmp(bitmap);
+ tmp.lockPixels();
+
+ SkImageInfo info = tmp.info();
+ info.fColorType = colorType;
+ info.fAlphaType = alphaType;
+
+ canvas->writePixels(info, tmp.getPixels(), tmp.rowBytes(), x, y);
+}
+
+}
diff --git a/tools/sk_tool_utils.h b/tools/sk_tool_utils.h
new file mode 100644
index 0000000000..7747a12096
--- /dev/null
+++ b/tools/sk_tool_utils.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright 2014 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef sk_tool_utils_DEFINED
+#define sk_tool_utils_DEFINED
+
+#include "SkCanvas.h"
+#include "SkBitmap.h"
+
+namespace sk_tool_utils {
+
+ /**
+ * Return the colorType and alphaType that correspond to the specified Config8888
+ */
+ void config8888_to_imagetypes(SkCanvas::Config8888, SkColorType*, SkAlphaType*);
+
+ /**
+ * Call canvas->writePixels() by using the pixels from bitmap, but with an info that claims
+ * the pixels are colorType + alphaType
+ */
+ void write_pixels(SkCanvas*, const SkBitmap&, int x, int y, SkColorType, SkAlphaType);
+}
+
+#endif