check-point for image experiment

git-svn-id: http://skia.googlecode.com/svn/trunk@4811 2bbb7eff-a529-9590-31e7-b0007b416f81
This commit is contained in:
reed@google.com 2012-07-27 18:02:50 +00:00
parent 20a550c6ea
commit f6627b78f9
4 changed files with 379 additions and 12 deletions

View File

@ -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,19 +103,38 @@ 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)
@ -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

View File

@ -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<void*>(fData->data()), NULL);
}
SkDataPixelRef::~SkDataPixelRef() {
fData->unref();
}
void* SkDataPixelRef::onLockPixels(SkColorTable** ct) {
*ct = NULL;
return const_cast<void*>(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<void*>(fData->data()), NULL);
}
SK_DEFINE_FLATTENABLE_REGISTRAR(SkDataPixelRef)

View File

@ -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

239
src/image/SkImage.cpp Normal file
View File

@ -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<SkImage_Base*>(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);
}
}