add new readPixels with direct memory parameters
BUG=skia:
R=scroggo@google.com, bsalomon@google.com, robertphillips@google.com, fmalita@google.com
Author: reed@google.com
Review URL: https://codereview.chromium.org/199413013
git-svn-id: http://skia.googlecode.com/svn/trunk@13840 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/src/core/SkBitmapDevice.cpp b/src/core/SkBitmapDevice.cpp
index 476a124..868306c 100644
--- a/src/core/SkBitmapDevice.cpp
+++ b/src/core/SkBitmapDevice.cpp
@@ -173,6 +173,7 @@
return true;
}
+#ifdef SK_SUPPORT_LEGACY_READPIXELSCONFIG
bool SkBitmapDevice::onReadPixels(const SkBitmap& bitmap,
int x, int y,
SkCanvas::Config8888 config8888) {
@@ -198,6 +199,7 @@
SkCopyBitmapToConfig8888(bmpPixels, bitmap.rowBytes(), config8888, subset);
return true;
}
+#endif
void* SkBitmapDevice::onAccessPixels(SkImageInfo* info, size_t* rowBytes) {
if (fBitmap.getPixels()) {
@@ -246,8 +248,8 @@
// 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) {
+static bool copy_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;
}
@@ -295,13 +297,39 @@
void* dstPixels = fBitmap.getAddr(x, y);
size_t dstRowBytes = fBitmap.rowBytes();
- if (write_pixels(dstInfo, dstPixels, dstRowBytes, srcInfo, srcPixels, srcRowBytes)) {
+ if (copy_pixels(dstInfo, dstPixels, dstRowBytes, srcInfo, srcPixels, srcRowBytes)) {
fBitmap.notifyPixelsChanged();
return true;
}
return false;
}
+bool SkBitmapDevice::onReadPixels(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRowBytes,
+ int x, int y) {
+ // since we don't stop creating un-pixeled devices yet, check for no pixels here
+ if (NULL == fBitmap.getPixels()) {
+ return false;
+ }
+
+ SkImageInfo srcInfo = fBitmap.info();
+
+ // perhaps can relax these in the future
+ if (4 != dstInfo.bytesPerPixel()) {
+ return false;
+ }
+ if (4 != srcInfo.bytesPerPixel()) {
+ return false;
+ }
+
+ srcInfo.fWidth = dstInfo.width();
+ srcInfo.fHeight = dstInfo.height();
+
+ const void* srcPixels = fBitmap.getAddr(x, y);
+ const size_t srcRowBytes = fBitmap.rowBytes();
+
+ return copy_pixels(dstInfo, dstPixels, dstRowBytes, srcInfo, srcPixels, srcRowBytes);
+}
+
///////////////////////////////////////////////////////////////////////////////
void SkBitmapDevice::drawPaint(const SkDraw& draw, const SkPaint& paint) {
diff --git a/src/core/SkCanvas.cpp b/src/core/SkCanvas.cpp
index 17e03c2..ef6a82d 100644
--- a/src/core/SkCanvas.cpp
+++ b/src/core/SkCanvas.cpp
@@ -667,6 +667,7 @@
return device;
}
+#ifdef SK_SUPPORT_LEGACY_READPIXELSCONFIG
bool SkCanvas::readPixels(SkBitmap* bitmap,
int x, int y,
Config8888 config8888) {
@@ -676,28 +677,95 @@
}
return device->readPixels(bitmap, x, y, config8888);
}
+#endif
+
+bool SkCanvas::readPixels(SkBitmap* bitmap, int x, int y) {
+ if (kUnknown_SkColorType == bitmap->colorType() || bitmap->getTexture()) {
+ return false;
+ }
+
+ bool weAllocated = false;
+ if (NULL == bitmap->pixelRef()) {
+ if (!bitmap->allocPixels()) {
+ return false;
+ }
+ weAllocated = true;
+ }
+
+ SkBitmap bm(*bitmap);
+ bm.lockPixels();
+ if (bm.getPixels() && this->readPixels(bm.info(), bm.getPixels(), bm.rowBytes(), x, y)) {
+ return true;
+ }
+
+ if (weAllocated) {
+ bitmap->setPixelRef(NULL);
+ }
+ return false;
+}
bool SkCanvas::readPixels(const SkIRect& srcRect, SkBitmap* bitmap) {
+ SkIRect r = srcRect;
+ const SkISize size = this->getBaseLayerSize();
+ if (!r.intersect(0, 0, size.width(), size.height())) {
+ bitmap->reset();
+ return false;
+ }
+
+ if (!bitmap->allocN32Pixels(r.width(), r.height())) {
+ // bitmap will already be reset.
+ return false;
+ }
+ if (!this->readPixels(bitmap->info(), bitmap->getPixels(), bitmap->rowBytes(), r.x(), r.y())) {
+ bitmap->reset();
+ return false;
+ }
+ return true;
+}
+
+bool SkCanvas::readPixels(const SkImageInfo& origInfo, void* dstP, size_t rowBytes, int x, int y) {
+ switch (origInfo.colorType()) {
+ case kUnknown_SkColorType:
+ case kIndex_8_SkColorType:
+ return false;
+ default:
+ break;
+ }
+ if (NULL == dstP || rowBytes < origInfo.minRowBytes()) {
+ return false;
+ }
+ if (0 == origInfo.width() || 0 == origInfo.height()) {
+ return false;
+ }
+
SkBaseDevice* device = this->getDevice();
if (!device) {
return false;
}
- SkIRect bounds;
- bounds.set(0, 0, device->width(), device->height());
- if (!bounds.intersect(srcRect)) {
+ const SkISize size = this->getBaseLayerSize();
+ SkIRect srcR = SkIRect::MakeXYWH(x, y, origInfo.width(), origInfo.height());
+ if (!srcR.intersect(0, 0, size.width(), size.height())) {
return false;
}
-
- SkBitmap tmp;
- tmp.setConfig(SkBitmap::kARGB_8888_Config, bounds.width(),
- bounds.height());
- if (this->readPixels(&tmp, bounds.fLeft, bounds.fTop)) {
- bitmap->swap(tmp);
- return true;
- } else {
- return false;
+
+ SkImageInfo info = origInfo;
+ // the intersect may have shrunk info's logical size
+ info.fWidth = srcR.width();
+ info.fHeight = srcR.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
+ dstP = ((char*)dstP - y * rowBytes - x * info.bytesPerPixel());
+
+ // The device can assert that the requested area is always contained in its bounds
+ return device->readPixels(info, dstP, rowBytes, srcR.x(), srcR.y());
}
bool SkCanvas::writePixels(const SkBitmap& bitmap, int x, int y) {
@@ -1063,12 +1131,9 @@
fAddr = canvas->peekPixels(&fInfo, &fRowBytes);
if (NULL == fAddr) {
fInfo = canvas->imageInfo();
- if (kUnknown_SkColorType == fInfo.colorType() ||
- !fBitmap.allocPixels(fInfo))
- {
+ if (kUnknown_SkColorType == fInfo.colorType() || !fBitmap.allocPixels(fInfo)) {
return; // failure, fAddr is NULL
}
- fBitmap.lockPixels();
if (!canvas->readPixels(&fBitmap, 0, 0)) {
return; // failure, fAddr is NULL
}
diff --git a/src/core/SkDevice.cpp b/src/core/SkDevice.cpp
index 5b6ecc0..61a7ab6 100644
--- a/src/core/SkDevice.cpp
+++ b/src/core/SkDevice.cpp
@@ -112,6 +112,7 @@
return bitmap;
}
+#ifdef SK_SUPPORT_LEGACY_READPIXELSCONFIG
bool SkBaseDevice::readPixels(SkBitmap* bitmap, int x, int y,
SkCanvas::Config8888 config8888) {
if (SkBitmap::kARGB_8888_Config != bitmap->config() ||
@@ -154,6 +155,10 @@
}
return result;
}
+bool SkBaseDevice::onReadPixels(const SkBitmap&, int x, int y, SkCanvas::Config8888) {
+ return false;
+}
+#endif
SkSurface* SkBaseDevice::newSurface(const SkImageInfo&) { return NULL; }
@@ -171,6 +176,20 @@
this->drawPath(draw, path, paint, preMatrix, pathIsMutable);
}
+bool SkBaseDevice::readPixels(const SkImageInfo& info, void* dstP, size_t rowBytes, int x, int y) {
+#ifdef SK_DEBUG
+ SkASSERT(info.width() > 0 && info.height() > 0);
+ SkASSERT(dstP);
+ SkASSERT(rowBytes >= info.minRowBytes());
+ SkASSERT(x >= 0 && y >= 0);
+
+ const SkImageInfo& srcInfo = this->imageInfo();
+ SkASSERT(x + info.width() <= srcInfo.width());
+ SkASSERT(y + info.height() <= srcInfo.height());
+#endif
+ return this->onReadPixels(info, dstP, rowBytes, x, y);
+}
+
bool SkBaseDevice::writePixels(const SkImageInfo& info, const void* pixels, size_t rowBytes,
int x, int y) {
#ifdef SK_DEBUG
@@ -190,7 +209,7 @@
return false;
}
-bool SkBaseDevice::onReadPixels(const SkBitmap&, int x, int y, SkCanvas::Config8888) {
+bool SkBaseDevice::onReadPixels(const SkImageInfo&, void*, size_t, int x, int y) {
return false;
}
diff --git a/src/gpu/SkGpuDevice.cpp b/src/gpu/SkGpuDevice.cpp
index 26392ca..ac4c02a 100644
--- a/src/gpu/SkGpuDevice.cpp
+++ b/src/gpu/SkGpuDevice.cpp
@@ -343,6 +343,7 @@
///////////////////////////////////////////////////////////////////////////////
+#ifdef SK_SUPPORT_LEGACY_READPIXELSCONFIG
namespace {
GrPixelConfig config8888_to_grconfig_and_flags(SkCanvas::Config8888 config8888, uint32_t* flags) {
switch (config8888) {
@@ -379,7 +380,7 @@
SkASSERT(SkBitmap::kARGB_8888_Config == bitmap.config());
SkASSERT(!bitmap.isNull());
SkASSERT(SkIRect::MakeWH(this->width(), this->height()).contains(SkIRect::MakeXYWH(x, y, bitmap.width(), bitmap.height())));
-
+
SkAutoLockPixels alp(bitmap);
GrPixelConfig config;
uint32_t flags;
@@ -393,6 +394,25 @@
bitmap.rowBytes(),
flags);
}
+#endif
+
+bool SkGpuDevice::onReadPixels(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRowBytes,
+ int x, int y) {
+ DO_DEFERRED_CLEAR();
+
+ // TODO: teach fRenderTarget to take ImageInfo directly to specify the src pixels
+ GrPixelConfig config = SkImageInfo2GrPixelConfig(dstInfo.colorType(), dstInfo.alphaType());
+ if (kUnknown_GrPixelConfig == config) {
+ return false;
+ }
+
+ uint32_t flags = 0;
+ if (kUnpremul_SkAlphaType == dstInfo.alphaType()) {
+ flags = GrContext::kUnpremul_PixelOpsFlag;
+ }
+ return fContext->readRenderTargetPixels(fRenderTarget, x, y, dstInfo.width(), dstInfo.height(),
+ config, dstPixels, dstRowBytes, flags);
+}
bool SkGpuDevice::onWritePixels(const SkImageInfo& info, const void* pixels, size_t rowBytes,
int x, int y) {
diff --git a/src/pdf/SkPDFDevice.cpp b/src/pdf/SkPDFDevice.cpp
index efd2b02..66ddccf 100644
--- a/src/pdf/SkPDFDevice.cpp
+++ b/src/pdf/SkPDFDevice.cpp
@@ -2310,10 +2310,12 @@
&content.entry()->fContent);
}
+#ifdef SK_SUPPORT_LEGACY_READPIXELSCONFIG
bool SkPDFDevice::onReadPixels(const SkBitmap& bitmap, int x, int y,
SkCanvas::Config8888) {
return false;
}
+#endif
bool SkPDFDevice::allowImageFilter(const SkImageFilter*) {
return false;
diff --git a/src/utils/SkDeferredCanvas.cpp b/src/utils/SkDeferredCanvas.cpp
index 9051874..2e3f5bb 100644
--- a/src/utils/SkDeferredCanvas.cpp
+++ b/src/utils/SkDeferredCanvas.cpp
@@ -171,9 +171,12 @@
protected:
virtual const SkBitmap& onAccessBitmap() SK_OVERRIDE;
+#ifdef SK_SUPPORT_LEGACY_READPIXELSCONFIG
virtual bool onReadPixels(const SkBitmap& bitmap,
int x, int y,
SkCanvas::Config8888 config8888) SK_OVERRIDE;
+#endif
+ virtual bool onReadPixels(const SkImageInfo&, void*, size_t, int x, int y) 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
@@ -506,12 +509,20 @@
return this->immediateDevice()->newSurface(info);
}
+#ifdef SK_SUPPORT_LEGACY_READPIXELSCONFIG
bool SkDeferredDevice::onReadPixels(
const SkBitmap& bitmap, int x, int y, SkCanvas::Config8888 config8888) {
this->flushPendingCommands(kNormal_PlaybackMode);
return fImmediateCanvas->readPixels(const_cast<SkBitmap*>(&bitmap),
x, y, config8888);
}
+#endif
+
+bool SkDeferredDevice::onReadPixels(const SkImageInfo& info, void* pixels, size_t rowBytes,
+ int x, int y) {
+ this->flushPendingCommands(kNormal_PlaybackMode);
+ return fImmediateCanvas->readPixels(info, pixels, rowBytes, x, y);
+}
class AutoImmediateDrawIfNeeded {
public:
diff --git a/src/utils/SkGatherPixelRefsAndRects.h b/src/utils/SkGatherPixelRefsAndRects.h
index 1c9d6fc..894b8f0 100644
--- a/src/utils/SkGatherPixelRefsAndRects.h
+++ b/src/utils/SkGatherPixelRefsAndRects.h
@@ -291,12 +291,6 @@
virtual const SkBitmap& onAccessBitmap() SK_OVERRIDE {
return fEmptyBitmap;
}
- virtual bool onReadPixels(const SkBitmap& bitmap,
- int x, int y,
- SkCanvas::Config8888 config8888) SK_OVERRIDE {
- NotSupported();
- return false;
- }
virtual void lockPixels() SK_OVERRIDE { NothingToDo(); }
virtual void unlockPixels() SK_OVERRIDE { NothingToDo(); }
virtual bool allowImageFilter(const SkImageFilter*) SK_OVERRIDE { return false; }
diff --git a/src/utils/SkPictureUtils.cpp b/src/utils/SkPictureUtils.cpp
index 78d70ca..fc1611d 100644
--- a/src/utils/SkPictureUtils.cpp
+++ b/src/utils/SkPictureUtils.cpp
@@ -157,13 +157,6 @@
}
protected:
- virtual bool onReadPixels(const SkBitmap& bitmap,
- int x, int y,
- SkCanvas::Config8888 config8888) SK_OVERRIDE {
- not_supported();
- return false;
- }
-
virtual void replaceBitmapBackendForRasterSurface(const SkBitmap&) SK_OVERRIDE {
not_supported();
}