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:
parent
20a550c6ea
commit
f6627b78f9
@ -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
|
||||
|
42
src/image/SkDataPixelRef.cpp
Normal file
42
src/image/SkDataPixelRef.cpp
Normal 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)
|
35
src/image/SkDataPixelRef.h
Normal file
35
src/image/SkDataPixelRef.h
Normal 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
239
src/image/SkImage.cpp
Normal 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);
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user