From 889b09edfeb5f461ca283dfd08ee6b23560a7859 Mon Sep 17 00:00:00 2001 From: "reed@google.com" Date: Fri, 27 Jul 2012 21:10:42 +0000 Subject: check-point for surface experiment git-svn-id: http://skia.googlecode.com/svn/trunk@4819 2bbb7eff-a529-9590-31e7-b0007b416f81 --- src/image/SkImage.cpp | 97 ++++++++------------------ src/image/SkImagePriv.cpp | 109 +++++++++++++++++++++++++++++ src/image/SkImagePriv.h | 27 ++++++++ src/image/SkSurface.cpp | 173 ++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 336 insertions(+), 70 deletions(-) create mode 100644 src/image/SkImagePriv.cpp create mode 100644 src/image/SkImagePriv.h create mode 100644 src/image/SkSurface.cpp (limited to 'src') diff --git a/src/image/SkImage.cpp b/src/image/SkImage.cpp index 0573a83836..4d96b9ffff 100644 --- a/src/image/SkImage.cpp +++ b/src/image/SkImage.cpp @@ -1,5 +1,5 @@ #include "SkImage.h" - +#include "SkImagePriv.h" #include "SkBitmap.h" /////////////////////////////////////////////////////////////////////////////// @@ -20,70 +20,6 @@ static SkImage_Base* asIB(SkImage* image) { /////////////////////////////////////////////////////////////////////////////// -static SkBitmap::Config InfoToConfig(const SkImage::Info& info, bool* isOpaque) { - switch (info.fColorType) { - case SkImage::kAlpha_8_ColorType: - switch (info.fAlphaType) { - case SkImage::kIgnore_AlphaType: - // makes no sense - return SkBitmap::kNo_Config; - - case SkImage::kOpaque_AlphaType: - *isOpaque = true; - return SkBitmap::kA8_Config; - - case SkImage::kPremul_AlphaType: - case SkImage::kUnpremul_AlphaType: - *isOpaque = false; - return SkBitmap::kA8_Config; - } - break; - - case SkImage::kRGB_565_ColorType: - // we ignore fAlpahType, though some would not make sense - *isOpaque = true; - return SkBitmap::kRGB_565_Config; - - case SkImage::kRGBA_8888_ColorType: - case SkImage::kBGRA_8888_ColorType: - // not supported yet - return SkBitmap::kNo_Config; - - case SkImage::kPMColor_ColorType: - switch (info.fAlphaType) { - case SkImage::kIgnore_AlphaType: - case SkImage::kUnpremul_AlphaType: - // not supported yet - return SkBitmap::kNo_Config; - case SkImage::kOpaque_AlphaType: - *isOpaque = true; - return SkBitmap::kARGB_8888_Config; - case SkImage::kPremul_AlphaType: - *isOpaque = false; - return SkBitmap::kARGB_8888_Config; - } - break; - } - SkASSERT(!"how did we get here"); - return SkBitmap::kNo_Config; -} - -static int BytesPerPixel(SkImage::ColorType ct) { - static const uint8_t gColorTypeBytesPerPixel[] = { - 1, // kAlpha_8_ColorType - 2, // kRGB_565_ColorType - 4, // kRGBA_8888_ColorType - 4, // kBGRA_8888_ColorType - 4, // kPMColor_ColorType - }; - - SkASSERT((size_t)ct < SK_ARRAY_COUNT(gColorTypeBytesPerPixel)); - return gColorTypeBytesPerPixel[ct]; -} - -static size_t ComputeMinRowBytes(const SkImage::Info& info) { - return info.fWidth * BytesPerPixel(info.fColorType); -} class SkImage_Raster : public SkImage_Base { public: @@ -105,13 +41,13 @@ public: } bool isOpaque; - if (InfoToConfig(info, &isOpaque) == SkBitmap::kNo_Config) { + if (SkImageInfoToBitmapConfig(info, &isOpaque) == SkBitmap::kNo_Config) { return false; } // TODO: check colorspace - if (rowBytes < ComputeMinRowBytes(info)) { + if (rowBytes < SkImageMinRowBytes(info)) { return false; } @@ -129,6 +65,9 @@ public: virtual const SkBitmap* asABitmap() SK_OVERRIDE; + // exposed for SkSurface_Raster via SkNewImageFromPixelRef + SkImage_Raster(const SkImage::Info&, SkPixelRef*, size_t rowBytes); + private: SkImage_Raster() : INHERITED(0, 0) {} @@ -137,6 +76,11 @@ private: typedef SkImage_Base INHERITED; }; +SkImage* SkNewImageFromPixelRef(const SkImage::Info& info, SkPixelRef* pr, + size_t rowBytes) { + return SkNEW_ARGS(SkImage_Raster, (info, pr, rowBytes)); +} + /////////////////////////////////////////////////////////////////////////////// #include "SkData.h" @@ -154,14 +98,27 @@ SkImage* SkImage_Raster::NewEmpty() { SkImage_Raster::SkImage_Raster(const Info& info, SkColorSpace* cs, SkData* data, size_t rowBytes) +: INHERITED(info.fWidth, info.fHeight) { + bool isOpaque; + SkBitmap::Config config = SkImageInfoToBitmapConfig(info, &isOpaque); + + fBitmap.setConfig(config, info.fWidth, info.fHeight, rowBytes); + fBitmap.setPixelRef(SkNEW_ARGS(SkDataPixelRef, (data)))->unref(); + fBitmap.setIsOpaque(isOpaque); + fBitmap.setImmutable(); +} + +SkImage_Raster::SkImage_Raster(const Info& info, SkPixelRef* pr, size_t rowBytes) : INHERITED(info.fWidth, info.fHeight) { + SkASSERT(pr->isImmutable()); + bool isOpaque; - SkBitmap::Config config = InfoToConfig(info, &isOpaque); + SkBitmap::Config config = SkImageInfoToBitmapConfig(info, &isOpaque); fBitmap.setConfig(config, info.fWidth, info.fHeight, rowBytes); - fBitmap.setPixelRef(SkNEW_ARGS(SkDataPixelRef, (data)))->unref(); + fBitmap.setPixelRef(pr); fBitmap.setIsOpaque(isOpaque); - fBitmap.setImmutable(); // Yea baby! + fBitmap.setImmutable(); } SkImage_Raster::~SkImage_Raster() {} diff --git a/src/image/SkImagePriv.cpp b/src/image/SkImagePriv.cpp new file mode 100644 index 0000000000..d0c56fd2ef --- /dev/null +++ b/src/image/SkImagePriv.cpp @@ -0,0 +1,109 @@ +#include "SkImagePriv.h" + +SkBitmap::Config SkImageInfoToBitmapConfig(const SkImage::Info& info, + bool* isOpaque) { + switch (info.fColorType) { + case SkImage::kAlpha_8_ColorType: + switch (info.fAlphaType) { + case SkImage::kIgnore_AlphaType: + // makes no sense + return SkBitmap::kNo_Config; + + case SkImage::kOpaque_AlphaType: + *isOpaque = true; + return SkBitmap::kA8_Config; + + case SkImage::kPremul_AlphaType: + case SkImage::kUnpremul_AlphaType: + *isOpaque = false; + return SkBitmap::kA8_Config; + } + break; + + case SkImage::kRGB_565_ColorType: + // we ignore fAlpahType, though some would not make sense + *isOpaque = true; + return SkBitmap::kRGB_565_Config; + + case SkImage::kRGBA_8888_ColorType: + case SkImage::kBGRA_8888_ColorType: + // not supported yet + return SkBitmap::kNo_Config; + + case SkImage::kPMColor_ColorType: + switch (info.fAlphaType) { + case SkImage::kIgnore_AlphaType: + case SkImage::kUnpremul_AlphaType: + // not supported yet + return SkBitmap::kNo_Config; + case SkImage::kOpaque_AlphaType: + *isOpaque = true; + return SkBitmap::kARGB_8888_Config; + case SkImage::kPremul_AlphaType: + *isOpaque = false; + return SkBitmap::kARGB_8888_Config; + } + break; + } + SkASSERT(!"how did we get here"); + return SkBitmap::kNo_Config; +} + +int SkImageBytesPerPixel(SkImage::ColorType ct) { + static const uint8_t gColorTypeBytesPerPixel[] = { + 1, // kAlpha_8_ColorType + 2, // kRGB_565_ColorType + 4, // kRGBA_8888_ColorType + 4, // kBGRA_8888_ColorType + 4, // kPMColor_ColorType + }; + + SkASSERT((size_t)ct < SK_ARRAY_COUNT(gColorTypeBytesPerPixel)); + return gColorTypeBytesPerPixel[ct]; +} + +bool SkBitmapToImageInfo(const SkBitmap& bm, SkImage::Info* info) { + switch (bm.config()) { + case SkBitmap::kA8_Config: + info->fColorType = SkImage::kAlpha_8_ColorType; + break; + + case SkBitmap::kRGB_565_Config: + info->fColorType = SkImage::kRGB_565_ColorType; + break; + + case SkBitmap::kARGB_8888_Config: + info->fColorType = SkImage::kPMColor_ColorType; + break; + + default: + return false; + } + + info->fWidth = bm.width(); + info->fHeight = bm.height(); + info->fAlphaType = bm.isOpaque() ? SkImage::kOpaque_AlphaType : + SkImage::kPremul_AlphaType; + return true; +} + +SkImage* SkNewImageFromBitmap(const SkBitmap& bm) { + SkImage::Info info; + if (!SkBitmapToImageInfo(bm, &info)) { + return NULL; + } + + SkImage* image = NULL; + if (bm.isImmutable()) { + image = SkNewImageFromPixelRef(info, bm.pixelRef(), bm.rowBytes()); + } else { + bm.lockPixels(); + if (NULL == bm.getPixels()) { + image = SkImage::NewRasterCopy(info, NULL, bm.getPixels(), + bm.rowBytes()); + } + bm.unlockPixels(); + } + return image; +} + diff --git a/src/image/SkImagePriv.h b/src/image/SkImagePriv.h new file mode 100644 index 0000000000..1c732c3b9f --- /dev/null +++ b/src/image/SkImagePriv.h @@ -0,0 +1,27 @@ + +#ifndef SkImagePriv_DEFINED +#define SkImagePriv_DEFINED + +#include "SkBitmap.h" +#include "SkImage.h" + +extern SkBitmap::Config SkImageInfoToBitmapConfig(const SkImage::Info&, + bool* isOpaque); + +extern int SkImageBytesPerPixel(SkImage::ColorType); + +extern bool SkBitmapToImageInfo(const SkBitmap&, SkImage::Info*); +extern SkImage* SkNewImageFromPixelRef(const SkImage::Info&, SkPixelRef*, + size_t rowBytes); + +/** + * Examines the bitmap to decide if it can share the existing pixelRef, or + * if it needs to make a deep-copy of the pixels + */ +extern SkImage* SkNewImageFromBitmap(const SkBitmap&); + +static inline size_t SkImageMinRowBytes(const SkImage::Info& info) { + return info.fWidth * SkImageBytesPerPixel(info.fColorType); +} + +#endif diff --git a/src/image/SkSurface.cpp b/src/image/SkSurface.cpp new file mode 100644 index 0000000000..2a9e33a8e2 --- /dev/null +++ b/src/image/SkSurface.cpp @@ -0,0 +1,173 @@ +#include "SkSurface.h" +#include "SkImagePriv.h" +#include "SkCanvas.h" + +/////////////////////////////////////////////////////////////////////////////// + +class SkSurface_Base : public SkSurface { +public: + SkSurface_Base(int width, int height) : INHERITED(width, height) {} + + virtual SkCanvas* onNewCanvas() = 0; + virtual SkSurface* onNewSurface(const SkImage::Info&, SkColorSpace*) = 0; + virtual SkImage* onNewImageShapshot() = 0; + + /** + * Default implementation: + * + * image = this->newImageSnapshot(); + * if (image) { + * image->draw(canvas, ...); + * image->unref(); + * } + */ + virtual void onDraw(SkCanvas*, SkScalar x, SkScalar y, const SkPaint*); + +private: + typedef SkSurface INHERITED; +}; + +void SkSurface_Base::onDraw(SkCanvas* canvas, SkScalar x, SkScalar y, + const SkPaint* paint) { + SkImage* image = this->newImageShapshot(); + if (image) { + image->draw(canvas, x, y, paint); + image->unref(); + } +} + +static SkSurface_Base* asSB(SkSurface* surface) { + return static_cast(surface); +} + +/////////////////////////////////////////////////////////////////////////////// + +SkSurface::SkSurface(int width, int height) : fWidth(width), fHeight(height) { + SkASSERT(width >= 0); + SkASSERT(height >= 0); + fGenerationID = 0; +} + +SkCanvas* SkSurface::newCanvas() { + return asSB(this)->onNewCanvas(); +} + +SkSurface* SkSurface::newSurface(const SkImage::Info& info, SkColorSpace* cs) { + return asSB(this)->onNewSurface(info, cs); +} + +SkImage* SkSurface::newImageShapshot() { + return asSB(this)->onNewImageShapshot(); +} + +void SkSurface::draw(SkCanvas* canvas, SkScalar x, SkScalar y, + const SkPaint* paint) { + return asSB(this)->onDraw(canvas, x, y, paint); +} + +/////////////////////////////////////////////////////////////////////////////// + +class SkSurface_Raster : public SkSurface { +public: + static bool Valid(const SkImage::Info&, SkColorSpace*, size_t rb); + + SkSurface_Raster(const SkImage::Info&, SkColorSpace*, void*, size_t rb); + + virtual SkCanvas* onNewCanvas() SK_OVERRIDE; + virtual SkSurface* onNewSurface(const SkImage::Info&, SkColorSpace*) SK_OVERRIDE; + virtual SkImage* onNewImageShapshot() SK_OVERRIDE; + virtual void onDraw(SkCanvas*, SkScalar x, SkScalar y, + const SkPaint*) SK_OVERRIDE; + +private: + SkBitmap fBitmap; + + typedef SkSurface INHERITED; +}; + +bool SkSurface_Raster::Valid(const SkImage::Info& info, SkColorSpace* cs, + size_t rowBytes) { + static size_t kMaxTotalSize = (1 << 31) - 1; + + bool isOpaque; + SkBitmap::Config config = SkImageInfoToBitmapConfig(info, &isOpaque); + + int shift = 0; + switch (config) { + case SkBitmap::kA8_Config: + shift = 0; + break; + case SkBitmap::kRGB_565_Config: + shift = 1; + break; + case SkBitmap::kARGB_8888_Config: + shift = 2; + break; + default: + return false; + } + + // TODO: examine colorspace + + uint64_t minRB = (uint64_t)info.fWidth << shift; + if (minRB > rowBytes) { + return false; + } + + size_t alignedRowBytes = rowBytes >> shift << shift; + if (alignedRowBytes != rowBytes) { + return false; + } + + uint64_t size = (uint64_t)info.fHeight * rowBytes; + if (size > kMaxTotalSize) { + return false; + } + + return true; +} + +SkSurface_Raster::SkSurface_Raster(const SkImage::Info& info, SkColorSpace* cs, + void* pixels, size_t rb) + : INHERITED(info.fWidth, info.fHeight) { + bool isOpaque; + SkBitmap::Config config = SkImageInfoToBitmapConfig(info, &isOpaque); + + fBitmap.setConfig(config, info.fWidth, info.fHeight, rb); + fBitmap.setPixels(pixels); + fBitmap.setIsOpaque(isOpaque); +} + +SkCanvas* SkSurface_Raster::onNewCanvas() { + return SkNEW_ARGS(SkCanvas, (fBitmap)); +} + +SkSurface* SkSurface_Raster::onNewSurface(const SkImage::Info& info, + SkColorSpace* cs) { + return SkSurface::NewRaster(info, cs); +} + +SkImage* SkSurface_Raster::onNewImageShapshot() { + return SkNewImageFromBitmap(fBitmap); +} + +void SkSurface_Raster::onDraw(SkCanvas* canvas, SkScalar x, SkScalar y, + const SkPaint* paint) { + canvas->drawBitmap(fBitmap, x, y, paint); +} + +/////////////////////////////////////////////////////////////////////////////// + +SkSurface* SkSurface::NewRasterDirect(const SkImage::Info& info, + SkColorSpace* cs, + void* pixels, size_t rowBytes) { + if (!SkSurface_Raster::Valid(info, cs, rowBytes)) { + return NULL; + } + if (NULL == pixels) { + return NULL; + } + + return SkNEW_ARGS(SkSurface_Raster, (info, cs, pixels, rowBytes)); +} + -- cgit v1.2.3