From f6627b78f933b77b358ac0791c520f99b0e79fca Mon Sep 17 00:00:00 2001 From: "reed@google.com" Date: Fri, 27 Jul 2012 18:02:50 +0000 Subject: [PATCH] check-point for image experiment git-svn-id: http://skia.googlecode.com/svn/trunk@4811 2bbb7eff-a529-9590-31e7-b0007b416f81 --- include/core/SkImage.h | 75 +++++++++++--- src/image/SkDataPixelRef.cpp | 42 ++++++++ src/image/SkDataPixelRef.h | 35 +++++++ src/image/SkImage.cpp | 239 +++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 379 insertions(+), 12 deletions(-) create mode 100644 src/image/SkDataPixelRef.cpp create mode 100644 src/image/SkDataPixelRef.h create mode 100644 src/image/SkImage.cpp diff --git a/include/core/SkImage.h b/include/core/SkImage.h index 9f1bd1f..df71875 100644 --- a/include/core/SkImage.h +++ b/include/core/SkImage.h @@ -8,9 +8,20 @@ #ifndef SkImage_DEFINED #define SkImage_DEFINED +#include "SkRefCnt.h" +#include "SkScalar.h" + +class SkData; +class SkCanvas; +class SkPaint; +class SkShader; + +// need for TileMode +#include "SkShader.h" ////// EXPERIMENTAL +class SkColorSpace; /** * SkImage is an abstraction for drawing a rectagle of pixels, though the @@ -25,18 +36,22 @@ class SkImage : public SkRefCnt { public: enum ColorType { - kA8_ColorType, + kAlpha_8_ColorType, kRGB_565_ColorType, kRGBA_8888_ColorType, kBGRA_8888_ColorType, kPMColor_ColorType, + + kLastEnum_ColorType = kPMColor_ColorType }; enum AlphaType { kIgnore_AlphaType, kOpaque_AlphaType, kPremul_AlphaType, - kUnpremul_AlphaType + kUnpremul_AlphaType, + + kLastEnum_AlphaType = kUnpremul_AlphaType }; struct Info { @@ -51,14 +66,31 @@ public: static SkImage* NewRasterData(const Info&, SkColorSpace*, SkData* pixels, size_t rowBytes); static SkImage* NewEncodedData(SkData*); - int width() const; - int height() const; - uint32_t uniqueID() const; - + int width() const { return fWidth; } + int height() const { return fHeight; } + uint32_t uniqueID() const { return fUniqueID; } + SkShader* newShaderClamp() const; SkShader* newShader(SkShader::TileMode, SkShader::TileMode) const; - - void SkCanvas::drawImage(...); + + void draw(SkCanvas*, SkScalar x, SkScalar y, const SkPaint*); + +protected: + SkImage(int width, int height) : + fWidth(width), + fHeight(height), + fUniqueID(NextUniqueID()) { + + SkASSERT(width >= 0); + SkASSERT(height >= 0); + } + +private: + const int fWidth; + const int fHeight; + const uint32_t fUniqueID; + + static uint32_t NextUniqueID(); }; /** @@ -71,20 +103,39 @@ public: */ class SkSurface : public SkRefCnt { public: - static SkSurface* NewRasterDirect(const Info&, SkColorSpace*, + static SkSurface* NewRasterDirect(const SkImage::Info&, SkColorSpace*, const void* pixels, size_t rowBytes); - static SkSurface* NewRaster(const Info&, SkColorSpace*); + static SkSurface* NewRaster(const SkImage::Info&, SkColorSpace*); static SkSurface* NewGpu(GrContext*); static SkSurface* NewPDF(...); static SkSurface* NewXPS(...); static SkSurface* NewPicture(int width, int height); /** - * Return a canvas that will draw into this surface + * Return a canvas that will draw into this surface. + * + * LIFECYCLE QUESTIONS + * 1. Is this owned by the surface or the caller? + * 2. Can the caller get a 2nd canvas, or reset the state of the first? */ SkCanvas* newCanvas(); /** + * Return a new surface that is "compatible" with this one, in that it will + * efficiently be able to be drawn into this surface. Typical calling + * pattern: + * + * SkSurface* A = SkSurface::New...(); + * SkCanvas* canvasA = surfaceA->newCanvas(); + * ... + * SkSurface* surfaceB = surfaceA->newSurface(...); + * SkCanvas* canvasB = surfaceB->newCanvas(); + * ... // draw using canvasB + * canvasA->drawSurface(surfaceB); // <--- this will always be optimal! + */ + SkSurface* newSurface(int width, int height); + + /** * Returns an image of the current state of the surface pixels up to this * point. Subsequent changes to the surface (by drawing into its canvas) * will not be reflected in this image. @@ -98,7 +149,7 @@ public: * we'd know that the "snapshot" need only live until we've handed it off * to the canvas. */ - void SkCanvas::drawSurface(...); + void draw(SkCanvas*, SkScalar x, SkScalar y, const SkPaint*); }; #endif diff --git a/src/image/SkDataPixelRef.cpp b/src/image/SkDataPixelRef.cpp new file mode 100644 index 0000000..e02f0ec --- /dev/null +++ b/src/image/SkDataPixelRef.cpp @@ -0,0 +1,42 @@ +/* + * Copyright 2012 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "SkDataPixelRef.h" +#include "SkData.h" + +SkDataPixelRef::SkDataPixelRef(SkData* data) : fData(data) { + fData->ref(); + this->setPreLocked(const_cast(fData->data()), NULL); +} + +SkDataPixelRef::~SkDataPixelRef() { + fData->unref(); +} + +void* SkDataPixelRef::onLockPixels(SkColorTable** ct) { + *ct = NULL; + return const_cast(fData->data()); +} + +void SkDataPixelRef::onUnlockPixels() { + // nothing to do +} + +void SkDataPixelRef::flatten(SkFlattenableWriteBuffer& buffer) const { + this->INHERITED::flatten(buffer); + +// fData->flatten(buffer); +} + +SkDataPixelRef::SkDataPixelRef(SkFlattenableReadBuffer& buffer) + : INHERITED(buffer, NULL) { + +// fData = buffer.readData(); + this->setPreLocked(const_cast(fData->data()), NULL); +} + +SK_DEFINE_FLATTENABLE_REGISTRAR(SkDataPixelRef) diff --git a/src/image/SkDataPixelRef.h b/src/image/SkDataPixelRef.h new file mode 100644 index 0000000..b6e16e0 --- /dev/null +++ b/src/image/SkDataPixelRef.h @@ -0,0 +1,35 @@ +/* + * Copyright 2012 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkDataPixelRef_DEFINED +#define SkDataPixelRef_DEFINED + +#include "SkPixelRef.h" + +class SkData; + +class SkDataPixelRef : public SkPixelRef { +public: + SkDataPixelRef(SkData* data); + virtual ~SkDataPixelRef(); + + SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkDataPixelRef) + +protected: + virtual void* onLockPixels(SkColorTable**) SK_OVERRIDE; + virtual void onUnlockPixels() SK_OVERRIDE; + + SkDataPixelRef(SkFlattenableReadBuffer& buffer); + virtual void flatten(SkFlattenableWriteBuffer&) const SK_OVERRIDE; + +private: + SkData* fData; + + typedef SkPixelRef INHERITED; +}; + +#endif diff --git a/src/image/SkImage.cpp b/src/image/SkImage.cpp new file mode 100644 index 0000000..0573a83 --- /dev/null +++ b/src/image/SkImage.cpp @@ -0,0 +1,239 @@ +#include "SkImage.h" + +#include "SkBitmap.h" + +/////////////////////////////////////////////////////////////////////////////// + +class SkImage_Base : public SkImage { +public: + SkImage_Base(int width, int height) : INHERITED(width, height) {} + + virtual const SkBitmap* asABitmap() { return NULL; } + +private: + typedef SkImage INHERITED; +}; + +static SkImage_Base* asIB(SkImage* image) { + return static_cast(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: + static bool ValidArgs(const Info& info, SkColorSpace* cs, size_t rowBytes) { + const int maxDimension = SK_MaxS32 >> 2; + const size_t kMaxPixelByteSize = SK_MaxS32; + + if (info.fWidth < 0 || info.fHeight < 0) { + return false; + } + if (info.fWidth > maxDimension || info.fHeight > maxDimension) { + return false; + } + if ((unsigned)info.fColorType > (unsigned)kLastEnum_ColorType) { + return false; + } + if ((unsigned)info.fAlphaType > (unsigned)kLastEnum_AlphaType) { + return false; + } + + bool isOpaque; + if (InfoToConfig(info, &isOpaque) == SkBitmap::kNo_Config) { + return false; + } + + // TODO: check colorspace + + if (rowBytes < ComputeMinRowBytes(info)) { + return false; + } + + int64_t size = (int64_t)info.fHeight * rowBytes; + if (size > kMaxPixelByteSize) { + return false; + } + return true; + } + + static SkImage* NewEmpty(); + + SkImage_Raster(const SkImage::Info&, SkColorSpace*, SkData*, size_t rb); + virtual ~SkImage_Raster(); + + virtual const SkBitmap* asABitmap() SK_OVERRIDE; + +private: + SkImage_Raster() : INHERITED(0, 0) {} + + SkBitmap fBitmap; + + typedef SkImage_Base INHERITED; +}; + +/////////////////////////////////////////////////////////////////////////////// + +#include "SkData.h" +#include "SkDataPixelRef.h" + +SkImage* SkImage_Raster::NewEmpty() { + // Returns lazily created singleton + static SkImage* gEmpty; + if (NULL == gEmpty) { + gEmpty = SkNEW(SkImage_Raster); + } + gEmpty->ref(); + return gEmpty; +} + +SkImage_Raster::SkImage_Raster(const Info& info, SkColorSpace* cs, + SkData* data, size_t rowBytes) + : INHERITED(info.fWidth, info.fHeight) { + bool isOpaque; + SkBitmap::Config config = InfoToConfig(info, &isOpaque); + + fBitmap.setConfig(config, info.fWidth, info.fHeight, rowBytes); + fBitmap.setPixelRef(SkNEW_ARGS(SkDataPixelRef, (data)))->unref(); + fBitmap.setIsOpaque(isOpaque); + fBitmap.setImmutable(); // Yea baby! +} + +SkImage_Raster::~SkImage_Raster() {} + +const SkBitmap* SkImage_Raster::asABitmap() { + return &fBitmap; +} + +/////////////////////////////////////////////////////////////////////////////// + +SkImage* SkImage::NewRasterCopy(const SkImage::Info& info, SkColorSpace* cs, + const void* pixels, size_t rowBytes) { + if (!SkImage_Raster::ValidArgs(info, cs, rowBytes)) { + return NULL; + } + if (0 == info.fWidth && 0 == info.fHeight) { + return SkImage_Raster::NewEmpty(); + } + // check this after empty-check + if (NULL == pixels) { + return NULL; + } + + // Here we actually make a copy of the caller's pixel data + SkAutoDataUnref data(SkData::NewWithCopy(pixels, info.fHeight * rowBytes)); + return SkNEW_ARGS(SkImage_Raster, (info, cs, data, rowBytes)); +} + + +SkImage* SkImage::NewRasterData(const SkImage::Info& info, SkColorSpace* cs, + SkData* pixelData, size_t rowBytes) { + if (!SkImage_Raster::ValidArgs(info, cs, rowBytes)) { + return NULL; + } + if (0 == info.fWidth && 0 == info.fHeight) { + return SkImage_Raster::NewEmpty(); + } + // check this after empty-check + if (NULL == pixelData) { + return NULL; + } + + // did they give us enough data? + size_t size = info.fHeight * rowBytes; + if (pixelData->size() < size) { + return NULL; + } + + SkAutoDataUnref data(pixelData); + return SkNEW_ARGS(SkImage_Raster, (info, cs, data, rowBytes)); +} + +/////////////////////////////////////////////////////////////////////////////// + +#include "SkCanvas.h" + +uint32_t SkImage::NextUniqueID() { + static int32_t gUniqueID; + + // never return 0; + uint32_t id; + do { + id = sk_atomic_inc(&gUniqueID) + 1; + } while (0 == id); + return id; +} + +void SkImage::draw(SkCanvas* canvas, SkScalar x, SkScalar y, + const SkPaint* paint) { + const SkBitmap* bitmap = asIB(this)->asABitmap(); + if (bitmap) { + canvas->drawBitmap(*bitmap, x, y, paint); + } +} + -- 2.7.4