зеркало из https://github.com/mozilla/gecko-dev.git
Merge m-c to fx-team
This commit is contained in:
Коммит
4b6c7f4bc0
2
CLOBBER
2
CLOBBER
|
@ -22,4 +22,4 @@
|
|||
# changes to stick? As of bug 928195, this shouldn't be necessary! Please
|
||||
# don't change CLOBBER for WebIDL changes any more.
|
||||
|
||||
Recent Android build system changes from bug 961339 and bug 946083 seem to be needs-clobbery.
|
||||
Skia update from Bug 910754 needs a CLOBBER build
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#include "MacIOSurface.h"
|
||||
#include "FilterNodeSoftware.h"
|
||||
#include "mozilla/Assertions.h"
|
||||
#include "mozilla/FloatingPoint.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
|
@ -413,6 +414,8 @@ UpdateLinearParametersToIncludePoint(double *min_t, double *max_t,
|
|||
double dx, double dy,
|
||||
double x, double y)
|
||||
{
|
||||
MOZ_ASSERT(IsFinite(x) && IsFinite(y));
|
||||
|
||||
/**
|
||||
* Compute a parameter t such that a line perpendicular to the (dx,dy)
|
||||
* vector, passing through (start->x + dx*t, start->y + dy*t), also
|
||||
|
@ -609,6 +612,10 @@ DrawRadialRepeatingGradient(CGContextRef cg, const RadialGradientPattern &aPatte
|
|||
static void
|
||||
DrawGradient(CGContextRef cg, const Pattern &aPattern, const CGRect &aExtents)
|
||||
{
|
||||
if (CGRectIsEmpty(aExtents)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (aPattern.GetType() == PatternType::LINEAR_GRADIENT) {
|
||||
const LinearGradientPattern& pat = static_cast<const LinearGradientPattern&>(aPattern);
|
||||
GradientStopsCG *stops = static_cast<GradientStopsCG*>(pat.mStops.get());
|
||||
|
|
|
@ -7,7 +7,8 @@
|
|||
#include "SourceSurfaceSkia.h"
|
||||
#include "ScaledFontBase.h"
|
||||
#include "ScaledFontCairo.h"
|
||||
#include "skia/SkDevice.h"
|
||||
#include "skia/SkGpuDevice.h"
|
||||
#include "skia/SkBitmapDevice.h"
|
||||
#include "FilterNodeSoftware.h"
|
||||
|
||||
#ifdef USE_SKIA_GPU
|
||||
|
@ -747,9 +748,9 @@ DrawTargetSkia::CopySurface(SourceSurface *aSurface,
|
|||
bool
|
||||
DrawTargetSkia::Init(const IntSize &aSize, SurfaceFormat aFormat)
|
||||
{
|
||||
SkAutoTUnref<SkDevice> device(new SkDevice(GfxFormatToSkiaConfig(aFormat),
|
||||
aSize.width, aSize.height,
|
||||
aFormat == SurfaceFormat::B8G8R8X8));
|
||||
SkAutoTUnref<SkBaseDevice> device(new SkBitmapDevice(GfxFormatToSkiaConfig(aFormat),
|
||||
aSize.width, aSize.height,
|
||||
aFormat == SurfaceFormat::B8G8R8X8));
|
||||
|
||||
SkBitmap bitmap = device->accessBitmap(true);
|
||||
if (!bitmap.allocPixels()) {
|
||||
|
@ -794,7 +795,7 @@ DrawTargetSkia::InitWithGLContextAndGrGLInterface(GenericRefCountedBase* aGLCont
|
|||
targetDescriptor.fRenderTargetHandle = 0; // GLContext always exposes the right framebuffer as id 0
|
||||
|
||||
SkAutoTUnref<GrRenderTarget> target(mGrContext->wrapBackendRenderTarget(targetDescriptor));
|
||||
SkAutoTUnref<SkDevice> device(new SkGpuDevice(mGrContext.get(), target.get()));
|
||||
SkAutoTUnref<SkBaseDevice> device(new SkGpuDevice(mGrContext.get(), target.get()));
|
||||
SkAutoTUnref<SkCanvas> canvas(new SkCanvas(device.get()));
|
||||
mCanvas = canvas.get();
|
||||
|
||||
|
@ -812,18 +813,17 @@ DrawTargetSkia::SetCacheLimits(int aCount, int aSizeInBytes)
|
|||
void
|
||||
DrawTargetSkia::Init(unsigned char* aData, const IntSize &aSize, int32_t aStride, SurfaceFormat aFormat)
|
||||
{
|
||||
bool isOpaque = false;
|
||||
SkAlphaType alphaType = kPremul_SkAlphaType;
|
||||
if (aFormat == SurfaceFormat::B8G8R8X8) {
|
||||
// We have to manually set the A channel to be 255 as Skia doesn't understand BGRX
|
||||
ConvertBGRXToBGRA(aData, aSize, aStride);
|
||||
isOpaque = true;
|
||||
alphaType = kOpaque_SkAlphaType;
|
||||
}
|
||||
|
||||
SkBitmap bitmap;
|
||||
bitmap.setConfig(GfxFormatToSkiaConfig(aFormat), aSize.width, aSize.height, aStride);
|
||||
bitmap.setConfig(GfxFormatToSkiaConfig(aFormat), aSize.width, aSize.height, aStride, alphaType);
|
||||
bitmap.setPixels(aData);
|
||||
bitmap.setIsOpaque(isOpaque);
|
||||
SkAutoTUnref<SkCanvas> canvas(new SkCanvas(new SkDevice(bitmap)));
|
||||
SkAutoTUnref<SkCanvas> canvas(new SkCanvas(new SkBitmapDevice(bitmap)));
|
||||
|
||||
mSize = aSize;
|
||||
mCanvas = canvas.get();
|
||||
|
|
|
@ -18,19 +18,18 @@ bool Scale(uint8_t* srcData, int32_t srcWidth, int32_t srcHeight, int32_t srcStr
|
|||
SurfaceFormat format)
|
||||
{
|
||||
#ifdef USE_SKIA
|
||||
bool opaque;
|
||||
SkAlphaType alphaType;
|
||||
if (format == SurfaceFormat::B8G8R8A8) {
|
||||
opaque = false;
|
||||
alphaType = kPremul_SkAlphaType;
|
||||
} else {
|
||||
opaque = true;
|
||||
alphaType = kOpaque_SkAlphaType;
|
||||
}
|
||||
|
||||
SkBitmap::Config config = GfxFormatToSkiaConfig(format);
|
||||
|
||||
SkBitmap imgSrc;
|
||||
imgSrc.setConfig(config, srcWidth, srcHeight, srcStride);
|
||||
imgSrc.setConfig(config, srcWidth, srcHeight, srcStride, alphaType);
|
||||
imgSrc.setPixels(srcData);
|
||||
imgSrc.setIsOpaque(opaque);
|
||||
|
||||
// Rescaler is compatible with 32 bpp only. Convert to RGB32 if needed.
|
||||
if (config != SkBitmap::kARGB_8888_Config) {
|
||||
|
|
|
@ -78,7 +78,7 @@ SourceSurfaceSkia::InitFromData(unsigned char* aData,
|
|||
ConvertBGRXToBGRA(reinterpret_cast<unsigned char*>(mBitmap.getPixels()), aSize, mBitmap.rowBytes());
|
||||
mBitmap.unlockPixels();
|
||||
mBitmap.notifyPixelsChanged();
|
||||
mBitmap.setIsOpaque(true);
|
||||
mBitmap.setAlphaType(kOpaque_SkAlphaType);
|
||||
}
|
||||
|
||||
mSize = aSize;
|
||||
|
|
|
@ -470,7 +470,7 @@ SkBitmap ImageOperations::ResizeSubpixel(const SkBitmap& source,
|
|||
src_row += h * row_words;
|
||||
dst_row += result.rowBytes() / 4;
|
||||
}
|
||||
result.setIsOpaque(img.isOpaque());
|
||||
result.setAlphaType(img.alphaType());
|
||||
return result;
|
||||
#else
|
||||
return SkBitmap();
|
||||
|
@ -534,7 +534,7 @@ SkBitmap ImageOperations::ResizeBasic(const SkBitmap& source,
|
|||
/* sse = */ false);
|
||||
|
||||
// Preserve the "opaque" flag for use as an optimization later.
|
||||
result.setIsOpaque(source.isOpaque());
|
||||
result.setAlphaType(source.alphaType());
|
||||
|
||||
return result;
|
||||
}
|
||||
|
|
|
@ -499,6 +499,19 @@ GLContext::InitWithPrefix(const char *prefix, bool trygl)
|
|||
{ (PRFuncPtr*) &mSymbols.fUnmapBuffer, { "UnmapBuffer", nullptr } },
|
||||
{ (PRFuncPtr*) &mSymbols.fPointParameterf, { "PointParameterf", nullptr } },
|
||||
{ (PRFuncPtr*) &mSymbols.fDrawBuffer, { "DrawBuffer", nullptr } },
|
||||
// These functions are only used by Skia/GL in desktop mode.
|
||||
// Other parts of Gecko should avoid using these
|
||||
{ (PRFuncPtr*) &mSymbols.fDrawBuffers, { "DrawBuffers", nullptr } },
|
||||
{ (PRFuncPtr*) &mSymbols.fClientActiveTexture, { "ClientActiveTexture", nullptr } },
|
||||
{ (PRFuncPtr*) &mSymbols.fDisableClientState, { "DisableClientState", nullptr } },
|
||||
{ (PRFuncPtr*) &mSymbols.fEnableClientState, { "EnableClientState", nullptr } },
|
||||
{ (PRFuncPtr*) &mSymbols.fLoadIdentity, { "LoadIdentity", nullptr } },
|
||||
{ (PRFuncPtr*) &mSymbols.fLoadMatrixf, { "LoadMatrixf", nullptr } },
|
||||
{ (PRFuncPtr*) &mSymbols.fMatrixMode, { "MatrixMode", nullptr } },
|
||||
{ (PRFuncPtr*) &mSymbols.fTexGeni, { "TexGeni", nullptr } },
|
||||
{ (PRFuncPtr*) &mSymbols.fTexGenf, { "TexGenf", nullptr } },
|
||||
{ (PRFuncPtr*) &mSymbols.fTexGenfv, { "TexGenfv", nullptr } },
|
||||
{ (PRFuncPtr*) &mSymbols.fVertexPointer, { "VertexPointer", nullptr } },
|
||||
{ nullptr, { nullptr } },
|
||||
};
|
||||
|
||||
|
|
|
@ -862,6 +862,12 @@ public:
|
|||
AFTER_GL_CALL;
|
||||
}
|
||||
|
||||
void fClientActiveTexture(GLenum texture) {
|
||||
BEFORE_GL_CALL;
|
||||
mSymbols.fClientActiveTexture(texture);
|
||||
AFTER_GL_CALL;
|
||||
}
|
||||
|
||||
void fColorMask(realGLboolean red, realGLboolean green, realGLboolean blue, realGLboolean alpha) {
|
||||
BEFORE_GL_CALL;
|
||||
mSymbols.fColorMask(red, green, blue, alpha);
|
||||
|
@ -954,6 +960,12 @@ public:
|
|||
AFTER_GL_CALL;
|
||||
}
|
||||
|
||||
void fDisableClientState(GLenum capability) {
|
||||
BEFORE_GL_CALL;
|
||||
mSymbols.fDisableClientState(capability);
|
||||
AFTER_GL_CALL;
|
||||
}
|
||||
|
||||
void fDisableVertexAttribArray(GLuint index) {
|
||||
BEFORE_GL_CALL;
|
||||
mSymbols.fDisableVertexAttribArray(index);
|
||||
|
@ -998,6 +1010,12 @@ public:
|
|||
AFTER_GL_CALL;
|
||||
}
|
||||
|
||||
void fEnableClientState(GLenum capability) {
|
||||
BEFORE_GL_CALL;
|
||||
mSymbols.fEnableClientState(capability);
|
||||
AFTER_GL_CALL;
|
||||
}
|
||||
|
||||
void fEnableVertexAttribArray(GLuint index) {
|
||||
BEFORE_GL_CALL;
|
||||
mSymbols.fEnableVertexAttribArray(index);
|
||||
|
@ -1343,6 +1361,24 @@ public:
|
|||
AFTER_GL_CALL;
|
||||
}
|
||||
|
||||
void fLoadIdentity() {
|
||||
BEFORE_GL_CALL;
|
||||
mSymbols.fLoadIdentity();
|
||||
AFTER_GL_CALL;
|
||||
}
|
||||
|
||||
void fLoadMatrixf(const GLfloat *matrix) {
|
||||
BEFORE_GL_CALL;
|
||||
mSymbols.fLoadMatrixf(matrix);
|
||||
AFTER_GL_CALL;
|
||||
}
|
||||
|
||||
void fMatrixMode(GLenum mode) {
|
||||
BEFORE_GL_CALL;
|
||||
mSymbols.fMatrixMode(mode);
|
||||
AFTER_GL_CALL;
|
||||
}
|
||||
|
||||
void fPixelStorei(GLenum pname, GLint param) {
|
||||
BEFORE_GL_CALL;
|
||||
mSymbols.fPixelStorei(pname, param);
|
||||
|
@ -1470,6 +1506,24 @@ public:
|
|||
AFTER_GL_CALL;
|
||||
}
|
||||
|
||||
void fTexGeni(GLenum coord, GLenum pname, GLint param) {
|
||||
BEFORE_GL_CALL;
|
||||
mSymbols.fTexGeni(coord, pname, param);
|
||||
AFTER_GL_CALL;
|
||||
}
|
||||
|
||||
void fTexGenf(GLenum coord, GLenum pname, GLfloat param) {
|
||||
BEFORE_GL_CALL;
|
||||
mSymbols.fTexGenf(coord, pname, param);
|
||||
AFTER_GL_CALL;
|
||||
}
|
||||
|
||||
void fTexGenfv(GLenum coord, GLenum pname, const GLfloat *params) {
|
||||
BEFORE_GL_CALL;
|
||||
mSymbols.fTexGenfv(coord, pname, params);
|
||||
AFTER_GL_CALL;
|
||||
}
|
||||
|
||||
private:
|
||||
void raw_fTexImage2D(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *pixels) {
|
||||
BEFORE_GL_CALL;
|
||||
|
@ -1676,6 +1730,12 @@ public:
|
|||
AFTER_GL_CALL;
|
||||
}
|
||||
|
||||
void fVertexPointer(GLint size, GLenum type, GLsizei stride, const GLvoid* pointer) {
|
||||
BEFORE_GL_CALL;
|
||||
mSymbols.fVertexPointer(size, type, stride, pointer);
|
||||
AFTER_GL_CALL;
|
||||
}
|
||||
|
||||
void fCompileShader(GLuint shader) {
|
||||
BEFORE_GL_CALL;
|
||||
mSymbols.fCompileShader(shader);
|
||||
|
|
|
@ -125,6 +125,12 @@ GrGLvoid glCompileShader_mozilla(GrGLuint shader)
|
|||
return sGLContext.get()->fCompileShader(shader);
|
||||
}
|
||||
|
||||
GrGLvoid glCopyTexSubImage2D_mozilla(GrGLenum target, GrGLint level, GrGLint xoffset, GrGLint yoffset,
|
||||
GrGLint x, GrGLint y, GrGLsizei width, GrGLsizei height)
|
||||
{
|
||||
return sGLContext.get()->fCopyTexSubImage2D(target, level, xoffset, yoffset, x, y, width, height);
|
||||
}
|
||||
|
||||
GrGLuint glCreateProgram_mozilla(void)
|
||||
{
|
||||
return sGLContext.get()->fCreateProgram();
|
||||
|
@ -250,6 +256,11 @@ GrGLvoid glGenTextures_mozilla(GrGLsizei n, GrGLuint* textures)
|
|||
return sGLContext.get()->fGenTextures(n, textures);
|
||||
}
|
||||
|
||||
GrGLvoid glGenerateMipmap_mozilla(GrGLenum target)
|
||||
{
|
||||
return sGLContext.get()->fGenerateMipmap(target);
|
||||
}
|
||||
|
||||
GrGLvoid glGetBufferParameteriv_mozilla(GrGLenum target, GrGLenum pname, GrGLint* params)
|
||||
{
|
||||
return sGLContext.get()->fGetBufferParameteriv(target, pname, params);
|
||||
|
@ -710,6 +721,57 @@ GrGLvoid glGenVertexArrays_mozilla(GrGLsizei n, GrGLuint *arrays) {
|
|||
return sGLContext.get()->fGenVertexArrays(n, arrays);
|
||||
}
|
||||
|
||||
// Additional functions required for desktop GL < version 3.2
|
||||
|
||||
GrGLvoid glClientActiveTexture_mozilla(GrGLenum texture)
|
||||
{
|
||||
return sGLContext.get()->fClientActiveTexture(texture);
|
||||
}
|
||||
|
||||
GrGLvoid glDisableClientState_mozilla(GrGLenum capability)
|
||||
{
|
||||
return sGLContext.get()->fDisableClientState(capability);
|
||||
}
|
||||
|
||||
GrGLvoid glEnableClientState_mozilla(GrGLenum capability)
|
||||
{
|
||||
return sGLContext.get()->fEnableClientState(capability);
|
||||
}
|
||||
|
||||
GrGLvoid glLoadMatrixf_mozilla(const GLfloat* matrix)
|
||||
{
|
||||
return sGLContext.get()->fLoadMatrixf(matrix);
|
||||
}
|
||||
|
||||
GrGLvoid glLoadIdentity_mozilla()
|
||||
{
|
||||
return sGLContext.get()->fLoadIdentity();
|
||||
}
|
||||
|
||||
GrGLvoid glMatrixMode_mozilla(GrGLenum mode)
|
||||
{
|
||||
return sGLContext.get()->fMatrixMode(mode);
|
||||
}
|
||||
|
||||
GrGLvoid glTexGeni_mozilla(GrGLenum coord, GrGLenum pname, GrGLint param)
|
||||
{
|
||||
return sGLContext.get()->fTexGeni(coord, pname, param);
|
||||
}
|
||||
|
||||
GrGLvoid glTexGenf_mozilla(GrGLenum coord, GrGLenum pname, GrGLfloat param)
|
||||
{
|
||||
return sGLContext.get()->fTexGenf(coord, pname, param);
|
||||
}
|
||||
|
||||
GrGLvoid glTexGenfv_mozilla(GrGLenum coord, GrGLenum pname, const GrGLfloat* param)
|
||||
{
|
||||
return sGLContext.get()->fTexGenfv(coord, pname, param);
|
||||
}
|
||||
|
||||
GrGLvoid glVertexPointer_mozilla(GrGLint size, GrGLenum type, GrGLsizei stride, const GrGLvoid* pointer)
|
||||
{
|
||||
return sGLContext.get()->fVertexPointer(size, type, stride, pointer);
|
||||
}
|
||||
|
||||
} // extern "C"
|
||||
|
||||
|
@ -737,6 +799,7 @@ GrGLInterface* CreateGrGLInterfaceFromGLContext(GLContext* context)
|
|||
i->fClearStencil = glClearStencil_mozilla;
|
||||
i->fColorMask = glColorMask_mozilla;
|
||||
i->fCompileShader = glCompileShader_mozilla;
|
||||
i->fCopyTexSubImage2D = glCopyTexSubImage2D_mozilla;
|
||||
i->fCreateProgram = glCreateProgram_mozilla;
|
||||
i->fCreateShader = glCreateShader_mozilla;
|
||||
i->fCullFace = glCullFace_mozilla;
|
||||
|
@ -763,6 +826,7 @@ GrGLInterface* CreateGrGLInterfaceFromGLContext(GLContext* context)
|
|||
i->fGenRenderbuffers = glGenRenderbuffers_mozilla;
|
||||
i->fGetFramebufferAttachmentParameteriv = glGetFramebufferAttachmentParameteriv_mozilla;
|
||||
i->fGenTextures = glGenTextures_mozilla;
|
||||
i->fGenerateMipmap = glGenerateMipmap_mozilla;
|
||||
i->fGetBufferParameteriv = glGetBufferParameteriv_mozilla;
|
||||
i->fGetError = glGetError_mozilla;
|
||||
i->fGetIntegerv = glGetIntegerv_mozilla;
|
||||
|
@ -849,6 +913,18 @@ GrGLInterface* CreateGrGLInterfaceFromGLContext(GLContext* context)
|
|||
// Desktop OpenGL > 2.0
|
||||
i->fDrawBuffers = glDrawBuffers_mozilla;
|
||||
|
||||
// Desktop OpenGL < 3.2 (which we pretend to be)
|
||||
i->fClientActiveTexture = glClientActiveTexture_mozilla;
|
||||
i->fDisableClientState = glDisableClientState_mozilla;
|
||||
i->fEnableClientState = glEnableClientState_mozilla;
|
||||
i->fLoadIdentity = glLoadIdentity_mozilla;
|
||||
i->fLoadMatrixf = glLoadMatrixf_mozilla;
|
||||
i->fMatrixMode = glMatrixMode_mozilla;
|
||||
i->fTexGenf = glTexGenf_mozilla;
|
||||
i->fTexGenfv = glTexGenfv_mozilla;
|
||||
i->fTexGeni = glTexGeni_mozilla;
|
||||
i->fVertexPointer = glVertexPointer_mozilla;
|
||||
|
||||
// We support both desktop GL and GLES2
|
||||
if (context->IsGLES2()) {
|
||||
i->fBindingsExported = kES2_GrGLBinding;
|
||||
|
|
|
@ -313,6 +313,31 @@ struct GLContextSymbols
|
|||
typedef void (GLAPIENTRY * PFNGLRENDERBUFFERSTORAGE) (GLenum target, GLenum internalFormat, GLsizei width, GLsizei height);
|
||||
PFNGLRENDERBUFFERSTORAGE fRenderbufferStorage;
|
||||
|
||||
// These functions are only used by Skia/GL in desktop mode.
|
||||
// Other parts of Gecko should avoid using these
|
||||
typedef void (GLAPIENTRY * PFNGLCLIENTACTIVETEXTURE) (GLenum texture);
|
||||
PFNGLCLIENTACTIVETEXTURE fClientActiveTexture;
|
||||
typedef void (GLAPIENTRY * PFNDISABLECLIENTSTATE) (GLenum capability);
|
||||
PFNDISABLECLIENTSTATE fDisableClientState;
|
||||
typedef void (GLAPIENTRY * PFNENABLECLIENTSTATE) (GLenum capability);
|
||||
PFNENABLECLIENTSTATE fEnableClientState;
|
||||
typedef void (GLAPIENTRY * PFNLOADIDENTITY) (void);
|
||||
PFNLOADIDENTITY fLoadIdentity;
|
||||
typedef void (GLAPIENTRY * PFNLOADMATRIXD) (const GLdouble* matrix);
|
||||
PFNLOADMATRIXD fLoadMatrixd;
|
||||
typedef void (GLAPIENTRY * PFNLOADMATRIXF) (const GLfloat* matrix);
|
||||
PFNLOADMATRIXF fLoadMatrixf;
|
||||
typedef void (GLAPIENTRY * PFNMATRIXMODE) (GLenum mode);
|
||||
PFNMATRIXMODE fMatrixMode;
|
||||
typedef void (GLAPIENTRY * PFNTEXGENI) (GLenum coord, GLenum pname, GLint param);
|
||||
PFNTEXGENI fTexGeni;
|
||||
typedef void (GLAPIENTRY * PFNTEXGENF) (GLenum coord, GLenum pname, GLfloat param);
|
||||
PFNTEXGENF fTexGenf;
|
||||
typedef void (GLAPIENTRY * PFNTEXGENFV) (GLenum coord, GLenum pname, const GLfloat* param);
|
||||
PFNTEXGENFV fTexGenfv;
|
||||
typedef void (GLAPIENTRY * PFNVERTEXPOINTER) (GLint size, GLenum type, GLsizei stride, const GLvoid* pointer);
|
||||
PFNVERTEXPOINTER fVertexPointer;
|
||||
|
||||
typedef void (GLAPIENTRY * PFNGLBLITFRAMEBUFFER) (GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter);
|
||||
PFNGLBLITFRAMEBUFFER fBlitFramebuffer;
|
||||
typedef void (GLAPIENTRY * PFNGLRENDERBUFFERSTORAGEMULTISAMPLE) (GLenum target, GLsizei samples, GLenum internalFormat, GLsizei width, GLsizei height);
|
||||
|
|
|
@ -813,9 +813,13 @@ ContainerLayer::RepositionChild(Layer* aChild, Layer* aAfter)
|
|||
}
|
||||
if (prev) {
|
||||
prev->SetNextSibling(next);
|
||||
} else {
|
||||
mFirstChild = next;
|
||||
}
|
||||
if (next) {
|
||||
next->SetPrevSibling(prev);
|
||||
} else {
|
||||
mLastChild = prev;
|
||||
}
|
||||
if (!aAfter) {
|
||||
aChild->SetPrevSibling(nullptr);
|
||||
|
|
|
@ -19,10 +19,13 @@ include $(topsrcdir)/config/rules.mk
|
|||
|
||||
ifneq (,$(INTEL_ARCHITECTURE))
|
||||
ifdef GNU_CC
|
||||
SkBitmapFilter_opts_SSE2.$(OBJ_SUFFIX): CXXFLAGS+=-msse2
|
||||
SkBitmapProcState_opts_SSE2.$(OBJ_SUFFIX): CXXFLAGS+=-msse2
|
||||
SkBitmapProcState_opts_SSSE3.$(OBJ_SUFFIX): CXXFLAGS+=-mssse3
|
||||
SkBlitRow_opts_SSE2.$(OBJ_SUFFIX): CXXFLAGS+=-msse2
|
||||
SkBlitRect_opts_SSE2.$(OBJ_SUFFIX): CXXFLAGS+=-msse2
|
||||
SkBlitRow_opts_SSE2.$(OBJ_SUFFIX): CXXFLAGS+=-msse2
|
||||
SkBlurImage_opts_SSE2.$(OBJ_SUFFIX): CXXFLAGS+=-msse2
|
||||
SkMorphology_opts_SSE2.$(OBJ_SUFFIX): CXXFLAGS+=-msse2
|
||||
SkUtils_opts_SSE2.$(OBJ_SUFFIX): CXXFLAGS+=-msse2
|
||||
endif
|
||||
endif
|
||||
|
|
|
@ -2,4 +2,14 @@ The source from this directory was copied from the skia subversion trunk
|
|||
using the update.sh script. The changes made were those applied by update.sh,
|
||||
the addition/update of Makefile.in files for the Mozilla build system.
|
||||
|
||||
The subversion revision used was r8495.
|
||||
The subversion revision used was r13424.
|
||||
|
||||
To update to a new version of Skia:
|
||||
|
||||
- Copy the entire trunk/ directory from a Skia clone to mozilla-central/gfx/skia
|
||||
- cd gfx/skia && ./gyp_mozbuild
|
||||
|
||||
Once that's done, use git status to view the files that have changed. Keep an eye on GrUserConfig.h
|
||||
and SkUserConfig.h as those probably don't want to be overwritten by upstream versions.
|
||||
|
||||
This process will be made more automatic in the future.
|
||||
|
|
|
@ -0,0 +1,92 @@
|
|||
# Copyright (c) 2012 Google Inc. All rights reserved.
|
||||
# Use of this source code is governed by a BSD-style license that can be
|
||||
# found in the LICENSE file.
|
||||
|
||||
import collections
|
||||
import os
|
||||
import gyp
|
||||
import gyp.common
|
||||
import gyp.msvs_emulation
|
||||
import json
|
||||
import sys
|
||||
|
||||
generator_supports_multiple_toolsets = True
|
||||
|
||||
generator_wants_static_library_dependencies_adjusted = False
|
||||
|
||||
generator_default_variables = {
|
||||
}
|
||||
for dirname in ['INTERMEDIATE_DIR', 'SHARED_INTERMEDIATE_DIR', 'PRODUCT_DIR',
|
||||
'LIB_DIR', 'SHARED_LIB_DIR']:
|
||||
# Some gyp steps fail if these are empty(!).
|
||||
generator_default_variables[dirname] = 'dir'
|
||||
for unused in ['RULE_INPUT_PATH', 'RULE_INPUT_ROOT', 'RULE_INPUT_NAME',
|
||||
'RULE_INPUT_DIRNAME', 'RULE_INPUT_EXT',
|
||||
'EXECUTABLE_PREFIX', 'EXECUTABLE_SUFFIX',
|
||||
'STATIC_LIB_PREFIX', 'STATIC_LIB_SUFFIX',
|
||||
'SHARED_LIB_PREFIX', 'SHARED_LIB_SUFFIX',
|
||||
'CONFIGURATION_NAME']:
|
||||
generator_default_variables[unused] = ''
|
||||
|
||||
|
||||
def CalculateVariables(default_variables, params):
|
||||
generator_flags = params.get('generator_flags', {})
|
||||
for key, val in generator_flags.items():
|
||||
default_variables.setdefault(key, val)
|
||||
default_variables.setdefault('OS', gyp.common.GetFlavor(params))
|
||||
|
||||
flavor = gyp.common.GetFlavor(params)
|
||||
if flavor =='win':
|
||||
# Copy additional generator configuration data from VS, which is shared
|
||||
# by the Windows Ninja generator.
|
||||
import gyp.generator.msvs as msvs_generator
|
||||
generator_additional_non_configuration_keys = getattr(msvs_generator,
|
||||
'generator_additional_non_configuration_keys', [])
|
||||
generator_additional_path_sections = getattr(msvs_generator,
|
||||
'generator_additional_path_sections', [])
|
||||
|
||||
gyp.msvs_emulation.CalculateCommonVariables(default_variables, params)
|
||||
|
||||
|
||||
def CalculateGeneratorInputInfo(params):
|
||||
"""Calculate the generator specific info that gets fed to input (called by
|
||||
gyp)."""
|
||||
generator_flags = params.get('generator_flags', {})
|
||||
if generator_flags.get('adjust_static_libraries', False):
|
||||
global generator_wants_static_library_dependencies_adjusted
|
||||
generator_wants_static_library_dependencies_adjusted = True
|
||||
|
||||
def GetOS(params):
|
||||
for d in params['defines']:
|
||||
pass
|
||||
|
||||
def GenerateOutput(target_list, target_dicts, data, params):
|
||||
# Map of target -> list of targets it depends on.
|
||||
edges = {}
|
||||
|
||||
# Queue of targets to visit.
|
||||
targets_to_visit = target_list[:]
|
||||
|
||||
sources = [];
|
||||
|
||||
while len(targets_to_visit) > 0:
|
||||
target = targets_to_visit.pop()
|
||||
if target in edges:
|
||||
continue
|
||||
edges[target] = []
|
||||
|
||||
target_sources = target_dicts[target].get('sources')
|
||||
if target_sources:
|
||||
for source in target_sources:
|
||||
if source.endswith('.cpp'):
|
||||
sources.append(source)
|
||||
|
||||
for dep in target_dicts[target].get('dependencies', []):
|
||||
edges[target].append(dep)
|
||||
targets_to_visit.append(dep)
|
||||
|
||||
skia_os = data['gyp/core.gyp']['variables']['skia_os%']
|
||||
|
||||
f = open('sources.json', 'w')
|
||||
json.dump(sources, f)
|
||||
f.close()
|
|
@ -0,0 +1,295 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
import os
|
||||
|
||||
import locale
|
||||
locale.setlocale(locale.LC_ALL, 'en_US.UTF-8')
|
||||
|
||||
footer = """
|
||||
|
||||
# left out of UNIFIED_SOURCES for now; that's not C++ anyway, nothing else to unify it with
|
||||
if not CONFIG['INTEL_ARCHITECTURE'] and CONFIG['CPU_ARCH'] == 'arm' and CONFIG['GNU_CC']:
|
||||
SOURCES += [
|
||||
'trunk/src/opts/memset.arm.S',
|
||||
]
|
||||
|
||||
MSVC_ENABLE_PGO = True
|
||||
|
||||
FINAL_LIBRARY = 'gkmedias'
|
||||
LOCAL_INCLUDES += [
|
||||
'trunk/include/config',
|
||||
'trunk/include/core',
|
||||
'trunk/include/effects',
|
||||
'trunk/include/gpu',
|
||||
'trunk/include/images',
|
||||
'trunk/include/lazy',
|
||||
'trunk/include/pathops',
|
||||
'trunk/include/pipe',
|
||||
'trunk/include/ports',
|
||||
'trunk/include/utils',
|
||||
'trunk/include/utils/mac',
|
||||
'trunk/include/utils/win',
|
||||
'trunk/include/views',
|
||||
'trunk/src/core',
|
||||
'trunk/src/gpu',
|
||||
'trunk/src/gpu/effects',
|
||||
'trunk/src/gpu/gl',
|
||||
'trunk/src/image',
|
||||
'trunk/src/lazy',
|
||||
'trunk/src/opts',
|
||||
'trunk/src/sfnt',
|
||||
'trunk/src/utils',
|
||||
'trunk/src/utils/android',
|
||||
'trunk/src/utils/mac',
|
||||
'trunk/src/utils/win',
|
||||
]
|
||||
|
||||
DEFINES['SK_A32_SHIFT'] = 24
|
||||
DEFINES['SK_R32_SHIFT'] = 16
|
||||
DEFINES['SK_G32_SHIFT'] = 8
|
||||
DEFINES['SK_B32_SHIFT'] = 0
|
||||
|
||||
if CONFIG['MOZ_WIDGET_TOOLKIT'] in ('android', 'gtk2', 'gtk3', 'gonk', 'cocoa'):
|
||||
DEFINES['SK_USE_POSIX_THREADS'] = 1
|
||||
|
||||
if CONFIG['INTEL_ARCHITECTURE'] and CONFIG['HAVE_TOOLCHAIN_SUPPORT_MSSSE3']:
|
||||
DEFINES['SK_BUILD_SSSE3'] = 1
|
||||
|
||||
if (CONFIG['MOZ_WIDGET_TOOLKIT'] == 'android') or \
|
||||
(CONFIG['MOZ_WIDGET_TOOLKIT'] == 'cocoa') or \
|
||||
CONFIG['MOZ_WIDGET_GTK']:
|
||||
DEFINES['SK_FONTHOST_DOES_NOT_USE_FONTMGR'] = 1
|
||||
|
||||
if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'windows':
|
||||
DEFINES['SKIA_DLL'] = 1
|
||||
|
||||
DEFINES['SKIA_IMPLEMENTATION'] = 1
|
||||
DEFINES['GR_IMPLEMENTATION'] = 1
|
||||
"""
|
||||
|
||||
import json
|
||||
|
||||
platforms = ['linux', 'mac', 'android', 'win']
|
||||
|
||||
custom_includes = {
|
||||
'trunk/src/ports/SkAtomics_android.h': True,
|
||||
'trunk/src/ports/SkAtomics_sync.h': True,
|
||||
'trunk/src/ports/SkAtomics_win.h': True,
|
||||
'trunk/src/ports/SkMutex_pthread.h': True,
|
||||
'trunk/src/ports/SkMutex_win.h': True
|
||||
}
|
||||
|
||||
def generate_includes():
|
||||
includes = {}
|
||||
for root, dirs, files in os.walk('trunk/include'):
|
||||
for name in files:
|
||||
if name.endswith('.h'):
|
||||
includes[os.path.join(root, name)] = True
|
||||
|
||||
return dict(includes.items() + custom_includes.items())
|
||||
|
||||
def generate_opt_sources():
|
||||
opt_sources = {'opts': {''}}
|
||||
for root, dirs, files in os.walk('trunk/src/opts'):
|
||||
for name in files:
|
||||
if name.endswith('.cpp'):
|
||||
opt_sources['opts'].add(os.path.join(root, name))
|
||||
|
||||
return opt_sources
|
||||
|
||||
def generate_platform_sources():
|
||||
sources = {}
|
||||
|
||||
for plat in platforms:
|
||||
if os.system("cd trunk && GYP_GENERATORS=dump_mozbuild ./gyp_skia -D OS=%s gyp/skia_lib.gyp" % plat) != 0:
|
||||
print 'Failed to generate sources for ' + plat
|
||||
continue
|
||||
|
||||
|
||||
f = open('trunk/sources.json');
|
||||
sources[plat] = set(json.load(f));
|
||||
f.close()
|
||||
|
||||
return dict(sources.items() + generate_opt_sources().items())
|
||||
|
||||
|
||||
def generate_separated_sources(platform_sources):
|
||||
blacklist = [
|
||||
'ChromeUtils',
|
||||
'SkImageDecoder_',
|
||||
'_gif',
|
||||
'SkFontConfigParser_android',
|
||||
'SkJpeg',
|
||||
'SkXML',
|
||||
'SkCity',
|
||||
'GrGLCreateNativeInterface',
|
||||
'fontconfig',
|
||||
'_neon',
|
||||
'SkImage_Codec',
|
||||
'SkBitmapChecksummer',
|
||||
'SkNativeGLContext',
|
||||
'SkFontConfig',
|
||||
'SkFontHost_win_dw',
|
||||
'SkForceLinking',
|
||||
'SkMovie',
|
||||
'SkImageDecoder',
|
||||
'SkImageEncoder',
|
||||
'SkBitmapHasher',
|
||||
'SkWGL',
|
||||
'SkImages',
|
||||
'SkDiscardableMemory_ashmem'
|
||||
]
|
||||
|
||||
def isblacklisted(value):
|
||||
for item in blacklist:
|
||||
if value.find(item) >= 0:
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
separated = {
|
||||
'common': {
|
||||
#'trunk/src/effects/gradients/SkGradientTileProc.cpp',
|
||||
'trunk/src/gpu/gl/GrGLCreateNativeInterface_none.cpp',
|
||||
'trunk/src/ports/SkDiscardableMemory_none.cpp',
|
||||
'trunk/src/ports/SkImageDecoder_empty.cpp',
|
||||
# 'trunk/src/images/SkImages.cpp',
|
||||
# 'trunk/src/images/SkImageRef.cpp',
|
||||
# 'trunk/src/images/SkImageRef_GlobalPool.cpp',
|
||||
# 'trunk/src/images/SkImageRefPool.cpp',
|
||||
# 'trunk/src/images/SkImageDecoder.cpp',
|
||||
# 'trunk/src/images/SkImageDecoder_Factory.cpp',
|
||||
},
|
||||
'android': {
|
||||
# 'trunk/src/ports/SkDebug_android.cpp',
|
||||
'trunk/src/ports/SkFontHost_cairo.cpp',
|
||||
# 'trunk/src/ports/SkFontHost_FreeType.cpp',
|
||||
# 'trunk/src/ports/SkFontHost_FreeType_common.cpp',
|
||||
# 'trunk/src/ports/SkThread_pthread.cpp',
|
||||
# 'trunk/src/ports/SkPurgeableMemoryBlock_android.cpp',
|
||||
# 'trunk/src/ports/SkTime_Unix.cpp',
|
||||
# 'trunk/src/utils/SkThreadUtils_pthread.cpp',
|
||||
# 'trunk/src/utils/SkThreadUtils_pthread_other.cpp',
|
||||
# 'trunk/src/images/SkImageRef_ashmem.cpp',
|
||||
# 'trunk/src/utils/android/ashmem.cpp',
|
||||
},
|
||||
'linux': {
|
||||
'trunk/src/ports/SkFontHost_cairo.cpp',
|
||||
},
|
||||
'intel': {
|
||||
'trunk/src/opts/SkXfermode_opts_none.cpp',
|
||||
},
|
||||
'arm': {
|
||||
'trunk/src/opts/SkUtils_opts_arm.cpp',
|
||||
},
|
||||
'none': {
|
||||
'trunk/src/opts/SkUtils_opts_none.cpp',
|
||||
}
|
||||
}
|
||||
|
||||
for plat in platform_sources.keys():
|
||||
if not separated.has_key(plat):
|
||||
separated[plat] = set()
|
||||
|
||||
for value in platform_sources[plat]:
|
||||
if isblacklisted(value):
|
||||
continue
|
||||
|
||||
if value.find('_SSE') > 0 or value.find('_SSSE') > 0: #lol
|
||||
separated['intel'].add(value)
|
||||
continue
|
||||
|
||||
if value.find('_arm') > 0 or value.find('_neon') > 0:
|
||||
separated['arm'].add(value)
|
||||
continue
|
||||
|
||||
if value.find('_none') > 0:
|
||||
separated['none'].add(value)
|
||||
continue
|
||||
|
||||
found = True
|
||||
for other in platforms:
|
||||
if other == plat or not platform_sources.has_key(other):
|
||||
continue
|
||||
|
||||
if not value in platform_sources[other]:
|
||||
found = False
|
||||
break;
|
||||
|
||||
if found:
|
||||
separated['common'].add(value)
|
||||
else:
|
||||
separated[plat].add(value)
|
||||
|
||||
return separated
|
||||
|
||||
def uniq(seq):
|
||||
seen = set()
|
||||
seen_add = seen.add
|
||||
return [ x for x in seq if x not in seen and not seen_add(x)]
|
||||
|
||||
def write_list(f, name, values, indent):
|
||||
def write_indent(indent):
|
||||
for _ in range(indent):
|
||||
f.write(' ')
|
||||
|
||||
val_list = uniq(sorted(map(lambda val: val.replace('../', 'trunk/'), values), key=lambda x: x.lower()))
|
||||
|
||||
if len(val_list) == 0:
|
||||
return
|
||||
|
||||
write_indent(indent)
|
||||
f.write(name + ' += [\n')
|
||||
for val in val_list:
|
||||
write_indent(indent + 4)
|
||||
f.write('\'' + val + '\',\n')
|
||||
|
||||
write_indent(4)
|
||||
f.write(']\n')
|
||||
|
||||
def write_mozbuild(includes, sources):
|
||||
filename = 'moz.build'
|
||||
f = open(filename, 'w')
|
||||
|
||||
|
||||
write_list(f, 'EXPORTS.skia', includes, 0)
|
||||
|
||||
write_list(f, 'SOURCES', sources['common'], 0)
|
||||
|
||||
f.write("if CONFIG['MOZ_WIDGET_TOOLKIT'] in ('android', 'gonk'):\n")
|
||||
write_list(f, 'SOURCES', sources['android'], 4)
|
||||
|
||||
f.write("if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'cocoa':\n")
|
||||
write_list(f, 'SOURCES', sources['mac'], 4)
|
||||
|
||||
f.write("if CONFIG['MOZ_WIDGET_GTK']:\n")
|
||||
write_list(f, 'SOURCES', sources['linux'], 4)
|
||||
|
||||
f.write("if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'windows':\n")
|
||||
write_list(f, 'SOURCES', sources['win'], 4)
|
||||
|
||||
f.write("\n\n")
|
||||
f.write("if CONFIG['INTEL_ARCHITECTURE']:\n")
|
||||
write_list(f, 'SOURCES', sources['intel'], 4)
|
||||
|
||||
f.write("elif CONFIG['CPU_ARCH'] == 'arm' and CONFIG['GNU_CC']:\n")
|
||||
write_list(f, 'SOURCES', sources['arm'], 4)
|
||||
|
||||
f.write("else:\n")
|
||||
write_list(f, 'SOURCES', sources['none'], 4)
|
||||
|
||||
f.write(footer)
|
||||
|
||||
f.close()
|
||||
|
||||
print 'Wrote ' + filename
|
||||
|
||||
def main():
|
||||
includes = generate_includes()
|
||||
platform_sources = generate_platform_sources()
|
||||
separated_sources = generate_separated_sources(platform_sources)
|
||||
write_mozbuild(includes, separated_sources)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
|
@ -0,0 +1,13 @@
|
|||
#!/bin/bash
|
||||
|
||||
# Install our generator
|
||||
cp dump_mozbuild.py trunk/third_party/externals/gyp/pylib/gyp/generator
|
||||
|
||||
# pushd trunk
|
||||
# for OS in win linux mac; do
|
||||
# GYP_GENERATORS=dump_mozbuild ./gyp_skia -D OS=$OS -D arm_neon=0 gyp/effects.gyp
|
||||
# done
|
||||
# popd
|
||||
|
||||
./generate_mozbuild.py
|
||||
|
|
@ -1,23 +0,0 @@
|
|||
|
||||
/*
|
||||
* Copyright 2011 Google Inc.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
#ifndef sk_stdint_DEFINED
|
||||
#define sk_stdint_DEFINED
|
||||
|
||||
typedef signed char int8_t;
|
||||
typedef unsigned char uint8_t;
|
||||
typedef short int16_t;
|
||||
typedef unsigned short uint16_t;
|
||||
typedef int int32_t;
|
||||
typedef unsigned uint32_t;
|
||||
typedef long long int64_t;
|
||||
typedef unsigned long long uint64_t;
|
||||
|
||||
typedef int64_t intmax_t;
|
||||
typedef uint64_t uintmax_t;
|
||||
|
||||
#endif
|
|
@ -1,112 +0,0 @@
|
|||
|
||||
/*
|
||||
* 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 SkColorTable_DEFINED
|
||||
#define SkColorTable_DEFINED
|
||||
|
||||
#include "SkColor.h"
|
||||
#include "SkFlattenable.h"
|
||||
|
||||
/** \class SkColorTable
|
||||
|
||||
SkColorTable holds an array SkPMColors (premultiplied 32-bit colors) used by
|
||||
8-bit bitmaps, where the bitmap bytes are interpreted as indices into the colortable.
|
||||
*/
|
||||
class SkColorTable : public SkFlattenable {
|
||||
public:
|
||||
SK_DECLARE_INST_COUNT(SkColorTable)
|
||||
|
||||
/** Makes a deep copy of colors.
|
||||
*/
|
||||
SkColorTable(const SkColorTable& src);
|
||||
/** Preallocates the colortable to have 'count' colors, which
|
||||
* are initially set to 0.
|
||||
*/
|
||||
explicit SkColorTable(int count);
|
||||
SkColorTable(const SkPMColor colors[], int count);
|
||||
virtual ~SkColorTable();
|
||||
|
||||
enum Flags {
|
||||
kColorsAreOpaque_Flag = 0x01 //!< if set, all of the colors in the table are opaque (alpha==0xFF)
|
||||
};
|
||||
/** Returns the flag bits for the color table. These can be changed with setFlags().
|
||||
*/
|
||||
unsigned getFlags() const { return fFlags; }
|
||||
/** Set the flags for the color table. See the Flags enum for possible values.
|
||||
*/
|
||||
void setFlags(unsigned flags);
|
||||
|
||||
bool isOpaque() const { return (fFlags & kColorsAreOpaque_Flag) != 0; }
|
||||
void setIsOpaque(bool isOpaque);
|
||||
|
||||
/** Returns the number of colors in the table.
|
||||
*/
|
||||
int count() const { return fCount; }
|
||||
|
||||
/** Returns the specified color from the table. In the debug build, this asserts that
|
||||
the index is in range (0 <= index < count).
|
||||
*/
|
||||
SkPMColor operator[](int index) const {
|
||||
SkASSERT(fColors != NULL && (unsigned)index < fCount);
|
||||
return fColors[index];
|
||||
}
|
||||
|
||||
/** Specify the number of colors in the color table. This does not initialize the colors
|
||||
to any value, just allocates memory for them. To initialize the values, either call
|
||||
setColors(array, count), or follow setCount(count) with a call to
|
||||
lockColors()/{set the values}/unlockColors(true).
|
||||
*/
|
||||
// void setColors(int count) { this->setColors(NULL, count); }
|
||||
// void setColors(const SkPMColor[], int count);
|
||||
|
||||
/** Return the array of colors for reading and/or writing. This must be
|
||||
balanced by a call to unlockColors(changed?), telling the colortable if
|
||||
the colors were changed during the lock.
|
||||
*/
|
||||
SkPMColor* lockColors() {
|
||||
SkDEBUGCODE(sk_atomic_inc(&fColorLockCount);)
|
||||
return fColors;
|
||||
}
|
||||
/** Balancing call to lockColors(). If the colors have been changed, pass true.
|
||||
*/
|
||||
void unlockColors(bool changed);
|
||||
|
||||
/** Similar to lockColors(), lock16BitCache() returns the array of
|
||||
RGB16 colors that mirror the 32bit colors. However, this function
|
||||
will return null if kColorsAreOpaque_Flag is not set.
|
||||
Also, unlike lockColors(), the returned array here cannot be modified.
|
||||
*/
|
||||
const uint16_t* lock16BitCache();
|
||||
/** Balancing call to lock16BitCache().
|
||||
*/
|
||||
void unlock16BitCache() {
|
||||
SkASSERT(f16BitCacheLockCount > 0);
|
||||
SkDEBUGCODE(f16BitCacheLockCount -= 1);
|
||||
}
|
||||
|
||||
SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkColorTable)
|
||||
|
||||
protected:
|
||||
explicit SkColorTable(SkFlattenableReadBuffer&);
|
||||
void flatten(SkFlattenableWriteBuffer&) const;
|
||||
|
||||
private:
|
||||
SkPMColor* fColors;
|
||||
uint16_t* f16BitCache;
|
||||
uint16_t fCount;
|
||||
uint8_t fFlags;
|
||||
SkDEBUGCODE(int fColorLockCount;)
|
||||
SkDEBUGCODE(int f16BitCacheLockCount;)
|
||||
|
||||
void inval16BitCache();
|
||||
|
||||
typedef SkFlattenable INHERITED;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -1,88 +0,0 @@
|
|||
/*
|
||||
* 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 SkDataSet_DEFINED
|
||||
#define SkDataSet_DEFINED
|
||||
|
||||
#include "SkData.h"
|
||||
#include "SkFlattenable.h"
|
||||
|
||||
class SkStream;
|
||||
class SkWStream;
|
||||
|
||||
class SkDataSet : public SkFlattenable {
|
||||
public:
|
||||
/**
|
||||
* Returns a new empty dataset. Note: since SkDataSet is immutable, this
|
||||
* "new" set may be the same one that was returned before, but each
|
||||
* returned object must have its reference-count balanced regardless.
|
||||
*
|
||||
* SkDataSet* empty = SkDataSet::NewEmpty();
|
||||
* ...
|
||||
* empty->unref();
|
||||
*/
|
||||
static SkDataSet* NewEmpty();
|
||||
|
||||
struct Pair {
|
||||
const char* fKey;
|
||||
SkData* fValue;
|
||||
};
|
||||
|
||||
SkDataSet(const char key[], SkData* value);
|
||||
SkDataSet(const Pair[], int count);
|
||||
virtual ~SkDataSet();
|
||||
|
||||
bool isEmpty() const { return 0 == fCount; }
|
||||
int count() const { return fCount; }
|
||||
SkData* find(const char name[]) const;
|
||||
|
||||
class Iter {
|
||||
public:
|
||||
Iter(const SkDataSet& ds) {
|
||||
fPair = ds.fPairs;
|
||||
fStop = ds.fPairs + ds.fCount;
|
||||
}
|
||||
|
||||
const char* key() const {
|
||||
SkASSERT(!this->done());
|
||||
return fPair->fKey;
|
||||
}
|
||||
|
||||
SkData* value() const {
|
||||
SkASSERT(!this->done());
|
||||
return fPair->fValue;
|
||||
}
|
||||
|
||||
bool done() const { return fPair >= fStop; }
|
||||
void next() {
|
||||
SkASSERT(!this->done());
|
||||
fPair += 1;
|
||||
}
|
||||
|
||||
private:
|
||||
const SkDataSet::Pair* fPair;
|
||||
const SkDataSet::Pair* fStop;
|
||||
};
|
||||
|
||||
explicit SkDataSet(SkStream*);
|
||||
void writeToStream(SkWStream*) const;
|
||||
|
||||
SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkDataSet)
|
||||
|
||||
protected:
|
||||
SkDataSet(SkFlattenableReadBuffer&);
|
||||
virtual void flatten(SkFlattenableWriteBuffer&) const SK_OVERRIDE;
|
||||
|
||||
private:
|
||||
int32_t fCount;
|
||||
uint32_t fKeySize;
|
||||
Pair* fPairs;
|
||||
|
||||
typedef SkFlattenable INHERITED;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -1,175 +0,0 @@
|
|||
|
||||
/*
|
||||
* 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 SkFlattenableBuffers_DEFINED
|
||||
#define SkFlattenableBuffers_DEFINED
|
||||
|
||||
#include "SkColor.h"
|
||||
#include "SkPaint.h"
|
||||
#include "SkPoint.h"
|
||||
|
||||
class SkBitmap;
|
||||
class SkFlattenable;
|
||||
struct SkIRect;
|
||||
class SkMatrix;
|
||||
class SkOrderedReadBuffer;
|
||||
class SkOrderedWriteBuffer;
|
||||
class SkPath;
|
||||
class SkPixelRef;
|
||||
struct SkRect;
|
||||
class SkRefCnt;
|
||||
class SkRegion;
|
||||
class SkStream;
|
||||
class SkString;
|
||||
class SkTypeface;
|
||||
class SkWStream;
|
||||
|
||||
class SkFlattenableReadBuffer {
|
||||
public:
|
||||
SkFlattenableReadBuffer();
|
||||
virtual ~SkFlattenableReadBuffer();
|
||||
|
||||
bool isOrderedBinaryBuffer() { return NULL != getOrderedBinaryBuffer(); }
|
||||
virtual SkOrderedReadBuffer* getOrderedBinaryBuffer() { return NULL; }
|
||||
|
||||
enum Flags {
|
||||
kCrossProcess_Flag = 1 << 0,
|
||||
kScalarIsFloat_Flag = 1 << 1,
|
||||
kPtrIs64Bit_Flag = 1 << 2,
|
||||
};
|
||||
|
||||
void setFlags(uint32_t flags) { fFlags = flags; }
|
||||
uint32_t getFlags() const { return fFlags; }
|
||||
|
||||
bool isCrossProcess() const { return SkToBool(fFlags & kCrossProcess_Flag); }
|
||||
bool isScalarFloat() const { return SkToBool(fFlags & kScalarIsFloat_Flag); }
|
||||
bool isPtr64Bit() const { return SkToBool(fFlags & kPtrIs64Bit_Flag); }
|
||||
|
||||
// primitives
|
||||
virtual bool readBool() = 0;
|
||||
virtual SkColor readColor() = 0;
|
||||
virtual SkFixed readFixed() = 0;
|
||||
virtual int32_t readInt() = 0;
|
||||
virtual SkScalar readScalar() = 0;
|
||||
virtual uint32_t readUInt() = 0;
|
||||
virtual int32_t read32() = 0;
|
||||
|
||||
// strings -- the caller is responsible for freeing the string contents
|
||||
virtual char* readString() = 0;
|
||||
virtual void* readEncodedString(size_t* length, SkPaint::TextEncoding encoding) = 0;
|
||||
|
||||
// common data structures
|
||||
virtual SkFlattenable* readFlattenable() = 0;
|
||||
virtual void readPoint(SkPoint* point) = 0;
|
||||
virtual void readMatrix(SkMatrix* matrix) = 0;
|
||||
virtual void readIRect(SkIRect* rect) = 0;
|
||||
virtual void readRect(SkRect* rect) = 0;
|
||||
virtual void readRegion(SkRegion* region) = 0;
|
||||
virtual void readPath(SkPath* path) = 0;
|
||||
|
||||
// binary data and arrays
|
||||
virtual uint32_t readByteArray(void* value) = 0;
|
||||
virtual uint32_t readColorArray(SkColor* colors) = 0;
|
||||
virtual uint32_t readIntArray(int32_t* values) = 0;
|
||||
virtual uint32_t readPointArray(SkPoint* points) = 0;
|
||||
virtual uint32_t readScalarArray(SkScalar* values) = 0;
|
||||
|
||||
/** This helper peeks into the buffer and reports back the length of the next array in
|
||||
* the buffer but does not change the state of the buffer.
|
||||
*/
|
||||
virtual uint32_t getArrayCount() = 0;
|
||||
|
||||
// helper functions
|
||||
virtual void* readFunctionPtr();
|
||||
virtual void readPaint(SkPaint* paint);
|
||||
|
||||
virtual void readBitmap(SkBitmap* bitmap) = 0;
|
||||
virtual SkTypeface* readTypeface() = 0;
|
||||
|
||||
// helper function for classes with const SkPoint members
|
||||
SkPoint readPoint() {
|
||||
SkPoint point;
|
||||
this->readPoint(&point);
|
||||
return point;
|
||||
}
|
||||
|
||||
template <typename T> T* readFlattenableT() {
|
||||
return static_cast<T*>(this->readFlattenable());
|
||||
}
|
||||
|
||||
private:
|
||||
uint32_t fFlags;
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class SkFlattenableWriteBuffer {
|
||||
public:
|
||||
SkFlattenableWriteBuffer();
|
||||
virtual ~SkFlattenableWriteBuffer();
|
||||
|
||||
virtual bool isOrderedBinaryBuffer() { return false; }
|
||||
virtual SkOrderedWriteBuffer* getOrderedBinaryBuffer() { sk_throw(); return NULL; }
|
||||
|
||||
// primitives
|
||||
virtual void writeByteArray(const void* data, size_t size) = 0;
|
||||
virtual void writeBool(bool value) = 0;
|
||||
virtual void writeFixed(SkFixed value) = 0;
|
||||
virtual void writeScalar(SkScalar value) = 0;
|
||||
virtual void writeScalarArray(const SkScalar* value, uint32_t count) = 0;
|
||||
virtual void writeInt(int32_t value) = 0;
|
||||
virtual void writeIntArray(const int32_t* value, uint32_t count) = 0;
|
||||
virtual void writeUInt(uint32_t value) = 0;
|
||||
virtual void write32(int32_t value) = 0; // printf in hex
|
||||
virtual void writeString(const char* value) = 0;
|
||||
virtual void writeEncodedString(const void* value, size_t byteLength,
|
||||
SkPaint::TextEncoding encoding) = 0;
|
||||
|
||||
// common data structures
|
||||
virtual void writeFlattenable(SkFlattenable* flattenable) = 0;
|
||||
virtual void writeColor(const SkColor& color) = 0;
|
||||
virtual void writeColorArray(const SkColor* color, uint32_t count) = 0;
|
||||
virtual void writePoint(const SkPoint& point) = 0;
|
||||
virtual void writePointArray(const SkPoint* points, uint32_t count) = 0;
|
||||
virtual void writeMatrix(const SkMatrix& matrix) = 0;
|
||||
virtual void writeIRect(const SkIRect& rect) = 0;
|
||||
virtual void writeRect(const SkRect& rect) = 0;
|
||||
virtual void writeRegion(const SkRegion& region) = 0;
|
||||
virtual void writePath(const SkPath& path) = 0;
|
||||
virtual size_t writeStream(SkStream* stream, size_t length) = 0;
|
||||
|
||||
// helper functions
|
||||
virtual void writeFunctionPtr(void* ptr);
|
||||
virtual void writePaint(const SkPaint& paint);
|
||||
|
||||
virtual void writeBitmap(const SkBitmap& bitmap) = 0;
|
||||
virtual void writeTypeface(SkTypeface* typeface) = 0;
|
||||
|
||||
virtual bool writeToStream(SkWStream*) = 0;
|
||||
|
||||
enum Flags {
|
||||
kCrossProcess_Flag = 0x01,
|
||||
};
|
||||
|
||||
uint32_t getFlags() const { return fFlags; }
|
||||
void setFlags(uint32_t flags) { fFlags = flags; }
|
||||
|
||||
bool isCrossProcess() const {
|
||||
return SkToBool(fFlags & kCrossProcess_Flag);
|
||||
}
|
||||
|
||||
bool persistTypeface() const { return (fFlags & kCrossProcess_Flag) != 0; }
|
||||
|
||||
protected:
|
||||
// A helper function so that each subclass does not have to be a friend of SkFlattenable
|
||||
void flattenObject(SkFlattenable* obj, SkFlattenableWriteBuffer& buffer);
|
||||
|
||||
uint32_t fFlags;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -1,100 +0,0 @@
|
|||
/*
|
||||
* 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 SkImage_DEFINED
|
||||
#define SkImage_DEFINED
|
||||
|
||||
#include "SkRefCnt.h"
|
||||
#include "SkScalar.h"
|
||||
|
||||
class SkData;
|
||||
class SkCanvas;
|
||||
class SkPaint;
|
||||
class SkShader;
|
||||
class GrContext;
|
||||
class GrTexture;
|
||||
|
||||
// need for TileMode
|
||||
#include "SkShader.h"
|
||||
|
||||
////// EXPERIMENTAL
|
||||
|
||||
/**
|
||||
* SkImage is an abstraction for drawing a rectagle of pixels, though the
|
||||
* particular type of image could be actually storing its data on the GPU, or
|
||||
* as drawing commands (picture or PDF or otherwise), ready to be played back
|
||||
* into another canvas.
|
||||
*
|
||||
* The content of SkImage is always immutable, though the actual storage may
|
||||
* change, if for example that image can be re-created via encoded data or
|
||||
* other means.
|
||||
*/
|
||||
class SkImage : public SkRefCnt {
|
||||
public:
|
||||
SK_DECLARE_INST_COUNT(SkImage)
|
||||
|
||||
enum 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,
|
||||
|
||||
kLastEnum_AlphaType = kUnpremul_AlphaType
|
||||
};
|
||||
|
||||
struct Info {
|
||||
int fWidth;
|
||||
int fHeight;
|
||||
ColorType fColorType;
|
||||
AlphaType fAlphaType;
|
||||
};
|
||||
|
||||
static SkImage* NewRasterCopy(const Info&, const void* pixels, size_t rowBytes);
|
||||
static SkImage* NewRasterData(const Info&, SkData* pixels, size_t rowBytes);
|
||||
static SkImage* NewEncodedData(SkData*);
|
||||
static SkImage* NewTexture(GrTexture*);
|
||||
|
||||
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 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();
|
||||
|
||||
typedef SkRefCnt INHERITED;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -1,171 +0,0 @@
|
|||
/*
|
||||
* Copyright 2011 Google Inc.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#ifndef SkImageFilter_DEFINED
|
||||
#define SkImageFilter_DEFINED
|
||||
|
||||
#include "SkFlattenable.h"
|
||||
|
||||
class SkBitmap;
|
||||
class SkColorFilter;
|
||||
class SkDevice;
|
||||
class SkMatrix;
|
||||
struct SkIPoint;
|
||||
struct SkIRect;
|
||||
class SkShader;
|
||||
class GrEffectRef;
|
||||
class GrTexture;
|
||||
|
||||
/**
|
||||
* Experimental.
|
||||
*
|
||||
* Base class for image filters. If one is installed in the paint, then
|
||||
* all drawing occurs as usual, but it is as if the drawing happened into an
|
||||
* offscreen (before the xfermode is applied). This offscreen bitmap will
|
||||
* then be handed to the imagefilter, who in turn creates a new bitmap which
|
||||
* is what will finally be drawn to the device (using the original xfermode).
|
||||
*
|
||||
* THIS SIGNATURE IS TEMPORARY
|
||||
*
|
||||
* There are several weaknesses in this function signature:
|
||||
* 1. Does not expose the destination/target device, so filters that can draw
|
||||
* directly to it are unable to take advantage of that optimization.
|
||||
* 2. Does not expose a way to create a "compabitible" image (i.e. gpu -> gpu)
|
||||
* 3. As with #1, the filter is unable to "read" the dest (which would be slow)
|
||||
*
|
||||
* Therefore, we should not create any real dependencies on this API yet -- it
|
||||
* is being checked in as a check-point so we can explore these and other
|
||||
* considerations.
|
||||
*/
|
||||
class SK_API SkImageFilter : public SkFlattenable {
|
||||
public:
|
||||
SK_DECLARE_INST_COUNT(SkImageFilter)
|
||||
|
||||
class Proxy {
|
||||
public:
|
||||
virtual ~Proxy() {};
|
||||
|
||||
virtual SkDevice* createDevice(int width, int height) = 0;
|
||||
// returns true if the proxy can handle this filter natively
|
||||
virtual bool canHandleImageFilter(SkImageFilter*) = 0;
|
||||
// returns true if the proxy handled the filter itself. if this returns
|
||||
// false then the filter's code will be called.
|
||||
virtual bool filterImage(SkImageFilter*, const SkBitmap& src,
|
||||
const SkMatrix& ctm,
|
||||
SkBitmap* result, SkIPoint* offset) = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* Request a new (result) image to be created from the src image.
|
||||
* If the src has no pixels (isNull()) then the request just wants to
|
||||
* receive the config and width/height of the result.
|
||||
*
|
||||
* The matrix is the current matrix on the canvas.
|
||||
*
|
||||
* Offset is the amount to translate the resulting image relative to the
|
||||
* src when it is drawn.
|
||||
*
|
||||
* If the result image cannot be created, return false, in which case both
|
||||
* the result and offset parameters will be ignored by the caller.
|
||||
*/
|
||||
bool filterImage(Proxy*, const SkBitmap& src, const SkMatrix& ctm,
|
||||
SkBitmap* result, SkIPoint* offset);
|
||||
|
||||
/**
|
||||
* Given the src bounds of an image, this returns the bounds of the result
|
||||
* image after the filter has been applied.
|
||||
*/
|
||||
bool filterBounds(const SkIRect& src, const SkMatrix& ctm, SkIRect* dst);
|
||||
|
||||
/**
|
||||
* Returns true if the filter can be expressed a single-pass
|
||||
* GrEffect, used to process this filter on the GPU, or false if
|
||||
* not.
|
||||
*
|
||||
* If effect is non-NULL, a new GrEffect instance is stored
|
||||
* in it. The caller assumes ownership of the stage, and it is up to the
|
||||
* caller to unref it.
|
||||
*
|
||||
* The effect can assume its vertexCoords space maps 1-to-1 with texels
|
||||
* in the texture.
|
||||
*/
|
||||
virtual bool asNewEffect(GrEffectRef** effect, GrTexture*) const;
|
||||
|
||||
/**
|
||||
* Returns true if the filter can be processed on the GPU. This is most
|
||||
* often used for multi-pass effects, where intermediate results must be
|
||||
* rendered to textures. For single-pass effects, use asNewEffect().
|
||||
* The default implementation returns false.
|
||||
*/
|
||||
virtual bool canFilterImageGPU() const;
|
||||
|
||||
/**
|
||||
* Process this image filter on the GPU. src is the source image for
|
||||
* processing, as a texture-backed bitmap. result is the destination
|
||||
* bitmap, which should contain a texture-backed pixelref on success.
|
||||
* The default implementation returns returns false and ignores the
|
||||
* result parameter.
|
||||
*/
|
||||
virtual bool filterImageGPU(Proxy*, const SkBitmap& src, SkBitmap* result);
|
||||
|
||||
/**
|
||||
* Returns whether this image filter is a color filter and puts the color filter into the
|
||||
* "filterPtr" parameter if it can. Does nothing otherwise.
|
||||
* If this returns false, then the filterPtr is unchanged.
|
||||
* If this returns true, then if filterPtr is not null, it must be set to a ref'd colorfitler
|
||||
* (i.e. it may not be set to NULL).
|
||||
*/
|
||||
virtual bool asColorFilter(SkColorFilter** filterPtr) const;
|
||||
|
||||
/**
|
||||
* Returns the number of inputs this filter will accept (some inputs can
|
||||
* be NULL).
|
||||
*/
|
||||
int countInputs() const { return fInputCount; }
|
||||
|
||||
/**
|
||||
* Returns the input filter at a given index, or NULL if no input is
|
||||
* connected. The indices used are filter-specific.
|
||||
*/
|
||||
SkImageFilter* getInput(int i) const {
|
||||
SkASSERT(i < fInputCount);
|
||||
return fInputs[i];
|
||||
}
|
||||
|
||||
protected:
|
||||
SkImageFilter(int inputCount, SkImageFilter** inputs);
|
||||
|
||||
// Convenience constructor for 1-input filters.
|
||||
explicit SkImageFilter(SkImageFilter* input);
|
||||
|
||||
// Convenience constructor for 2-input filters.
|
||||
SkImageFilter(SkImageFilter* input1, SkImageFilter* input2);
|
||||
|
||||
virtual ~SkImageFilter();
|
||||
|
||||
explicit SkImageFilter(SkFlattenableReadBuffer& rb);
|
||||
|
||||
virtual void flatten(SkFlattenableWriteBuffer& wb) const SK_OVERRIDE;
|
||||
|
||||
// Default impl returns false
|
||||
virtual bool onFilterImage(Proxy*, const SkBitmap& src, const SkMatrix&,
|
||||
SkBitmap* result, SkIPoint* offset);
|
||||
// Default impl copies src into dst and returns true
|
||||
virtual bool onFilterBounds(const SkIRect&, const SkMatrix&, SkIRect*);
|
||||
|
||||
// Return the result of processing the given input, or the source bitmap
|
||||
// if we have no connected input at that index.
|
||||
SkBitmap getInputResult(int index, Proxy*, const SkBitmap& src, const SkMatrix&,
|
||||
SkIPoint*);
|
||||
|
||||
private:
|
||||
typedef SkFlattenable INHERITED;
|
||||
int fInputCount;
|
||||
SkImageFilter** fInputs;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -1,39 +0,0 @@
|
|||
/*
|
||||
* Copyright 2013 Google Inc.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#ifndef SkImageTypes_DEFINED
|
||||
#define SkImageTypes_DEFINED
|
||||
|
||||
#include "SkTypes.h"
|
||||
|
||||
enum SkColorType {
|
||||
kAlpha_8_SkColorType,
|
||||
kRGB_565_SkColorType,
|
||||
// kRGBA_8888_SkColorType,
|
||||
// kBGRA_8888_SkColorType,
|
||||
kPMColor_SkColorType,
|
||||
|
||||
kLastEnum_SkColorType = kPMColor_SkColorType
|
||||
};
|
||||
|
||||
enum SkAlphaType {
|
||||
// kIgnore_SkAlphaType,
|
||||
kOpaque_SkAlphaType,
|
||||
// kUnpremul_SkAlphaType,
|
||||
kPremul_SkAlphaType,
|
||||
|
||||
kLastEnum_SkAlphaType = kPremul_SkAlphaType
|
||||
};
|
||||
|
||||
struct SkImageInfo {
|
||||
int fWidth;
|
||||
int fHeight;
|
||||
SkColorType fColorType;
|
||||
SkAlphaType fAlphaType;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -1,51 +0,0 @@
|
|||
|
||||
/*
|
||||
* Copyright 2008 The Android Open Source Project
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef SkMallocPixelRef_DEFINED
|
||||
#define SkMallocPixelRef_DEFINED
|
||||
|
||||
#include "SkPixelRef.h"
|
||||
|
||||
/** We explicitly use the same allocator for our pixels that SkMask does,
|
||||
so that we can freely assign memory allocated by one class to the other.
|
||||
*/
|
||||
class SkMallocPixelRef : public SkPixelRef {
|
||||
public:
|
||||
/** Allocate the specified buffer for pixels. The memory is freed when the
|
||||
last owner of this pixelref is gone. If addr is NULL, sk_malloc_throw()
|
||||
is called to allocate it.
|
||||
*/
|
||||
SkMallocPixelRef(void* addr, size_t size, SkColorTable* ctable, bool ownPixels = true);
|
||||
virtual ~SkMallocPixelRef();
|
||||
|
||||
//! Return the allocation size for the pixels
|
||||
size_t getSize() const { return fSize; }
|
||||
void* getAddr() const { return fStorage; }
|
||||
|
||||
SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkMallocPixelRef)
|
||||
|
||||
protected:
|
||||
// overrides from SkPixelRef
|
||||
virtual void* onLockPixels(SkColorTable**);
|
||||
virtual void onUnlockPixels();
|
||||
|
||||
SkMallocPixelRef(SkFlattenableReadBuffer& buffer);
|
||||
virtual void flatten(SkFlattenableWriteBuffer&) const SK_OVERRIDE;
|
||||
|
||||
private:
|
||||
void* fStorage;
|
||||
size_t fSize;
|
||||
SkColorTable* fCTable;
|
||||
bool fOwnPixels;
|
||||
|
||||
typedef SkPixelRef INHERITED;
|
||||
};
|
||||
|
||||
|
||||
#endif
|
|
@ -1,363 +0,0 @@
|
|||
|
||||
/*
|
||||
* Copyright 2006 The Android Open Source Project
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef SkPostConfig_DEFINED
|
||||
#define SkPostConfig_DEFINED
|
||||
|
||||
#if defined(SK_BUILD_FOR_WIN32) || defined(SK_BUILD_FOR_WINCE)
|
||||
#define SK_BUILD_FOR_WIN
|
||||
#endif
|
||||
|
||||
#if defined(SK_DEBUG) && defined(SK_RELEASE)
|
||||
#error "cannot define both SK_DEBUG and SK_RELEASE"
|
||||
#elif !defined(SK_DEBUG) && !defined(SK_RELEASE)
|
||||
#error "must define either SK_DEBUG or SK_RELEASE"
|
||||
#endif
|
||||
|
||||
#if defined SK_SUPPORT_UNITTEST && !defined(SK_DEBUG)
|
||||
#error "can't have unittests without debug"
|
||||
#endif
|
||||
|
||||
#if defined(SK_SCALAR_IS_FIXED) && defined(SK_SCALAR_IS_FLOAT)
|
||||
#error "cannot define both SK_SCALAR_IS_FIXED and SK_SCALAR_IS_FLOAT"
|
||||
#elif !defined(SK_SCALAR_IS_FIXED) && !defined(SK_SCALAR_IS_FLOAT)
|
||||
#define SK_SCALAR_IS_FLOAT
|
||||
#endif
|
||||
|
||||
#if defined(SK_MSCALAR_IS_DOUBLE) && defined(SK_MSCALAR_IS_FLOAT)
|
||||
#error "cannot define both SK_MSCALAR_IS_DOUBLE and SK_MSCALAR_IS_FLOAT"
|
||||
#elif !defined(SK_MSCALAR_IS_DOUBLE) && !defined(SK_MSCALAR_IS_FLOAT)
|
||||
// default is double, as that is faster given our impl uses doubles
|
||||
// for intermediate calculations.
|
||||
#define SK_MSCALAR_IS_DOUBLE
|
||||
#endif
|
||||
|
||||
#if defined(SK_CPU_LENDIAN) && defined(SK_CPU_BENDIAN)
|
||||
#error "cannot define both SK_CPU_LENDIAN and SK_CPU_BENDIAN"
|
||||
#elif !defined(SK_CPU_LENDIAN) && !defined(SK_CPU_BENDIAN)
|
||||
#error "must define either SK_CPU_LENDIAN or SK_CPU_BENDIAN"
|
||||
#endif
|
||||
|
||||
// ensure the port has defined all of these, or none of them
|
||||
#ifdef SK_A32_SHIFT
|
||||
#if !defined(SK_R32_SHIFT) || !defined(SK_G32_SHIFT) || !defined(SK_B32_SHIFT)
|
||||
#error "all or none of the 32bit SHIFT amounts must be defined"
|
||||
#endif
|
||||
#else
|
||||
#if defined(SK_R32_SHIFT) || defined(SK_G32_SHIFT) || defined(SK_B32_SHIFT)
|
||||
#error "all or none of the 32bit SHIFT amounts must be defined"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if !defined(SK_HAS_COMPILER_FEATURE)
|
||||
#if defined(__has_feature)
|
||||
#define SK_HAS_COMPILER_FEATURE(x) __has_feature(x)
|
||||
#else
|
||||
#define SK_HAS_COMPILER_FEATURE(x) 0
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if !defined(SK_SUPPORT_GPU)
|
||||
#define SK_SUPPORT_GPU 1
|
||||
#endif
|
||||
|
||||
/**
|
||||
* The clang static analyzer likes to know that when the program is not
|
||||
* expected to continue (crash, assertion failure, etc). It will notice that
|
||||
* some combination of parameters lead to a function call that does not return.
|
||||
* It can then make appropriate assumptions about the parameters in code
|
||||
* executed only if the non-returning function was *not* called.
|
||||
*/
|
||||
#if !defined(SkNO_RETURN_HINT)
|
||||
#if SK_HAS_COMPILER_FEATURE(attribute_analyzer_noreturn)
|
||||
static inline void SkNO_RETURN_HINT() __attribute__((analyzer_noreturn));
|
||||
static inline void SkNO_RETURN_HINT() {}
|
||||
#else
|
||||
#define SkNO_RETURN_HINT() do {} while (false)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(SK_ZLIB_INCLUDE) && defined(SK_SYSTEM_ZLIB)
|
||||
#error "cannot define both SK_ZLIB_INCLUDE and SK_SYSTEM_ZLIB"
|
||||
#elif defined(SK_ZLIB_INCLUDE) || defined(SK_SYSTEM_ZLIB)
|
||||
#define SK_HAS_ZLIB
|
||||
#endif
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef SkNEW
|
||||
#define SkNEW(type_name) (new type_name)
|
||||
#define SkNEW_ARGS(type_name, args) (new type_name args)
|
||||
#define SkNEW_ARRAY(type_name, count) (new type_name[(count)])
|
||||
#define SkNEW_PLACEMENT(buf, type_name) (new (buf) type_name)
|
||||
#define SkNEW_PLACEMENT_ARGS(buf, type_name, args) \
|
||||
(new (buf) type_name args)
|
||||
#define SkDELETE(obj) (delete (obj))
|
||||
#define SkDELETE_ARRAY(array) (delete[] (array))
|
||||
#endif
|
||||
|
||||
#ifndef SK_CRASH
|
||||
#if 1 // set to 0 for infinite loop, which can help connecting gdb
|
||||
#define SK_CRASH() do { SkNO_RETURN_HINT(); *(int *)(uintptr_t)0xbbadbeef = 0; } while (false)
|
||||
#else
|
||||
#define SK_CRASH() do { SkNO_RETURN_HINT(); } while (true)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// SK_ENABLE_INST_COUNT defaults to 1 in DEBUG and 0 in RELEASE
|
||||
#ifndef SK_ENABLE_INST_COUNT
|
||||
#ifdef SK_DEBUG
|
||||
#define SK_ENABLE_INST_COUNT 1
|
||||
#else
|
||||
#define SK_ENABLE_INST_COUNT 0
|
||||
#endif
|
||||
#endif
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#if defined(SK_SOFTWARE_FLOAT) && defined(SK_SCALAR_IS_FLOAT)
|
||||
// if this is defined, we convert floats to 2scompliment ints for compares
|
||||
#ifndef SK_SCALAR_SLOW_COMPARES
|
||||
#define SK_SCALAR_SLOW_COMPARES
|
||||
#endif
|
||||
#ifndef SK_USE_FLOATBITS
|
||||
#define SK_USE_FLOATBITS
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef SK_BUILD_FOR_WIN
|
||||
// we want lean_and_mean when we include windows.h
|
||||
#ifndef WIN32_LEAN_AND_MEAN
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#define WIN32_IS_MEAN_WAS_LOCALLY_DEFINED
|
||||
#endif
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#ifdef WIN32_IS_MEAN_WAS_LOCALLY_DEFINED
|
||||
#undef WIN32_LEAN_AND_MEAN
|
||||
#endif
|
||||
|
||||
#ifndef SK_DEBUGBREAK
|
||||
#define SK_DEBUGBREAK(cond) do { if (!(cond)) { SkNO_RETURN_HINT(); __debugbreak(); }} while (false)
|
||||
#endif
|
||||
|
||||
#ifndef SK_A32_SHIFT
|
||||
#define SK_A32_SHIFT 24
|
||||
#define SK_R32_SHIFT 16
|
||||
#define SK_G32_SHIFT 8
|
||||
#define SK_B32_SHIFT 0
|
||||
#endif
|
||||
|
||||
#else
|
||||
#ifdef SK_DEBUG
|
||||
#include <stdio.h>
|
||||
#ifndef SK_DEBUGBREAK
|
||||
#define SK_DEBUGBREAK(cond) do { if (cond) break; \
|
||||
SkDebugf("%s:%d: failed assertion \"%s\"\n", \
|
||||
__FILE__, __LINE__, #cond); SK_CRASH(); } while (false)
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/*
|
||||
* We check to see if the SHIFT value has already been defined.
|
||||
* if not, we define it ourself to some default values. We default to OpenGL
|
||||
* order (in memory: r,g,b,a)
|
||||
*/
|
||||
#ifndef SK_A32_SHIFT
|
||||
#ifdef SK_CPU_BENDIAN
|
||||
#define SK_R32_SHIFT 24
|
||||
#define SK_G32_SHIFT 16
|
||||
#define SK_B32_SHIFT 8
|
||||
#define SK_A32_SHIFT 0
|
||||
#else
|
||||
#define SK_R32_SHIFT 0
|
||||
#define SK_G32_SHIFT 8
|
||||
#define SK_B32_SHIFT 16
|
||||
#define SK_A32_SHIFT 24
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/**
|
||||
* SK_PMCOLOR_BYTE_ORDER can be used to query the byte order of SkPMColor at compile time. The
|
||||
* relationship between the byte order and shift values depends on machine endianness. If the shift
|
||||
* order is R=0, G=8, B=16, A=24 then ((char*)&pmcolor)[0] will produce the R channel on a little
|
||||
* endian machine and the A channel on a big endian machine. Thus, given those shifts values,
|
||||
* SK_PMCOLOR_BYTE_ORDER(R,G,B,A) will be true on a little endian machine and
|
||||
* SK_PMCOLOR_BYTE_ORDER(A,B,G,R) will be true on a big endian machine.
|
||||
*/
|
||||
#ifdef SK_CPU_BENDIAN
|
||||
#define SK_PMCOLOR_BYTE_ORDER(C0, C1, C2, C3) \
|
||||
(SK_ ## C3 ## 32_SHIFT == 0 && \
|
||||
SK_ ## C2 ## 32_SHIFT == 8 && \
|
||||
SK_ ## C1 ## 32_SHIFT == 16 && \
|
||||
SK_ ## C0 ## 32_SHIFT == 24)
|
||||
#else
|
||||
#define SK_PMCOLOR_BYTE_ORDER(C0, C1, C2, C3) \
|
||||
(SK_ ## C0 ## 32_SHIFT == 0 && \
|
||||
SK_ ## C1 ## 32_SHIFT == 8 && \
|
||||
SK_ ## C2 ## 32_SHIFT == 16 && \
|
||||
SK_ ## C3 ## 32_SHIFT == 24)
|
||||
#endif
|
||||
|
||||
// stdlib macros
|
||||
|
||||
#if 0
|
||||
#if !defined(strlen) && defined(SK_DEBUG)
|
||||
extern size_t sk_strlen(const char*);
|
||||
#define strlen(s) sk_strlen(s)
|
||||
#endif
|
||||
#ifndef sk_strcpy
|
||||
#define sk_strcpy(dst, src) strcpy(dst, src)
|
||||
#endif
|
||||
#ifndef sk_strchr
|
||||
#define sk_strchr(s, c) strchr(s, c)
|
||||
#endif
|
||||
#ifndef sk_strrchr
|
||||
#define sk_strrchr(s, c) strrchr(s, c)
|
||||
#endif
|
||||
#ifndef sk_strcmp
|
||||
#define sk_strcmp(s, t) strcmp(s, t)
|
||||
#endif
|
||||
#ifndef sk_strncmp
|
||||
#define sk_strncmp(s, t, n) strncmp(s, t, n)
|
||||
#endif
|
||||
#ifndef sk_memcpy
|
||||
#define sk_memcpy(dst, src, n) memcpy(dst, src, n)
|
||||
#endif
|
||||
#ifndef memmove
|
||||
#define memmove(dst, src, n) memmove(dst, src, n)
|
||||
#endif
|
||||
#ifndef sk_memset
|
||||
#define sk_memset(dst, val, n) memset(dst, val, n)
|
||||
#endif
|
||||
#ifndef sk_memcmp
|
||||
#define sk_memcmp(s, t, n) memcmp(s, t, n)
|
||||
#endif
|
||||
|
||||
#define sk_strequal(s, t) (!sk_strcmp(s, t))
|
||||
#define sk_strnequal(s, t, n) (!sk_strncmp(s, t, n))
|
||||
#endif
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
#if defined(SK_BUILD_FOR_WIN32) || defined(SK_BUILD_FOR_MAC)
|
||||
#ifndef SkLONGLONG
|
||||
#ifdef SK_BUILD_FOR_WIN32
|
||||
#define SkLONGLONG __int64
|
||||
#else
|
||||
#define SkLONGLONG long long
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////
|
||||
#ifndef SK_BUILD_FOR_WINCE
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#else
|
||||
#define _CMNINTRIN_DECLARE_ONLY
|
||||
#include "cmnintrin.h"
|
||||
#endif
|
||||
|
||||
#if defined SK_DEBUG && defined SK_BUILD_FOR_WIN32
|
||||
//#define _CRTDBG_MAP_ALLOC
|
||||
#ifdef free
|
||||
#undef free
|
||||
#endif
|
||||
#include <crtdbg.h>
|
||||
#undef free
|
||||
|
||||
#ifdef SK_DEBUGx
|
||||
#if defined(SK_SIMULATE_FAILED_MALLOC) && defined(__cplusplus)
|
||||
void * operator new(
|
||||
size_t cb,
|
||||
int nBlockUse,
|
||||
const char * szFileName,
|
||||
int nLine,
|
||||
int foo
|
||||
);
|
||||
void * operator new[](
|
||||
size_t cb,
|
||||
int nBlockUse,
|
||||
const char * szFileName,
|
||||
int nLine,
|
||||
int foo
|
||||
);
|
||||
void operator delete(
|
||||
void *pUserData,
|
||||
int, const char*, int, int
|
||||
);
|
||||
void operator delete(
|
||||
void *pUserData
|
||||
);
|
||||
void operator delete[]( void * p );
|
||||
#define DEBUG_CLIENTBLOCK new( _CLIENT_BLOCK, __FILE__, __LINE__, 0)
|
||||
#else
|
||||
#define DEBUG_CLIENTBLOCK new( _CLIENT_BLOCK, __FILE__, __LINE__)
|
||||
#endif
|
||||
#define new DEBUG_CLIENTBLOCK
|
||||
#else
|
||||
#define DEBUG_CLIENTBLOCK
|
||||
#endif // _DEBUG
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef SK_OVERRIDE
|
||||
#if defined(_MSC_VER)
|
||||
#define SK_OVERRIDE override
|
||||
#elif defined(__clang__) && !defined(SK_BUILD_FOR_IOS)
|
||||
#if __has_feature(cxx_override_control)
|
||||
// Some documentation suggests we should be using __attribute__((override)),
|
||||
// but it doesn't work.
|
||||
#define SK_OVERRIDE override
|
||||
#elif defined(__has_extension)
|
||||
#if __has_extension(cxx_override_control)
|
||||
#define SK_OVERRIDE override
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
#ifndef SK_OVERRIDE
|
||||
#define SK_OVERRIDE
|
||||
#endif
|
||||
#endif
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef SK_PRINTF_LIKE
|
||||
#if defined(__clang__) || defined(__GNUC__)
|
||||
#define SK_PRINTF_LIKE(A, B) __attribute__((format(printf, (A), (B))))
|
||||
#else
|
||||
#define SK_PRINTF_LIKE(A, B)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef SK_SIZE_T_SPECIFIER
|
||||
#if defined(_MSC_VER)
|
||||
#define SK_SIZE_T_SPECIFIER "%Iu"
|
||||
#else
|
||||
#define SK_SIZE_T_SPECIFIER "%zu"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef SK_ALLOW_STATIC_GLOBAL_INITIALIZERS
|
||||
#define SK_ALLOW_STATIC_GLOBAL_INITIALIZERS 1
|
||||
#endif
|
|
@ -1,379 +0,0 @@
|
|||
|
||||
/*
|
||||
* Copyright 2006 The Android Open Source Project
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef SkScalar_DEFINED
|
||||
#define SkScalar_DEFINED
|
||||
|
||||
#include "SkFixed.h"
|
||||
#include "SkFloatingPoint.h"
|
||||
|
||||
/** \file SkScalar.h
|
||||
|
||||
Types and macros for the data type SkScalar. This is the fractional numeric type
|
||||
that, depending on the compile-time flag SK_SCALAR_IS_FLOAT, may be implemented
|
||||
either as an IEEE float, or as a 16.16 SkFixed. The macros in this file are written
|
||||
to allow the calling code to manipulate SkScalar values without knowing which representation
|
||||
is in effect.
|
||||
*/
|
||||
|
||||
#ifdef SK_SCALAR_IS_FLOAT
|
||||
|
||||
/** SkScalar is our type for fractional values and coordinates. Depending on
|
||||
compile configurations, it is either represented as an IEEE float, or
|
||||
as a 16.16 fixed point integer.
|
||||
*/
|
||||
typedef float SkScalar;
|
||||
|
||||
/** SK_Scalar1 is defined to be 1.0 represented as an SkScalar
|
||||
*/
|
||||
#define SK_Scalar1 (1.0f)
|
||||
/** SK_Scalar1 is defined to be 1/2 represented as an SkScalar
|
||||
*/
|
||||
#define SK_ScalarHalf (0.5f)
|
||||
/** SK_ScalarInfinity is defined to be infinity as an SkScalar
|
||||
*/
|
||||
#define SK_ScalarInfinity SK_FloatInfinity
|
||||
/** SK_ScalarNegativeInfinity is defined to be negative infinity as an SkScalar
|
||||
*/
|
||||
#define SK_ScalarNegativeInfinity SK_FloatNegativeInfinity
|
||||
/** SK_ScalarMax is defined to be the largest value representable as an SkScalar
|
||||
*/
|
||||
#define SK_ScalarMax (3.402823466e+38f)
|
||||
/** SK_ScalarMin is defined to be the smallest value representable as an SkScalar
|
||||
*/
|
||||
#define SK_ScalarMin (-SK_ScalarMax)
|
||||
/** SK_ScalarNaN is defined to be 'Not a Number' as an SkScalar
|
||||
*/
|
||||
#define SK_ScalarNaN SK_FloatNaN
|
||||
/** SkScalarIsNaN(n) returns true if argument is not a number
|
||||
*/
|
||||
static inline bool SkScalarIsNaN(float x) { return x != x; }
|
||||
|
||||
/** Returns true if x is not NaN and not infinite */
|
||||
static inline bool SkScalarIsFinite(float x) {
|
||||
// We rely on the following behavior of infinities and nans
|
||||
// 0 * finite --> 0
|
||||
// 0 * infinity --> NaN
|
||||
// 0 * NaN --> NaN
|
||||
float prod = x * 0;
|
||||
// At this point, prod will either be NaN or 0
|
||||
// Therefore we can return (prod == prod) or (0 == prod).
|
||||
return prod == prod;
|
||||
}
|
||||
|
||||
#ifdef SK_DEBUG
|
||||
/** SkIntToScalar(n) returns its integer argument as an SkScalar
|
||||
*
|
||||
* If we're compiling in DEBUG mode, and can thus afford some extra runtime
|
||||
* cycles, check to make sure that the parameter passed in has not already
|
||||
* been converted to SkScalar. (A double conversion like this is harmless
|
||||
* for SK_SCALAR_IS_FLOAT, but for SK_SCALAR_IS_FIXED this causes trouble.)
|
||||
*
|
||||
* Note that we need all of these method signatures to properly handle the
|
||||
* various types that we pass into SkIntToScalar() to date:
|
||||
* int, size_t, U8CPU, etc., even though what we really mean is "anything
|
||||
* but a float".
|
||||
*/
|
||||
static inline float SkIntToScalar(signed int param) {
|
||||
return (float)param;
|
||||
}
|
||||
static inline float SkIntToScalar(unsigned int param) {
|
||||
return (float)param;
|
||||
}
|
||||
static inline float SkIntToScalar(signed long param) {
|
||||
return (float)param;
|
||||
}
|
||||
static inline float SkIntToScalar(unsigned long param) {
|
||||
return (float)param;
|
||||
}
|
||||
static inline float SkIntToScalar(float /* param */) {
|
||||
/* If the parameter passed into SkIntToScalar is a float,
|
||||
* one of two things has happened:
|
||||
* 1. the parameter was an SkScalar (which is typedef'd to float)
|
||||
* 2. the parameter was a float instead of an int
|
||||
*
|
||||
* Either way, it's not good.
|
||||
*/
|
||||
SkDEBUGFAIL("looks like you passed an SkScalar into SkIntToScalar");
|
||||
return (float)0;
|
||||
}
|
||||
#else // not SK_DEBUG
|
||||
/** SkIntToScalar(n) returns its integer argument as an SkScalar
|
||||
*/
|
||||
#define SkIntToScalar(n) ((float)(n))
|
||||
#endif // not SK_DEBUG
|
||||
/** SkFixedToScalar(n) returns its SkFixed argument as an SkScalar
|
||||
*/
|
||||
#define SkFixedToScalar(x) SkFixedToFloat(x)
|
||||
/** SkScalarToFixed(n) returns its SkScalar argument as an SkFixed
|
||||
*/
|
||||
#define SkScalarToFixed(x) SkFloatToFixed(x)
|
||||
|
||||
#define SkScalarToFloat(n) (n)
|
||||
#define SkFloatToScalar(n) (n)
|
||||
|
||||
#define SkScalarToDouble(n) (double)(n)
|
||||
#define SkDoubleToScalar(n) (float)(n)
|
||||
|
||||
/** SkScalarFraction(x) returns the signed fractional part of the argument
|
||||
*/
|
||||
#define SkScalarFraction(x) sk_float_mod(x, 1.0f)
|
||||
|
||||
#define SkScalarFloorToScalar(x) sk_float_floor(x)
|
||||
#define SkScalarCeilToScalar(x) sk_float_ceil(x)
|
||||
#define SkScalarRoundToScalar(x) sk_float_floor((x) + 0.5f)
|
||||
|
||||
#define SkScalarFloorToInt(x) sk_float_floor2int(x)
|
||||
#define SkScalarCeilToInt(x) sk_float_ceil2int(x)
|
||||
#define SkScalarRoundToInt(x) sk_float_round2int(x)
|
||||
#define SkScalarTruncToInt(x) static_cast<int>(x)
|
||||
|
||||
/** Returns the absolute value of the specified SkScalar
|
||||
*/
|
||||
#define SkScalarAbs(x) sk_float_abs(x)
|
||||
/** Return x with the sign of y
|
||||
*/
|
||||
#define SkScalarCopySign(x, y) sk_float_copysign(x, y)
|
||||
/** Returns the value pinned between 0 and max inclusive
|
||||
*/
|
||||
inline SkScalar SkScalarClampMax(SkScalar x, SkScalar max) {
|
||||
return x < 0 ? 0 : x > max ? max : x;
|
||||
}
|
||||
/** Returns the value pinned between min and max inclusive
|
||||
*/
|
||||
inline SkScalar SkScalarPin(SkScalar x, SkScalar min, SkScalar max) {
|
||||
return x < min ? min : x > max ? max : x;
|
||||
}
|
||||
/** Returns the specified SkScalar squared (x*x)
|
||||
*/
|
||||
inline SkScalar SkScalarSquare(SkScalar x) { return x * x; }
|
||||
/** Returns the product of two SkScalars
|
||||
*/
|
||||
#define SkScalarMul(a, b) ((float)(a) * (b))
|
||||
/** Returns the product of two SkScalars plus a third SkScalar
|
||||
*/
|
||||
#define SkScalarMulAdd(a, b, c) ((float)(a) * (b) + (c))
|
||||
/** Returns the product of a SkScalar and an int rounded to the nearest integer value
|
||||
*/
|
||||
#define SkScalarMulRound(a, b) SkScalarRound((float)(a) * (b))
|
||||
/** Returns the product of a SkScalar and an int promoted to the next larger int
|
||||
*/
|
||||
#define SkScalarMulCeil(a, b) SkScalarCeil((float)(a) * (b))
|
||||
/** Returns the product of a SkScalar and an int truncated to the next smaller int
|
||||
*/
|
||||
#define SkScalarMulFloor(a, b) SkScalarFloor((float)(a) * (b))
|
||||
/** Returns the quotient of two SkScalars (a/b)
|
||||
*/
|
||||
#define SkScalarDiv(a, b) ((float)(a) / (b))
|
||||
/** Returns the mod of two SkScalars (a mod b)
|
||||
*/
|
||||
#define SkScalarMod(x,y) sk_float_mod(x,y)
|
||||
/** Returns the product of the first two arguments, divided by the third argument
|
||||
*/
|
||||
#define SkScalarMulDiv(a, b, c) ((float)(a) * (b) / (c))
|
||||
/** Returns the multiplicative inverse of the SkScalar (1/x)
|
||||
*/
|
||||
#define SkScalarInvert(x) (SK_Scalar1 / (x))
|
||||
#define SkScalarFastInvert(x) (SK_Scalar1 / (x))
|
||||
/** Returns the square root of the SkScalar
|
||||
*/
|
||||
#define SkScalarSqrt(x) sk_float_sqrt(x)
|
||||
/** Returns b to the e
|
||||
*/
|
||||
#define SkScalarPow(b, e) sk_float_pow(b, e)
|
||||
/** Returns the average of two SkScalars (a+b)/2
|
||||
*/
|
||||
#define SkScalarAve(a, b) (((a) + (b)) * 0.5f)
|
||||
/** Returns the geometric mean of two SkScalars
|
||||
*/
|
||||
#define SkScalarMean(a, b) sk_float_sqrt((float)(a) * (b))
|
||||
/** Returns one half of the specified SkScalar
|
||||
*/
|
||||
#define SkScalarHalf(a) ((a) * 0.5f)
|
||||
|
||||
#define SK_ScalarSqrt2 1.41421356f
|
||||
#define SK_ScalarPI 3.14159265f
|
||||
#define SK_ScalarTanPIOver8 0.414213562f
|
||||
#define SK_ScalarRoot2Over2 0.707106781f
|
||||
|
||||
#define SkDegreesToRadians(degrees) ((degrees) * (SK_ScalarPI / 180))
|
||||
float SkScalarSinCos(SkScalar radians, SkScalar* cosValue);
|
||||
#define SkScalarSin(radians) (float)sk_float_sin(radians)
|
||||
#define SkScalarCos(radians) (float)sk_float_cos(radians)
|
||||
#define SkScalarTan(radians) (float)sk_float_tan(radians)
|
||||
#define SkScalarASin(val) (float)sk_float_asin(val)
|
||||
#define SkScalarACos(val) (float)sk_float_acos(val)
|
||||
#define SkScalarATan2(y, x) (float)sk_float_atan2(y,x)
|
||||
#define SkScalarExp(x) (float)sk_float_exp(x)
|
||||
#define SkScalarLog(x) (float)sk_float_log(x)
|
||||
|
||||
inline SkScalar SkMaxScalar(SkScalar a, SkScalar b) { return a > b ? a : b; }
|
||||
inline SkScalar SkMinScalar(SkScalar a, SkScalar b) { return a < b ? a : b; }
|
||||
|
||||
static inline bool SkScalarIsInt(SkScalar x) {
|
||||
return x == (float)(int)x;
|
||||
}
|
||||
#else
|
||||
typedef SkFixed SkScalar;
|
||||
|
||||
#define SK_Scalar1 SK_Fixed1
|
||||
#define SK_ScalarHalf SK_FixedHalf
|
||||
#define SK_ScalarInfinity SK_FixedMax
|
||||
#define SK_ScalarNegativeInfinity SK_FixedMin
|
||||
#define SK_ScalarMax SK_FixedMax
|
||||
#define SK_ScalarMin SK_FixedMin
|
||||
#define SK_ScalarNaN SK_FixedNaN
|
||||
#define SkScalarIsNaN(x) ((x) == SK_FixedNaN)
|
||||
#define SkScalarIsFinite(x) ((x) != SK_FixedNaN)
|
||||
|
||||
#define SkIntToScalar(n) SkIntToFixed(n)
|
||||
#define SkFixedToScalar(x) (x)
|
||||
#define SkScalarToFixed(x) (x)
|
||||
#define SkScalarToFloat(n) SkFixedToFloat(n)
|
||||
#define SkFloatToScalar(n) SkFloatToFixed(n)
|
||||
|
||||
#define SkScalarToDouble(n) SkFixedToDouble(n)
|
||||
#define SkDoubleToScalar(n) SkDoubleToFixed(n)
|
||||
#define SkScalarFraction(x) SkFixedFraction(x)
|
||||
|
||||
#define SkScalarFloorToScalar(x) SkFixedFloorToFixed(x)
|
||||
#define SkScalarCeilToScalar(x) SkFixedCeilToFixed(x)
|
||||
#define SkScalarRoundToScalar(x) SkFixedRoundToFixed(x)
|
||||
|
||||
#define SkScalarFloorToInt(x) SkFixedFloorToInt(x)
|
||||
#define SkScalarCeilToInt(x) SkFixedCeilToInt(x)
|
||||
#define SkScalarRoundToInt(x) SkFixedRoundToInt(x)
|
||||
#define SkScalarTruncToInt(x) (((x) < 0) ? SkScalarCeilToInt(x) : SkScalarFloorToInt(x))
|
||||
|
||||
#define SkScalarAbs(x) SkFixedAbs(x)
|
||||
#define SkScalarCopySign(x, y) SkCopySign32(x, y)
|
||||
#define SkScalarClampMax(x, max) SkClampMax(x, max)
|
||||
#define SkScalarPin(x, min, max) SkPin32(x, min, max)
|
||||
#define SkScalarSquare(x) SkFixedSquare(x)
|
||||
#define SkScalarMul(a, b) SkFixedMul(a, b)
|
||||
#define SkScalarMulAdd(a, b, c) SkFixedMulAdd(a, b, c)
|
||||
#define SkScalarMulRound(a, b) SkFixedMulCommon(a, b, SK_FixedHalf)
|
||||
#define SkScalarMulCeil(a, b) SkFixedMulCommon(a, b, SK_Fixed1 - 1)
|
||||
#define SkScalarMulFloor(a, b) SkFixedMulCommon(a, b, 0)
|
||||
#define SkScalarDiv(a, b) SkFixedDiv(a, b)
|
||||
#define SkScalarMod(a, b) SkFixedMod(a, b)
|
||||
#define SkScalarMulDiv(a, b, c) SkMulDiv(a, b, c)
|
||||
#define SkScalarInvert(x) SkFixedInvert(x)
|
||||
#define SkScalarFastInvert(x) SkFixedFastInvert(x)
|
||||
#define SkScalarSqrt(x) SkFixedSqrt(x)
|
||||
#define SkScalarAve(a, b) SkFixedAve(a, b)
|
||||
#define SkScalarMean(a, b) SkFixedMean(a, b)
|
||||
#define SkScalarHalf(a) ((a) >> 1)
|
||||
|
||||
#define SK_ScalarSqrt2 SK_FixedSqrt2
|
||||
#define SK_ScalarPI SK_FixedPI
|
||||
#define SK_ScalarTanPIOver8 SK_FixedTanPIOver8
|
||||
#define SK_ScalarRoot2Over2 SK_FixedRoot2Over2
|
||||
|
||||
#define SkDegreesToRadians(degrees) SkFractMul(degrees, SK_FractPIOver180)
|
||||
#define SkScalarSinCos(radians, cosPtr) SkFixedSinCos(radians, cosPtr)
|
||||
#define SkScalarSin(radians) SkFixedSin(radians)
|
||||
#define SkScalarCos(radians) SkFixedCos(radians)
|
||||
#define SkScalarTan(val) SkFixedTan(val)
|
||||
#define SkScalarASin(val) SkFixedASin(val)
|
||||
#define SkScalarACos(val) SkFixedACos(val)
|
||||
#define SkScalarATan2(y, x) SkFixedATan2(y,x)
|
||||
#define SkScalarExp(x) SkFixedExp(x)
|
||||
#define SkScalarLog(x) SkFixedLog(x)
|
||||
|
||||
#define SkMaxScalar(a, b) SkMax32(a, b)
|
||||
#define SkMinScalar(a, b) SkMin32(a, b)
|
||||
|
||||
static inline bool SkScalarIsInt(SkFixed x) {
|
||||
return 0 == (x & 0xffff);
|
||||
}
|
||||
#endif
|
||||
|
||||
// DEPRECATED : use ToInt or ToScalar variant
|
||||
#define SkScalarFloor(x) SkScalarFloorToInt(x)
|
||||
#define SkScalarCeil(x) SkScalarCeilToInt(x)
|
||||
#define SkScalarRound(x) SkScalarRoundToInt(x)
|
||||
|
||||
/**
|
||||
* Returns -1 || 0 || 1 depending on the sign of value:
|
||||
* -1 if x < 0
|
||||
* 0 if x == 0
|
||||
* 1 if x > 0
|
||||
*/
|
||||
static inline int SkScalarSignAsInt(SkScalar x) {
|
||||
return x < 0 ? -1 : (x > 0);
|
||||
}
|
||||
|
||||
// Scalar result version of above
|
||||
static inline SkScalar SkScalarSignAsScalar(SkScalar x) {
|
||||
return x < 0 ? -SK_Scalar1 : ((x > 0) ? SK_Scalar1 : 0);
|
||||
}
|
||||
|
||||
#define SK_ScalarNearlyZero (SK_Scalar1 / (1 << 12))
|
||||
|
||||
static inline bool SkScalarNearlyZero(SkScalar x,
|
||||
SkScalar tolerance = SK_ScalarNearlyZero) {
|
||||
SkASSERT(tolerance >= 0);
|
||||
return SkScalarAbs(x) <= tolerance;
|
||||
}
|
||||
|
||||
static inline bool SkScalarNearlyEqual(SkScalar x, SkScalar y,
|
||||
SkScalar tolerance = SK_ScalarNearlyZero) {
|
||||
SkASSERT(tolerance >= 0);
|
||||
return SkScalarAbs(x-y) <= tolerance;
|
||||
}
|
||||
|
||||
/** Linearly interpolate between A and B, based on t.
|
||||
If t is 0, return A
|
||||
If t is 1, return B
|
||||
else interpolate.
|
||||
t must be [0..SK_Scalar1]
|
||||
*/
|
||||
static inline SkScalar SkScalarInterp(SkScalar A, SkScalar B, SkScalar t) {
|
||||
SkASSERT(t >= 0 && t <= SK_Scalar1);
|
||||
return A + SkScalarMul(B - A, t);
|
||||
}
|
||||
|
||||
static inline SkScalar SkScalarLog2(SkScalar x) {
|
||||
static const SkScalar log2_conversion_factor = SkScalarDiv(1, SkScalarLog(2));
|
||||
|
||||
return SkScalarMul(SkScalarLog(x), log2_conversion_factor);
|
||||
}
|
||||
|
||||
/** Interpolate along the function described by (keys[length], values[length])
|
||||
for the passed searchKey. SearchKeys outside the range keys[0]-keys[Length]
|
||||
clamp to the min or max value. This function was inspired by a desire
|
||||
to change the multiplier for thickness in fakeBold; therefore it assumes
|
||||
the number of pairs (length) will be small, and a linear search is used.
|
||||
Repeated keys are allowed for discontinuous functions (so long as keys is
|
||||
monotonically increasing), and if key is the value of a repeated scalar in
|
||||
keys, the first one will be used. However, that may change if a binary
|
||||
search is used.
|
||||
*/
|
||||
SkScalar SkScalarInterpFunc(SkScalar searchKey, const SkScalar keys[],
|
||||
const SkScalar values[], int length);
|
||||
|
||||
/*
|
||||
* Helper to compare an array of scalars.
|
||||
*/
|
||||
static inline bool SkScalarsEqual(const SkScalar a[], const SkScalar b[], int n) {
|
||||
#ifdef SK_SCALAR_IS_FLOAT
|
||||
SkASSERT(n >= 0);
|
||||
for (int i = 0; i < n; ++i) {
|
||||
if (a[i] != b[i]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
#else
|
||||
return 0 == memcmp(a, b, n * sizeof(SkScalar));
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif
|
|
@ -1,397 +0,0 @@
|
|||
|
||||
/*
|
||||
* Copyright 2006 The Android Open Source Project
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef SkStream_DEFINED
|
||||
#define SkStream_DEFINED
|
||||
|
||||
#include "SkRefCnt.h"
|
||||
#include "SkScalar.h"
|
||||
|
||||
class SkData;
|
||||
|
||||
class SK_API SkStream : public SkRefCnt {
|
||||
public:
|
||||
/**
|
||||
* Attempts to open the specified file, and return a stream to it (using
|
||||
* mmap if available). On success, the caller must call unref() on the
|
||||
* returned object. On failure, returns NULL.
|
||||
*/
|
||||
static SkStream* NewFromFile(const char path[]);
|
||||
|
||||
SK_DECLARE_INST_COUNT(SkStream)
|
||||
|
||||
/** Called to rewind to the beginning of the stream. If this cannot be
|
||||
done, return false.
|
||||
*/
|
||||
virtual bool rewind() = 0;
|
||||
/** If this stream represents a file, this method returns the file's name.
|
||||
If it does not, it returns NULL (the default behavior).
|
||||
*/
|
||||
virtual const char* getFileName();
|
||||
/** Called to read or skip size number of bytes.
|
||||
If buffer is NULL and size > 0, skip that many bytes, returning how many were skipped.
|
||||
If buffer is NULL and size == 0, return the total length of the stream.
|
||||
If buffer != NULL, copy the requested number of bytes into buffer, returning how many were copied.
|
||||
@param buffer If buffer is NULL, ignore and just skip size bytes, otherwise copy size bytes into buffer
|
||||
@param size The number of bytes to skip or copy
|
||||
@return bytes read on success
|
||||
*/
|
||||
virtual size_t read(void* buffer, size_t size) = 0;
|
||||
|
||||
/** Return the total length of the stream.
|
||||
*/
|
||||
size_t getLength() { return this->read(NULL, 0); }
|
||||
|
||||
/** Skip the specified number of bytes, returning the actual number
|
||||
of bytes that could be skipped.
|
||||
*/
|
||||
size_t skip(size_t bytes);
|
||||
|
||||
/** If the stream is backed by RAM, this method returns the starting
|
||||
address for the data. If not (i.e. it is backed by a file or other
|
||||
structure), this method returns NULL.
|
||||
The default implementation returns NULL.
|
||||
*/
|
||||
virtual const void* getMemoryBase();
|
||||
|
||||
int8_t readS8();
|
||||
int16_t readS16();
|
||||
int32_t readS32();
|
||||
|
||||
uint8_t readU8() { return (uint8_t)this->readS8(); }
|
||||
uint16_t readU16() { return (uint16_t)this->readS16(); }
|
||||
uint32_t readU32() { return (uint32_t)this->readS32(); }
|
||||
|
||||
bool readBool() { return this->readU8() != 0; }
|
||||
SkScalar readScalar();
|
||||
size_t readPackedUInt();
|
||||
|
||||
/**
|
||||
* Reconstitute an SkData object that was written to the stream
|
||||
* using SkWStream::writeData().
|
||||
*/
|
||||
SkData* readData();
|
||||
|
||||
private:
|
||||
typedef SkRefCnt INHERITED;
|
||||
};
|
||||
|
||||
class SK_API SkWStream : SkNoncopyable {
|
||||
public:
|
||||
SK_DECLARE_INST_COUNT_ROOT(SkWStream)
|
||||
|
||||
virtual ~SkWStream();
|
||||
|
||||
/** Called to write bytes to a SkWStream. Returns true on success
|
||||
@param buffer the address of at least size bytes to be written to the stream
|
||||
@param size The number of bytes in buffer to write to the stream
|
||||
@return true on success
|
||||
*/
|
||||
virtual bool write(const void* buffer, size_t size) = 0;
|
||||
virtual void newline();
|
||||
virtual void flush();
|
||||
|
||||
// helpers
|
||||
|
||||
bool write8(U8CPU);
|
||||
bool write16(U16CPU);
|
||||
bool write32(uint32_t);
|
||||
|
||||
bool writeText(const char text[]);
|
||||
bool writeDecAsText(int32_t);
|
||||
bool writeBigDecAsText(int64_t, int minDigits = 0);
|
||||
bool writeHexAsText(uint32_t, int minDigits = 0);
|
||||
bool writeScalarAsText(SkScalar);
|
||||
|
||||
bool writeBool(bool v) { return this->write8(v); }
|
||||
bool writeScalar(SkScalar);
|
||||
bool writePackedUInt(size_t);
|
||||
|
||||
bool writeStream(SkStream* input, size_t length);
|
||||
|
||||
/**
|
||||
* Append an SkData object to the stream, such that it can be read
|
||||
* out of the stream using SkStream::readData().
|
||||
*
|
||||
* Note that the encoding method used to write the SkData object
|
||||
* to the stream may change over time. This method DOES NOT
|
||||
* just write the raw content of the SkData object to the stream.
|
||||
*/
|
||||
bool writeData(const SkData*);
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "SkString.h"
|
||||
|
||||
struct SkFILE;
|
||||
|
||||
/** A stream that reads from a FILE*, which is opened in the constructor and
|
||||
closed in the destructor
|
||||
*/
|
||||
class SK_API SkFILEStream : public SkStream {
|
||||
public:
|
||||
SK_DECLARE_INST_COUNT(SkFILEStream)
|
||||
|
||||
/** Initialize the stream by calling fopen on the specified path. Will be
|
||||
closed in the destructor.
|
||||
*/
|
||||
explicit SkFILEStream(const char path[] = NULL);
|
||||
virtual ~SkFILEStream();
|
||||
|
||||
/** Returns true if the current path could be opened.
|
||||
*/
|
||||
bool isValid() const { return fFILE != NULL; }
|
||||
/** Close the current file, and open a new file with the specified
|
||||
path. If path is NULL, just close the current file.
|
||||
*/
|
||||
void setPath(const char path[]);
|
||||
|
||||
virtual bool rewind() SK_OVERRIDE;
|
||||
virtual size_t read(void* buffer, size_t size) SK_OVERRIDE;
|
||||
virtual const char* getFileName() SK_OVERRIDE;
|
||||
|
||||
private:
|
||||
SkFILE* fFILE;
|
||||
SkString fName;
|
||||
|
||||
typedef SkStream INHERITED;
|
||||
};
|
||||
|
||||
/** A stream that reads from a file descriptor
|
||||
*/
|
||||
class SK_API SkFDStream : public SkStream {
|
||||
public:
|
||||
SK_DECLARE_INST_COUNT(SkFDStream)
|
||||
|
||||
/** Initialize the stream with a dup() of the specified file descriptor.
|
||||
If closeWhenDone is true, then the descriptor will be closed in the
|
||||
destructor.
|
||||
*/
|
||||
SkFDStream(int fileDesc, bool closeWhenDone);
|
||||
virtual ~SkFDStream();
|
||||
|
||||
/** Returns true if the current path could be opened.
|
||||
*/
|
||||
bool isValid() const { return fFD >= 0; }
|
||||
|
||||
virtual bool rewind() SK_OVERRIDE;
|
||||
virtual size_t read(void* buffer, size_t size) SK_OVERRIDE;
|
||||
virtual const char* getFileName() SK_OVERRIDE { return NULL; }
|
||||
|
||||
private:
|
||||
int fFD;
|
||||
bool fCloseWhenDone;
|
||||
|
||||
typedef SkStream INHERITED;
|
||||
};
|
||||
|
||||
class SK_API SkMemoryStream : public SkStream {
|
||||
public:
|
||||
SK_DECLARE_INST_COUNT(SkMemoryStream)
|
||||
|
||||
SkMemoryStream();
|
||||
/** We allocate (and free) the memory. Write to it via getMemoryBase()
|
||||
*/
|
||||
SkMemoryStream(size_t length);
|
||||
/** if copyData is true, the stream makes a private copy of the data
|
||||
*/
|
||||
SkMemoryStream(const void* data, size_t length, bool copyData = false);
|
||||
|
||||
/**
|
||||
* Use the specified data as the memory for this stream. The stream will
|
||||
* call ref() on the data (assuming it is not null).
|
||||
*/
|
||||
SkMemoryStream(SkData*);
|
||||
|
||||
virtual ~SkMemoryStream();
|
||||
|
||||
/** Resets the stream to the specified data and length,
|
||||
just like the constructor.
|
||||
if copyData is true, the stream makes a private copy of the data
|
||||
*/
|
||||
virtual void setMemory(const void* data, size_t length,
|
||||
bool copyData = false);
|
||||
/** Replace any memory buffer with the specified buffer. The caller
|
||||
must have allocated data with sk_malloc or sk_realloc, since it
|
||||
will be freed with sk_free.
|
||||
*/
|
||||
void setMemoryOwned(const void* data, size_t length);
|
||||
|
||||
/**
|
||||
* Return the stream's data in a SkData. The caller must call unref() when
|
||||
* it is finished using the data.
|
||||
*/
|
||||
SkData* copyToData() const;
|
||||
|
||||
/**
|
||||
* Use the specified data as the memory for this stream. The stream will
|
||||
* call ref() on the data (assuming it is not null). The function returns
|
||||
* the data parameter as a convenience.
|
||||
*/
|
||||
SkData* setData(SkData*);
|
||||
|
||||
void skipToAlign4();
|
||||
virtual bool rewind() SK_OVERRIDE;
|
||||
virtual size_t read(void* buffer, size_t size) SK_OVERRIDE;
|
||||
virtual const void* getMemoryBase() SK_OVERRIDE;
|
||||
const void* getAtPos();
|
||||
size_t seek(size_t offset);
|
||||
size_t peek() const { return fOffset; }
|
||||
|
||||
private:
|
||||
SkData* fData;
|
||||
size_t fOffset;
|
||||
|
||||
typedef SkStream INHERITED;
|
||||
};
|
||||
|
||||
/** \class SkBufferStream
|
||||
This is a wrapper class that adds buffering to another stream.
|
||||
The caller can provide the buffer, or ask SkBufferStream to allocated/free
|
||||
it automatically.
|
||||
*/
|
||||
class SK_API SkBufferStream : public SkStream {
|
||||
public:
|
||||
SK_DECLARE_INST_COUNT(SkBufferStream)
|
||||
|
||||
/** Provide the stream to be buffered (proxy), and the size of the buffer that
|
||||
should be used. This will be allocated and freed automatically. If bufferSize is 0,
|
||||
a default buffer size will be used.
|
||||
The proxy stream is referenced, and will be unreferenced in when the
|
||||
bufferstream is destroyed.
|
||||
*/
|
||||
SkBufferStream(SkStream* proxy, size_t bufferSize = 0);
|
||||
/** Provide the stream to be buffered (proxy), and a buffer and size to be used.
|
||||
This buffer is owned by the caller, and must be at least bufferSize bytes big.
|
||||
Passing NULL for buffer will cause the buffer to be allocated/freed automatically.
|
||||
If buffer is not NULL, it is an error for bufferSize to be 0.
|
||||
The proxy stream is referenced, and will be unreferenced in when the
|
||||
bufferstream is destroyed.
|
||||
*/
|
||||
SkBufferStream(SkStream* proxy, void* buffer, size_t bufferSize);
|
||||
virtual ~SkBufferStream();
|
||||
|
||||
virtual bool rewind() SK_OVERRIDE;
|
||||
virtual const char* getFileName() SK_OVERRIDE;
|
||||
virtual size_t read(void* buffer, size_t size) SK_OVERRIDE;
|
||||
virtual const void* getMemoryBase() SK_OVERRIDE;
|
||||
|
||||
private:
|
||||
enum {
|
||||
kDefaultBufferSize = 128
|
||||
};
|
||||
// illegal
|
||||
SkBufferStream(const SkBufferStream&);
|
||||
SkBufferStream& operator=(const SkBufferStream&);
|
||||
|
||||
SkStream* fProxy;
|
||||
char* fBuffer;
|
||||
size_t fOrigBufferSize, fBufferSize, fBufferOffset;
|
||||
bool fWeOwnTheBuffer;
|
||||
|
||||
void init(void*, size_t);
|
||||
|
||||
typedef SkStream INHERITED;
|
||||
};
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class SK_API SkFILEWStream : public SkWStream {
|
||||
public:
|
||||
SK_DECLARE_INST_COUNT(SkFILEWStream)
|
||||
|
||||
SkFILEWStream(const char path[]);
|
||||
virtual ~SkFILEWStream();
|
||||
|
||||
/** Returns true if the current path could be opened.
|
||||
*/
|
||||
bool isValid() const { return fFILE != NULL; }
|
||||
|
||||
virtual bool write(const void* buffer, size_t size) SK_OVERRIDE;
|
||||
virtual void flush() SK_OVERRIDE;
|
||||
|
||||
private:
|
||||
SkFILE* fFILE;
|
||||
|
||||
typedef SkWStream INHERITED;
|
||||
};
|
||||
|
||||
class SkMemoryWStream : public SkWStream {
|
||||
public:
|
||||
SK_DECLARE_INST_COUNT(SkMemoryWStream)
|
||||
|
||||
SkMemoryWStream(void* buffer, size_t size);
|
||||
virtual bool write(const void* buffer, size_t size) SK_OVERRIDE;
|
||||
size_t bytesWritten() const { return fBytesWritten; }
|
||||
|
||||
private:
|
||||
char* fBuffer;
|
||||
size_t fMaxLength;
|
||||
size_t fBytesWritten;
|
||||
|
||||
typedef SkWStream INHERITED;
|
||||
};
|
||||
|
||||
class SK_API SkDynamicMemoryWStream : public SkWStream {
|
||||
public:
|
||||
SK_DECLARE_INST_COUNT(SkDynamicMemoryWStream)
|
||||
|
||||
SkDynamicMemoryWStream();
|
||||
virtual ~SkDynamicMemoryWStream();
|
||||
|
||||
virtual bool write(const void* buffer, size_t size) SK_OVERRIDE;
|
||||
// random access write
|
||||
// modifies stream and returns true if offset + size is less than or equal to getOffset()
|
||||
bool write(const void* buffer, size_t offset, size_t size);
|
||||
bool read(void* buffer, size_t offset, size_t size);
|
||||
size_t getOffset() const { return fBytesWritten; }
|
||||
size_t bytesWritten() const { return fBytesWritten; }
|
||||
|
||||
// copy what has been written to the stream into dst
|
||||
void copyTo(void* dst) const;
|
||||
|
||||
/**
|
||||
* Return a copy of the data written so far. This call is responsible for
|
||||
* calling unref() when they are finished with the data.
|
||||
*/
|
||||
SkData* copyToData() const;
|
||||
|
||||
// reset the stream to its original state
|
||||
void reset();
|
||||
void padToAlign4();
|
||||
private:
|
||||
struct Block;
|
||||
Block* fHead;
|
||||
Block* fTail;
|
||||
size_t fBytesWritten;
|
||||
mutable SkData* fCopy; // is invalidated if we write after it is created
|
||||
|
||||
void invalidateCopy();
|
||||
|
||||
typedef SkWStream INHERITED;
|
||||
};
|
||||
|
||||
|
||||
class SK_API SkDebugWStream : public SkWStream {
|
||||
public:
|
||||
SK_DECLARE_INST_COUNT(SkDebugWStream)
|
||||
|
||||
// overrides
|
||||
virtual bool write(const void* buffer, size_t size) SK_OVERRIDE;
|
||||
virtual void newline() SK_OVERRIDE;
|
||||
|
||||
private:
|
||||
typedef SkWStream INHERITED;
|
||||
};
|
||||
|
||||
// for now
|
||||
typedef SkFILEStream SkURLStream;
|
||||
|
||||
#endif
|
|
@ -1,76 +0,0 @@
|
|||
|
||||
/*
|
||||
* Copyright 2011 Google Inc.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef SkTScopedPtr_DEFINED
|
||||
#define SkTScopedPtr_DEFINED
|
||||
|
||||
#include "SkTypes.h"
|
||||
|
||||
/** \class SkTScopedPtr
|
||||
A SkTScopedPtr<T> is like a T*, except that the destructor of SkTScopedPtr<T>
|
||||
automatically deletes the pointer it holds (if any). That is, SkTScopedPtr<T>
|
||||
owns the T object that it points to. Like a T*, a SkTScopedPtr<T> may hold
|
||||
either NULL or a pointer to a T object. Also like T*, SkTScopedPtr<T> is
|
||||
thread-compatible, and once you dereference it, you get the threadsafety
|
||||
guarantees of T.
|
||||
|
||||
The size of a SkTScopedPtr is small: sizeof(SkTScopedPtr<T>) == sizeof(T*)
|
||||
*/
|
||||
template <typename T> class SkTScopedPtr : SkNoncopyable {
|
||||
public:
|
||||
explicit SkTScopedPtr(T* o = NULL) : fObj(o) {}
|
||||
~SkTScopedPtr() {
|
||||
enum { kTypeMustBeComplete = sizeof(T) };
|
||||
delete fObj;
|
||||
}
|
||||
|
||||
/** Delete the current object, if any. Then take ownership of the
|
||||
passed object.
|
||||
*/
|
||||
void reset(T* o = NULL) {
|
||||
if (o != fObj) {
|
||||
enum { kTypeMustBeComplete = sizeof(T) };
|
||||
delete fObj;
|
||||
fObj = o;
|
||||
}
|
||||
}
|
||||
|
||||
/** Without deleting the current object, return it and forget about it.
|
||||
Similar to calling get() and reset(), but the object is not deleted.
|
||||
*/
|
||||
T* release() {
|
||||
T* retVal = fObj;
|
||||
fObj = NULL;
|
||||
return retVal;
|
||||
}
|
||||
|
||||
T& operator*() const {
|
||||
SkASSERT(fObj != NULL);
|
||||
return *fObj;
|
||||
}
|
||||
T* operator->() const {
|
||||
SkASSERT(fObj != NULL);
|
||||
return fObj;
|
||||
}
|
||||
T* get() const { return fObj; }
|
||||
|
||||
bool operator==(T* o) const { return fObj == o; }
|
||||
bool operator!=(T* o) const { return fObj != o; }
|
||||
|
||||
private:
|
||||
T* fObj;
|
||||
|
||||
// Forbid comparison of SkTScopedPtr types. If T2 != T, it doesn't make
|
||||
// sense, and if T2 == T, it still doesn't make sense because the same
|
||||
// object can't be owned by two different scoped_ptrs.
|
||||
template <class T2> bool operator==(SkTScopedPtr<T2> const& o2) const;
|
||||
template <class T2> bool operator!=(SkTScopedPtr<T2> const& o2) const;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -1,239 +0,0 @@
|
|||
|
||||
/*
|
||||
* Copyright 2006 The Android Open Source Project
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef SkTSearch_DEFINED
|
||||
#define SkTSearch_DEFINED
|
||||
|
||||
#include "SkTypes.h"
|
||||
|
||||
/**
|
||||
* All of the SkTSearch variants want to return the index (0...N-1) of the
|
||||
* found element, or the bit-not of where to insert the element.
|
||||
*
|
||||
* At a simple level, if the return value is negative, it was not found.
|
||||
*
|
||||
* For clients that want to insert the new element if it was not found, use
|
||||
* the following logic:
|
||||
*
|
||||
* int index = SkTSearch(...);
|
||||
* if (index >= 0) {
|
||||
* // found at index
|
||||
* } else {
|
||||
* index = ~index; // now we are positive
|
||||
* // insert at index
|
||||
* }
|
||||
*/
|
||||
|
||||
template <typename T>
|
||||
int SkTSearch(const T* base, int count, const T& target, size_t elemSize)
|
||||
{
|
||||
SkASSERT(count >= 0);
|
||||
if (count <= 0)
|
||||
return ~0;
|
||||
|
||||
SkASSERT(base != NULL); // base may be NULL if count is zero
|
||||
|
||||
int lo = 0;
|
||||
int hi = count - 1;
|
||||
|
||||
while (lo < hi)
|
||||
{
|
||||
int mid = (hi + lo) >> 1;
|
||||
const T* elem = (const T*)((const char*)base + mid * elemSize);
|
||||
|
||||
if (*elem < target)
|
||||
lo = mid + 1;
|
||||
else
|
||||
hi = mid;
|
||||
}
|
||||
|
||||
const T* elem = (const T*)((const char*)base + hi * elemSize);
|
||||
if (*elem != target)
|
||||
{
|
||||
if (*elem < target)
|
||||
hi += 1;
|
||||
hi = ~hi;
|
||||
}
|
||||
return hi;
|
||||
}
|
||||
|
||||
template <typename T, int (COMPARE)(const T*, const T*)>
|
||||
int SkTSearch(const T* base, int count, const T& target, size_t elemSize)
|
||||
{
|
||||
SkASSERT(count >= 0);
|
||||
if (count <= 0) {
|
||||
return ~0;
|
||||
}
|
||||
|
||||
SkASSERT(base != NULL); // base may be NULL if count is zero
|
||||
|
||||
int lo = 0;
|
||||
int hi = count - 1;
|
||||
|
||||
while (lo < hi) {
|
||||
int mid = (hi + lo) >> 1;
|
||||
const T* elem = (const T*)((const char*)base + mid * elemSize);
|
||||
|
||||
if (COMPARE(elem, &target) < 0)
|
||||
lo = mid + 1;
|
||||
else
|
||||
hi = mid;
|
||||
}
|
||||
|
||||
const T* elem = (const T*)((const char*)base + hi * elemSize);
|
||||
int pred = COMPARE(elem, &target);
|
||||
if (pred != 0) {
|
||||
if (pred < 0)
|
||||
hi += 1;
|
||||
hi = ~hi;
|
||||
}
|
||||
return hi;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
int SkTSearch(const T* base, int count, const T& target, size_t elemSize,
|
||||
int (*compare)(const T*, const T*))
|
||||
{
|
||||
SkASSERT(count >= 0);
|
||||
if (count <= 0) {
|
||||
return ~0;
|
||||
}
|
||||
|
||||
SkASSERT(base != NULL); // base may be NULL if count is zero
|
||||
|
||||
int lo = 0;
|
||||
int hi = count - 1;
|
||||
|
||||
while (lo < hi) {
|
||||
int mid = (hi + lo) >> 1;
|
||||
const T* elem = (const T*)((const char*)base + mid * elemSize);
|
||||
|
||||
if ((*compare)(elem, &target) < 0)
|
||||
lo = mid + 1;
|
||||
else
|
||||
hi = mid;
|
||||
}
|
||||
|
||||
const T* elem = (const T*)((const char*)base + hi * elemSize);
|
||||
int pred = (*compare)(elem, &target);
|
||||
if (pred != 0) {
|
||||
if (pred < 0)
|
||||
hi += 1;
|
||||
hi = ~hi;
|
||||
}
|
||||
return hi;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
int SkTSearch(const T** base, int count, const T* target, size_t elemSize,
|
||||
int (*compare)(const T*, const T*))
|
||||
{
|
||||
SkASSERT(count >= 0);
|
||||
if (count <= 0)
|
||||
return ~0;
|
||||
|
||||
SkASSERT(base != NULL); // base may be NULL if count is zero
|
||||
|
||||
int lo = 0;
|
||||
int hi = count - 1;
|
||||
|
||||
while (lo < hi)
|
||||
{
|
||||
int mid = (hi + lo) >> 1;
|
||||
const T* elem = *(const T**)((const char*)base + mid * elemSize);
|
||||
|
||||
if ((*compare)(elem, target) < 0)
|
||||
lo = mid + 1;
|
||||
else
|
||||
hi = mid;
|
||||
}
|
||||
|
||||
const T* elem = *(const T**)((const char*)base + hi * elemSize);
|
||||
int pred = (*compare)(elem, target);
|
||||
if (pred != 0)
|
||||
{
|
||||
if (pred < 0)
|
||||
hi += 1;
|
||||
hi = ~hi;
|
||||
}
|
||||
return hi;
|
||||
}
|
||||
|
||||
template <typename T, int (COMPARE)(const T*, const T*)>
|
||||
int SkTSearch(const T** base, int count, const T* target, size_t elemSize)
|
||||
{
|
||||
SkASSERT(count >= 0);
|
||||
if (count <= 0)
|
||||
return ~0;
|
||||
|
||||
SkASSERT(base != NULL); // base may be NULL if count is zero
|
||||
|
||||
int lo = 0;
|
||||
int hi = count - 1;
|
||||
|
||||
while (lo < hi)
|
||||
{
|
||||
int mid = (hi + lo) >> 1;
|
||||
const T* elem = *(const T**)((const char*)base + mid * elemSize);
|
||||
|
||||
if (COMPARE(elem, target) < 0)
|
||||
lo = mid + 1;
|
||||
else
|
||||
hi = mid;
|
||||
}
|
||||
|
||||
const T* elem = *(const T**)((const char*)base + hi * elemSize);
|
||||
int pred = COMPARE(elem, target);
|
||||
if (pred != 0)
|
||||
{
|
||||
if (pred < 0)
|
||||
hi += 1;
|
||||
hi = ~hi;
|
||||
}
|
||||
return hi;
|
||||
}
|
||||
int SkStrSearch(const char*const* base, int count, const char target[],
|
||||
size_t target_len, size_t elemSize);
|
||||
int SkStrSearch(const char*const* base, int count, const char target[],
|
||||
size_t elemSize);
|
||||
|
||||
/** Like SkStrSearch, but treats target as if it were all lower-case. Assumes that
|
||||
base points to a table of lower-case strings.
|
||||
*/
|
||||
int SkStrLCSearch(const char*const* base, int count, const char target[],
|
||||
size_t target_len, size_t elemSize);
|
||||
int SkStrLCSearch(const char*const* base, int count, const char target[],
|
||||
size_t elemSize);
|
||||
|
||||
/** Helper class to convert a string to lower-case, but only modifying the ascii
|
||||
characters. This makes the routine very fast and never changes the string
|
||||
length, but it is not suitable for linguistic purposes. Normally this is
|
||||
used for buiding and searching string tables.
|
||||
*/
|
||||
class SkAutoAsciiToLC {
|
||||
public:
|
||||
SkAutoAsciiToLC(const char str[], size_t len = (size_t)-1);
|
||||
~SkAutoAsciiToLC();
|
||||
|
||||
const char* lc() const { return fLC; }
|
||||
size_t length() const { return fLength; }
|
||||
|
||||
private:
|
||||
char* fLC; // points to either the heap or fStorage
|
||||
size_t fLength;
|
||||
enum {
|
||||
STORAGE = 64
|
||||
};
|
||||
char fStorage[STORAGE+1];
|
||||
};
|
||||
|
||||
// Helper when calling qsort with a compare proc that has typed its arguments
|
||||
#define SkCastForQSort(compare) reinterpret_cast<int (*)(const void*, const void*)>(compare)
|
||||
|
||||
#endif
|
|
@ -1,68 +0,0 @@
|
|||
|
||||
/*
|
||||
* Copyright 2006 The Android Open Source Project
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef SkThread_DEFINED
|
||||
#define SkThread_DEFINED
|
||||
|
||||
#include "SkTypes.h"
|
||||
#include "SkThread_platform.h"
|
||||
|
||||
/****** SkThread_platform needs to define the following...
|
||||
|
||||
int32_t sk_atomic_inc(int32_t*);
|
||||
int32_t sk_atomic_add(int32_t*, int32_t);
|
||||
int32_t sk_atomic_dec(int32_t*);
|
||||
int32_t sk_atomic_conditional_inc(int32_t*);
|
||||
|
||||
class SkMutex {
|
||||
public:
|
||||
SkMutex();
|
||||
~SkMutex();
|
||||
|
||||
void acquire();
|
||||
void release();
|
||||
};
|
||||
|
||||
****************/
|
||||
|
||||
class SkAutoMutexAcquire : SkNoncopyable {
|
||||
public:
|
||||
explicit SkAutoMutexAcquire(SkBaseMutex& mutex) : fMutex(&mutex) {
|
||||
SkASSERT(fMutex != NULL);
|
||||
mutex.acquire();
|
||||
}
|
||||
|
||||
SkAutoMutexAcquire(SkBaseMutex* mutex) : fMutex(mutex) {
|
||||
if (mutex) {
|
||||
mutex->acquire();
|
||||
}
|
||||
}
|
||||
|
||||
/** If the mutex has not been release, release it now.
|
||||
*/
|
||||
~SkAutoMutexAcquire() {
|
||||
if (fMutex) {
|
||||
fMutex->release();
|
||||
}
|
||||
}
|
||||
|
||||
/** If the mutex has not been release, release it now.
|
||||
*/
|
||||
void release() {
|
||||
if (fMutex) {
|
||||
fMutex->release();
|
||||
fMutex = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
SkBaseMutex* fMutex;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -1,294 +0,0 @@
|
|||
|
||||
/*
|
||||
* Copyright 2008 The Android Open Source Project
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef SkWriter32_DEFINED
|
||||
#define SkWriter32_DEFINED
|
||||
|
||||
#include "SkTypes.h"
|
||||
|
||||
#include "SkScalar.h"
|
||||
#include "SkPath.h"
|
||||
#include "SkPoint.h"
|
||||
#include "SkRect.h"
|
||||
#include "SkRRect.h"
|
||||
#include "SkMatrix.h"
|
||||
#include "SkRegion.h"
|
||||
|
||||
class SkStream;
|
||||
class SkWStream;
|
||||
|
||||
class SkWriter32 : SkNoncopyable {
|
||||
struct BlockHeader;
|
||||
public:
|
||||
/**
|
||||
* The caller can specify an initial block of storage, which the caller manages.
|
||||
* SkWriter32 will not attempt to free this in its destructor. It is up to the
|
||||
* implementation to decide if, and how much, of the storage to utilize, and it
|
||||
* is possible that it may be ignored entirely.
|
||||
*/
|
||||
SkWriter32(size_t minSize, void* initialStorage, size_t storageSize);
|
||||
|
||||
SkWriter32(size_t minSize)
|
||||
: fHead(NULL)
|
||||
, fTail(NULL)
|
||||
, fMinSize(minSize)
|
||||
, fSize(0)
|
||||
, fWrittenBeforeLastBlock(0)
|
||||
{}
|
||||
|
||||
~SkWriter32();
|
||||
|
||||
// return the current offset (will always be a multiple of 4)
|
||||
uint32_t bytesWritten() const { return fSize; }
|
||||
// DEPRECATED: use byetsWritten instead
|
||||
uint32_t size() const { return this->bytesWritten(); }
|
||||
|
||||
void reset();
|
||||
|
||||
// size MUST be multiple of 4
|
||||
uint32_t* reserve(size_t size) {
|
||||
SkASSERT(SkAlign4(size) == size);
|
||||
|
||||
Block* block = fTail;
|
||||
if (NULL == block || block->available() < size) {
|
||||
block = this->doReserve(size);
|
||||
}
|
||||
fSize += size;
|
||||
return block->alloc(size);
|
||||
}
|
||||
|
||||
void reset(void* storage, size_t size);
|
||||
|
||||
bool writeBool(bool value) {
|
||||
this->writeInt(value);
|
||||
return value;
|
||||
}
|
||||
|
||||
void writeInt(int32_t value) {
|
||||
*(int32_t*)this->reserve(sizeof(value)) = value;
|
||||
}
|
||||
|
||||
void write8(int32_t value) {
|
||||
*(int32_t*)this->reserve(sizeof(value)) = value & 0xFF;
|
||||
}
|
||||
|
||||
void write16(int32_t value) {
|
||||
*(int32_t*)this->reserve(sizeof(value)) = value & 0xFFFF;
|
||||
}
|
||||
|
||||
void write32(int32_t value) {
|
||||
*(int32_t*)this->reserve(sizeof(value)) = value;
|
||||
}
|
||||
|
||||
void writePtr(void* ptr) {
|
||||
// Since we "know" that we're always 4-byte aligned, we can tell the
|
||||
// compiler that here, by assigning to an int32 ptr.
|
||||
int32_t* addr = (int32_t*)this->reserve(sizeof(void*));
|
||||
if (4 == sizeof(void*)) {
|
||||
*(void**)addr = ptr;
|
||||
} else {
|
||||
memcpy(addr, &ptr, sizeof(void*));
|
||||
}
|
||||
}
|
||||
|
||||
void writeScalar(SkScalar value) {
|
||||
*(SkScalar*)this->reserve(sizeof(value)) = value;
|
||||
}
|
||||
|
||||
void writePoint(const SkPoint& pt) {
|
||||
*(SkPoint*)this->reserve(sizeof(pt)) = pt;
|
||||
}
|
||||
|
||||
void writeRect(const SkRect& rect) {
|
||||
*(SkRect*)this->reserve(sizeof(rect)) = rect;
|
||||
}
|
||||
|
||||
void writeRRect(const SkRRect& rrect) {
|
||||
rrect.writeToMemory(this->reserve(SkRRect::kSizeInMemory));
|
||||
}
|
||||
|
||||
void writePath(const SkPath& path) {
|
||||
size_t size = path.writeToMemory(NULL);
|
||||
SkASSERT(SkAlign4(size) == size);
|
||||
path.writeToMemory(this->reserve(size));
|
||||
}
|
||||
|
||||
void writeMatrix(const SkMatrix& matrix) {
|
||||
size_t size = matrix.writeToMemory(NULL);
|
||||
SkASSERT(SkAlign4(size) == size);
|
||||
matrix.writeToMemory(this->reserve(size));
|
||||
}
|
||||
|
||||
void writeRegion(const SkRegion& rgn) {
|
||||
size_t size = rgn.writeToMemory(NULL);
|
||||
SkASSERT(SkAlign4(size) == size);
|
||||
rgn.writeToMemory(this->reserve(size));
|
||||
}
|
||||
|
||||
// write count bytes (must be a multiple of 4)
|
||||
void writeMul4(const void* values, size_t size) {
|
||||
this->write(values, size);
|
||||
}
|
||||
|
||||
/**
|
||||
* Write size bytes from values. size must be a multiple of 4, though
|
||||
* values need not be 4-byte aligned.
|
||||
*/
|
||||
void write(const void* values, size_t size) {
|
||||
SkASSERT(SkAlign4(size) == size);
|
||||
// if we could query how much is avail in the current block, we might
|
||||
// copy that much, and then alloc the rest. That would reduce the waste
|
||||
// in the current block
|
||||
memcpy(this->reserve(size), values, size);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reserve size bytes. Does not need to be 4 byte aligned. The remaining space (if any) will be
|
||||
* filled in with zeroes.
|
||||
*/
|
||||
uint32_t* reservePad(size_t size);
|
||||
|
||||
/**
|
||||
* Write size bytes from src, and pad to 4 byte alignment with zeroes.
|
||||
*/
|
||||
void writePad(const void* src, size_t size);
|
||||
|
||||
/**
|
||||
* Writes a string to the writer, which can be retrieved with
|
||||
* SkReader32::readString().
|
||||
* The length can be specified, or if -1 is passed, it will be computed by
|
||||
* calling strlen(). The length must be < 0xFFFF
|
||||
*/
|
||||
void writeString(const char* str, size_t len = (size_t)-1);
|
||||
|
||||
/**
|
||||
* Computes the size (aligned to multiple of 4) need to write the string
|
||||
* in a call to writeString(). If the length is not specified, it will be
|
||||
* computed by calling strlen().
|
||||
*/
|
||||
static size_t WriteStringSize(const char* str, size_t len = (size_t)-1);
|
||||
|
||||
// return the address of the 4byte int at the specified offset (which must
|
||||
// be a multiple of 4. This does not allocate any new space, so the returned
|
||||
// address is only valid for 1 int.
|
||||
uint32_t* peek32(size_t offset);
|
||||
|
||||
/**
|
||||
* Move the cursor back to offset bytes from the beginning.
|
||||
* This has the same restrictions as peek32: offset must be <= size() and
|
||||
* offset must be a multiple of 4.
|
||||
*/
|
||||
void rewindToOffset(size_t offset);
|
||||
|
||||
// copy into a single buffer (allocated by caller). Must be at least size()
|
||||
void flatten(void* dst) const;
|
||||
|
||||
// read from the stream, and write up to length bytes. Return the actual
|
||||
// number of bytes written.
|
||||
size_t readFromStream(SkStream*, size_t length);
|
||||
|
||||
bool writeToStream(SkWStream*);
|
||||
|
||||
private:
|
||||
struct Block {
|
||||
Block* fNext;
|
||||
char* fBasePtr;
|
||||
size_t fSizeOfBlock; // total space allocated (after this)
|
||||
size_t fAllocatedSoFar; // space used so far
|
||||
|
||||
size_t available() const { return fSizeOfBlock - fAllocatedSoFar; }
|
||||
char* base() { return fBasePtr; }
|
||||
const char* base() const { return fBasePtr; }
|
||||
|
||||
uint32_t* alloc(size_t size) {
|
||||
SkASSERT(SkAlign4(size) == size);
|
||||
SkASSERT(this->available() >= size);
|
||||
void* ptr = this->base() + fAllocatedSoFar;
|
||||
fAllocatedSoFar += size;
|
||||
SkASSERT(fAllocatedSoFar <= fSizeOfBlock);
|
||||
return (uint32_t*)ptr;
|
||||
}
|
||||
|
||||
uint32_t* peek32(size_t offset) {
|
||||
SkASSERT(offset <= fAllocatedSoFar + 4);
|
||||
void* ptr = this->base() + offset;
|
||||
return (uint32_t*)ptr;
|
||||
}
|
||||
|
||||
void rewind() {
|
||||
fNext = NULL;
|
||||
fAllocatedSoFar = 0;
|
||||
// keep fSizeOfBlock as is
|
||||
}
|
||||
|
||||
static Block* Create(size_t size) {
|
||||
SkASSERT(SkIsAlign4(size));
|
||||
Block* block = (Block*)sk_malloc_throw(sizeof(Block) + size);
|
||||
block->fNext = NULL;
|
||||
block->fBasePtr = (char*)(block + 1);
|
||||
block->fSizeOfBlock = size;
|
||||
block->fAllocatedSoFar = 0;
|
||||
return block;
|
||||
}
|
||||
|
||||
Block* initFromStorage(void* storage, size_t size) {
|
||||
SkASSERT(SkIsAlign4((intptr_t)storage));
|
||||
SkASSERT(SkIsAlign4(size));
|
||||
Block* block = this;
|
||||
block->fNext = NULL;
|
||||
block->fBasePtr = (char*)storage;
|
||||
block->fSizeOfBlock = size;
|
||||
block->fAllocatedSoFar = 0;
|
||||
return block;
|
||||
}
|
||||
};
|
||||
|
||||
enum {
|
||||
MIN_BLOCKSIZE = sizeof(SkWriter32::Block) + sizeof(intptr_t)
|
||||
};
|
||||
|
||||
Block fExternalBlock;
|
||||
Block* fHead;
|
||||
Block* fTail;
|
||||
size_t fMinSize;
|
||||
uint32_t fSize;
|
||||
// sum of bytes written in all blocks *before* fTail
|
||||
uint32_t fWrittenBeforeLastBlock;
|
||||
|
||||
bool isHeadExternallyAllocated() const {
|
||||
return fHead == &fExternalBlock;
|
||||
}
|
||||
|
||||
Block* newBlock(size_t bytes);
|
||||
|
||||
// only call from reserve()
|
||||
Block* doReserve(size_t bytes);
|
||||
|
||||
SkDEBUGCODE(void validate() const;)
|
||||
};
|
||||
|
||||
/**
|
||||
* Helper class to allocated SIZE bytes as part of the writer, and to provide
|
||||
* that storage to the constructor as its initial storage buffer.
|
||||
*
|
||||
* This wrapper ensures proper alignment rules are met for the storage.
|
||||
*/
|
||||
template <size_t SIZE> class SkSWriter32 : public SkWriter32 {
|
||||
public:
|
||||
SkSWriter32(size_t minSize) : SkWriter32(minSize, fData.fStorage, SIZE) {}
|
||||
|
||||
private:
|
||||
union {
|
||||
void* fPtrAlignment;
|
||||
double fDoubleAlignment;
|
||||
char fStorage[SIZE];
|
||||
} fData;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -1,50 +0,0 @@
|
|||
/*
|
||||
* Copyright 2012 The Android Open Source Project
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#ifndef SkBlendImageFilter_DEFINED
|
||||
#define SkBlendImageFilter_DEFINED
|
||||
|
||||
#include "SkImageFilter.h"
|
||||
#include "SkBitmap.h"
|
||||
|
||||
class SK_API SkBlendImageFilter : public SkImageFilter {
|
||||
public:
|
||||
enum Mode {
|
||||
kNormal_Mode,
|
||||
kMultiply_Mode,
|
||||
kScreen_Mode,
|
||||
kDarken_Mode,
|
||||
kLighten_Mode,
|
||||
};
|
||||
SkBlendImageFilter(Mode mode, SkImageFilter* background, SkImageFilter* foreground = NULL);
|
||||
|
||||
~SkBlendImageFilter();
|
||||
|
||||
SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkBlendImageFilter)
|
||||
|
||||
virtual bool onFilterImage(Proxy* proxy,
|
||||
const SkBitmap& src,
|
||||
const SkMatrix& ctm,
|
||||
SkBitmap* dst,
|
||||
SkIPoint* offset) SK_OVERRIDE;
|
||||
#if SK_SUPPORT_GPU
|
||||
virtual bool canFilterImageGPU() const SK_OVERRIDE { return true; }
|
||||
virtual bool filterImageGPU(Proxy* proxy, const SkBitmap& src, SkBitmap* result) SK_OVERRIDE;
|
||||
#endif
|
||||
|
||||
protected:
|
||||
explicit SkBlendImageFilter(SkFlattenableReadBuffer& buffer);
|
||||
virtual void flatten(SkFlattenableWriteBuffer&) const SK_OVERRIDE;
|
||||
|
||||
private:
|
||||
Mode fMode;
|
||||
typedef SkImageFilter INHERITED;
|
||||
SkImageFilter* getBackgroundInput() { return getInput(0); }
|
||||
SkImageFilter* getForegroundInput() { return getInput(1); }
|
||||
};
|
||||
|
||||
#endif
|
|
@ -1,73 +0,0 @@
|
|||
/*
|
||||
* Copyright 2012 The Android Open Source Project
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef SkMorphologyImageFilter_DEFINED
|
||||
#define SkMorphologyImageFilter_DEFINED
|
||||
|
||||
#include "SkImageFilter.h"
|
||||
#include "SkSize.h"
|
||||
|
||||
class SK_API SkMorphologyImageFilter : public SkImageFilter {
|
||||
public:
|
||||
SkMorphologyImageFilter(int radiusX, int radiusY, SkImageFilter* input);
|
||||
|
||||
protected:
|
||||
SkMorphologyImageFilter(SkFlattenableReadBuffer& buffer);
|
||||
virtual void flatten(SkFlattenableWriteBuffer&) const SK_OVERRIDE;
|
||||
#if SK_SUPPORT_GPU
|
||||
virtual bool canFilterImageGPU() const SK_OVERRIDE { return true; }
|
||||
#endif
|
||||
|
||||
SkISize radius() const { return fRadius; }
|
||||
|
||||
private:
|
||||
SkISize fRadius;
|
||||
typedef SkImageFilter INHERITED;
|
||||
};
|
||||
|
||||
class SK_API SkDilateImageFilter : public SkMorphologyImageFilter {
|
||||
public:
|
||||
SkDilateImageFilter(int radiusX, int radiusY, SkImageFilter* input = NULL)
|
||||
: INHERITED(radiusX, radiusY, input) {}
|
||||
|
||||
virtual bool onFilterImage(Proxy*, const SkBitmap& src, const SkMatrix&,
|
||||
SkBitmap* result, SkIPoint* offset) SK_OVERRIDE;
|
||||
#if SK_SUPPORT_GPU
|
||||
virtual bool filterImageGPU(Proxy* proxy, const SkBitmap& src, SkBitmap* result) SK_OVERRIDE;
|
||||
#endif
|
||||
|
||||
SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkDilateImageFilter)
|
||||
|
||||
protected:
|
||||
SkDilateImageFilter(SkFlattenableReadBuffer& buffer) : INHERITED(buffer) {}
|
||||
|
||||
private:
|
||||
typedef SkMorphologyImageFilter INHERITED;
|
||||
};
|
||||
|
||||
class SK_API SkErodeImageFilter : public SkMorphologyImageFilter {
|
||||
public:
|
||||
SkErodeImageFilter(int radiusX, int radiusY, SkImageFilter* input = NULL)
|
||||
: INHERITED(radiusX, radiusY, input) {}
|
||||
|
||||
virtual bool onFilterImage(Proxy*, const SkBitmap& src, const SkMatrix&,
|
||||
SkBitmap* result, SkIPoint* offset) SK_OVERRIDE;
|
||||
#if SK_SUPPORT_GPU
|
||||
virtual bool filterImageGPU(Proxy* proxy, const SkBitmap& src, SkBitmap* result) SK_OVERRIDE;
|
||||
#endif
|
||||
|
||||
SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkErodeImageFilter)
|
||||
|
||||
protected:
|
||||
SkErodeImageFilter(SkFlattenableReadBuffer& buffer) : INHERITED(buffer) {}
|
||||
|
||||
private:
|
||||
typedef SkMorphologyImageFilter INHERITED;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -1,43 +0,0 @@
|
|||
/*
|
||||
* Copyright 2013 Google Inc.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#ifndef SkRectShaderImageFilter_DEFINED
|
||||
#define SkRectShaderImageFilter_DEFINED
|
||||
|
||||
#include "SkImageFilter.h"
|
||||
#include "SkRect.h"
|
||||
|
||||
class SkShader;
|
||||
|
||||
class SK_API SkRectShaderImageFilter : public SkImageFilter {
|
||||
public:
|
||||
/**
|
||||
* The SkShader object will have its refcnt increased as it becomes a member of the
|
||||
* SkRectShaderImageFilter object returned by this function. It cannot be NULL.
|
||||
* The region parameter is used to specify on which region the shader is applied.
|
||||
*/
|
||||
static SkRectShaderImageFilter* Create(SkShader* s, const SkRect& rect);
|
||||
virtual ~SkRectShaderImageFilter();
|
||||
|
||||
SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkRectShaderImageFilter)
|
||||
|
||||
protected:
|
||||
SkRectShaderImageFilter(SkFlattenableReadBuffer& buffer);
|
||||
virtual void flatten(SkFlattenableWriteBuffer&) const SK_OVERRIDE;
|
||||
|
||||
virtual bool onFilterImage(Proxy*, const SkBitmap& src, const SkMatrix&,
|
||||
SkBitmap* result, SkIPoint* loc) SK_OVERRIDE;
|
||||
|
||||
private:
|
||||
SkRectShaderImageFilter(SkShader* s, const SkRect& rect);
|
||||
SkShader* fShader;
|
||||
SkRect fRect;
|
||||
|
||||
typedef SkImageFilter INHERITED;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -1,47 +0,0 @@
|
|||
#ifndef _SkTestImageFilters_h
|
||||
#define _SkTestImageFilters_h
|
||||
|
||||
#include "SkImageFilter.h"
|
||||
#include "SkPoint.h"
|
||||
|
||||
class SK_API SkComposeImageFilter : public SkImageFilter {
|
||||
public:
|
||||
SkComposeImageFilter(SkImageFilter* outer, SkImageFilter* inner) : INHERITED(outer, inner) {}
|
||||
virtual ~SkComposeImageFilter();
|
||||
|
||||
SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkComposeImageFilter)
|
||||
|
||||
protected:
|
||||
SkComposeImageFilter(SkFlattenableReadBuffer& buffer);
|
||||
|
||||
virtual bool onFilterImage(Proxy*, const SkBitmap& src, const SkMatrix&,
|
||||
SkBitmap* result, SkIPoint* loc) SK_OVERRIDE;
|
||||
virtual bool onFilterBounds(const SkIRect&, const SkMatrix&, SkIRect*) SK_OVERRIDE;
|
||||
|
||||
private:
|
||||
typedef SkImageFilter INHERITED;
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Fun mode that scales down (only) and then scales back up to look pixelated
|
||||
class SK_API SkDownSampleImageFilter : public SkImageFilter {
|
||||
public:
|
||||
SkDownSampleImageFilter(SkScalar scale) : INHERITED(0), fScale(scale) {}
|
||||
|
||||
SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkDownSampleImageFilter)
|
||||
|
||||
protected:
|
||||
SkDownSampleImageFilter(SkFlattenableReadBuffer& buffer);
|
||||
virtual void flatten(SkFlattenableWriteBuffer&) const SK_OVERRIDE;
|
||||
|
||||
virtual bool onFilterImage(Proxy*, const SkBitmap& src, const SkMatrix&,
|
||||
SkBitmap* result, SkIPoint* loc) SK_OVERRIDE;
|
||||
|
||||
private:
|
||||
SkScalar fScale;
|
||||
|
||||
typedef SkImageFilter INHERITED;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -1,65 +0,0 @@
|
|||
/*
|
||||
* 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 GrAARectRenderer_DEFINED
|
||||
#define GrAARectRenderer_DEFINED
|
||||
|
||||
#include "GrRect.h"
|
||||
#include "GrRefCnt.h"
|
||||
|
||||
class GrGpu;
|
||||
class GrDrawTarget;
|
||||
class GrIndexBuffer;
|
||||
|
||||
/*
|
||||
* This class wraps helper functions that draw AA rects (filled & stroked)
|
||||
*/
|
||||
class GrAARectRenderer : public GrRefCnt {
|
||||
public:
|
||||
SK_DECLARE_INST_COUNT(GrAARectRenderer)
|
||||
|
||||
GrAARectRenderer()
|
||||
: fAAFillRectIndexBuffer(NULL)
|
||||
, fAAStrokeRectIndexBuffer(NULL) {
|
||||
}
|
||||
|
||||
void reset();
|
||||
|
||||
~GrAARectRenderer() {
|
||||
this->reset();
|
||||
}
|
||||
|
||||
// TODO: potentialy fuse the fill & stroke methods and differentiate
|
||||
// btween them by passing in strokeWidth (<0 means fill).
|
||||
|
||||
// TODO: Remove the useVertexCoverage boolean. Just use it all the time
|
||||
// since we now have a coverage vertex attribute
|
||||
void fillAARect(GrGpu* gpu,
|
||||
GrDrawTarget* target,
|
||||
const GrRect& devRect,
|
||||
bool useVertexCoverage);
|
||||
|
||||
void strokeAARect(GrGpu* gpu,
|
||||
GrDrawTarget* target,
|
||||
const GrRect& devRect,
|
||||
const GrVec& devStrokeSize,
|
||||
bool useVertexCoverage);
|
||||
|
||||
private:
|
||||
GrIndexBuffer* fAAFillRectIndexBuffer;
|
||||
GrIndexBuffer* fAAStrokeRectIndexBuffer;
|
||||
|
||||
GrIndexBuffer* aaFillRectIndexBuffer(GrGpu* gpu);
|
||||
|
||||
static int aaStrokeRectIndexCount();
|
||||
GrIndexBuffer* aaStrokeRectIndexBuffer(GrGpu* gpu);
|
||||
|
||||
typedef GrRefCnt INHERITED;
|
||||
};
|
||||
|
||||
#endif // GrAARectRenderer_DEFINED
|
|
@ -1,211 +0,0 @@
|
|||
|
||||
/*
|
||||
* Copyright 2010 Google Inc.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
#ifndef GrEffectStage_DEFINED
|
||||
#define GrEffectStage_DEFINED
|
||||
|
||||
#include "GrBackendEffectFactory.h"
|
||||
#include "GrEffect.h"
|
||||
#include "SkMatrix.h"
|
||||
#include "GrTypes.h"
|
||||
|
||||
#include "SkShader.h"
|
||||
|
||||
class GrEffectStage {
|
||||
public:
|
||||
GrEffectStage()
|
||||
: fEffectRef (NULL) {
|
||||
GR_DEBUGCODE(fSavedCoordChangeCnt = 0;)
|
||||
}
|
||||
|
||||
~GrEffectStage() {
|
||||
GrSafeUnref(fEffectRef);
|
||||
GrAssert(0 == fSavedCoordChangeCnt);
|
||||
}
|
||||
|
||||
bool operator ==(const GrEffectStage& other) const {
|
||||
// first handle cases where one or the other has no effect
|
||||
if (NULL == fEffectRef) {
|
||||
return NULL == other.fEffectRef;
|
||||
} else if (NULL == other.fEffectRef) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!(*this->getEffect())->isEqual(*other.getEffect())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return fCoordChangeMatrix == other.fCoordChangeMatrix;
|
||||
}
|
||||
|
||||
bool operator !=(const GrEffectStage& s) const { return !(*this == s); }
|
||||
|
||||
GrEffectStage& operator =(const GrEffectStage& other) {
|
||||
GrSafeAssign(fEffectRef, other.fEffectRef);
|
||||
if (NULL != fEffectRef) {
|
||||
fCoordChangeMatrix = other.fCoordChangeMatrix;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* This is called when the coordinate system in which the geometry is specified will change.
|
||||
*
|
||||
* @param matrix The transformation from the old coord system in which geometry is specified
|
||||
* to the new one from which it will actually be drawn.
|
||||
*/
|
||||
void localCoordChange(const SkMatrix& matrix) { fCoordChangeMatrix.preConcat(matrix); }
|
||||
|
||||
class SavedCoordChange {
|
||||
private:
|
||||
SkMatrix fCoordChangeMatrix;
|
||||
GR_DEBUGCODE(mutable SkAutoTUnref<const GrEffectRef> fEffectRef;)
|
||||
|
||||
friend class GrEffectStage;
|
||||
};
|
||||
|
||||
/**
|
||||
* This gets the current coordinate system change. It is the accumulation of
|
||||
* localCoordChange calls since the effect was installed. It is used when then caller
|
||||
* wants to temporarily change the source geometry coord system, draw something, and then
|
||||
* restore the previous coord system (e.g. temporarily draw in device coords).
|
||||
*/
|
||||
void saveCoordChange(SavedCoordChange* savedCoordChange) const {
|
||||
savedCoordChange->fCoordChangeMatrix = fCoordChangeMatrix;
|
||||
GrAssert(NULL == savedCoordChange->fEffectRef.get());
|
||||
GR_DEBUGCODE(GrSafeRef(fEffectRef);)
|
||||
GR_DEBUGCODE(savedCoordChange->fEffectRef.reset(fEffectRef);)
|
||||
GR_DEBUGCODE(++fSavedCoordChangeCnt);
|
||||
}
|
||||
|
||||
/**
|
||||
* This balances the saveCoordChange call.
|
||||
*/
|
||||
void restoreCoordChange(const SavedCoordChange& savedCoordChange) {
|
||||
fCoordChangeMatrix = savedCoordChange.fCoordChangeMatrix;
|
||||
GrAssert(savedCoordChange.fEffectRef.get() == fEffectRef);
|
||||
GR_DEBUGCODE(--fSavedCoordChangeCnt);
|
||||
GR_DEBUGCODE(savedCoordChange.fEffectRef.reset(NULL);)
|
||||
}
|
||||
|
||||
/**
|
||||
* Used when storing a deferred GrDrawState. The DeferredStage allows resources owned by its
|
||||
* GrEffect to be recycled through the cache.
|
||||
*/
|
||||
class DeferredStage {
|
||||
public:
|
||||
DeferredStage() : fEffect(NULL) {
|
||||
SkDEBUGCODE(fInitialized = false;)
|
||||
}
|
||||
|
||||
~DeferredStage() {
|
||||
if (NULL != fEffect) {
|
||||
fEffect->decDeferredRefCounts();
|
||||
}
|
||||
}
|
||||
|
||||
void saveFrom(const GrEffectStage& stage) {
|
||||
GrAssert(!fInitialized);
|
||||
if (NULL != stage.fEffectRef) {
|
||||
stage.fEffectRef->get()->incDeferredRefCounts();
|
||||
fEffect = stage.fEffectRef->get();
|
||||
fCoordChangeMatrix = stage.fCoordChangeMatrix;
|
||||
fVertexAttribIndices[0] = stage.fVertexAttribIndices[0];
|
||||
fVertexAttribIndices[1] = stage.fVertexAttribIndices[1];
|
||||
}
|
||||
SkDEBUGCODE(fInitialized = true;)
|
||||
}
|
||||
|
||||
void restoreTo(GrEffectStage* stage) {
|
||||
GrAssert(fInitialized);
|
||||
const GrEffectRef* oldEffectRef = stage->fEffectRef;
|
||||
if (NULL != fEffect) {
|
||||
stage->fEffectRef = GrEffect::CreateEffectRef(fEffect);
|
||||
stage->fCoordChangeMatrix = fCoordChangeMatrix;
|
||||
stage->fVertexAttribIndices[0] = fVertexAttribIndices[0];
|
||||
stage->fVertexAttribIndices[1] = fVertexAttribIndices[1];
|
||||
} else {
|
||||
stage->fEffectRef = NULL;
|
||||
}
|
||||
SkSafeUnref(oldEffectRef);
|
||||
}
|
||||
|
||||
bool isEqual(const GrEffectStage& stage) const {
|
||||
if (NULL == stage.fEffectRef) {
|
||||
return NULL == fEffect;
|
||||
} else if (NULL == fEffect) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (fVertexAttribIndices[0] != stage.fVertexAttribIndices[0]
|
||||
|| fVertexAttribIndices[1] != stage.fVertexAttribIndices[1]) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!(*stage.getEffect())->isEqual(*fEffect)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return fCoordChangeMatrix == stage.fCoordChangeMatrix;
|
||||
}
|
||||
|
||||
private:
|
||||
const GrEffect* fEffect;
|
||||
SkMatrix fCoordChangeMatrix;
|
||||
int fVertexAttribIndices[2];
|
||||
SkDEBUGCODE(bool fInitialized;)
|
||||
};
|
||||
|
||||
/**
|
||||
* Gets the matrix representing all changes of coordinate system since the GrEffect was
|
||||
* installed in the stage.
|
||||
*/
|
||||
const SkMatrix& getCoordChangeMatrix() const { return fCoordChangeMatrix; }
|
||||
|
||||
void reset() {
|
||||
GrSafeSetNull(fEffectRef);
|
||||
}
|
||||
|
||||
const GrEffectRef* setEffect(const GrEffectRef* EffectRef) {
|
||||
GrAssert(0 == fSavedCoordChangeCnt);
|
||||
GrSafeAssign(fEffectRef, EffectRef);
|
||||
fCoordChangeMatrix.reset();
|
||||
|
||||
fVertexAttribIndices[0] = -1;
|
||||
fVertexAttribIndices[1] = -1;
|
||||
|
||||
return EffectRef;
|
||||
}
|
||||
|
||||
const GrEffectRef* setEffect(const GrEffectRef* EffectRef, int attr0, int attr1 = -1) {
|
||||
GrAssert(0 == fSavedCoordChangeCnt);
|
||||
GrSafeAssign(fEffectRef, EffectRef);
|
||||
fCoordChangeMatrix.reset();
|
||||
|
||||
fVertexAttribIndices[0] = attr0;
|
||||
fVertexAttribIndices[1] = attr1;
|
||||
|
||||
return EffectRef;
|
||||
}
|
||||
|
||||
const GrEffectRef* getEffect() const { return fEffectRef; }
|
||||
|
||||
const int* getVertexAttribIndices() const { return fVertexAttribIndices; }
|
||||
int getVertexAttribIndexCount() const { return fEffectRef->get()->numVertexAttribs(); }
|
||||
|
||||
private:
|
||||
SkMatrix fCoordChangeMatrix;
|
||||
const GrEffectRef* fEffectRef;
|
||||
int fVertexAttribIndices[2];
|
||||
|
||||
GR_DEBUGCODE(mutable int fSavedCoordChangeCnt;)
|
||||
};
|
||||
|
||||
#endif
|
|
@ -1,30 +0,0 @@
|
|||
|
||||
/*
|
||||
* Copyright 2010 Google Inc.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
#ifndef GrNoncopyable_DEFINED
|
||||
#define GrNoncopyable_DEFINED
|
||||
|
||||
#include "GrTypes.h"
|
||||
|
||||
/**
|
||||
* Base for classes that want to disallow copying themselves. It makes its
|
||||
* copy-constructor and assignment operators private (and unimplemented).
|
||||
*/
|
||||
class GR_API GrNoncopyable {
|
||||
public:
|
||||
GrNoncopyable() {}
|
||||
|
||||
private:
|
||||
// illegal
|
||||
GrNoncopyable(const GrNoncopyable&);
|
||||
GrNoncopyable& operator=(const GrNoncopyable&);
|
||||
};
|
||||
|
||||
#endif
|
|
@ -1,46 +0,0 @@
|
|||
/*
|
||||
* Copyright 2013 Google Inc.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef GrOvalRenderer_DEFINED
|
||||
#define GrOvalRenderer_DEFINED
|
||||
|
||||
#include "GrContext.h"
|
||||
#include "GrPaint.h"
|
||||
#include "GrRefCnt.h"
|
||||
#include "GrRect.h"
|
||||
|
||||
class GrContext;
|
||||
class GrDrawTarget;
|
||||
class GrPaint;
|
||||
class SkStrokeRec;
|
||||
|
||||
/*
|
||||
* This class wraps helper functions that draw ovals (filled & stroked)
|
||||
*/
|
||||
class GrOvalRenderer : public GrRefCnt {
|
||||
public:
|
||||
SK_DECLARE_INST_COUNT(GrOvalRenderer)
|
||||
|
||||
GrOvalRenderer() {}
|
||||
|
||||
~GrOvalRenderer() {}
|
||||
|
||||
bool drawOval(GrDrawTarget* target, const GrContext* context, const GrPaint& paint,
|
||||
const GrRect& oval, const SkStrokeRec& stroke);
|
||||
private:
|
||||
void drawEllipse(GrDrawTarget* target, const GrPaint& paint,
|
||||
const GrRect& ellipse,
|
||||
const SkStrokeRec& stroke);
|
||||
void drawCircle(GrDrawTarget* target, const GrPaint& paint,
|
||||
const GrRect& circle,
|
||||
const SkStrokeRec& stroke);
|
||||
|
||||
typedef GrRefCnt INHERITED;
|
||||
};
|
||||
|
||||
#endif // GrOvalRenderer_DEFINED
|
|
@ -1,33 +0,0 @@
|
|||
|
||||
/*
|
||||
* Copyright 2010 Google Inc.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
#ifndef GrRefCnt_DEFINED
|
||||
#define GrRefCnt_DEFINED
|
||||
|
||||
#include "GrTypes.h"
|
||||
#include "SkRefCnt.h"
|
||||
|
||||
typedef SkRefCnt GrRefCnt;
|
||||
typedef SkAutoRef GrAutoRef;
|
||||
typedef SkAutoUnref GrAutoUnref;
|
||||
|
||||
#define GrSafeRef SkSafeRef
|
||||
#define GrSafeUnref SkSafeUnref
|
||||
#define GrSafeAssign(a, b) SkRefCnt_SafeAssign(a, b)
|
||||
|
||||
template<typename T>
|
||||
static inline void GrSafeSetNull(T*& obj) {
|
||||
if (NULL != obj) {
|
||||
obj->unref();
|
||||
obj = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
|
@ -1,60 +0,0 @@
|
|||
|
||||
/*
|
||||
* Copyright 2010 Google Inc.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
#ifndef GrTextContext_DEFINED
|
||||
#define GrTextContext_DEFINED
|
||||
|
||||
#include "GrContext.h"
|
||||
#include "GrGlyph.h"
|
||||
#include "GrPaint.h"
|
||||
|
||||
class GrContext;
|
||||
class GrTextStrike;
|
||||
class GrFontScaler;
|
||||
class GrDrawTarget;
|
||||
|
||||
class GrTextContext {
|
||||
public:
|
||||
GrTextContext(GrContext*, const GrPaint&);
|
||||
~GrTextContext();
|
||||
|
||||
void drawPackedGlyph(GrGlyph::PackedID, GrFixed left, GrFixed top,
|
||||
GrFontScaler*);
|
||||
|
||||
void flush(); // optional; automatically called by destructor
|
||||
|
||||
private:
|
||||
GrPaint fPaint;
|
||||
GrContext* fContext;
|
||||
GrDrawTarget* fDrawTarget;
|
||||
|
||||
GrFontScaler* fScaler;
|
||||
GrTextStrike* fStrike;
|
||||
|
||||
inline void flushGlyphs();
|
||||
void setupDrawTarget();
|
||||
|
||||
enum {
|
||||
kMinRequestedGlyphs = 1,
|
||||
kDefaultRequestedGlyphs = 64,
|
||||
kMinRequestedVerts = kMinRequestedGlyphs * 4,
|
||||
kDefaultRequestedVerts = kDefaultRequestedGlyphs * 4,
|
||||
};
|
||||
|
||||
SkPoint* fVertices;
|
||||
int32_t fMaxVertices;
|
||||
GrTexture* fCurrTexture;
|
||||
int fCurrVertex;
|
||||
|
||||
GrIRect fClipRect;
|
||||
GrContext::AutoMatrix fAutoMatrix;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -1,326 +0,0 @@
|
|||
|
||||
/*
|
||||
* Copyright 2011 Google Inc.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef GrGLInterface_DEFINED
|
||||
#define GrGLInterface_DEFINED
|
||||
|
||||
#include "GrGLFunctions.h"
|
||||
#include "GrRefCnt.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/**
|
||||
* Classifies GL contexts (currently as Desktop vs. ES2). This is a bitfield.
|
||||
* A GrGLInterface (defined below) may support multiple bindings.
|
||||
*/
|
||||
enum GrGLBinding {
|
||||
kNone_GrGLBinding = 0x0,
|
||||
|
||||
kDesktop_GrGLBinding = 0x01,
|
||||
kES2_GrGLBinding = 0x02,
|
||||
|
||||
// for iteration of GrGLBindings
|
||||
kFirstGrGLBinding = kDesktop_GrGLBinding,
|
||||
kLastGrGLBinding = kES2_GrGLBinding
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/**
|
||||
* Rather than depend on platform-specific GL headers and libraries, we require
|
||||
* the client to provide a struct of GL function pointers. This struct can be
|
||||
* specified per-GrContext as a parameter to GrContext::Create. If NULL is
|
||||
* passed to Create then the "default" GL interface is used. If the default is
|
||||
* also NULL GrContext creation will fail.
|
||||
*
|
||||
* The default interface is returned by GrGLDefaultInterface. This function's
|
||||
* implementation is platform-specific. Several have been provided, along with
|
||||
* an implementation that simply returns NULL. It is implementation-specific
|
||||
* whether the same GrGLInterface is returned or whether a new one is created
|
||||
* at each call. Some platforms may not be able to use a single GrGLInterface
|
||||
* because extension function ptrs vary across contexts. Note that GrGLInterface
|
||||
* is ref-counted. So if the same object is returned by multiple calls to
|
||||
* GrGLDefaultInterface, each should bump the ref count.
|
||||
*
|
||||
* By defining GR_GL_PER_GL_CALL_IFACE_CALLBACK to 1 the client can specify a
|
||||
* callback function that will be called prior to each GL function call. See
|
||||
* comments in GrGLConfig.h
|
||||
*/
|
||||
|
||||
struct GrGLInterface;
|
||||
|
||||
const GrGLInterface* GrGLDefaultInterface();
|
||||
|
||||
/**
|
||||
* Creates a GrGLInterface for a "native" GL context (e.g. WGL on windows,
|
||||
* GLX on linux, AGL on Mac). On platforms that have context-specific function
|
||||
* pointers for GL extensions (e.g. windows) the returned interface is only
|
||||
* valid for the context that was current at creation.
|
||||
*/
|
||||
const GrGLInterface* GrGLCreateNativeInterface();
|
||||
|
||||
#if SK_MESA
|
||||
/**
|
||||
* Creates a GrGLInterface for an OSMesa context.
|
||||
*/
|
||||
const GrGLInterface* GrGLCreateMesaInterface();
|
||||
#endif
|
||||
|
||||
#if SK_ANGLE
|
||||
/**
|
||||
* Creates a GrGLInterface for an ANGLE context.
|
||||
*/
|
||||
const GrGLInterface* GrGLCreateANGLEInterface();
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Creates a null GrGLInterface that doesn't draw anything. Used for measuring
|
||||
* CPU overhead.
|
||||
*/
|
||||
const GrGLInterface* GrGLCreateNullInterface();
|
||||
|
||||
/**
|
||||
* Creates a debugging GrGLInterface that doesn't draw anything. Used for
|
||||
* finding memory leaks and invalid memory accesses.
|
||||
*/
|
||||
const GrGLInterface* GrGLCreateDebugInterface();
|
||||
|
||||
#if GR_GL_PER_GL_FUNC_CALLBACK
|
||||
typedef void (*GrGLInterfaceCallbackProc)(const GrGLInterface*);
|
||||
typedef intptr_t GrGLInterfaceCallbackData;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* GrContext uses the following interface to make all calls into OpenGL. When a
|
||||
* GrContext is created it is given a GrGLInterface. The interface's function
|
||||
* pointers must be valid for the OpenGL context associated with the GrContext.
|
||||
* On some platforms, such as Windows, function pointers for OpenGL extensions
|
||||
* may vary between OpenGL contexts. So the caller must be careful to use a
|
||||
* GrGLInterface initialized for the correct context. All functions that should
|
||||
* be available based on the OpenGL's version and extension string must be
|
||||
* non-NULL or GrContext creation will fail. This can be tested with the
|
||||
* validate() method when the OpenGL context has been made current.
|
||||
*/
|
||||
struct GR_API GrGLInterface : public GrRefCnt {
|
||||
private:
|
||||
// simple wrapper class that exists only to initialize a pointer to NULL
|
||||
template <typename FNPTR_TYPE> class GLPtr {
|
||||
public:
|
||||
GLPtr() : fPtr(NULL) {}
|
||||
GLPtr operator =(FNPTR_TYPE ptr) { fPtr = ptr; return *this; }
|
||||
operator FNPTR_TYPE() const { return fPtr; }
|
||||
private:
|
||||
FNPTR_TYPE fPtr;
|
||||
};
|
||||
|
||||
typedef GrRefCnt INHERITED;
|
||||
|
||||
public:
|
||||
SK_DECLARE_INST_COUNT(GrGLInterface)
|
||||
|
||||
GrGLInterface();
|
||||
|
||||
// Validates that the GrGLInterface supports a binding. This means that
|
||||
// the GrGLinterface advertises the binding in fBindingsExported and all
|
||||
// the necessary function pointers have been initialized. The interface is
|
||||
// validated for the current OpenGL context.
|
||||
bool validate(GrGLBinding binding) const;
|
||||
|
||||
// Indicator variable specifying the type of GL implementation
|
||||
// exported: GLES2 and/or Desktop.
|
||||
GrGLBinding fBindingsExported;
|
||||
|
||||
GLPtr<GrGLActiveTextureProc> fActiveTexture;
|
||||
GLPtr<GrGLAttachShaderProc> fAttachShader;
|
||||
GLPtr<GrGLBeginQueryProc> fBeginQuery;
|
||||
GLPtr<GrGLBindAttribLocationProc> fBindAttribLocation;
|
||||
GLPtr<GrGLBindBufferProc> fBindBuffer;
|
||||
GLPtr<GrGLBindFragDataLocationProc> fBindFragDataLocation;
|
||||
GLPtr<GrGLBindFragDataLocationIndexedProc> fBindFragDataLocationIndexed;
|
||||
GLPtr<GrGLBindFramebufferProc> fBindFramebuffer;
|
||||
GLPtr<GrGLBindRenderbufferProc> fBindRenderbuffer;
|
||||
GLPtr<GrGLBindTextureProc> fBindTexture;
|
||||
GLPtr<GrGLBindVertexArrayProc> fBindVertexArray;
|
||||
GLPtr<GrGLBlendColorProc> fBlendColor;
|
||||
GLPtr<GrGLBlendFuncProc> fBlendFunc;
|
||||
GLPtr<GrGLBlitFramebufferProc> fBlitFramebuffer;
|
||||
GLPtr<GrGLBufferDataProc> fBufferData;
|
||||
GLPtr<GrGLBufferSubDataProc> fBufferSubData;
|
||||
GLPtr<GrGLCheckFramebufferStatusProc> fCheckFramebufferStatus;
|
||||
GLPtr<GrGLClearProc> fClear;
|
||||
GLPtr<GrGLClearColorProc> fClearColor;
|
||||
GLPtr<GrGLClearStencilProc> fClearStencil;
|
||||
GLPtr<GrGLColorMaskProc> fColorMask;
|
||||
GLPtr<GrGLCompileShaderProc> fCompileShader;
|
||||
GLPtr<GrGLCompressedTexImage2DProc> fCompressedTexImage2D;
|
||||
GLPtr<GrGLCreateProgramProc> fCreateProgram;
|
||||
GLPtr<GrGLCreateShaderProc> fCreateShader;
|
||||
GLPtr<GrGLCullFaceProc> fCullFace;
|
||||
GLPtr<GrGLDeleteBuffersProc> fDeleteBuffers;
|
||||
GLPtr<GrGLDeleteFramebuffersProc> fDeleteFramebuffers;
|
||||
GLPtr<GrGLDeleteProgramProc> fDeleteProgram;
|
||||
GLPtr<GrGLDeleteQueriesProc> fDeleteQueries;
|
||||
GLPtr<GrGLDeleteRenderbuffersProc> fDeleteRenderbuffers;
|
||||
GLPtr<GrGLDeleteShaderProc> fDeleteShader;
|
||||
GLPtr<GrGLDeleteTexturesProc> fDeleteTextures;
|
||||
GLPtr<GrGLDeleteVertexArraysProc> fDeleteVertexArrays;
|
||||
GLPtr<GrGLDepthMaskProc> fDepthMask;
|
||||
GLPtr<GrGLDisableProc> fDisable;
|
||||
GLPtr<GrGLDisableVertexAttribArrayProc> fDisableVertexAttribArray;
|
||||
GLPtr<GrGLDrawArraysProc> fDrawArrays;
|
||||
GLPtr<GrGLDrawBufferProc> fDrawBuffer;
|
||||
GLPtr<GrGLDrawBuffersProc> fDrawBuffers;
|
||||
GLPtr<GrGLDrawElementsProc> fDrawElements;
|
||||
GLPtr<GrGLEnableProc> fEnable;
|
||||
GLPtr<GrGLEnableVertexAttribArrayProc> fEnableVertexAttribArray;
|
||||
GLPtr<GrGLEndQueryProc> fEndQuery;
|
||||
GLPtr<GrGLFinishProc> fFinish;
|
||||
GLPtr<GrGLFlushProc> fFlush;
|
||||
GLPtr<GrGLFramebufferRenderbufferProc> fFramebufferRenderbuffer;
|
||||
GLPtr<GrGLFramebufferTexture2DProc> fFramebufferTexture2D;
|
||||
GLPtr<GrGLFramebufferTexture2DMultisampleProc> fFramebufferTexture2DMultisample;
|
||||
GLPtr<GrGLFrontFaceProc> fFrontFace;
|
||||
GLPtr<GrGLGenBuffersProc> fGenBuffers;
|
||||
GLPtr<GrGLGenFramebuffersProc> fGenFramebuffers;
|
||||
GLPtr<GrGLGenQueriesProc> fGenQueries;
|
||||
GLPtr<GrGLGenRenderbuffersProc> fGenRenderbuffers;
|
||||
GLPtr<GrGLGenTexturesProc> fGenTextures;
|
||||
GLPtr<GrGLGenVertexArraysProc> fGenVertexArrays;
|
||||
GLPtr<GrGLGetBufferParameterivProc> fGetBufferParameteriv;
|
||||
GLPtr<GrGLGetErrorProc> fGetError;
|
||||
GLPtr<GrGLGetFramebufferAttachmentParameterivProc> fGetFramebufferAttachmentParameteriv;
|
||||
GLPtr<GrGLGetIntegervProc> fGetIntegerv;
|
||||
GLPtr<GrGLGetQueryObjecti64vProc> fGetQueryObjecti64v;
|
||||
GLPtr<GrGLGetQueryObjectivProc> fGetQueryObjectiv;
|
||||
GLPtr<GrGLGetQueryObjectui64vProc> fGetQueryObjectui64v;
|
||||
GLPtr<GrGLGetQueryObjectuivProc> fGetQueryObjectuiv;
|
||||
GLPtr<GrGLGetQueryivProc> fGetQueryiv;
|
||||
GLPtr<GrGLGetProgramInfoLogProc> fGetProgramInfoLog;
|
||||
GLPtr<GrGLGetProgramivProc> fGetProgramiv;
|
||||
GLPtr<GrGLGetRenderbufferParameterivProc> fGetRenderbufferParameteriv;
|
||||
GLPtr<GrGLGetShaderInfoLogProc> fGetShaderInfoLog;
|
||||
GLPtr<GrGLGetShaderivProc> fGetShaderiv;
|
||||
GLPtr<GrGLGetStringProc> fGetString;
|
||||
GLPtr<GrGLGetStringiProc> fGetStringi;
|
||||
GLPtr<GrGLGetTexLevelParameterivProc> fGetTexLevelParameteriv;
|
||||
GLPtr<GrGLGetUniformLocationProc> fGetUniformLocation;
|
||||
GLPtr<GrGLLineWidthProc> fLineWidth;
|
||||
GLPtr<GrGLLinkProgramProc> fLinkProgram;
|
||||
GLPtr<GrGLMapBufferProc> fMapBuffer;
|
||||
GLPtr<GrGLPixelStoreiProc> fPixelStorei;
|
||||
GLPtr<GrGLQueryCounterProc> fQueryCounter;
|
||||
GLPtr<GrGLReadBufferProc> fReadBuffer;
|
||||
GLPtr<GrGLReadPixelsProc> fReadPixels;
|
||||
GLPtr<GrGLRenderbufferStorageProc> fRenderbufferStorage;
|
||||
GLPtr<GrGLRenderbufferStorageMultisampleProc> fRenderbufferStorageMultisample;
|
||||
GLPtr<GrGLRenderbufferStorageMultisampleCoverageProc> fRenderbufferStorageMultisampleCoverage;
|
||||
GLPtr<GrGLResolveMultisampleFramebufferProc> fResolveMultisampleFramebuffer;
|
||||
GLPtr<GrGLScissorProc> fScissor;
|
||||
GLPtr<GrGLShaderSourceProc> fShaderSource;
|
||||
GLPtr<GrGLStencilFuncProc> fStencilFunc;
|
||||
GLPtr<GrGLStencilFuncSeparateProc> fStencilFuncSeparate;
|
||||
GLPtr<GrGLStencilMaskProc> fStencilMask;
|
||||
GLPtr<GrGLStencilMaskSeparateProc> fStencilMaskSeparate;
|
||||
GLPtr<GrGLStencilOpProc> fStencilOp;
|
||||
GLPtr<GrGLStencilOpSeparateProc> fStencilOpSeparate;
|
||||
GLPtr<GrGLTexImage2DProc> fTexImage2D;
|
||||
GLPtr<GrGLTexParameteriProc> fTexParameteri;
|
||||
GLPtr<GrGLTexParameterivProc> fTexParameteriv;
|
||||
GLPtr<GrGLTexSubImage2DProc> fTexSubImage2D;
|
||||
GLPtr<GrGLTexStorage2DProc> fTexStorage2D;
|
||||
GLPtr<GrGLUniform1fProc> fUniform1f;
|
||||
GLPtr<GrGLUniform1iProc> fUniform1i;
|
||||
GLPtr<GrGLUniform1fvProc> fUniform1fv;
|
||||
GLPtr<GrGLUniform1ivProc> fUniform1iv;
|
||||
GLPtr<GrGLUniform2fProc> fUniform2f;
|
||||
GLPtr<GrGLUniform2iProc> fUniform2i;
|
||||
GLPtr<GrGLUniform2fvProc> fUniform2fv;
|
||||
GLPtr<GrGLUniform2ivProc> fUniform2iv;
|
||||
GLPtr<GrGLUniform3fProc> fUniform3f;
|
||||
GLPtr<GrGLUniform3iProc> fUniform3i;
|
||||
GLPtr<GrGLUniform3fvProc> fUniform3fv;
|
||||
GLPtr<GrGLUniform3ivProc> fUniform3iv;
|
||||
GLPtr<GrGLUniform4fProc> fUniform4f;
|
||||
GLPtr<GrGLUniform4iProc> fUniform4i;
|
||||
GLPtr<GrGLUniform4fvProc> fUniform4fv;
|
||||
GLPtr<GrGLUniform4ivProc> fUniform4iv;
|
||||
GLPtr<GrGLUniformMatrix2fvProc> fUniformMatrix2fv;
|
||||
GLPtr<GrGLUniformMatrix3fvProc> fUniformMatrix3fv;
|
||||
GLPtr<GrGLUniformMatrix4fvProc> fUniformMatrix4fv;
|
||||
GLPtr<GrGLUnmapBufferProc> fUnmapBuffer;
|
||||
GLPtr<GrGLUseProgramProc> fUseProgram;
|
||||
GLPtr<GrGLVertexAttrib4fvProc> fVertexAttrib4fv;
|
||||
GLPtr<GrGLVertexAttribPointerProc> fVertexAttribPointer;
|
||||
GLPtr<GrGLViewportProc> fViewport;
|
||||
|
||||
// Experimental: Functions for GL_NV_path_rendering. These will be
|
||||
// alphabetized with the above functions once this is fully supported
|
||||
// (and functions we are unlikely to use will possibly be omitted).
|
||||
GLPtr<GrGLMatrixModeProc> fMatrixMode;
|
||||
GLPtr<GrGLLoadIdentityProc> fLoadIdentity;
|
||||
GLPtr<GrGLLoadMatrixfProc> fLoadMatrixf;
|
||||
GLPtr<GrGLPathCommandsProc> fPathCommands;
|
||||
GLPtr<GrGLPathCoordsProc> fPathCoords;
|
||||
GLPtr<GrGLPathSubCommandsProc> fPathSubCommands;
|
||||
GLPtr<GrGLPathSubCoordsProc> fPathSubCoords;
|
||||
GLPtr<GrGLPathStringProc> fPathString;
|
||||
GLPtr<GrGLPathGlyphsProc> fPathGlyphs;
|
||||
GLPtr<GrGLPathGlyphRangeProc> fPathGlyphRange;
|
||||
GLPtr<GrGLWeightPathsProc> fWeightPaths;
|
||||
GLPtr<GrGLCopyPathProc> fCopyPath;
|
||||
GLPtr<GrGLInterpolatePathsProc> fInterpolatePaths;
|
||||
GLPtr<GrGLTransformPathProc> fTransformPath;
|
||||
GLPtr<GrGLPathParameterivProc> fPathParameteriv;
|
||||
GLPtr<GrGLPathParameteriProc> fPathParameteri;
|
||||
GLPtr<GrGLPathParameterfvProc> fPathParameterfv;
|
||||
GLPtr<GrGLPathParameterfProc> fPathParameterf;
|
||||
GLPtr<GrGLPathDashArrayProc> fPathDashArray;
|
||||
GLPtr<GrGLGenPathsProc> fGenPaths;
|
||||
GLPtr<GrGLDeletePathsProc> fDeletePaths;
|
||||
GLPtr<GrGLIsPathProc> fIsPath;
|
||||
GLPtr<GrGLPathStencilFuncProc> fPathStencilFunc;
|
||||
GLPtr<GrGLPathStencilDepthOffsetProc> fPathStencilDepthOffset;
|
||||
GLPtr<GrGLStencilFillPathProc> fStencilFillPath;
|
||||
GLPtr<GrGLStencilStrokePathProc> fStencilStrokePath;
|
||||
GLPtr<GrGLStencilFillPathInstancedProc> fStencilFillPathInstanced;
|
||||
GLPtr<GrGLStencilStrokePathInstancedProc> fStencilStrokePathInstanced;
|
||||
GLPtr<GrGLPathCoverDepthFuncProc> fPathCoverDepthFunc;
|
||||
GLPtr<GrGLPathColorGenProc> fPathColorGen;
|
||||
GLPtr<GrGLPathTexGenProc> fPathTexGen;
|
||||
GLPtr<GrGLPathFogGenProc> fPathFogGen;
|
||||
GLPtr<GrGLCoverFillPathProc> fCoverFillPath;
|
||||
GLPtr<GrGLCoverStrokePathProc> fCoverStrokePath;
|
||||
GLPtr<GrGLCoverFillPathInstancedProc> fCoverFillPathInstanced;
|
||||
GLPtr<GrGLCoverStrokePathInstancedProc> fCoverStrokePathInstanced;
|
||||
GLPtr<GrGLGetPathParameterivProc> fGetPathParameteriv;
|
||||
GLPtr<GrGLGetPathParameterfvProc> fGetPathParameterfv;
|
||||
GLPtr<GrGLGetPathCommandsProc> fGetPathCommands;
|
||||
GLPtr<GrGLGetPathCoordsProc> fGetPathCoords;
|
||||
GLPtr<GrGLGetPathDashArrayProc> fGetPathDashArray;
|
||||
GLPtr<GrGLGetPathMetricsProc> fGetPathMetrics;
|
||||
GLPtr<GrGLGetPathMetricRangeProc> fGetPathMetricRange;
|
||||
GLPtr<GrGLGetPathSpacingProc> fGetPathSpacing;
|
||||
GLPtr<GrGLGetPathColorGenivProc> fGetPathColorGeniv;
|
||||
GLPtr<GrGLGetPathColorGenfvProc> fGetPathColorGenfv;
|
||||
GLPtr<GrGLGetPathTexGenivProc> fGetPathTexGeniv;
|
||||
GLPtr<GrGLGetPathTexGenfvProc> fGetPathTexGenfv;
|
||||
GLPtr<GrGLIsPointInFillPathProc> fIsPointInFillPath;
|
||||
GLPtr<GrGLIsPointInStrokePathProc> fIsPointInStrokePath;
|
||||
GLPtr<GrGLGetPathLengthProc> fGetPathLength;
|
||||
GLPtr<GrGLPointAlongPathProc> fPointAlongPath;
|
||||
|
||||
// Per-GL func callback
|
||||
#if GR_GL_PER_GL_FUNC_CALLBACK
|
||||
GrGLInterfaceCallbackProc fCallback;
|
||||
GrGLInterfaceCallbackData fCallbackData;
|
||||
#endif
|
||||
|
||||
};
|
||||
|
||||
#endif
|
|
@ -1,54 +0,0 @@
|
|||
/*
|
||||
* Copyright 2011 The Android Open Source Project
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef SkBitmapRegionDecoder_DEFINED
|
||||
#define SkBitmapRegionDecoder_DEFINED
|
||||
|
||||
#include "SkBitmap.h"
|
||||
#include "SkImageDecoder.h"
|
||||
#include "SkStream.h"
|
||||
|
||||
struct SkIRect;
|
||||
|
||||
/**
|
||||
* SkBitmapRegionDecoder can be used to decode a specified rect from an image.
|
||||
* This is particularly useful when the original image is large and you only
|
||||
* need parts of the image.
|
||||
*
|
||||
* However, not all image codecs on all platforms support this feature so be
|
||||
* prepared to fallback to standard decoding if decodeRegion(...) returns false.
|
||||
*/
|
||||
class SkBitmapRegionDecoder {
|
||||
public:
|
||||
SkBitmapRegionDecoder(SkImageDecoder* decoder, SkStream* stream,
|
||||
int width, int height) {
|
||||
fDecoder = decoder;
|
||||
fStream = stream;
|
||||
fWidth = width;
|
||||
fHeight = height;
|
||||
}
|
||||
~SkBitmapRegionDecoder() {
|
||||
SkDELETE(fDecoder);
|
||||
SkSafeUnref(fStream);
|
||||
}
|
||||
|
||||
bool decodeRegion(SkBitmap* bitmap, const SkIRect& rect,
|
||||
SkBitmap::Config pref, int sampleSize);
|
||||
|
||||
SkImageDecoder* getDecoder() const { return fDecoder; }
|
||||
int getWidth() const { return fWidth; }
|
||||
int getHeight() const { return fHeight; }
|
||||
|
||||
private:
|
||||
SkImageDecoder* fDecoder;
|
||||
SkStream* fStream;
|
||||
int fWidth;
|
||||
int fHeight;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -1,95 +0,0 @@
|
|||
/*
|
||||
* 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 SkBitmapFactory_DEFINED
|
||||
#define SkBitmapFactory_DEFINED
|
||||
|
||||
#include "SkImage.h"
|
||||
#include "SkTypes.h"
|
||||
|
||||
class SkBitmap;
|
||||
class SkData;
|
||||
class SkImageCache;
|
||||
|
||||
/**
|
||||
* Factory for creating a bitmap from encoded data.
|
||||
*/
|
||||
class SkBitmapFactory {
|
||||
|
||||
public:
|
||||
/**
|
||||
* Struct containing information about a pixel destination.
|
||||
*/
|
||||
struct Target {
|
||||
/**
|
||||
* Pre-allocated memory.
|
||||
*/
|
||||
void* fAddr;
|
||||
|
||||
/**
|
||||
* Rowbytes of the allocated memory.
|
||||
*/
|
||||
size_t fRowBytes;
|
||||
};
|
||||
|
||||
/**
|
||||
* Signature for a function to decode an image from encoded data.
|
||||
*/
|
||||
typedef bool (*DecodeProc)(const void* data, size_t length, SkImage::Info*, const Target*);
|
||||
|
||||
/**
|
||||
* Create a bitmap factory which uses DecodeProc for decoding.
|
||||
* @param DecodeProc Must not be NULL.
|
||||
*/
|
||||
SkBitmapFactory(DecodeProc);
|
||||
|
||||
~SkBitmapFactory();
|
||||
|
||||
/**
|
||||
* Set an image cache to use on pixelrefs provided by installPixelRef. Mutually exclusive
|
||||
* with fCacheSelector.
|
||||
*/
|
||||
void setImageCache(SkImageCache* cache);
|
||||
|
||||
/**
|
||||
* Sets up an SkBitmap from encoded data. On success, the SkBitmap will have its Config,
|
||||
* width, height, rowBytes and pixelref set. If fImageCache is non-NULL, or if fCacheSelector
|
||||
* is set and returns non-NULL, the pixelref will lazily decode, and that SkImageCache will
|
||||
* handle the pixel memory. Otherwise installPixelRef will do an immediate decode.
|
||||
* @param SkData Encoded data.
|
||||
* @param SkBitmap to install the pixel ref on.
|
||||
* @return bool Whether or not a pixel ref was successfully installed.
|
||||
*/
|
||||
bool installPixelRef(SkData*, SkBitmap*);
|
||||
|
||||
/**
|
||||
* An object for selecting an SkImageCache to use based on an SkImage::Info.
|
||||
*/
|
||||
class CacheSelector : public SkRefCnt {
|
||||
|
||||
public:
|
||||
/**
|
||||
* Return an SkImageCache to use based on the provided SkImage::Info. If the caller decides
|
||||
* to hang on to the result, it will call ref, so the implementation should not add a ref
|
||||
* as a result of this call.
|
||||
*/
|
||||
virtual SkImageCache* selectCache(const SkImage::Info&) = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* Set the function to be used to select which SkImageCache to use. Mutually exclusive with
|
||||
* fImageCache.
|
||||
*/
|
||||
void setCacheSelector(CacheSelector*);
|
||||
|
||||
private:
|
||||
DecodeProc fDecodeProc;
|
||||
SkImageCache* fImageCache;
|
||||
CacheSelector* fCacheSelector;
|
||||
};
|
||||
|
||||
#endif // SkBitmapFactory_DEFINED
|
|
@ -1,125 +0,0 @@
|
|||
/*
|
||||
* Copyright 2013 Google Inc.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#ifndef SkImageCache_DEFINED
|
||||
#define SkImageCache_DEFINED
|
||||
|
||||
#include "SkRefCnt.h"
|
||||
#include "SkTypes.h"
|
||||
|
||||
/**
|
||||
* Interface for a cache that manages pixel memory.
|
||||
*/
|
||||
class SkImageCache : public SkRefCnt {
|
||||
|
||||
public:
|
||||
/**
|
||||
* Allocate memory whose lifetime is managed by the cache. On success, MUST be balanced with a
|
||||
* call to releaseCache and a call to throwAwayCache.
|
||||
* @param bytes Number of bytes needed.
|
||||
* @param ID Output parameter which must not be NULL. On success, ID will be set to a value
|
||||
* associated with that memory which can be used as a parameter to the other functions
|
||||
* in SkImageCache. On failure, ID is unchanged.
|
||||
* @return Pointer to the newly allocated memory, or NULL. This memory is safe to use until
|
||||
* releaseCache is called with ID.
|
||||
*/
|
||||
virtual void* allocAndPinCache(size_t bytes, intptr_t* ID) = 0;
|
||||
|
||||
/**
|
||||
* Output parameter for pinCache, stating whether the memory still contains the data it held
|
||||
* when releaseCache was last called for the same ID.
|
||||
*/
|
||||
enum DataStatus {
|
||||
/**
|
||||
* The data has been purged, and therefore needs to be rewritten to the returned memory.
|
||||
*/
|
||||
kUninitialized_DataStatus,
|
||||
|
||||
/**
|
||||
* The memory still contains the data it held when releaseCache was last called with the
|
||||
* same ID.
|
||||
*/
|
||||
kRetained_DataStatus,
|
||||
};
|
||||
|
||||
/**
|
||||
* Re-request the memory associated with ID and pin it so that it will not be reclaimed until
|
||||
* the next call to releaseCache with the same ID.
|
||||
* @param ID Unique ID for the memory block.
|
||||
* @param status Output parameter which must not be NULL. On success (i.e. the return value is
|
||||
* not NULL), status will be set to one of two states representing the cached memory. If
|
||||
* status is set to kRetained_DataStatus, the memory contains the same data it did
|
||||
* before releaseCache was called with this ID. If status is set to
|
||||
* kUninitialized_DataStatus, the memory is still pinned, but the previous data is no
|
||||
* longer available. If the return value is NULL, status is unchanged.
|
||||
* @return Pointer: If non-NULL, points to the previously allocated memory, in which case
|
||||
* this call must be balanced with a call to releaseCache. If NULL, the memory
|
||||
* has been reclaimed, and throwAwayCache MUST NOT be called.
|
||||
*/
|
||||
virtual void* pinCache(intptr_t ID, DataStatus* status) = 0;
|
||||
|
||||
/**
|
||||
* Inform the cache that it is safe to free the block of memory corresponding to ID. After
|
||||
* calling this function, the pointer returned by allocAndPinCache or pinCache must not be
|
||||
* used again. In order to access the same memory after this, pinCache must be called with
|
||||
* the same ID.
|
||||
* @param ID Unique ID for the memory block which is now safe to age out of the cache.
|
||||
*/
|
||||
virtual void releaseCache(intptr_t ID) = 0;
|
||||
|
||||
/**
|
||||
* Inform the cache that the block of memory associated with ID will not be asked for again.
|
||||
* After this call, ID is no longer valid. Must not be called while the associated memory is
|
||||
* pinned. Must be called to balance a successful allocAndPinCache.
|
||||
*/
|
||||
virtual void throwAwayCache(intptr_t ID) = 0;
|
||||
|
||||
/**
|
||||
* ID which does not correspond to any valid cache.
|
||||
*/
|
||||
static const intptr_t UNINITIALIZED_ID = 0;
|
||||
|
||||
#ifdef SK_DEBUG
|
||||
/**
|
||||
* Debug only status of a memory block.
|
||||
*/
|
||||
enum MemoryStatus {
|
||||
/**
|
||||
* It is safe to use the pointer returned by the most recent of allocAndPinCache(ID) or
|
||||
* pinCache(ID) with the same ID.
|
||||
*/
|
||||
kPinned_MemoryStatus,
|
||||
|
||||
/**
|
||||
* The pointer returned by the most recent call to allocAndPinCache(ID) or pinCache(ID) has
|
||||
* since been released by releaseCache(ID). In order to reuse it, pinCache(ID) must be
|
||||
* called again. Note that after calling releaseCache(ID), the status of that particular
|
||||
* ID may not be kUnpinned_MemoryStatus, depending on the implementation, but it will not
|
||||
* be kPinned_MemoryStatus.
|
||||
*/
|
||||
kUnpinned_MemoryStatus,
|
||||
|
||||
/**
|
||||
* The memory associated with ID has been thrown away. No calls should be made using the
|
||||
* same ID.
|
||||
*/
|
||||
kFreed_MemoryStatus,
|
||||
};
|
||||
|
||||
/**
|
||||
* Debug only function to get the status of a particular block of memory. Safe to call after
|
||||
* throwAwayCache has been called with this ID.
|
||||
*/
|
||||
virtual MemoryStatus getMemoryStatus(intptr_t ID) const = 0;
|
||||
|
||||
/**
|
||||
* Debug only function to clear all unpinned caches.
|
||||
*/
|
||||
virtual void purgeAllUnpinnedCaches() = 0;
|
||||
#endif
|
||||
};
|
||||
#endif // SkImageCache_DEFINED
|
|
@ -1,89 +0,0 @@
|
|||
/*
|
||||
* Copyright 2013 Google Inc.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#ifndef SkLruImageCache_DEFINED
|
||||
#define SkLruImageCache_DEFINED
|
||||
|
||||
#include "SkImageCache.h"
|
||||
#include "SkThread.h"
|
||||
#include "SkTInternalLList.h"
|
||||
|
||||
class CachedPixels;
|
||||
|
||||
/**
|
||||
* SkImageCache implementation that uses an LRU cache to age out old images.
|
||||
*/
|
||||
class SkLruImageCache : public SkImageCache {
|
||||
|
||||
public:
|
||||
SkLruImageCache(size_t budget);
|
||||
|
||||
virtual ~SkLruImageCache();
|
||||
|
||||
#ifdef SK_DEBUG
|
||||
virtual MemoryStatus getMemoryStatus(intptr_t ID) const SK_OVERRIDE;
|
||||
virtual void purgeAllUnpinnedCaches() SK_OVERRIDE;
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Set the byte limit on cached pixels. If more bytes are used than this, the cache will free
|
||||
* unpinned memory until under the new limit or until all unpinned memory is freed. This will
|
||||
* never free pinned memory, so the cache can potentially remain over the limit. The limit is
|
||||
* enforced each time memory is allocated or released.
|
||||
* 0 is a special flag for an infinite budget.
|
||||
* @return size_t The previous limit.
|
||||
*/
|
||||
size_t setImageCacheLimit(size_t newLimit);
|
||||
|
||||
/**
|
||||
* Return the number of bytes of memory currently in use by the cache. Can include memory that
|
||||
* is no longer pinned, but has not been freed.
|
||||
*/
|
||||
size_t getImageCacheUsed() const { return fRamUsed; }
|
||||
|
||||
virtual void* allocAndPinCache(size_t bytes, intptr_t* ID) SK_OVERRIDE;
|
||||
virtual void* pinCache(intptr_t ID, SkImageCache::DataStatus*) SK_OVERRIDE;
|
||||
virtual void releaseCache(intptr_t ID) SK_OVERRIDE;
|
||||
virtual void throwAwayCache(intptr_t ID) SK_OVERRIDE;
|
||||
|
||||
private:
|
||||
// Linked list of recently used. Head is the most recently used, and tail is the least.
|
||||
SkTInternalLList<CachedPixels> fLRU;
|
||||
typedef SkTInternalLList<CachedPixels>::Iter Iter;
|
||||
|
||||
#ifdef SK_DEBUG
|
||||
// fMutex is mutable so that getMemoryStatus can be const
|
||||
mutable
|
||||
#endif
|
||||
SkMutex fMutex;
|
||||
size_t fRamBudget;
|
||||
size_t fRamUsed;
|
||||
|
||||
/**
|
||||
* Find the CachedPixels represented by ID, or NULL if not in the cache. Mutex must be locked
|
||||
* before calling.
|
||||
*/
|
||||
CachedPixels* findByID(intptr_t ID) const;
|
||||
|
||||
/**
|
||||
* If over budget, throw away pixels which are not currently in use until below budget or there
|
||||
* are no more pixels eligible to be thrown away. Mutex must be locked before calling.
|
||||
*/
|
||||
void purgeIfNeeded();
|
||||
|
||||
/**
|
||||
* Purge until below limit. Mutex must be locked before calling.
|
||||
*/
|
||||
void purgeTilAtOrBelow(size_t limit);
|
||||
|
||||
/**
|
||||
* Remove a set of CachedPixels. Mutex must be locked before calling.
|
||||
*/
|
||||
void removePixels(CachedPixels*);
|
||||
};
|
||||
|
||||
#endif // SkLruImageCache_DEFINED
|
|
@ -1,45 +0,0 @@
|
|||
/*
|
||||
* Copyright 2013 Google Inc.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#ifndef SkPurgeableImageCache_DEFINED
|
||||
#define SkPurgeableImageCache_DEFINED
|
||||
|
||||
#include "SkImageCache.h"
|
||||
|
||||
#ifdef SK_DEBUG
|
||||
#include "SkTDArray.h"
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Implementation for SkImageCache that uses system defined purgeable memory.
|
||||
*/
|
||||
class SkPurgeableImageCache : public SkImageCache {
|
||||
|
||||
public:
|
||||
static SkImageCache* Create();
|
||||
|
||||
virtual void* allocAndPinCache(size_t bytes, intptr_t* ID) SK_OVERRIDE;
|
||||
virtual void* pinCache(intptr_t ID, SkImageCache::DataStatus*) SK_OVERRIDE;
|
||||
virtual void releaseCache(intptr_t ID) SK_OVERRIDE;
|
||||
virtual void throwAwayCache(intptr_t ID) SK_OVERRIDE;
|
||||
|
||||
#ifdef SK_DEBUG
|
||||
virtual MemoryStatus getMemoryStatus(intptr_t ID) const SK_OVERRIDE;
|
||||
virtual void purgeAllUnpinnedCaches() SK_OVERRIDE;
|
||||
virtual ~SkPurgeableImageCache();
|
||||
#endif
|
||||
|
||||
private:
|
||||
SkPurgeableImageCache();
|
||||
|
||||
#ifdef SK_DEBUG
|
||||
SkTDArray<intptr_t> fRecs;
|
||||
int findRec(intptr_t) const;
|
||||
#endif
|
||||
void removeRec(intptr_t);
|
||||
};
|
||||
#endif // SkPurgeableImageCache_DEFINED
|
|
@ -1,98 +0,0 @@
|
|||
/*
|
||||
* 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 SkTypeface_android_DEFINED
|
||||
#define SkTypeface_android_DEFINED
|
||||
|
||||
#include "SkTypeface.h"
|
||||
|
||||
enum FallbackScripts {
|
||||
kArabic_FallbackScript,
|
||||
kArmenian_FallbackScript,
|
||||
kBengali_FallbackScript,
|
||||
kDevanagari_FallbackScript,
|
||||
kEthiopic_FallbackScript,
|
||||
kGeorgian_FallbackScript,
|
||||
kHebrewRegular_FallbackScript,
|
||||
kHebrewBold_FallbackScript,
|
||||
kKannada_FallbackScript,
|
||||
kMalayalam_FallbackScript,
|
||||
kTamilRegular_FallbackScript,
|
||||
kTamilBold_FallbackScript,
|
||||
kThai_FallbackScript,
|
||||
kTelugu_FallbackScript,
|
||||
kFallbackScriptNumber
|
||||
};
|
||||
|
||||
// This particular mapping will be removed after WebKit is updated to use the
|
||||
// new mappings. No new caller should use the kTamil_FallbackScript but rather
|
||||
// the more specific Tamil scripts in the standard enum.
|
||||
#define kTamil_FallbackScript kTamilRegular_FallbackScript
|
||||
|
||||
#define SkTypeface_ValidScript(s) (s >= 0 && s < kFallbackScriptNumber)
|
||||
|
||||
/**
|
||||
* Return a new typeface for a fallback script. If the script is
|
||||
* not valid, or can not map to a font, returns null.
|
||||
* @param script The script id.
|
||||
* @return reference to the matching typeface. Caller must call
|
||||
* unref() when they are done.
|
||||
*/
|
||||
SK_API SkTypeface* SkCreateTypefaceForScript(FallbackScripts script);
|
||||
|
||||
/**
|
||||
* Return the string representation for the fallback script on Android.
|
||||
* If the script is not valid, returns null.
|
||||
*/
|
||||
SK_API const char* SkGetFallbackScriptID(FallbackScripts script);
|
||||
|
||||
/**
|
||||
* Return the fallback script enum for the ID on Android.
|
||||
* If the ID is not valid, or can not map to a fallback
|
||||
* script, returns kFallbackScriptNumber.
|
||||
*/
|
||||
SK_API FallbackScripts SkGetFallbackScriptFromID(const char* id);
|
||||
|
||||
/**
|
||||
* Return a new typeface of the font in the fallback font list containing
|
||||
* the specified chararacter. If no typeface is found, returns null.
|
||||
*/
|
||||
SK_API SkTypeface* SkCreateFallbackTypefaceForChar(SkUnichar uni,
|
||||
SkTypeface::Style style);
|
||||
|
||||
/**
|
||||
* Get the family name of the font in the fallback font list containing
|
||||
* the specified chararacter. if no font is found, returns false.
|
||||
*/
|
||||
SK_API bool SkGetFallbackFamilyNameForChar(SkUnichar uni, SkString* name);
|
||||
|
||||
/**
|
||||
* For test only.
|
||||
* Load font config from given xml files, instead of those from Android system.
|
||||
*/
|
||||
SK_API void SkUseTestFontConfigFile(const char* mainconf, const char* fallbackconf,
|
||||
const char* fontsdir);
|
||||
|
||||
/**
|
||||
* Given a "current" fontID, return a ref to the next logical typeface
|
||||
* when searching fonts for a given unicode value. Typically the caller
|
||||
* will query a given font, and if a unicode value is not supported, they
|
||||
* will call this, and if 0 is not returned, will search that font, and so
|
||||
* on. This process must be finite, and when the fonthost sees a
|
||||
* font with no logical successor, it must return NULL.
|
||||
*
|
||||
* The original fontID is also provided. This is the initial font that was
|
||||
* stored in the typeface of the caller. It is provided as an aid to choose
|
||||
* the best next logical font. e.g. If the original font was bold or serif,
|
||||
* but the 2nd in the logical chain was plain, then a subsequent call to
|
||||
* get the 3rd can still inspect the original, and try to match its
|
||||
* stylistic attributes.
|
||||
*/
|
||||
SkTypeface* SkAndroidNextLogicalTypeface(SkFontID currFontID, SkFontID origFontID);
|
||||
|
||||
#endif
|
|
@ -1,31 +0,0 @@
|
|||
/*
|
||||
* 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 SkPictureUtils_DEFINED
|
||||
#define SkPictureUtils_DEFINED
|
||||
|
||||
#include "SkPicture.h"
|
||||
|
||||
class SkData;
|
||||
struct SkRect;
|
||||
|
||||
class SK_API SkPictureUtils {
|
||||
public:
|
||||
/**
|
||||
* Given a rectangular visible "window" into the picture, return an array
|
||||
* of SkPixelRefs that might intersect that area. To keep the call fast,
|
||||
* the returned list is not guaranteed to be exact, so it may miss some,
|
||||
* and it may return false positives.
|
||||
*
|
||||
* The pixelrefs returned in the SkData are already owned by the picture,
|
||||
* so the returned pointers are only valid while the picture is in scope
|
||||
* and remains unchanged.
|
||||
*/
|
||||
static SkData* GatherPixelRefs(SkPicture* pict, const SkRect& area);
|
||||
};
|
||||
|
||||
#endif
|
1396
gfx/skia/moz.build
1396
gfx/skia/moz.build
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -1,178 +0,0 @@
|
|||
|
||||
/*
|
||||
* Copyright 2006 The Android Open Source Project
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
|
||||
#include "SkAntiRun.h"
|
||||
#include "SkUtils.h"
|
||||
|
||||
void SkAlphaRuns::reset(int width) {
|
||||
SkASSERT(width > 0);
|
||||
|
||||
#ifdef SK_DEBUG
|
||||
sk_memset16((uint16_t*)fRuns, (uint16_t)(-42), width);
|
||||
#endif
|
||||
fRuns[0] = SkToS16(width);
|
||||
fRuns[width] = 0;
|
||||
fAlpha[0] = 0;
|
||||
|
||||
SkDEBUGCODE(fWidth = width;)
|
||||
SkDEBUGCODE(this->validate();)
|
||||
}
|
||||
|
||||
void SkAlphaRuns::Break(int16_t runs[], uint8_t alpha[], int x, int count) {
|
||||
SkASSERT(count > 0 && x >= 0);
|
||||
|
||||
// SkAlphaRuns::BreakAt(runs, alpha, x);
|
||||
// SkAlphaRuns::BreakAt(&runs[x], &alpha[x], count);
|
||||
|
||||
int16_t* next_runs = runs + x;
|
||||
uint8_t* next_alpha = alpha + x;
|
||||
|
||||
while (x > 0) {
|
||||
int n = runs[0];
|
||||
SkASSERT(n > 0);
|
||||
|
||||
if (x < n) {
|
||||
alpha[x] = alpha[0];
|
||||
runs[0] = SkToS16(x);
|
||||
runs[x] = SkToS16(n - x);
|
||||
break;
|
||||
}
|
||||
runs += n;
|
||||
alpha += n;
|
||||
x -= n;
|
||||
}
|
||||
|
||||
runs = next_runs;
|
||||
alpha = next_alpha;
|
||||
x = count;
|
||||
|
||||
for (;;) {
|
||||
int n = runs[0];
|
||||
SkASSERT(n > 0);
|
||||
|
||||
if (x < n) {
|
||||
alpha[x] = alpha[0];
|
||||
runs[0] = SkToS16(x);
|
||||
runs[x] = SkToS16(n - x);
|
||||
break;
|
||||
}
|
||||
x -= n;
|
||||
if (x <= 0) {
|
||||
break;
|
||||
}
|
||||
runs += n;
|
||||
alpha += n;
|
||||
}
|
||||
}
|
||||
|
||||
int SkAlphaRuns::add(int x, U8CPU startAlpha, int middleCount, U8CPU stopAlpha,
|
||||
U8CPU maxValue, int offsetX) {
|
||||
SkASSERT(middleCount >= 0);
|
||||
SkASSERT(x >= 0 && x + (startAlpha != 0) + middleCount + (stopAlpha != 0) <= fWidth);
|
||||
|
||||
SkASSERT(fRuns[offsetX] >= 0);
|
||||
|
||||
int16_t* runs = fRuns + offsetX;
|
||||
uint8_t* alpha = fAlpha + offsetX;
|
||||
uint8_t* lastAlpha = alpha;
|
||||
x -= offsetX;
|
||||
|
||||
if (startAlpha) {
|
||||
SkAlphaRuns::Break(runs, alpha, x, 1);
|
||||
/* I should be able to just add alpha[x] + startAlpha.
|
||||
However, if the trailing edge of the previous span and the leading
|
||||
edge of the current span round to the same super-sampled x value,
|
||||
I might overflow to 256 with this add, hence the funny subtract (crud).
|
||||
*/
|
||||
unsigned tmp = alpha[x] + startAlpha;
|
||||
SkASSERT(tmp <= 256);
|
||||
alpha[x] = SkToU8(tmp - (tmp >> 8)); // was (tmp >> 7), but that seems wrong if we're trying to catch 256
|
||||
|
||||
runs += x + 1;
|
||||
alpha += x + 1;
|
||||
x = 0;
|
||||
lastAlpha += x; // we don't want the +1
|
||||
SkDEBUGCODE(this->validate();)
|
||||
}
|
||||
|
||||
if (middleCount) {
|
||||
SkAlphaRuns::Break(runs, alpha, x, middleCount);
|
||||
alpha += x;
|
||||
runs += x;
|
||||
x = 0;
|
||||
do {
|
||||
alpha[0] = SkToU8(alpha[0] + maxValue);
|
||||
int n = runs[0];
|
||||
SkASSERT(n <= middleCount);
|
||||
alpha += n;
|
||||
runs += n;
|
||||
middleCount -= n;
|
||||
} while (middleCount > 0);
|
||||
SkDEBUGCODE(this->validate();)
|
||||
lastAlpha = alpha;
|
||||
}
|
||||
|
||||
if (stopAlpha) {
|
||||
SkAlphaRuns::Break(runs, alpha, x, 1);
|
||||
alpha += x;
|
||||
alpha[0] = SkToU8(alpha[0] + stopAlpha);
|
||||
SkDEBUGCODE(this->validate();)
|
||||
lastAlpha = alpha;
|
||||
}
|
||||
|
||||
return SkToS32(lastAlpha - fAlpha); // new offsetX
|
||||
}
|
||||
|
||||
#ifdef SK_DEBUG
|
||||
void SkAlphaRuns::assertValid(int y, int maxStep) const {
|
||||
int max = (y + 1) * maxStep - (y == maxStep - 1);
|
||||
|
||||
const int16_t* runs = fRuns;
|
||||
const uint8_t* alpha = fAlpha;
|
||||
|
||||
while (*runs) {
|
||||
SkASSERT(*alpha <= max);
|
||||
alpha += *runs;
|
||||
runs += *runs;
|
||||
}
|
||||
}
|
||||
|
||||
void SkAlphaRuns::dump() const {
|
||||
const int16_t* runs = fRuns;
|
||||
const uint8_t* alpha = fAlpha;
|
||||
|
||||
SkDebugf("Runs");
|
||||
while (*runs) {
|
||||
int n = *runs;
|
||||
|
||||
SkDebugf(" %02x", *alpha);
|
||||
if (n > 1) {
|
||||
SkDebugf(",%d", n);
|
||||
}
|
||||
alpha += n;
|
||||
runs += n;
|
||||
}
|
||||
SkDebugf("\n");
|
||||
}
|
||||
|
||||
void SkAlphaRuns::validate() const {
|
||||
SkASSERT(fWidth > 0);
|
||||
|
||||
int count = 0;
|
||||
const int16_t* runs = fRuns;
|
||||
|
||||
while (*runs) {
|
||||
SkASSERT(*runs > 0);
|
||||
count += *runs;
|
||||
SkASSERT(count <= fWidth);
|
||||
runs += *runs;
|
||||
}
|
||||
SkASSERT(count == fWidth);
|
||||
}
|
||||
#endif
|
|
@ -1,92 +0,0 @@
|
|||
|
||||
/*
|
||||
* Copyright 2006 The Android Open Source Project
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef SkAntiRun_DEFINED
|
||||
#define SkAntiRun_DEFINED
|
||||
|
||||
#include "SkBlitter.h"
|
||||
|
||||
/** Sparse array of run-length-encoded alpha (supersampling coverage) values.
|
||||
Sparseness allows us to independently compose several paths into the
|
||||
same SkAlphaRuns buffer.
|
||||
*/
|
||||
|
||||
class SkAlphaRuns {
|
||||
public:
|
||||
int16_t* fRuns;
|
||||
uint8_t* fAlpha;
|
||||
|
||||
/// Returns true if the scanline contains only a single run,
|
||||
/// of alpha value 0.
|
||||
bool empty() const {
|
||||
SkASSERT(fRuns[0] > 0);
|
||||
return fAlpha[0] == 0 && fRuns[fRuns[0]] == 0;
|
||||
}
|
||||
|
||||
/// Reinitialize for a new scanline.
|
||||
void reset(int width);
|
||||
|
||||
/**
|
||||
* Insert into the buffer a run starting at (x-offsetX):
|
||||
* if startAlpha > 0
|
||||
* one pixel with value += startAlpha,
|
||||
* max 255
|
||||
* if middleCount > 0
|
||||
* middleCount pixels with value += maxValue
|
||||
* if stopAlpha > 0
|
||||
* one pixel with value += stopAlpha
|
||||
* Returns the offsetX value that should be passed on the next call,
|
||||
* assuming we're on the same scanline. If the caller is switching
|
||||
* scanlines, then offsetX should be 0 when this is called.
|
||||
*/
|
||||
int add(int x, U8CPU startAlpha, int middleCount, U8CPU stopAlpha,
|
||||
U8CPU maxValue, int offsetX);
|
||||
|
||||
SkDEBUGCODE(void assertValid(int y, int maxStep) const;)
|
||||
SkDEBUGCODE(void dump() const;)
|
||||
|
||||
/**
|
||||
* Break the runs in the buffer at offsets x and x+count, properly
|
||||
* updating the runs to the right and left.
|
||||
* i.e. from the state AAAABBBB, run-length encoded as A4B4,
|
||||
* Break(..., 2, 5) would produce AAAABBBB rle as A2A2B3B1.
|
||||
* Allows add() to sum another run to some of the new sub-runs.
|
||||
* i.e. adding ..CCCCC. would produce AADDEEEB, rle as A2D2E3B1.
|
||||
*/
|
||||
static void Break(int16_t runs[], uint8_t alpha[], int x, int count);
|
||||
|
||||
/**
|
||||
* Cut (at offset x in the buffer) a run into two shorter runs with
|
||||
* matching alpha values.
|
||||
* Used by the RectClipBlitter to trim a RLE encoding to match the
|
||||
* clipping rectangle.
|
||||
*/
|
||||
static void BreakAt(int16_t runs[], uint8_t alpha[], int x) {
|
||||
while (x > 0) {
|
||||
int n = runs[0];
|
||||
SkASSERT(n > 0);
|
||||
|
||||
if (x < n) {
|
||||
alpha[x] = alpha[0];
|
||||
runs[0] = SkToS16(x);
|
||||
runs[x] = SkToS16(n - x);
|
||||
break;
|
||||
}
|
||||
runs += n;
|
||||
alpha += n;
|
||||
x -= n;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
SkDEBUGCODE(int fWidth;)
|
||||
SkDEBUGCODE(void validate() const;)
|
||||
};
|
||||
|
||||
#endif
|
|
@ -1,11 +0,0 @@
|
|||
|
||||
/*
|
||||
* 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 "SkBBoxHierarchy.h"
|
||||
|
||||
SK_DEFINE_INST_COUNT(SkBBoxHierarchy)
|
|
@ -1,720 +0,0 @@
|
|||
|
||||
/*
|
||||
* Copyright 2011 Google Inc.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
#include "SkBitmapProcState.h"
|
||||
#include "SkColorPriv.h"
|
||||
#include "SkFilterProc.h"
|
||||
#include "SkPaint.h"
|
||||
#include "SkShader.h" // for tilemodes
|
||||
#include "SkUtilsArm.h"
|
||||
|
||||
#if !SK_ARM_NEON_IS_NONE
|
||||
// These are defined in src/opts/SkBitmapProcState_arm_neon.cpp
|
||||
extern const SkBitmapProcState::SampleProc16 gSkBitmapProcStateSample16_neon[];
|
||||
extern const SkBitmapProcState::SampleProc32 gSkBitmapProcStateSample32_neon[];
|
||||
extern void S16_D16_filter_DX_neon(const SkBitmapProcState&, const uint32_t*, int, uint16_t*);
|
||||
extern void Clamp_S16_D16_filter_DX_shaderproc_neon(const SkBitmapProcState&, int, int, uint16_t*, int);
|
||||
extern void Repeat_S16_D16_filter_DX_shaderproc_neon(const SkBitmapProcState&, int, int, uint16_t*, int);
|
||||
extern void SI8_opaque_D32_filter_DX_neon(const SkBitmapProcState&, const uint32_t*, int, SkPMColor*);
|
||||
extern void SI8_opaque_D32_filter_DX_shaderproc_neon(const SkBitmapProcState&, int, int, uint32_t*, int);
|
||||
extern void Clamp_SI8_opaque_D32_filter_DX_shaderproc_neon(const SkBitmapProcState&, int, int, uint32_t*, int);
|
||||
#endif
|
||||
|
||||
#define NAME_WRAP(x) x
|
||||
#include "SkBitmapProcState_filter.h"
|
||||
#include "SkBitmapProcState_procs.h"
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/**
|
||||
* For the purposes of drawing bitmaps, if a matrix is "almost" translate
|
||||
* go ahead and treat it as if it were, so that subsequent code can go fast.
|
||||
*/
|
||||
static bool just_trans_clamp(const SkMatrix& matrix, const SkBitmap& bitmap) {
|
||||
SkMatrix::TypeMask mask = matrix.getType();
|
||||
|
||||
if (mask & (SkMatrix::kAffine_Mask | SkMatrix::kPerspective_Mask)) {
|
||||
return false;
|
||||
}
|
||||
if (mask & SkMatrix::kScale_Mask) {
|
||||
SkScalar sx = matrix[SkMatrix::kMScaleX];
|
||||
SkScalar sy = matrix[SkMatrix::kMScaleY];
|
||||
int w = bitmap.width();
|
||||
int h = bitmap.height();
|
||||
int sw = SkScalarRound(SkScalarMul(sx, SkIntToScalar(w)));
|
||||
int sh = SkScalarRound(SkScalarMul(sy, SkIntToScalar(h)));
|
||||
return sw == w && sh == h;
|
||||
}
|
||||
// if we got here, we're either kTranslate_Mask or identity
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool just_trans_general(const SkMatrix& matrix) {
|
||||
SkMatrix::TypeMask mask = matrix.getType();
|
||||
|
||||
if (mask & (SkMatrix::kAffine_Mask | SkMatrix::kPerspective_Mask)) {
|
||||
return false;
|
||||
}
|
||||
if (mask & SkMatrix::kScale_Mask) {
|
||||
const SkScalar tol = SK_Scalar1 / 32768;
|
||||
|
||||
if (!SkScalarNearlyZero(matrix[SkMatrix::kMScaleX] - SK_Scalar1, tol)) {
|
||||
return false;
|
||||
}
|
||||
if (!SkScalarNearlyZero(matrix[SkMatrix::kMScaleY] - SK_Scalar1, tol)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// if we got here, treat us as either kTranslate_Mask or identity
|
||||
return true;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static bool valid_for_filtering(unsigned dimension) {
|
||||
// for filtering, width and height must fit in 14bits, since we use steal
|
||||
// 2 bits from each to store our 4bit subpixel data
|
||||
return (dimension & ~0x3FFF) == 0;
|
||||
}
|
||||
|
||||
bool SkBitmapProcState::chooseProcs(const SkMatrix& inv, const SkPaint& paint) {
|
||||
if (fOrigBitmap.width() == 0 || fOrigBitmap.height() == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const SkMatrix* m;
|
||||
bool trivial_matrix = (inv.getType() & ~SkMatrix::kTranslate_Mask) == 0;
|
||||
bool clamp_clamp = SkShader::kClamp_TileMode == fTileModeX &&
|
||||
SkShader::kClamp_TileMode == fTileModeY;
|
||||
|
||||
if (clamp_clamp || trivial_matrix) {
|
||||
m = &inv;
|
||||
} else {
|
||||
fUnitInvMatrix = inv;
|
||||
fUnitInvMatrix.postIDiv(fOrigBitmap.width(), fOrigBitmap.height());
|
||||
m = &fUnitInvMatrix;
|
||||
}
|
||||
|
||||
fBitmap = &fOrigBitmap;
|
||||
if (fOrigBitmap.hasMipMap()) {
|
||||
int shift = fOrigBitmap.extractMipLevel(&fMipBitmap,
|
||||
SkScalarToFixed(m->getScaleX()),
|
||||
SkScalarToFixed(m->getSkewY()));
|
||||
|
||||
if (shift > 0) {
|
||||
if (m != &fUnitInvMatrix) {
|
||||
fUnitInvMatrix = *m;
|
||||
m = &fUnitInvMatrix;
|
||||
}
|
||||
|
||||
SkScalar scale = SkFixedToScalar(SK_Fixed1 >> shift);
|
||||
fUnitInvMatrix.postScale(scale, scale);
|
||||
|
||||
// now point here instead of fOrigBitmap
|
||||
fBitmap = &fMipBitmap;
|
||||
}
|
||||
}
|
||||
|
||||
// wack our matrix to exactly no-scale, if we're really close to begin with
|
||||
{
|
||||
bool fixupMatrix = clamp_clamp ?
|
||||
just_trans_clamp(*m, *fBitmap) : just_trans_general(*m);
|
||||
if (fixupMatrix) {
|
||||
// If we can be treated just like translate, construct that inverse
|
||||
// such that we landed in the proper place. Given that m may have
|
||||
// some slight scale, we have to invert it to compute this new
|
||||
// matrix.
|
||||
SkMatrix forward;
|
||||
if (m->invert(&forward)) {
|
||||
SkScalar tx = -SkScalarRoundToScalar(forward.getTranslateX());
|
||||
SkScalar ty = -SkScalarRoundToScalar(forward.getTranslateY());
|
||||
fUnitInvMatrix.setTranslate(tx, ty);
|
||||
m = &fUnitInvMatrix;
|
||||
// now the following code will sniff m, and decide to take the
|
||||
// fast case (since m is purely translate).
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Below this point, we should never refer to the inv parameter, since we
|
||||
// may be using a munged version for "our" inverse.
|
||||
|
||||
fInvMatrix = m;
|
||||
fInvProc = m->getMapXYProc();
|
||||
fInvType = m->getType();
|
||||
fInvSx = SkScalarToFixed(m->getScaleX());
|
||||
fInvSxFractionalInt = SkScalarToFractionalInt(m->getScaleX());
|
||||
fInvKy = SkScalarToFixed(m->getSkewY());
|
||||
fInvKyFractionalInt = SkScalarToFractionalInt(m->getSkewY());
|
||||
|
||||
fAlphaScale = SkAlpha255To256(paint.getAlpha());
|
||||
|
||||
// pick-up filtering from the paint, but only if the matrix is
|
||||
// more complex than identity/translate (i.e. no need to pay the cost
|
||||
// of filtering if we're not scaled etc.).
|
||||
// note: we explicitly check inv, since m might be scaled due to unitinv
|
||||
// trickery, but we don't want to see that for this test
|
||||
fDoFilter = paint.isFilterBitmap() &&
|
||||
(fInvType > SkMatrix::kTranslate_Mask &&
|
||||
valid_for_filtering(fBitmap->width() | fBitmap->height()));
|
||||
|
||||
fShaderProc32 = NULL;
|
||||
fShaderProc16 = NULL;
|
||||
fSampleProc32 = NULL;
|
||||
fSampleProc16 = NULL;
|
||||
|
||||
fMatrixProc = this->chooseMatrixProc(trivial_matrix);
|
||||
if (NULL == fMatrixProc) {
|
||||
return false;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
|
||||
int index = 0;
|
||||
if (fAlphaScale < 256) { // note: this distinction is not used for D16
|
||||
index |= 1;
|
||||
}
|
||||
if (fInvType <= (SkMatrix::kTranslate_Mask | SkMatrix::kScale_Mask)) {
|
||||
index |= 2;
|
||||
}
|
||||
if (fDoFilter) {
|
||||
index |= 4;
|
||||
}
|
||||
// bits 3,4,5 encoding the source bitmap format
|
||||
switch (fBitmap->config()) {
|
||||
case SkBitmap::kARGB_8888_Config:
|
||||
index |= 0;
|
||||
break;
|
||||
case SkBitmap::kRGB_565_Config:
|
||||
index |= 8;
|
||||
break;
|
||||
case SkBitmap::kIndex8_Config:
|
||||
index |= 16;
|
||||
break;
|
||||
case SkBitmap::kARGB_4444_Config:
|
||||
index |= 24;
|
||||
break;
|
||||
case SkBitmap::kA8_Config:
|
||||
index |= 32;
|
||||
fPaintPMColor = SkPreMultiplyColor(paint.getColor());
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
#if !SK_ARM_NEON_IS_ALWAYS
|
||||
static const SampleProc32 gSkBitmapProcStateSample32[] = {
|
||||
S32_opaque_D32_nofilter_DXDY,
|
||||
S32_alpha_D32_nofilter_DXDY,
|
||||
S32_opaque_D32_nofilter_DX,
|
||||
S32_alpha_D32_nofilter_DX,
|
||||
S32_opaque_D32_filter_DXDY,
|
||||
S32_alpha_D32_filter_DXDY,
|
||||
S32_opaque_D32_filter_DX,
|
||||
S32_alpha_D32_filter_DX,
|
||||
|
||||
S16_opaque_D32_nofilter_DXDY,
|
||||
S16_alpha_D32_nofilter_DXDY,
|
||||
S16_opaque_D32_nofilter_DX,
|
||||
S16_alpha_D32_nofilter_DX,
|
||||
S16_opaque_D32_filter_DXDY,
|
||||
S16_alpha_D32_filter_DXDY,
|
||||
S16_opaque_D32_filter_DX,
|
||||
S16_alpha_D32_filter_DX,
|
||||
|
||||
SI8_opaque_D32_nofilter_DXDY,
|
||||
SI8_alpha_D32_nofilter_DXDY,
|
||||
SI8_opaque_D32_nofilter_DX,
|
||||
SI8_alpha_D32_nofilter_DX,
|
||||
SI8_opaque_D32_filter_DXDY,
|
||||
SI8_alpha_D32_filter_DXDY,
|
||||
SI8_opaque_D32_filter_DX,
|
||||
SI8_alpha_D32_filter_DX,
|
||||
|
||||
S4444_opaque_D32_nofilter_DXDY,
|
||||
S4444_alpha_D32_nofilter_DXDY,
|
||||
S4444_opaque_D32_nofilter_DX,
|
||||
S4444_alpha_D32_nofilter_DX,
|
||||
S4444_opaque_D32_filter_DXDY,
|
||||
S4444_alpha_D32_filter_DXDY,
|
||||
S4444_opaque_D32_filter_DX,
|
||||
S4444_alpha_D32_filter_DX,
|
||||
|
||||
// A8 treats alpha/opaque the same (equally efficient)
|
||||
SA8_alpha_D32_nofilter_DXDY,
|
||||
SA8_alpha_D32_nofilter_DXDY,
|
||||
SA8_alpha_D32_nofilter_DX,
|
||||
SA8_alpha_D32_nofilter_DX,
|
||||
SA8_alpha_D32_filter_DXDY,
|
||||
SA8_alpha_D32_filter_DXDY,
|
||||
SA8_alpha_D32_filter_DX,
|
||||
SA8_alpha_D32_filter_DX
|
||||
};
|
||||
|
||||
static const SampleProc16 gSkBitmapProcStateSample16[] = {
|
||||
S32_D16_nofilter_DXDY,
|
||||
S32_D16_nofilter_DX,
|
||||
S32_D16_filter_DXDY,
|
||||
S32_D16_filter_DX,
|
||||
|
||||
S16_D16_nofilter_DXDY,
|
||||
S16_D16_nofilter_DX,
|
||||
S16_D16_filter_DXDY,
|
||||
S16_D16_filter_DX,
|
||||
|
||||
SI8_D16_nofilter_DXDY,
|
||||
SI8_D16_nofilter_DX,
|
||||
SI8_D16_filter_DXDY,
|
||||
SI8_D16_filter_DX,
|
||||
|
||||
// Don't support 4444 -> 565
|
||||
NULL, NULL, NULL, NULL,
|
||||
// Don't support A8 -> 565
|
||||
NULL, NULL, NULL, NULL
|
||||
};
|
||||
#endif
|
||||
|
||||
fSampleProc32 = SK_ARM_NEON_WRAP(gSkBitmapProcStateSample32)[index];
|
||||
index >>= 1; // shift away any opaque/alpha distinction
|
||||
fSampleProc16 = SK_ARM_NEON_WRAP(gSkBitmapProcStateSample16)[index];
|
||||
|
||||
// our special-case shaderprocs
|
||||
if (SK_ARM_NEON_WRAP(S16_D16_filter_DX) == fSampleProc16) {
|
||||
if (clamp_clamp) {
|
||||
fShaderProc16 = SK_ARM_NEON_WRAP(Clamp_S16_D16_filter_DX_shaderproc);
|
||||
} else if (SkShader::kRepeat_TileMode == fTileModeX &&
|
||||
SkShader::kRepeat_TileMode == fTileModeY) {
|
||||
fShaderProc16 = SK_ARM_NEON_WRAP(Repeat_S16_D16_filter_DX_shaderproc);
|
||||
}
|
||||
} else if (SK_ARM_NEON_WRAP(SI8_opaque_D32_filter_DX) == fSampleProc32 && clamp_clamp) {
|
||||
fShaderProc32 = SK_ARM_NEON_WRAP(Clamp_SI8_opaque_D32_filter_DX_shaderproc);
|
||||
}
|
||||
|
||||
if (NULL == fShaderProc32) {
|
||||
fShaderProc32 = this->chooseShaderProc32();
|
||||
}
|
||||
|
||||
// see if our platform has any accelerated overrides
|
||||
this->platformProcs();
|
||||
return true;
|
||||
}
|
||||
|
||||
static void Clamp_S32_D32_nofilter_trans_shaderproc(const SkBitmapProcState& s,
|
||||
int x, int y,
|
||||
SkPMColor* SK_RESTRICT colors,
|
||||
int count) {
|
||||
SkASSERT(((s.fInvType & ~SkMatrix::kTranslate_Mask)) == 0);
|
||||
SkASSERT(s.fInvKy == 0);
|
||||
SkASSERT(count > 0 && colors != NULL);
|
||||
SkASSERT(!s.fDoFilter);
|
||||
|
||||
const int maxX = s.fBitmap->width() - 1;
|
||||
const int maxY = s.fBitmap->height() - 1;
|
||||
int ix = s.fFilterOneX + x;
|
||||
int iy = SkClampMax(s.fFilterOneY + y, maxY);
|
||||
#ifdef SK_DEBUG
|
||||
{
|
||||
SkPoint pt;
|
||||
s.fInvProc(*s.fInvMatrix, SkIntToScalar(x) + SK_ScalarHalf,
|
||||
SkIntToScalar(y) + SK_ScalarHalf, &pt);
|
||||
int iy2 = SkClampMax(SkScalarFloorToInt(pt.fY), maxY);
|
||||
int ix2 = SkScalarFloorToInt(pt.fX);
|
||||
|
||||
SkASSERT(iy == iy2);
|
||||
SkASSERT(ix == ix2);
|
||||
}
|
||||
#endif
|
||||
const SkPMColor* row = s.fBitmap->getAddr32(0, iy);
|
||||
|
||||
// clamp to the left
|
||||
if (ix < 0) {
|
||||
int n = SkMin32(-ix, count);
|
||||
sk_memset32(colors, row[0], n);
|
||||
count -= n;
|
||||
if (0 == count) {
|
||||
return;
|
||||
}
|
||||
colors += n;
|
||||
SkASSERT(-ix == n);
|
||||
ix = 0;
|
||||
}
|
||||
// copy the middle
|
||||
if (ix <= maxX) {
|
||||
int n = SkMin32(maxX - ix + 1, count);
|
||||
memcpy(colors, row + ix, n * sizeof(SkPMColor));
|
||||
count -= n;
|
||||
if (0 == count) {
|
||||
return;
|
||||
}
|
||||
colors += n;
|
||||
}
|
||||
SkASSERT(count > 0);
|
||||
// clamp to the right
|
||||
sk_memset32(colors, row[maxX], count);
|
||||
}
|
||||
|
||||
static inline int sk_int_mod(int x, int n) {
|
||||
SkASSERT(n > 0);
|
||||
if ((unsigned)x >= (unsigned)n) {
|
||||
if (x < 0) {
|
||||
x = n + ~(~x % n);
|
||||
} else {
|
||||
x = x % n;
|
||||
}
|
||||
}
|
||||
return x;
|
||||
}
|
||||
|
||||
static inline int sk_int_mirror(int x, int n) {
|
||||
x = sk_int_mod(x, 2 * n);
|
||||
if (x >= n) {
|
||||
x = n + ~(x - n);
|
||||
}
|
||||
return x;
|
||||
}
|
||||
|
||||
static void Repeat_S32_D32_nofilter_trans_shaderproc(const SkBitmapProcState& s,
|
||||
int x, int y,
|
||||
SkPMColor* SK_RESTRICT colors,
|
||||
int count) {
|
||||
SkASSERT(((s.fInvType & ~SkMatrix::kTranslate_Mask)) == 0);
|
||||
SkASSERT(s.fInvKy == 0);
|
||||
SkASSERT(count > 0 && colors != NULL);
|
||||
SkASSERT(!s.fDoFilter);
|
||||
|
||||
const int stopX = s.fBitmap->width();
|
||||
const int stopY = s.fBitmap->height();
|
||||
int ix = s.fFilterOneX + x;
|
||||
int iy = sk_int_mod(s.fFilterOneY + y, stopY);
|
||||
#ifdef SK_DEBUG
|
||||
{
|
||||
SkPoint pt;
|
||||
s.fInvProc(*s.fInvMatrix, SkIntToScalar(x) + SK_ScalarHalf,
|
||||
SkIntToScalar(y) + SK_ScalarHalf, &pt);
|
||||
int iy2 = sk_int_mod(SkScalarFloorToInt(pt.fY), stopY);
|
||||
int ix2 = SkScalarFloorToInt(pt.fX);
|
||||
|
||||
SkASSERT(iy == iy2);
|
||||
SkASSERT(ix == ix2);
|
||||
}
|
||||
#endif
|
||||
const SkPMColor* row = s.fBitmap->getAddr32(0, iy);
|
||||
|
||||
ix = sk_int_mod(ix, stopX);
|
||||
for (;;) {
|
||||
int n = SkMin32(stopX - ix, count);
|
||||
memcpy(colors, row + ix, n * sizeof(SkPMColor));
|
||||
count -= n;
|
||||
if (0 == count) {
|
||||
return;
|
||||
}
|
||||
colors += n;
|
||||
ix = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void S32_D32_constX_shaderproc(const SkBitmapProcState& s,
|
||||
int x, int y,
|
||||
SkPMColor* SK_RESTRICT colors,
|
||||
int count) {
|
||||
SkASSERT((s.fInvType & ~(SkMatrix::kTranslate_Mask | SkMatrix::kScale_Mask)) == 0);
|
||||
SkASSERT(s.fInvKy == 0);
|
||||
SkASSERT(count > 0 && colors != NULL);
|
||||
SkASSERT(1 == s.fBitmap->width());
|
||||
|
||||
int iY0;
|
||||
int iY1 SK_INIT_TO_AVOID_WARNING;
|
||||
int iSubY SK_INIT_TO_AVOID_WARNING;
|
||||
|
||||
if (s.fDoFilter) {
|
||||
SkBitmapProcState::MatrixProc mproc = s.getMatrixProc();
|
||||
uint32_t xy[2];
|
||||
|
||||
mproc(s, xy, 1, x, y);
|
||||
|
||||
iY0 = xy[0] >> 18;
|
||||
iY1 = xy[0] & 0x3FFF;
|
||||
iSubY = (xy[0] >> 14) & 0xF;
|
||||
} else {
|
||||
int yTemp;
|
||||
|
||||
if (s.fInvType > SkMatrix::kTranslate_Mask) {
|
||||
SkPoint pt;
|
||||
s.fInvProc(*s.fInvMatrix,
|
||||
SkIntToScalar(x) + SK_ScalarHalf,
|
||||
SkIntToScalar(y) + SK_ScalarHalf,
|
||||
&pt);
|
||||
// When the matrix has a scale component the setup code in
|
||||
// chooseProcs multiples the inverse matrix by the inverse of the
|
||||
// bitmap's width and height. Since this method is going to do
|
||||
// its own tiling and sampling we need to undo that here.
|
||||
if (SkShader::kClamp_TileMode != s.fTileModeX ||
|
||||
SkShader::kClamp_TileMode != s.fTileModeY) {
|
||||
yTemp = SkScalarFloorToInt(pt.fY * s.fBitmap->height());
|
||||
} else {
|
||||
yTemp = SkScalarFloorToInt(pt.fY);
|
||||
}
|
||||
} else {
|
||||
yTemp = s.fFilterOneY + y;
|
||||
}
|
||||
|
||||
const int stopY = s.fBitmap->height();
|
||||
switch (s.fTileModeY) {
|
||||
case SkShader::kClamp_TileMode:
|
||||
iY0 = SkClampMax(yTemp, stopY-1);
|
||||
break;
|
||||
case SkShader::kRepeat_TileMode:
|
||||
iY0 = sk_int_mod(yTemp, stopY);
|
||||
break;
|
||||
case SkShader::kMirror_TileMode:
|
||||
default:
|
||||
iY0 = sk_int_mirror(yTemp, stopY);
|
||||
break;
|
||||
}
|
||||
|
||||
#ifdef SK_DEBUG
|
||||
{
|
||||
SkPoint pt;
|
||||
s.fInvProc(*s.fInvMatrix,
|
||||
SkIntToScalar(x) + SK_ScalarHalf,
|
||||
SkIntToScalar(y) + SK_ScalarHalf,
|
||||
&pt);
|
||||
if (s.fInvType > SkMatrix::kTranslate_Mask &&
|
||||
(SkShader::kClamp_TileMode != s.fTileModeX ||
|
||||
SkShader::kClamp_TileMode != s.fTileModeY)) {
|
||||
pt.fY *= s.fBitmap->height();
|
||||
}
|
||||
int iY2;
|
||||
|
||||
switch (s.fTileModeY) {
|
||||
case SkShader::kClamp_TileMode:
|
||||
iY2 = SkClampMax(SkScalarFloorToInt(pt.fY), stopY-1);
|
||||
break;
|
||||
case SkShader::kRepeat_TileMode:
|
||||
iY2 = sk_int_mod(SkScalarFloorToInt(pt.fY), stopY);
|
||||
break;
|
||||
case SkShader::kMirror_TileMode:
|
||||
default:
|
||||
iY2 = sk_int_mirror(SkScalarFloorToInt(pt.fY), stopY);
|
||||
break;
|
||||
}
|
||||
|
||||
SkASSERT(iY0 == iY2);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
const SkPMColor* row0 = s.fBitmap->getAddr32(0, iY0);
|
||||
SkPMColor color;
|
||||
|
||||
if (s.fDoFilter) {
|
||||
const SkPMColor* row1 = s.fBitmap->getAddr32(0, iY1);
|
||||
|
||||
if (s.fAlphaScale < 256) {
|
||||
Filter_32_alpha(iSubY, *row0, *row1, &color, s.fAlphaScale);
|
||||
} else {
|
||||
Filter_32_opaque(iSubY, *row0, *row1, &color);
|
||||
}
|
||||
} else {
|
||||
if (s.fAlphaScale < 256) {
|
||||
color = SkAlphaMulQ(*row0, s.fAlphaScale);
|
||||
} else {
|
||||
color = *row0;
|
||||
}
|
||||
}
|
||||
|
||||
sk_memset32(colors, color, count);
|
||||
}
|
||||
|
||||
static void DoNothing_shaderproc(const SkBitmapProcState&, int x, int y,
|
||||
SkPMColor* SK_RESTRICT colors, int count) {
|
||||
// if we get called, the matrix is too tricky, so we just draw nothing
|
||||
sk_memset32(colors, 0, count);
|
||||
}
|
||||
|
||||
bool SkBitmapProcState::setupForTranslate() {
|
||||
SkPoint pt;
|
||||
fInvProc(*fInvMatrix, SK_ScalarHalf, SK_ScalarHalf, &pt);
|
||||
|
||||
/*
|
||||
* if the translate is larger than our ints, we can get random results, or
|
||||
* worse, we might get 0x80000000, which wreaks havoc on us, since we can't
|
||||
* negate it.
|
||||
*/
|
||||
const SkScalar too_big = SkIntToScalar(1 << 30);
|
||||
if (SkScalarAbs(pt.fX) > too_big || SkScalarAbs(pt.fY) > too_big) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Since we know we're not filtered, we re-purpose these fields allow
|
||||
// us to go from device -> src coordinates w/ just an integer add,
|
||||
// rather than running through the inverse-matrix
|
||||
fFilterOneX = SkScalarFloorToInt(pt.fX);
|
||||
fFilterOneY = SkScalarFloorToInt(pt.fY);
|
||||
return true;
|
||||
}
|
||||
|
||||
SkBitmapProcState::ShaderProc32 SkBitmapProcState::chooseShaderProc32() {
|
||||
|
||||
if (SkBitmap::kARGB_8888_Config != fBitmap->config()) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static const unsigned kMask = SkMatrix::kTranslate_Mask | SkMatrix::kScale_Mask;
|
||||
|
||||
if (1 == fBitmap->width() && 0 == (fInvType & ~kMask)) {
|
||||
if (!fDoFilter && fInvType <= SkMatrix::kTranslate_Mask && !this->setupForTranslate()) {
|
||||
return DoNothing_shaderproc;
|
||||
}
|
||||
return S32_D32_constX_shaderproc;
|
||||
}
|
||||
|
||||
if (fAlphaScale < 256) {
|
||||
return NULL;
|
||||
}
|
||||
if (fInvType > SkMatrix::kTranslate_Mask) {
|
||||
return NULL;
|
||||
}
|
||||
if (fDoFilter) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
SkShader::TileMode tx = (SkShader::TileMode)fTileModeX;
|
||||
SkShader::TileMode ty = (SkShader::TileMode)fTileModeY;
|
||||
|
||||
if (SkShader::kClamp_TileMode == tx && SkShader::kClamp_TileMode == ty) {
|
||||
if (this->setupForTranslate()) {
|
||||
return Clamp_S32_D32_nofilter_trans_shaderproc;
|
||||
}
|
||||
return DoNothing_shaderproc;
|
||||
}
|
||||
if (SkShader::kRepeat_TileMode == tx && SkShader::kRepeat_TileMode == ty) {
|
||||
if (this->setupForTranslate()) {
|
||||
return Repeat_S32_D32_nofilter_trans_shaderproc;
|
||||
}
|
||||
return DoNothing_shaderproc;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifdef SK_DEBUG
|
||||
|
||||
static void check_scale_nofilter(uint32_t bitmapXY[], int count,
|
||||
unsigned mx, unsigned my) {
|
||||
unsigned y = *bitmapXY++;
|
||||
SkASSERT(y < my);
|
||||
|
||||
const uint16_t* xptr = reinterpret_cast<const uint16_t*>(bitmapXY);
|
||||
for (int i = 0; i < count; ++i) {
|
||||
SkASSERT(xptr[i] < mx);
|
||||
}
|
||||
}
|
||||
|
||||
static void check_scale_filter(uint32_t bitmapXY[], int count,
|
||||
unsigned mx, unsigned my) {
|
||||
uint32_t YY = *bitmapXY++;
|
||||
unsigned y0 = YY >> 18;
|
||||
unsigned y1 = YY & 0x3FFF;
|
||||
SkASSERT(y0 < my);
|
||||
SkASSERT(y1 < my);
|
||||
|
||||
for (int i = 0; i < count; ++i) {
|
||||
uint32_t XX = bitmapXY[i];
|
||||
unsigned x0 = XX >> 18;
|
||||
unsigned x1 = XX & 0x3FFF;
|
||||
SkASSERT(x0 < mx);
|
||||
SkASSERT(x1 < mx);
|
||||
}
|
||||
}
|
||||
|
||||
static void check_affine_nofilter(uint32_t bitmapXY[], int count,
|
||||
unsigned mx, unsigned my) {
|
||||
for (int i = 0; i < count; ++i) {
|
||||
uint32_t XY = bitmapXY[i];
|
||||
unsigned x = XY & 0xFFFF;
|
||||
unsigned y = XY >> 16;
|
||||
SkASSERT(x < mx);
|
||||
SkASSERT(y < my);
|
||||
}
|
||||
}
|
||||
|
||||
static void check_affine_filter(uint32_t bitmapXY[], int count,
|
||||
unsigned mx, unsigned my) {
|
||||
for (int i = 0; i < count; ++i) {
|
||||
uint32_t YY = *bitmapXY++;
|
||||
unsigned y0 = YY >> 18;
|
||||
unsigned y1 = YY & 0x3FFF;
|
||||
SkASSERT(y0 < my);
|
||||
SkASSERT(y1 < my);
|
||||
|
||||
uint32_t XX = *bitmapXY++;
|
||||
unsigned x0 = XX >> 18;
|
||||
unsigned x1 = XX & 0x3FFF;
|
||||
SkASSERT(x0 < mx);
|
||||
SkASSERT(x1 < mx);
|
||||
}
|
||||
}
|
||||
|
||||
void SkBitmapProcState::DebugMatrixProc(const SkBitmapProcState& state,
|
||||
uint32_t bitmapXY[], int count,
|
||||
int x, int y) {
|
||||
SkASSERT(bitmapXY);
|
||||
SkASSERT(count > 0);
|
||||
|
||||
state.fMatrixProc(state, bitmapXY, count, x, y);
|
||||
|
||||
void (*proc)(uint32_t bitmapXY[], int count, unsigned mx, unsigned my);
|
||||
|
||||
// There are four formats possible:
|
||||
// scale -vs- affine
|
||||
// filter -vs- nofilter
|
||||
if (state.fInvType <= (SkMatrix::kTranslate_Mask | SkMatrix::kScale_Mask)) {
|
||||
proc = state.fDoFilter ? check_scale_filter : check_scale_nofilter;
|
||||
} else {
|
||||
proc = state.fDoFilter ? check_affine_filter : check_affine_nofilter;
|
||||
}
|
||||
proc(bitmapXY, count, state.fBitmap->width(), state.fBitmap->height());
|
||||
}
|
||||
|
||||
SkBitmapProcState::MatrixProc SkBitmapProcState::getMatrixProc() const {
|
||||
return DebugMatrixProc;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
/*
|
||||
The storage requirements for the different matrix procs are as follows,
|
||||
where each X or Y is 2 bytes, and N is the number of pixels/elements:
|
||||
|
||||
scale/translate nofilter Y(4bytes) + N * X
|
||||
affine/perspective nofilter N * (X Y)
|
||||
scale/translate filter Y Y + N * (X X)
|
||||
affine/perspective filter N * (Y Y X X)
|
||||
*/
|
||||
int SkBitmapProcState::maxCountForBufferSize(size_t bufferSize) const {
|
||||
int32_t size = static_cast<int32_t>(bufferSize);
|
||||
|
||||
size &= ~3; // only care about 4-byte aligned chunks
|
||||
if (fInvType <= (SkMatrix::kTranslate_Mask | SkMatrix::kScale_Mask)) {
|
||||
size -= 4; // the shared Y (or YY) coordinate
|
||||
if (size < 0) {
|
||||
size = 0;
|
||||
}
|
||||
size >>= 1;
|
||||
} else {
|
||||
size >>= 2;
|
||||
}
|
||||
|
||||
if (fDoFilter) {
|
||||
size >>= 1;
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
|
@ -1,414 +0,0 @@
|
|||
|
||||
/*
|
||||
* Copyright 2006 The Android Open Source Project
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
|
||||
#include "SkBitmapSampler.h"
|
||||
|
||||
static SkTileModeProc get_tilemode_proc(SkShader::TileMode mode)
|
||||
{
|
||||
switch (mode) {
|
||||
case SkShader::kClamp_TileMode:
|
||||
return do_clamp;
|
||||
case SkShader::kRepeat_TileMode:
|
||||
return do_repeat_mod;
|
||||
case SkShader::kMirror_TileMode:
|
||||
return do_mirror_mod;
|
||||
default:
|
||||
SkDEBUGFAIL("unknown mode");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
SkBitmapSampler::SkBitmapSampler(const SkBitmap& bm, bool filter,
|
||||
SkShader::TileMode tmx, SkShader::TileMode tmy)
|
||||
: fBitmap(bm), fFilterBitmap(filter), fTileModeX(tmx), fTileModeY(tmy)
|
||||
{
|
||||
SkASSERT(bm.width() > 0 && bm.height() > 0);
|
||||
|
||||
fMaxX = SkToU16(bm.width() - 1);
|
||||
fMaxY = SkToU16(bm.height() - 1);
|
||||
|
||||
fTileProcX = get_tilemode_proc(tmx);
|
||||
fTileProcY = get_tilemode_proc(tmy);
|
||||
}
|
||||
|
||||
void SkBitmapSampler::setPaint(const SkPaint& paint)
|
||||
{
|
||||
}
|
||||
|
||||
class SkNullBitmapSampler : public SkBitmapSampler {
|
||||
public:
|
||||
SkNullBitmapSampler(const SkBitmap& bm, bool filter,
|
||||
SkShader::TileMode tmx, SkShader::TileMode tmy)
|
||||
: SkBitmapSampler(bm, filter, tmx, tmy) {}
|
||||
|
||||
virtual SkPMColor sample(SkFixed x, SkFixed y) const { return 0; }
|
||||
};
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#define BITMAP_CLASSNAME_PREFIX(name) ARGB32##name
|
||||
#define BITMAP_PIXEL_TO_PMCOLOR(bitmap, x, y) *bitmap.getAddr32(x, y)
|
||||
#include "SkBitmapSamplerTemplate.h"
|
||||
|
||||
#include "SkColorPriv.h"
|
||||
|
||||
#define BITMAP_CLASSNAME_PREFIX(name) RGB16##name
|
||||
#define BITMAP_PIXEL_TO_PMCOLOR(bitmap, x, y) SkPixel16ToPixel32(*bitmap.getAddr16(x, y))
|
||||
#include "SkBitmapSamplerTemplate.h"
|
||||
|
||||
#define BITMAP_CLASSNAME_PREFIX(name) Index8##name
|
||||
#define BITMAP_PIXEL_TO_PMCOLOR(bitmap, x, y) bitmap.getIndex8Color(x, y)
|
||||
#include "SkBitmapSamplerTemplate.h"
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
///////////////// The Bilinear versions
|
||||
|
||||
#include "SkFilterProc.h"
|
||||
|
||||
class ARGB32_Bilinear_Sampler : public SkBitmapSampler {
|
||||
public:
|
||||
ARGB32_Bilinear_Sampler(const SkBitmap& bm, SkShader::TileMode tmx, SkShader::TileMode tmy)
|
||||
: SkBitmapSampler(bm, true, tmx, tmy)
|
||||
{
|
||||
fPtrProcTable = SkGetBilinearFilterPtrProcTable();
|
||||
}
|
||||
|
||||
virtual SkPMColor sample(SkFixed x, SkFixed y) const
|
||||
{
|
||||
const uint32_t *p00, *p01, *p10, *p11;
|
||||
|
||||
// turn pixel centers into the top-left of our filter-box
|
||||
x -= SK_FixedHalf;
|
||||
y -= SK_FixedHalf;
|
||||
|
||||
// compute our pointers
|
||||
{
|
||||
const SkBitmap* bitmap = &fBitmap;
|
||||
int ix = x >> 16;
|
||||
int iy = y >> 16;
|
||||
|
||||
int maxX = fMaxX;
|
||||
SkTileModeProc procX = fTileProcX;
|
||||
int maxY = fMaxY;
|
||||
SkTileModeProc procY = fTileProcY;
|
||||
|
||||
int tmpx = procX(ix, maxX);
|
||||
int tmpy = procY(iy, maxY);
|
||||
p00 = bitmap->getAddr32(tmpx, tmpy);
|
||||
|
||||
int tmpx1 = procX(ix + 1, maxX);
|
||||
p01 = bitmap->getAddr32(tmpx1, tmpy);
|
||||
|
||||
int tmpy1 = procY(iy + 1, maxY);
|
||||
p10 = bitmap->getAddr32(tmpx, tmpy1);
|
||||
|
||||
p11 = bitmap->getAddr32(tmpx1, tmpy1);
|
||||
}
|
||||
|
||||
SkFilterPtrProc proc = SkGetBilinearFilterPtrProc(fPtrProcTable, x, y);
|
||||
return proc(p00, p01, p10, p11);
|
||||
}
|
||||
|
||||
private:
|
||||
const SkFilterPtrProc* fPtrProcTable;
|
||||
};
|
||||
|
||||
class RGB16_Bilinear_Sampler : public SkBitmapSampler {
|
||||
public:
|
||||
RGB16_Bilinear_Sampler(const SkBitmap& bm, SkShader::TileMode tmx, SkShader::TileMode tmy)
|
||||
: SkBitmapSampler(bm, true, tmx, tmy)
|
||||
{
|
||||
fProcTable = SkGetBilinearFilterProcTable();
|
||||
}
|
||||
|
||||
virtual SkPMColor sample(SkFixed x, SkFixed y) const
|
||||
{
|
||||
const uint16_t *p00, *p01, *p10, *p11;
|
||||
|
||||
// turn pixel centers into the top-left of our filter-box
|
||||
x -= SK_FixedHalf;
|
||||
y -= SK_FixedHalf;
|
||||
|
||||
// compute our pointers
|
||||
{
|
||||
const SkBitmap* bitmap = &fBitmap;
|
||||
int ix = x >> 16;
|
||||
int iy = y >> 16;
|
||||
|
||||
int maxX = fMaxX;
|
||||
SkTileModeProc procX = fTileProcX;
|
||||
int maxY = fMaxY;
|
||||
SkTileModeProc procY = fTileProcY;
|
||||
|
||||
int tmpx = procX(ix, maxX);
|
||||
int tmpy = procY(iy, maxY);
|
||||
p00 = bitmap->getAddr16(tmpx, tmpy);
|
||||
|
||||
int tmpx1 = procX(ix + 1, maxX);
|
||||
p01 = bitmap->getAddr16(tmpx1, tmpy);
|
||||
|
||||
int tmpy1 = procY(iy + 1, maxY);
|
||||
p10 = bitmap->getAddr16(tmpx, tmpy1);
|
||||
|
||||
p11 = bitmap->getAddr16(tmpx1, tmpy1);
|
||||
}
|
||||
|
||||
SkFilterProc proc = SkGetBilinearFilterProc(fProcTable, x, y);
|
||||
uint32_t c = proc(SkExpand_rgb_16(*p00), SkExpand_rgb_16(*p01),
|
||||
SkExpand_rgb_16(*p10), SkExpand_rgb_16(*p11));
|
||||
|
||||
return SkPixel16ToPixel32((uint16_t)SkCompact_rgb_16(c));
|
||||
}
|
||||
|
||||
private:
|
||||
const SkFilterProc* fProcTable;
|
||||
};
|
||||
|
||||
// If we had a init/term method on sampler, we could avoid the per-pixel
|
||||
// call to lockColors/unlockColors
|
||||
|
||||
class Index8_Bilinear_Sampler : public SkBitmapSampler {
|
||||
public:
|
||||
Index8_Bilinear_Sampler(const SkBitmap& bm, SkShader::TileMode tmx, SkShader::TileMode tmy)
|
||||
: SkBitmapSampler(bm, true, tmx, tmy)
|
||||
{
|
||||
fPtrProcTable = SkGetBilinearFilterPtrProcTable();
|
||||
}
|
||||
|
||||
virtual SkPMColor sample(SkFixed x, SkFixed y) const
|
||||
{
|
||||
const SkBitmap* bitmap = &fBitmap;
|
||||
|
||||
const uint8_t *p00, *p01, *p10, *p11;
|
||||
|
||||
// turn pixel centers into the top-left of our filter-box
|
||||
x -= SK_FixedHalf;
|
||||
y -= SK_FixedHalf;
|
||||
|
||||
// compute our pointers
|
||||
{
|
||||
int ix = x >> 16;
|
||||
int iy = y >> 16;
|
||||
|
||||
int maxX = fMaxX;
|
||||
SkTileModeProc procX = fTileProcX;
|
||||
int maxY = fMaxY;
|
||||
SkTileModeProc procY = fTileProcY;
|
||||
|
||||
int tmpx = procX(ix, maxX);
|
||||
int tmpy = procY(iy, maxY);
|
||||
p00 = bitmap->getAddr8(tmpx, tmpy);
|
||||
|
||||
int tmpx1 = procX(ix + 1, maxX);
|
||||
p01 = bitmap->getAddr8(tmpx1, tmpy);
|
||||
|
||||
int tmpy1 = procY(iy + 1, maxY);
|
||||
p10 = bitmap->getAddr8(tmpx, tmpy1);
|
||||
|
||||
p11 = bitmap->getAddr8(tmpx1, tmpy1);
|
||||
}
|
||||
|
||||
const SkPMColor* colors = bitmap->getColorTable()->lockColors();
|
||||
|
||||
SkFilterPtrProc proc = SkGetBilinearFilterPtrProc(fPtrProcTable, x, y);
|
||||
uint32_t c = proc(&colors[*p00], &colors[*p01], &colors[*p10], &colors[*p11]);
|
||||
|
||||
bitmap->getColorTable()->unlockColors(false);
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
private:
|
||||
const SkFilterPtrProc* fPtrProcTable;
|
||||
};
|
||||
|
||||
class A8_Bilinear_Sampler : public SkBitmapSampler {
|
||||
public:
|
||||
A8_Bilinear_Sampler(const SkBitmap& bm, SkShader::TileMode tmx, SkShader::TileMode tmy)
|
||||
: SkBitmapSampler(bm, true, tmx, tmy)
|
||||
, fColor(0)
|
||||
{
|
||||
fProcTable = SkGetBilinearFilterProcTable();
|
||||
}
|
||||
|
||||
virtual void setPaint(const SkPaint& paint)
|
||||
{
|
||||
fColor = SkPreMultiplyColor(paint.getColor());
|
||||
}
|
||||
|
||||
virtual SkPMColor sample(SkFixed x, SkFixed y) const
|
||||
{
|
||||
const uint8_t *p00, *p01, *p10, *p11;
|
||||
|
||||
// turn pixel centers into the top-left of our filter-box
|
||||
x -= SK_FixedHalf;
|
||||
y -= SK_FixedHalf;
|
||||
|
||||
// compute our pointers
|
||||
{
|
||||
const SkBitmap* bitmap = &fBitmap;
|
||||
int ix = x >> 16;
|
||||
int iy = y >> 16;
|
||||
|
||||
int maxX = fMaxX;
|
||||
SkTileModeProc procX = fTileProcX;
|
||||
int maxY = fMaxY;
|
||||
SkTileModeProc procY = fTileProcY;
|
||||
|
||||
int tmpx = procX(ix, maxX);
|
||||
int tmpy = procY(iy, maxY);
|
||||
p00 = bitmap->getAddr8(tmpx, tmpy);
|
||||
|
||||
int tmpx1 = procX(ix + 1, maxX);
|
||||
p01 = bitmap->getAddr8(tmpx1, tmpy);
|
||||
|
||||
int tmpy1 = procY(iy + 1, maxY);
|
||||
p10 = bitmap->getAddr8(tmpx, tmpy1);
|
||||
|
||||
p11 = bitmap->getAddr8(tmpx1, tmpy1);
|
||||
}
|
||||
|
||||
SkFilterProc proc = SkGetBilinearFilterProc(fProcTable, x, y);
|
||||
int alpha = proc(*p00, *p01, *p10, *p11);
|
||||
return SkAlphaMulQ(fColor, SkAlpha255To256(alpha));
|
||||
}
|
||||
|
||||
private:
|
||||
const SkFilterProc* fProcTable;
|
||||
SkPMColor fColor;
|
||||
};
|
||||
|
||||
class A8_NoFilter_Sampler : public SkBitmapSampler {
|
||||
public:
|
||||
A8_NoFilter_Sampler(const SkBitmap& bm, SkShader::TileMode tmx, SkShader::TileMode tmy)
|
||||
: SkBitmapSampler(bm, false, tmx, tmy)
|
||||
{
|
||||
}
|
||||
|
||||
virtual void setPaint(const SkPaint& paint)
|
||||
{
|
||||
fColor = SkPreMultiplyColor(paint.getColor());
|
||||
}
|
||||
|
||||
virtual SkPMColor sample(SkFixed x, SkFixed y) const
|
||||
{
|
||||
int ix = SkFixedFloor(x);
|
||||
int iy = SkFixedFloor(y);
|
||||
|
||||
int alpha = *fBitmap.getAddr8(fTileProcX(ix, fMaxX), fTileProcY(iy, fMaxY));
|
||||
return SkAlphaMulQ(fColor, SkAlpha255To256(alpha));
|
||||
}
|
||||
|
||||
private:
|
||||
SkPMColor fColor;
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
SkBitmapSampler* SkBitmapSampler::Create(const SkBitmap& bm, bool doFilter,
|
||||
SkShader::TileMode tmx,
|
||||
SkShader::TileMode tmy)
|
||||
{
|
||||
switch (bm.getConfig()) {
|
||||
case SkBitmap::kARGB_8888_Config:
|
||||
if (doFilter)
|
||||
return SkNEW_ARGS(ARGB32_Bilinear_Sampler, (bm, tmx, tmy));
|
||||
|
||||
if (tmx == tmy) {
|
||||
switch (tmx) {
|
||||
case SkShader::kClamp_TileMode:
|
||||
return SkNEW_ARGS(ARGB32_Point_Clamp_Sampler, (bm));
|
||||
case SkShader::kRepeat_TileMode:
|
||||
if (is_pow2(bm.width()) && is_pow2(bm.height()))
|
||||
return SkNEW_ARGS(ARGB32_Point_Repeat_Pow2_Sampler, (bm));
|
||||
else
|
||||
return SkNEW_ARGS(ARGB32_Point_Repeat_Mod_Sampler, (bm));
|
||||
case SkShader::kMirror_TileMode:
|
||||
if (is_pow2(bm.width()) && is_pow2(bm.height()))
|
||||
return SkNEW_ARGS(ARGB32_Point_Mirror_Pow2_Sampler, (bm));
|
||||
else
|
||||
return SkNEW_ARGS(ARGB32_Point_Mirror_Mod_Sampler, (bm));
|
||||
default:
|
||||
SkDEBUGFAIL("unknown mode");
|
||||
}
|
||||
}
|
||||
else { // tmx != tmy
|
||||
return SkNEW_ARGS(ARGB32_Point_Sampler, (bm, tmx, tmy));
|
||||
}
|
||||
break;
|
||||
|
||||
case SkBitmap::kRGB_565_Config:
|
||||
if (doFilter)
|
||||
return SkNEW_ARGS(RGB16_Bilinear_Sampler, (bm, tmx, tmy));
|
||||
|
||||
if (tmx == tmy) {
|
||||
switch (tmx) {
|
||||
case SkShader::kClamp_TileMode:
|
||||
return SkNEW_ARGS(RGB16_Point_Clamp_Sampler, (bm));
|
||||
case SkShader::kRepeat_TileMode:
|
||||
if (is_pow2(bm.width()) && is_pow2(bm.height()))
|
||||
return SkNEW_ARGS(RGB16_Point_Repeat_Pow2_Sampler, (bm));
|
||||
else
|
||||
return SkNEW_ARGS(RGB16_Point_Repeat_Mod_Sampler, (bm));
|
||||
case SkShader::kMirror_TileMode:
|
||||
if (is_pow2(bm.width()) && is_pow2(bm.height()))
|
||||
return SkNEW_ARGS(RGB16_Point_Mirror_Pow2_Sampler, (bm));
|
||||
else
|
||||
return SkNEW_ARGS(RGB16_Point_Mirror_Mod_Sampler, (bm));
|
||||
default:
|
||||
SkDEBUGFAIL("unknown mode");
|
||||
}
|
||||
}
|
||||
else { // tmx != tmy
|
||||
return SkNEW_ARGS(RGB16_Point_Sampler, (bm, tmx, tmy));
|
||||
}
|
||||
break;
|
||||
|
||||
case SkBitmap::kIndex8_Config:
|
||||
if (doFilter)
|
||||
return SkNEW_ARGS(Index8_Bilinear_Sampler, (bm, tmx, tmy));
|
||||
|
||||
if (tmx == tmy) {
|
||||
switch (tmx) {
|
||||
case SkShader::kClamp_TileMode:
|
||||
return SkNEW_ARGS(Index8_Point_Clamp_Sampler, (bm));
|
||||
case SkShader::kRepeat_TileMode:
|
||||
if (is_pow2(bm.width()) && is_pow2(bm.height()))
|
||||
return SkNEW_ARGS(Index8_Point_Repeat_Pow2_Sampler, (bm));
|
||||
else
|
||||
return SkNEW_ARGS(Index8_Point_Repeat_Mod_Sampler, (bm));
|
||||
case SkShader::kMirror_TileMode:
|
||||
if (is_pow2(bm.width()) && is_pow2(bm.height()))
|
||||
return SkNEW_ARGS(Index8_Point_Mirror_Pow2_Sampler, (bm));
|
||||
else
|
||||
return SkNEW_ARGS(Index8_Point_Mirror_Mod_Sampler, (bm));
|
||||
default:
|
||||
SkDEBUGFAIL("unknown mode");
|
||||
}
|
||||
}
|
||||
else { // tmx != tmy
|
||||
return SkNEW_ARGS(Index8_Point_Sampler, (bm, tmx, tmy));
|
||||
}
|
||||
break;
|
||||
|
||||
case SkBitmap::kA8_Config:
|
||||
if (doFilter)
|
||||
return SkNEW_ARGS(A8_Bilinear_Sampler, (bm, tmx, tmy));
|
||||
else
|
||||
return SkNEW_ARGS(A8_NoFilter_Sampler, (bm, tmx, tmy));
|
||||
break;
|
||||
|
||||
default:
|
||||
SkDEBUGFAIL("unknown device");
|
||||
}
|
||||
return SkNEW_ARGS(SkNullBitmapSampler, (bm, doFilter, tmx, tmy));
|
||||
}
|
|
@ -1,162 +0,0 @@
|
|||
|
||||
/*
|
||||
* Copyright 2006 The Android Open Source Project
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef SkBitmapSampler_DEFINED
|
||||
#define SkBitmapSampler_DEFINED
|
||||
|
||||
#include "SkBitmap.h"
|
||||
#include "SkPaint.h"
|
||||
#include "SkShader.h"
|
||||
|
||||
typedef int (*SkTileModeProc)(int value, unsigned max);
|
||||
|
||||
class SkBitmapSampler {
|
||||
public:
|
||||
SkBitmapSampler(const SkBitmap&, bool filter, SkShader::TileMode tmx, SkShader::TileMode tmy);
|
||||
virtual ~SkBitmapSampler() {}
|
||||
|
||||
const SkBitmap& getBitmap() const { return fBitmap; }
|
||||
bool getFilterBitmap() const { return fFilterBitmap; }
|
||||
SkShader::TileMode getTileModeX() const { return fTileModeX; }
|
||||
SkShader::TileMode getTileModeY() const { return fTileModeY; }
|
||||
|
||||
/** Given a pixel center at [x,y], return the color sample
|
||||
*/
|
||||
virtual SkPMColor sample(SkFixed x, SkFixed y) const = 0;
|
||||
|
||||
virtual void setPaint(const SkPaint& paint);
|
||||
|
||||
// This is the factory for finding an optimal subclass
|
||||
static SkBitmapSampler* Create(const SkBitmap&, bool filter,
|
||||
SkShader::TileMode tmx, SkShader::TileMode tmy);
|
||||
|
||||
protected:
|
||||
const SkBitmap& fBitmap;
|
||||
uint16_t fMaxX, fMaxY;
|
||||
bool fFilterBitmap;
|
||||
SkShader::TileMode fTileModeX;
|
||||
SkShader::TileMode fTileModeY;
|
||||
SkTileModeProc fTileProcX;
|
||||
SkTileModeProc fTileProcY;
|
||||
|
||||
// illegal
|
||||
SkBitmapSampler& operator=(const SkBitmapSampler&);
|
||||
};
|
||||
|
||||
static inline int fixed_clamp(SkFixed x)
|
||||
{
|
||||
#ifdef SK_CPU_HAS_CONDITIONAL_INSTR
|
||||
if (x >> 16)
|
||||
x = 0xFFFF;
|
||||
if (x < 0)
|
||||
x = 0;
|
||||
#else
|
||||
if (x >> 16)
|
||||
{
|
||||
if (x < 0)
|
||||
x = 0;
|
||||
else
|
||||
x = 0xFFFF;
|
||||
}
|
||||
#endif
|
||||
return x;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static inline int fixed_repeat(SkFixed x)
|
||||
{
|
||||
return x & 0xFFFF;
|
||||
}
|
||||
|
||||
static inline int fixed_mirror(SkFixed x)
|
||||
{
|
||||
SkFixed s = x << 15 >> 31;
|
||||
// s is FFFFFFFF if we're on an odd interval, or 0 if an even interval
|
||||
return (x ^ s) & 0xFFFF;
|
||||
}
|
||||
|
||||
static inline bool is_pow2(int count)
|
||||
{
|
||||
SkASSERT(count > 0);
|
||||
return (count & (count - 1)) == 0;
|
||||
}
|
||||
|
||||
static inline int do_clamp(int index, unsigned max)
|
||||
{
|
||||
SkASSERT((int)max >= 0);
|
||||
|
||||
#ifdef SK_CPU_HAS_CONDITIONAL_INSTR
|
||||
if (index > (int)max)
|
||||
index = max;
|
||||
if (index < 0)
|
||||
index = 0;
|
||||
#else
|
||||
if ((unsigned)index > max)
|
||||
{
|
||||
if (index < 0)
|
||||
index = 0;
|
||||
else
|
||||
index = max;
|
||||
}
|
||||
#endif
|
||||
return index;
|
||||
}
|
||||
|
||||
static inline int do_repeat_mod(int index, unsigned max)
|
||||
{
|
||||
SkASSERT((int)max >= 0);
|
||||
|
||||
if ((unsigned)index > max)
|
||||
{
|
||||
if (index < 0)
|
||||
index = max - (~index % (max + 1));
|
||||
else
|
||||
index = index % (max + 1);
|
||||
}
|
||||
return index;
|
||||
}
|
||||
|
||||
static inline int do_repeat_pow2(int index, unsigned max)
|
||||
{
|
||||
SkASSERT((int)max >= 0 && is_pow2(max + 1));
|
||||
|
||||
return index & max;
|
||||
}
|
||||
|
||||
static inline int do_mirror_mod(int index, unsigned max)
|
||||
{
|
||||
SkASSERT((int)max >= 0);
|
||||
|
||||
// have to handle negatives so that
|
||||
// -1 -> 0, -2 -> 1, -3 -> 2, etc.
|
||||
// so we can't just cal abs
|
||||
index ^= index >> 31;
|
||||
|
||||
if ((unsigned)index > max)
|
||||
{
|
||||
int mod = (max + 1) << 1;
|
||||
index = index % mod;
|
||||
if ((unsigned)index > max)
|
||||
index = mod - index - 1;
|
||||
}
|
||||
return index;
|
||||
}
|
||||
|
||||
static inline int do_mirror_pow2(int index, unsigned max)
|
||||
{
|
||||
SkASSERT((int)max >= 0 && is_pow2(max + 1));
|
||||
|
||||
int s = (index & (max + 1)) - 1;
|
||||
s = ~(s >> 31);
|
||||
// at this stage, s is FFFFFFFF if we're on an odd interval, or 0 if an even interval
|
||||
return (index ^ s) & max;
|
||||
}
|
||||
|
||||
#endif
|
|
@ -1,108 +0,0 @@
|
|||
|
||||
/*
|
||||
* Copyright 2006 The Android Open Source Project
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
|
||||
/* this guy is pulled in multiple times, with the following symbols defined each time:
|
||||
|
||||
#define BITMAP_CLASSNAME_PREFIX(name) ARGB32##name
|
||||
#defube BITMAP_PIXEL_TO_PMCOLOR(bitmap, x, y) *bitmap.getAddr32(x, y)
|
||||
*/
|
||||
|
||||
class BITMAP_CLASSNAME_PREFIX(_Point_Sampler) : public SkBitmapSampler {
|
||||
public:
|
||||
BITMAP_CLASSNAME_PREFIX(_Point_Sampler)(const SkBitmap& bm, SkShader::TileMode tmx, SkShader::TileMode tmy)
|
||||
: SkBitmapSampler(bm, false, tmx, tmy)
|
||||
{
|
||||
}
|
||||
|
||||
virtual SkPMColor sample(SkFixed x, SkFixed y) const
|
||||
{
|
||||
x = fTileProcX(SkFixedFloor(x), fMaxX);
|
||||
y = fTileProcY(SkFixedFloor(y), fMaxY);
|
||||
return BITMAP_PIXEL_TO_PMCOLOR(fBitmap, x, y);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class BITMAP_CLASSNAME_PREFIX(_Point_Clamp_Sampler) : public SkBitmapSampler {
|
||||
public:
|
||||
BITMAP_CLASSNAME_PREFIX(_Point_Clamp_Sampler)(const SkBitmap& bm)
|
||||
: SkBitmapSampler(bm, false, SkShader::kClamp_TileMode, SkShader::kClamp_TileMode)
|
||||
{
|
||||
}
|
||||
|
||||
virtual SkPMColor sample(SkFixed x, SkFixed y) const
|
||||
{
|
||||
x = do_clamp(SkFixedFloor(x), fMaxX);
|
||||
y = do_clamp(SkFixedFloor(y), fMaxY);
|
||||
return BITMAP_PIXEL_TO_PMCOLOR(fBitmap, x, y);
|
||||
}
|
||||
};
|
||||
|
||||
class BITMAP_CLASSNAME_PREFIX(_Point_Repeat_Pow2_Sampler) : public SkBitmapSampler {
|
||||
public:
|
||||
BITMAP_CLASSNAME_PREFIX(_Point_Repeat_Pow2_Sampler)(const SkBitmap& bm)
|
||||
: SkBitmapSampler(bm, false, SkShader::kRepeat_TileMode, SkShader::kRepeat_TileMode)
|
||||
{
|
||||
}
|
||||
|
||||
virtual SkPMColor sample(SkFixed x, SkFixed y) const
|
||||
{
|
||||
x = do_repeat_pow2(SkFixedFloor(x), fMaxX);
|
||||
y = do_repeat_pow2(SkFixedFloor(y), fMaxY);
|
||||
return BITMAP_PIXEL_TO_PMCOLOR(fBitmap, x, y);
|
||||
}
|
||||
};
|
||||
|
||||
class BITMAP_CLASSNAME_PREFIX(_Point_Repeat_Mod_Sampler) : public SkBitmapSampler {
|
||||
public:
|
||||
BITMAP_CLASSNAME_PREFIX(_Point_Repeat_Mod_Sampler)(const SkBitmap& bm)
|
||||
: SkBitmapSampler(bm, false, SkShader::kRepeat_TileMode, SkShader::kRepeat_TileMode)
|
||||
{
|
||||
}
|
||||
|
||||
virtual SkPMColor sample(SkFixed x, SkFixed y) const
|
||||
{
|
||||
x = do_repeat_mod(SkFixedFloor(x), fMaxX);
|
||||
y = do_repeat_mod(SkFixedFloor(y), fMaxY);
|
||||
return BITMAP_PIXEL_TO_PMCOLOR(fBitmap, x, y);
|
||||
}
|
||||
};
|
||||
|
||||
class BITMAP_CLASSNAME_PREFIX(_Point_Mirror_Pow2_Sampler) : public SkBitmapSampler {
|
||||
public:
|
||||
BITMAP_CLASSNAME_PREFIX(_Point_Mirror_Pow2_Sampler)(const SkBitmap& bm)
|
||||
: SkBitmapSampler(bm, false, SkShader::kMirror_TileMode, SkShader::kMirror_TileMode)
|
||||
{
|
||||
}
|
||||
|
||||
virtual SkPMColor sample(SkFixed x, SkFixed y) const
|
||||
{
|
||||
x = do_mirror_pow2(SkFixedFloor(x), fMaxX);
|
||||
y = do_mirror_pow2(SkFixedFloor(y), fMaxY);
|
||||
return BITMAP_PIXEL_TO_PMCOLOR(fBitmap, x, y);
|
||||
}
|
||||
};
|
||||
|
||||
class BITMAP_CLASSNAME_PREFIX(_Point_Mirror_Mod_Sampler) : public SkBitmapSampler {
|
||||
public:
|
||||
BITMAP_CLASSNAME_PREFIX(_Point_Mirror_Mod_Sampler)(const SkBitmap& bm)
|
||||
: SkBitmapSampler(bm, false, SkShader::kMirror_TileMode, SkShader::kMirror_TileMode)
|
||||
{
|
||||
}
|
||||
|
||||
virtual SkPMColor sample(SkFixed x, SkFixed y) const
|
||||
{
|
||||
x = do_mirror_mod(SkFixedFloor(x), fMaxX);
|
||||
y = do_mirror_mod(SkFixedFloor(y), fMaxY);
|
||||
return BITMAP_PIXEL_TO_PMCOLOR(fBitmap, x, y);
|
||||
}
|
||||
};
|
||||
|
||||
#undef BITMAP_CLASSNAME_PREFIX
|
||||
#undef BITMAP_PIXEL_TO_PMCOLOR
|
|
@ -1,218 +0,0 @@
|
|||
/*
|
||||
* Copyright 2011 Google Inc.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include "SkBlitRow.h"
|
||||
#include "SkColorPriv.h"
|
||||
#include "SkDither.h"
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static void S32_D4444_Opaque(uint16_t* SK_RESTRICT dst,
|
||||
const SkPMColor* SK_RESTRICT src, int count,
|
||||
U8CPU alpha, int /*x*/, int /*y*/) {
|
||||
SkASSERT(255 == alpha);
|
||||
|
||||
if (count > 0) {
|
||||
do {
|
||||
SkPMColor c = *src++;
|
||||
SkPMColorAssert(c);
|
||||
SkASSERT(SkGetPackedA32(c) == 255);
|
||||
*dst++ = SkPixel32ToPixel4444(c);
|
||||
} while (--count != 0);
|
||||
}
|
||||
}
|
||||
|
||||
static void S32_D4444_Blend(uint16_t* SK_RESTRICT dst,
|
||||
const SkPMColor* SK_RESTRICT src, int count,
|
||||
U8CPU alpha, int /*x*/, int /*y*/) {
|
||||
SkASSERT(255 > alpha);
|
||||
|
||||
if (count > 0) {
|
||||
unsigned scale16 = SkAlpha255To256(alpha) >> 4;
|
||||
do {
|
||||
SkPMColor c = *src++;
|
||||
SkPMColorAssert(c);
|
||||
SkASSERT(SkGetPackedA32(c) == 255);
|
||||
|
||||
uint32_t src_expand = SkExpand32_4444(c);
|
||||
uint32_t dst_expand = SkExpand_4444(*dst);
|
||||
dst_expand += (src_expand - dst_expand) * scale16 >> 4;
|
||||
*dst++ = SkCompact_4444(dst_expand);
|
||||
} while (--count != 0);
|
||||
}
|
||||
}
|
||||
|
||||
static void S32A_D4444_Opaque(uint16_t* SK_RESTRICT dst,
|
||||
const SkPMColor* SK_RESTRICT src, int count,
|
||||
U8CPU alpha, int /*x*/, int /*y*/) {
|
||||
SkASSERT(255 == alpha);
|
||||
|
||||
if (count > 0) {
|
||||
do {
|
||||
SkPMColor c = *src++;
|
||||
SkPMColorAssert(c);
|
||||
// if (__builtin_expect(c!=0, 1))
|
||||
if (c)
|
||||
{
|
||||
unsigned scale16 = SkAlpha255To256(255 - SkGetPackedA32(c)) >> 4;
|
||||
uint32_t src_expand = SkExpand_8888(c);
|
||||
uint32_t dst_expand = SkExpand_4444(*dst) * scale16;
|
||||
*dst = SkCompact_4444((src_expand + dst_expand) >> 4);
|
||||
}
|
||||
dst += 1;
|
||||
} while (--count != 0);
|
||||
}
|
||||
}
|
||||
|
||||
static void S32A_D4444_Blend(uint16_t* SK_RESTRICT dst,
|
||||
const SkPMColor* SK_RESTRICT src, int count,
|
||||
U8CPU alpha, int /*x*/, int /*y*/) {
|
||||
SkASSERT(255 > alpha);
|
||||
|
||||
if (count > 0) {
|
||||
int src_scale = SkAlpha255To256(alpha) >> 4;
|
||||
do {
|
||||
SkPMColor sc = *src++;
|
||||
SkPMColorAssert(sc);
|
||||
|
||||
if (sc) {
|
||||
unsigned dst_scale = 16 - (SkGetPackedA32(sc) * src_scale >> 8);
|
||||
uint32_t src_expand = SkExpand32_4444(sc) * src_scale;
|
||||
uint32_t dst_expand = SkExpand_4444(*dst) * dst_scale;
|
||||
*dst = SkCompact_4444((src_expand + dst_expand) >> 4);
|
||||
}
|
||||
dst += 1;
|
||||
} while (--count != 0);
|
||||
}
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static void S32_D4444_Opaque_Dither(uint16_t* SK_RESTRICT dst,
|
||||
const SkPMColor* SK_RESTRICT src,
|
||||
int count, U8CPU alpha, int x, int y) {
|
||||
SkASSERT(255 == alpha);
|
||||
|
||||
if (count > 0) {
|
||||
DITHER_4444_SCAN(y);
|
||||
do {
|
||||
SkPMColor c = *src++;
|
||||
SkPMColorAssert(c);
|
||||
|
||||
unsigned dither = DITHER_VALUE(x);
|
||||
*dst++ = SkDitherARGB32To4444(c, dither);
|
||||
DITHER_INC_X(x);
|
||||
} while (--count != 0);
|
||||
}
|
||||
}
|
||||
|
||||
static void S32_D4444_Blend_Dither(uint16_t* SK_RESTRICT dst,
|
||||
const SkPMColor* SK_RESTRICT src,
|
||||
int count, U8CPU alpha, int x, int y) {
|
||||
SkASSERT(255 > alpha);
|
||||
|
||||
if (count > 0) {
|
||||
int scale16 = SkAlpha255To256(alpha) >> 4;
|
||||
DITHER_4444_SCAN(y);
|
||||
do {
|
||||
SkPMColor c = *src++;
|
||||
SkPMColorAssert(c);
|
||||
SkASSERT(SkGetPackedA32(c) == 255);
|
||||
|
||||
uint32_t src_expand = SkExpand32_4444(c) * scale16;
|
||||
uint32_t dst_expand = SkExpand_4444(*dst) * (16 - scale16);
|
||||
|
||||
c = SkCompact_8888(src_expand + dst_expand); // convert back to SkPMColor
|
||||
*dst++ = SkDitherARGB32To4444(c, DITHER_VALUE(x));
|
||||
DITHER_INC_X(x);
|
||||
} while (--count != 0);
|
||||
}
|
||||
}
|
||||
|
||||
static void S32A_D4444_Opaque_Dither(uint16_t* SK_RESTRICT dst,
|
||||
const SkPMColor* SK_RESTRICT src,
|
||||
int count, U8CPU alpha, int x, int y) {
|
||||
SkASSERT(255 == alpha);
|
||||
|
||||
if (count > 0) {
|
||||
DITHER_4444_SCAN(y);
|
||||
do {
|
||||
SkPMColor c = *src++;
|
||||
SkPMColorAssert(c);
|
||||
if (c) {
|
||||
unsigned a = SkGetPackedA32(c);
|
||||
int d = SkAlphaMul(DITHER_VALUE(x), SkAlpha255To256(a));
|
||||
|
||||
unsigned scale16 = SkAlpha255To256(255 - a) >> 4;
|
||||
uint32_t src_expand = SkExpand_8888(c);
|
||||
uint32_t dst_expand = SkExpand_4444(*dst) * scale16;
|
||||
// convert back to SkPMColor
|
||||
c = SkCompact_8888(src_expand + dst_expand);
|
||||
*dst = SkDitherARGB32To4444(c, d);
|
||||
}
|
||||
dst += 1;
|
||||
DITHER_INC_X(x);
|
||||
} while (--count != 0);
|
||||
}
|
||||
}
|
||||
|
||||
// need DitherExpand888To4444(expand, dither)
|
||||
|
||||
static void S32A_D4444_Blend_Dither(uint16_t* SK_RESTRICT dst,
|
||||
const SkPMColor* SK_RESTRICT src,
|
||||
int count, U8CPU alpha, int x, int y) {
|
||||
SkASSERT(255 > alpha);
|
||||
|
||||
if (count > 0) {
|
||||
int src_scale = SkAlpha255To256(alpha) >> 4;
|
||||
DITHER_4444_SCAN(y);
|
||||
do {
|
||||
SkPMColor c = *src++;
|
||||
SkPMColorAssert(c);
|
||||
if (c) {
|
||||
unsigned a = SkAlpha255To256(SkGetPackedA32(c));
|
||||
int d = SkAlphaMul(DITHER_VALUE(x), a);
|
||||
|
||||
unsigned dst_scale = 16 - SkAlphaMul(src_scale, a);
|
||||
uint32_t src_expand = SkExpand32_4444(c) * src_scale;
|
||||
uint32_t dst_expand = SkExpand_4444(*dst) * dst_scale;
|
||||
// convert back to SkPMColor
|
||||
c = SkCompact_8888(src_expand + dst_expand);
|
||||
*dst = SkDitherARGB32To4444(c, d);
|
||||
}
|
||||
dst += 1;
|
||||
DITHER_INC_X(x);
|
||||
} while (--count != 0);
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static const SkBlitRow::Proc gProcs4444[] = {
|
||||
// no dither
|
||||
S32_D4444_Opaque,
|
||||
S32_D4444_Blend,
|
||||
|
||||
S32A_D4444_Opaque,
|
||||
S32A_D4444_Blend,
|
||||
|
||||
// dither
|
||||
S32_D4444_Opaque_Dither,
|
||||
S32_D4444_Blend_Dither,
|
||||
|
||||
S32A_D4444_Opaque_Dither,
|
||||
S32A_D4444_Blend_Dither
|
||||
};
|
||||
|
||||
SkBlitRow::Proc SkBlitRow_Factory_4444(unsigned flags);
|
||||
SkBlitRow::Proc SkBlitRow_Factory_4444(unsigned flags)
|
||||
{
|
||||
SkASSERT(flags < SK_ARRAY_COUNT(gProcs4444));
|
||||
|
||||
return gProcs4444[flags];
|
||||
}
|
|
@ -1,480 +0,0 @@
|
|||
|
||||
/*
|
||||
* Copyright 2006 The Android Open Source Project
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
|
||||
#include "SkCoreBlitters.h"
|
||||
#include "SkColorPriv.h"
|
||||
#include "SkDither.h"
|
||||
#include "SkShader.h"
|
||||
#include "SkTemplatesPriv.h"
|
||||
#include "SkUtils.h"
|
||||
#include "SkXfermode.h"
|
||||
|
||||
static inline SkPMColor SkBlendARGB4444(SkPMColor16 src, SkPMColor16 dst,
|
||||
U8CPU aa) {
|
||||
SkASSERT((unsigned)aa <= 255);
|
||||
|
||||
unsigned src_scale = SkAlpha255To256(aa) >> 4;
|
||||
unsigned dst_scale = SkAlpha15To16(15 - SkAlphaMul4(SkGetPackedA4444(src), src_scale));
|
||||
|
||||
uint32_t src32 = SkExpand_4444(src) * src_scale;
|
||||
uint32_t dst32 = SkExpand_4444(dst) * dst_scale;
|
||||
return SkCompact_4444((src32 + dst32) >> 4);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class SkARGB4444_Blitter : public SkRasterBlitter {
|
||||
public:
|
||||
SkARGB4444_Blitter(const SkBitmap& device, const SkPaint& paint);
|
||||
virtual void blitH(int x, int y, int width);
|
||||
virtual void blitAntiH(int x, int y, const SkAlpha antialias[],
|
||||
const int16_t runs[]);
|
||||
virtual void blitV(int x, int y, int height, SkAlpha alpha);
|
||||
virtual void blitRect(int x, int y, int width, int height);
|
||||
virtual void blitMask(const SkMask&, const SkIRect&);
|
||||
virtual const SkBitmap* justAnOpaqueColor(uint32_t*);
|
||||
|
||||
protected:
|
||||
SkPMColor16 fPMColor16, fPMColor16Other;
|
||||
SkPMColor16 fRawColor16, fRawColor16Other;
|
||||
uint8_t fScale16;
|
||||
|
||||
private:
|
||||
// illegal
|
||||
SkARGB4444_Blitter& operator=(const SkARGB4444_Blitter&);
|
||||
|
||||
typedef SkRasterBlitter INHERITED;
|
||||
};
|
||||
|
||||
|
||||
SkARGB4444_Blitter::SkARGB4444_Blitter(const SkBitmap& device,
|
||||
const SkPaint& paint) : INHERITED(device) {
|
||||
// cache premultiplied versions in 4444
|
||||
SkPMColor c = SkPreMultiplyColor(paint.getColor());
|
||||
fPMColor16 = SkPixel32ToPixel4444(c);
|
||||
if (paint.isDither()) {
|
||||
fPMColor16Other = SkDitherPixel32To4444(c);
|
||||
} else {
|
||||
fPMColor16Other = fPMColor16;
|
||||
}
|
||||
|
||||
// cache raw versions in 4444
|
||||
fRawColor16 = SkPackARGB4444(0xFF >> 4, SkColorGetR(c) >> 4,
|
||||
SkColorGetG(c) >> 4, SkColorGetB(c) >> 4);
|
||||
if (paint.isDither()) {
|
||||
fRawColor16Other = SkDitherARGB32To4444(0xFF, SkColorGetR(c),
|
||||
SkColorGetG(c), SkColorGetB(c));
|
||||
} else {
|
||||
fRawColor16Other = fRawColor16;
|
||||
}
|
||||
|
||||
fScale16 = SkAlpha15To16(SkGetPackedA4444(fPMColor16Other));
|
||||
if (16 == fScale16) {
|
||||
// force the original to also be opaque
|
||||
fPMColor16 |= (0xF << SK_A4444_SHIFT);
|
||||
}
|
||||
}
|
||||
|
||||
const SkBitmap* SkARGB4444_Blitter::justAnOpaqueColor(uint32_t* value) {
|
||||
if (16 == fScale16) {
|
||||
*value = fPMColor16;
|
||||
return &fDevice;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void src_over_4444(SkPMColor16 dst[], SkPMColor16 color,
|
||||
SkPMColor16 other, unsigned invScale, int count) {
|
||||
int twice = count >> 1;
|
||||
while (--twice >= 0) {
|
||||
*dst = color + SkAlphaMulQ4(*dst, invScale);
|
||||
dst++;
|
||||
*dst = other + SkAlphaMulQ4(*dst, invScale);
|
||||
dst++;
|
||||
}
|
||||
if (count & 1) {
|
||||
*dst = color + SkAlphaMulQ4(*dst, invScale);
|
||||
}
|
||||
}
|
||||
|
||||
static inline uint32_t SkExpand_4444_Replicate(SkPMColor16 c) {
|
||||
uint32_t c32 = SkExpand_4444(c);
|
||||
return c32 | (c32 << 4);
|
||||
}
|
||||
|
||||
static void src_over_4444x(SkPMColor16 dst[], uint32_t color,
|
||||
uint32_t other, unsigned invScale, int count) {
|
||||
int twice = count >> 1;
|
||||
uint32_t tmp;
|
||||
while (--twice >= 0) {
|
||||
tmp = SkExpand_4444(*dst) * invScale;
|
||||
*dst++ = SkCompact_4444((color + tmp) >> 4);
|
||||
tmp = SkExpand_4444(*dst) * invScale;
|
||||
*dst++ = SkCompact_4444((other + tmp) >> 4);
|
||||
}
|
||||
if (count & 1) {
|
||||
tmp = SkExpand_4444(*dst) * invScale;
|
||||
*dst = SkCompact_4444((color + tmp) >> 4);
|
||||
}
|
||||
}
|
||||
|
||||
void SkARGB4444_Blitter::blitH(int x, int y, int width) {
|
||||
SkASSERT(x >= 0 && y >= 0 && x + width <= fDevice.width());
|
||||
|
||||
if (0 == fScale16) {
|
||||
return;
|
||||
}
|
||||
|
||||
SkPMColor16* device = fDevice.getAddr16(x, y);
|
||||
SkPMColor16 color = fPMColor16;
|
||||
SkPMColor16 other = fPMColor16Other;
|
||||
|
||||
if ((x ^ y) & 1) {
|
||||
SkTSwap<SkPMColor16>(color, other);
|
||||
}
|
||||
|
||||
if (16 == fScale16) {
|
||||
sk_dither_memset16(device, color, other, width);
|
||||
} else {
|
||||
src_over_4444x(device, SkExpand_4444_Replicate(color),
|
||||
SkExpand_4444_Replicate(other),
|
||||
16 - fScale16, width);
|
||||
}
|
||||
}
|
||||
|
||||
void SkARGB4444_Blitter::blitV(int x, int y, int height, SkAlpha alpha) {
|
||||
if (0 == alpha || 0 == fScale16) {
|
||||
return;
|
||||
}
|
||||
|
||||
SkPMColor16* device = fDevice.getAddr16(x, y);
|
||||
SkPMColor16 color = fPMColor16;
|
||||
SkPMColor16 other = fPMColor16Other;
|
||||
size_t rb = fDevice.rowBytes();
|
||||
|
||||
if ((x ^ y) & 1) {
|
||||
SkTSwap<SkPMColor16>(color, other);
|
||||
}
|
||||
|
||||
if (16 == fScale16 && 255 == alpha) {
|
||||
while (--height >= 0) {
|
||||
*device = color;
|
||||
device = (SkPMColor16*)((char*)device + rb);
|
||||
SkTSwap<SkPMColor16>(color, other);
|
||||
}
|
||||
} else {
|
||||
unsigned alphaScale = SkAlpha255To256(alpha);
|
||||
uint32_t c32 = SkExpand_4444(color) * (alphaScale >> 4);
|
||||
// need to normalize the low nibble of each expanded component
|
||||
// so we don't overflow the add with d32
|
||||
c32 = SkCompact_4444(c32 >> 4);
|
||||
unsigned invScale = 16 - SkAlpha15To16(SkGetPackedA4444(c32));
|
||||
// now re-expand and replicate
|
||||
c32 = SkExpand_4444_Replicate(c32);
|
||||
|
||||
while (--height >= 0) {
|
||||
uint32_t d32 = SkExpand_4444(*device) * invScale;
|
||||
*device = SkCompact_4444((c32 + d32) >> 4);
|
||||
device = (SkPMColor16*)((char*)device + rb);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SkARGB4444_Blitter::blitRect(int x, int y, int width, int height) {
|
||||
SkASSERT(x >= 0 && y >= 0 && x + width <= fDevice.width() &&
|
||||
y + height <= fDevice.height());
|
||||
|
||||
if (0 == fScale16) {
|
||||
return;
|
||||
}
|
||||
|
||||
SkPMColor16* device = fDevice.getAddr16(x, y);
|
||||
SkPMColor16 color = fPMColor16;
|
||||
SkPMColor16 other = fPMColor16Other;
|
||||
|
||||
if ((x ^ y) & 1) {
|
||||
SkTSwap<SkPMColor16>(color, other);
|
||||
}
|
||||
|
||||
if (16 == fScale16) {
|
||||
while (--height >= 0) {
|
||||
sk_dither_memset16(device, color, other, width);
|
||||
device = (SkPMColor16*)((char*)device + fDevice.rowBytes());
|
||||
SkTSwap<SkPMColor16>(color, other);
|
||||
}
|
||||
} else {
|
||||
unsigned invScale = 16 - fScale16;
|
||||
|
||||
uint32_t c32 = SkExpand_4444_Replicate(color);
|
||||
uint32_t o32 = SkExpand_4444_Replicate(other);
|
||||
while (--height >= 0) {
|
||||
src_over_4444x(device, c32, o32, invScale, width);
|
||||
device = (SkPMColor16*)((char*)device + fDevice.rowBytes());
|
||||
SkTSwap<uint32_t>(c32, o32);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SkARGB4444_Blitter::blitAntiH(int x, int y, const SkAlpha antialias[],
|
||||
const int16_t runs[]) {
|
||||
if (0 == fScale16) {
|
||||
return;
|
||||
}
|
||||
|
||||
SkPMColor16* device = fDevice.getAddr16(x, y);
|
||||
SkPMColor16 color = fPMColor16;
|
||||
SkPMColor16 other = fPMColor16Other;
|
||||
|
||||
if ((x ^ y) & 1) {
|
||||
SkTSwap<SkPMColor16>(color, other);
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
int count = runs[0];
|
||||
SkASSERT(count >= 0);
|
||||
if (count <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
unsigned aa = antialias[0];
|
||||
if (aa) {
|
||||
if (0xFF == aa) {
|
||||
if (16 == fScale16) {
|
||||
sk_dither_memset16(device, color, other, count);
|
||||
} else {
|
||||
src_over_4444(device, color, other, 16 - fScale16, count);
|
||||
}
|
||||
} else {
|
||||
// todo: respect dithering
|
||||
aa = SkAlpha255To256(aa); // FIX
|
||||
SkPMColor16 src = SkAlphaMulQ4(color, aa >> 4);
|
||||
unsigned dst_scale = SkAlpha15To16(15 - SkGetPackedA4444(src)); // FIX
|
||||
int n = count;
|
||||
do {
|
||||
--n;
|
||||
device[n] = src + SkAlphaMulQ4(device[n], dst_scale);
|
||||
} while (n > 0);
|
||||
}
|
||||
}
|
||||
|
||||
runs += count;
|
||||
antialias += count;
|
||||
device += count;
|
||||
|
||||
if (count & 1) {
|
||||
SkTSwap<SkPMColor16>(color, other);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#define solid_8_pixels(mask, dst, color) \
|
||||
do { \
|
||||
if (mask & 0x80) dst[0] = color; \
|
||||
if (mask & 0x40) dst[1] = color; \
|
||||
if (mask & 0x20) dst[2] = color; \
|
||||
if (mask & 0x10) dst[3] = color; \
|
||||
if (mask & 0x08) dst[4] = color; \
|
||||
if (mask & 0x04) dst[5] = color; \
|
||||
if (mask & 0x02) dst[6] = color; \
|
||||
if (mask & 0x01) dst[7] = color; \
|
||||
} while (0)
|
||||
|
||||
#define SK_BLITBWMASK_NAME SkARGB4444_BlitBW
|
||||
#define SK_BLITBWMASK_ARGS , SkPMColor16 color
|
||||
#define SK_BLITBWMASK_BLIT8(mask, dst) solid_8_pixels(mask, dst, color)
|
||||
#define SK_BLITBWMASK_GETADDR getAddr16
|
||||
#define SK_BLITBWMASK_DEVTYPE uint16_t
|
||||
#include "SkBlitBWMaskTemplate.h"
|
||||
|
||||
#define blend_8_pixels(mask, dst, sc, dst_scale) \
|
||||
do { \
|
||||
if (mask & 0x80) { dst[0] = sc + SkAlphaMulQ4(dst[0], dst_scale); } \
|
||||
if (mask & 0x40) { dst[1] = sc + SkAlphaMulQ4(dst[1], dst_scale); } \
|
||||
if (mask & 0x20) { dst[2] = sc + SkAlphaMulQ4(dst[2], dst_scale); } \
|
||||
if (mask & 0x10) { dst[3] = sc + SkAlphaMulQ4(dst[3], dst_scale); } \
|
||||
if (mask & 0x08) { dst[4] = sc + SkAlphaMulQ4(dst[4], dst_scale); } \
|
||||
if (mask & 0x04) { dst[5] = sc + SkAlphaMulQ4(dst[5], dst_scale); } \
|
||||
if (mask & 0x02) { dst[6] = sc + SkAlphaMulQ4(dst[6], dst_scale); } \
|
||||
if (mask & 0x01) { dst[7] = sc + SkAlphaMulQ4(dst[7], dst_scale); } \
|
||||
} while (0)
|
||||
|
||||
#define SK_BLITBWMASK_NAME SkARGB4444_BlendBW
|
||||
#define SK_BLITBWMASK_ARGS , uint16_t sc, unsigned dst_scale
|
||||
#define SK_BLITBWMASK_BLIT8(mask, dst) blend_8_pixels(mask, dst, sc, dst_scale)
|
||||
#define SK_BLITBWMASK_GETADDR getAddr16
|
||||
#define SK_BLITBWMASK_DEVTYPE uint16_t
|
||||
#include "SkBlitBWMaskTemplate.h"
|
||||
|
||||
void SkARGB4444_Blitter::blitMask(const SkMask& mask, const SkIRect& clip) {
|
||||
SkASSERT(mask.fBounds.contains(clip));
|
||||
|
||||
if (0 == fScale16) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (mask.fFormat == SkMask::kBW_Format) {
|
||||
if (16 == fScale16) {
|
||||
SkARGB4444_BlitBW(fDevice, mask, clip, fPMColor16);
|
||||
} else {
|
||||
SkARGB4444_BlendBW(fDevice, mask, clip, fPMColor16, 16 - fScale16);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
int x = clip.fLeft;
|
||||
int y = clip.fTop;
|
||||
int width = clip.width();
|
||||
int height = clip.height();
|
||||
|
||||
SkPMColor16* device = fDevice.getAddr16(x, y);
|
||||
const uint8_t* alpha = mask.getAddr8(x, y);
|
||||
SkPMColor16 srcColor = fPMColor16;
|
||||
size_t devRB = fDevice.rowBytes() - (width << 1);
|
||||
unsigned maskRB = mask.fRowBytes - width;
|
||||
|
||||
do {
|
||||
int w = width;
|
||||
do {
|
||||
unsigned aa = *alpha++;
|
||||
*device = SkBlendARGB4444(srcColor, *device, aa);
|
||||
device += 1;
|
||||
} while (--w != 0);
|
||||
device = (SkPMColor16*)((char*)device + devRB);
|
||||
alpha += maskRB;
|
||||
} while (--height != 0);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class SkARGB4444_Shader_Blitter : public SkShaderBlitter {
|
||||
SkXfermode* fXfermode;
|
||||
SkBlitRow::Proc fOpaqueProc;
|
||||
SkBlitRow::Proc fAlphaProc;
|
||||
SkPMColor* fBuffer;
|
||||
uint8_t* fAAExpand;
|
||||
public:
|
||||
|
||||
SkARGB4444_Shader_Blitter(const SkBitmap& device, const SkPaint& paint)
|
||||
: INHERITED(device, paint) {
|
||||
const int width = device.width();
|
||||
fBuffer = (SkPMColor*)sk_malloc_throw(width * sizeof(SkPMColor) + width);
|
||||
fAAExpand = (uint8_t*)(fBuffer + width);
|
||||
|
||||
fXfermode = paint.getXfermode();
|
||||
SkSafeRef(fXfermode);
|
||||
|
||||
unsigned flags = 0;
|
||||
if (!(fShader->getFlags() & SkShader::kOpaqueAlpha_Flag)) {
|
||||
flags |= SkBlitRow::kSrcPixelAlpha_Flag;
|
||||
}
|
||||
if (paint.isDither()) {
|
||||
flags |= SkBlitRow::kDither_Flag;
|
||||
}
|
||||
fOpaqueProc = SkBlitRow::Factory(flags, SkBitmap::kARGB_4444_Config);
|
||||
fAlphaProc = SkBlitRow::Factory(flags | SkBlitRow::kGlobalAlpha_Flag,
|
||||
SkBitmap::kARGB_4444_Config);
|
||||
}
|
||||
|
||||
virtual ~SkARGB4444_Shader_Blitter() {
|
||||
SkSafeUnref(fXfermode);
|
||||
sk_free(fBuffer);
|
||||
}
|
||||
|
||||
virtual void blitH(int x, int y, int width) {
|
||||
SkASSERT(x >= 0 && y >= 0 && x + width <= fDevice.width());
|
||||
|
||||
SkPMColor16* device = fDevice.getAddr16(x, y);
|
||||
SkPMColor* span = fBuffer;
|
||||
|
||||
fShader->shadeSpan(x, y, span, width);
|
||||
if (fXfermode) {
|
||||
fXfermode->xfer4444(device, span, width, NULL);
|
||||
} else {
|
||||
fOpaqueProc(device, span, width, 0xFF, x, y);
|
||||
}
|
||||
}
|
||||
|
||||
virtual void blitAntiH(int x, int y, const SkAlpha antialias[],
|
||||
const int16_t runs[]) {
|
||||
SkPMColor* SK_RESTRICT span = fBuffer;
|
||||
uint8_t* SK_RESTRICT aaExpand = fAAExpand;
|
||||
SkPMColor16* device = fDevice.getAddr16(x, y);
|
||||
SkShader* shader = fShader;
|
||||
SkXfermode* xfer = fXfermode;
|
||||
|
||||
if (NULL != xfer) {
|
||||
for (;;) {
|
||||
int count = *runs;
|
||||
if (count <= 0) {
|
||||
break;
|
||||
}
|
||||
int aa = *antialias;
|
||||
if (aa) {
|
||||
shader->shadeSpan(x, y, span, count);
|
||||
if (255 == aa) {
|
||||
xfer->xfer4444(device, span, count, NULL);
|
||||
} else {
|
||||
const uint8_t* aaBuffer = antialias;
|
||||
if (count > 1) {
|
||||
memset(aaExpand, aa, count);
|
||||
aaBuffer = aaExpand;
|
||||
}
|
||||
xfer->xfer4444(device, span, count, aaBuffer);
|
||||
}
|
||||
}
|
||||
device += count;
|
||||
runs += count;
|
||||
antialias += count;
|
||||
x += count;
|
||||
}
|
||||
} else { // no xfermode
|
||||
for (;;) {
|
||||
int count = *runs;
|
||||
if (count <= 0) {
|
||||
break;
|
||||
}
|
||||
int aa = *antialias;
|
||||
if (aa) {
|
||||
fShader->shadeSpan(x, y, span, count);
|
||||
if (255 == aa) {
|
||||
fOpaqueProc(device, span, count, aa, x, y);
|
||||
} else {
|
||||
fAlphaProc(device, span, count, aa, x, y);
|
||||
}
|
||||
}
|
||||
device += count;
|
||||
runs += count;
|
||||
antialias += count;
|
||||
x += count;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
typedef SkShaderBlitter INHERITED;
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
SkBlitter* SkBlitter_ChooseD4444(const SkBitmap& device,
|
||||
const SkPaint& paint,
|
||||
void* storage, size_t storageSize)
|
||||
{
|
||||
SkBlitter* blitter;
|
||||
|
||||
if (paint.getShader()) {
|
||||
SK_PLACEMENT_NEW_ARGS(blitter, SkARGB4444_Shader_Blitter, storage, storageSize, (device, paint));
|
||||
} else {
|
||||
SK_PLACEMENT_NEW_ARGS(blitter, SkARGB4444_Blitter, storage, storageSize, (device, paint));
|
||||
}
|
||||
return blitter;
|
||||
}
|
|
@ -1,50 +0,0 @@
|
|||
|
||||
/*
|
||||
* Copyright 2006 The Android Open Source Project
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
|
||||
#include "SkCoreBlitters.h"
|
||||
|
||||
SkA1_Blitter::SkA1_Blitter(const SkBitmap& device, const SkPaint& paint)
|
||||
: INHERITED(device) {
|
||||
fSrcA = paint.getAlpha();
|
||||
}
|
||||
|
||||
void SkA1_Blitter::blitH(int x, int y, int width) {
|
||||
SkASSERT(x >= 0 && y >= 0 &&
|
||||
(unsigned)(x + width) <= (unsigned)fDevice.width());
|
||||
|
||||
if (fSrcA <= 0x7F) {
|
||||
return;
|
||||
}
|
||||
uint8_t* dst = fDevice.getAddr1(x, y);
|
||||
int right = x + width;
|
||||
|
||||
int left_mask = 0xFF >> (x & 7);
|
||||
int rite_mask = 0xFF << (8 - (right & 7));
|
||||
int full_runs = (right >> 3) - ((x + 7) >> 3);
|
||||
|
||||
// check for empty right mask, so we don't read off the end
|
||||
// (or go slower than we need to)
|
||||
if (rite_mask == 0) {
|
||||
SkASSERT(full_runs >= 0);
|
||||
full_runs -= 1;
|
||||
rite_mask = 0xFF;
|
||||
}
|
||||
if (left_mask == 0xFF) {
|
||||
full_runs -= 1;
|
||||
}
|
||||
if (full_runs < 0) {
|
||||
SkASSERT((left_mask & rite_mask) != 0);
|
||||
*dst |= (left_mask & rite_mask);
|
||||
} else {
|
||||
*dst++ |= left_mask;
|
||||
memset(dst, 0xFF, full_runs);
|
||||
dst += full_runs;
|
||||
*dst |= rite_mask;
|
||||
}
|
||||
}
|
|
@ -1,159 +0,0 @@
|
|||
|
||||
/*
|
||||
* Copyright 2009 The Android Open Source Project
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
|
||||
#include "SkColorTable.h"
|
||||
#include "SkFlattenableBuffers.h"
|
||||
#include "SkStream.h"
|
||||
#include "SkTemplates.h"
|
||||
|
||||
SK_DEFINE_INST_COUNT(SkColorTable)
|
||||
|
||||
SkColorTable::SkColorTable(int count)
|
||||
: f16BitCache(NULL), fFlags(0)
|
||||
{
|
||||
if (count < 0)
|
||||
count = 0;
|
||||
else if (count > 256)
|
||||
count = 256;
|
||||
|
||||
fCount = SkToU16(count);
|
||||
fColors = (SkPMColor*)sk_malloc_throw(count * sizeof(SkPMColor));
|
||||
memset(fColors, 0, count * sizeof(SkPMColor));
|
||||
|
||||
SkDEBUGCODE(fColorLockCount = 0;)
|
||||
SkDEBUGCODE(f16BitCacheLockCount = 0;)
|
||||
}
|
||||
|
||||
// As copy constructor is hidden in the class hierarchy, we need to call
|
||||
// default constructor explicitly to suppress a compiler warning.
|
||||
SkColorTable::SkColorTable(const SkColorTable& src) : INHERITED() {
|
||||
f16BitCache = NULL;
|
||||
fFlags = src.fFlags;
|
||||
int count = src.count();
|
||||
fCount = SkToU16(count);
|
||||
fColors = reinterpret_cast<SkPMColor*>(
|
||||
sk_malloc_throw(count * sizeof(SkPMColor)));
|
||||
memcpy(fColors, src.fColors, count * sizeof(SkPMColor));
|
||||
|
||||
SkDEBUGCODE(fColorLockCount = 0;)
|
||||
SkDEBUGCODE(f16BitCacheLockCount = 0;)
|
||||
}
|
||||
|
||||
SkColorTable::SkColorTable(const SkPMColor colors[], int count)
|
||||
: f16BitCache(NULL), fFlags(0)
|
||||
{
|
||||
if (count < 0)
|
||||
count = 0;
|
||||
else if (count > 256)
|
||||
count = 256;
|
||||
|
||||
fCount = SkToU16(count);
|
||||
fColors = reinterpret_cast<SkPMColor*>(
|
||||
sk_malloc_throw(count * sizeof(SkPMColor)));
|
||||
|
||||
if (colors)
|
||||
memcpy(fColors, colors, count * sizeof(SkPMColor));
|
||||
|
||||
SkDEBUGCODE(fColorLockCount = 0;)
|
||||
SkDEBUGCODE(f16BitCacheLockCount = 0;)
|
||||
}
|
||||
|
||||
SkColorTable::~SkColorTable()
|
||||
{
|
||||
SkASSERT(fColorLockCount == 0);
|
||||
SkASSERT(f16BitCacheLockCount == 0);
|
||||
|
||||
sk_free(fColors);
|
||||
sk_free(f16BitCache);
|
||||
}
|
||||
|
||||
void SkColorTable::setFlags(unsigned flags)
|
||||
{
|
||||
fFlags = SkToU8(flags);
|
||||
}
|
||||
|
||||
void SkColorTable::unlockColors(bool changed)
|
||||
{
|
||||
SkASSERT(fColorLockCount != 0);
|
||||
SkDEBUGCODE(sk_atomic_dec(&fColorLockCount);)
|
||||
if (changed)
|
||||
this->inval16BitCache();
|
||||
}
|
||||
|
||||
void SkColorTable::inval16BitCache()
|
||||
{
|
||||
SkASSERT(f16BitCacheLockCount == 0);
|
||||
if (f16BitCache)
|
||||
{
|
||||
sk_free(f16BitCache);
|
||||
f16BitCache = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
#include "SkColorPriv.h"
|
||||
|
||||
static inline void build_16bitcache(uint16_t dst[], const SkPMColor src[], int count)
|
||||
{
|
||||
while (--count >= 0)
|
||||
*dst++ = SkPixel32ToPixel16_ToU16(*src++);
|
||||
}
|
||||
|
||||
const uint16_t* SkColorTable::lock16BitCache()
|
||||
{
|
||||
if (fFlags & kColorsAreOpaque_Flag)
|
||||
{
|
||||
if (f16BitCache == NULL) // build the cache
|
||||
{
|
||||
f16BitCache = (uint16_t*)sk_malloc_throw(fCount * sizeof(uint16_t));
|
||||
build_16bitcache(f16BitCache, fColors, fCount);
|
||||
}
|
||||
}
|
||||
else // our colors have alpha, so no cache
|
||||
{
|
||||
this->inval16BitCache();
|
||||
if (f16BitCache)
|
||||
{
|
||||
sk_free(f16BitCache);
|
||||
f16BitCache = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
SkDEBUGCODE(f16BitCacheLockCount += 1);
|
||||
return f16BitCache;
|
||||
}
|
||||
|
||||
void SkColorTable::setIsOpaque(bool isOpaque) {
|
||||
if (isOpaque) {
|
||||
fFlags |= kColorsAreOpaque_Flag;
|
||||
} else {
|
||||
fFlags &= ~kColorsAreOpaque_Flag;
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
SkColorTable::SkColorTable(SkFlattenableReadBuffer& buffer) {
|
||||
f16BitCache = NULL;
|
||||
SkDEBUGCODE(fColorLockCount = 0;)
|
||||
SkDEBUGCODE(f16BitCacheLockCount = 0;)
|
||||
|
||||
fFlags = buffer.readUInt();
|
||||
fCount = buffer.getArrayCount();
|
||||
fColors = (SkPMColor*)sk_malloc_throw(fCount * sizeof(SkPMColor));
|
||||
SkDEBUGCODE(const uint32_t countRead =) buffer.readColorArray(fColors);
|
||||
#ifdef SK_DEBUG
|
||||
SkASSERT((unsigned)fCount <= 256);
|
||||
SkASSERT(countRead == fCount);
|
||||
#endif
|
||||
}
|
||||
|
||||
void SkColorTable::flatten(SkFlattenableWriteBuffer& buffer) const {
|
||||
buffer.writeUInt(fFlags);
|
||||
buffer.writeColorArray(fColors, fCount);
|
||||
}
|
|
@ -1,323 +0,0 @@
|
|||
/*
|
||||
* Copyright 2011 Google Inc.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include "SkData.h"
|
||||
#include "SkFlattenableBuffers.h"
|
||||
|
||||
#if SK_MMAP_SUPPORT
|
||||
#include <unistd.h>
|
||||
#include <sys/mman.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#endif
|
||||
|
||||
SK_DEFINE_INST_COUNT(SkData)
|
||||
|
||||
SkData::SkData(const void* ptr, size_t size, ReleaseProc proc, void* context) {
|
||||
fPtr = ptr;
|
||||
fSize = size;
|
||||
fReleaseProc = proc;
|
||||
fReleaseProcContext = context;
|
||||
}
|
||||
|
||||
SkData::~SkData() {
|
||||
if (fReleaseProc) {
|
||||
fReleaseProc(fPtr, fSize, fReleaseProcContext);
|
||||
}
|
||||
}
|
||||
|
||||
bool SkData::equals(const SkData* other) const {
|
||||
if (NULL == other) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return fSize == other->fSize && !memcmp(fPtr, other->fPtr, fSize);
|
||||
}
|
||||
|
||||
size_t SkData::copyRange(size_t offset, size_t length, void* buffer) const {
|
||||
size_t available = fSize;
|
||||
if (offset >= available || 0 == length) {
|
||||
return 0;
|
||||
}
|
||||
available -= offset;
|
||||
if (length > available) {
|
||||
length = available;
|
||||
}
|
||||
SkASSERT(length > 0);
|
||||
|
||||
memcpy(buffer, this->bytes() + offset, length);
|
||||
return length;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
SkData* SkData::NewEmpty() {
|
||||
static SkData* gEmptyRef;
|
||||
if (NULL == gEmptyRef) {
|
||||
gEmptyRef = new SkData(NULL, 0, NULL, NULL);
|
||||
}
|
||||
gEmptyRef->ref();
|
||||
return gEmptyRef;
|
||||
}
|
||||
|
||||
// assumes fPtr was allocated via sk_malloc
|
||||
static void sk_free_releaseproc(const void* ptr, size_t, void*) {
|
||||
sk_free((void*)ptr);
|
||||
}
|
||||
|
||||
SkData* SkData::NewFromMalloc(const void* data, size_t length) {
|
||||
return new SkData(data, length, sk_free_releaseproc, NULL);
|
||||
}
|
||||
|
||||
SkData* SkData::NewWithCopy(const void* data, size_t length) {
|
||||
if (0 == length) {
|
||||
return SkData::NewEmpty();
|
||||
}
|
||||
|
||||
void* copy = sk_malloc_throw(length); // balanced in sk_free_releaseproc
|
||||
memcpy(copy, data, length);
|
||||
return new SkData(copy, length, sk_free_releaseproc, NULL);
|
||||
}
|
||||
|
||||
SkData* SkData::NewWithProc(const void* data, size_t length,
|
||||
ReleaseProc proc, void* context) {
|
||||
return new SkData(data, length, proc, context);
|
||||
}
|
||||
|
||||
// assumes context is a SkData
|
||||
static void sk_dataref_releaseproc(const void*, size_t, void* context) {
|
||||
SkData* src = reinterpret_cast<SkData*>(context);
|
||||
src->unref();
|
||||
}
|
||||
|
||||
SkData* SkData::NewSubset(const SkData* src, size_t offset, size_t length) {
|
||||
/*
|
||||
We could, if we wanted/need to, just make a deep copy of src's data,
|
||||
rather than referencing it. This would duplicate the storage (of the
|
||||
subset amount) but would possibly allow src to go out of scope sooner.
|
||||
*/
|
||||
|
||||
size_t available = src->size();
|
||||
if (offset >= available || 0 == length) {
|
||||
return SkData::NewEmpty();
|
||||
}
|
||||
available -= offset;
|
||||
if (length > available) {
|
||||
length = available;
|
||||
}
|
||||
SkASSERT(length > 0);
|
||||
|
||||
src->ref(); // this will be balanced in sk_dataref_releaseproc
|
||||
return new SkData(src->bytes() + offset, length, sk_dataref_releaseproc,
|
||||
const_cast<SkData*>(src));
|
||||
}
|
||||
|
||||
SkData* SkData::NewWithCString(const char cstr[]) {
|
||||
size_t size;
|
||||
if (NULL == cstr) {
|
||||
cstr = "";
|
||||
size = 1;
|
||||
} else {
|
||||
size = strlen(cstr) + 1;
|
||||
}
|
||||
return NewWithCopy(cstr, size);
|
||||
}
|
||||
|
||||
#if SK_MMAP_SUPPORT
|
||||
static void sk_munmap_releaseproc(const void* addr, size_t length, void*) {
|
||||
munmap(const_cast<void*>(addr), length);
|
||||
}
|
||||
|
||||
SkData* SkData::NewFromMMap(const void* addr, size_t length) {
|
||||
return SkNEW_ARGS(SkData, (addr, length, sk_munmap_releaseproc, NULL));
|
||||
}
|
||||
#else
|
||||
SkData* SkData::NewFromMMap(const void* addr, size_t length) {
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void SkData::flatten(SkFlattenableWriteBuffer& buffer) const {
|
||||
buffer.writeByteArray(fPtr, fSize);
|
||||
}
|
||||
|
||||
SkData::SkData(SkFlattenableReadBuffer& buffer) {
|
||||
fSize = buffer.getArrayCount();
|
||||
fReleaseProcContext = NULL;
|
||||
|
||||
if (fSize > 0) {
|
||||
fPtr = sk_malloc_throw(fSize);
|
||||
fReleaseProc = sk_free_releaseproc;
|
||||
} else {
|
||||
fPtr = NULL;
|
||||
fReleaseProc = NULL;
|
||||
}
|
||||
|
||||
buffer.readByteArray(const_cast<void*>(fPtr));
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "SkDataSet.h"
|
||||
#include "SkFlattenable.h"
|
||||
#include "SkStream.h"
|
||||
|
||||
static SkData* dupdata(SkData* data) {
|
||||
if (data) {
|
||||
data->ref();
|
||||
} else {
|
||||
data = SkData::NewEmpty();
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
static SkData* findValue(const char key[], const SkDataSet::Pair array[], int n) {
|
||||
for (int i = 0; i < n; ++i) {
|
||||
if (!strcmp(key, array[i].fKey)) {
|
||||
return array[i].fValue;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static SkDataSet::Pair* allocatePairStorage(int count, size_t storage) {
|
||||
size_t size = count * sizeof(SkDataSet::Pair) + storage;
|
||||
return (SkDataSet::Pair*)sk_malloc_throw(size);
|
||||
}
|
||||
|
||||
SkDataSet::SkDataSet(const char key[], SkData* value) {
|
||||
size_t keyLen = strlen(key);
|
||||
|
||||
fCount = 1;
|
||||
fKeySize = keyLen + 1;
|
||||
fPairs = allocatePairStorage(1, keyLen + 1);
|
||||
|
||||
fPairs[0].fKey = (char*)(fPairs + 1);
|
||||
memcpy(const_cast<char*>(fPairs[0].fKey), key, keyLen + 1);
|
||||
|
||||
fPairs[0].fValue = dupdata(value);
|
||||
}
|
||||
|
||||
SkDataSet::SkDataSet(const Pair array[], int count) {
|
||||
if (count < 1) {
|
||||
fCount = 0;
|
||||
fKeySize = 0;
|
||||
fPairs = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
int i;
|
||||
size_t keySize = 0;
|
||||
for (i = 0; i < count; ++i) {
|
||||
keySize += strlen(array[i].fKey) + 1;
|
||||
}
|
||||
|
||||
Pair* pairs = fPairs = allocatePairStorage(count, keySize);
|
||||
char* keyStorage = (char*)(pairs + count);
|
||||
|
||||
keySize = 0; // reset this, so we can compute the size for unique keys
|
||||
int uniqueCount = 0;
|
||||
for (int i = 0; i < count; ++i) {
|
||||
if (!findValue(array[i].fKey, pairs, uniqueCount)) {
|
||||
size_t len = strlen(array[i].fKey);
|
||||
memcpy(keyStorage, array[i].fKey, len + 1);
|
||||
pairs[uniqueCount].fKey = keyStorage;
|
||||
keyStorage += len + 1;
|
||||
keySize += len + 1;
|
||||
|
||||
pairs[uniqueCount].fValue = dupdata(array[i].fValue);
|
||||
uniqueCount += 1;
|
||||
}
|
||||
}
|
||||
fCount = uniqueCount;
|
||||
fKeySize = keySize;
|
||||
}
|
||||
|
||||
SkDataSet::~SkDataSet() {
|
||||
for (int i = 0; i < fCount; ++i) {
|
||||
fPairs[i].fValue->unref();
|
||||
}
|
||||
sk_free(fPairs); // this also frees the key storage
|
||||
}
|
||||
|
||||
SkData* SkDataSet::find(const char key[]) const {
|
||||
return findValue(key, fPairs, fCount);
|
||||
}
|
||||
|
||||
void SkDataSet::writeToStream(SkWStream* stream) const {
|
||||
stream->write32(fCount);
|
||||
if (fCount > 0) {
|
||||
stream->write32(fKeySize);
|
||||
// our first key points to all the key storage
|
||||
stream->write(fPairs[0].fKey, fKeySize);
|
||||
for (int i = 0; i < fCount; ++i) {
|
||||
stream->writeData(fPairs[i].fValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SkDataSet::flatten(SkFlattenableWriteBuffer& buffer) const {
|
||||
buffer.writeInt(fCount);
|
||||
if (fCount > 0) {
|
||||
buffer.writeByteArray(fPairs[0].fKey, fKeySize);
|
||||
for (int i = 0; i < fCount; ++i) {
|
||||
buffer.writeFlattenable(fPairs[i].fValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SkDataSet::SkDataSet(SkStream* stream) {
|
||||
fCount = stream->readU32();
|
||||
if (fCount > 0) {
|
||||
fKeySize = stream->readU32();
|
||||
fPairs = allocatePairStorage(fCount, fKeySize);
|
||||
char* keyStorage = (char*)(fPairs + fCount);
|
||||
|
||||
stream->read(keyStorage, fKeySize);
|
||||
|
||||
for (int i = 0; i < fCount; ++i) {
|
||||
fPairs[i].fKey = keyStorage;
|
||||
keyStorage += strlen(keyStorage) + 1;
|
||||
fPairs[i].fValue = stream->readData();
|
||||
}
|
||||
} else {
|
||||
fKeySize = 0;
|
||||
fPairs = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
SkDataSet::SkDataSet(SkFlattenableReadBuffer& buffer) {
|
||||
fCount = buffer.readInt();
|
||||
if (fCount > 0) {
|
||||
fKeySize = buffer.getArrayCount();
|
||||
fPairs = allocatePairStorage(fCount, fKeySize);
|
||||
char* keyStorage = (char*)(fPairs + fCount);
|
||||
|
||||
buffer.readByteArray(keyStorage);
|
||||
|
||||
for (int i = 0; i < fCount; ++i) {
|
||||
fPairs[i].fKey = keyStorage;
|
||||
keyStorage += strlen(keyStorage) + 1;
|
||||
fPairs[i].fValue = buffer.readFlattenableT<SkData>();
|
||||
}
|
||||
} else {
|
||||
fKeySize = 0;
|
||||
fPairs = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
SkDataSet* SkDataSet::NewEmpty() {
|
||||
static SkDataSet* gEmptySet;
|
||||
if (NULL == gEmptySet) {
|
||||
gEmptySet = SkNEW_ARGS(SkDataSet, (NULL, 0));
|
||||
}
|
||||
gEmptySet->ref();
|
||||
return gEmptySet;
|
||||
}
|
|
@ -1,546 +0,0 @@
|
|||
|
||||
/*
|
||||
* Copyright 2011 Google Inc.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
#include "SkDevice.h"
|
||||
#include "SkDeviceProperties.h"
|
||||
#include "SkDraw.h"
|
||||
#include "SkImageFilter.h"
|
||||
#include "SkMetaData.h"
|
||||
#include "SkRasterClip.h"
|
||||
#include "SkRect.h"
|
||||
#include "SkShader.h"
|
||||
|
||||
SK_DEFINE_INST_COUNT(SkDevice)
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#define CHECK_FOR_NODRAW_ANNOTATION(paint) \
|
||||
do { if (paint.isNoDrawAnnotation()) { return; } } while (0)
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
SkDevice::SkDevice(const SkBitmap& bitmap)
|
||||
: fBitmap(bitmap), fLeakyProperties(SkDeviceProperties::MakeDefault())
|
||||
#ifdef SK_DEBUG
|
||||
, fAttachedToCanvas(false)
|
||||
#endif
|
||||
{
|
||||
fOrigin.setZero();
|
||||
fMetaData = NULL;
|
||||
}
|
||||
|
||||
SkDevice::SkDevice(const SkBitmap& bitmap, const SkDeviceProperties& deviceProperties)
|
||||
: fBitmap(bitmap), fLeakyProperties(deviceProperties)
|
||||
#ifdef SK_DEBUG
|
||||
, fAttachedToCanvas(false)
|
||||
#endif
|
||||
{
|
||||
fOrigin.setZero();
|
||||
fMetaData = NULL;
|
||||
}
|
||||
|
||||
SkDevice::SkDevice(SkBitmap::Config config, int width, int height, bool isOpaque)
|
||||
: fLeakyProperties(SkDeviceProperties::MakeDefault())
|
||||
#ifdef SK_DEBUG
|
||||
, fAttachedToCanvas(false)
|
||||
#endif
|
||||
{
|
||||
fOrigin.setZero();
|
||||
fMetaData = NULL;
|
||||
|
||||
fBitmap.setConfig(config, width, height);
|
||||
fBitmap.allocPixels();
|
||||
fBitmap.setIsOpaque(isOpaque);
|
||||
if (!isOpaque) {
|
||||
fBitmap.eraseColor(SK_ColorTRANSPARENT);
|
||||
}
|
||||
}
|
||||
|
||||
SkDevice::SkDevice(SkBitmap::Config config, int width, int height, bool isOpaque,
|
||||
const SkDeviceProperties& deviceProperties)
|
||||
: fLeakyProperties(deviceProperties)
|
||||
#ifdef SK_DEBUG
|
||||
, fAttachedToCanvas(false)
|
||||
#endif
|
||||
{
|
||||
fOrigin.setZero();
|
||||
fMetaData = NULL;
|
||||
|
||||
fBitmap.setConfig(config, width, height);
|
||||
fBitmap.allocPixels();
|
||||
fBitmap.setIsOpaque(isOpaque);
|
||||
if (!isOpaque) {
|
||||
fBitmap.eraseColor(SK_ColorTRANSPARENT);
|
||||
}
|
||||
}
|
||||
|
||||
SkDevice::~SkDevice() {
|
||||
delete fMetaData;
|
||||
}
|
||||
|
||||
void SkDevice::replaceBitmapBackendForRasterSurface(const SkBitmap& bm) {
|
||||
SkASSERT(bm.width() == fBitmap.width());
|
||||
SkASSERT(bm.height() == fBitmap.height());
|
||||
fBitmap = bm; // intent is to use bm's pixelRef (and rowbytes/config)
|
||||
fBitmap.lockPixels();
|
||||
}
|
||||
|
||||
SkDevice* SkDevice::createCompatibleDevice(SkBitmap::Config config,
|
||||
int width, int height,
|
||||
bool isOpaque) {
|
||||
return this->onCreateCompatibleDevice(config, width, height,
|
||||
isOpaque, kGeneral_Usage);
|
||||
}
|
||||
|
||||
SkDevice* SkDevice::createCompatibleDeviceForSaveLayer(SkBitmap::Config config,
|
||||
int width, int height,
|
||||
bool isOpaque) {
|
||||
return this->onCreateCompatibleDevice(config, width, height,
|
||||
isOpaque, kSaveLayer_Usage);
|
||||
}
|
||||
|
||||
SkDevice* SkDevice::onCreateCompatibleDevice(SkBitmap::Config config,
|
||||
int width, int height,
|
||||
bool isOpaque,
|
||||
Usage usage) {
|
||||
return SkNEW_ARGS(SkDevice,(config, width, height, isOpaque, fLeakyProperties));
|
||||
}
|
||||
|
||||
SkMetaData& SkDevice::getMetaData() {
|
||||
// metadata users are rare, so we lazily allocate it. If that changes we
|
||||
// can decide to just make it a field in the device (rather than a ptr)
|
||||
if (NULL == fMetaData) {
|
||||
fMetaData = new SkMetaData;
|
||||
}
|
||||
return *fMetaData;
|
||||
}
|
||||
|
||||
void SkDevice::lockPixels() {
|
||||
if (fBitmap.lockPixelsAreWritable()) {
|
||||
fBitmap.lockPixels();
|
||||
}
|
||||
}
|
||||
|
||||
void SkDevice::unlockPixels() {
|
||||
if (fBitmap.lockPixelsAreWritable()) {
|
||||
fBitmap.unlockPixels();
|
||||
}
|
||||
}
|
||||
|
||||
const SkBitmap& SkDevice::accessBitmap(bool changePixels) {
|
||||
const SkBitmap& bitmap = this->onAccessBitmap(&fBitmap);
|
||||
if (changePixels) {
|
||||
bitmap.notifyPixelsChanged();
|
||||
}
|
||||
return bitmap;
|
||||
}
|
||||
|
||||
void SkDevice::getGlobalBounds(SkIRect* bounds) const {
|
||||
if (bounds) {
|
||||
bounds->setXYWH(fOrigin.x(), fOrigin.y(),
|
||||
fBitmap.width(), fBitmap.height());
|
||||
}
|
||||
}
|
||||
|
||||
void SkDevice::clear(SkColor color) {
|
||||
fBitmap.eraseColor(color);
|
||||
}
|
||||
|
||||
const SkBitmap& SkDevice::onAccessBitmap(SkBitmap* bitmap) {return *bitmap;}
|
||||
|
||||
void SkDevice::setMatrixClip(const SkMatrix& matrix, const SkRegion& region,
|
||||
const SkClipStack& clipStack) {
|
||||
}
|
||||
|
||||
bool SkDevice::canHandleImageFilter(SkImageFilter*) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool SkDevice::filterImage(SkImageFilter* filter, const SkBitmap& src,
|
||||
const SkMatrix& ctm, SkBitmap* result,
|
||||
SkIPoint* offset) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool SkDevice::allowImageFilter(SkImageFilter*) {
|
||||
return true;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool SkDevice::readPixels(SkBitmap* bitmap, int x, int y,
|
||||
SkCanvas::Config8888 config8888) {
|
||||
if (SkBitmap::kARGB_8888_Config != bitmap->config() ||
|
||||
NULL != bitmap->getTexture()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const SkBitmap& src = this->accessBitmap(false);
|
||||
|
||||
SkIRect srcRect = SkIRect::MakeXYWH(x, y, bitmap->width(),
|
||||
bitmap->height());
|
||||
SkIRect devbounds = SkIRect::MakeWH(src.width(), src.height());
|
||||
if (!srcRect.intersect(devbounds)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
SkBitmap tmp;
|
||||
SkBitmap* bmp;
|
||||
if (bitmap->isNull()) {
|
||||
tmp.setConfig(SkBitmap::kARGB_8888_Config, bitmap->width(),
|
||||
bitmap->height());
|
||||
if (!tmp.allocPixels()) {
|
||||
return false;
|
||||
}
|
||||
bmp = &tmp;
|
||||
} else {
|
||||
bmp = bitmap;
|
||||
}
|
||||
|
||||
SkIRect subrect = srcRect;
|
||||
subrect.offset(-x, -y);
|
||||
SkBitmap bmpSubset;
|
||||
bmp->extractSubset(&bmpSubset, subrect);
|
||||
|
||||
bool result = this->onReadPixels(bmpSubset,
|
||||
srcRect.fLeft,
|
||||
srcRect.fTop,
|
||||
config8888);
|
||||
if (result && bmp == &tmp) {
|
||||
tmp.swap(*bitmap);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
#ifdef SK_CPU_LENDIAN
|
||||
#if 24 == SK_A32_SHIFT && 16 == SK_R32_SHIFT && \
|
||||
8 == SK_G32_SHIFT && 0 == SK_B32_SHIFT
|
||||
const SkCanvas::Config8888 SkDevice::kPMColorAlias =
|
||||
SkCanvas::kBGRA_Premul_Config8888;
|
||||
#elif 24 == SK_A32_SHIFT && 0 == SK_R32_SHIFT && \
|
||||
8 == SK_G32_SHIFT && 16 == SK_B32_SHIFT
|
||||
const SkCanvas::Config8888 SkDevice::kPMColorAlias =
|
||||
SkCanvas::kRGBA_Premul_Config8888;
|
||||
#else
|
||||
const SkCanvas::Config8888 SkDevice::kPMColorAlias =
|
||||
(SkCanvas::Config8888) -1;
|
||||
#endif
|
||||
#else
|
||||
#if 0 == SK_A32_SHIFT && 8 == SK_R32_SHIFT && \
|
||||
16 == SK_G32_SHIFT && 24 == SK_B32_SHIFT
|
||||
const SkCanvas::Config8888 SkDevice::kPMColorAlias =
|
||||
SkCanvas::kBGRA_Premul_Config8888;
|
||||
#elif 0 == SK_A32_SHIFT && 24 == SK_R32_SHIFT && \
|
||||
16 == SK_G32_SHIFT && 8 == SK_B32_SHIFT
|
||||
const SkCanvas::Config8888 SkDevice::kPMColorAlias =
|
||||
SkCanvas::kRGBA_Premul_Config8888;
|
||||
#else
|
||||
const SkCanvas::Config8888 SkDevice::kPMColorAlias =
|
||||
(SkCanvas::Config8888) -1;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include <SkConfig8888.h>
|
||||
|
||||
bool SkDevice::onReadPixels(const SkBitmap& bitmap,
|
||||
int x, int y,
|
||||
SkCanvas::Config8888 config8888) {
|
||||
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())));
|
||||
|
||||
SkIRect srcRect = SkIRect::MakeXYWH(x, y, bitmap.width(),
|
||||
bitmap.height());
|
||||
const SkBitmap& src = this->accessBitmap(false);
|
||||
|
||||
SkBitmap subset;
|
||||
if (!src.extractSubset(&subset, srcRect)) {
|
||||
return false;
|
||||
}
|
||||
if (SkBitmap::kARGB_8888_Config != subset.config()) {
|
||||
// It'd be preferable to do this directly to bitmap.
|
||||
subset.copyTo(&subset, SkBitmap::kARGB_8888_Config);
|
||||
}
|
||||
SkAutoLockPixels alp(bitmap);
|
||||
uint32_t* bmpPixels = reinterpret_cast<uint32_t*>(bitmap.getPixels());
|
||||
SkCopyBitmapToConfig8888(bmpPixels, bitmap.rowBytes(), config8888, subset);
|
||||
return true;
|
||||
}
|
||||
|
||||
void SkDevice::writePixels(const SkBitmap& bitmap,
|
||||
int x, int y,
|
||||
SkCanvas::Config8888 config8888) {
|
||||
if (bitmap.isNull() || bitmap.getTexture()) {
|
||||
return;
|
||||
}
|
||||
const SkBitmap* sprite = &bitmap;
|
||||
// check whether we have to handle a config8888 that doesn't match SkPMColor
|
||||
if (SkBitmap::kARGB_8888_Config == bitmap.config() &&
|
||||
SkCanvas::kNative_Premul_Config8888 != config8888 &&
|
||||
kPMColorAlias != config8888) {
|
||||
|
||||
// We're going to have to convert from a config8888 to the native config
|
||||
// First we clip to the device bounds.
|
||||
SkBitmap dstBmp = this->accessBitmap(true);
|
||||
SkIRect spriteRect = SkIRect::MakeXYWH(x, y,
|
||||
bitmap.width(), bitmap.height());
|
||||
SkIRect devRect = SkIRect::MakeWH(dstBmp.width(), dstBmp.height());
|
||||
if (!spriteRect.intersect(devRect)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// write directly to the device if it has pixels and is SkPMColor
|
||||
bool drawSprite;
|
||||
if (SkBitmap::kARGB_8888_Config == dstBmp.config() && !dstBmp.isNull()) {
|
||||
// we can write directly to the dst when doing the conversion
|
||||
dstBmp.extractSubset(&dstBmp, spriteRect);
|
||||
drawSprite = false;
|
||||
} else {
|
||||
// we convert to a temporary bitmap and draw that as a sprite
|
||||
dstBmp.setConfig(SkBitmap::kARGB_8888_Config,
|
||||
spriteRect.width(),
|
||||
spriteRect.height());
|
||||
if (!dstBmp.allocPixels()) {
|
||||
return;
|
||||
}
|
||||
drawSprite = true;
|
||||
}
|
||||
|
||||
// copy pixels to dstBmp and convert from config8888 to native config.
|
||||
SkAutoLockPixels alp(bitmap);
|
||||
uint32_t* srcPixels = bitmap.getAddr32(spriteRect.fLeft - x,
|
||||
spriteRect.fTop - y);
|
||||
SkCopyConfig8888ToBitmap(dstBmp,
|
||||
srcPixels,
|
||||
bitmap.rowBytes(),
|
||||
config8888);
|
||||
|
||||
if (drawSprite) {
|
||||
// we've clipped the sprite when we made a copy
|
||||
x = spriteRect.fLeft;
|
||||
y = spriteRect.fTop;
|
||||
sprite = &dstBmp;
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
SkPaint paint;
|
||||
paint.setXfermodeMode(SkXfermode::kSrc_Mode);
|
||||
SkRasterClip clip(SkIRect::MakeWH(fBitmap.width(), fBitmap.height()));
|
||||
SkDraw draw;
|
||||
draw.fRC = &clip;
|
||||
draw.fClip = &clip.bwRgn();
|
||||
draw.fBitmap = &fBitmap; // canvas should have already called accessBitmap
|
||||
draw.fMatrix = &SkMatrix::I();
|
||||
this->drawSprite(draw, *sprite, x, y, paint);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void SkDevice::drawPaint(const SkDraw& draw, const SkPaint& paint) {
|
||||
draw.drawPaint(paint);
|
||||
}
|
||||
|
||||
void SkDevice::drawPoints(const SkDraw& draw, SkCanvas::PointMode mode, size_t count,
|
||||
const SkPoint pts[], const SkPaint& paint) {
|
||||
CHECK_FOR_NODRAW_ANNOTATION(paint);
|
||||
draw.drawPoints(mode, count, pts, paint);
|
||||
}
|
||||
|
||||
void SkDevice::drawRect(const SkDraw& draw, const SkRect& r, const SkPaint& paint) {
|
||||
CHECK_FOR_NODRAW_ANNOTATION(paint);
|
||||
draw.drawRect(r, paint);
|
||||
}
|
||||
|
||||
void SkDevice::drawOval(const SkDraw& draw, const SkRect& oval, const SkPaint& paint) {
|
||||
CHECK_FOR_NODRAW_ANNOTATION(paint);
|
||||
|
||||
SkPath path;
|
||||
path.addOval(oval);
|
||||
// call the VIRTUAL version, so any subclasses who do handle drawPath aren't
|
||||
// required to override drawOval.
|
||||
this->drawPath(draw, path, paint, NULL, true);
|
||||
}
|
||||
|
||||
void SkDevice::drawPath(const SkDraw& draw, const SkPath& path,
|
||||
const SkPaint& paint, const SkMatrix* prePathMatrix,
|
||||
bool pathIsMutable) {
|
||||
CHECK_FOR_NODRAW_ANNOTATION(paint);
|
||||
draw.drawPath(path, paint, prePathMatrix, pathIsMutable);
|
||||
}
|
||||
|
||||
void SkDevice::drawBitmap(const SkDraw& draw, const SkBitmap& bitmap,
|
||||
const SkIRect* srcRect,
|
||||
const SkMatrix& matrix, const SkPaint& paint) {
|
||||
SkBitmap tmp; // storage if we need a subset of bitmap
|
||||
const SkBitmap* bitmapPtr = &bitmap;
|
||||
|
||||
if (srcRect) {
|
||||
if (!bitmap.extractSubset(&tmp, *srcRect)) {
|
||||
return; // extraction failed
|
||||
}
|
||||
bitmapPtr = &tmp;
|
||||
}
|
||||
draw.drawBitmap(*bitmapPtr, matrix, paint);
|
||||
}
|
||||
|
||||
void SkDevice::drawBitmapRect(const SkDraw& draw, const SkBitmap& bitmap,
|
||||
const SkRect* src, const SkRect& dst,
|
||||
const SkPaint& paint) {
|
||||
SkMatrix matrix;
|
||||
SkRect bitmapBounds, tmpSrc, tmpDst;
|
||||
SkBitmap tmpBitmap;
|
||||
|
||||
bitmapBounds.isetWH(bitmap.width(), bitmap.height());
|
||||
|
||||
// Compute matrix from the two rectangles
|
||||
if (src) {
|
||||
tmpSrc = *src;
|
||||
} else {
|
||||
tmpSrc = bitmapBounds;
|
||||
}
|
||||
matrix.setRectToRect(tmpSrc, dst, SkMatrix::kFill_ScaleToFit);
|
||||
|
||||
const SkRect* dstPtr = &dst;
|
||||
const SkBitmap* bitmapPtr = &bitmap;
|
||||
|
||||
// clip the tmpSrc to the bounds of the bitmap, and recompute dstRect if
|
||||
// needed (if the src was clipped). No check needed if src==null.
|
||||
if (src) {
|
||||
if (!bitmapBounds.contains(*src)) {
|
||||
if (!tmpSrc.intersect(bitmapBounds)) {
|
||||
return; // nothing to draw
|
||||
}
|
||||
// recompute dst, based on the smaller tmpSrc
|
||||
matrix.mapRect(&tmpDst, tmpSrc);
|
||||
dstPtr = &tmpDst;
|
||||
}
|
||||
|
||||
// since we may need to clamp to the borders of the src rect within
|
||||
// the bitmap, we extract a subset.
|
||||
SkIRect srcIR;
|
||||
tmpSrc.roundOut(&srcIR);
|
||||
if (!bitmap.extractSubset(&tmpBitmap, srcIR)) {
|
||||
return;
|
||||
}
|
||||
bitmapPtr = &tmpBitmap;
|
||||
|
||||
// Since we did an extract, we need to adjust the matrix accordingly
|
||||
SkScalar dx = 0, dy = 0;
|
||||
if (srcIR.fLeft > 0) {
|
||||
dx = SkIntToScalar(srcIR.fLeft);
|
||||
}
|
||||
if (srcIR.fTop > 0) {
|
||||
dy = SkIntToScalar(srcIR.fTop);
|
||||
}
|
||||
if (dx || dy) {
|
||||
matrix.preTranslate(dx, dy);
|
||||
}
|
||||
|
||||
SkRect extractedBitmapBounds;
|
||||
extractedBitmapBounds.isetWH(bitmapPtr->width(), bitmapPtr->height());
|
||||
if (extractedBitmapBounds == tmpSrc) {
|
||||
// no fractional part in src, we can just call drawBitmap
|
||||
goto USE_DRAWBITMAP;
|
||||
}
|
||||
} else {
|
||||
USE_DRAWBITMAP:
|
||||
// We can go faster by just calling drawBitmap, which will concat the
|
||||
// matrix with the CTM, and try to call drawSprite if it can. If not,
|
||||
// it will make a shader and call drawRect, as we do below.
|
||||
this->drawBitmap(draw, *bitmapPtr, NULL, matrix, paint);
|
||||
return;
|
||||
}
|
||||
|
||||
// construct a shader, so we can call drawRect with the dst
|
||||
SkShader* s = SkShader::CreateBitmapShader(*bitmapPtr,
|
||||
SkShader::kClamp_TileMode,
|
||||
SkShader::kClamp_TileMode);
|
||||
if (NULL == s) {
|
||||
return;
|
||||
}
|
||||
s->setLocalMatrix(matrix);
|
||||
|
||||
SkPaint paintWithShader(paint);
|
||||
paintWithShader.setStyle(SkPaint::kFill_Style);
|
||||
paintWithShader.setShader(s)->unref();
|
||||
|
||||
// Call ourself, in case the subclass wanted to share this setup code
|
||||
// but handle the drawRect code themselves.
|
||||
this->drawRect(draw, *dstPtr, paintWithShader);
|
||||
}
|
||||
|
||||
void SkDevice::drawSprite(const SkDraw& draw, const SkBitmap& bitmap,
|
||||
int x, int y, const SkPaint& paint) {
|
||||
draw.drawSprite(bitmap, x, y, paint);
|
||||
}
|
||||
|
||||
void SkDevice::drawText(const SkDraw& draw, const void* text, size_t len,
|
||||
SkScalar x, SkScalar y, const SkPaint& paint) {
|
||||
draw.drawText((const char*)text, len, x, y, paint);
|
||||
}
|
||||
|
||||
void SkDevice::drawPosText(const SkDraw& draw, const void* text, size_t len,
|
||||
const SkScalar xpos[], SkScalar y,
|
||||
int scalarsPerPos, const SkPaint& paint) {
|
||||
draw.drawPosText((const char*)text, len, xpos, y, scalarsPerPos, paint);
|
||||
}
|
||||
|
||||
void SkDevice::drawTextOnPath(const SkDraw& draw, const void* text,
|
||||
size_t len, const SkPath& path,
|
||||
const SkMatrix* matrix,
|
||||
const SkPaint& paint) {
|
||||
draw.drawTextOnPath((const char*)text, len, path, matrix, paint);
|
||||
}
|
||||
|
||||
#ifdef SK_BUILD_FOR_ANDROID
|
||||
void SkDevice::drawPosTextOnPath(const SkDraw& draw, const void* text, size_t len,
|
||||
const SkPoint pos[], const SkPaint& paint,
|
||||
const SkPath& path, const SkMatrix* matrix) {
|
||||
draw.drawPosTextOnPath((const char*)text, len, pos, paint, path, matrix);
|
||||
}
|
||||
#endif
|
||||
|
||||
void SkDevice::drawVertices(const SkDraw& draw, SkCanvas::VertexMode vmode,
|
||||
int vertexCount,
|
||||
const SkPoint verts[], const SkPoint textures[],
|
||||
const SkColor colors[], SkXfermode* xmode,
|
||||
const uint16_t indices[], int indexCount,
|
||||
const SkPaint& paint) {
|
||||
draw.drawVertices(vmode, vertexCount, verts, textures, colors, xmode,
|
||||
indices, indexCount, paint);
|
||||
}
|
||||
|
||||
void SkDevice::drawDevice(const SkDraw& draw, SkDevice* device,
|
||||
int x, int y, const SkPaint& paint) {
|
||||
const SkBitmap& src = device->accessBitmap(false);
|
||||
draw.drawSprite(src, x, y, paint);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool SkDevice::filterTextFlags(const SkPaint& paint, TextFlags* flags) {
|
||||
if (!paint.isLCDRenderText() || !paint.isAntiAlias()) {
|
||||
// we're cool with the paint as is
|
||||
return false;
|
||||
}
|
||||
|
||||
if (SkBitmap::kARGB_8888_Config != fBitmap.config() ||
|
||||
paint.getRasterizer() ||
|
||||
paint.getPathEffect() ||
|
||||
paint.isFakeBoldText() ||
|
||||
paint.getStyle() != SkPaint::kFill_Style ||
|
||||
!SkXfermode::IsMode(paint.getXfermode(), SkXfermode::kSrcOver_Mode)) {
|
||||
// turn off lcd
|
||||
flags->fFlags = paint.getFlags() & ~SkPaint::kLCDRenderText_Flag;
|
||||
flags->fHinting = paint.getHinting();
|
||||
return true;
|
||||
}
|
||||
// we're cool with the paint as is
|
||||
return false;
|
||||
}
|
|
@ -1,104 +0,0 @@
|
|||
|
||||
/*
|
||||
* Copyright 2011 Google Inc.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
#include "SkStream.h"
|
||||
|
||||
#ifdef SK_BUILD_FOR_WIN
|
||||
|
||||
// -1 means isValid() will return false
|
||||
SkFDStream::SkFDStream(int, bool) : fFD(-1), fCloseWhenDone(false) {}
|
||||
SkFDStream::~SkFDStream() {}
|
||||
bool SkFDStream::rewind() { return false; }
|
||||
size_t SkFDStream::read(void*, size_t) { return 0; }
|
||||
|
||||
#else
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
//#define TRACE_FDSTREAM
|
||||
|
||||
SkFDStream::SkFDStream(int fileDesc, bool closeWhenDone)
|
||||
: fFD(fileDesc), fCloseWhenDone(closeWhenDone) {
|
||||
}
|
||||
|
||||
SkFDStream::~SkFDStream() {
|
||||
if (fFD >= 0 && fCloseWhenDone) {
|
||||
::close(fFD);
|
||||
}
|
||||
}
|
||||
|
||||
bool SkFDStream::rewind() {
|
||||
if (fFD >= 0) {
|
||||
off_t value = ::lseek(fFD, 0, SEEK_SET);
|
||||
#ifdef TRACE_FDSTREAM
|
||||
if (value) {
|
||||
SkDebugf("xxxxxxxxxxxxxx rewind failed %d\n", value);
|
||||
}
|
||||
#endif
|
||||
return value == 0;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t SkFDStream::read(void* buffer, size_t size) {
|
||||
if (fFD >= 0) {
|
||||
if (buffer == NULL && size == 0) { // request total size
|
||||
off_t curr = ::lseek(fFD, 0, SEEK_CUR);
|
||||
if (curr < 0) {
|
||||
#ifdef TRACE_FDSTREAM
|
||||
SkDebugf("xxxxxxxxxxxxx lseek failed 0 CURR\n");
|
||||
#endif
|
||||
return 0; // error
|
||||
}
|
||||
off_t size = ::lseek(fFD, 0, SEEK_END);
|
||||
if (size < 0) {
|
||||
#ifdef TRACE_FDSTREAM
|
||||
SkDebugf("xxxxxxxxxxxxx lseek failed 0 END\n");
|
||||
#endif
|
||||
size = 0; // error
|
||||
}
|
||||
if (::lseek(fFD, curr, SEEK_SET) != curr) {
|
||||
// can't restore, error
|
||||
#ifdef TRACE_FDSTREAM
|
||||
SkDebugf("xxxxxxxxxxxxx lseek failed %d SET\n", curr);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
return (size_t) size;
|
||||
} else if (NULL == buffer) { // skip
|
||||
off_t oldCurr = ::lseek(fFD, 0, SEEK_CUR);
|
||||
if (oldCurr < 0) {
|
||||
#ifdef TRACE_FDSTREAM
|
||||
SkDebugf("xxxxxxxxxxxxx lseek1 failed %d CUR\n", oldCurr);
|
||||
#endif
|
||||
return 0; // error;
|
||||
}
|
||||
off_t newCurr = ::lseek(fFD, size, SEEK_CUR);
|
||||
if (newCurr < 0) {
|
||||
#ifdef TRACE_FDSTREAM
|
||||
SkDebugf("xxxxxxxxxxxxx lseek2 failed %d CUR\n", newCurr);
|
||||
#endif
|
||||
return 0; // error;
|
||||
}
|
||||
// return the actual amount we skipped
|
||||
return (size_t) (newCurr - oldCurr);
|
||||
} else { // read
|
||||
ssize_t actual = ::read(fFD, buffer, size);
|
||||
// our API can't return an error, so we return 0
|
||||
if (actual < 0) {
|
||||
#ifdef TRACE_FDSTREAM
|
||||
SkDebugf("xxxxxxxxxxxxx read failed %d actual %d\n", size, actual);
|
||||
#endif
|
||||
actual = 0;
|
||||
}
|
||||
return actual;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
|
@ -1,56 +0,0 @@
|
|||
|
||||
/*
|
||||
* 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 "SkFlattenableBuffers.h"
|
||||
#include "SkPaint.h"
|
||||
#include "SkTypeface.h"
|
||||
|
||||
SkFlattenableReadBuffer::SkFlattenableReadBuffer() {
|
||||
// Set default values. These should be explicitly set by our client
|
||||
// via setFlags() if the buffer came from serialization.
|
||||
fFlags = 0;
|
||||
#ifdef SK_SCALAR_IS_FLOAT
|
||||
fFlags |= kScalarIsFloat_Flag;
|
||||
#endif
|
||||
if (8 == sizeof(void*)) {
|
||||
fFlags |= kPtrIs64Bit_Flag;
|
||||
}
|
||||
}
|
||||
|
||||
SkFlattenableReadBuffer::~SkFlattenableReadBuffer() { }
|
||||
|
||||
void* SkFlattenableReadBuffer::readFunctionPtr() {
|
||||
void* proc;
|
||||
SkASSERT(sizeof(void*) == this->getArrayCount());
|
||||
this->readByteArray(&proc);
|
||||
return proc;
|
||||
}
|
||||
|
||||
void SkFlattenableReadBuffer::readPaint(SkPaint* paint) {
|
||||
paint->unflatten(*this);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
SkFlattenableWriteBuffer::SkFlattenableWriteBuffer() {
|
||||
fFlags = (Flags)0;
|
||||
}
|
||||
|
||||
SkFlattenableWriteBuffer::~SkFlattenableWriteBuffer() { }
|
||||
|
||||
void SkFlattenableWriteBuffer::writeFunctionPtr(void* ptr) {
|
||||
void* ptrStorage[] = { ptr };
|
||||
this->writeByteArray(ptrStorage, sizeof(void*));
|
||||
}
|
||||
|
||||
void SkFlattenableWriteBuffer::writePaint(const SkPaint& paint) {
|
||||
paint.flatten(*this);
|
||||
}
|
||||
|
||||
void SkFlattenableWriteBuffer::flattenObject(SkFlattenable* obj, SkFlattenableWriteBuffer& buffer) {
|
||||
obj->flatten(buffer);
|
||||
}
|
|
@ -1,175 +0,0 @@
|
|||
/*
|
||||
* Copyright 2009 The Android Open Source Project
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include "SkFontLCDConfig.h"
|
||||
|
||||
static SkFontLCDConfig::LCDOrientation gLCDOrientation = SkFontLCDConfig::kHorizontal_LCDOrientation;
|
||||
static SkFontLCDConfig::LCDOrder gLCDOrder = SkFontLCDConfig::kRGB_LCDOrder;
|
||||
|
||||
SkFontLCDConfig::LCDOrientation SkFontLCDConfig::GetSubpixelOrientation() {
|
||||
return gLCDOrientation;
|
||||
}
|
||||
|
||||
void SkFontLCDConfig::SetSubpixelOrientation(LCDOrientation orientation) {
|
||||
gLCDOrientation = orientation;
|
||||
}
|
||||
|
||||
SkFontLCDConfig::LCDOrder SkFontLCDConfig::GetSubpixelOrder() {
|
||||
return gLCDOrder;
|
||||
}
|
||||
|
||||
void SkFontLCDConfig::SetSubpixelOrder(LCDOrder order) {
|
||||
gLCDOrder = order;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Legacy wrappers : remove from SkFontHost when webkit switches to new API
|
||||
|
||||
#include "SkFontHost.h"
|
||||
|
||||
SkFontHost::LCDOrientation SkFontHost::GetSubpixelOrientation() {
|
||||
return (SkFontHost::LCDOrientation)SkFontLCDConfig::GetSubpixelOrientation();
|
||||
}
|
||||
|
||||
void SkFontHost::SetSubpixelOrientation(LCDOrientation orientation) {
|
||||
SkFontLCDConfig::SetSubpixelOrientation((SkFontLCDConfig::LCDOrientation)orientation);
|
||||
}
|
||||
|
||||
SkFontHost::LCDOrder SkFontHost::GetSubpixelOrder() {
|
||||
return (SkFontHost::LCDOrder)SkFontLCDConfig::GetSubpixelOrder();
|
||||
}
|
||||
|
||||
void SkFontHost::SetSubpixelOrder(LCDOrder order) {
|
||||
SkFontLCDConfig::SetSubpixelOrder((SkFontLCDConfig::LCDOrder)order);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "SkFontStyle.h"
|
||||
|
||||
SkFontStyle::SkFontStyle() {
|
||||
fUnion.fU32 = 0;
|
||||
fUnion.fR.fWeight = kNormal_Weight;
|
||||
fUnion.fR.fWidth = kNormal_Width;
|
||||
fUnion.fR.fSlant = kUpright_Slant;
|
||||
}
|
||||
|
||||
SkFontStyle::SkFontStyle(int weight, int width, Slant slant) {
|
||||
fUnion.fU32 = 0;
|
||||
fUnion.fR.fWeight = SkPin32(weight, kThin_Weight, kBlack_Weight);
|
||||
fUnion.fR.fWidth = SkPin32(width, kUltraCondensed_Width, kUltaExpanded_Width);
|
||||
fUnion.fR.fSlant = SkPin32(slant, kUpright_Slant, kItalic_Slant);
|
||||
}
|
||||
|
||||
#include "SkFontMgr.h"
|
||||
|
||||
class SkEmptyFontStyleSet : public SkFontStyleSet {
|
||||
public:
|
||||
virtual int count() SK_OVERRIDE { return 0; }
|
||||
virtual void getStyle(int, SkFontStyle*, SkString*) SK_OVERRIDE {
|
||||
SkASSERT(!"SkFontStyleSet::getStyle called on empty set");
|
||||
}
|
||||
virtual SkTypeface* createTypeface(int index) SK_OVERRIDE {
|
||||
SkASSERT(!"SkFontStyleSet::createTypeface called on empty set");
|
||||
return NULL;
|
||||
}
|
||||
virtual SkTypeface* matchStyle(const SkFontStyle&) SK_OVERRIDE {
|
||||
return NULL;
|
||||
}
|
||||
};
|
||||
|
||||
SkFontStyleSet* SkFontStyleSet::CreateEmpty() {
|
||||
return SkNEW(SkEmptyFontStyleSet);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class SkEmptyFontMgr : public SkFontMgr {
|
||||
protected:
|
||||
virtual int onCountFamilies() SK_OVERRIDE {
|
||||
return 0;
|
||||
}
|
||||
virtual void onGetFamilyName(int index, SkString* familyName) SK_OVERRIDE {
|
||||
SkASSERT(!"onGetFamilyName called with bad index");
|
||||
}
|
||||
virtual SkFontStyleSet* onCreateStyleSet(int index) SK_OVERRIDE {
|
||||
SkASSERT(!"onCreateStyleSet called with bad index");
|
||||
return NULL;
|
||||
}
|
||||
virtual SkFontStyleSet* onMatchFamily(const char[]) SK_OVERRIDE {
|
||||
return SkFontStyleSet::CreateEmpty();
|
||||
}
|
||||
|
||||
virtual SkTypeface* onMatchFamilyStyle(const char[],
|
||||
const SkFontStyle&) SK_OVERRIDE {
|
||||
return NULL;
|
||||
}
|
||||
virtual SkTypeface* onMatchFaceStyle(const SkTypeface*,
|
||||
const SkFontStyle&) SK_OVERRIDE {
|
||||
return NULL;
|
||||
}
|
||||
virtual SkTypeface* onCreateFromData(SkData*, int) SK_OVERRIDE {
|
||||
return NULL;
|
||||
}
|
||||
virtual SkTypeface* onCreateFromStream(SkStream*, int) SK_OVERRIDE {
|
||||
return NULL;
|
||||
}
|
||||
virtual SkTypeface* onCreateFromFile(const char[], int) SK_OVERRIDE {
|
||||
return NULL;
|
||||
}
|
||||
};
|
||||
|
||||
int SkFontMgr::countFamilies() {
|
||||
return this->onCountFamilies();
|
||||
}
|
||||
|
||||
void SkFontMgr::getFamilyName(int index, SkString* familyName) {
|
||||
this->onGetFamilyName(index, familyName);
|
||||
}
|
||||
|
||||
SkFontStyleSet* SkFontMgr::createStyleSet(int index) {
|
||||
return this->onCreateStyleSet(index);
|
||||
}
|
||||
|
||||
SkFontStyleSet* SkFontMgr::matchFamily(const char familyName[]) {
|
||||
return this->onMatchFamily(familyName);
|
||||
}
|
||||
|
||||
SkTypeface* SkFontMgr::matchFamilyStyle(const char familyName[],
|
||||
const SkFontStyle& fs) {
|
||||
return this->onMatchFamilyStyle(familyName, fs);
|
||||
}
|
||||
|
||||
SkTypeface* SkFontMgr::matchFaceStyle(const SkTypeface* face,
|
||||
const SkFontStyle& fs) {
|
||||
return this->onMatchFaceStyle(face, fs);
|
||||
}
|
||||
|
||||
SkTypeface* SkFontMgr::createFromData(SkData* data, int ttcIndex) {
|
||||
return this->onCreateFromData(data, ttcIndex);
|
||||
}
|
||||
|
||||
SkTypeface* SkFontMgr::createFromStream(SkStream* stream, int ttcIndex) {
|
||||
return this->onCreateFromStream(stream, ttcIndex);
|
||||
}
|
||||
|
||||
SkTypeface* SkFontMgr::createFromFile(const char path[], int ttcIndex) {
|
||||
return this->onCreateFromFile(path, ttcIndex);
|
||||
}
|
||||
|
||||
SkFontMgr* SkFontMgr::RefDefault() {
|
||||
static SkFontMgr* gFM;
|
||||
if (NULL == gFM) {
|
||||
gFM = SkFontMgr::Factory();
|
||||
// we never want to return NULL
|
||||
if (NULL == gFM) {
|
||||
gFM = SkNEW(SkEmptyFontMgr);
|
||||
}
|
||||
}
|
||||
return SkRef(gFM);
|
||||
}
|
|
@ -1,127 +0,0 @@
|
|||
/*
|
||||
* Copyright 2012 The Android Open Source Project
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include "SkImageFilter.h"
|
||||
|
||||
#include "SkBitmap.h"
|
||||
#include "SkFlattenableBuffers.h"
|
||||
#include "SkRect.h"
|
||||
|
||||
SK_DEFINE_INST_COUNT(SkImageFilter)
|
||||
|
||||
SkImageFilter::SkImageFilter(int inputCount, SkImageFilter** inputs)
|
||||
: fInputCount(inputCount), fInputs(new SkImageFilter*[inputCount]) {
|
||||
for (int i = 0; i < inputCount; ++i) {
|
||||
fInputs[i] = inputs[i];
|
||||
SkSafeRef(fInputs[i]);
|
||||
}
|
||||
}
|
||||
|
||||
SkImageFilter::SkImageFilter(SkImageFilter* input)
|
||||
: fInputCount(1), fInputs(new SkImageFilter*[1]) {
|
||||
fInputs[0] = input;
|
||||
SkSafeRef(fInputs[0]);
|
||||
}
|
||||
|
||||
SkImageFilter::SkImageFilter(SkImageFilter* input1, SkImageFilter* input2)
|
||||
: fInputCount(2), fInputs(new SkImageFilter*[2]) {
|
||||
fInputs[0] = input1;
|
||||
fInputs[1] = input2;
|
||||
SkSafeRef(fInputs[0]);
|
||||
SkSafeRef(fInputs[1]);
|
||||
}
|
||||
|
||||
SkImageFilter::~SkImageFilter() {
|
||||
for (int i = 0; i < fInputCount; i++) {
|
||||
SkSafeUnref(fInputs[i]);
|
||||
}
|
||||
delete[] fInputs;
|
||||
}
|
||||
|
||||
SkImageFilter::SkImageFilter(SkFlattenableReadBuffer& buffer)
|
||||
: fInputCount(buffer.readInt()), fInputs(new SkImageFilter*[fInputCount]) {
|
||||
for (int i = 0; i < fInputCount; i++) {
|
||||
if (buffer.readBool()) {
|
||||
fInputs[i] = static_cast<SkImageFilter*>(buffer.readFlattenable());
|
||||
} else {
|
||||
fInputs[i] = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SkImageFilter::flatten(SkFlattenableWriteBuffer& buffer) const {
|
||||
buffer.writeInt(fInputCount);
|
||||
for (int i = 0; i < fInputCount; i++) {
|
||||
SkImageFilter* input = getInput(i);
|
||||
buffer.writeBool(input != NULL);
|
||||
if (input != NULL) {
|
||||
buffer.writeFlattenable(input);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SkBitmap SkImageFilter::getInputResult(int index, Proxy* proxy,
|
||||
const SkBitmap& src, const SkMatrix& ctm,
|
||||
SkIPoint* loc) {
|
||||
SkASSERT(index < fInputCount);
|
||||
SkImageFilter* input = getInput(index);
|
||||
SkBitmap result;
|
||||
if (input && input->filterImage(proxy, src, ctm, &result, loc)) {
|
||||
return result;
|
||||
} else {
|
||||
return src;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool SkImageFilter::filterImage(Proxy* proxy, const SkBitmap& src,
|
||||
const SkMatrix& ctm,
|
||||
SkBitmap* result, SkIPoint* loc) {
|
||||
SkASSERT(result);
|
||||
SkASSERT(loc);
|
||||
/*
|
||||
* Give the proxy first shot at the filter. If it returns false, ask
|
||||
* the filter to do it.
|
||||
*/
|
||||
return (proxy && proxy->filterImage(this, src, ctm, result, loc)) ||
|
||||
this->onFilterImage(proxy, src, ctm, result, loc);
|
||||
}
|
||||
|
||||
bool SkImageFilter::filterBounds(const SkIRect& src, const SkMatrix& ctm,
|
||||
SkIRect* dst) {
|
||||
SkASSERT(&src);
|
||||
SkASSERT(dst);
|
||||
return this->onFilterBounds(src, ctm, dst);
|
||||
}
|
||||
|
||||
bool SkImageFilter::onFilterImage(Proxy*, const SkBitmap&, const SkMatrix&,
|
||||
SkBitmap*, SkIPoint*) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool SkImageFilter::canFilterImageGPU() const {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool SkImageFilter::filterImageGPU(Proxy* proxy, const SkBitmap& src, SkBitmap* result) {
|
||||
SkASSERT(false); // Should never be called, since canFilterImageGPU() returned false.
|
||||
return false;
|
||||
}
|
||||
|
||||
bool SkImageFilter::onFilterBounds(const SkIRect& src, const SkMatrix& ctm,
|
||||
SkIRect* dst) {
|
||||
*dst = src;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SkImageFilter::asNewEffect(GrEffectRef**, GrTexture*) const {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool SkImageFilter::asColorFilter(SkColorFilter**) const {
|
||||
return false;
|
||||
}
|
|
@ -1,66 +0,0 @@
|
|||
|
||||
/*
|
||||
* Copyright 2011 Google Inc.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
#include "SkMallocPixelRef.h"
|
||||
#include "SkBitmap.h"
|
||||
#include "SkFlattenableBuffers.h"
|
||||
|
||||
SkMallocPixelRef::SkMallocPixelRef(void* storage, size_t size,
|
||||
SkColorTable* ctable, bool ownPixels) {
|
||||
if (NULL == storage) {
|
||||
SkASSERT(ownPixels);
|
||||
storage = sk_malloc_throw(size);
|
||||
}
|
||||
fStorage = storage;
|
||||
fSize = size;
|
||||
fCTable = ctable;
|
||||
SkSafeRef(ctable);
|
||||
fOwnPixels = ownPixels;
|
||||
|
||||
this->setPreLocked(fStorage, fCTable);
|
||||
}
|
||||
|
||||
SkMallocPixelRef::~SkMallocPixelRef() {
|
||||
SkSafeUnref(fCTable);
|
||||
if (fOwnPixels) {
|
||||
sk_free(fStorage);
|
||||
}
|
||||
}
|
||||
|
||||
void* SkMallocPixelRef::onLockPixels(SkColorTable** ct) {
|
||||
*ct = fCTable;
|
||||
return fStorage;
|
||||
}
|
||||
|
||||
void SkMallocPixelRef::onUnlockPixels() {
|
||||
// nothing to do
|
||||
}
|
||||
|
||||
void SkMallocPixelRef::flatten(SkFlattenableWriteBuffer& buffer) const {
|
||||
this->INHERITED::flatten(buffer);
|
||||
|
||||
buffer.writeByteArray(fStorage, fSize);
|
||||
buffer.writeBool(fCTable != NULL);
|
||||
if (fCTable) {
|
||||
buffer.writeFlattenable(fCTable);
|
||||
}
|
||||
}
|
||||
|
||||
SkMallocPixelRef::SkMallocPixelRef(SkFlattenableReadBuffer& buffer)
|
||||
: INHERITED(buffer, NULL) {
|
||||
fSize = buffer.getArrayCount();
|
||||
fStorage = sk_malloc_throw(fSize);
|
||||
buffer.readByteArray(fStorage);
|
||||
if (buffer.readBool()) {
|
||||
fCTable = buffer.readFlattenableT<SkColorTable>();
|
||||
} else {
|
||||
fCTable = NULL;
|
||||
}
|
||||
fOwnPixels = true;
|
||||
|
||||
this->setPreLocked(fStorage, fCTable);
|
||||
}
|
|
@ -1,267 +0,0 @@
|
|||
|
||||
/*
|
||||
* Copyright 2006 The Android Open Source Project
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
|
||||
#include "SkTypes.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#ifdef SK_DEBUG
|
||||
#define SK_TAG_BLOCKS
|
||||
// #define SK_TRACK_ALLOC // enable to see a printf for every alloc/free
|
||||
// #define SK_CHECK_TAGS // enable to double-check debugging link list
|
||||
#endif
|
||||
|
||||
#ifdef SK_TAG_BLOCKS
|
||||
|
||||
#include "SkThread.h"
|
||||
|
||||
// size this (as a multiple of 4) so that the total offset to the internal data
|
||||
// is at least a multiple of 8 (since some clients of our malloc may require
|
||||
// that.
|
||||
static const char kBlockHeaderTag[] = { 's', 'k', 'i', 'a', '1', '2', '3', '4' };
|
||||
static const char kBlockTrailerTag[] = { 'a', 'i', 'k', 's' };
|
||||
#define kByteFill 0xCD
|
||||
#define kDeleteFill 0xEF
|
||||
|
||||
static SkBaseMutex& get_block_mutex() {
|
||||
static SkMutex* gBlockMutex;
|
||||
if (NULL == gBlockMutex) {
|
||||
gBlockMutex = new SkMutex;
|
||||
}
|
||||
return *gBlockMutex;
|
||||
}
|
||||
|
||||
static struct SkBlockHeader* gHeader;
|
||||
|
||||
struct SkBlockHeader {
|
||||
SkBlockHeader* fNext;
|
||||
#ifdef SK_CHECK_TAGS
|
||||
SkBlockHeader** fTop; // set to verify in debugger that block was alloc'd / freed with same gHeader
|
||||
SkBlockHeader* fPrevious; // set to see in debugger previous block when corruption happens
|
||||
#endif
|
||||
size_t fSize;
|
||||
char fHeader[sizeof(kBlockHeaderTag)];
|
||||
// data goes here. The offset to this point must be a multiple of 8
|
||||
char fTrailer[sizeof(kBlockTrailerTag)];
|
||||
|
||||
void* add(size_t realSize)
|
||||
{
|
||||
SkAutoMutexAcquire ac(get_block_mutex());
|
||||
InMutexValidate();
|
||||
fNext = gHeader;
|
||||
#ifdef SK_CHECK_TAGS
|
||||
fTop = &gHeader;
|
||||
fPrevious = NULL;
|
||||
if (fNext != NULL)
|
||||
fNext->fPrevious = this;
|
||||
#endif
|
||||
gHeader = this;
|
||||
fSize = realSize;
|
||||
memcpy(fHeader, kBlockHeaderTag, sizeof(kBlockHeaderTag));
|
||||
void* result = fTrailer;
|
||||
void* trailer = (char*)result + realSize;
|
||||
memcpy(trailer, kBlockTrailerTag, sizeof(kBlockTrailerTag));
|
||||
return result;
|
||||
}
|
||||
|
||||
static void Dump()
|
||||
{
|
||||
SkAutoMutexAcquire ac(get_block_mutex());
|
||||
InMutexValidate();
|
||||
SkBlockHeader* header = gHeader;
|
||||
int count = 0;
|
||||
size_t size = 0;
|
||||
while (header != NULL) {
|
||||
char scratch[256];
|
||||
char* pos = scratch;
|
||||
size_t size = header->fSize;
|
||||
int* data = (int*)(void*)header->fTrailer;
|
||||
pos += sprintf(pos, "%p 0x%08zx (%7zd) ",
|
||||
data, size, size);
|
||||
size >>= 2;
|
||||
size_t ints = size > 4 ? 4 : size;
|
||||
size_t index;
|
||||
for (index = 0; index < ints; index++)
|
||||
pos += sprintf(pos, "0x%08x ", data[index]);
|
||||
pos += sprintf(pos, " (");
|
||||
for (index = 0; index < ints; index++)
|
||||
pos += sprintf(pos, "%g ", data[index] / 65536.0f);
|
||||
if (ints > 0)
|
||||
--pos;
|
||||
pos += sprintf(pos, ") \"");
|
||||
size_t chars = size > 16 ? 16 : size;
|
||||
char* chPtr = (char*) data;
|
||||
for (index = 0; index < chars; index++) {
|
||||
char ch = chPtr[index];
|
||||
pos += sprintf(pos, "%c", ch >= ' ' && ch < 0x7f ? ch : '?');
|
||||
}
|
||||
pos += sprintf(pos, "\"");
|
||||
SkDebugf("%s\n", scratch);
|
||||
count++;
|
||||
size += header->fSize;
|
||||
header = header->fNext;
|
||||
}
|
||||
SkDebugf("--- count %d size 0x%08x (%zd) ---\n", count, size, size);
|
||||
}
|
||||
|
||||
void remove() const
|
||||
{
|
||||
SkAutoMutexAcquire ac(get_block_mutex());
|
||||
SkBlockHeader** findPtr = &gHeader;
|
||||
do {
|
||||
SkBlockHeader* find = *findPtr;
|
||||
SkASSERT(find != NULL);
|
||||
if (find == this) {
|
||||
*findPtr = fNext;
|
||||
break;
|
||||
}
|
||||
findPtr = &find->fNext;
|
||||
} while (true);
|
||||
InMutexValidate();
|
||||
SkASSERT(memcmp(fHeader, kBlockHeaderTag, sizeof(kBlockHeaderTag)) == 0);
|
||||
const char* trailer = fTrailer + fSize;
|
||||
SkASSERT(memcmp(trailer, kBlockTrailerTag, sizeof(kBlockTrailerTag)) == 0);
|
||||
}
|
||||
|
||||
static void Validate()
|
||||
{
|
||||
SkAutoMutexAcquire ac(get_block_mutex());
|
||||
InMutexValidate();
|
||||
}
|
||||
|
||||
private:
|
||||
static void InMutexValidate()
|
||||
{
|
||||
SkBlockHeader* header = gHeader;
|
||||
while (header != NULL) {
|
||||
SkASSERT(memcmp(header->fHeader, kBlockHeaderTag, sizeof(kBlockHeaderTag)) == 0);
|
||||
char* trailer = header->fTrailer + header->fSize;
|
||||
SkASSERT(memcmp(trailer, kBlockTrailerTag, sizeof(kBlockTrailerTag)) == 0);
|
||||
header = header->fNext;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
void ValidateHeap();
|
||||
void ValidateHeap()
|
||||
{
|
||||
SkBlockHeader::Validate();
|
||||
}
|
||||
#else
|
||||
void ValidateHeap() {}
|
||||
#endif
|
||||
|
||||
void sk_throw()
|
||||
{
|
||||
SkDEBUGFAIL("sk_throw");
|
||||
abort();
|
||||
}
|
||||
|
||||
void sk_out_of_memory(void)
|
||||
{
|
||||
SkDEBUGFAIL("sk_out_of_memory");
|
||||
abort();
|
||||
}
|
||||
|
||||
void* sk_malloc_throw(size_t size)
|
||||
{
|
||||
return sk_malloc_flags(size, SK_MALLOC_THROW);
|
||||
}
|
||||
|
||||
void* sk_realloc_throw(void* addr, size_t size)
|
||||
{
|
||||
#ifdef SK_TAG_BLOCKS
|
||||
ValidateHeap();
|
||||
if (addr != NULL) {
|
||||
SkBlockHeader* header = (SkBlockHeader*)
|
||||
((char*)addr - SK_OFFSETOF(SkBlockHeader, fTrailer));
|
||||
header->remove();
|
||||
#ifdef SK_TRACK_ALLOC
|
||||
printf("sk_realloc_throw %p oldSize=%zd\n", addr, header->fSize);
|
||||
#endif
|
||||
addr = header;
|
||||
}
|
||||
size_t realSize = size;
|
||||
if (size)
|
||||
size += sizeof(SkBlockHeader);
|
||||
#endif
|
||||
|
||||
void* p = realloc(addr, size);
|
||||
if (size == 0)
|
||||
{
|
||||
ValidateHeap();
|
||||
return p;
|
||||
}
|
||||
|
||||
if (p == NULL)
|
||||
sk_throw();
|
||||
#ifdef SK_TAG_BLOCKS
|
||||
else
|
||||
{
|
||||
SkBlockHeader* header = (SkBlockHeader*) p;
|
||||
p = header->add(realSize);
|
||||
#ifdef SK_TRACK_ALLOC
|
||||
printf("sk_realloc_throw %p size=%zd\n", p, realSize);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
ValidateHeap();
|
||||
return p;
|
||||
}
|
||||
|
||||
void sk_free(void* p)
|
||||
{
|
||||
if (p)
|
||||
{
|
||||
ValidateHeap();
|
||||
#ifdef SK_TAG_BLOCKS
|
||||
SkBlockHeader* header = (SkBlockHeader*)
|
||||
((char*)p - SK_OFFSETOF(SkBlockHeader, fTrailer));
|
||||
header->remove();
|
||||
#ifdef SK_TRACK_ALLOC
|
||||
printf("sk_free %p size=%zd\n", p, header->fSize);
|
||||
#endif
|
||||
size_t size = header->fSize + sizeof(SkBlockHeader);
|
||||
memset(header, kDeleteFill, size);
|
||||
p = header;
|
||||
#endif
|
||||
ValidateHeap();
|
||||
free(p);
|
||||
ValidateHeap();
|
||||
}
|
||||
}
|
||||
|
||||
void* sk_malloc_flags(size_t size, unsigned flags)
|
||||
{
|
||||
ValidateHeap();
|
||||
#ifdef SK_TAG_BLOCKS
|
||||
size_t realSize = size;
|
||||
size += sizeof(SkBlockHeader);
|
||||
#endif
|
||||
|
||||
void* p = malloc(size);
|
||||
if (p == NULL)
|
||||
{
|
||||
if (flags & SK_MALLOC_THROW)
|
||||
sk_throw();
|
||||
}
|
||||
#ifdef SK_TAG_BLOCKS
|
||||
else
|
||||
{
|
||||
SkBlockHeader* header = (SkBlockHeader*) p;
|
||||
p = header->add(realSize);
|
||||
memset(p, kByteFill, realSize);
|
||||
#ifdef SK_TRACK_ALLOC
|
||||
printf("sk_malloc_flags %p size=%zd\n", p, realSize);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
ValidateHeap();
|
||||
return p;
|
||||
}
|
|
@ -1,256 +0,0 @@
|
|||
|
||||
/*
|
||||
* 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 "SkBitmap.h"
|
||||
#include "SkOrderedReadBuffer.h"
|
||||
#include "SkStream.h"
|
||||
#include "SkTypeface.h"
|
||||
|
||||
SkOrderedReadBuffer::SkOrderedReadBuffer() : INHERITED() {
|
||||
fMemoryPtr = NULL;
|
||||
|
||||
fBitmapStorage = NULL;
|
||||
fTFArray = NULL;
|
||||
fTFCount = 0;
|
||||
|
||||
fFactoryTDArray = NULL;
|
||||
fFactoryArray = NULL;
|
||||
fFactoryCount = 0;
|
||||
fBitmapDecoder = NULL;
|
||||
}
|
||||
|
||||
SkOrderedReadBuffer::SkOrderedReadBuffer(const void* data, size_t size) : INHERITED() {
|
||||
fReader.setMemory(data, size);
|
||||
fMemoryPtr = NULL;
|
||||
|
||||
fBitmapStorage = NULL;
|
||||
fTFArray = NULL;
|
||||
fTFCount = 0;
|
||||
|
||||
fFactoryTDArray = NULL;
|
||||
fFactoryArray = NULL;
|
||||
fFactoryCount = 0;
|
||||
fBitmapDecoder = NULL;
|
||||
}
|
||||
|
||||
SkOrderedReadBuffer::SkOrderedReadBuffer(SkStream* stream) {
|
||||
const size_t length = stream->getLength();
|
||||
fMemoryPtr = sk_malloc_throw(length);
|
||||
stream->read(fMemoryPtr, length);
|
||||
fReader.setMemory(fMemoryPtr, length);
|
||||
|
||||
fBitmapStorage = NULL;
|
||||
fTFArray = NULL;
|
||||
fTFCount = 0;
|
||||
|
||||
fFactoryTDArray = NULL;
|
||||
fFactoryArray = NULL;
|
||||
fFactoryCount = 0;
|
||||
fBitmapDecoder = NULL;
|
||||
}
|
||||
|
||||
SkOrderedReadBuffer::~SkOrderedReadBuffer() {
|
||||
sk_free(fMemoryPtr);
|
||||
SkSafeUnref(fBitmapStorage);
|
||||
}
|
||||
|
||||
bool SkOrderedReadBuffer::readBool() {
|
||||
return fReader.readBool();
|
||||
}
|
||||
|
||||
SkColor SkOrderedReadBuffer::readColor() {
|
||||
return fReader.readInt();
|
||||
}
|
||||
|
||||
SkFixed SkOrderedReadBuffer::readFixed() {
|
||||
return fReader.readS32();
|
||||
}
|
||||
|
||||
int32_t SkOrderedReadBuffer::readInt() {
|
||||
return fReader.readInt();
|
||||
}
|
||||
|
||||
SkScalar SkOrderedReadBuffer::readScalar() {
|
||||
return fReader.readScalar();
|
||||
}
|
||||
|
||||
uint32_t SkOrderedReadBuffer::readUInt() {
|
||||
return fReader.readU32();
|
||||
}
|
||||
|
||||
int32_t SkOrderedReadBuffer::read32() {
|
||||
return fReader.readInt();
|
||||
}
|
||||
|
||||
char* SkOrderedReadBuffer::readString() {
|
||||
const char* string = fReader.readString();
|
||||
const size_t length = strlen(string);
|
||||
char* value = (char*)sk_malloc_throw(length + 1);
|
||||
strcpy(value, string);
|
||||
return value;
|
||||
}
|
||||
|
||||
void* SkOrderedReadBuffer::readEncodedString(size_t* length, SkPaint::TextEncoding encoding) {
|
||||
SkDEBUGCODE(int32_t encodingType = ) fReader.readInt();
|
||||
SkASSERT(encodingType == encoding);
|
||||
*length = fReader.readInt();
|
||||
void* data = sk_malloc_throw(*length);
|
||||
memcpy(data, fReader.skip(SkAlign4(*length)), *length);
|
||||
return data;
|
||||
}
|
||||
|
||||
void SkOrderedReadBuffer::readPoint(SkPoint* point) {
|
||||
point->fX = fReader.readScalar();
|
||||
point->fY = fReader.readScalar();
|
||||
}
|
||||
|
||||
void SkOrderedReadBuffer::readMatrix(SkMatrix* matrix) {
|
||||
fReader.readMatrix(matrix);
|
||||
}
|
||||
|
||||
void SkOrderedReadBuffer::readIRect(SkIRect* rect) {
|
||||
memcpy(rect, fReader.skip(sizeof(SkIRect)), sizeof(SkIRect));
|
||||
}
|
||||
|
||||
void SkOrderedReadBuffer::readRect(SkRect* rect) {
|
||||
memcpy(rect, fReader.skip(sizeof(SkRect)), sizeof(SkRect));
|
||||
}
|
||||
|
||||
void SkOrderedReadBuffer::readRegion(SkRegion* region) {
|
||||
fReader.readRegion(region);
|
||||
}
|
||||
|
||||
void SkOrderedReadBuffer::readPath(SkPath* path) {
|
||||
fReader.readPath(path);
|
||||
}
|
||||
|
||||
uint32_t SkOrderedReadBuffer::readByteArray(void* value) {
|
||||
const uint32_t length = fReader.readU32();
|
||||
memcpy(value, fReader.skip(SkAlign4(length)), length);
|
||||
return length;
|
||||
}
|
||||
|
||||
uint32_t SkOrderedReadBuffer::readColorArray(SkColor* colors) {
|
||||
const uint32_t count = fReader.readU32();
|
||||
const uint32_t byteLength = count * sizeof(SkColor);
|
||||
memcpy(colors, fReader.skip(SkAlign4(byteLength)), byteLength);
|
||||
return count;
|
||||
}
|
||||
|
||||
uint32_t SkOrderedReadBuffer::readIntArray(int32_t* values) {
|
||||
const uint32_t count = fReader.readU32();
|
||||
const uint32_t byteLength = count * sizeof(int32_t);
|
||||
memcpy(values, fReader.skip(SkAlign4(byteLength)), byteLength);
|
||||
return count;
|
||||
}
|
||||
|
||||
uint32_t SkOrderedReadBuffer::readPointArray(SkPoint* points) {
|
||||
const uint32_t count = fReader.readU32();
|
||||
const uint32_t byteLength = count * sizeof(SkPoint);
|
||||
memcpy(points, fReader.skip(SkAlign4(byteLength)), byteLength);
|
||||
return count;
|
||||
}
|
||||
|
||||
uint32_t SkOrderedReadBuffer::readScalarArray(SkScalar* values) {
|
||||
const uint32_t count = fReader.readU32();
|
||||
const uint32_t byteLength = count * sizeof(SkScalar);
|
||||
memcpy(values, fReader.skip(SkAlign4(byteLength)), byteLength);
|
||||
return count;
|
||||
}
|
||||
|
||||
uint32_t SkOrderedReadBuffer::getArrayCount() {
|
||||
return *(uint32_t*)fReader.peek();
|
||||
}
|
||||
|
||||
void SkOrderedReadBuffer::readBitmap(SkBitmap* bitmap) {
|
||||
const size_t length = this->readUInt();
|
||||
if (length > 0) {
|
||||
// Bitmap was encoded.
|
||||
const void* data = this->skip(length);
|
||||
const int width = this->readInt();
|
||||
const int height = this->readInt();
|
||||
if (fBitmapDecoder != NULL && fBitmapDecoder(data, length, bitmap)) {
|
||||
SkASSERT(bitmap->width() == width && bitmap->height() == height);
|
||||
} else {
|
||||
// This bitmap was encoded when written, but we are unable to decode, possibly due to
|
||||
// not having a decoder. Use a placeholder bitmap.
|
||||
SkDebugf("Could not decode bitmap. Resulting bitmap will be red.\n");
|
||||
bitmap->setConfig(SkBitmap::kARGB_8888_Config, width, height);
|
||||
bitmap->allocPixels();
|
||||
bitmap->eraseColor(SK_ColorRED);
|
||||
}
|
||||
} else {
|
||||
if (fBitmapStorage) {
|
||||
const uint32_t index = fReader.readU32();
|
||||
fReader.readU32(); // bitmap generation ID (see SkOrderedWriteBuffer::writeBitmap)
|
||||
*bitmap = *fBitmapStorage->getBitmap(index);
|
||||
fBitmapStorage->releaseRef(index);
|
||||
} else {
|
||||
bitmap->unflatten(*this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SkTypeface* SkOrderedReadBuffer::readTypeface() {
|
||||
|
||||
uint32_t index = fReader.readU32();
|
||||
if (0 == index || index > (unsigned)fTFCount) {
|
||||
if (index) {
|
||||
SkDebugf("====== typeface index %d\n", index);
|
||||
}
|
||||
return NULL;
|
||||
} else {
|
||||
SkASSERT(fTFArray);
|
||||
return fTFArray[index - 1];
|
||||
}
|
||||
}
|
||||
|
||||
SkFlattenable* SkOrderedReadBuffer::readFlattenable() {
|
||||
SkFlattenable::Factory factory = NULL;
|
||||
|
||||
if (fFactoryCount > 0) {
|
||||
int32_t index = fReader.readU32();
|
||||
if (0 == index) {
|
||||
return NULL; // writer failed to give us the flattenable
|
||||
}
|
||||
index -= 1; // we stored the index-base-1
|
||||
SkASSERT(index < fFactoryCount);
|
||||
factory = fFactoryArray[index];
|
||||
} else if (fFactoryTDArray) {
|
||||
int32_t index = fReader.readU32();
|
||||
if (0 == index) {
|
||||
return NULL; // writer failed to give us the flattenable
|
||||
}
|
||||
index -= 1; // we stored the index-base-1
|
||||
factory = (*fFactoryTDArray)[index];
|
||||
} else {
|
||||
factory = (SkFlattenable::Factory)readFunctionPtr();
|
||||
if (NULL == factory) {
|
||||
return NULL; // writer failed to give us the flattenable
|
||||
}
|
||||
}
|
||||
|
||||
// if we get here, factory may still be null, but if that is the case, the
|
||||
// failure was ours, not the writer.
|
||||
SkFlattenable* obj = NULL;
|
||||
uint32_t sizeRecorded = fReader.readU32();
|
||||
if (factory) {
|
||||
uint32_t offset = fReader.offset();
|
||||
obj = (*factory)(*this);
|
||||
// check that we read the amount we expected
|
||||
uint32_t sizeRead = fReader.offset() - offset;
|
||||
if (sizeRecorded != sizeRead) {
|
||||
// we could try to fix up the offset...
|
||||
sk_throw();
|
||||
}
|
||||
} else {
|
||||
// we must skip the remaining data
|
||||
fReader.skip(sizeRecorded);
|
||||
}
|
||||
return obj;
|
||||
}
|
|
@ -1,128 +0,0 @@
|
|||
|
||||
/*
|
||||
* Copyright 2011 Google Inc.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#ifndef SkOrderedReadBuffer_DEFINED
|
||||
#define SkOrderedReadBuffer_DEFINED
|
||||
|
||||
#include "SkRefCnt.h"
|
||||
#include "SkBitmapHeap.h"
|
||||
#include "SkFlattenableBuffers.h"
|
||||
#include "SkPath.h"
|
||||
#include "SkPicture.h"
|
||||
#include "SkReader32.h"
|
||||
|
||||
class SkBitmap;
|
||||
|
||||
class SkOrderedReadBuffer : public SkFlattenableReadBuffer {
|
||||
public:
|
||||
SkOrderedReadBuffer();
|
||||
SkOrderedReadBuffer(const void* data, size_t size);
|
||||
SkOrderedReadBuffer(SkStream* stream);
|
||||
virtual ~SkOrderedReadBuffer();
|
||||
|
||||
virtual SkOrderedReadBuffer* getOrderedBinaryBuffer() SK_OVERRIDE { return this; }
|
||||
|
||||
SkReader32* getReader32() { return &fReader; }
|
||||
|
||||
uint32_t size() { return fReader.size(); }
|
||||
uint32_t offset() { return fReader.offset(); }
|
||||
bool eof() { return fReader.eof(); }
|
||||
const void* skip(size_t size) { return fReader.skip(size); }
|
||||
|
||||
// primitives
|
||||
virtual bool readBool() SK_OVERRIDE;
|
||||
virtual SkColor readColor() SK_OVERRIDE;
|
||||
virtual SkFixed readFixed() SK_OVERRIDE;
|
||||
virtual int32_t readInt() SK_OVERRIDE;
|
||||
virtual SkScalar readScalar() SK_OVERRIDE;
|
||||
virtual uint32_t readUInt() SK_OVERRIDE;
|
||||
virtual int32_t read32() SK_OVERRIDE;
|
||||
|
||||
// strings -- the caller is responsible for freeing the string contents
|
||||
virtual char* readString() SK_OVERRIDE;
|
||||
virtual void* readEncodedString(size_t* length, SkPaint::TextEncoding encoding) SK_OVERRIDE;
|
||||
|
||||
// common data structures
|
||||
virtual SkFlattenable* readFlattenable() SK_OVERRIDE;
|
||||
virtual void readPoint(SkPoint* point) SK_OVERRIDE;
|
||||
virtual void readMatrix(SkMatrix* matrix) SK_OVERRIDE;
|
||||
virtual void readIRect(SkIRect* rect) SK_OVERRIDE;
|
||||
virtual void readRect(SkRect* rect) SK_OVERRIDE;
|
||||
virtual void readRegion(SkRegion* region) SK_OVERRIDE;
|
||||
virtual void readPath(SkPath* path) SK_OVERRIDE;
|
||||
|
||||
// binary data and arrays
|
||||
virtual uint32_t readByteArray(void* value) SK_OVERRIDE;
|
||||
virtual uint32_t readColorArray(SkColor* colors) SK_OVERRIDE;
|
||||
virtual uint32_t readIntArray(int32_t* values) SK_OVERRIDE;
|
||||
virtual uint32_t readPointArray(SkPoint* points) SK_OVERRIDE;
|
||||
virtual uint32_t readScalarArray(SkScalar* values) SK_OVERRIDE;
|
||||
|
||||
// helpers to get info about arrays and binary data
|
||||
virtual uint32_t getArrayCount() SK_OVERRIDE;
|
||||
|
||||
virtual void readBitmap(SkBitmap* bitmap) SK_OVERRIDE;
|
||||
virtual SkTypeface* readTypeface() SK_OVERRIDE;
|
||||
|
||||
void setBitmapStorage(SkBitmapHeapReader* bitmapStorage) {
|
||||
SkRefCnt_SafeAssign(fBitmapStorage, bitmapStorage);
|
||||
}
|
||||
|
||||
void setTypefaceArray(SkTypeface* array[], int count) {
|
||||
fTFArray = array;
|
||||
fTFCount = count;
|
||||
}
|
||||
|
||||
/**
|
||||
* Call this with a pre-loaded array of Factories, in the same order as
|
||||
* were created/written by the writer. SkPicture uses this.
|
||||
*/
|
||||
void setFactoryPlayback(SkFlattenable::Factory array[], int count) {
|
||||
fFactoryTDArray = NULL;
|
||||
fFactoryArray = array;
|
||||
fFactoryCount = count;
|
||||
}
|
||||
|
||||
/**
|
||||
* Call this with an initially empty array, so the reader can cache each
|
||||
* factory it sees by name. Used by the pipe code in conjunction with
|
||||
* SkOrderedWriteBuffer::setNamedFactoryRecorder.
|
||||
*/
|
||||
void setFactoryArray(SkTDArray<SkFlattenable::Factory>* array) {
|
||||
fFactoryTDArray = array;
|
||||
fFactoryArray = NULL;
|
||||
fFactoryCount = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Provide a function to decode an SkBitmap from encoded data. Only used if the writer
|
||||
* encoded the SkBitmap. If the proper decoder cannot be used, a red bitmap with the
|
||||
* appropriate size will be used.
|
||||
*/
|
||||
void setBitmapDecoder(SkPicture::InstallPixelRefProc bitmapDecoder) {
|
||||
fBitmapDecoder = bitmapDecoder;
|
||||
}
|
||||
|
||||
private:
|
||||
SkReader32 fReader;
|
||||
void* fMemoryPtr;
|
||||
|
||||
SkBitmapHeapReader* fBitmapStorage;
|
||||
SkTypeface** fTFArray;
|
||||
int fTFCount;
|
||||
|
||||
SkTDArray<SkFlattenable::Factory>* fFactoryTDArray;
|
||||
SkFlattenable::Factory* fFactoryArray;
|
||||
int fFactoryCount;
|
||||
|
||||
SkPicture::InstallPixelRefProc fBitmapDecoder;
|
||||
|
||||
typedef SkFlattenableReadBuffer INHERITED;
|
||||
};
|
||||
|
||||
#endif // SkOrderedReadBuffer_DEFINED
|
|
@ -1,606 +0,0 @@
|
|||
|
||||
/*
|
||||
* 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 SkPathRef_DEFINED
|
||||
#define SkPathRef_DEFINED
|
||||
|
||||
#include "SkRefCnt.h"
|
||||
#include <stddef.h> // ptrdiff_t
|
||||
|
||||
// When we're ready to break the picture format. Changes:
|
||||
// * Write genID.
|
||||
// * SkPathRef read/write counts (which will change the field order)
|
||||
// * SkPathRef reads/writes verbs backwards.
|
||||
#define NEW_PICTURE_FORMAT 0
|
||||
|
||||
/**
|
||||
* Holds the path verbs and points. It is versioned by a generation ID. None of its public methods
|
||||
* modify the contents. To modify or append to the verbs/points wrap the SkPathRef in an
|
||||
* SkPathRef::Editor object. Installing the editor resets the generation ID. It also performs
|
||||
* copy-on-write if the SkPathRef is shared by multipls SkPaths. The caller passes the Editor's
|
||||
* constructor a SkAutoTUnref, which may be updated to point to a new SkPathRef after the editor's
|
||||
* constructor returns.
|
||||
*
|
||||
* The points and verbs are stored in a single allocation. The points are at the begining of the
|
||||
* allocation while the verbs are stored at end of the allocation, in reverse order. Thus the points
|
||||
* and verbs both grow into the middle of the allocation until the meet. To access verb i in the
|
||||
* verb array use ref.verbs()[~i] (because verbs() returns a pointer just beyond the first
|
||||
* logical verb or the last verb in memory).
|
||||
*/
|
||||
|
||||
class SkPathRef;
|
||||
|
||||
// This path ref should never be deleted once it is created. It should not be global but was made
|
||||
// so for checks when SK_DEBUG_PATH_REF is enabled. It we be re-hidden when the debugging code is
|
||||
// reverted.
|
||||
SkPathRef* gEmptyPathRef;
|
||||
|
||||
// Temporary hackery to try to nail down http://code.google.com/p/chromium/issues/detail?id=148637
|
||||
#if SK_DEBUG_PATH_REF
|
||||
#define PR_CONTAINER SkPath::PathRefDebugRef
|
||||
#define SkDEBUGCODE_X(code) code
|
||||
#define SkASSERT_X(cond) SK_DEBUGBREAK(cond)
|
||||
// We put the mutex in a factory function to protect against static-initializion order
|
||||
// fiasco when SkPaths are created before main().
|
||||
static SkMutex* owners_mutex() {
|
||||
static SkMutex* gOwnersMutex;
|
||||
if (!gOwnersMutex) {
|
||||
gOwnersMutex = new SkMutex(); // leak!
|
||||
}
|
||||
return gOwnersMutex;
|
||||
}
|
||||
// We have a static initializer that calls owners_mutex before main() so that
|
||||
// hopefully that we only wind up with one mutex (assuming no threads created
|
||||
// before static initialization is finished.)
|
||||
static const SkMutex* gOwnersMutexForce = owners_mutex();
|
||||
#else
|
||||
#define PR_CONTAINER SkAutoTUnref<SkPathRef>
|
||||
#define SkDEBUGCODE_X(code) SkDEBUGCODE(code)
|
||||
#define SkASSERT_X(cond) SkASSERT(cond)
|
||||
#endif
|
||||
|
||||
class SkPathRef : public ::SkRefCnt {
|
||||
public:
|
||||
SK_DECLARE_INST_COUNT(SkPathRef);
|
||||
|
||||
class Editor {
|
||||
public:
|
||||
Editor(PR_CONTAINER* pathRef,
|
||||
int incReserveVerbs = 0,
|
||||
int incReservePoints = 0) {
|
||||
if (pathRef->get()->getRefCnt() > 1) {
|
||||
SkPathRef* copy = SkNEW(SkPathRef);
|
||||
copy->copy(*pathRef->get(), incReserveVerbs, incReservePoints);
|
||||
pathRef->reset(copy);
|
||||
} else {
|
||||
(*pathRef)->incReserve(incReserveVerbs, incReservePoints);
|
||||
}
|
||||
fPathRef = pathRef->get();
|
||||
fPathRef->fGenerationID = 0;
|
||||
SkDEBUGCODE_X(sk_atomic_inc(&fPathRef->fEditorsAttached);)
|
||||
}
|
||||
|
||||
~Editor() { SkDEBUGCODE_X(sk_atomic_dec(&fPathRef->fEditorsAttached);) }
|
||||
|
||||
/**
|
||||
* Returns the array of points.
|
||||
*/
|
||||
SkPoint* points() { return fPathRef->fPoints; }
|
||||
|
||||
/**
|
||||
* Gets the ith point. Shortcut for this->points() + i
|
||||
*/
|
||||
SkPoint* atPoint(int i) {
|
||||
SkASSERT((unsigned) i < (unsigned) fPathRef->fPointCnt);
|
||||
return this->points() + i;
|
||||
};
|
||||
|
||||
/**
|
||||
* Adds the verb and allocates space for the number of points indicated by the verb. The
|
||||
* return value is a pointer to where the points for the verb should be written.
|
||||
*/
|
||||
SkPoint* growForVerb(SkPath::Verb verb) {
|
||||
fPathRef->validate();
|
||||
return fPathRef->growForVerb(verb);
|
||||
}
|
||||
|
||||
/**
|
||||
* Allocates space for additional verbs and points and returns pointers to the new verbs and
|
||||
* points. verbs will point one beyond the first new verb (index it using [~<i>]). pts points
|
||||
* at the first new point (indexed normally [<i>]).
|
||||
*/
|
||||
void grow(int newVerbs, int newPts, uint8_t** verbs, SkPoint** pts) {
|
||||
SkASSERT(NULL != verbs);
|
||||
SkASSERT(NULL != pts);
|
||||
fPathRef->validate();
|
||||
int oldVerbCnt = fPathRef->fVerbCnt;
|
||||
int oldPointCnt = fPathRef->fPointCnt;
|
||||
SkASSERT(verbs && pts);
|
||||
fPathRef->grow(newVerbs, newPts);
|
||||
*verbs = fPathRef->fVerbs - oldVerbCnt;
|
||||
*pts = fPathRef->fPoints + oldPointCnt;
|
||||
fPathRef->validate();
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the path ref to a new verb and point count. The new verbs and points are
|
||||
* uninitialized.
|
||||
*/
|
||||
void resetToSize(int newVerbCnt, int newPointCnt) {
|
||||
fPathRef->resetToSize(newVerbCnt, newPointCnt);
|
||||
}
|
||||
/**
|
||||
* Gets the path ref that is wrapped in the Editor.
|
||||
*/
|
||||
SkPathRef* pathRef() { return fPathRef; }
|
||||
|
||||
private:
|
||||
SkPathRef* fPathRef;
|
||||
};
|
||||
|
||||
public:
|
||||
#if SK_DEBUG_PATH_REF
|
||||
void addOwner(SkPath* owner) {
|
||||
SkAutoMutexAcquire ac(owners_mutex());
|
||||
for (int i = 0; i < fOwners.count(); ++i) {
|
||||
SkASSERT_X(fOwners[i] != owner);
|
||||
}
|
||||
*fOwners.append() = owner;
|
||||
SkASSERT_X((this->getRefCnt() == fOwners.count()) ||
|
||||
(this == gEmptyPathRef && this->getRefCnt() == fOwners.count() + 1));
|
||||
}
|
||||
|
||||
void removeOwner(SkPath* owner) {
|
||||
SkAutoMutexAcquire ac(owners_mutex());
|
||||
SkASSERT_X((this->getRefCnt() == fOwners.count()) ||
|
||||
(this == gEmptyPathRef && this->getRefCnt() == fOwners.count() + 1));
|
||||
bool found = false;
|
||||
for (int i = 0; !found && i < fOwners.count(); ++i) {
|
||||
found = (owner == fOwners[i]);
|
||||
if (found) {
|
||||
fOwners.remove(i);
|
||||
}
|
||||
}
|
||||
SkASSERT_X(found);
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Gets a path ref with no verbs or points.
|
||||
*/
|
||||
static SkPathRef* CreateEmpty() {
|
||||
if (!gEmptyPathRef) {
|
||||
gEmptyPathRef = SkNEW(SkPathRef); // leak!
|
||||
}
|
||||
return SkRef(gEmptyPathRef);
|
||||
}
|
||||
|
||||
/**
|
||||
* Transforms a path ref by a matrix, allocating a new one only if necessary.
|
||||
*/
|
||||
static void CreateTransformedCopy(PR_CONTAINER* dst,
|
||||
const SkPathRef& src,
|
||||
const SkMatrix& matrix) {
|
||||
src.validate();
|
||||
if (matrix.isIdentity()) {
|
||||
if (dst->get() != &src) {
|
||||
src.ref();
|
||||
dst->reset(const_cast<SkPathRef*>(&src));
|
||||
(*dst)->validate();
|
||||
}
|
||||
return;
|
||||
}
|
||||
int32_t rcnt = dst->get()->getRefCnt();
|
||||
if (&src == dst->get() && 1 == rcnt) {
|
||||
matrix.mapPoints((*dst)->fPoints, (*dst)->fPointCnt);
|
||||
return;
|
||||
} else if (rcnt > 1) {
|
||||
dst->reset(SkNEW(SkPathRef));
|
||||
}
|
||||
(*dst)->resetToSize(src.fVerbCnt, src.fPointCnt);
|
||||
memcpy((*dst)->verbsMemWritable(), src.verbsMemBegin(), src.fVerbCnt * sizeof(uint8_t));
|
||||
matrix.mapPoints((*dst)->fPoints, src.points(), src.fPointCnt);
|
||||
(*dst)->validate();
|
||||
}
|
||||
|
||||
#if NEW_PICTURE_FORMAT
|
||||
static SkPathRef* CreateFromBuffer(SkRBuffer* buffer) {
|
||||
SkPathRef* ref = SkNEW(SkPathRef);
|
||||
ref->fGenerationID = buffer->readU32();
|
||||
int32_t verbCount = buffer->readS32();
|
||||
int32_t pointCount = buffer->readS32();
|
||||
ref->resetToSize(verbCount, pointCount);
|
||||
|
||||
SkASSERT(verbCount == ref->countVerbs());
|
||||
SkASSERT(pointCount == ref->countPoints());
|
||||
buffer->read(ref->verbsMemWritable(), verbCount * sizeof(uint8_t));
|
||||
buffer->read(ref->fPoints, pointCount * sizeof(SkPoint));
|
||||
return ref;
|
||||
}
|
||||
#else
|
||||
static SkPathRef* CreateFromBuffer(int verbCount, int pointCount, SkRBuffer* buffer) {
|
||||
SkPathRef* ref = SkNEW(SkPathRef);
|
||||
|
||||
ref->resetToSize(verbCount, pointCount);
|
||||
SkASSERT(verbCount == ref->countVerbs());
|
||||
SkASSERT(pointCount == ref->countPoints());
|
||||
buffer->read(ref->fPoints, pointCount * sizeof(SkPoint));
|
||||
for (int i = 0; i < verbCount; ++i) {
|
||||
ref->fVerbs[~i] = buffer->readU8();
|
||||
}
|
||||
return ref;
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Rollsback a path ref to zero verbs and points with the assumption that the path ref will be
|
||||
* repopulated with approximately the same number of verbs and points. A new path ref is created
|
||||
* only if necessary.
|
||||
*/
|
||||
static void Rewind(PR_CONTAINER* pathRef) {
|
||||
if (1 == (*pathRef)->getRefCnt()) {
|
||||
(*pathRef)->validate();
|
||||
(*pathRef)->fVerbCnt = 0;
|
||||
(*pathRef)->fPointCnt = 0;
|
||||
(*pathRef)->fFreeSpace = (*pathRef)->currSize();
|
||||
(*pathRef)->fGenerationID = 0;
|
||||
(*pathRef)->validate();
|
||||
} else {
|
||||
int oldVCnt = (*pathRef)->countVerbs();
|
||||
int oldPCnt = (*pathRef)->countPoints();
|
||||
pathRef->reset(SkNEW(SkPathRef));
|
||||
(*pathRef)->resetToSize(0, 0, oldVCnt, oldPCnt);
|
||||
}
|
||||
}
|
||||
|
||||
virtual ~SkPathRef() {
|
||||
SkASSERT_X(this != gEmptyPathRef);
|
||||
#if SK_DEBUG_PATH_REF
|
||||
SkASSERT_X(!fOwners.count());
|
||||
#endif
|
||||
|
||||
this->validate();
|
||||
sk_free(fPoints);
|
||||
|
||||
SkDEBUGCODE_X(fPoints = NULL;)
|
||||
SkDEBUGCODE_X(fVerbs = NULL;)
|
||||
SkDEBUGCODE_X(fVerbCnt = 0x9999999;)
|
||||
SkDEBUGCODE_X(fPointCnt = 0xAAAAAAA;)
|
||||
SkDEBUGCODE_X(fPointCnt = 0xBBBBBBB;)
|
||||
SkDEBUGCODE_X(fGenerationID = 0xEEEEEEEE;)
|
||||
SkDEBUGCODE_X(fEditorsAttached = 0x7777777;)
|
||||
}
|
||||
|
||||
int countPoints() const { this->validate(); return fPointCnt; }
|
||||
int countVerbs() const { this->validate(); return fVerbCnt; }
|
||||
|
||||
/**
|
||||
* Returns a pointer one beyond the first logical verb (last verb in memory order).
|
||||
*/
|
||||
const uint8_t* verbs() const { this->validate(); return fVerbs; }
|
||||
|
||||
/**
|
||||
* Returns a const pointer to the first verb in memory (which is the last logical verb).
|
||||
*/
|
||||
const uint8_t* verbsMemBegin() const { return this->verbs() - fVerbCnt; }
|
||||
|
||||
/**
|
||||
* Returns a const pointer to the first point.
|
||||
*/
|
||||
const SkPoint* points() const { this->validate(); return fPoints; }
|
||||
|
||||
/**
|
||||
* Shortcut for this->points() + this->countPoints()
|
||||
*/
|
||||
const SkPoint* pointsEnd() const { return this->points() + this->countPoints(); }
|
||||
|
||||
/**
|
||||
* Convenience methods for getting to a verb or point by index.
|
||||
*/
|
||||
uint8_t atVerb(int index) {
|
||||
SkASSERT((unsigned) index < (unsigned) fVerbCnt);
|
||||
return this->verbs()[~index];
|
||||
}
|
||||
const SkPoint& atPoint(int index) const {
|
||||
SkASSERT((unsigned) index < (unsigned) fPointCnt);
|
||||
return this->points()[index];
|
||||
}
|
||||
|
||||
bool operator== (const SkPathRef& ref) const {
|
||||
this->validate();
|
||||
ref.validate();
|
||||
bool genIDMatch = fGenerationID && fGenerationID == ref.fGenerationID;
|
||||
#ifdef SK_RELEASE
|
||||
if (genIDMatch) {
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
if (fPointCnt != ref.fPointCnt ||
|
||||
fVerbCnt != ref.fVerbCnt) {
|
||||
SkASSERT(!genIDMatch);
|
||||
return false;
|
||||
}
|
||||
if (0 != memcmp(this->verbsMemBegin(),
|
||||
ref.verbsMemBegin(),
|
||||
ref.fVerbCnt * sizeof(uint8_t))) {
|
||||
SkASSERT(!genIDMatch);
|
||||
return false;
|
||||
}
|
||||
if (0 != memcmp(this->points(),
|
||||
ref.points(),
|
||||
ref.fPointCnt * sizeof(SkPoint))) {
|
||||
SkASSERT(!genIDMatch);
|
||||
return false;
|
||||
}
|
||||
// We've done the work to determine that these are equal. If either has a zero genID, copy
|
||||
// the other's. If both are 0 then genID() will compute the next ID.
|
||||
if (0 == fGenerationID) {
|
||||
fGenerationID = ref.genID();
|
||||
} else if (0 == ref.fGenerationID) {
|
||||
ref.fGenerationID = this->genID();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes the path points and verbs to a buffer.
|
||||
*/
|
||||
#if NEW_PICTURE_FORMAT
|
||||
void writeToBuffer(SkWBuffer* buffer) {
|
||||
this->validate();
|
||||
SkDEBUGCODE_X(size_t beforePos = buffer->pos();)
|
||||
|
||||
// TODO: write gen ID here. Problem: We don't know if we're cross process or not from
|
||||
// SkWBuffer. Until this is fixed we write 0.
|
||||
buffer->write32(0);
|
||||
buffer->write32(this->fVerbCnt);
|
||||
buffer->write32(this->fPointCnt);
|
||||
buffer->write(this->verbsMemBegin(), fVerbCnt * sizeof(uint8_t));
|
||||
buffer->write(fPoints, fPointCnt * sizeof(SkPoint));
|
||||
|
||||
SkASSERT(buffer->pos() - beforePos == (size_t) this->writeSize());
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the number of bytes that would be written in writeBuffer()
|
||||
*/
|
||||
uint32_t writeSize() {
|
||||
return 3 * sizeof(uint32_t) + fVerbCnt * sizeof(uint8_t) + fPointCnt * sizeof(SkPoint);
|
||||
}
|
||||
#else
|
||||
void writeToBuffer(SkWBuffer* buffer) {
|
||||
this->validate();
|
||||
buffer->write(fPoints, fPointCnt * sizeof(SkPoint));
|
||||
for (int i = 0; i < fVerbCnt; ++i) {
|
||||
buffer->write8(fVerbs[~i]);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
private:
|
||||
SkPathRef() {
|
||||
fPointCnt = 0;
|
||||
fVerbCnt = 0;
|
||||
fVerbs = NULL;
|
||||
fPoints = NULL;
|
||||
fFreeSpace = 0;
|
||||
fGenerationID = kEmptyGenID;
|
||||
SkDEBUGCODE_X(fEditorsAttached = 0;)
|
||||
this->validate();
|
||||
}
|
||||
|
||||
void copy(const SkPathRef& ref, int additionalReserveVerbs, int additionalReservePoints) {
|
||||
this->validate();
|
||||
this->resetToSize(ref.fVerbCnt, ref.fPointCnt,
|
||||
additionalReserveVerbs, additionalReservePoints);
|
||||
memcpy(this->verbsMemWritable(), ref.verbsMemBegin(), ref.fVerbCnt * sizeof(uint8_t));
|
||||
memcpy(this->fPoints, ref.fPoints, ref.fPointCnt * sizeof(SkPoint));
|
||||
// We could call genID() here to force a real ID (instead of 0). However, if we're making
|
||||
// a copy then presumably we intend to make a modification immediately afterwards.
|
||||
fGenerationID = ref.fGenerationID;
|
||||
this->validate();
|
||||
}
|
||||
|
||||
/** Makes additional room but does not change the counts or change the genID */
|
||||
void incReserve(int additionalVerbs, int additionalPoints) {
|
||||
this->validate();
|
||||
size_t space = additionalVerbs * sizeof(uint8_t) + additionalPoints * sizeof (SkPoint);
|
||||
this->makeSpace(space);
|
||||
this->validate();
|
||||
}
|
||||
|
||||
/** Resets the path ref with verbCount verbs and pointCount points, all unitialized. Also
|
||||
* allocates space for reserveVerb additional verbs and reservePoints additional points.*/
|
||||
void resetToSize(int verbCount, int pointCount, int reserveVerbs = 0, int reservePoints = 0) {
|
||||
this->validate();
|
||||
fGenerationID = 0;
|
||||
|
||||
size_t newSize = sizeof(uint8_t) * verbCount + sizeof(SkPoint) * pointCount;
|
||||
size_t newReserve = sizeof(uint8_t) * reserveVerbs + sizeof(SkPoint) * reservePoints;
|
||||
size_t minSize = newSize + newReserve;
|
||||
|
||||
ptrdiff_t sizeDelta = this->currSize() - minSize;
|
||||
|
||||
if (sizeDelta < 0 || static_cast<size_t>(sizeDelta) >= 3 * minSize) {
|
||||
sk_free(fPoints);
|
||||
fPoints = NULL;
|
||||
fVerbs = NULL;
|
||||
fFreeSpace = 0;
|
||||
fVerbCnt = 0;
|
||||
fPointCnt = 0;
|
||||
this->makeSpace(minSize);
|
||||
fVerbCnt = verbCount;
|
||||
fPointCnt = pointCount;
|
||||
fFreeSpace -= newSize;
|
||||
} else {
|
||||
fPointCnt = pointCount;
|
||||
fVerbCnt = verbCount;
|
||||
fFreeSpace = this->currSize() - minSize;
|
||||
}
|
||||
this->validate();
|
||||
}
|
||||
|
||||
/**
|
||||
* Increases the verb count by newVerbs and the point count be newPoints. New verbs and points
|
||||
* are uninitialized.
|
||||
*/
|
||||
void grow(int newVerbs, int newPoints) {
|
||||
this->validate();
|
||||
size_t space = newVerbs * sizeof(uint8_t) + newPoints * sizeof (SkPoint);
|
||||
this->makeSpace(space);
|
||||
fVerbCnt += newVerbs;
|
||||
fPointCnt += newPoints;
|
||||
fFreeSpace -= space;
|
||||
this->validate();
|
||||
}
|
||||
|
||||
/**
|
||||
* Increases the verb count 1, records the new verb, and creates room for the requisite number
|
||||
* of additional points. A pointer to the first point is returned. Any new points are
|
||||
* uninitialized.
|
||||
*/
|
||||
SkPoint* growForVerb(SkPath::Verb verb) {
|
||||
this->validate();
|
||||
int pCnt;
|
||||
switch (verb) {
|
||||
case SkPath::kMove_Verb:
|
||||
pCnt = 1;
|
||||
break;
|
||||
case SkPath::kLine_Verb:
|
||||
pCnt = 1;
|
||||
break;
|
||||
case SkPath::kQuad_Verb:
|
||||
pCnt = 2;
|
||||
break;
|
||||
case SkPath::kCubic_Verb:
|
||||
pCnt = 3;
|
||||
break;
|
||||
default:
|
||||
pCnt = 0;
|
||||
}
|
||||
size_t space = sizeof(uint8_t) + pCnt * sizeof (SkPoint);
|
||||
this->makeSpace(space);
|
||||
this->fVerbs[~fVerbCnt] = verb;
|
||||
SkPoint* ret = fPoints + fPointCnt;
|
||||
fVerbCnt += 1;
|
||||
fPointCnt += pCnt;
|
||||
fFreeSpace -= space;
|
||||
this->validate();
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensures that the free space available in the path ref is >= size. The verb and point counts
|
||||
* are not changed.
|
||||
*/
|
||||
void makeSpace(size_t size) {
|
||||
this->validate();
|
||||
ptrdiff_t growSize = size - fFreeSpace;
|
||||
if (growSize <= 0) {
|
||||
return;
|
||||
}
|
||||
size_t oldSize = this->currSize();
|
||||
// round to next multiple of 8 bytes
|
||||
growSize = (growSize + 7) & ~static_cast<size_t>(7);
|
||||
// we always at least double the allocation
|
||||
if (static_cast<size_t>(growSize) < oldSize) {
|
||||
growSize = oldSize;
|
||||
}
|
||||
if (growSize < kMinSize) {
|
||||
growSize = kMinSize;
|
||||
}
|
||||
size_t newSize = oldSize + growSize;
|
||||
// Note that realloc could memcpy more than we need. It seems to be a win anyway. TODO:
|
||||
// encapsulate this.
|
||||
fPoints = reinterpret_cast<SkPoint*>(sk_realloc_throw(fPoints, newSize));
|
||||
size_t oldVerbSize = fVerbCnt * sizeof(uint8_t);
|
||||
void* newVerbsDst = reinterpret_cast<void*>(
|
||||
reinterpret_cast<intptr_t>(fPoints) + newSize - oldVerbSize);
|
||||
void* oldVerbsSrc = reinterpret_cast<void*>(
|
||||
reinterpret_cast<intptr_t>(fPoints) + oldSize - oldVerbSize);
|
||||
memmove(newVerbsDst, oldVerbsSrc, oldVerbSize);
|
||||
fVerbs = reinterpret_cast<uint8_t*>(reinterpret_cast<intptr_t>(fPoints) + newSize);
|
||||
fFreeSpace += growSize;
|
||||
this->validate();
|
||||
}
|
||||
|
||||
/**
|
||||
* Private, non-const-ptr version of the public function verbsMemBegin().
|
||||
*/
|
||||
uint8_t* verbsMemWritable() {
|
||||
this->validate();
|
||||
return fVerbs - fVerbCnt;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the total amount of space allocated for verbs, points, and reserve.
|
||||
*/
|
||||
size_t currSize() const {
|
||||
return reinterpret_cast<intptr_t>(fVerbs) - reinterpret_cast<intptr_t>(fPoints);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an ID that uniquely identifies the contents of the path ref. If two path refs have the
|
||||
* same ID then they have the same verbs and points. However, two path refs may have the same
|
||||
* contents but different genIDs. Zero is reserved and means an ID has not yet been determined
|
||||
* for the path ref.
|
||||
*/
|
||||
int32_t genID() const {
|
||||
SkASSERT_X(!fEditorsAttached);
|
||||
if (!fGenerationID) {
|
||||
if (0 == fPointCnt && 0 == fVerbCnt) {
|
||||
fGenerationID = kEmptyGenID;
|
||||
} else {
|
||||
static int32_t gPathRefGenerationID;
|
||||
// do a loop in case our global wraps around, as we never want to return a 0 or the
|
||||
// empty ID
|
||||
do {
|
||||
fGenerationID = sk_atomic_inc(&gPathRefGenerationID) + 1;
|
||||
} while (fGenerationID <= kEmptyGenID);
|
||||
}
|
||||
}
|
||||
return fGenerationID;
|
||||
}
|
||||
|
||||
void validate() const {
|
||||
SkASSERT(static_cast<ptrdiff_t>(fFreeSpace) >= 0);
|
||||
SkASSERT(reinterpret_cast<intptr_t>(fVerbs) - reinterpret_cast<intptr_t>(fPoints) >= 0);
|
||||
SkASSERT((NULL == fPoints) == (NULL == fVerbs));
|
||||
SkASSERT(!(NULL == fPoints && 0 != fFreeSpace));
|
||||
SkASSERT(!(NULL == fPoints && 0 != fFreeSpace));
|
||||
SkASSERT(!(NULL == fPoints && fPointCnt));
|
||||
SkASSERT(!(NULL == fVerbs && fVerbCnt));
|
||||
SkASSERT(this->currSize() ==
|
||||
fFreeSpace + sizeof(SkPoint) * fPointCnt + sizeof(uint8_t) * fVerbCnt);
|
||||
}
|
||||
|
||||
enum {
|
||||
kMinSize = 256,
|
||||
};
|
||||
|
||||
SkPoint* fPoints; // points to begining of the allocation
|
||||
uint8_t* fVerbs; // points just past the end of the allocation (verbs grow backwards)
|
||||
int fVerbCnt;
|
||||
int fPointCnt;
|
||||
size_t fFreeSpace; // redundant but saves computation
|
||||
enum {
|
||||
kEmptyGenID = 1, // GenID reserved for path ref with zero points and zero verbs.
|
||||
};
|
||||
mutable int32_t fGenerationID;
|
||||
SkDEBUGCODE_X(int32_t fEditorsAttached;) // assert that only one editor in use at any time.
|
||||
|
||||
#if SK_DEBUG_PATH_REF
|
||||
SkTDArray<SkPath*> fOwners;
|
||||
#endif
|
||||
|
||||
typedef SkRefCnt INHERITED;
|
||||
};
|
||||
|
||||
SK_DEFINE_INST_COUNT(SkPathRef);
|
||||
|
||||
#endif
|
|
@ -1,718 +0,0 @@
|
|||
|
||||
/*
|
||||
* Copyright 2011 Google Inc.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
#ifndef SkPictureFlat_DEFINED
|
||||
#define SkPictureFlat_DEFINED
|
||||
|
||||
//#define SK_DEBUG_SIZE
|
||||
|
||||
#include "SkChunkAlloc.h"
|
||||
#include "SkBitmap.h"
|
||||
#include "SkBitmapHeap.h"
|
||||
#include "SkOrderedReadBuffer.h"
|
||||
#include "SkOrderedWriteBuffer.h"
|
||||
#include "SkPicture.h"
|
||||
#include "SkPtrRecorder.h"
|
||||
#include "SkMatrix.h"
|
||||
#include "SkPaint.h"
|
||||
#include "SkPath.h"
|
||||
#include "SkRegion.h"
|
||||
#include "SkTRefArray.h"
|
||||
#include "SkTSearch.h"
|
||||
|
||||
enum DrawType {
|
||||
UNUSED,
|
||||
CLIP_PATH,
|
||||
CLIP_REGION,
|
||||
CLIP_RECT,
|
||||
CLIP_RRECT,
|
||||
CONCAT,
|
||||
DRAW_BITMAP,
|
||||
DRAW_BITMAP_MATRIX,
|
||||
DRAW_BITMAP_NINE,
|
||||
DRAW_BITMAP_RECT_TO_RECT,
|
||||
DRAW_CLEAR,
|
||||
DRAW_DATA,
|
||||
DRAW_OVAL,
|
||||
DRAW_PAINT,
|
||||
DRAW_PATH,
|
||||
DRAW_PICTURE,
|
||||
DRAW_POINTS,
|
||||
DRAW_POS_TEXT,
|
||||
DRAW_POS_TEXT_TOP_BOTTOM, // fast variant of DRAW_POS_TEXT
|
||||
DRAW_POS_TEXT_H,
|
||||
DRAW_POS_TEXT_H_TOP_BOTTOM, // fast variant of DRAW_POS_TEXT_H
|
||||
DRAW_RECT,
|
||||
DRAW_RRECT,
|
||||
DRAW_SPRITE,
|
||||
DRAW_TEXT,
|
||||
DRAW_TEXT_ON_PATH,
|
||||
DRAW_TEXT_TOP_BOTTOM, // fast variant of DRAW_TEXT
|
||||
DRAW_VERTICES,
|
||||
RESTORE,
|
||||
ROTATE,
|
||||
SAVE,
|
||||
SAVE_LAYER,
|
||||
SCALE,
|
||||
SET_MATRIX,
|
||||
SKEW,
|
||||
TRANSLATE,
|
||||
NOOP,
|
||||
|
||||
LAST_DRAWTYPE_ENUM = NOOP
|
||||
};
|
||||
|
||||
// In the 'match' method, this constant will match any flavor of DRAW_BITMAP*
|
||||
static const int kDRAW_BITMAP_FLAVOR = LAST_DRAWTYPE_ENUM+1;
|
||||
|
||||
enum DrawVertexFlags {
|
||||
DRAW_VERTICES_HAS_TEXS = 0x01,
|
||||
DRAW_VERTICES_HAS_COLORS = 0x02,
|
||||
DRAW_VERTICES_HAS_INDICES = 0x04
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// clipparams are packed in 5 bits
|
||||
// doAA:1 | regionOp:4
|
||||
|
||||
static inline uint32_t ClipParams_pack(SkRegion::Op op, bool doAA) {
|
||||
unsigned doAABit = doAA ? 1 : 0;
|
||||
return (doAABit << 4) | op;
|
||||
}
|
||||
|
||||
static inline SkRegion::Op ClipParams_unpackRegionOp(uint32_t packed) {
|
||||
return (SkRegion::Op)(packed & 0xF);
|
||||
}
|
||||
|
||||
static inline bool ClipParams_unpackDoAA(uint32_t packed) {
|
||||
return SkToBool((packed >> 4) & 1);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class SkTypefacePlayback {
|
||||
public:
|
||||
SkTypefacePlayback();
|
||||
virtual ~SkTypefacePlayback();
|
||||
|
||||
int count() const { return fCount; }
|
||||
|
||||
void reset(const SkRefCntSet*);
|
||||
|
||||
void setCount(int count);
|
||||
SkRefCnt* set(int index, SkRefCnt*);
|
||||
|
||||
void setupBuffer(SkOrderedReadBuffer& buffer) const {
|
||||
buffer.setTypefaceArray((SkTypeface**)fArray, fCount);
|
||||
}
|
||||
|
||||
protected:
|
||||
int fCount;
|
||||
SkRefCnt** fArray;
|
||||
};
|
||||
|
||||
class SkFactoryPlayback {
|
||||
public:
|
||||
SkFactoryPlayback(int count) : fCount(count) {
|
||||
fArray = SkNEW_ARRAY(SkFlattenable::Factory, count);
|
||||
}
|
||||
|
||||
~SkFactoryPlayback() {
|
||||
SkDELETE_ARRAY(fArray);
|
||||
}
|
||||
|
||||
SkFlattenable::Factory* base() const { return fArray; }
|
||||
|
||||
void setupBuffer(SkOrderedReadBuffer& buffer) const {
|
||||
buffer.setFactoryPlayback(fArray, fCount);
|
||||
}
|
||||
|
||||
private:
|
||||
int fCount;
|
||||
SkFlattenable::Factory* fArray;
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
//
|
||||
// The following templated classes provide an efficient way to store and compare
|
||||
// objects that have been flattened (i.e. serialized in an ordered binary
|
||||
// format).
|
||||
//
|
||||
// SkFlatData: is a simple indexable container for the flattened data
|
||||
// which is agnostic to the type of data is is indexing. It is
|
||||
// also responsible for flattening/unflattening objects but
|
||||
// details of that operation are hidden in the provided procs
|
||||
// SkFlatDictionary: is an abstract templated dictionary that maintains a
|
||||
// searchable set of SkFlataData objects of type T.
|
||||
// SkFlatController: is an interface provided to SkFlatDictionary which handles
|
||||
// allocation and unallocation in some cases. It also holds
|
||||
// ref count recorders and the like.
|
||||
//
|
||||
// NOTE: any class that wishes to be used in conjunction with SkFlatDictionary
|
||||
// must subclass the dictionary and provide the necessary flattening procs.
|
||||
// The end of this header contains dictionary subclasses for some common classes
|
||||
// like SkBitmap, SkMatrix, SkPaint, and SkRegion. SkFlatController must also
|
||||
// be implemented, or SkChunkFlatController can be used to use an
|
||||
// SkChunkAllocator and never do replacements.
|
||||
//
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class SkFlatData;
|
||||
|
||||
class SkFlatController : public SkRefCnt {
|
||||
public:
|
||||
SK_DECLARE_INST_COUNT(SkFlatController)
|
||||
|
||||
SkFlatController();
|
||||
virtual ~SkFlatController();
|
||||
/**
|
||||
* Provide a new block of memory for the SkFlatDictionary to use.
|
||||
*/
|
||||
virtual void* allocThrow(size_t bytes) = 0;
|
||||
|
||||
/**
|
||||
* Unallocate a previously allocated block, returned by allocThrow.
|
||||
* Implementation should at least perform an unallocation if passed the last
|
||||
* pointer returned by allocThrow. If findAndReplace() is intended to be
|
||||
* used, unalloc should also be able to unallocate the SkFlatData that is
|
||||
* provided.
|
||||
*/
|
||||
virtual void unalloc(void* ptr) = 0;
|
||||
|
||||
/**
|
||||
* Used during creation and unflattening of SkFlatData objects. If the
|
||||
* objects being flattened contain bitmaps they are stored in this heap
|
||||
* and the flattenable stores the index to the bitmap on the heap.
|
||||
* This should be set by the protected setBitmapHeap.
|
||||
*/
|
||||
SkBitmapHeap* getBitmapHeap() { return fBitmapHeap; }
|
||||
|
||||
/**
|
||||
* Used during creation of SkFlatData objects. If a typeface recorder is
|
||||
* required to flatten the objects being flattened (i.e. for SkPaints), this
|
||||
* should be set by the protected setTypefaceSet.
|
||||
*/
|
||||
SkRefCntSet* getTypefaceSet() { return fTypefaceSet; }
|
||||
|
||||
/**
|
||||
* Used during unflattening of the SkFlatData objects in the
|
||||
* SkFlatDictionary. Needs to be set by the protected setTypefacePlayback
|
||||
* and needs to be reset to the SkRefCntSet passed to setTypefaceSet.
|
||||
*/
|
||||
SkTypefacePlayback* getTypefacePlayback() { return fTypefacePlayback; }
|
||||
|
||||
/**
|
||||
* Optional factory recorder used during creation of SkFlatData objects. Set
|
||||
* using the protected method setNamedFactorySet.
|
||||
*/
|
||||
SkNamedFactorySet* getNamedFactorySet() { return fFactorySet; }
|
||||
|
||||
/**
|
||||
* Flags to use during creation of SkFlatData objects. Defaults to zero.
|
||||
*/
|
||||
uint32_t getWriteBufferFlags() { return fWriteBufferFlags; }
|
||||
|
||||
protected:
|
||||
/**
|
||||
* Set an SkBitmapHeap to be used to store/read SkBitmaps. Ref counted.
|
||||
*/
|
||||
void setBitmapHeap(SkBitmapHeap*);
|
||||
|
||||
/**
|
||||
* Set an SkRefCntSet to be used to store SkTypefaces during flattening. Ref
|
||||
* counted.
|
||||
*/
|
||||
void setTypefaceSet(SkRefCntSet*);
|
||||
|
||||
/**
|
||||
* Set an SkTypefacePlayback to be used to find references to SkTypefaces
|
||||
* during unflattening. Should be reset to the set provided to
|
||||
* setTypefaceSet.
|
||||
*/
|
||||
void setTypefacePlayback(SkTypefacePlayback*);
|
||||
|
||||
/**
|
||||
* Set an SkNamedFactorySet to be used to store Factorys and their
|
||||
* corresponding names during flattening. Ref counted. Returns the same
|
||||
* set as a convenience.
|
||||
*/
|
||||
SkNamedFactorySet* setNamedFactorySet(SkNamedFactorySet*);
|
||||
|
||||
/**
|
||||
* Set the flags to be used during flattening.
|
||||
*/
|
||||
void setWriteBufferFlags(uint32_t flags) { fWriteBufferFlags = flags; }
|
||||
|
||||
private:
|
||||
SkBitmapHeap* fBitmapHeap;
|
||||
SkRefCntSet* fTypefaceSet;
|
||||
SkTypefacePlayback* fTypefacePlayback;
|
||||
SkNamedFactorySet* fFactorySet;
|
||||
uint32_t fWriteBufferFlags;
|
||||
|
||||
typedef SkRefCnt INHERITED;
|
||||
};
|
||||
|
||||
class SkFlatData {
|
||||
public:
|
||||
/**
|
||||
* Compare two SkFlatData ptrs, returning -1, 0, 1 to allow them to be
|
||||
* sorted.
|
||||
*
|
||||
* Note: this assumes that a and b have different sentinel values, either
|
||||
* InCache or AsCandidate, otherwise the loop will go beyond the end of
|
||||
* the buffers.
|
||||
*
|
||||
* dataToCompare() returns 2 fields before the flattened data:
|
||||
* - checksum
|
||||
* - size
|
||||
* This ensures that if we see two blocks of different length, we will
|
||||
* notice that right away, and not read any further. It also ensures that
|
||||
* we see the checksum right away, so that most of the time it is enough
|
||||
* to short-circuit our comparison.
|
||||
*/
|
||||
static int Compare(const SkFlatData* a, const SkFlatData* b) {
|
||||
const uint32_t* stop = a->dataStop();
|
||||
const uint32_t* a_ptr = a->dataToCompare() - 1;
|
||||
const uint32_t* b_ptr = b->dataToCompare() - 1;
|
||||
// We use -1 above, so we can pre-increment our pointers in the loop
|
||||
while (*++a_ptr == *++b_ptr) {}
|
||||
|
||||
if (a_ptr == stop) { // sentinel
|
||||
SkASSERT(b->dataStop() == b_ptr);
|
||||
return 0;
|
||||
}
|
||||
SkASSERT(a_ptr < a->dataStop());
|
||||
SkASSERT(b_ptr < b->dataStop());
|
||||
return (*a_ptr < *b_ptr) ? -1 : 1;
|
||||
}
|
||||
|
||||
int index() const { return fIndex; }
|
||||
const void* data() const { return (const char*)this + sizeof(*this); }
|
||||
void* data() { return (char*)this + sizeof(*this); }
|
||||
// Our data is always 32bit aligned, so we can offer this accessor
|
||||
uint32_t* data32() { return (uint32_t*)this->data(); }
|
||||
// Returns the size of the flattened data.
|
||||
size_t flatSize() const { return fFlatSize; }
|
||||
|
||||
void setSentinelInCache() {
|
||||
this->setSentinel(kInCache_Sentinel);
|
||||
}
|
||||
void setSentinelAsCandidate() {
|
||||
this->setSentinel(kCandidate_Sentinel);
|
||||
}
|
||||
|
||||
uint32_t checksum() const { return fChecksum; }
|
||||
|
||||
#ifdef SK_DEBUG_SIZE
|
||||
// returns the logical size of our data. Does not return any sentinel or
|
||||
// padding we might have.
|
||||
size_t size() const {
|
||||
return sizeof(SkFlatData) + fFlatSize;
|
||||
}
|
||||
#endif
|
||||
|
||||
static SkFlatData* Create(SkFlatController* controller, const void* obj, int index,
|
||||
void (*flattenProc)(SkOrderedWriteBuffer&, const void*));
|
||||
|
||||
void unflatten(void* result,
|
||||
void (*unflattenProc)(SkOrderedReadBuffer&, void*),
|
||||
SkBitmapHeap* bitmapHeap = NULL,
|
||||
SkTypefacePlayback* facePlayback = NULL) const;
|
||||
|
||||
// When we purge an entry, we want to reuse an old index for the new entry,
|
||||
// so we expose this setter.
|
||||
void setIndex(int index) { fIndex = index; }
|
||||
|
||||
// for unittesting
|
||||
friend bool operator==(const SkFlatData& a, const SkFlatData& b) {
|
||||
size_t N = (const char*)a.dataStop() - (const char*)a.dataToCompare();
|
||||
return !memcmp(a.dataToCompare(), b.dataToCompare(), N);
|
||||
}
|
||||
|
||||
// returns true if fTopBot[] has been recorded
|
||||
bool isTopBotWritten() const {
|
||||
return !SkScalarIsNaN(fTopBot[0]);
|
||||
}
|
||||
|
||||
// Returns fTopBot array, so it can be passed to a routine to compute them.
|
||||
// For efficiency, we assert that fTopBot have not been recorded yet.
|
||||
SkScalar* writableTopBot() const {
|
||||
SkASSERT(!this->isTopBotWritten());
|
||||
return fTopBot;
|
||||
}
|
||||
|
||||
// return the topbot[] after it has been recorded
|
||||
const SkScalar* topBot() const {
|
||||
SkASSERT(this->isTopBotWritten());
|
||||
return fTopBot;
|
||||
}
|
||||
|
||||
private:
|
||||
// This is *not* part of the key for search/sort
|
||||
int fIndex;
|
||||
|
||||
// Cache of paint's FontMetrics fTop,fBottom
|
||||
// initialied to [NaN,NaN] as a sentinel that they have not been recorded yet
|
||||
//
|
||||
// This is *not* part of the key for search/sort
|
||||
mutable SkScalar fTopBot[2];
|
||||
|
||||
// marks fTopBot[] as unrecorded
|
||||
void setTopBotUnwritten() {
|
||||
this->fTopBot[0] = SK_ScalarNaN; // initial to sentinel values
|
||||
}
|
||||
|
||||
// From here down is the data we look at in the search/sort. We always begin
|
||||
// with the checksum and then length.
|
||||
uint32_t fChecksum;
|
||||
int32_t fFlatSize; // size of flattened data
|
||||
// uint32_t flattenedData[]
|
||||
// uint32_t sentinelValue
|
||||
|
||||
const uint32_t* dataToCompare() const {
|
||||
return (const uint32_t*)&fChecksum;
|
||||
}
|
||||
const uint32_t* dataStop() const {
|
||||
SkASSERT(SkIsAlign4(fFlatSize));
|
||||
return (const uint32_t*)((const char*)this->data() + fFlatSize);
|
||||
}
|
||||
|
||||
enum {
|
||||
kInCache_Sentinel = 0,
|
||||
kCandidate_Sentinel = ~0U,
|
||||
};
|
||||
void setSentinel(uint32_t value) {
|
||||
SkASSERT(SkIsAlign4(fFlatSize));
|
||||
this->data32()[fFlatSize >> 2] = value;
|
||||
}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
class SkFlatDictionary {
|
||||
public:
|
||||
SkFlatDictionary(SkFlatController* controller)
|
||||
: fController(controller) {
|
||||
fFlattenProc = NULL;
|
||||
fUnflattenProc = NULL;
|
||||
SkASSERT(controller);
|
||||
fController->ref();
|
||||
// set to 1 since returning a zero from find() indicates failure
|
||||
fNextIndex = 1;
|
||||
sk_bzero(fHash, sizeof(fHash));
|
||||
// index 0 is always empty since it is used as a signal that find failed
|
||||
fIndexedData.push(NULL);
|
||||
}
|
||||
|
||||
virtual ~SkFlatDictionary() {
|
||||
fController->unref();
|
||||
}
|
||||
|
||||
int count() const {
|
||||
SkASSERT(fIndexedData.count() == fSortedData.count()+1);
|
||||
return fSortedData.count();
|
||||
}
|
||||
|
||||
const SkFlatData* operator[](int index) const {
|
||||
SkASSERT(index >= 0 && index < fSortedData.count());
|
||||
return fSortedData[index];
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears the dictionary of all entries. However, it does NOT free the
|
||||
* memory that was allocated for each entry.
|
||||
*/
|
||||
void reset() {
|
||||
fSortedData.reset();
|
||||
fIndexedData.rewind();
|
||||
// index 0 is always empty since it is used as a signal that find failed
|
||||
fIndexedData.push(NULL);
|
||||
fNextIndex = 1;
|
||||
sk_bzero(fHash, sizeof(fHash));
|
||||
}
|
||||
|
||||
/**
|
||||
* Similar to find. Allows the caller to specify an SkFlatData to replace in
|
||||
* the case of an add. Also tells the caller whether a new SkFlatData was
|
||||
* added and whether the old one was replaced. The parameters added and
|
||||
* replaced are required to be non-NULL. Rather than returning the index of
|
||||
* the entry in the dictionary, it returns the actual SkFlatData.
|
||||
*/
|
||||
const SkFlatData* findAndReplace(const T& element,
|
||||
const SkFlatData* toReplace, bool* added,
|
||||
bool* replaced) {
|
||||
SkASSERT(added != NULL && replaced != NULL);
|
||||
int oldCount = fSortedData.count();
|
||||
const SkFlatData* flat = this->findAndReturnFlat(element);
|
||||
*added = fSortedData.count() == oldCount + 1;
|
||||
*replaced = false;
|
||||
if (*added && toReplace != NULL) {
|
||||
// First, find the index of the one to replace
|
||||
int indexToReplace = fSortedData.find(toReplace);
|
||||
if (indexToReplace >= 0) {
|
||||
// findAndReturnFlat set the index to fNextIndex and increased
|
||||
// fNextIndex by one. Reuse the index from the one being
|
||||
// replaced and reset fNextIndex to the proper value.
|
||||
int oldIndex = flat->index();
|
||||
const_cast<SkFlatData*>(flat)->setIndex(toReplace->index());
|
||||
fIndexedData[toReplace->index()] = flat;
|
||||
fNextIndex--;
|
||||
// Remove from the arrays.
|
||||
fSortedData.remove(indexToReplace);
|
||||
fIndexedData.remove(oldIndex);
|
||||
// Remove from the hash table.
|
||||
int oldHash = ChecksumToHashIndex(toReplace->checksum());
|
||||
if (fHash[oldHash] == toReplace) {
|
||||
fHash[oldHash] = NULL;
|
||||
}
|
||||
// Delete the actual object.
|
||||
fController->unalloc((void*)toReplace);
|
||||
*replaced = true;
|
||||
SkASSERT(fIndexedData.count() == fSortedData.count()+1);
|
||||
}
|
||||
}
|
||||
return flat;
|
||||
}
|
||||
|
||||
/**
|
||||
* Given an element of type T return its 1-based index in the dictionary. If
|
||||
* the element wasn't previously in the dictionary it is automatically
|
||||
* added.
|
||||
*
|
||||
* To make the Compare function fast, we write a sentinel value at the end
|
||||
* of each block. The blocks in our fSortedData[] all have a 0 sentinel. The
|
||||
* newly created block we're comparing against has a -1 in the sentinel.
|
||||
*
|
||||
* This trick allows Compare to always loop until failure. If it fails on
|
||||
* the sentinal value, we know the blocks are equal.
|
||||
*/
|
||||
int find(const T& element) {
|
||||
return this->findAndReturnFlat(element)->index();
|
||||
}
|
||||
|
||||
/**
|
||||
* Unflatten the objects and return them in SkTRefArray, or return NULL
|
||||
* if there no objects (instead of an empty array).
|
||||
*/
|
||||
SkTRefArray<T>* unflattenToArray() const {
|
||||
int count = fSortedData.count();
|
||||
SkTRefArray<T>* array = NULL;
|
||||
if (count > 0) {
|
||||
array = SkTRefArray<T>::Create(count);
|
||||
this->unflattenIntoArray(&array->writableAt(0));
|
||||
}
|
||||
return array;
|
||||
}
|
||||
|
||||
/**
|
||||
* Unflatten the specific object at the given index
|
||||
*/
|
||||
T* unflatten(int index) const {
|
||||
SkASSERT(fIndexedData.count() == fSortedData.count()+1);
|
||||
const SkFlatData* element = fIndexedData[index];
|
||||
SkASSERT(index == element->index());
|
||||
|
||||
T* dst = new T;
|
||||
this->unflatten(dst, element);
|
||||
return dst;
|
||||
}
|
||||
|
||||
const SkFlatData* findAndReturnFlat(const T& element) {
|
||||
SkFlatData* flat = SkFlatData::Create(fController, &element, fNextIndex, fFlattenProc);
|
||||
|
||||
int hashIndex = ChecksumToHashIndex(flat->checksum());
|
||||
const SkFlatData* candidate = fHash[hashIndex];
|
||||
if (candidate && !SkFlatData::Compare(flat, candidate)) {
|
||||
fController->unalloc(flat);
|
||||
return candidate;
|
||||
}
|
||||
|
||||
int index = SkTSearch<SkFlatData>((const SkFlatData**) fSortedData.begin(),
|
||||
fSortedData.count(), flat, sizeof(flat),
|
||||
&SkFlatData::Compare);
|
||||
if (index >= 0) {
|
||||
fController->unalloc(flat);
|
||||
fHash[hashIndex] = fSortedData[index];
|
||||
return fSortedData[index];
|
||||
}
|
||||
|
||||
index = ~index;
|
||||
*fSortedData.insert(index) = flat;
|
||||
*fIndexedData.insert(flat->index()) = flat;
|
||||
SkASSERT(fSortedData.count() == fNextIndex);
|
||||
fNextIndex++;
|
||||
flat->setSentinelInCache();
|
||||
fHash[hashIndex] = flat;
|
||||
SkASSERT(fIndexedData.count() == fSortedData.count()+1);
|
||||
return flat;
|
||||
}
|
||||
|
||||
protected:
|
||||
void (*fFlattenProc)(SkOrderedWriteBuffer&, const void*);
|
||||
void (*fUnflattenProc)(SkOrderedReadBuffer&, void*);
|
||||
|
||||
private:
|
||||
void unflatten(T* dst, const SkFlatData* element) const {
|
||||
element->unflatten(dst, fUnflattenProc,
|
||||
fController->getBitmapHeap(),
|
||||
fController->getTypefacePlayback());
|
||||
}
|
||||
|
||||
void unflattenIntoArray(T* array) const {
|
||||
const int count = fSortedData.count();
|
||||
SkASSERT(fIndexedData.count() == fSortedData.count()+1);
|
||||
const SkFlatData* const* iter = fSortedData.begin();
|
||||
for (int i = 0; i < count; ++i) {
|
||||
const SkFlatData* element = iter[i];
|
||||
int index = element->index() - 1;
|
||||
SkASSERT((unsigned)index < (unsigned)count);
|
||||
unflatten(&array[index], element);
|
||||
}
|
||||
}
|
||||
|
||||
SkFlatController * const fController;
|
||||
int fNextIndex;
|
||||
|
||||
// SkFlatDictionary has two copies of the data one indexed by the
|
||||
// SkFlatData's index and the other sorted. The sorted data is used
|
||||
// for finding and uniquification while the indexed copy is used
|
||||
// for standard array-style lookups based on the SkFlatData's index
|
||||
// (as in 'unflatten').
|
||||
SkTDArray<const SkFlatData*> fIndexedData;
|
||||
// fSortedData is sorted by checksum/size/data.
|
||||
SkTDArray<const SkFlatData*> fSortedData;
|
||||
|
||||
enum {
|
||||
// Determined by trying diff values on picture-recording benchmarks
|
||||
// (e.g. PictureRecordBench.cpp), choosing the smallest value that
|
||||
// showed a big improvement. Even better would be to benchmark diff
|
||||
// values on recording representative web-pages or other "real" content.
|
||||
HASH_BITS = 7,
|
||||
HASH_MASK = (1 << HASH_BITS) - 1,
|
||||
HASH_COUNT = 1 << HASH_BITS
|
||||
};
|
||||
const SkFlatData* fHash[HASH_COUNT];
|
||||
|
||||
static int ChecksumToHashIndex(uint32_t checksum) {
|
||||
int n = checksum;
|
||||
if (HASH_BITS < 32) {
|
||||
n ^= n >> 16;
|
||||
}
|
||||
if (HASH_BITS < 16) {
|
||||
n ^= n >> 8;
|
||||
}
|
||||
if (HASH_BITS < 8) {
|
||||
n ^= n >> 4;
|
||||
}
|
||||
return n & HASH_MASK;
|
||||
}
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Some common dictionaries are defined here for both reference and convenience
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
template <class T>
|
||||
static void SkFlattenObjectProc(SkOrderedWriteBuffer& buffer, const void* obj) {
|
||||
((T*)obj)->flatten(buffer);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
static void SkUnflattenObjectProc(SkOrderedReadBuffer& buffer, void* obj) {
|
||||
((T*)obj)->unflatten(buffer);
|
||||
}
|
||||
|
||||
class SkChunkFlatController : public SkFlatController {
|
||||
public:
|
||||
SkChunkFlatController(size_t minSize)
|
||||
: fHeap(minSize)
|
||||
, fTypefaceSet(SkNEW(SkRefCntSet)) {
|
||||
this->setTypefaceSet(fTypefaceSet);
|
||||
this->setTypefacePlayback(&fTypefacePlayback);
|
||||
}
|
||||
|
||||
~SkChunkFlatController() {
|
||||
fTypefaceSet->unref();
|
||||
}
|
||||
|
||||
virtual void* allocThrow(size_t bytes) SK_OVERRIDE {
|
||||
return fHeap.allocThrow(bytes);
|
||||
}
|
||||
|
||||
virtual void unalloc(void* ptr) SK_OVERRIDE {
|
||||
(void) fHeap.unalloc(ptr);
|
||||
}
|
||||
|
||||
void setupPlaybacks() const {
|
||||
fTypefacePlayback.reset(fTypefaceSet);
|
||||
}
|
||||
|
||||
void setBitmapStorage(SkBitmapHeap* heap) {
|
||||
this->setBitmapHeap(heap);
|
||||
}
|
||||
|
||||
private:
|
||||
SkChunkAlloc fHeap;
|
||||
SkRefCntSet* fTypefaceSet;
|
||||
mutable SkTypefacePlayback fTypefacePlayback;
|
||||
};
|
||||
|
||||
class SkBitmapDictionary : public SkFlatDictionary<SkBitmap> {
|
||||
public:
|
||||
SkBitmapDictionary(SkFlatController* controller)
|
||||
: SkFlatDictionary<SkBitmap>(controller) {
|
||||
fFlattenProc = &SkFlattenObjectProc<SkBitmap>;
|
||||
fUnflattenProc = &SkUnflattenObjectProc<SkBitmap>;
|
||||
}
|
||||
};
|
||||
|
||||
class SkMatrixDictionary : public SkFlatDictionary<SkMatrix> {
|
||||
public:
|
||||
SkMatrixDictionary(SkFlatController* controller)
|
||||
: SkFlatDictionary<SkMatrix>(controller) {
|
||||
fFlattenProc = &flattenMatrix;
|
||||
fUnflattenProc = &unflattenMatrix;
|
||||
}
|
||||
|
||||
static void flattenMatrix(SkOrderedWriteBuffer& buffer, const void* obj) {
|
||||
buffer.getWriter32()->writeMatrix(*(SkMatrix*)obj);
|
||||
}
|
||||
|
||||
static void unflattenMatrix(SkOrderedReadBuffer& buffer, void* obj) {
|
||||
buffer.getReader32()->readMatrix((SkMatrix*)obj);
|
||||
}
|
||||
};
|
||||
|
||||
class SkPaintDictionary : public SkFlatDictionary<SkPaint> {
|
||||
public:
|
||||
SkPaintDictionary(SkFlatController* controller)
|
||||
: SkFlatDictionary<SkPaint>(controller) {
|
||||
fFlattenProc = &SkFlattenObjectProc<SkPaint>;
|
||||
fUnflattenProc = &SkUnflattenObjectProc<SkPaint>;
|
||||
}
|
||||
};
|
||||
|
||||
class SkRegionDictionary : public SkFlatDictionary<SkRegion> {
|
||||
public:
|
||||
SkRegionDictionary(SkFlatController* controller)
|
||||
: SkFlatDictionary<SkRegion>(controller) {
|
||||
fFlattenProc = &flattenRegion;
|
||||
fUnflattenProc = &unflattenRegion;
|
||||
}
|
||||
|
||||
static void flattenRegion(SkOrderedWriteBuffer& buffer, const void* obj) {
|
||||
buffer.getWriter32()->writeRegion(*(SkRegion*)obj);
|
||||
}
|
||||
|
||||
static void unflattenRegion(SkOrderedReadBuffer& buffer, void* obj) {
|
||||
buffer.getReader32()->readRegion((SkRegion*)obj);
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
|
@ -1,187 +0,0 @@
|
|||
|
||||
/*
|
||||
* Copyright 2011 Google Inc.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
#include "SkPixelRef.h"
|
||||
#include "SkFlattenableBuffers.h"
|
||||
#include "SkThread.h"
|
||||
|
||||
SK_DEFINE_INST_COUNT(SkPixelRef)
|
||||
|
||||
// must be a power-of-2. undef to just use 1 mutex
|
||||
#define PIXELREF_MUTEX_RING_COUNT 32
|
||||
|
||||
#ifdef PIXELREF_MUTEX_RING_COUNT
|
||||
static int32_t gPixelRefMutexRingIndex;
|
||||
static SK_DECLARE_MUTEX_ARRAY(gPixelRefMutexRing, PIXELREF_MUTEX_RING_COUNT);
|
||||
#else
|
||||
SK_DECLARE_STATIC_MUTEX(gPixelRefMutex);
|
||||
#endif
|
||||
|
||||
static SkBaseMutex* get_default_mutex() {
|
||||
#ifdef PIXELREF_MUTEX_RING_COUNT
|
||||
// atomic_inc might be overkill here. It may be fine if once in a while
|
||||
// we hit a race-condition and two subsequent calls get the same index...
|
||||
int index = sk_atomic_inc(&gPixelRefMutexRingIndex);
|
||||
return &gPixelRefMutexRing[index & (PIXELREF_MUTEX_RING_COUNT - 1)];
|
||||
#else
|
||||
return &gPixelRefMutex;
|
||||
#endif
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
int32_t SkNextPixelRefGenerationID();
|
||||
|
||||
int32_t SkNextPixelRefGenerationID() {
|
||||
static int32_t gPixelRefGenerationID;
|
||||
// do a loop in case our global wraps around, as we never want to
|
||||
// return a 0
|
||||
int32_t genID;
|
||||
do {
|
||||
genID = sk_atomic_inc(&gPixelRefGenerationID) + 1;
|
||||
} while (0 == genID);
|
||||
return genID;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void SkPixelRef::setMutex(SkBaseMutex* mutex) {
|
||||
if (NULL == mutex) {
|
||||
mutex = get_default_mutex();
|
||||
}
|
||||
fMutex = mutex;
|
||||
}
|
||||
|
||||
// just need a > 0 value, so pick a funny one to aid in debugging
|
||||
#define SKPIXELREF_PRELOCKED_LOCKCOUNT 123456789
|
||||
|
||||
SkPixelRef::SkPixelRef(SkBaseMutex* mutex) : fPreLocked(false) {
|
||||
this->setMutex(mutex);
|
||||
fPixels = NULL;
|
||||
fColorTable = NULL; // we do not track ownership of this
|
||||
fLockCount = 0;
|
||||
fGenerationID = 0; // signal to rebuild
|
||||
fIsImmutable = false;
|
||||
fPreLocked = false;
|
||||
}
|
||||
|
||||
SkPixelRef::SkPixelRef(SkFlattenableReadBuffer& buffer, SkBaseMutex* mutex)
|
||||
: INHERITED(buffer) {
|
||||
this->setMutex(mutex);
|
||||
fPixels = NULL;
|
||||
fColorTable = NULL; // we do not track ownership of this
|
||||
fLockCount = 0;
|
||||
fIsImmutable = buffer.readBool();
|
||||
fGenerationID = buffer.readUInt();
|
||||
fPreLocked = false;
|
||||
}
|
||||
|
||||
void SkPixelRef::setPreLocked(void* pixels, SkColorTable* ctable) {
|
||||
#ifndef SK_IGNORE_PIXELREF_SETPRELOCKED
|
||||
// only call me in your constructor, otherwise fLockCount tracking can get
|
||||
// out of sync.
|
||||
fPixels = pixels;
|
||||
fColorTable = ctable;
|
||||
fLockCount = SKPIXELREF_PRELOCKED_LOCKCOUNT;
|
||||
fPreLocked = true;
|
||||
#endif
|
||||
}
|
||||
|
||||
void SkPixelRef::flatten(SkFlattenableWriteBuffer& buffer) const {
|
||||
this->INHERITED::flatten(buffer);
|
||||
buffer.writeBool(fIsImmutable);
|
||||
// We write the gen ID into the picture for within-process recording. This
|
||||
// is safe since the same genID will never refer to two different sets of
|
||||
// pixels (barring overflow). However, each process has its own "namespace"
|
||||
// of genIDs. So for cross-process recording we write a zero which will
|
||||
// trigger assignment of a new genID in playback.
|
||||
if (buffer.isCrossProcess()) {
|
||||
buffer.writeUInt(0);
|
||||
} else {
|
||||
buffer.writeUInt(fGenerationID);
|
||||
}
|
||||
}
|
||||
|
||||
void SkPixelRef::lockPixels() {
|
||||
SkASSERT(!fPreLocked || SKPIXELREF_PRELOCKED_LOCKCOUNT == fLockCount);
|
||||
|
||||
if (!fPreLocked) {
|
||||
SkAutoMutexAcquire ac(*fMutex);
|
||||
|
||||
if (1 == ++fLockCount) {
|
||||
fPixels = this->onLockPixels(&fColorTable);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SkPixelRef::unlockPixels() {
|
||||
SkASSERT(!fPreLocked || SKPIXELREF_PRELOCKED_LOCKCOUNT == fLockCount);
|
||||
|
||||
if (!fPreLocked) {
|
||||
SkAutoMutexAcquire ac(*fMutex);
|
||||
|
||||
SkASSERT(fLockCount > 0);
|
||||
if (0 == --fLockCount) {
|
||||
this->onUnlockPixels();
|
||||
fPixels = NULL;
|
||||
fColorTable = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool SkPixelRef::lockPixelsAreWritable() const {
|
||||
return this->onLockPixelsAreWritable();
|
||||
}
|
||||
|
||||
bool SkPixelRef::onLockPixelsAreWritable() const {
|
||||
return true;
|
||||
}
|
||||
|
||||
uint32_t SkPixelRef::getGenerationID() const {
|
||||
if (0 == fGenerationID) {
|
||||
fGenerationID = SkNextPixelRefGenerationID();
|
||||
}
|
||||
return fGenerationID;
|
||||
}
|
||||
|
||||
void SkPixelRef::notifyPixelsChanged() {
|
||||
#ifdef SK_DEBUG
|
||||
if (fIsImmutable) {
|
||||
SkDebugf("========== notifyPixelsChanged called on immutable pixelref");
|
||||
}
|
||||
#endif
|
||||
// this signals us to recompute this next time around
|
||||
fGenerationID = 0;
|
||||
}
|
||||
|
||||
void SkPixelRef::setImmutable() {
|
||||
fIsImmutable = true;
|
||||
}
|
||||
|
||||
bool SkPixelRef::readPixels(SkBitmap* dst, const SkIRect* subset) {
|
||||
return this->onReadPixels(dst, subset);
|
||||
}
|
||||
|
||||
bool SkPixelRef::onReadPixels(SkBitmap* dst, const SkIRect* subset) {
|
||||
return false;
|
||||
}
|
||||
|
||||
SkData* SkPixelRef::onRefEncodedData() {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifdef SK_BUILD_FOR_ANDROID
|
||||
void SkPixelRef::globalRef(void* data) {
|
||||
this->ref();
|
||||
}
|
||||
|
||||
void SkPixelRef::globalUnref() {
|
||||
this->unref();
|
||||
}
|
||||
#endif
|
|
@ -1,473 +0,0 @@
|
|||
|
||||
/*
|
||||
* Copyright 2008 The Android Open Source Project
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
|
||||
#include "SkPoint.h"
|
||||
|
||||
void SkIPoint::rotateCW(SkIPoint* dst) const {
|
||||
SkASSERT(dst);
|
||||
|
||||
// use a tmp in case this == dst
|
||||
int32_t tmp = fX;
|
||||
dst->fX = -fY;
|
||||
dst->fY = tmp;
|
||||
}
|
||||
|
||||
void SkIPoint::rotateCCW(SkIPoint* dst) const {
|
||||
SkASSERT(dst);
|
||||
|
||||
// use a tmp in case this == dst
|
||||
int32_t tmp = fX;
|
||||
dst->fX = fY;
|
||||
dst->fY = -tmp;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void SkPoint::setIRectFan(int l, int t, int r, int b, size_t stride) {
|
||||
SkASSERT(stride >= sizeof(SkPoint));
|
||||
|
||||
((SkPoint*)((intptr_t)this + 0 * stride))->set(SkIntToScalar(l),
|
||||
SkIntToScalar(t));
|
||||
((SkPoint*)((intptr_t)this + 1 * stride))->set(SkIntToScalar(l),
|
||||
SkIntToScalar(b));
|
||||
((SkPoint*)((intptr_t)this + 2 * stride))->set(SkIntToScalar(r),
|
||||
SkIntToScalar(b));
|
||||
((SkPoint*)((intptr_t)this + 3 * stride))->set(SkIntToScalar(r),
|
||||
SkIntToScalar(t));
|
||||
}
|
||||
|
||||
void SkPoint::setRectFan(SkScalar l, SkScalar t, SkScalar r, SkScalar b,
|
||||
size_t stride) {
|
||||
SkASSERT(stride >= sizeof(SkPoint));
|
||||
|
||||
((SkPoint*)((intptr_t)this + 0 * stride))->set(l, t);
|
||||
((SkPoint*)((intptr_t)this + 1 * stride))->set(l, b);
|
||||
((SkPoint*)((intptr_t)this + 2 * stride))->set(r, b);
|
||||
((SkPoint*)((intptr_t)this + 3 * stride))->set(r, t);
|
||||
}
|
||||
|
||||
void SkPoint::rotateCW(SkPoint* dst) const {
|
||||
SkASSERT(dst);
|
||||
|
||||
// use a tmp in case this == dst
|
||||
SkScalar tmp = fX;
|
||||
dst->fX = -fY;
|
||||
dst->fY = tmp;
|
||||
}
|
||||
|
||||
void SkPoint::rotateCCW(SkPoint* dst) const {
|
||||
SkASSERT(dst);
|
||||
|
||||
// use a tmp in case this == dst
|
||||
SkScalar tmp = fX;
|
||||
dst->fX = fY;
|
||||
dst->fY = -tmp;
|
||||
}
|
||||
|
||||
void SkPoint::scale(SkScalar scale, SkPoint* dst) const {
|
||||
SkASSERT(dst);
|
||||
dst->set(SkScalarMul(fX, scale), SkScalarMul(fY, scale));
|
||||
}
|
||||
|
||||
bool SkPoint::normalize() {
|
||||
return this->setLength(fX, fY, SK_Scalar1);
|
||||
}
|
||||
|
||||
bool SkPoint::setNormalize(SkScalar x, SkScalar y) {
|
||||
return this->setLength(x, y, SK_Scalar1);
|
||||
}
|
||||
|
||||
bool SkPoint::setLength(SkScalar length) {
|
||||
return this->setLength(fX, fY, length);
|
||||
}
|
||||
|
||||
#ifdef SK_SCALAR_IS_FLOAT
|
||||
|
||||
// Returns the square of the Euclidian distance to (dx,dy).
|
||||
static inline float getLengthSquared(float dx, float dy) {
|
||||
return dx * dx + dy * dy;
|
||||
}
|
||||
|
||||
// Calculates the square of the Euclidian distance to (dx,dy) and stores it in
|
||||
// *lengthSquared. Returns true if the distance is judged to be "nearly zero".
|
||||
//
|
||||
// This logic is encapsulated in a helper method to make it explicit that we
|
||||
// always perform this check in the same manner, to avoid inconsistencies
|
||||
// (see http://code.google.com/p/skia/issues/detail?id=560 ).
|
||||
static inline bool isLengthNearlyZero(float dx, float dy,
|
||||
float *lengthSquared) {
|
||||
*lengthSquared = getLengthSquared(dx, dy);
|
||||
return *lengthSquared <= (SK_ScalarNearlyZero * SK_ScalarNearlyZero);
|
||||
}
|
||||
|
||||
SkScalar SkPoint::Normalize(SkPoint* pt) {
|
||||
float mag2;
|
||||
if (!isLengthNearlyZero(pt->fX, pt->fY, &mag2)) {
|
||||
float mag = sk_float_sqrt(mag2);
|
||||
float scale = 1.0f / mag;
|
||||
pt->fX = pt->fX * scale;
|
||||
pt->fY = pt->fY * scale;
|
||||
return mag;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
SkScalar SkPoint::Length(SkScalar dx, SkScalar dy) {
|
||||
return sk_float_sqrt(getLengthSquared(dx, dy));
|
||||
}
|
||||
|
||||
bool SkPoint::setLength(float x, float y, float length) {
|
||||
float mag2;
|
||||
if (!isLengthNearlyZero(x, y, &mag2)) {
|
||||
float scale = length / sk_float_sqrt(mag2);
|
||||
fX = x * scale;
|
||||
fY = y * scale;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
#include "Sk64.h"
|
||||
|
||||
// Returns the square of the Euclidian distance to (dx,dy) in *result.
|
||||
static inline void getLengthSquared(SkScalar dx, SkScalar dy, Sk64 *result) {
|
||||
Sk64 dySqr;
|
||||
|
||||
result->setMul(dx, dx);
|
||||
dySqr.setMul(dy, dy);
|
||||
result->add(dySqr);
|
||||
}
|
||||
|
||||
// Calculates the square of the Euclidian distance to (dx,dy) and stores it in
|
||||
// *lengthSquared. Returns true if the distance is judged to be "nearly zero".
|
||||
//
|
||||
// This logic is encapsulated in a helper method to make it explicit that we
|
||||
// always perform this check in the same manner, to avoid inconsistencies
|
||||
// (see http://code.google.com/p/skia/issues/detail?id=560 ).
|
||||
static inline bool isLengthNearlyZero(SkScalar dx, SkScalar dy,
|
||||
Sk64 *lengthSquared) {
|
||||
Sk64 tolSqr;
|
||||
getLengthSquared(dx, dy, lengthSquared);
|
||||
|
||||
// we want nearlyzero^2, but to compute it fast we want to just do a
|
||||
// 32bit multiply, so we require that it not exceed 31bits. That is true
|
||||
// if nearlyzero is <= 0xB504, which should be trivial, since usually
|
||||
// nearlyzero is a very small fixed-point value.
|
||||
SkASSERT(SK_ScalarNearlyZero <= 0xB504);
|
||||
|
||||
tolSqr.set(0, SK_ScalarNearlyZero * SK_ScalarNearlyZero);
|
||||
return *lengthSquared <= tolSqr;
|
||||
}
|
||||
|
||||
SkScalar SkPoint::Normalize(SkPoint* pt) {
|
||||
Sk64 mag2;
|
||||
if (!isLengthNearlyZero(pt->fX, pt->fY, &mag2)) {
|
||||
SkScalar mag = mag2.getSqrt();
|
||||
SkScalar scale = SkScalarInvert(mag);
|
||||
pt->fX = SkScalarMul(pt->fX, scale);
|
||||
pt->fY = SkScalarMul(pt->fY, scale);
|
||||
return mag;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool SkPoint::CanNormalize(SkScalar dx, SkScalar dy) {
|
||||
Sk64 mag2_unused;
|
||||
return !isLengthNearlyZero(dx, dy, &mag2_unused);
|
||||
}
|
||||
|
||||
SkScalar SkPoint::Length(SkScalar dx, SkScalar dy) {
|
||||
Sk64 tmp;
|
||||
getLengthSquared(dx, dy, &tmp);
|
||||
return tmp.getSqrt();
|
||||
}
|
||||
|
||||
#ifdef SK_DEBUGx
|
||||
static SkFixed fixlen(SkFixed x, SkFixed y) {
|
||||
float fx = (float)x;
|
||||
float fy = (float)y;
|
||||
|
||||
return (int)floorf(sqrtf(fx*fx + fy*fy) + 0.5f);
|
||||
}
|
||||
#endif
|
||||
|
||||
static inline uint32_t squarefixed(unsigned x) {
|
||||
x >>= 16;
|
||||
return x*x;
|
||||
}
|
||||
|
||||
#if 1 // Newton iter for setLength
|
||||
|
||||
static inline unsigned invsqrt_iter(unsigned V, unsigned U) {
|
||||
unsigned x = V * U >> 14;
|
||||
x = x * U >> 14;
|
||||
x = (3 << 14) - x;
|
||||
x = (U >> 1) * x >> 14;
|
||||
return x;
|
||||
}
|
||||
|
||||
static const uint16_t gInvSqrt14GuessTable[] = {
|
||||
0x4000, 0x3c57, 0x393e, 0x3695, 0x3441, 0x3235, 0x3061,
|
||||
0x2ebd, 0x2d41, 0x2be7, 0x2aaa, 0x2987, 0x287a, 0x2780,
|
||||
0x2698, 0x25be, 0x24f3, 0x2434, 0x2380, 0x22d6, 0x2235,
|
||||
0x219d, 0x210c, 0x2083, 0x2000, 0x1f82, 0x1f0b, 0x1e99,
|
||||
0x1e2b, 0x1dc2, 0x1d5d, 0x1cfc, 0x1c9f, 0x1c45, 0x1bee,
|
||||
0x1b9b, 0x1b4a, 0x1afc, 0x1ab0, 0x1a67, 0x1a20, 0x19dc,
|
||||
0x1999, 0x1959, 0x191a, 0x18dd, 0x18a2, 0x1868, 0x1830,
|
||||
0x17fa, 0x17c4, 0x1791, 0x175e, 0x172d, 0x16fd, 0x16ce
|
||||
};
|
||||
|
||||
#define BUILD_INVSQRT_TABLEx
|
||||
#ifdef BUILD_INVSQRT_TABLE
|
||||
static void build_invsqrt14_guess_table() {
|
||||
for (int i = 8; i <= 63; i++) {
|
||||
unsigned x = SkToU16((1 << 28) / SkSqrt32(i << 25));
|
||||
printf("0x%x, ", x);
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
#endif
|
||||
|
||||
static unsigned fast_invsqrt(uint32_t x) {
|
||||
#ifdef BUILD_INVSQRT_TABLE
|
||||
unsigned top2 = x >> 25;
|
||||
SkASSERT(top2 >= 8 && top2 <= 63);
|
||||
|
||||
static bool gOnce;
|
||||
if (!gOnce) {
|
||||
build_invsqrt14_guess_table();
|
||||
gOnce = true;
|
||||
}
|
||||
#endif
|
||||
|
||||
unsigned V = x >> 14; // make V .14
|
||||
|
||||
unsigned top = x >> 25;
|
||||
SkASSERT(top >= 8 && top <= 63);
|
||||
SkASSERT(top - 8 < SK_ARRAY_COUNT(gInvSqrt14GuessTable));
|
||||
unsigned U = gInvSqrt14GuessTable[top - 8];
|
||||
|
||||
U = invsqrt_iter(V, U);
|
||||
return invsqrt_iter(V, U);
|
||||
}
|
||||
|
||||
/* We "normalize" x,y to be .14 values (so we can square them and stay 32bits.
|
||||
Then we Newton-iterate this in .14 space to compute the invser-sqrt, and
|
||||
scale by it at the end. The .14 space means we can execute our iterations
|
||||
and stay in 32bits as well, making the multiplies much cheaper than calling
|
||||
SkFixedMul.
|
||||
*/
|
||||
bool SkPoint::setLength(SkFixed ox, SkFixed oy, SkFixed length) {
|
||||
if (ox == 0) {
|
||||
if (oy == 0) {
|
||||
return false;
|
||||
}
|
||||
this->set(0, SkApplySign(length, SkExtractSign(oy)));
|
||||
return true;
|
||||
}
|
||||
if (oy == 0) {
|
||||
this->set(SkApplySign(length, SkExtractSign(ox)), 0);
|
||||
return true;
|
||||
}
|
||||
|
||||
unsigned x = SkAbs32(ox);
|
||||
unsigned y = SkAbs32(oy);
|
||||
int zeros = SkCLZ(x | y);
|
||||
|
||||
// make x,y 1.14 values so our fast sqr won't overflow
|
||||
if (zeros > 17) {
|
||||
x <<= zeros - 17;
|
||||
y <<= zeros - 17;
|
||||
} else {
|
||||
x >>= 17 - zeros;
|
||||
y >>= 17 - zeros;
|
||||
}
|
||||
SkASSERT((x | y) <= 0x7FFF);
|
||||
|
||||
unsigned invrt = fast_invsqrt(x*x + y*y);
|
||||
|
||||
x = x * invrt >> 12;
|
||||
y = y * invrt >> 12;
|
||||
|
||||
if (length != SK_Fixed1) {
|
||||
x = SkFixedMul(x, length);
|
||||
y = SkFixedMul(y, length);
|
||||
}
|
||||
this->set(SkApplySign(x, SkExtractSign(ox)),
|
||||
SkApplySign(y, SkExtractSign(oy)));
|
||||
return true;
|
||||
}
|
||||
#else
|
||||
/*
|
||||
Normalize x,y, and then scale them by length.
|
||||
|
||||
The obvious way to do this would be the following:
|
||||
S64 tmp1, tmp2;
|
||||
tmp1.setMul(x,x);
|
||||
tmp2.setMul(y,y);
|
||||
tmp1.add(tmp2);
|
||||
len = tmp1.getSqrt();
|
||||
x' = SkFixedDiv(x, len);
|
||||
y' = SkFixedDiv(y, len);
|
||||
This is fine, but slower than what we do below.
|
||||
|
||||
The present technique does not compute the starting length, but
|
||||
rather fiddles with x,y iteratively, all the while checking its
|
||||
magnitude^2 (avoiding a sqrt).
|
||||
|
||||
We normalize by first shifting x,y so that at least one of them
|
||||
has bit 31 set (after taking the abs of them).
|
||||
Then we loop, refining x,y by squaring them and comparing
|
||||
against a very large 1.0 (1 << 28), and then adding or subtracting
|
||||
a delta (which itself is reduced by half each time through the loop).
|
||||
For speed we want the squaring to be with a simple integer mul. To keep
|
||||
that from overflowing we shift our coordinates down until we are dealing
|
||||
with at most 15 bits (2^15-1)^2 * 2 says withing 32 bits)
|
||||
When our square is close to 1.0, we shift x,y down into fixed range.
|
||||
*/
|
||||
bool SkPoint::setLength(SkFixed ox, SkFixed oy, SkFixed length) {
|
||||
if (ox == 0) {
|
||||
if (oy == 0)
|
||||
return false;
|
||||
this->set(0, SkApplySign(length, SkExtractSign(oy)));
|
||||
return true;
|
||||
}
|
||||
if (oy == 0) {
|
||||
this->set(SkApplySign(length, SkExtractSign(ox)), 0);
|
||||
return true;
|
||||
}
|
||||
|
||||
SkFixed x = SkAbs32(ox);
|
||||
SkFixed y = SkAbs32(oy);
|
||||
|
||||
// shift x,y so that the greater of them is 15bits (1.14 fixed point)
|
||||
{
|
||||
int shift = SkCLZ(x | y);
|
||||
// make them .30
|
||||
x <<= shift - 1;
|
||||
y <<= shift - 1;
|
||||
}
|
||||
|
||||
SkFixed dx = x;
|
||||
SkFixed dy = y;
|
||||
|
||||
for (int i = 0; i < 17; i++) {
|
||||
dx >>= 1;
|
||||
dy >>= 1;
|
||||
|
||||
U32 len2 = squarefixed(x) + squarefixed(y);
|
||||
if (len2 >> 28) {
|
||||
x -= dx;
|
||||
y -= dy;
|
||||
} else {
|
||||
x += dx;
|
||||
y += dy;
|
||||
}
|
||||
}
|
||||
x >>= 14;
|
||||
y >>= 14;
|
||||
|
||||
#ifdef SK_DEBUGx // measure how far we are from unit-length
|
||||
{
|
||||
static int gMaxError;
|
||||
static int gMaxDiff;
|
||||
|
||||
SkFixed len = fixlen(x, y);
|
||||
int err = len - SK_Fixed1;
|
||||
err = SkAbs32(err);
|
||||
|
||||
if (err > gMaxError) {
|
||||
gMaxError = err;
|
||||
SkDebugf("gMaxError %d\n", err);
|
||||
}
|
||||
|
||||
float fx = SkAbs32(ox)/65536.0f;
|
||||
float fy = SkAbs32(oy)/65536.0f;
|
||||
float mag = sqrtf(fx*fx + fy*fy);
|
||||
fx /= mag;
|
||||
fy /= mag;
|
||||
SkFixed xx = (int)floorf(fx * 65536 + 0.5f);
|
||||
SkFixed yy = (int)floorf(fy * 65536 + 0.5f);
|
||||
err = SkMax32(SkAbs32(xx-x), SkAbs32(yy-y));
|
||||
if (err > gMaxDiff) {
|
||||
gMaxDiff = err;
|
||||
SkDebugf("gMaxDiff %d\n", err);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
x = SkApplySign(x, SkExtractSign(ox));
|
||||
y = SkApplySign(y, SkExtractSign(oy));
|
||||
if (length != SK_Fixed1) {
|
||||
x = SkFixedMul(x, length);
|
||||
y = SkFixedMul(y, length);
|
||||
}
|
||||
|
||||
this->set(x, y);
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
SkScalar SkPoint::distanceToLineBetweenSqd(const SkPoint& a,
|
||||
const SkPoint& b,
|
||||
Side* side) const {
|
||||
|
||||
SkVector u = b - a;
|
||||
SkVector v = *this - a;
|
||||
|
||||
SkScalar uLengthSqd = u.lengthSqd();
|
||||
SkScalar det = u.cross(v);
|
||||
if (NULL != side) {
|
||||
SkASSERT(-1 == SkPoint::kLeft_Side &&
|
||||
0 == SkPoint::kOn_Side &&
|
||||
1 == kRight_Side);
|
||||
*side = (Side) SkScalarSignAsInt(det);
|
||||
}
|
||||
return SkScalarMulDiv(det, det, uLengthSqd);
|
||||
}
|
||||
|
||||
SkScalar SkPoint::distanceToLineSegmentBetweenSqd(const SkPoint& a,
|
||||
const SkPoint& b) const {
|
||||
// See comments to distanceToLineBetweenSqd. If the projection of c onto
|
||||
// u is between a and b then this returns the same result as that
|
||||
// function. Otherwise, it returns the distance to the closer of a and
|
||||
// b. Let the projection of v onto u be v'. There are three cases:
|
||||
// 1. v' points opposite to u. c is not between a and b and is closer
|
||||
// to a than b.
|
||||
// 2. v' points along u and has magnitude less than y. c is between
|
||||
// a and b and the distance to the segment is the same as distance
|
||||
// to the line ab.
|
||||
// 3. v' points along u and has greater magnitude than u. c is not
|
||||
// not between a and b and is closer to b than a.
|
||||
// v' = (u dot v) * u / |u|. So if (u dot v)/|u| is less than zero we're
|
||||
// in case 1. If (u dot v)/|u| is > |u| we are in case 3. Otherwise
|
||||
// we're in case 2. We actually compare (u dot v) to 0 and |u|^2 to
|
||||
// avoid a sqrt to compute |u|.
|
||||
|
||||
SkVector u = b - a;
|
||||
SkVector v = *this - a;
|
||||
|
||||
SkScalar uLengthSqd = u.lengthSqd();
|
||||
SkScalar uDotV = SkPoint::DotProduct(u, v);
|
||||
|
||||
if (uDotV <= 0) {
|
||||
return v.lengthSqd();
|
||||
} else if (uDotV > uLengthSqd) {
|
||||
return b.distanceToSqd(*this);
|
||||
} else {
|
||||
SkScalar det = u.cross(v);
|
||||
return SkScalarMulDiv(det, det, uLengthSqd);
|
||||
}
|
||||
}
|
|
@ -1,200 +0,0 @@
|
|||
/*
|
||||
* Copyright 2011 The Android Open Source Project
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include "SkAdvancedTypefaceMetrics.h"
|
||||
#include "SkFontDescriptor.h"
|
||||
#include "SkFontHost.h"
|
||||
#include "SkFontStream.h"
|
||||
#include "SkStream.h"
|
||||
#include "SkTypeface.h"
|
||||
|
||||
SK_DEFINE_INST_COUNT(SkTypeface)
|
||||
|
||||
//#define TRACE_LIFECYCLE
|
||||
|
||||
#ifdef TRACE_LIFECYCLE
|
||||
static int32_t gTypefaceCounter;
|
||||
#endif
|
||||
|
||||
SkTypeface::SkTypeface(Style style, SkFontID fontID, bool isFixedPitch)
|
||||
: fUniqueID(fontID), fStyle(style), fIsFixedPitch(isFixedPitch) {
|
||||
#ifdef TRACE_LIFECYCLE
|
||||
SkDebugf("SkTypeface: create %p fontID %d total %d\n",
|
||||
this, fontID, ++gTypefaceCounter);
|
||||
#endif
|
||||
}
|
||||
|
||||
SkTypeface::~SkTypeface() {
|
||||
#ifdef TRACE_LIFECYCLE
|
||||
SkDebugf("SkTypeface: destroy %p fontID %d total %d\n",
|
||||
this, fUniqueID, --gTypefaceCounter);
|
||||
#endif
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
SkTypeface* SkTypeface::GetDefaultTypeface() {
|
||||
// we keep a reference to this guy for all time, since if we return its
|
||||
// fontID, the font cache may later on ask to resolve that back into a
|
||||
// typeface object.
|
||||
static SkTypeface* gDefaultTypeface;
|
||||
|
||||
if (NULL == gDefaultTypeface) {
|
||||
gDefaultTypeface =
|
||||
SkFontHost::CreateTypeface(NULL, NULL, SkTypeface::kNormal);
|
||||
}
|
||||
return gDefaultTypeface;
|
||||
}
|
||||
|
||||
SkTypeface* SkTypeface::RefDefault() {
|
||||
return SkRef(GetDefaultTypeface());
|
||||
}
|
||||
|
||||
uint32_t SkTypeface::UniqueID(const SkTypeface* face) {
|
||||
if (NULL == face) {
|
||||
face = GetDefaultTypeface();
|
||||
}
|
||||
return face->uniqueID();
|
||||
}
|
||||
|
||||
bool SkTypeface::Equal(const SkTypeface* facea, const SkTypeface* faceb) {
|
||||
return SkTypeface::UniqueID(facea) == SkTypeface::UniqueID(faceb);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
SkTypeface* SkTypeface::CreateFromName(const char name[], Style style) {
|
||||
return SkFontHost::CreateTypeface(NULL, name, style);
|
||||
}
|
||||
|
||||
SkTypeface* SkTypeface::CreateFromTypeface(const SkTypeface* family, Style s) {
|
||||
if (family && family->style() == s) {
|
||||
family->ref();
|
||||
return const_cast<SkTypeface*>(family);
|
||||
}
|
||||
return SkFontHost::CreateTypeface(family, NULL, s);
|
||||
}
|
||||
|
||||
SkTypeface* SkTypeface::CreateFromStream(SkStream* stream) {
|
||||
return SkFontHost::CreateTypefaceFromStream(stream);
|
||||
}
|
||||
|
||||
SkTypeface* SkTypeface::CreateFromFile(const char path[]) {
|
||||
return SkFontHost::CreateTypefaceFromFile(path);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void SkTypeface::serialize(SkWStream* wstream) const {
|
||||
bool isLocal = false;
|
||||
SkFontDescriptor desc(this->style());
|
||||
this->onGetFontDescriptor(&desc, &isLocal);
|
||||
|
||||
desc.serialize(wstream);
|
||||
if (isLocal) {
|
||||
int ttcIndex; // TODO: write this to the stream?
|
||||
SkAutoTUnref<SkStream> rstream(this->openStream(&ttcIndex));
|
||||
if (rstream.get()) {
|
||||
size_t length = rstream->getLength();
|
||||
wstream->writePackedUInt(length);
|
||||
wstream->writeStream(rstream, length);
|
||||
} else {
|
||||
wstream->writePackedUInt(0);
|
||||
}
|
||||
} else {
|
||||
wstream->writePackedUInt(0);
|
||||
}
|
||||
}
|
||||
|
||||
SkTypeface* SkTypeface::Deserialize(SkStream* stream) {
|
||||
SkFontDescriptor desc(stream);
|
||||
size_t length = stream->readPackedUInt();
|
||||
if (length > 0) {
|
||||
void* addr = sk_malloc_flags(length, 0);
|
||||
if (addr) {
|
||||
SkAutoTUnref<SkStream> localStream(SkNEW_ARGS(SkMemoryStream,
|
||||
(addr, length, false)));
|
||||
return SkTypeface::CreateFromStream(localStream.get());
|
||||
}
|
||||
// failed to allocate, so just skip and create-from-name
|
||||
stream->skip(length);
|
||||
}
|
||||
|
||||
return SkTypeface::CreateFromName(desc.getFamilyName(), desc.getStyle());
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
int SkTypeface::countTables() const {
|
||||
return this->onGetTableTags(NULL);
|
||||
}
|
||||
|
||||
int SkTypeface::getTableTags(SkFontTableTag tags[]) const {
|
||||
return this->onGetTableTags(tags);
|
||||
}
|
||||
|
||||
size_t SkTypeface::getTableSize(SkFontTableTag tag) const {
|
||||
return this->onGetTableData(tag, 0, ~0U, NULL);
|
||||
}
|
||||
|
||||
size_t SkTypeface::getTableData(SkFontTableTag tag, size_t offset, size_t length,
|
||||
void* data) const {
|
||||
return this->onGetTableData(tag, offset, length, data);
|
||||
}
|
||||
|
||||
SkStream* SkTypeface::openStream(int* ttcIndex) const {
|
||||
int ttcIndexStorage;
|
||||
if (NULL == ttcIndex) {
|
||||
// So our subclasses don't need to check for null param
|
||||
ttcIndex = &ttcIndexStorage;
|
||||
}
|
||||
return this->onOpenStream(ttcIndex);
|
||||
}
|
||||
|
||||
int SkTypeface::getUnitsPerEm() const {
|
||||
// should we try to cache this in the base-class?
|
||||
return this->onGetUPEM();
|
||||
}
|
||||
|
||||
SkAdvancedTypefaceMetrics* SkTypeface::getAdvancedTypefaceMetrics(
|
||||
SkAdvancedTypefaceMetrics::PerGlyphInfo info,
|
||||
const uint32_t* glyphIDs,
|
||||
uint32_t glyphIDsCount) const {
|
||||
return this->onGetAdvancedTypefaceMetrics(info, glyphIDs, glyphIDsCount);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
int SkTypeface::onGetUPEM() const {
|
||||
int upem = 0;
|
||||
|
||||
SkAdvancedTypefaceMetrics* metrics;
|
||||
metrics = this->getAdvancedTypefaceMetrics(
|
||||
SkAdvancedTypefaceMetrics::kNo_PerGlyphInfo,
|
||||
NULL, 0);
|
||||
if (metrics) {
|
||||
upem = metrics->fEmSize;
|
||||
metrics->unref();
|
||||
}
|
||||
return upem;
|
||||
}
|
||||
|
||||
int SkTypeface::onGetTableTags(SkFontTableTag tags[]) const {
|
||||
int ttcIndex;
|
||||
SkAutoTUnref<SkStream> stream(this->openStream(&ttcIndex));
|
||||
return stream.get() ? SkFontStream::GetTableTags(stream, ttcIndex, tags) : 0;
|
||||
}
|
||||
|
||||
size_t SkTypeface::onGetTableData(SkFontTableTag tag, size_t offset,
|
||||
size_t length, void* data) const {
|
||||
int ttcIndex;
|
||||
SkAutoTUnref<SkStream> stream(this->openStream(&ttcIndex));
|
||||
return stream.get()
|
||||
? SkFontStream::GetTableData(stream, ttcIndex, tag, offset, length, data)
|
||||
: 0;
|
||||
}
|
|
@ -1,296 +0,0 @@
|
|||
/*
|
||||
* Copyright 2011 Google Inc.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include "SkWriter32.h"
|
||||
|
||||
SkWriter32::SkWriter32(size_t minSize, void* storage, size_t storageSize) {
|
||||
fMinSize = minSize;
|
||||
fSize = 0;
|
||||
fWrittenBeforeLastBlock = 0;
|
||||
fHead = fTail = NULL;
|
||||
|
||||
if (storageSize) {
|
||||
this->reset(storage, storageSize);
|
||||
}
|
||||
}
|
||||
|
||||
SkWriter32::~SkWriter32() {
|
||||
this->reset();
|
||||
}
|
||||
|
||||
void SkWriter32::reset() {
|
||||
Block* block = fHead;
|
||||
|
||||
if (this->isHeadExternallyAllocated()) {
|
||||
SkASSERT(block);
|
||||
// don't 'free' the first block, since it is owned by the caller
|
||||
block = block->fNext;
|
||||
}
|
||||
while (block) {
|
||||
Block* next = block->fNext;
|
||||
sk_free(block);
|
||||
block = next;
|
||||
}
|
||||
|
||||
fSize = 0;
|
||||
fWrittenBeforeLastBlock = 0;
|
||||
fHead = fTail = NULL;
|
||||
}
|
||||
|
||||
void SkWriter32::reset(void* storage, size_t storageSize) {
|
||||
this->reset();
|
||||
|
||||
storageSize &= ~3; // trunc down to multiple of 4
|
||||
if (storageSize > 0 && SkIsAlign4((intptr_t)storage)) {
|
||||
fHead = fTail = fExternalBlock.initFromStorage(storage, storageSize);
|
||||
}
|
||||
}
|
||||
|
||||
SkWriter32::Block* SkWriter32::doReserve(size_t size) {
|
||||
SkASSERT(SkAlign4(size) == size);
|
||||
|
||||
Block* block = fTail;
|
||||
SkASSERT(NULL == block || block->available() < size);
|
||||
|
||||
if (NULL == block) {
|
||||
SkASSERT(NULL == fHead);
|
||||
fHead = fTail = block = Block::Create(SkMax32(size, fMinSize));
|
||||
SkASSERT(0 == fWrittenBeforeLastBlock);
|
||||
} else {
|
||||
SkASSERT(fSize > 0);
|
||||
fWrittenBeforeLastBlock = fSize;
|
||||
|
||||
fTail = Block::Create(SkMax32(size, fMinSize));
|
||||
block->fNext = fTail;
|
||||
block = fTail;
|
||||
}
|
||||
return block;
|
||||
}
|
||||
|
||||
uint32_t* SkWriter32::peek32(size_t offset) {
|
||||
SkDEBUGCODE(this->validate();)
|
||||
|
||||
SkASSERT(SkAlign4(offset) == offset);
|
||||
SkASSERT(offset <= fSize);
|
||||
|
||||
// try the fast case, where offset is within fTail
|
||||
if (offset >= fWrittenBeforeLastBlock) {
|
||||
return fTail->peek32(offset - fWrittenBeforeLastBlock);
|
||||
}
|
||||
|
||||
Block* block = fHead;
|
||||
SkASSERT(NULL != block);
|
||||
|
||||
while (offset >= block->fAllocatedSoFar) {
|
||||
offset -= block->fAllocatedSoFar;
|
||||
block = block->fNext;
|
||||
SkASSERT(NULL != block);
|
||||
}
|
||||
return block->peek32(offset);
|
||||
}
|
||||
|
||||
void SkWriter32::rewindToOffset(size_t offset) {
|
||||
if (offset >= fSize) {
|
||||
return;
|
||||
}
|
||||
if (0 == offset) {
|
||||
this->reset();
|
||||
return;
|
||||
}
|
||||
|
||||
SkDEBUGCODE(this->validate();)
|
||||
|
||||
SkASSERT(SkAlign4(offset) == offset);
|
||||
SkASSERT(offset <= fSize);
|
||||
fSize = offset;
|
||||
|
||||
// Try the fast case, where offset is within fTail
|
||||
if (offset >= fWrittenBeforeLastBlock) {
|
||||
fTail->fAllocatedSoFar = offset - fWrittenBeforeLastBlock;
|
||||
} else {
|
||||
// Similar to peek32, except that we free up any following blocks.
|
||||
// We have to re-compute fWrittenBeforeLastBlock as well.
|
||||
|
||||
size_t globalOffset = offset;
|
||||
Block* block = fHead;
|
||||
SkASSERT(NULL != block);
|
||||
while (offset >= block->fAllocatedSoFar) {
|
||||
offset -= block->fAllocatedSoFar;
|
||||
block = block->fNext;
|
||||
SkASSERT(NULL != block);
|
||||
}
|
||||
|
||||
// this has to be recomputed, since we may free up fTail
|
||||
fWrittenBeforeLastBlock = globalOffset - offset;
|
||||
|
||||
// update the size on the "last" block
|
||||
block->fAllocatedSoFar = offset;
|
||||
// end our list
|
||||
fTail = block;
|
||||
Block* next = block->fNext;
|
||||
block->fNext = NULL;
|
||||
// free up any trailing blocks
|
||||
block = next;
|
||||
while (block) {
|
||||
Block* next = block->fNext;
|
||||
sk_free(block);
|
||||
block = next;
|
||||
}
|
||||
}
|
||||
SkDEBUGCODE(this->validate();)
|
||||
}
|
||||
|
||||
void SkWriter32::flatten(void* dst) const {
|
||||
const Block* block = fHead;
|
||||
SkDEBUGCODE(size_t total = 0;)
|
||||
|
||||
while (block) {
|
||||
size_t allocated = block->fAllocatedSoFar;
|
||||
memcpy(dst, block->base(), allocated);
|
||||
dst = (char*)dst + allocated;
|
||||
block = block->fNext;
|
||||
|
||||
SkDEBUGCODE(total += allocated;)
|
||||
SkASSERT(total <= fSize);
|
||||
}
|
||||
SkASSERT(total == fSize);
|
||||
}
|
||||
|
||||
uint32_t* SkWriter32::reservePad(size_t size) {
|
||||
if (size > 0) {
|
||||
size_t alignedSize = SkAlign4(size);
|
||||
char* dst = (char*)this->reserve(alignedSize);
|
||||
// Pad the last four bytes with zeroes in one step.
|
||||
uint32_t* padding = (uint32_t*)(dst + (alignedSize - 4));
|
||||
*padding = 0;
|
||||
return (uint32_t*) dst;
|
||||
}
|
||||
return this->reserve(0);
|
||||
}
|
||||
|
||||
void SkWriter32::writePad(const void* src, size_t size) {
|
||||
if (size > 0) {
|
||||
char* dst = (char*)this->reservePad(size);
|
||||
// Copy the actual data.
|
||||
memcpy(dst, src, size);
|
||||
}
|
||||
}
|
||||
|
||||
#include "SkStream.h"
|
||||
|
||||
size_t SkWriter32::readFromStream(SkStream* stream, size_t length) {
|
||||
char scratch[1024];
|
||||
const size_t MAX = sizeof(scratch);
|
||||
size_t remaining = length;
|
||||
|
||||
while (remaining != 0) {
|
||||
size_t n = remaining;
|
||||
if (n > MAX) {
|
||||
n = MAX;
|
||||
}
|
||||
size_t bytes = stream->read(scratch, n);
|
||||
this->writePad(scratch, bytes);
|
||||
remaining -= bytes;
|
||||
if (bytes != n) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return length - remaining;
|
||||
}
|
||||
|
||||
bool SkWriter32::writeToStream(SkWStream* stream) {
|
||||
const Block* block = fHead;
|
||||
while (block) {
|
||||
if (!stream->write(block->base(), block->fAllocatedSoFar)) {
|
||||
return false;
|
||||
}
|
||||
block = block->fNext;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifdef SK_DEBUG
|
||||
void SkWriter32::validate() const {
|
||||
SkASSERT(SkIsAlign4(fSize));
|
||||
|
||||
size_t accum = 0;
|
||||
const Block* block = fHead;
|
||||
while (block) {
|
||||
SkASSERT(SkIsAlign4(block->fSizeOfBlock));
|
||||
SkASSERT(SkIsAlign4(block->fAllocatedSoFar));
|
||||
SkASSERT(block->fAllocatedSoFar <= block->fSizeOfBlock);
|
||||
if (NULL == block->fNext) {
|
||||
SkASSERT(fTail == block);
|
||||
SkASSERT(fWrittenBeforeLastBlock == accum);
|
||||
}
|
||||
accum += block->fAllocatedSoFar;
|
||||
SkASSERT(accum <= fSize);
|
||||
block = block->fNext;
|
||||
}
|
||||
SkASSERT(accum == fSize);
|
||||
}
|
||||
#endif
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "SkReader32.h"
|
||||
#include "SkString.h"
|
||||
|
||||
/*
|
||||
* Strings are stored as: length[4-bytes] + string_data + '\0' + pad_to_mul_4
|
||||
*/
|
||||
|
||||
const char* SkReader32::readString(size_t* outLen) {
|
||||
size_t len = this->readInt();
|
||||
const void* ptr = this->peek();
|
||||
|
||||
// skip over teh string + '\0' and then pad to a multiple of 4
|
||||
size_t alignedSize = SkAlign4(len + 1);
|
||||
this->skip(alignedSize);
|
||||
|
||||
if (outLen) {
|
||||
*outLen = len;
|
||||
}
|
||||
return (const char*)ptr;
|
||||
}
|
||||
|
||||
size_t SkReader32::readIntoString(SkString* copy) {
|
||||
size_t len;
|
||||
const char* ptr = this->readString(&len);
|
||||
if (copy) {
|
||||
copy->set(ptr, len);
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
void SkWriter32::writeString(const char str[], size_t len) {
|
||||
if ((long)len < 0) {
|
||||
SkASSERT(str);
|
||||
len = strlen(str);
|
||||
}
|
||||
this->write32(len);
|
||||
// add 1 since we also write a terminating 0
|
||||
size_t alignedLen = SkAlign4(len + 1);
|
||||
char* ptr = (char*)this->reserve(alignedLen);
|
||||
{
|
||||
// Write the terminating 0 and fill in the rest with zeroes
|
||||
uint32_t* padding = (uint32_t*)(ptr + (alignedLen - 4));
|
||||
*padding = 0;
|
||||
}
|
||||
// Copy the string itself.
|
||||
memcpy(ptr, str, len);
|
||||
}
|
||||
|
||||
size_t SkWriter32::WriteStringSize(const char* str, size_t len) {
|
||||
if ((long)len < 0) {
|
||||
SkASSERT(str);
|
||||
len = strlen(str);
|
||||
}
|
||||
const size_t lenBytes = 4; // we use 4 bytes to record the length
|
||||
// add 1 since we also write a terminating 0
|
||||
return SkAlign4(lenBytes + len + 1);
|
||||
}
|
|
@ -1,193 +0,0 @@
|
|||
/*
|
||||
* Copyright 2013 Google Inc.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include "SkArithmeticMode.h"
|
||||
#include "SkColorPriv.h"
|
||||
#include "SkString.h"
|
||||
#include "SkUnPreMultiply.h"
|
||||
|
||||
class SkArithmeticMode_scalar : public SkXfermode {
|
||||
public:
|
||||
SkArithmeticMode_scalar(SkScalar k1, SkScalar k2, SkScalar k3, SkScalar k4) {
|
||||
fK[0] = k1;
|
||||
fK[1] = k2;
|
||||
fK[2] = k3;
|
||||
fK[3] = k4;
|
||||
}
|
||||
|
||||
virtual void xfer32(SkPMColor dst[], const SkPMColor src[], int count,
|
||||
const SkAlpha aa[]) const SK_OVERRIDE;
|
||||
|
||||
SK_DEVELOPER_TO_STRING()
|
||||
SK_DECLARE_UNFLATTENABLE_OBJECT()
|
||||
|
||||
private:
|
||||
SkScalar fK[4];
|
||||
|
||||
typedef SkXfermode INHERITED;
|
||||
};
|
||||
|
||||
static int pinToByte(int value) {
|
||||
if (value < 0) {
|
||||
value = 0;
|
||||
} else if (value > 255) {
|
||||
value = 255;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
static int arith(SkScalar k1, SkScalar k2, SkScalar k3, SkScalar k4,
|
||||
int src, int dst) {
|
||||
SkScalar result = SkScalarMul(k1, src * dst) +
|
||||
SkScalarMul(k2, src) +
|
||||
SkScalarMul(k3, dst) +
|
||||
k4;
|
||||
int res = SkScalarRoundToInt(result);
|
||||
return pinToByte(res);
|
||||
}
|
||||
|
||||
static int blend(int src, int dst, int scale) {
|
||||
return dst + ((src - dst) * scale >> 8);
|
||||
}
|
||||
|
||||
static bool needsUnpremul(int alpha) {
|
||||
return 0 != alpha && 0xFF != alpha;
|
||||
}
|
||||
|
||||
void SkArithmeticMode_scalar::xfer32(SkPMColor dst[], const SkPMColor src[],
|
||||
int count, const SkAlpha aaCoverage[]) const {
|
||||
SkScalar k1 = fK[0] / 255;
|
||||
SkScalar k2 = fK[1];
|
||||
SkScalar k3 = fK[2];
|
||||
SkScalar k4 = fK[3] * 255;
|
||||
|
||||
for (int i = 0; i < count; ++i) {
|
||||
if ((NULL == aaCoverage) || aaCoverage[i]) {
|
||||
SkPMColor sc = src[i];
|
||||
SkPMColor dc = dst[i];
|
||||
int sa = SkGetPackedA32(sc);
|
||||
int da = SkGetPackedA32(dc);
|
||||
|
||||
int srcNeedsUnpremul = needsUnpremul(sa);
|
||||
int dstNeedsUnpremul = needsUnpremul(sa);
|
||||
|
||||
int a, r, g, b;
|
||||
|
||||
if (!srcNeedsUnpremul && !dstNeedsUnpremul) {
|
||||
a = arith(k1, k2, k3, k4, sa, sa);
|
||||
r = arith(k1, k2, k3, k4, SkGetPackedR32(sc), SkGetPackedR32(dc));
|
||||
g = arith(k1, k2, k3, k4, SkGetPackedG32(sc), SkGetPackedG32(dc));
|
||||
b = arith(k1, k2, k3, k4, SkGetPackedB32(sc), SkGetPackedB32(dc));
|
||||
} else {
|
||||
int sr = SkGetPackedR32(sc);
|
||||
int sg = SkGetPackedG32(sc);
|
||||
int sb = SkGetPackedB32(sc);
|
||||
if (srcNeedsUnpremul) {
|
||||
SkUnPreMultiply::Scale scale = SkUnPreMultiply::GetScale(sa);
|
||||
sr = SkUnPreMultiply::ApplyScale(scale, sr);
|
||||
sg = SkUnPreMultiply::ApplyScale(scale, sg);
|
||||
sb = SkUnPreMultiply::ApplyScale(scale, sb);
|
||||
}
|
||||
|
||||
int dr = SkGetPackedR32(dc);
|
||||
int dg = SkGetPackedG32(dc);
|
||||
int db = SkGetPackedB32(dc);
|
||||
if (dstNeedsUnpremul) {
|
||||
SkUnPreMultiply::Scale scale = SkUnPreMultiply::GetScale(da);
|
||||
dr = SkUnPreMultiply::ApplyScale(scale, dr);
|
||||
dg = SkUnPreMultiply::ApplyScale(scale, dg);
|
||||
db = SkUnPreMultiply::ApplyScale(scale, db);
|
||||
}
|
||||
|
||||
a = arith(k1, k2, k3, k4, sa, sa);
|
||||
r = arith(k1, k2, k3, k4, sr, dr);
|
||||
g = arith(k1, k2, k3, k4, sg, dg);
|
||||
b = arith(k1, k2, k3, k4, sb, db);
|
||||
}
|
||||
|
||||
// apply antialias coverage if necessary
|
||||
if (aaCoverage && 0xFF != aaCoverage[i]) {
|
||||
int scale = aaCoverage[i] + (aaCoverage[i] >> 7);
|
||||
a = blend(a, SkGetPackedA32(sc), scale);
|
||||
r = blend(r, SkGetPackedR32(sc), scale);
|
||||
g = blend(g, SkGetPackedG32(sc), scale);
|
||||
b = blend(b, SkGetPackedB32(sc), scale);
|
||||
}
|
||||
|
||||
// turn the result back into premul
|
||||
if (0xFF != a) {
|
||||
int scale = a + (a >> 7);
|
||||
r = SkAlphaMul(r, scale);
|
||||
g = SkAlphaMul(g, scale);
|
||||
b = SkAlphaMul(b, scale);
|
||||
}
|
||||
dst[i] = SkPackARGB32(a, r, g, b);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef SK_DEVELOPER
|
||||
void SkArithmeticMode_scalar::toString(SkString* str) const {
|
||||
str->append("SkArithmeticMode_scalar: ");
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
str->appendScalar(fK[i]);
|
||||
if (i < 3) {
|
||||
str->append(" ");
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static bool fitsInBits(SkScalar x, int bits) {
|
||||
#ifdef SK_SCALAR_IS_FIXED
|
||||
x = SkAbs32(x);
|
||||
x += 1 << 7;
|
||||
x >>= 8;
|
||||
return x < (1 << (bits - 1));
|
||||
#else
|
||||
return SkScalarAbs(x) < (1 << (bits - 1));
|
||||
#endif
|
||||
}
|
||||
|
||||
#if 0 // UNUSED
|
||||
static int32_t toDot8(SkScalar x) {
|
||||
#ifdef SK_SCALAR_IS_FIXED
|
||||
x += 1 << 7;
|
||||
x >>= 8;
|
||||
return x;
|
||||
#else
|
||||
return (int32_t)(x * 256);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
SkXfermode* SkArithmeticMode::Create(SkScalar k1, SkScalar k2,
|
||||
SkScalar k3, SkScalar k4) {
|
||||
if (fitsInBits(k1, 8) && fitsInBits(k2, 16) &&
|
||||
fitsInBits(k2, 16) && fitsInBits(k2, 24)) {
|
||||
|
||||
#if 0 // UNUSED
|
||||
int32_t i1 = toDot8(k1);
|
||||
int32_t i2 = toDot8(k2);
|
||||
int32_t i3 = toDot8(k3);
|
||||
int32_t i4 = toDot8(k4);
|
||||
if (i1) {
|
||||
return SkNEW_ARGS(SkArithmeticMode_quad, (i1, i2, i3, i4));
|
||||
}
|
||||
if (0 == i2) {
|
||||
return SkNEW_ARGS(SkArithmeticMode_dst, (i3, i4));
|
||||
}
|
||||
if (0 == i3) {
|
||||
return SkNEW_ARGS(SkArithmeticMode_src, (i2, i4));
|
||||
}
|
||||
return SkNEW_ARGS(SkArithmeticMode_linear, (i2, i3, i4));
|
||||
#endif
|
||||
}
|
||||
return SkNEW_ARGS(SkArithmeticMode_scalar, (k1, k2, k3, k4));
|
||||
}
|
|
@ -1,372 +0,0 @@
|
|||
/*
|
||||
* Copyright 2013 The Android Open Source Project
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include "SkBicubicImageFilter.h"
|
||||
#include "SkBitmap.h"
|
||||
#include "SkColorPriv.h"
|
||||
#include "SkFlattenableBuffers.h"
|
||||
#include "SkMatrix.h"
|
||||
#include "SkRect.h"
|
||||
#include "SkUnPreMultiply.h"
|
||||
|
||||
#if SK_SUPPORT_GPU
|
||||
#include "gl/GrGLEffectMatrix.h"
|
||||
#include "effects/GrSingleTextureEffect.h"
|
||||
#include "GrTBackendEffectFactory.h"
|
||||
#include "GrContext.h"
|
||||
#include "GrTexture.h"
|
||||
#include "SkImageFilterUtils.h"
|
||||
#endif
|
||||
|
||||
SkBicubicImageFilter::SkBicubicImageFilter(const SkSize& scale, const SkScalar coefficients[16], SkImageFilter* input)
|
||||
: INHERITED(input),
|
||||
fScale(scale) {
|
||||
memcpy(fCoefficients, coefficients, sizeof(fCoefficients));
|
||||
}
|
||||
|
||||
#define DS(x) SkDoubleToScalar(x)
|
||||
|
||||
SkBicubicImageFilter* SkBicubicImageFilter::CreateMitchell(const SkSize& scale,
|
||||
SkImageFilter* input) {
|
||||
static const SkScalar coefficients[16] = {
|
||||
DS( 1.0 / 18.0), DS(-9.0 / 18.0), DS( 15.0 / 18.0), DS( -7.0 / 18.0),
|
||||
DS(16.0 / 18.0), DS( 0.0 / 18.0), DS(-36.0 / 18.0), DS( 21.0 / 18.0),
|
||||
DS( 1.0 / 18.0), DS( 9.0 / 18.0), DS( 27.0 / 18.0), DS(-21.0 / 18.0),
|
||||
DS( 0.0 / 18.0), DS( 0.0 / 18.0), DS( -6.0 / 18.0), DS( 7.0 / 18.0),
|
||||
};
|
||||
return SkNEW_ARGS(SkBicubicImageFilter, (scale, coefficients, input));
|
||||
}
|
||||
|
||||
SkBicubicImageFilter::SkBicubicImageFilter(SkFlattenableReadBuffer& buffer) : INHERITED(buffer) {
|
||||
SkDEBUGCODE(uint32_t readSize =) buffer.readScalarArray(fCoefficients);
|
||||
SkASSERT(readSize == 16);
|
||||
fScale.fWidth = buffer.readScalar();
|
||||
fScale.fHeight = buffer.readScalar();
|
||||
}
|
||||
|
||||
void SkBicubicImageFilter::flatten(SkFlattenableWriteBuffer& buffer) const {
|
||||
this->INHERITED::flatten(buffer);
|
||||
buffer.writeScalarArray(fCoefficients, 16);
|
||||
buffer.writeScalar(fScale.fWidth);
|
||||
buffer.writeScalar(fScale.fHeight);
|
||||
}
|
||||
|
||||
SkBicubicImageFilter::~SkBicubicImageFilter() {
|
||||
}
|
||||
|
||||
inline SkPMColor cubicBlend(const SkScalar c[16], SkScalar t, SkPMColor c0, SkPMColor c1, SkPMColor c2, SkPMColor c3) {
|
||||
SkScalar t2 = t * t, t3 = t2 * t;
|
||||
SkScalar cc[4];
|
||||
// FIXME: For the fractx case, this should be refactored out of this function.
|
||||
cc[0] = c[0] + SkScalarMul(c[1], t) + SkScalarMul(c[2], t2) + SkScalarMul(c[3], t3);
|
||||
cc[1] = c[4] + SkScalarMul(c[5], t) + SkScalarMul(c[6], t2) + SkScalarMul(c[7], t3);
|
||||
cc[2] = c[8] + SkScalarMul(c[9], t) + SkScalarMul(c[10], t2) + SkScalarMul(c[11], t3);
|
||||
cc[3] = c[12] + SkScalarMul(c[13], t) + SkScalarMul(c[14], t2) + SkScalarMul(c[15], t3);
|
||||
SkScalar a = SkScalarClampMax(SkScalarMul(cc[0], SkGetPackedA32(c0)) + SkScalarMul(cc[1], SkGetPackedA32(c1)) + SkScalarMul(cc[2], SkGetPackedA32(c2)) + SkScalarMul(cc[3], SkGetPackedA32(c3)), 255);
|
||||
SkScalar r = SkScalarMul(cc[0], SkGetPackedR32(c0)) + SkScalarMul(cc[1], SkGetPackedR32(c1)) + SkScalarMul(cc[2], SkGetPackedR32(c2)) + SkScalarMul(cc[3], SkGetPackedR32(c3));
|
||||
SkScalar g = SkScalarMul(cc[0], SkGetPackedG32(c0)) + SkScalarMul(cc[1], SkGetPackedG32(c1)) + SkScalarMul(cc[2], SkGetPackedG32(c2)) + SkScalarMul(cc[3], SkGetPackedG32(c3));
|
||||
SkScalar b = SkScalarMul(cc[0], SkGetPackedB32(c0)) + SkScalarMul(cc[1], SkGetPackedB32(c1)) + SkScalarMul(cc[2], SkGetPackedB32(c2)) + SkScalarMul(cc[3], SkGetPackedB32(c3));
|
||||
return SkPackARGB32(SkScalarRoundToInt(a),
|
||||
SkScalarRoundToInt(SkScalarClampMax(r, a)),
|
||||
SkScalarRoundToInt(SkScalarClampMax(g, a)),
|
||||
SkScalarRoundToInt(SkScalarClampMax(b, a)));
|
||||
}
|
||||
|
||||
bool SkBicubicImageFilter::onFilterImage(Proxy* proxy,
|
||||
const SkBitmap& source,
|
||||
const SkMatrix& matrix,
|
||||
SkBitmap* result,
|
||||
SkIPoint* loc) {
|
||||
SkBitmap src = this->getInputResult(0, proxy, source, matrix, loc);
|
||||
if (src.config() != SkBitmap::kARGB_8888_Config) {
|
||||
return false;
|
||||
}
|
||||
|
||||
SkAutoLockPixels alp(src);
|
||||
if (!src.getPixels()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
SkRect dstRect = SkRect::MakeWH(SkScalarMul(SkIntToScalar(src.width()), fScale.fWidth),
|
||||
SkScalarMul(SkIntToScalar(src.height()), fScale.fHeight));
|
||||
SkIRect dstIRect;
|
||||
dstRect.roundOut(&dstIRect);
|
||||
result->setConfig(src.config(), dstIRect.width(), dstIRect.height());
|
||||
result->allocPixels();
|
||||
if (!result->getPixels()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
SkRect srcRect;
|
||||
src.getBounds(&srcRect);
|
||||
SkMatrix inverse;
|
||||
inverse.setRectToRect(dstRect, srcRect, SkMatrix::kFill_ScaleToFit);
|
||||
inverse.postTranslate(SkFloatToScalar(-0.5f), SkFloatToScalar(-0.5f));
|
||||
|
||||
for (int y = dstIRect.fTop; y < dstIRect.fBottom; ++y) {
|
||||
SkPMColor* dptr = result->getAddr32(dstIRect.fLeft, y);
|
||||
for (int x = dstIRect.fLeft; x < dstIRect.fRight; ++x) {
|
||||
SkPoint srcPt, dstPt = SkPoint::Make(SkIntToScalar(x), SkIntToScalar(y));
|
||||
inverse.mapPoints(&srcPt, &dstPt, 1);
|
||||
SkScalar fractx = srcPt.fX - SkScalarFloorToScalar(srcPt.fX);
|
||||
SkScalar fracty = srcPt.fY - SkScalarFloorToScalar(srcPt.fY);
|
||||
int sx = SkScalarFloorToInt(srcPt.fX);
|
||||
int sy = SkScalarFloorToInt(srcPt.fY);
|
||||
int x0 = SkClampMax(sx - 1, src.width() - 1);
|
||||
int x1 = SkClampMax(sx , src.width() - 1);
|
||||
int x2 = SkClampMax(sx + 1, src.width() - 1);
|
||||
int x3 = SkClampMax(sx + 2, src.width() - 1);
|
||||
int y0 = SkClampMax(sy - 1, src.height() - 1);
|
||||
int y1 = SkClampMax(sy , src.height() - 1);
|
||||
int y2 = SkClampMax(sy + 1, src.height() - 1);
|
||||
int y3 = SkClampMax(sy + 2, src.height() - 1);
|
||||
SkPMColor s00 = *src.getAddr32(x0, y0);
|
||||
SkPMColor s10 = *src.getAddr32(x1, y0);
|
||||
SkPMColor s20 = *src.getAddr32(x2, y0);
|
||||
SkPMColor s30 = *src.getAddr32(x3, y0);
|
||||
SkPMColor s0 = cubicBlend(fCoefficients, fractx, s00, s10, s20, s30);
|
||||
SkPMColor s01 = *src.getAddr32(x0, y1);
|
||||
SkPMColor s11 = *src.getAddr32(x1, y1);
|
||||
SkPMColor s21 = *src.getAddr32(x2, y1);
|
||||
SkPMColor s31 = *src.getAddr32(x3, y1);
|
||||
SkPMColor s1 = cubicBlend(fCoefficients, fractx, s01, s11, s21, s31);
|
||||
SkPMColor s02 = *src.getAddr32(x0, y2);
|
||||
SkPMColor s12 = *src.getAddr32(x1, y2);
|
||||
SkPMColor s22 = *src.getAddr32(x2, y2);
|
||||
SkPMColor s32 = *src.getAddr32(x3, y2);
|
||||
SkPMColor s2 = cubicBlend(fCoefficients, fractx, s02, s12, s22, s32);
|
||||
SkPMColor s03 = *src.getAddr32(x0, y3);
|
||||
SkPMColor s13 = *src.getAddr32(x1, y3);
|
||||
SkPMColor s23 = *src.getAddr32(x2, y3);
|
||||
SkPMColor s33 = *src.getAddr32(x3, y3);
|
||||
SkPMColor s3 = cubicBlend(fCoefficients, fractx, s03, s13, s23, s33);
|
||||
*dptr++ = cubicBlend(fCoefficients, fracty, s0, s1, s2, s3);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#if SK_SUPPORT_GPU
|
||||
class GrGLBicubicEffect;
|
||||
|
||||
class GrBicubicEffect : public GrSingleTextureEffect {
|
||||
public:
|
||||
virtual ~GrBicubicEffect();
|
||||
|
||||
static const char* Name() { return "Bicubic"; }
|
||||
const float* coefficients() const { return fCoefficients; }
|
||||
|
||||
typedef GrGLBicubicEffect GLEffect;
|
||||
|
||||
virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE;
|
||||
virtual void getConstantColorComponents(GrColor* color, uint32_t* validFlags) const SK_OVERRIDE;
|
||||
|
||||
static GrEffectRef* Create(GrTexture* tex, const SkScalar coefficients[16]) {
|
||||
AutoEffectUnref effect(SkNEW_ARGS(GrBicubicEffect, (tex, coefficients)));
|
||||
return CreateEffectRef(effect);
|
||||
}
|
||||
|
||||
private:
|
||||
GrBicubicEffect(GrTexture*, const SkScalar coefficients[16]);
|
||||
virtual bool onIsEqual(const GrEffect&) const SK_OVERRIDE;
|
||||
float fCoefficients[16];
|
||||
|
||||
GR_DECLARE_EFFECT_TEST;
|
||||
|
||||
typedef GrSingleTextureEffect INHERITED;
|
||||
};
|
||||
|
||||
class GrGLBicubicEffect : public GrGLEffect {
|
||||
public:
|
||||
GrGLBicubicEffect(const GrBackendEffectFactory& factory,
|
||||
const GrDrawEffect&);
|
||||
virtual void emitCode(GrGLShaderBuilder*,
|
||||
const GrDrawEffect&,
|
||||
EffectKey,
|
||||
const char* outputColor,
|
||||
const char* inputColor,
|
||||
const TextureSamplerArray&) SK_OVERRIDE;
|
||||
|
||||
static inline EffectKey GenKey(const GrDrawEffect&, const GrGLCaps&);
|
||||
|
||||
virtual void setData(const GrGLUniformManager&, const GrDrawEffect&) SK_OVERRIDE;
|
||||
|
||||
private:
|
||||
typedef GrGLUniformManager::UniformHandle UniformHandle;
|
||||
|
||||
UniformHandle fCoefficientsUni;
|
||||
UniformHandle fImageIncrementUni;
|
||||
|
||||
GrGLEffectMatrix fEffectMatrix;
|
||||
|
||||
typedef GrGLEffect INHERITED;
|
||||
};
|
||||
|
||||
GrGLBicubicEffect::GrGLBicubicEffect(const GrBackendEffectFactory& factory,
|
||||
const GrDrawEffect& drawEffect)
|
||||
: INHERITED(factory)
|
||||
, fCoefficientsUni(GrGLUniformManager::kInvalidUniformHandle)
|
||||
, fImageIncrementUni(GrGLUniformManager::kInvalidUniformHandle)
|
||||
, fEffectMatrix(drawEffect.castEffect<GrBicubicEffect>().coordsType()) {
|
||||
}
|
||||
|
||||
void GrGLBicubicEffect::emitCode(GrGLShaderBuilder* builder,
|
||||
const GrDrawEffect&,
|
||||
EffectKey key,
|
||||
const char* outputColor,
|
||||
const char* inputColor,
|
||||
const TextureSamplerArray& samplers) {
|
||||
const char* coords;
|
||||
fEffectMatrix.emitCodeMakeFSCoords2D(builder, key, &coords);
|
||||
fCoefficientsUni = builder->addUniform(GrGLShaderBuilder::kFragment_ShaderType,
|
||||
kMat44f_GrSLType, "Coefficients");
|
||||
fImageIncrementUni = builder->addUniform(GrGLShaderBuilder::kFragment_ShaderType,
|
||||
kVec2f_GrSLType, "ImageIncrement");
|
||||
|
||||
const char* imgInc = builder->getUniformCStr(fImageIncrementUni);
|
||||
const char* coeff = builder->getUniformCStr(fCoefficientsUni);
|
||||
|
||||
SkString cubicBlendName;
|
||||
|
||||
static const GrGLShaderVar gCubicBlendArgs[] = {
|
||||
GrGLShaderVar("coefficients", kMat44f_GrSLType),
|
||||
GrGLShaderVar("t", kFloat_GrSLType),
|
||||
GrGLShaderVar("c0", kVec4f_GrSLType),
|
||||
GrGLShaderVar("c1", kVec4f_GrSLType),
|
||||
GrGLShaderVar("c2", kVec4f_GrSLType),
|
||||
GrGLShaderVar("c3", kVec4f_GrSLType),
|
||||
};
|
||||
builder->emitFunction(GrGLShaderBuilder::kFragment_ShaderType,
|
||||
kVec4f_GrSLType,
|
||||
"cubicBlend",
|
||||
SK_ARRAY_COUNT(gCubicBlendArgs),
|
||||
gCubicBlendArgs,
|
||||
"\tvec4 ts = vec4(1.0, t, t * t, t * t * t);\n"
|
||||
"\tvec4 c = coefficients * ts;\n"
|
||||
"\treturn c.x * c0 + c.y * c1 + c.z * c2 + c.w * c3;\n",
|
||||
&cubicBlendName);
|
||||
builder->fsCodeAppendf("\tvec2 coord = %s - %s * vec2(0.5, 0.5);\n", coords, imgInc);
|
||||
builder->fsCodeAppendf("\tvec2 f = fract(coord / %s);\n", imgInc);
|
||||
for (int y = 0; y < 4; ++y) {
|
||||
for (int x = 0; x < 4; ++x) {
|
||||
SkString coord;
|
||||
coord.printf("coord + %s * vec2(%d, %d)", imgInc, x - 1, y - 1);
|
||||
builder->fsCodeAppendf("\tvec4 s%d%d = ", x, y);
|
||||
builder->appendTextureLookup(GrGLShaderBuilder::kFragment_ShaderType,
|
||||
samplers[0],
|
||||
coord.c_str());
|
||||
builder->fsCodeAppend(";\n");
|
||||
}
|
||||
builder->fsCodeAppendf("\tvec4 s%d = %s(%s, f.x, s0%d, s1%d, s2%d, s3%d);\n", y, cubicBlendName.c_str(), coeff, y, y, y, y);
|
||||
}
|
||||
builder->fsCodeAppendf("\t%s = %s(%s, f.y, s0, s1, s2, s3);\n", outputColor, cubicBlendName.c_str(), coeff);
|
||||
}
|
||||
|
||||
GrGLEffect::EffectKey GrGLBicubicEffect::GenKey(const GrDrawEffect& drawEffect, const GrGLCaps&) {
|
||||
const GrBicubicEffect& bicubic = drawEffect.castEffect<GrBicubicEffect>();
|
||||
EffectKey matrixKey = GrGLEffectMatrix::GenKey(bicubic.getMatrix(),
|
||||
drawEffect,
|
||||
bicubic.coordsType(),
|
||||
bicubic.texture(0));
|
||||
return matrixKey;
|
||||
}
|
||||
|
||||
void GrGLBicubicEffect::setData(const GrGLUniformManager& uman,
|
||||
const GrDrawEffect& drawEffect) {
|
||||
const GrBicubicEffect& effect = drawEffect.castEffect<GrBicubicEffect>();
|
||||
GrTexture& texture = *effect.texture(0);
|
||||
float imageIncrement[2];
|
||||
imageIncrement[0] = 1.0f / texture.width();
|
||||
imageIncrement[1] = 1.0f / texture.height();
|
||||
uman.set2fv(fImageIncrementUni, 0, 1, imageIncrement);
|
||||
uman.setMatrix4f(fCoefficientsUni, effect.coefficients());
|
||||
fEffectMatrix.setData(uman,
|
||||
effect.getMatrix(),
|
||||
drawEffect,
|
||||
effect.texture(0));
|
||||
}
|
||||
|
||||
GrBicubicEffect::GrBicubicEffect(GrTexture* texture,
|
||||
const SkScalar coefficients[16])
|
||||
: INHERITED(texture, MakeDivByTextureWHMatrix(texture)) {
|
||||
for (int y = 0; y < 4; y++) {
|
||||
for (int x = 0; x < 4; x++) {
|
||||
// Convert from row-major scalars to column-major floats.
|
||||
fCoefficients[x * 4 + y] = SkScalarToFloat(coefficients[y * 4 + x]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GrBicubicEffect::~GrBicubicEffect() {
|
||||
}
|
||||
|
||||
const GrBackendEffectFactory& GrBicubicEffect::getFactory() const {
|
||||
return GrTBackendEffectFactory<GrBicubicEffect>::getInstance();
|
||||
}
|
||||
|
||||
bool GrBicubicEffect::onIsEqual(const GrEffect& sBase) const {
|
||||
const GrBicubicEffect& s = CastEffect<GrBicubicEffect>(sBase);
|
||||
return this->texture(0) == s.texture(0) &&
|
||||
!memcmp(fCoefficients, s.coefficients(), 16);
|
||||
}
|
||||
|
||||
void GrBicubicEffect::getConstantColorComponents(GrColor* color, uint32_t* validFlags) const {
|
||||
// FIXME: Perhaps we can do better.
|
||||
*validFlags = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
GR_DEFINE_EFFECT_TEST(GrBicubicEffect);
|
||||
|
||||
GrEffectRef* GrBicubicEffect::TestCreate(SkMWCRandom* random,
|
||||
GrContext* context,
|
||||
const GrDrawTargetCaps&,
|
||||
GrTexture* textures[]) {
|
||||
int texIdx = random->nextBool() ? GrEffectUnitTest::kSkiaPMTextureIdx :
|
||||
GrEffectUnitTest::kAlphaTextureIdx;
|
||||
SkScalar coefficients[16];
|
||||
for (int i = 0; i < 16; i++) {
|
||||
coefficients[i] = random->nextSScalar1();
|
||||
}
|
||||
return GrBicubicEffect::Create(textures[texIdx], coefficients);
|
||||
}
|
||||
|
||||
bool SkBicubicImageFilter::filterImageGPU(Proxy* proxy, const SkBitmap& src, SkBitmap* result) {
|
||||
SkBitmap srcBM;
|
||||
if (!SkImageFilterUtils::GetInputResultGPU(getInput(0), proxy, src, &srcBM)) {
|
||||
return false;
|
||||
}
|
||||
GrTexture* srcTexture = (GrTexture*) srcBM.getTexture();
|
||||
GrContext* context = srcTexture->getContext();
|
||||
|
||||
SkRect dstRect = SkRect::MakeWH(srcBM.width() * fScale.fWidth,
|
||||
srcBM.height() * fScale.fHeight);
|
||||
|
||||
GrTextureDesc desc;
|
||||
desc.fFlags = kRenderTarget_GrTextureFlagBit | kNoStencil_GrTextureFlagBit;
|
||||
desc.fWidth = SkScalarCeilToInt(dstRect.width());
|
||||
desc.fHeight = SkScalarCeilToInt(dstRect.height());
|
||||
desc.fConfig = kSkia8888_GrPixelConfig;
|
||||
|
||||
GrAutoScratchTexture ast(context, desc);
|
||||
SkAutoTUnref<GrTexture> dst(ast.detach());
|
||||
if (!dst) {
|
||||
return false;
|
||||
}
|
||||
GrContext::AutoRenderTarget art(context, dst->asRenderTarget());
|
||||
GrPaint paint;
|
||||
paint.colorStage(0)->setEffect(GrBicubicEffect::Create(srcTexture, fCoefficients))->unref();
|
||||
SkRect srcRect;
|
||||
srcBM.getBounds(&srcRect);
|
||||
context->drawRectToRect(paint, dstRect, srcRect);
|
||||
return SkImageFilterUtils::WrapTexture(dst, desc.fWidth, desc.fHeight, result);
|
||||
}
|
||||
#endif
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
|
@ -1,29 +0,0 @@
|
|||
/*
|
||||
* Copyright 2012 The Android Open Source Project
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include "SkBitmapSource.h"
|
||||
|
||||
SkBitmapSource::SkBitmapSource(const SkBitmap& bitmap)
|
||||
: INHERITED(0),
|
||||
fBitmap(bitmap) {
|
||||
}
|
||||
|
||||
SkBitmapSource::SkBitmapSource(SkFlattenableReadBuffer& buffer)
|
||||
: INHERITED(buffer) {
|
||||
fBitmap.unflatten(buffer);
|
||||
}
|
||||
|
||||
void SkBitmapSource::flatten(SkFlattenableWriteBuffer& buffer) const {
|
||||
this->INHERITED::flatten(buffer);
|
||||
fBitmap.flatten(buffer);
|
||||
}
|
||||
|
||||
bool SkBitmapSource::onFilterImage(Proxy*, const SkBitmap&, const SkMatrix&,
|
||||
SkBitmap* result, SkIPoint* offset) {
|
||||
*result = fBitmap;
|
||||
return true;
|
||||
}
|
|
@ -1,321 +0,0 @@
|
|||
/*
|
||||
* Copyright 2012 The Android Open Source Project
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include "SkBlendImageFilter.h"
|
||||
#include "SkCanvas.h"
|
||||
#include "SkColorPriv.h"
|
||||
#include "SkFlattenableBuffers.h"
|
||||
#if SK_SUPPORT_GPU
|
||||
#include "GrContext.h"
|
||||
#include "gl/GrGLEffect.h"
|
||||
#include "gl/GrGLEffectMatrix.h"
|
||||
#include "GrTBackendEffectFactory.h"
|
||||
#include "SkImageFilterUtils.h"
|
||||
#endif
|
||||
|
||||
namespace {
|
||||
|
||||
SkXfermode::Mode modeToXfermode(SkBlendImageFilter::Mode mode) {
|
||||
switch (mode) {
|
||||
case SkBlendImageFilter::kNormal_Mode:
|
||||
return SkXfermode::kSrcOver_Mode;
|
||||
case SkBlendImageFilter::kMultiply_Mode:
|
||||
return SkXfermode::kMultiply_Mode;
|
||||
case SkBlendImageFilter::kScreen_Mode:
|
||||
return SkXfermode::kScreen_Mode;
|
||||
case SkBlendImageFilter::kDarken_Mode:
|
||||
return SkXfermode::kDarken_Mode;
|
||||
case SkBlendImageFilter::kLighten_Mode:
|
||||
return SkXfermode::kLighten_Mode;
|
||||
}
|
||||
SkASSERT(0);
|
||||
return SkXfermode::kSrcOver_Mode;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
SkBlendImageFilter::SkBlendImageFilter(SkBlendImageFilter::Mode mode, SkImageFilter* background, SkImageFilter* foreground)
|
||||
: INHERITED(background, foreground), fMode(mode)
|
||||
{
|
||||
}
|
||||
|
||||
SkBlendImageFilter::~SkBlendImageFilter() {
|
||||
}
|
||||
|
||||
SkBlendImageFilter::SkBlendImageFilter(SkFlattenableReadBuffer& buffer)
|
||||
: INHERITED(buffer)
|
||||
{
|
||||
fMode = (SkBlendImageFilter::Mode) buffer.readInt();
|
||||
}
|
||||
|
||||
void SkBlendImageFilter::flatten(SkFlattenableWriteBuffer& buffer) const {
|
||||
this->INHERITED::flatten(buffer);
|
||||
buffer.writeInt((int) fMode);
|
||||
}
|
||||
|
||||
bool SkBlendImageFilter::onFilterImage(Proxy* proxy,
|
||||
const SkBitmap& src,
|
||||
const SkMatrix& ctm,
|
||||
SkBitmap* dst,
|
||||
SkIPoint* offset) {
|
||||
SkBitmap background, foreground = src;
|
||||
SkImageFilter* backgroundInput = getBackgroundInput();
|
||||
SkImageFilter* foregroundInput = getForegroundInput();
|
||||
SkASSERT(NULL != backgroundInput);
|
||||
if (!backgroundInput->filterImage(proxy, src, ctm, &background, offset)) {
|
||||
return false;
|
||||
}
|
||||
if (foregroundInput && !foregroundInput->filterImage(proxy, src, ctm, &foreground, offset)) {
|
||||
return false;
|
||||
}
|
||||
SkAutoLockPixels alp_foreground(foreground), alp_background(background);
|
||||
if (!foreground.getPixels() || !background.getPixels()) {
|
||||
return false;
|
||||
}
|
||||
dst->setConfig(background.config(), background.width(), background.height());
|
||||
dst->allocPixels();
|
||||
SkCanvas canvas(*dst);
|
||||
SkPaint paint;
|
||||
paint.setXfermodeMode(SkXfermode::kSrc_Mode);
|
||||
canvas.drawBitmap(background, 0, 0, &paint);
|
||||
paint.setXfermodeMode(modeToXfermode(fMode));
|
||||
canvas.drawBitmap(foreground, 0, 0, &paint);
|
||||
return true;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#if SK_SUPPORT_GPU
|
||||
class GrGLBlendEffect : public GrGLEffect {
|
||||
public:
|
||||
GrGLBlendEffect(const GrBackendEffectFactory&, const GrDrawEffect&);
|
||||
virtual ~GrGLBlendEffect();
|
||||
|
||||
virtual void emitCode(GrGLShaderBuilder*,
|
||||
const GrDrawEffect&,
|
||||
EffectKey,
|
||||
const char* outputColor,
|
||||
const char* inputColor,
|
||||
const TextureSamplerArray&) SK_OVERRIDE;
|
||||
|
||||
static inline EffectKey GenKey(const GrDrawEffect&, const GrGLCaps&);
|
||||
|
||||
virtual void setData(const GrGLUniformManager&, const GrDrawEffect&) SK_OVERRIDE;
|
||||
|
||||
private:
|
||||
static const GrEffect::CoordsType kCoordsType = GrEffect::kLocal_CoordsType;
|
||||
|
||||
SkBlendImageFilter::Mode fMode;
|
||||
GrGLEffectMatrix fForegroundEffectMatrix;
|
||||
GrGLEffectMatrix fBackgroundEffectMatrix;
|
||||
|
||||
typedef GrGLEffect INHERITED;
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class GrBlendEffect : public GrEffect {
|
||||
public:
|
||||
static GrEffectRef* Create(SkBlendImageFilter::Mode mode,
|
||||
GrTexture* foreground,
|
||||
GrTexture* background) {
|
||||
AutoEffectUnref effect(SkNEW_ARGS(GrBlendEffect, (mode, foreground, background)));
|
||||
return CreateEffectRef(effect);
|
||||
}
|
||||
|
||||
virtual ~GrBlendEffect();
|
||||
|
||||
virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE;
|
||||
SkBlendImageFilter::Mode mode() const { return fMode; }
|
||||
|
||||
typedef GrGLBlendEffect GLEffect;
|
||||
static const char* Name() { return "Blend"; }
|
||||
|
||||
virtual void getConstantColorComponents(GrColor* color, uint32_t* validFlags) const SK_OVERRIDE;
|
||||
|
||||
private:
|
||||
virtual bool onIsEqual(const GrEffect&) const SK_OVERRIDE;
|
||||
|
||||
GrBlendEffect(SkBlendImageFilter::Mode mode, GrTexture* foreground, GrTexture* background);
|
||||
GrTextureAccess fForegroundAccess;
|
||||
GrTextureAccess fBackgroundAccess;
|
||||
SkBlendImageFilter::Mode fMode;
|
||||
|
||||
typedef GrEffect INHERITED;
|
||||
};
|
||||
|
||||
bool SkBlendImageFilter::filterImageGPU(Proxy* proxy, const SkBitmap& src, SkBitmap* result) {
|
||||
SkBitmap backgroundBM;
|
||||
if (!SkImageFilterUtils::GetInputResultGPU(getBackgroundInput(), proxy, src, &backgroundBM)) {
|
||||
return false;
|
||||
}
|
||||
GrTexture* background = (GrTexture*) backgroundBM.getTexture();
|
||||
SkBitmap foregroundBM;
|
||||
if (!SkImageFilterUtils::GetInputResultGPU(getForegroundInput(), proxy, src, &foregroundBM)) {
|
||||
return false;
|
||||
}
|
||||
GrTexture* foreground = (GrTexture*) foregroundBM.getTexture();
|
||||
GrContext* context = foreground->getContext();
|
||||
|
||||
GrTextureDesc desc;
|
||||
desc.fFlags = kRenderTarget_GrTextureFlagBit | kNoStencil_GrTextureFlagBit;
|
||||
desc.fWidth = src.width();
|
||||
desc.fHeight = src.height();
|
||||
desc.fConfig = kSkia8888_GrPixelConfig;
|
||||
|
||||
GrAutoScratchTexture ast(context, desc);
|
||||
SkAutoTUnref<GrTexture> dst(ast.detach());
|
||||
|
||||
GrContext::AutoRenderTarget art(context, dst->asRenderTarget());
|
||||
|
||||
GrPaint paint;
|
||||
paint.colorStage(0)->setEffect(
|
||||
GrBlendEffect::Create(fMode, foreground, background))->unref();
|
||||
SkRect srcRect;
|
||||
src.getBounds(&srcRect);
|
||||
context->drawRect(paint, srcRect);
|
||||
return SkImageFilterUtils::WrapTexture(dst, src.width(), src.height(), result);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
GrBlendEffect::GrBlendEffect(SkBlendImageFilter::Mode mode,
|
||||
GrTexture* foreground,
|
||||
GrTexture* background)
|
||||
: fForegroundAccess(foreground)
|
||||
, fBackgroundAccess(background)
|
||||
, fMode(mode) {
|
||||
this->addTextureAccess(&fForegroundAccess);
|
||||
this->addTextureAccess(&fBackgroundAccess);
|
||||
}
|
||||
|
||||
GrBlendEffect::~GrBlendEffect() {
|
||||
}
|
||||
|
||||
bool GrBlendEffect::onIsEqual(const GrEffect& sBase) const {
|
||||
const GrBlendEffect& s = CastEffect<GrBlendEffect>(sBase);
|
||||
return fForegroundAccess.getTexture() == s.fForegroundAccess.getTexture() &&
|
||||
fBackgroundAccess.getTexture() == s.fBackgroundAccess.getTexture() &&
|
||||
fMode == s.fMode;
|
||||
}
|
||||
|
||||
const GrBackendEffectFactory& GrBlendEffect::getFactory() const {
|
||||
return GrTBackendEffectFactory<GrBlendEffect>::getInstance();
|
||||
}
|
||||
|
||||
void GrBlendEffect::getConstantColorComponents(GrColor* color, uint32_t* validFlags) const {
|
||||
// The output alpha is always 1 - (1 - FGa) * (1 - BGa). So if either FGa or BGa is known to
|
||||
// be one then the output alpha is one. (This effect ignores its input. We should have a way to
|
||||
// communicate this.)
|
||||
if (GrPixelConfigIsOpaque(fForegroundAccess.getTexture()->config()) ||
|
||||
GrPixelConfigIsOpaque(fBackgroundAccess.getTexture()->config())) {
|
||||
*validFlags = kA_GrColorComponentFlag;
|
||||
*color = GrColorPackRGBA(0, 0, 0, 0xff);
|
||||
} else {
|
||||
*validFlags = 0;
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
GrGLBlendEffect::GrGLBlendEffect(const GrBackendEffectFactory& factory,
|
||||
const GrDrawEffect& drawEffect)
|
||||
: INHERITED(factory)
|
||||
, fMode(drawEffect.castEffect<GrBlendEffect>().mode())
|
||||
, fForegroundEffectMatrix(kCoordsType)
|
||||
, fBackgroundEffectMatrix(kCoordsType) {
|
||||
}
|
||||
|
||||
GrGLBlendEffect::~GrGLBlendEffect() {
|
||||
}
|
||||
|
||||
void GrGLBlendEffect::emitCode(GrGLShaderBuilder* builder,
|
||||
const GrDrawEffect&,
|
||||
EffectKey key,
|
||||
const char* outputColor,
|
||||
const char* inputColor,
|
||||
const TextureSamplerArray& samplers) {
|
||||
const char* fgCoords;
|
||||
const char* bgCoords;
|
||||
GrSLType fgCoordsType = fForegroundEffectMatrix.emitCode(builder, key, &fgCoords, NULL, "FG");
|
||||
GrSLType bgCoordsType = fBackgroundEffectMatrix.emitCode(builder, key, &bgCoords, NULL, "BG");
|
||||
|
||||
const char* bgColor = "bgColor";
|
||||
const char* fgColor = "fgColor";
|
||||
|
||||
builder->fsCodeAppendf("\t\tvec4 %s = ", fgColor);
|
||||
builder->appendTextureLookup(GrGLShaderBuilder::kFragment_ShaderType,
|
||||
samplers[0],
|
||||
fgCoords,
|
||||
fgCoordsType);
|
||||
builder->fsCodeAppend(";\n");
|
||||
|
||||
builder->fsCodeAppendf("\t\tvec4 %s = ", bgColor);
|
||||
builder->appendTextureLookup(GrGLShaderBuilder::kFragment_ShaderType,
|
||||
samplers[1],
|
||||
bgCoords,
|
||||
bgCoordsType);
|
||||
builder->fsCodeAppendf(";\n");
|
||||
|
||||
builder->fsCodeAppendf("\t\t%s.a = 1.0 - (1.0 - %s.a) * (1.0 - %s.b);\n", outputColor, bgColor, fgColor);
|
||||
switch (fMode) {
|
||||
case SkBlendImageFilter::kNormal_Mode:
|
||||
builder->fsCodeAppendf("\t\t%s.rgb = (1.0 - %s.a) * %s.rgb + %s.rgb;\n", outputColor, fgColor, bgColor, fgColor);
|
||||
break;
|
||||
case SkBlendImageFilter::kMultiply_Mode:
|
||||
builder->fsCodeAppendf("\t\t%s.rgb = (1.0 - %s.a) * %s.rgb + (1.0 - %s.a) * %s.rgb + %s.rgb * %s.rgb;\n", outputColor, fgColor, bgColor, bgColor, fgColor, fgColor, bgColor);
|
||||
break;
|
||||
case SkBlendImageFilter::kScreen_Mode:
|
||||
builder->fsCodeAppendf("\t\t%s.rgb = %s.rgb + %s.rgb - %s.rgb * %s.rgb;\n", outputColor, bgColor, fgColor, fgColor, bgColor);
|
||||
break;
|
||||
case SkBlendImageFilter::kDarken_Mode:
|
||||
builder->fsCodeAppendf("\t\t%s.rgb = min((1.0 - %s.a) * %s.rgb + %s.rgb, (1.0 - %s.a) * %s.rgb + %s.rgb);\n", outputColor, fgColor, bgColor, fgColor, bgColor, fgColor, bgColor);
|
||||
break;
|
||||
case SkBlendImageFilter::kLighten_Mode:
|
||||
builder->fsCodeAppendf("\t\t%s.rgb = max((1.0 - %s.a) * %s.rgb + %s.rgb, (1.0 - %s.a) * %s.rgb + %s.rgb);\n", outputColor, fgColor, bgColor, fgColor, bgColor, fgColor, bgColor);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void GrGLBlendEffect::setData(const GrGLUniformManager& uman, const GrDrawEffect& drawEffect) {
|
||||
const GrBlendEffect& blend = drawEffect.castEffect<GrBlendEffect>();
|
||||
GrTexture* fgTex = blend.texture(0);
|
||||
GrTexture* bgTex = blend.texture(1);
|
||||
fForegroundEffectMatrix.setData(uman,
|
||||
GrEffect::MakeDivByTextureWHMatrix(fgTex),
|
||||
drawEffect,
|
||||
fgTex);
|
||||
fBackgroundEffectMatrix.setData(uman,
|
||||
GrEffect::MakeDivByTextureWHMatrix(bgTex),
|
||||
drawEffect,
|
||||
bgTex);
|
||||
|
||||
}
|
||||
|
||||
GrGLEffect::EffectKey GrGLBlendEffect::GenKey(const GrDrawEffect& drawEffect, const GrGLCaps&) {
|
||||
const GrBlendEffect& blend = drawEffect.castEffect<GrBlendEffect>();
|
||||
|
||||
GrTexture* fgTex = blend.texture(0);
|
||||
GrTexture* bgTex = blend.texture(1);
|
||||
|
||||
EffectKey fgKey = GrGLEffectMatrix::GenKey(GrEffect::MakeDivByTextureWHMatrix(fgTex),
|
||||
drawEffect,
|
||||
kCoordsType,
|
||||
fgTex);
|
||||
|
||||
EffectKey bgKey = GrGLEffectMatrix::GenKey(GrEffect::MakeDivByTextureWHMatrix(bgTex),
|
||||
drawEffect,
|
||||
kCoordsType,
|
||||
bgTex);
|
||||
bgKey <<= GrGLEffectMatrix::kKeyBits;
|
||||
EffectKey modeKey = blend.mode() << (2 * GrGLEffectMatrix::kKeyBits);
|
||||
|
||||
return modeKey | bgKey | fgKey;
|
||||
}
|
||||
#endif
|
|
@ -1,207 +0,0 @@
|
|||
/*
|
||||
* Copyright 2011 The Android Open Source Project
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include "SkBitmap.h"
|
||||
#include "SkBlurImageFilter.h"
|
||||
#include "SkColorPriv.h"
|
||||
#include "SkFlattenableBuffers.h"
|
||||
#if SK_SUPPORT_GPU
|
||||
#include "GrContext.h"
|
||||
#include "SkImageFilterUtils.h"
|
||||
#endif
|
||||
|
||||
SkBlurImageFilter::SkBlurImageFilter(SkFlattenableReadBuffer& buffer)
|
||||
: INHERITED(buffer) {
|
||||
fSigma.fWidth = buffer.readScalar();
|
||||
fSigma.fHeight = buffer.readScalar();
|
||||
}
|
||||
|
||||
SkBlurImageFilter::SkBlurImageFilter(SkScalar sigmaX, SkScalar sigmaY, SkImageFilter* input)
|
||||
: INHERITED(input), fSigma(SkSize::Make(sigmaX, sigmaY)) {
|
||||
SkASSERT(sigmaX >= 0 && sigmaY >= 0);
|
||||
}
|
||||
|
||||
void SkBlurImageFilter::flatten(SkFlattenableWriteBuffer& buffer) const {
|
||||
this->INHERITED::flatten(buffer);
|
||||
buffer.writeScalar(fSigma.fWidth);
|
||||
buffer.writeScalar(fSigma.fHeight);
|
||||
}
|
||||
|
||||
static void boxBlurX(const SkBitmap& src, SkBitmap* dst, int kernelSize,
|
||||
int leftOffset, int rightOffset)
|
||||
{
|
||||
int width = src.width(), height = src.height();
|
||||
int rightBorder = SkMin32(rightOffset + 1, width);
|
||||
for (int y = 0; y < height; ++y) {
|
||||
int sumA = 0, sumR = 0, sumG = 0, sumB = 0;
|
||||
SkPMColor* p = src.getAddr32(0, y);
|
||||
for (int i = 0; i < rightBorder; ++i) {
|
||||
sumA += SkGetPackedA32(*p);
|
||||
sumR += SkGetPackedR32(*p);
|
||||
sumG += SkGetPackedG32(*p);
|
||||
sumB += SkGetPackedB32(*p);
|
||||
p++;
|
||||
}
|
||||
|
||||
const SkColor* sptr = src.getAddr32(0, y);
|
||||
SkColor* dptr = dst->getAddr32(0, y);
|
||||
for (int x = 0; x < width; ++x) {
|
||||
*dptr = SkPackARGB32(sumA / kernelSize,
|
||||
sumR / kernelSize,
|
||||
sumG / kernelSize,
|
||||
sumB / kernelSize);
|
||||
if (x >= leftOffset) {
|
||||
SkColor l = *(sptr - leftOffset);
|
||||
sumA -= SkGetPackedA32(l);
|
||||
sumR -= SkGetPackedR32(l);
|
||||
sumG -= SkGetPackedG32(l);
|
||||
sumB -= SkGetPackedB32(l);
|
||||
}
|
||||
if (x + rightOffset + 1 < width) {
|
||||
SkColor r = *(sptr + rightOffset + 1);
|
||||
sumA += SkGetPackedA32(r);
|
||||
sumR += SkGetPackedR32(r);
|
||||
sumG += SkGetPackedG32(r);
|
||||
sumB += SkGetPackedB32(r);
|
||||
}
|
||||
sptr++;
|
||||
dptr++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void boxBlurY(const SkBitmap& src, SkBitmap* dst, int kernelSize,
|
||||
int topOffset, int bottomOffset)
|
||||
{
|
||||
int width = src.width(), height = src.height();
|
||||
int bottomBorder = SkMin32(bottomOffset + 1, height);
|
||||
int srcStride = src.rowBytesAsPixels();
|
||||
int dstStride = dst->rowBytesAsPixels();
|
||||
for (int x = 0; x < width; ++x) {
|
||||
int sumA = 0, sumR = 0, sumG = 0, sumB = 0;
|
||||
SkColor* p = src.getAddr32(x, 0);
|
||||
for (int i = 0; i < bottomBorder; ++i) {
|
||||
sumA += SkGetPackedA32(*p);
|
||||
sumR += SkGetPackedR32(*p);
|
||||
sumG += SkGetPackedG32(*p);
|
||||
sumB += SkGetPackedB32(*p);
|
||||
p += srcStride;
|
||||
}
|
||||
|
||||
const SkColor* sptr = src.getAddr32(x, 0);
|
||||
SkColor* dptr = dst->getAddr32(x, 0);
|
||||
for (int y = 0; y < height; ++y) {
|
||||
*dptr = SkPackARGB32(sumA / kernelSize,
|
||||
sumR / kernelSize,
|
||||
sumG / kernelSize,
|
||||
sumB / kernelSize);
|
||||
if (y >= topOffset) {
|
||||
SkColor l = *(sptr - topOffset * srcStride);
|
||||
sumA -= SkGetPackedA32(l);
|
||||
sumR -= SkGetPackedR32(l);
|
||||
sumG -= SkGetPackedG32(l);
|
||||
sumB -= SkGetPackedB32(l);
|
||||
}
|
||||
if (y + bottomOffset + 1 < height) {
|
||||
SkColor r = *(sptr + (bottomOffset + 1) * srcStride);
|
||||
sumA += SkGetPackedA32(r);
|
||||
sumR += SkGetPackedR32(r);
|
||||
sumG += SkGetPackedG32(r);
|
||||
sumB += SkGetPackedB32(r);
|
||||
}
|
||||
sptr += srcStride;
|
||||
dptr += dstStride;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void getBox3Params(SkScalar s, int *kernelSize, int* kernelSize3, int *lowOffset, int *highOffset)
|
||||
{
|
||||
float pi = SkScalarToFloat(SK_ScalarPI);
|
||||
int d = static_cast<int>(floorf(SkScalarToFloat(s) * 3.0f * sqrtf(2.0f * pi) / 4.0f + 0.5f));
|
||||
*kernelSize = d;
|
||||
if (d % 2 == 1) {
|
||||
*lowOffset = *highOffset = (d - 1) / 2;
|
||||
*kernelSize3 = d;
|
||||
} else {
|
||||
*highOffset = d / 2;
|
||||
*lowOffset = *highOffset - 1;
|
||||
*kernelSize3 = d + 1;
|
||||
}
|
||||
}
|
||||
|
||||
bool SkBlurImageFilter::onFilterImage(Proxy* proxy,
|
||||
const SkBitmap& source, const SkMatrix& ctm,
|
||||
SkBitmap* dst, SkIPoint* offset) {
|
||||
SkBitmap src = this->getInputResult(0, proxy, source, ctm, offset);
|
||||
if (src.config() != SkBitmap::kARGB_8888_Config) {
|
||||
return false;
|
||||
}
|
||||
|
||||
SkAutoLockPixels alp(src);
|
||||
if (!src.getPixels()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
dst->setConfig(src.config(), src.width(), src.height());
|
||||
dst->allocPixels();
|
||||
int kernelSizeX, kernelSizeX3, lowOffsetX, highOffsetX;
|
||||
int kernelSizeY, kernelSizeY3, lowOffsetY, highOffsetY;
|
||||
getBox3Params(fSigma.width(), &kernelSizeX, &kernelSizeX3, &lowOffsetX, &highOffsetX);
|
||||
getBox3Params(fSigma.height(), &kernelSizeY, &kernelSizeY3, &lowOffsetY, &highOffsetY);
|
||||
|
||||
if (kernelSizeX < 0 || kernelSizeY < 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (kernelSizeX == 0 && kernelSizeY == 0) {
|
||||
src.copyTo(dst, dst->config());
|
||||
return true;
|
||||
}
|
||||
|
||||
SkBitmap temp;
|
||||
temp.setConfig(dst->config(), dst->width(), dst->height());
|
||||
if (!temp.allocPixels()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (kernelSizeX > 0 && kernelSizeY > 0) {
|
||||
boxBlurX(src, &temp, kernelSizeX, lowOffsetX, highOffsetX);
|
||||
boxBlurY(temp, dst, kernelSizeY, lowOffsetY, highOffsetY);
|
||||
boxBlurX(*dst, &temp, kernelSizeX, highOffsetX, lowOffsetX);
|
||||
boxBlurY(temp, dst, kernelSizeY, highOffsetY, lowOffsetY);
|
||||
boxBlurX(*dst, &temp, kernelSizeX3, highOffsetX, highOffsetX);
|
||||
boxBlurY(temp, dst, kernelSizeY3, highOffsetY, highOffsetY);
|
||||
} else if (kernelSizeX > 0) {
|
||||
boxBlurX(src, dst, kernelSizeX, lowOffsetX, highOffsetX);
|
||||
boxBlurX(*dst, &temp, kernelSizeX, highOffsetX, lowOffsetX);
|
||||
boxBlurX(temp, dst, kernelSizeX3, highOffsetX, highOffsetX);
|
||||
} else if (kernelSizeY > 0) {
|
||||
boxBlurY(src, dst, kernelSizeY, lowOffsetY, highOffsetY);
|
||||
boxBlurY(*dst, &temp, kernelSizeY, highOffsetY, lowOffsetY);
|
||||
boxBlurY(temp, dst, kernelSizeY3, highOffsetY, highOffsetY);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SkBlurImageFilter::filterImageGPU(Proxy* proxy, const SkBitmap& src, SkBitmap* result) {
|
||||
#if SK_SUPPORT_GPU
|
||||
SkBitmap input;
|
||||
if (!SkImageFilterUtils::GetInputResultGPU(getInput(0), proxy, src, &input)) {
|
||||
return false;
|
||||
}
|
||||
GrTexture* source = (GrTexture*) input.getTexture();
|
||||
SkRect rect;
|
||||
src.getBounds(&rect);
|
||||
SkAutoTUnref<GrTexture> tex(source->getContext()->gaussianBlur(source, false, rect,
|
||||
fSigma.width(), fSigma.height()));
|
||||
return SkImageFilterUtils::WrapTexture(tex, src.width(), src.height(), result);
|
||||
#else
|
||||
SkDEBUGFAIL("Should not call in GPU-less build");
|
||||
return false;
|
||||
#endif
|
||||
}
|
|
@ -1,57 +0,0 @@
|
|||
|
||||
/*
|
||||
* Copyright 2006 The Android Open Source Project
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef SkBlurMask_DEFINED
|
||||
#define SkBlurMask_DEFINED
|
||||
|
||||
#include "SkShader.h"
|
||||
#include "SkMask.h"
|
||||
|
||||
class SkBlurMask {
|
||||
public:
|
||||
enum Style {
|
||||
kNormal_Style, //!< fuzzy inside and outside
|
||||
kSolid_Style, //!< solid inside, fuzzy outside
|
||||
kOuter_Style, //!< nothing inside, fuzzy outside
|
||||
kInner_Style, //!< fuzzy inside, nothing outside
|
||||
|
||||
kStyleCount
|
||||
};
|
||||
|
||||
enum Quality {
|
||||
kLow_Quality, //!< box blur
|
||||
kHigh_Quality //!< three pass box blur (similar to gaussian)
|
||||
};
|
||||
|
||||
static bool BlurRect(SkMask *dst, const SkRect &src,
|
||||
SkScalar radius, Style style,
|
||||
SkIPoint *margin = NULL,
|
||||
SkMask::CreateMode createMode=SkMask::kComputeBoundsAndRenderImage_CreateMode);
|
||||
static bool Blur(SkMask* dst, const SkMask& src,
|
||||
SkScalar radius, Style style, Quality quality,
|
||||
SkIPoint* margin = NULL);
|
||||
static bool BlurSeparable(SkMask* dst, const SkMask& src,
|
||||
SkScalar radius, Style style, Quality quality,
|
||||
SkIPoint* margin = NULL);
|
||||
|
||||
|
||||
// the "ground truth" blur does a gaussian convolution; it's slow
|
||||
// but useful for comparison purposes.
|
||||
|
||||
static bool BlurGroundTruth(SkMask* dst, const SkMask& src,
|
||||
SkScalar provided_radius, Style style,
|
||||
SkIPoint* margin = NULL);
|
||||
|
||||
private:
|
||||
static bool Blur(SkMask* dst, const SkMask& src,
|
||||
SkScalar radius, Style style, Quality quality,
|
||||
SkIPoint* margin, bool separable);
|
||||
};
|
||||
|
||||
#endif
|
|
@ -1,375 +0,0 @@
|
|||
|
||||
/*
|
||||
* Copyright 2006 The Android Open Source Project
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include "SkBlurMaskFilter.h"
|
||||
#include "SkBlurMask.h"
|
||||
#include "SkFlattenableBuffers.h"
|
||||
#include "SkMaskFilter.h"
|
||||
#include "SkBounder.h"
|
||||
#include "SkRasterClip.h"
|
||||
#include "SkRTConf.h"
|
||||
#include "SkStringUtils.h"
|
||||
|
||||
class SkBlurMaskFilterImpl : public SkMaskFilter {
|
||||
public:
|
||||
SkBlurMaskFilterImpl(SkScalar radius, SkBlurMaskFilter::BlurStyle,
|
||||
uint32_t flags);
|
||||
|
||||
// overrides from SkMaskFilter
|
||||
virtual SkMask::Format getFormat() const SK_OVERRIDE;
|
||||
virtual bool filterMask(SkMask* dst, const SkMask& src, const SkMatrix&,
|
||||
SkIPoint* margin) const SK_OVERRIDE;
|
||||
|
||||
virtual BlurType asABlur(BlurInfo*) const SK_OVERRIDE;
|
||||
virtual void computeFastBounds(const SkRect&, SkRect*) const SK_OVERRIDE;
|
||||
|
||||
SkDEVCODE(virtual void toString(SkString* str) const SK_OVERRIDE;)
|
||||
SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkBlurMaskFilterImpl)
|
||||
|
||||
protected:
|
||||
virtual FilterReturn filterRectsToNine(const SkRect[], int count, const SkMatrix&,
|
||||
const SkIRect& clipBounds,
|
||||
NinePatch*) const SK_OVERRIDE;
|
||||
|
||||
bool filterRectMask(SkMask* dstM, const SkRect& r, const SkMatrix& matrix,
|
||||
SkIPoint* margin, SkMask::CreateMode createMode) const;
|
||||
|
||||
private:
|
||||
SkScalar fRadius;
|
||||
SkBlurMaskFilter::BlurStyle fBlurStyle;
|
||||
uint32_t fBlurFlags;
|
||||
|
||||
SkBlurMaskFilterImpl(SkFlattenableReadBuffer&);
|
||||
virtual void flatten(SkFlattenableWriteBuffer&) const SK_OVERRIDE;
|
||||
|
||||
typedef SkMaskFilter INHERITED;
|
||||
};
|
||||
|
||||
SkMaskFilter* SkBlurMaskFilter::Create(SkScalar radius,
|
||||
SkBlurMaskFilter::BlurStyle style,
|
||||
uint32_t flags) {
|
||||
// use !(radius > 0) instead of radius <= 0 to reject NaN values
|
||||
if (!(radius > 0) || (unsigned)style >= SkBlurMaskFilter::kBlurStyleCount
|
||||
|| flags > SkBlurMaskFilter::kAll_BlurFlag) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return SkNEW_ARGS(SkBlurMaskFilterImpl, (radius, style, flags));
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
SkBlurMaskFilterImpl::SkBlurMaskFilterImpl(SkScalar radius,
|
||||
SkBlurMaskFilter::BlurStyle style,
|
||||
uint32_t flags)
|
||||
: fRadius(radius), fBlurStyle(style), fBlurFlags(flags) {
|
||||
#if 0
|
||||
fGamma = NULL;
|
||||
if (gammaScale) {
|
||||
fGamma = new U8[256];
|
||||
if (gammaScale > 0)
|
||||
SkBlurMask::BuildSqrGamma(fGamma, gammaScale);
|
||||
else
|
||||
SkBlurMask::BuildSqrtGamma(fGamma, -gammaScale);
|
||||
}
|
||||
#endif
|
||||
SkASSERT(radius >= 0);
|
||||
SkASSERT((unsigned)style < SkBlurMaskFilter::kBlurStyleCount);
|
||||
SkASSERT(flags <= SkBlurMaskFilter::kAll_BlurFlag);
|
||||
}
|
||||
|
||||
SkMask::Format SkBlurMaskFilterImpl::getFormat() const {
|
||||
return SkMask::kA8_Format;
|
||||
}
|
||||
|
||||
bool SkBlurMaskFilterImpl::filterMask(SkMask* dst, const SkMask& src,
|
||||
const SkMatrix& matrix,
|
||||
SkIPoint* margin) const{
|
||||
SkScalar radius;
|
||||
if (fBlurFlags & SkBlurMaskFilter::kIgnoreTransform_BlurFlag) {
|
||||
radius = fRadius;
|
||||
} else {
|
||||
radius = matrix.mapRadius(fRadius);
|
||||
}
|
||||
|
||||
// To avoid unseemly allocation requests (esp. for finite platforms like
|
||||
// handset) we limit the radius so something manageable. (as opposed to
|
||||
// a request like 10,000)
|
||||
static const SkScalar MAX_RADIUS = SkIntToScalar(128);
|
||||
radius = SkMinScalar(radius, MAX_RADIUS);
|
||||
SkBlurMask::Quality blurQuality =
|
||||
(fBlurFlags & SkBlurMaskFilter::kHighQuality_BlurFlag) ?
|
||||
SkBlurMask::kHigh_Quality : SkBlurMask::kLow_Quality;
|
||||
|
||||
#ifndef SK_DISABLE_SEPARABLE_MASK_BLUR
|
||||
return SkBlurMask::BlurSeparable(dst, src, radius, (SkBlurMask::Style)fBlurStyle,
|
||||
blurQuality, margin);
|
||||
#else
|
||||
return SkBlurMask::Blur(dst, src, radius, (SkBlurMask::Style)fBlurStyle,
|
||||
blurQuality, margin);
|
||||
#endif
|
||||
}
|
||||
|
||||
bool SkBlurMaskFilterImpl::filterRectMask(SkMask* dst, const SkRect& r,
|
||||
const SkMatrix& matrix,
|
||||
SkIPoint* margin, SkMask::CreateMode createMode) const{
|
||||
SkScalar radius;
|
||||
if (fBlurFlags & SkBlurMaskFilter::kIgnoreTransform_BlurFlag) {
|
||||
radius = fRadius;
|
||||
} else {
|
||||
radius = matrix.mapRadius(fRadius);
|
||||
}
|
||||
|
||||
// To avoid unseemly allocation requests (esp. for finite platforms like
|
||||
// handset) we limit the radius so something manageable. (as opposed to
|
||||
// a request like 10,000)
|
||||
static const SkScalar MAX_RADIUS = SkIntToScalar(128);
|
||||
radius = SkMinScalar(radius, MAX_RADIUS);
|
||||
|
||||
return SkBlurMask::BlurRect(dst, r, radius, (SkBlurMask::Style)fBlurStyle,
|
||||
margin, createMode);
|
||||
}
|
||||
|
||||
#include "SkCanvas.h"
|
||||
|
||||
static bool drawRectsIntoMask(const SkRect rects[], int count, SkMask* mask) {
|
||||
rects[0].roundOut(&mask->fBounds);
|
||||
mask->fRowBytes = SkAlign4(mask->fBounds.width());
|
||||
mask->fFormat = SkMask::kA8_Format;
|
||||
size_t size = mask->computeImageSize();
|
||||
mask->fImage = SkMask::AllocImage(size);
|
||||
if (NULL == mask->fImage) {
|
||||
return false;
|
||||
}
|
||||
sk_bzero(mask->fImage, size);
|
||||
|
||||
SkBitmap bitmap;
|
||||
bitmap.setConfig(SkBitmap::kA8_Config,
|
||||
mask->fBounds.width(), mask->fBounds.height(),
|
||||
mask->fRowBytes);
|
||||
bitmap.setPixels(mask->fImage);
|
||||
|
||||
SkCanvas canvas(bitmap);
|
||||
canvas.translate(-SkIntToScalar(mask->fBounds.left()),
|
||||
-SkIntToScalar(mask->fBounds.top()));
|
||||
|
||||
SkPaint paint;
|
||||
paint.setAntiAlias(true);
|
||||
|
||||
if (1 == count) {
|
||||
canvas.drawRect(rects[0], paint);
|
||||
} else {
|
||||
// todo: do I need a fast way to do this?
|
||||
SkPath path;
|
||||
path.addRect(rects[0]);
|
||||
path.addRect(rects[1]);
|
||||
path.setFillType(SkPath::kEvenOdd_FillType);
|
||||
canvas.drawPath(path, paint);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool rect_exceeds(const SkRect& r, SkScalar v) {
|
||||
return r.fLeft < -v || r.fTop < -v || r.fRight > v || r.fBottom > v ||
|
||||
r.width() > v || r.height() > v;
|
||||
}
|
||||
|
||||
#ifdef SK_IGNORE_FAST_RECT_BLUR
|
||||
SK_CONF_DECLARE( bool, c_analyticBlurNinepatch, "mask.filter.analyticNinePatch", false, "Use the faster analytic blur approach for ninepatch rects" );
|
||||
#else
|
||||
SK_CONF_DECLARE( bool, c_analyticBlurNinepatch, "mask.filter.analyticNinePatch", true, "Use the faster analytic blur approach for ninepatch rects" );
|
||||
#endif
|
||||
|
||||
SkMaskFilter::FilterReturn
|
||||
SkBlurMaskFilterImpl::filterRectsToNine(const SkRect rects[], int count,
|
||||
const SkMatrix& matrix,
|
||||
const SkIRect& clipBounds,
|
||||
NinePatch* patch) const {
|
||||
if (count < 1 || count > 2) {
|
||||
return kUnimplemented_FilterReturn;
|
||||
}
|
||||
|
||||
// TODO: report correct metrics for innerstyle, where we do not grow the
|
||||
// total bounds, but we do need an inset the size of our blur-radius
|
||||
if (SkBlurMaskFilter::kInner_BlurStyle == fBlurStyle) {
|
||||
return kUnimplemented_FilterReturn;
|
||||
}
|
||||
|
||||
// TODO: take clipBounds into account to limit our coordinates up front
|
||||
// for now, just skip too-large src rects (to take the old code path).
|
||||
if (rect_exceeds(rects[0], SkIntToScalar(32767))) {
|
||||
return kUnimplemented_FilterReturn;
|
||||
}
|
||||
|
||||
SkIPoint margin;
|
||||
SkMask srcM, dstM;
|
||||
rects[0].roundOut(&srcM.fBounds);
|
||||
srcM.fImage = NULL;
|
||||
srcM.fFormat = SkMask::kA8_Format;
|
||||
srcM.fRowBytes = 0;
|
||||
|
||||
bool filterResult = false;
|
||||
if (count == 1 && c_analyticBlurNinepatch) {
|
||||
// special case for fast rect blur
|
||||
// don't actually do the blur the first time, just compute the correct size
|
||||
filterResult = this->filterRectMask(&dstM, rects[0], matrix, &margin,
|
||||
SkMask::kJustComputeBounds_CreateMode);
|
||||
} else {
|
||||
filterResult = this->filterMask(&dstM, srcM, matrix, &margin);
|
||||
}
|
||||
|
||||
if (!filterResult) {
|
||||
return kFalse_FilterReturn;
|
||||
}
|
||||
|
||||
/*
|
||||
* smallR is the smallest version of 'rect' that will still guarantee that
|
||||
* we get the same blur results on all edges, plus 1 center row/col that is
|
||||
* representative of the extendible/stretchable edges of the ninepatch.
|
||||
* Since our actual edge may be fractional we inset 1 more to be sure we
|
||||
* don't miss any interior blur.
|
||||
* x is an added pixel of blur, and { and } are the (fractional) edge
|
||||
* pixels from the original rect.
|
||||
*
|
||||
* x x { x x .... x x } x x
|
||||
*
|
||||
* Thus, in this case, we inset by a total of 5 (on each side) beginning
|
||||
* with our outer-rect (dstM.fBounds)
|
||||
*/
|
||||
SkRect smallR[2];
|
||||
SkIPoint center;
|
||||
|
||||
// +2 is from +1 for each edge (to account for possible fractional edges
|
||||
int smallW = dstM.fBounds.width() - srcM.fBounds.width() + 2;
|
||||
int smallH = dstM.fBounds.height() - srcM.fBounds.height() + 2;
|
||||
SkIRect innerIR;
|
||||
|
||||
if (1 == count) {
|
||||
innerIR = srcM.fBounds;
|
||||
center.set(smallW, smallH);
|
||||
} else {
|
||||
SkASSERT(2 == count);
|
||||
rects[1].roundIn(&innerIR);
|
||||
center.set(smallW + (innerIR.left() - srcM.fBounds.left()),
|
||||
smallH + (innerIR.top() - srcM.fBounds.top()));
|
||||
}
|
||||
|
||||
// +1 so we get a clean, stretchable, center row/col
|
||||
smallW += 1;
|
||||
smallH += 1;
|
||||
|
||||
// we want the inset amounts to be integral, so we don't change any
|
||||
// fractional phase on the fRight or fBottom of our smallR.
|
||||
const SkScalar dx = SkIntToScalar(innerIR.width() - smallW);
|
||||
const SkScalar dy = SkIntToScalar(innerIR.height() - smallH);
|
||||
if (dx < 0 || dy < 0) {
|
||||
// we're too small, relative to our blur, to break into nine-patch,
|
||||
// so we ask to have our normal filterMask() be called.
|
||||
return kUnimplemented_FilterReturn;
|
||||
}
|
||||
|
||||
smallR[0].set(rects[0].left(), rects[0].top(), rects[0].right() - dx, rects[0].bottom() - dy);
|
||||
SkASSERT(!smallR[0].isEmpty());
|
||||
if (2 == count) {
|
||||
smallR[1].set(rects[1].left(), rects[1].top(),
|
||||
rects[1].right() - dx, rects[1].bottom() - dy);
|
||||
SkASSERT(!smallR[1].isEmpty());
|
||||
}
|
||||
|
||||
if (count > 1 || !c_analyticBlurNinepatch) {
|
||||
if (!drawRectsIntoMask(smallR, count, &srcM)) {
|
||||
return kFalse_FilterReturn;
|
||||
}
|
||||
|
||||
SkAutoMaskFreeImage amf(srcM.fImage);
|
||||
|
||||
if (!this->filterMask(&patch->fMask, srcM, matrix, &margin)) {
|
||||
return kFalse_FilterReturn;
|
||||
}
|
||||
} else {
|
||||
if (!this->filterRectMask(&patch->fMask, smallR[0], matrix, &margin,
|
||||
SkMask::kComputeBoundsAndRenderImage_CreateMode)) {
|
||||
return kFalse_FilterReturn;
|
||||
}
|
||||
}
|
||||
patch->fMask.fBounds.offsetTo(0, 0);
|
||||
patch->fOuterRect = dstM.fBounds;
|
||||
patch->fCenter = center;
|
||||
return kTrue_FilterReturn;
|
||||
}
|
||||
|
||||
void SkBlurMaskFilterImpl::computeFastBounds(const SkRect& src,
|
||||
SkRect* dst) const {
|
||||
dst->set(src.fLeft - fRadius, src.fTop - fRadius,
|
||||
src.fRight + fRadius, src.fBottom + fRadius);
|
||||
}
|
||||
|
||||
SkBlurMaskFilterImpl::SkBlurMaskFilterImpl(SkFlattenableReadBuffer& buffer)
|
||||
: SkMaskFilter(buffer) {
|
||||
fRadius = buffer.readScalar();
|
||||
fBlurStyle = (SkBlurMaskFilter::BlurStyle)buffer.readInt();
|
||||
fBlurFlags = buffer.readUInt() & SkBlurMaskFilter::kAll_BlurFlag;
|
||||
SkASSERT(fRadius >= 0);
|
||||
SkASSERT((unsigned)fBlurStyle < SkBlurMaskFilter::kBlurStyleCount);
|
||||
}
|
||||
|
||||
void SkBlurMaskFilterImpl::flatten(SkFlattenableWriteBuffer& buffer) const {
|
||||
this->INHERITED::flatten(buffer);
|
||||
buffer.writeScalar(fRadius);
|
||||
buffer.writeInt(fBlurStyle);
|
||||
buffer.writeUInt(fBlurFlags);
|
||||
}
|
||||
|
||||
static const SkMaskFilter::BlurType gBlurStyle2BlurType[] = {
|
||||
SkMaskFilter::kNormal_BlurType,
|
||||
SkMaskFilter::kSolid_BlurType,
|
||||
SkMaskFilter::kOuter_BlurType,
|
||||
SkMaskFilter::kInner_BlurType,
|
||||
};
|
||||
|
||||
SkMaskFilter::BlurType SkBlurMaskFilterImpl::asABlur(BlurInfo* info) const {
|
||||
if (info) {
|
||||
info->fRadius = fRadius;
|
||||
info->fIgnoreTransform = SkToBool(fBlurFlags & SkBlurMaskFilter::kIgnoreTransform_BlurFlag);
|
||||
info->fHighQuality = SkToBool(fBlurFlags & SkBlurMaskFilter::kHighQuality_BlurFlag);
|
||||
}
|
||||
return gBlurStyle2BlurType[fBlurStyle];
|
||||
}
|
||||
|
||||
#ifdef SK_DEVELOPER
|
||||
void SkBlurMaskFilterImpl::toString(SkString* str) const {
|
||||
str->append("SkBlurMaskFilterImpl: (");
|
||||
|
||||
str->append("radius: ");
|
||||
str->appendScalar(fRadius);
|
||||
str->append(" ");
|
||||
|
||||
static const char* gStyleName[SkBlurMaskFilter::kBlurStyleCount] = {
|
||||
"normal", "solid", "outer", "inner"
|
||||
};
|
||||
|
||||
str->appendf("style: %s ", gStyleName[fBlurStyle]);
|
||||
str->append("flags: (");
|
||||
if (fBlurFlags) {
|
||||
bool needSeparator = false;
|
||||
SkAddFlagToString(str,
|
||||
SkToBool(fBlurFlags & SkBlurMaskFilter::kIgnoreTransform_BlurFlag),
|
||||
"IgnoreXform", &needSeparator);
|
||||
SkAddFlagToString(str,
|
||||
SkToBool(fBlurFlags & SkBlurMaskFilter::kHighQuality_BlurFlag),
|
||||
"HighQuality", &needSeparator);
|
||||
} else {
|
||||
str->append("None");
|
||||
}
|
||||
str->append("))");
|
||||
}
|
||||
#endif
|
||||
|
||||
SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkBlurMaskFilter)
|
||||
SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkBlurMaskFilterImpl)
|
||||
SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END
|
|
@ -1,492 +0,0 @@
|
|||
|
||||
/*
|
||||
* Copyright 2006 The Android Open Source Project
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
|
||||
#include "SkBlitRow.h"
|
||||
#include "SkColorFilter.h"
|
||||
#include "SkColorPriv.h"
|
||||
#include "SkFlattenableBuffers.h"
|
||||
#include "SkUtils.h"
|
||||
|
||||
#define ILLEGAL_XFERMODE_MODE ((SkXfermode::Mode)-1)
|
||||
|
||||
// baseclass for filters that store a color and mode
|
||||
class SkModeColorFilter : public SkColorFilter {
|
||||
public:
|
||||
SkModeColorFilter(SkColor color) {
|
||||
fColor = color;
|
||||
fMode = ILLEGAL_XFERMODE_MODE;
|
||||
this->updateCache();
|
||||
}
|
||||
|
||||
SkModeColorFilter(SkColor color, SkXfermode::Mode mode) {
|
||||
fColor = color;
|
||||
fMode = mode;
|
||||
this->updateCache();
|
||||
};
|
||||
|
||||
SkColor getColor() const { return fColor; }
|
||||
SkXfermode::Mode getMode() const { return fMode; }
|
||||
bool isModeValid() const { return ILLEGAL_XFERMODE_MODE != fMode; }
|
||||
SkPMColor getPMColor() const { return fPMColor; }
|
||||
|
||||
virtual bool asColorMode(SkColor* color, SkXfermode::Mode* mode) const SK_OVERRIDE {
|
||||
if (ILLEGAL_XFERMODE_MODE == fMode) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (color) {
|
||||
*color = fColor;
|
||||
}
|
||||
if (mode) {
|
||||
*mode = fMode;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual uint32_t getFlags() const SK_OVERRIDE {
|
||||
return fProc16 ? (kAlphaUnchanged_Flag | kHasFilter16_Flag) : 0;
|
||||
}
|
||||
|
||||
virtual void filterSpan(const SkPMColor shader[], int count,
|
||||
SkPMColor result[]) const SK_OVERRIDE {
|
||||
SkPMColor color = fPMColor;
|
||||
SkXfermodeProc proc = fProc;
|
||||
|
||||
for (int i = 0; i < count; i++) {
|
||||
result[i] = proc(color, shader[i]);
|
||||
}
|
||||
}
|
||||
|
||||
virtual void filterSpan16(const uint16_t shader[], int count,
|
||||
uint16_t result[]) const SK_OVERRIDE {
|
||||
SkASSERT(this->getFlags() & kHasFilter16_Flag);
|
||||
|
||||
SkPMColor color = fPMColor;
|
||||
SkXfermodeProc16 proc16 = fProc16;
|
||||
|
||||
for (int i = 0; i < count; i++) {
|
||||
result[i] = proc16(color, shader[i]);
|
||||
}
|
||||
}
|
||||
|
||||
SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkModeColorFilter)
|
||||
|
||||
protected:
|
||||
virtual void flatten(SkFlattenableWriteBuffer& buffer) const SK_OVERRIDE {
|
||||
this->INHERITED::flatten(buffer);
|
||||
buffer.writeColor(fColor);
|
||||
buffer.writeUInt(fMode);
|
||||
}
|
||||
|
||||
SkModeColorFilter(SkFlattenableReadBuffer& buffer) {
|
||||
fColor = buffer.readColor();
|
||||
fMode = (SkXfermode::Mode)buffer.readUInt();
|
||||
this->updateCache();
|
||||
}
|
||||
|
||||
private:
|
||||
SkColor fColor;
|
||||
SkXfermode::Mode fMode;
|
||||
// cache
|
||||
SkPMColor fPMColor;
|
||||
SkXfermodeProc fProc;
|
||||
SkXfermodeProc16 fProc16;
|
||||
|
||||
void updateCache() {
|
||||
fPMColor = SkPreMultiplyColor(fColor);
|
||||
fProc = SkXfermode::GetProc(fMode);
|
||||
fProc16 = SkXfermode::GetProc16(fMode, fColor);
|
||||
}
|
||||
|
||||
typedef SkColorFilter INHERITED;
|
||||
};
|
||||
|
||||
class Src_SkModeColorFilter : public SkModeColorFilter {
|
||||
public:
|
||||
Src_SkModeColorFilter(SkColor color) : INHERITED(color, SkXfermode::kSrc_Mode) {}
|
||||
|
||||
virtual uint32_t getFlags() const SK_OVERRIDE {
|
||||
if (SkGetPackedA32(this->getPMColor()) == 0xFF) {
|
||||
return kAlphaUnchanged_Flag | kHasFilter16_Flag;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
virtual void filterSpan(const SkPMColor shader[], int count,
|
||||
SkPMColor result[]) const SK_OVERRIDE {
|
||||
sk_memset32(result, this->getPMColor(), count);
|
||||
}
|
||||
|
||||
virtual void filterSpan16(const uint16_t shader[], int count,
|
||||
uint16_t result[]) const SK_OVERRIDE {
|
||||
SkASSERT(this->getFlags() & kHasFilter16_Flag);
|
||||
sk_memset16(result, SkPixel32ToPixel16(this->getPMColor()), count);
|
||||
}
|
||||
|
||||
SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(Src_SkModeColorFilter)
|
||||
|
||||
protected:
|
||||
Src_SkModeColorFilter(SkFlattenableReadBuffer& buffer)
|
||||
: INHERITED(buffer) {}
|
||||
|
||||
private:
|
||||
typedef SkModeColorFilter INHERITED;
|
||||
};
|
||||
|
||||
class SrcOver_SkModeColorFilter : public SkModeColorFilter {
|
||||
public:
|
||||
SrcOver_SkModeColorFilter(SkColor color)
|
||||
: INHERITED(color, SkXfermode::kSrcOver_Mode) {
|
||||
fColor32Proc = SkBlitRow::ColorProcFactory();
|
||||
}
|
||||
|
||||
virtual uint32_t getFlags() const SK_OVERRIDE {
|
||||
if (SkGetPackedA32(this->getPMColor()) == 0xFF) {
|
||||
return kAlphaUnchanged_Flag | kHasFilter16_Flag;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
virtual void filterSpan(const SkPMColor shader[], int count,
|
||||
SkPMColor result[]) const SK_OVERRIDE {
|
||||
fColor32Proc(result, shader, count, this->getPMColor());
|
||||
}
|
||||
|
||||
virtual void filterSpan16(const uint16_t shader[], int count,
|
||||
uint16_t result[]) const SK_OVERRIDE {
|
||||
SkASSERT(this->getFlags() & kHasFilter16_Flag);
|
||||
sk_memset16(result, SkPixel32ToPixel16(this->getPMColor()), count);
|
||||
}
|
||||
|
||||
SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SrcOver_SkModeColorFilter)
|
||||
|
||||
protected:
|
||||
SrcOver_SkModeColorFilter(SkFlattenableReadBuffer& buffer)
|
||||
: INHERITED(buffer) {
|
||||
fColor32Proc = SkBlitRow::ColorProcFactory();
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
SkBlitRow::ColorProc fColor32Proc;
|
||||
|
||||
typedef SkModeColorFilter INHERITED;
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
SkColorFilter* SkColorFilter::CreateModeFilter(SkColor color,
|
||||
SkXfermode::Mode mode) {
|
||||
unsigned alpha = SkColorGetA(color);
|
||||
|
||||
// first collaps some modes if possible
|
||||
|
||||
if (SkXfermode::kClear_Mode == mode) {
|
||||
color = 0;
|
||||
mode = SkXfermode::kSrc_Mode;
|
||||
} else if (SkXfermode::kSrcOver_Mode == mode) {
|
||||
if (0 == alpha) {
|
||||
mode = SkXfermode::kDst_Mode;
|
||||
} else if (255 == alpha) {
|
||||
mode = SkXfermode::kSrc_Mode;
|
||||
}
|
||||
// else just stay srcover
|
||||
}
|
||||
|
||||
// weed out combinations that are noops, and just return null
|
||||
if (SkXfermode::kDst_Mode == mode ||
|
||||
(0 == alpha && (SkXfermode::kSrcOver_Mode == mode ||
|
||||
SkXfermode::kDstOver_Mode == mode ||
|
||||
SkXfermode::kDstOut_Mode == mode ||
|
||||
SkXfermode::kSrcATop_Mode == mode ||
|
||||
SkXfermode::kXor_Mode == mode ||
|
||||
SkXfermode::kDarken_Mode == mode)) ||
|
||||
(0xFF == alpha && SkXfermode::kDstIn_Mode == mode)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
switch (mode) {
|
||||
case SkXfermode::kSrc_Mode:
|
||||
return SkNEW_ARGS(Src_SkModeColorFilter, (color));
|
||||
case SkXfermode::kSrcOver_Mode:
|
||||
return SkNEW_ARGS(SrcOver_SkModeColorFilter, (color));
|
||||
default:
|
||||
return SkNEW_ARGS(SkModeColorFilter, (color, mode));
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static inline unsigned pin(unsigned value, unsigned max) {
|
||||
if (value > max) {
|
||||
value = max;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
class SkLightingColorFilter : public SkColorFilter {
|
||||
public:
|
||||
SkLightingColorFilter(SkColor mul, SkColor add) : fMul(mul), fAdd(add) {}
|
||||
|
||||
virtual void filterSpan(const SkPMColor shader[], int count,
|
||||
SkPMColor result[]) const SK_OVERRIDE {
|
||||
unsigned scaleR = SkAlpha255To256(SkColorGetR(fMul));
|
||||
unsigned scaleG = SkAlpha255To256(SkColorGetG(fMul));
|
||||
unsigned scaleB = SkAlpha255To256(SkColorGetB(fMul));
|
||||
|
||||
unsigned addR = SkColorGetR(fAdd);
|
||||
unsigned addG = SkColorGetG(fAdd);
|
||||
unsigned addB = SkColorGetB(fAdd);
|
||||
|
||||
for (int i = 0; i < count; i++) {
|
||||
SkPMColor c = shader[i];
|
||||
if (c) {
|
||||
unsigned a = SkGetPackedA32(c);
|
||||
unsigned scaleA = SkAlpha255To256(a);
|
||||
unsigned r = pin(SkAlphaMul(SkGetPackedR32(c), scaleR) + SkAlphaMul(addR, scaleA), a);
|
||||
unsigned g = pin(SkAlphaMul(SkGetPackedG32(c), scaleG) + SkAlphaMul(addG, scaleA), a);
|
||||
unsigned b = pin(SkAlphaMul(SkGetPackedB32(c), scaleB) + SkAlphaMul(addB, scaleA), a);
|
||||
c = SkPackARGB32(a, r, g, b);
|
||||
}
|
||||
result[i] = c;
|
||||
}
|
||||
}
|
||||
|
||||
SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkLightingColorFilter)
|
||||
|
||||
protected:
|
||||
virtual void flatten(SkFlattenableWriteBuffer& buffer) const SK_OVERRIDE {
|
||||
this->INHERITED::flatten(buffer);
|
||||
buffer.writeColor(fMul);
|
||||
buffer.writeColor(fAdd);
|
||||
}
|
||||
|
||||
SkLightingColorFilter(SkFlattenableReadBuffer& buffer) {
|
||||
fMul = buffer.readColor();
|
||||
fAdd = buffer.readColor();
|
||||
}
|
||||
|
||||
SkColor fMul, fAdd;
|
||||
|
||||
private:
|
||||
typedef SkColorFilter INHERITED;
|
||||
};
|
||||
|
||||
class SkLightingColorFilter_JustAdd : public SkLightingColorFilter {
|
||||
public:
|
||||
SkLightingColorFilter_JustAdd(SkColor mul, SkColor add)
|
||||
: INHERITED(mul, add) {}
|
||||
|
||||
virtual void filterSpan(const SkPMColor shader[], int count,
|
||||
SkPMColor result[]) const SK_OVERRIDE {
|
||||
unsigned addR = SkColorGetR(fAdd);
|
||||
unsigned addG = SkColorGetG(fAdd);
|
||||
unsigned addB = SkColorGetB(fAdd);
|
||||
|
||||
for (int i = 0; i < count; i++) {
|
||||
SkPMColor c = shader[i];
|
||||
if (c) {
|
||||
unsigned a = SkGetPackedA32(c);
|
||||
unsigned scaleA = SkAlpha255To256(a);
|
||||
unsigned r = pin(SkGetPackedR32(c) + SkAlphaMul(addR, scaleA), a);
|
||||
unsigned g = pin(SkGetPackedG32(c) + SkAlphaMul(addG, scaleA), a);
|
||||
unsigned b = pin(SkGetPackedB32(c) + SkAlphaMul(addB, scaleA), a);
|
||||
c = SkPackARGB32(a, r, g, b);
|
||||
}
|
||||
result[i] = c;
|
||||
}
|
||||
}
|
||||
|
||||
SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkLightingColorFilter_JustAdd)
|
||||
|
||||
protected:
|
||||
SkLightingColorFilter_JustAdd(SkFlattenableReadBuffer& buffer)
|
||||
: INHERITED(buffer) {}
|
||||
|
||||
private:
|
||||
typedef SkLightingColorFilter INHERITED;
|
||||
};
|
||||
|
||||
class SkLightingColorFilter_JustMul : public SkLightingColorFilter {
|
||||
public:
|
||||
SkLightingColorFilter_JustMul(SkColor mul, SkColor add)
|
||||
: INHERITED(mul, add) {}
|
||||
|
||||
virtual void filterSpan(const SkPMColor shader[], int count,
|
||||
SkPMColor result[]) const SK_OVERRIDE {
|
||||
unsigned scaleR = SkAlpha255To256(SkColorGetR(fMul));
|
||||
unsigned scaleG = SkAlpha255To256(SkColorGetG(fMul));
|
||||
unsigned scaleB = SkAlpha255To256(SkColorGetB(fMul));
|
||||
|
||||
for (int i = 0; i < count; i++) {
|
||||
SkPMColor c = shader[i];
|
||||
if (c) {
|
||||
unsigned a = SkGetPackedA32(c);
|
||||
unsigned r = SkAlphaMul(SkGetPackedR32(c), scaleR);
|
||||
unsigned g = SkAlphaMul(SkGetPackedG32(c), scaleG);
|
||||
unsigned b = SkAlphaMul(SkGetPackedB32(c), scaleB);
|
||||
c = SkPackARGB32(a, r, g, b);
|
||||
}
|
||||
result[i] = c;
|
||||
}
|
||||
}
|
||||
|
||||
SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkLightingColorFilter_JustMul)
|
||||
|
||||
protected:
|
||||
SkLightingColorFilter_JustMul(SkFlattenableReadBuffer& buffer)
|
||||
: INHERITED(buffer) {}
|
||||
|
||||
private:
|
||||
typedef SkLightingColorFilter INHERITED;
|
||||
};
|
||||
|
||||
class SkLightingColorFilter_SingleMul : public SkLightingColorFilter {
|
||||
public:
|
||||
SkLightingColorFilter_SingleMul(SkColor mul, SkColor add)
|
||||
: INHERITED(mul, add) {
|
||||
SkASSERT(SkColorGetR(add) == 0);
|
||||
SkASSERT(SkColorGetG(add) == 0);
|
||||
SkASSERT(SkColorGetB(add) == 0);
|
||||
SkASSERT(SkColorGetR(mul) == SkColorGetG(mul));
|
||||
SkASSERT(SkColorGetR(mul) == SkColorGetB(mul));
|
||||
}
|
||||
|
||||
virtual uint32_t getFlags() const SK_OVERRIDE {
|
||||
return this->INHERITED::getFlags() | (kAlphaUnchanged_Flag | kHasFilter16_Flag);
|
||||
}
|
||||
|
||||
virtual void filterSpan16(const uint16_t shader[], int count,
|
||||
uint16_t result[]) const SK_OVERRIDE {
|
||||
// all mul components are the same
|
||||
unsigned scale = SkAlpha255To256(SkColorGetR(fMul));
|
||||
|
||||
if (count > 0) {
|
||||
do {
|
||||
*result++ = SkAlphaMulRGB16(*shader++, scale);
|
||||
} while (--count > 0);
|
||||
}
|
||||
}
|
||||
|
||||
SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkLightingColorFilter_SingleMul)
|
||||
|
||||
protected:
|
||||
SkLightingColorFilter_SingleMul(SkFlattenableReadBuffer& buffer)
|
||||
: INHERITED(buffer) {}
|
||||
|
||||
private:
|
||||
typedef SkLightingColorFilter INHERITED;
|
||||
};
|
||||
|
||||
class SkLightingColorFilter_NoPin : public SkLightingColorFilter {
|
||||
public:
|
||||
SkLightingColorFilter_NoPin(SkColor mul, SkColor add)
|
||||
: INHERITED(mul, add) {}
|
||||
|
||||
virtual void filterSpan(const SkPMColor shader[], int count,
|
||||
SkPMColor result[]) const SK_OVERRIDE {
|
||||
unsigned scaleR = SkAlpha255To256(SkColorGetR(fMul));
|
||||
unsigned scaleG = SkAlpha255To256(SkColorGetG(fMul));
|
||||
unsigned scaleB = SkAlpha255To256(SkColorGetB(fMul));
|
||||
|
||||
unsigned addR = SkColorGetR(fAdd);
|
||||
unsigned addG = SkColorGetG(fAdd);
|
||||
unsigned addB = SkColorGetB(fAdd);
|
||||
|
||||
for (int i = 0; i < count; i++) {
|
||||
SkPMColor c = shader[i];
|
||||
if (c) {
|
||||
unsigned a = SkGetPackedA32(c);
|
||||
unsigned scaleA = SkAlpha255To256(a);
|
||||
unsigned r = SkAlphaMul(SkGetPackedR32(c), scaleR) + SkAlphaMul(addR, scaleA);
|
||||
unsigned g = SkAlphaMul(SkGetPackedG32(c), scaleG) + SkAlphaMul(addG, scaleA);
|
||||
unsigned b = SkAlphaMul(SkGetPackedB32(c), scaleB) + SkAlphaMul(addB, scaleA);
|
||||
c = SkPackARGB32(a, r, g, b);
|
||||
}
|
||||
result[i] = c;
|
||||
}
|
||||
}
|
||||
|
||||
SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkLightingColorFilter_NoPin)
|
||||
|
||||
protected:
|
||||
SkLightingColorFilter_NoPin(SkFlattenableReadBuffer& buffer)
|
||||
: INHERITED(buffer) {}
|
||||
|
||||
private:
|
||||
typedef SkLightingColorFilter INHERITED;
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class SkSimpleColorFilter : public SkColorFilter {
|
||||
public:
|
||||
static SkFlattenable* CreateProc(SkFlattenableReadBuffer& buffer) {
|
||||
return SkNEW(SkSimpleColorFilter);
|
||||
}
|
||||
|
||||
protected:
|
||||
void filterSpan(const SkPMColor src[], int count, SkPMColor
|
||||
result[]) const SK_OVERRIDE {
|
||||
if (result != src) {
|
||||
memcpy(result, src, count * sizeof(SkPMColor));
|
||||
}
|
||||
}
|
||||
|
||||
virtual void flatten(SkFlattenableWriteBuffer& buffer) const SK_OVERRIDE {}
|
||||
|
||||
virtual Factory getFactory() {
|
||||
return CreateProc;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
SkColorFilter* SkColorFilter::CreateLightingFilter(SkColor mul, SkColor add) {
|
||||
mul &= 0x00FFFFFF;
|
||||
add &= 0x00FFFFFF;
|
||||
|
||||
if (0xFFFFFF == mul) {
|
||||
if (0 == add) {
|
||||
return SkNEW(SkSimpleColorFilter); // no change to the colors
|
||||
} else {
|
||||
return SkNEW_ARGS(SkLightingColorFilter_JustAdd, (mul, add));
|
||||
}
|
||||
}
|
||||
|
||||
if (0 == add) {
|
||||
if (SkColorGetR(mul) == SkColorGetG(mul) &&
|
||||
SkColorGetR(mul) == SkColorGetB(mul)) {
|
||||
return SkNEW_ARGS(SkLightingColorFilter_SingleMul, (mul, add));
|
||||
} else {
|
||||
return SkNEW_ARGS(SkLightingColorFilter_JustMul, (mul, add));
|
||||
}
|
||||
}
|
||||
|
||||
if (SkColorGetR(mul) + SkColorGetR(add) <= 255 &&
|
||||
SkColorGetG(mul) + SkColorGetG(add) <= 255 &&
|
||||
SkColorGetB(mul) + SkColorGetB(add) <= 255) {
|
||||
return SkNEW_ARGS(SkLightingColorFilter_NoPin, (mul, add));
|
||||
}
|
||||
|
||||
return SkNEW_ARGS(SkLightingColorFilter, (mul, add));
|
||||
}
|
||||
|
||||
SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkColorFilter)
|
||||
SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkModeColorFilter)
|
||||
SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(Src_SkModeColorFilter)
|
||||
SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SrcOver_SkModeColorFilter)
|
||||
SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkLightingColorFilter)
|
||||
SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkLightingColorFilter_JustAdd)
|
||||
SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkLightingColorFilter_JustMul)
|
||||
SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkLightingColorFilter_SingleMul)
|
||||
SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkLightingColorFilter_NoPin)
|
||||
SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkSimpleColorFilter)
|
||||
SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END
|
|
@ -1,46 +0,0 @@
|
|||
/*
|
||||
* Copyright 2013 The Android Open Source Project
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include "SkMatrix.h"
|
||||
|
||||
#if SK_SUPPORT_GPU
|
||||
#include "GrTexture.h"
|
||||
#include "SkImageFilterUtils.h"
|
||||
#include "SkBitmap.h"
|
||||
#include "SkGrPixelRef.h"
|
||||
#include "SkGr.h"
|
||||
|
||||
bool SkImageFilterUtils::WrapTexture(GrTexture* texture, int width, int height, SkBitmap* result) {
|
||||
SkASSERT(texture->config() == kSkia8888_GrPixelConfig);
|
||||
result->setConfig(SkBitmap::kARGB_8888_Config, width, height);
|
||||
result->setPixelRef(SkNEW_ARGS(SkGrPixelRef, (texture)))->unref();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SkImageFilterUtils::GetInputResultGPU(SkImageFilter* filter, SkImageFilter::Proxy* proxy, const SkBitmap& src, SkBitmap* result) {
|
||||
if (!filter) {
|
||||
*result = src;
|
||||
return true;
|
||||
} else if (filter->canFilterImageGPU()) {
|
||||
return filter->filterImageGPU(proxy, src, result);
|
||||
} else {
|
||||
SkIPoint offset;
|
||||
if (filter->filterImage(proxy, src, SkMatrix(), result, &offset)) {
|
||||
if (!result->getTexture()) {
|
||||
GrContext* context = ((GrTexture *) src.getTexture())->getContext();
|
||||
GrTexture* resultTex = GrLockAndRefCachedBitmapTexture(context,
|
||||
*result, NULL);
|
||||
result->setPixelRef(new SkGrPixelRef(resultTex))->unref();
|
||||
GrUnlockAndUnrefCachedBitmapTexture(resultTex);
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
|
@ -1,49 +0,0 @@
|
|||
/*
|
||||
* Copyright 2012 The Android Open Source Project
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include "SkOffsetImageFilter.h"
|
||||
#include "SkBitmap.h"
|
||||
#include "SkMatrix.h"
|
||||
#include "SkFlattenableBuffers.h"
|
||||
|
||||
bool SkOffsetImageFilter::onFilterImage(Proxy* proxy, const SkBitmap& source,
|
||||
const SkMatrix& matrix,
|
||||
SkBitmap* result,
|
||||
SkIPoint* loc) {
|
||||
SkBitmap src = this->getInputResult(0, proxy, source, matrix, loc);
|
||||
SkVector vec;
|
||||
matrix.mapVectors(&vec, &fOffset, 1);
|
||||
|
||||
loc->fX += SkScalarRoundToInt(vec.fX);
|
||||
loc->fY += SkScalarRoundToInt(vec.fY);
|
||||
*result = src;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SkOffsetImageFilter::onFilterBounds(const SkIRect& src, const SkMatrix& ctm,
|
||||
SkIRect* dst) {
|
||||
SkVector vec;
|
||||
ctm.mapVectors(&vec, &fOffset, 1);
|
||||
|
||||
*dst = src;
|
||||
dst->offset(SkScalarRoundToInt(vec.fX), SkScalarRoundToInt(vec.fY));
|
||||
return true;
|
||||
}
|
||||
|
||||
void SkOffsetImageFilter::flatten(SkFlattenableWriteBuffer& buffer) const {
|
||||
this->INHERITED::flatten(buffer);
|
||||
buffer.writePoint(fOffset);
|
||||
}
|
||||
|
||||
SkOffsetImageFilter::SkOffsetImageFilter(SkScalar dx, SkScalar dy,
|
||||
SkImageFilter* input) : INHERITED(input) {
|
||||
fOffset.set(dx, dy);
|
||||
}
|
||||
|
||||
SkOffsetImageFilter::SkOffsetImageFilter(SkFlattenableReadBuffer& buffer) : INHERITED(buffer) {
|
||||
buffer.readPoint(&fOffset);
|
||||
}
|
|
@ -1,58 +0,0 @@
|
|||
/*
|
||||
* Copyright 2013 Google Inc.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include "SkRectShaderImageFilter.h"
|
||||
#include "SkBitmap.h"
|
||||
#include "SkCanvas.h"
|
||||
#include "SkDevice.h"
|
||||
#include "SkFlattenableBuffers.h"
|
||||
#include "SkShader.h"
|
||||
|
||||
SkRectShaderImageFilter* SkRectShaderImageFilter::Create(SkShader* s, const SkRect& rect) {
|
||||
SkASSERT(s);
|
||||
return SkNEW_ARGS(SkRectShaderImageFilter, (s, rect));
|
||||
}
|
||||
|
||||
SkRectShaderImageFilter::SkRectShaderImageFilter(SkShader* s, const SkRect& rect)
|
||||
: INHERITED(NULL)
|
||||
, fShader(s)
|
||||
, fRect(rect) {
|
||||
SkASSERT(s);
|
||||
s->ref();
|
||||
}
|
||||
|
||||
SkRectShaderImageFilter::SkRectShaderImageFilter(SkFlattenableReadBuffer& buffer)
|
||||
: INHERITED(buffer) {
|
||||
fShader = buffer.readFlattenableT<SkShader>();
|
||||
buffer.readRect(&fRect);
|
||||
}
|
||||
|
||||
void SkRectShaderImageFilter::flatten(SkFlattenableWriteBuffer& buffer) const {
|
||||
this->INHERITED::flatten(buffer);
|
||||
|
||||
buffer.writeFlattenable(fShader);
|
||||
buffer.writeRect(fRect);
|
||||
}
|
||||
|
||||
SkRectShaderImageFilter::~SkRectShaderImageFilter() {
|
||||
SkSafeUnref(fShader);
|
||||
}
|
||||
|
||||
bool SkRectShaderImageFilter::onFilterImage(Proxy* proxy,
|
||||
const SkBitmap& source,
|
||||
const SkMatrix& matrix,
|
||||
SkBitmap* result,
|
||||
SkIPoint* loc) {
|
||||
SkAutoTUnref<SkDevice> device(proxy->createDevice(SkScalarCeilToInt(fRect.width()),
|
||||
SkScalarCeilToInt(fRect.height())));
|
||||
SkCanvas canvas(device.get());
|
||||
SkPaint paint;
|
||||
paint.setShader(fShader);
|
||||
canvas.drawRect(fRect, paint);
|
||||
*result = device.get()->accessBitmap(false);
|
||||
return true;
|
||||
}
|
|
@ -1,129 +0,0 @@
|
|||
|
||||
#include "SkTestImageFilters.h"
|
||||
#include "SkCanvas.h"
|
||||
#include "SkDevice.h"
|
||||
#include "SkFlattenableBuffers.h"
|
||||
|
||||
// Simple helper canvas that "takes ownership" of the provided device, so that
|
||||
// when this canvas goes out of scope, so will its device. Could be replaced
|
||||
// with the following:
|
||||
//
|
||||
// SkCanvas canvas(device);
|
||||
// SkAutoTUnref<SkDevice> aur(device);
|
||||
//
|
||||
class OwnDeviceCanvas : public SkCanvas {
|
||||
public:
|
||||
OwnDeviceCanvas(SkDevice* device) : SkCanvas(device) {
|
||||
SkSafeUnref(device);
|
||||
}
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
SkComposeImageFilter::~SkComposeImageFilter() {
|
||||
}
|
||||
|
||||
bool SkComposeImageFilter::onFilterImage(Proxy* proxy,
|
||||
const SkBitmap& src,
|
||||
const SkMatrix& ctm,
|
||||
SkBitmap* result,
|
||||
SkIPoint* loc) {
|
||||
SkImageFilter* outer = getInput(0);
|
||||
SkImageFilter* inner = getInput(1);
|
||||
|
||||
if (!outer && !inner) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!outer || !inner) {
|
||||
return (outer ? outer : inner)->filterImage(proxy, src, ctm, result, loc);
|
||||
}
|
||||
|
||||
SkBitmap tmp;
|
||||
return inner->filterImage(proxy, src, ctm, &tmp, loc) &&
|
||||
outer->filterImage(proxy, tmp, ctm, result, loc);
|
||||
}
|
||||
|
||||
bool SkComposeImageFilter::onFilterBounds(const SkIRect& src,
|
||||
const SkMatrix& ctm,
|
||||
SkIRect* dst) {
|
||||
SkImageFilter* outer = getInput(0);
|
||||
SkImageFilter* inner = getInput(1);
|
||||
|
||||
if (!outer && !inner) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!outer || !inner) {
|
||||
return (outer ? outer : inner)->filterBounds(src, ctm, dst);
|
||||
}
|
||||
|
||||
SkIRect tmp;
|
||||
return inner->filterBounds(src, ctm, &tmp) &&
|
||||
outer->filterBounds(tmp, ctm, dst);
|
||||
}
|
||||
|
||||
SkComposeImageFilter::SkComposeImageFilter(SkFlattenableReadBuffer& buffer) : INHERITED(buffer) {
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool SkDownSampleImageFilter::onFilterImage(Proxy* proxy, const SkBitmap& src,
|
||||
const SkMatrix&,
|
||||
SkBitmap* result, SkIPoint*) {
|
||||
SkScalar scale = fScale;
|
||||
if (scale > SK_Scalar1 || scale <= 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int dstW = SkScalarRoundToInt(src.width() * scale);
|
||||
int dstH = SkScalarRoundToInt(src.height() * scale);
|
||||
if (dstW < 1) {
|
||||
dstW = 1;
|
||||
}
|
||||
if (dstH < 1) {
|
||||
dstH = 1;
|
||||
}
|
||||
|
||||
SkBitmap tmp;
|
||||
|
||||
// downsample
|
||||
{
|
||||
SkDevice* dev = proxy->createDevice(dstW, dstH);
|
||||
if (NULL == dev) {
|
||||
return false;
|
||||
}
|
||||
OwnDeviceCanvas canvas(dev);
|
||||
SkPaint paint;
|
||||
|
||||
paint.setFilterBitmap(true);
|
||||
canvas.scale(scale, scale);
|
||||
canvas.drawBitmap(src, 0, 0, &paint);
|
||||
tmp = dev->accessBitmap(false);
|
||||
}
|
||||
|
||||
// upscale
|
||||
{
|
||||
SkDevice* dev = proxy->createDevice(src.width(), src.height());
|
||||
if (NULL == dev) {
|
||||
return false;
|
||||
}
|
||||
OwnDeviceCanvas canvas(dev);
|
||||
|
||||
SkRect r = SkRect::MakeWH(SkIntToScalar(src.width()),
|
||||
SkIntToScalar(src.height()));
|
||||
canvas.drawBitmapRect(tmp, NULL, r, NULL);
|
||||
*result = dev->accessBitmap(false);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void SkDownSampleImageFilter::flatten(SkFlattenableWriteBuffer& buffer) const {
|
||||
this->INHERITED::flatten(buffer);
|
||||
|
||||
buffer.writeScalar(fScale);
|
||||
}
|
||||
|
||||
SkDownSampleImageFilter::SkDownSampleImageFilter(SkFlattenableReadBuffer& buffer) : INHERITED(buffer) {
|
||||
fScale = buffer.readScalar();
|
||||
}
|
|
@ -1,38 +0,0 @@
|
|||
/*
|
||||
* 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 "SkGradientShaderPriv.h"
|
||||
|
||||
// Clamp
|
||||
|
||||
SkFixed clamp_tileproc(SkFixed x) {
|
||||
return SkClampMax(x, 0xFFFF);
|
||||
}
|
||||
|
||||
// Repeat
|
||||
|
||||
SkFixed repeat_tileproc(SkFixed x) {
|
||||
return x & 0xFFFF;
|
||||
}
|
||||
|
||||
// Mirror
|
||||
|
||||
// Visual Studio 2010 (MSC_VER=1600) optimizes bit-shift code incorrectly.
|
||||
// See http://code.google.com/p/skia/issues/detail?id=472
|
||||
#if defined(_MSC_VER) && (_MSC_VER >= 1600)
|
||||
#pragma optimize("", off)
|
||||
#endif
|
||||
|
||||
SkFixed mirror_tileproc(SkFixed x) {
|
||||
int s = x << 15 >> 31;
|
||||
return (x ^ s) & 0xFFFF;
|
||||
}
|
||||
|
||||
#if defined(_MSC_VER) && (_MSC_VER >= 1600)
|
||||
#pragma optimize("", on)
|
||||
#endif
|
||||
|
|
@ -1,849 +0,0 @@
|
|||
|
||||
/*
|
||||
* Copyright 2011 Google Inc.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include "GrAAHairLinePathRenderer.h"
|
||||
|
||||
#include "GrContext.h"
|
||||
#include "GrDrawState.h"
|
||||
#include "GrDrawTargetCaps.h"
|
||||
#include "GrEffect.h"
|
||||
#include "GrGpu.h"
|
||||
#include "GrIndexBuffer.h"
|
||||
#include "GrPathUtils.h"
|
||||
#include "GrTBackendEffectFactory.h"
|
||||
#include "SkGeometry.h"
|
||||
#include "SkStroke.h"
|
||||
#include "SkTemplates.h"
|
||||
|
||||
#include "gl/GrGLEffect.h"
|
||||
#include "gl/GrGLSL.h"
|
||||
|
||||
namespace {
|
||||
// quadratics are rendered as 5-sided polys in order to bound the
|
||||
// AA stroke around the center-curve. See comments in push_quad_index_buffer and
|
||||
// bloat_quad.
|
||||
static const int kVertsPerQuad = 5;
|
||||
static const int kIdxsPerQuad = 9;
|
||||
|
||||
static const int kVertsPerLineSeg = 4;
|
||||
static const int kIdxsPerLineSeg = 6;
|
||||
|
||||
static const int kNumQuadsInIdxBuffer = 256;
|
||||
static const size_t kQuadIdxSBufize = kIdxsPerQuad *
|
||||
sizeof(uint16_t) *
|
||||
kNumQuadsInIdxBuffer;
|
||||
|
||||
bool push_quad_index_data(GrIndexBuffer* qIdxBuffer) {
|
||||
uint16_t* data = (uint16_t*) qIdxBuffer->lock();
|
||||
bool tempData = NULL == data;
|
||||
if (tempData) {
|
||||
data = SkNEW_ARRAY(uint16_t, kNumQuadsInIdxBuffer * kIdxsPerQuad);
|
||||
}
|
||||
for (int i = 0; i < kNumQuadsInIdxBuffer; ++i) {
|
||||
|
||||
// Each quadratic is rendered as a five sided polygon. This poly bounds
|
||||
// the quadratic's bounding triangle but has been expanded so that the
|
||||
// 1-pixel wide area around the curve is inside the poly.
|
||||
// If a,b,c are the original control points then the poly a0,b0,c0,c1,a1
|
||||
// that is rendered would look like this:
|
||||
// b0
|
||||
// b
|
||||
//
|
||||
// a0 c0
|
||||
// a c
|
||||
// a1 c1
|
||||
// Each is drawn as three triangles specified by these 9 indices:
|
||||
int baseIdx = i * kIdxsPerQuad;
|
||||
uint16_t baseVert = (uint16_t)(i * kVertsPerQuad);
|
||||
data[0 + baseIdx] = baseVert + 0; // a0
|
||||
data[1 + baseIdx] = baseVert + 1; // a1
|
||||
data[2 + baseIdx] = baseVert + 2; // b0
|
||||
data[3 + baseIdx] = baseVert + 2; // b0
|
||||
data[4 + baseIdx] = baseVert + 4; // c1
|
||||
data[5 + baseIdx] = baseVert + 3; // c0
|
||||
data[6 + baseIdx] = baseVert + 1; // a1
|
||||
data[7 + baseIdx] = baseVert + 4; // c1
|
||||
data[8 + baseIdx] = baseVert + 2; // b0
|
||||
}
|
||||
if (tempData) {
|
||||
bool ret = qIdxBuffer->updateData(data, kQuadIdxSBufize);
|
||||
delete[] data;
|
||||
return ret;
|
||||
} else {
|
||||
qIdxBuffer->unlock();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GrPathRenderer* GrAAHairLinePathRenderer::Create(GrContext* context) {
|
||||
const GrIndexBuffer* lIdxBuffer = context->getQuadIndexBuffer();
|
||||
if (NULL == lIdxBuffer) {
|
||||
return NULL;
|
||||
}
|
||||
GrGpu* gpu = context->getGpu();
|
||||
GrIndexBuffer* qIdxBuf = gpu->createIndexBuffer(kQuadIdxSBufize, false);
|
||||
SkAutoTUnref<GrIndexBuffer> qIdxBuffer(qIdxBuf);
|
||||
if (NULL == qIdxBuf ||
|
||||
!push_quad_index_data(qIdxBuf)) {
|
||||
return NULL;
|
||||
}
|
||||
return SkNEW_ARGS(GrAAHairLinePathRenderer,
|
||||
(context, lIdxBuffer, qIdxBuf));
|
||||
}
|
||||
|
||||
GrAAHairLinePathRenderer::GrAAHairLinePathRenderer(
|
||||
const GrContext* context,
|
||||
const GrIndexBuffer* linesIndexBuffer,
|
||||
const GrIndexBuffer* quadsIndexBuffer) {
|
||||
fLinesIndexBuffer = linesIndexBuffer;
|
||||
linesIndexBuffer->ref();
|
||||
fQuadsIndexBuffer = quadsIndexBuffer;
|
||||
quadsIndexBuffer->ref();
|
||||
}
|
||||
|
||||
GrAAHairLinePathRenderer::~GrAAHairLinePathRenderer() {
|
||||
fLinesIndexBuffer->unref();
|
||||
fQuadsIndexBuffer->unref();
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
typedef SkTArray<SkPoint, true> PtArray;
|
||||
#define PREALLOC_PTARRAY(N) SkSTArray<(N),SkPoint, true>
|
||||
typedef SkTArray<int, true> IntArray;
|
||||
|
||||
// Takes 178th time of logf on Z600 / VC2010
|
||||
int get_float_exp(float x) {
|
||||
GR_STATIC_ASSERT(sizeof(int) == sizeof(float));
|
||||
#if GR_DEBUG
|
||||
static bool tested;
|
||||
if (!tested) {
|
||||
tested = true;
|
||||
GrAssert(get_float_exp(0.25f) == -2);
|
||||
GrAssert(get_float_exp(0.3f) == -2);
|
||||
GrAssert(get_float_exp(0.5f) == -1);
|
||||
GrAssert(get_float_exp(1.f) == 0);
|
||||
GrAssert(get_float_exp(2.f) == 1);
|
||||
GrAssert(get_float_exp(2.5f) == 1);
|
||||
GrAssert(get_float_exp(8.f) == 3);
|
||||
GrAssert(get_float_exp(100.f) == 6);
|
||||
GrAssert(get_float_exp(1000.f) == 9);
|
||||
GrAssert(get_float_exp(1024.f) == 10);
|
||||
GrAssert(get_float_exp(3000000.f) == 21);
|
||||
}
|
||||
#endif
|
||||
const int* iptr = (const int*)&x;
|
||||
return (((*iptr) & 0x7f800000) >> 23) - 127;
|
||||
}
|
||||
|
||||
// we subdivide the quads to avoid huge overfill
|
||||
// if it returns -1 then should be drawn as lines
|
||||
int num_quad_subdivs(const SkPoint p[3]) {
|
||||
static const SkScalar gDegenerateToLineTol = SK_Scalar1;
|
||||
static const SkScalar gDegenerateToLineTolSqd =
|
||||
SkScalarMul(gDegenerateToLineTol, gDegenerateToLineTol);
|
||||
|
||||
if (p[0].distanceToSqd(p[1]) < gDegenerateToLineTolSqd ||
|
||||
p[1].distanceToSqd(p[2]) < gDegenerateToLineTolSqd) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
SkScalar dsqd = p[1].distanceToLineBetweenSqd(p[0], p[2]);
|
||||
if (dsqd < gDegenerateToLineTolSqd) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (p[2].distanceToLineBetweenSqd(p[1], p[0]) < gDegenerateToLineTolSqd) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
// tolerance of triangle height in pixels
|
||||
// tuned on windows Quadro FX 380 / Z600
|
||||
// trade off of fill vs cpu time on verts
|
||||
// maybe different when do this using gpu (geo or tess shaders)
|
||||
static const SkScalar gSubdivTol = 175 * SK_Scalar1;
|
||||
|
||||
if (dsqd <= SkScalarMul(gSubdivTol, gSubdivTol)) {
|
||||
return 0;
|
||||
} else {
|
||||
static const int kMaxSub = 4;
|
||||
// subdividing the quad reduces d by 4. so we want x = log4(d/tol)
|
||||
// = log4(d*d/tol*tol)/2
|
||||
// = log2(d*d/tol*tol)
|
||||
|
||||
#ifdef SK_SCALAR_IS_FLOAT
|
||||
// +1 since we're ignoring the mantissa contribution.
|
||||
int log = get_float_exp(dsqd/(gSubdivTol*gSubdivTol)) + 1;
|
||||
log = GrMin(GrMax(0, log), kMaxSub);
|
||||
return log;
|
||||
#else
|
||||
SkScalar log = SkScalarLog(
|
||||
SkScalarDiv(dsqd,
|
||||
SkScalarMul(gSubdivTol, gSubdivTol)));
|
||||
static const SkScalar conv = SkScalarInvert(SkScalarLog(2));
|
||||
log = SkScalarMul(log, conv);
|
||||
return GrMin(GrMax(0, SkScalarCeilToInt(log)),kMaxSub);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates the lines and quads to be rendered. Lines are always recorded in
|
||||
* device space. We will do a device space bloat to account for the 1pixel
|
||||
* thickness.
|
||||
* Quads are recorded in device space unless m contains
|
||||
* perspective, then in they are in src space. We do this because we will
|
||||
* subdivide large quads to reduce over-fill. This subdivision has to be
|
||||
* performed before applying the perspective matrix.
|
||||
*/
|
||||
int generate_lines_and_quads(const SkPath& path,
|
||||
const SkMatrix& m,
|
||||
const GrIRect& devClipBounds,
|
||||
PtArray* lines,
|
||||
PtArray* quads,
|
||||
IntArray* quadSubdivCnts) {
|
||||
SkPath::Iter iter(path, false);
|
||||
|
||||
int totalQuadCount = 0;
|
||||
GrRect bounds;
|
||||
GrIRect ibounds;
|
||||
|
||||
bool persp = m.hasPerspective();
|
||||
|
||||
for (;;) {
|
||||
GrPoint pts[4];
|
||||
GrPoint devPts[4];
|
||||
GrPathCmd cmd = (GrPathCmd)iter.next(pts);
|
||||
switch (cmd) {
|
||||
case kMove_PathCmd:
|
||||
break;
|
||||
case kLine_PathCmd:
|
||||
m.mapPoints(devPts, pts, 2);
|
||||
bounds.setBounds(devPts, 2);
|
||||
bounds.outset(SK_Scalar1, SK_Scalar1);
|
||||
bounds.roundOut(&ibounds);
|
||||
if (SkIRect::Intersects(devClipBounds, ibounds)) {
|
||||
SkPoint* pts = lines->push_back_n(2);
|
||||
pts[0] = devPts[0];
|
||||
pts[1] = devPts[1];
|
||||
}
|
||||
break;
|
||||
case kQuadratic_PathCmd:
|
||||
m.mapPoints(devPts, pts, 3);
|
||||
bounds.setBounds(devPts, 3);
|
||||
bounds.outset(SK_Scalar1, SK_Scalar1);
|
||||
bounds.roundOut(&ibounds);
|
||||
if (SkIRect::Intersects(devClipBounds, ibounds)) {
|
||||
int subdiv = num_quad_subdivs(devPts);
|
||||
GrAssert(subdiv >= -1);
|
||||
if (-1 == subdiv) {
|
||||
SkPoint* pts = lines->push_back_n(4);
|
||||
pts[0] = devPts[0];
|
||||
pts[1] = devPts[1];
|
||||
pts[2] = devPts[1];
|
||||
pts[3] = devPts[2];
|
||||
} else {
|
||||
// when in perspective keep quads in src space
|
||||
SkPoint* qPts = persp ? pts : devPts;
|
||||
SkPoint* pts = quads->push_back_n(3);
|
||||
pts[0] = qPts[0];
|
||||
pts[1] = qPts[1];
|
||||
pts[2] = qPts[2];
|
||||
quadSubdivCnts->push_back() = subdiv;
|
||||
totalQuadCount += 1 << subdiv;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case kCubic_PathCmd:
|
||||
m.mapPoints(devPts, pts, 4);
|
||||
bounds.setBounds(devPts, 4);
|
||||
bounds.outset(SK_Scalar1, SK_Scalar1);
|
||||
bounds.roundOut(&ibounds);
|
||||
if (SkIRect::Intersects(devClipBounds, ibounds)) {
|
||||
PREALLOC_PTARRAY(32) q;
|
||||
// we don't need a direction if we aren't constraining the subdivision
|
||||
static const SkPath::Direction kDummyDir = SkPath::kCCW_Direction;
|
||||
// We convert cubics to quadratics (for now).
|
||||
// In perspective have to do conversion in src space.
|
||||
if (persp) {
|
||||
SkScalar tolScale =
|
||||
GrPathUtils::scaleToleranceToSrc(SK_Scalar1, m,
|
||||
path.getBounds());
|
||||
GrPathUtils::convertCubicToQuads(pts, tolScale, false, kDummyDir, &q);
|
||||
} else {
|
||||
GrPathUtils::convertCubicToQuads(devPts, SK_Scalar1, false, kDummyDir, &q);
|
||||
}
|
||||
for (int i = 0; i < q.count(); i += 3) {
|
||||
SkPoint* qInDevSpace;
|
||||
// bounds has to be calculated in device space, but q is
|
||||
// in src space when there is perspective.
|
||||
if (persp) {
|
||||
m.mapPoints(devPts, &q[i], 3);
|
||||
bounds.setBounds(devPts, 3);
|
||||
qInDevSpace = devPts;
|
||||
} else {
|
||||
bounds.setBounds(&q[i], 3);
|
||||
qInDevSpace = &q[i];
|
||||
}
|
||||
bounds.outset(SK_Scalar1, SK_Scalar1);
|
||||
bounds.roundOut(&ibounds);
|
||||
if (SkIRect::Intersects(devClipBounds, ibounds)) {
|
||||
int subdiv = num_quad_subdivs(qInDevSpace);
|
||||
GrAssert(subdiv >= -1);
|
||||
if (-1 == subdiv) {
|
||||
SkPoint* pts = lines->push_back_n(4);
|
||||
// lines should always be in device coords
|
||||
pts[0] = qInDevSpace[0];
|
||||
pts[1] = qInDevSpace[1];
|
||||
pts[2] = qInDevSpace[1];
|
||||
pts[3] = qInDevSpace[2];
|
||||
} else {
|
||||
SkPoint* pts = quads->push_back_n(3);
|
||||
// q is already in src space when there is no
|
||||
// perspective and dev coords otherwise.
|
||||
pts[0] = q[0 + i];
|
||||
pts[1] = q[1 + i];
|
||||
pts[2] = q[2 + i];
|
||||
quadSubdivCnts->push_back() = subdiv;
|
||||
totalQuadCount += 1 << subdiv;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case kClose_PathCmd:
|
||||
break;
|
||||
case kEnd_PathCmd:
|
||||
return totalQuadCount;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct Vertex {
|
||||
GrPoint fPos;
|
||||
union {
|
||||
struct {
|
||||
SkScalar fA;
|
||||
SkScalar fB;
|
||||
SkScalar fC;
|
||||
} fLine;
|
||||
GrVec fQuadCoord;
|
||||
struct {
|
||||
SkScalar fBogus[4];
|
||||
};
|
||||
};
|
||||
};
|
||||
GR_STATIC_ASSERT(sizeof(Vertex) == 3 * sizeof(GrPoint));
|
||||
|
||||
void intersect_lines(const SkPoint& ptA, const SkVector& normA,
|
||||
const SkPoint& ptB, const SkVector& normB,
|
||||
SkPoint* result) {
|
||||
|
||||
SkScalar lineAW = -normA.dot(ptA);
|
||||
SkScalar lineBW = -normB.dot(ptB);
|
||||
|
||||
SkScalar wInv = SkScalarMul(normA.fX, normB.fY) -
|
||||
SkScalarMul(normA.fY, normB.fX);
|
||||
wInv = SkScalarInvert(wInv);
|
||||
|
||||
result->fX = SkScalarMul(normA.fY, lineBW) - SkScalarMul(lineAW, normB.fY);
|
||||
result->fX = SkScalarMul(result->fX, wInv);
|
||||
|
||||
result->fY = SkScalarMul(lineAW, normB.fX) - SkScalarMul(normA.fX, lineBW);
|
||||
result->fY = SkScalarMul(result->fY, wInv);
|
||||
}
|
||||
|
||||
void bloat_quad(const SkPoint qpts[3], const SkMatrix* toDevice,
|
||||
const SkMatrix* toSrc, Vertex verts[kVertsPerQuad]) {
|
||||
GrAssert(!toDevice == !toSrc);
|
||||
// original quad is specified by tri a,b,c
|
||||
SkPoint a = qpts[0];
|
||||
SkPoint b = qpts[1];
|
||||
SkPoint c = qpts[2];
|
||||
|
||||
// this should be in the src space, not dev coords, when we have perspective
|
||||
GrPathUtils::QuadUVMatrix DevToUV(qpts);
|
||||
|
||||
if (toDevice) {
|
||||
toDevice->mapPoints(&a, 1);
|
||||
toDevice->mapPoints(&b, 1);
|
||||
toDevice->mapPoints(&c, 1);
|
||||
}
|
||||
// make a new poly where we replace a and c by a 1-pixel wide edges orthog
|
||||
// to edges ab and bc:
|
||||
//
|
||||
// before | after
|
||||
// | b0
|
||||
// b |
|
||||
// |
|
||||
// | a0 c0
|
||||
// a c | a1 c1
|
||||
//
|
||||
// edges a0->b0 and b0->c0 are parallel to original edges a->b and b->c,
|
||||
// respectively.
|
||||
Vertex& a0 = verts[0];
|
||||
Vertex& a1 = verts[1];
|
||||
Vertex& b0 = verts[2];
|
||||
Vertex& c0 = verts[3];
|
||||
Vertex& c1 = verts[4];
|
||||
|
||||
SkVector ab = b;
|
||||
ab -= a;
|
||||
SkVector ac = c;
|
||||
ac -= a;
|
||||
SkVector cb = b;
|
||||
cb -= c;
|
||||
|
||||
// We should have already handled degenerates
|
||||
GrAssert(ab.length() > 0 && cb.length() > 0);
|
||||
|
||||
ab.normalize();
|
||||
SkVector abN;
|
||||
abN.setOrthog(ab, SkVector::kLeft_Side);
|
||||
if (abN.dot(ac) > 0) {
|
||||
abN.negate();
|
||||
}
|
||||
|
||||
cb.normalize();
|
||||
SkVector cbN;
|
||||
cbN.setOrthog(cb, SkVector::kLeft_Side);
|
||||
if (cbN.dot(ac) < 0) {
|
||||
cbN.negate();
|
||||
}
|
||||
|
||||
a0.fPos = a;
|
||||
a0.fPos += abN;
|
||||
a1.fPos = a;
|
||||
a1.fPos -= abN;
|
||||
|
||||
c0.fPos = c;
|
||||
c0.fPos += cbN;
|
||||
c1.fPos = c;
|
||||
c1.fPos -= cbN;
|
||||
|
||||
intersect_lines(a0.fPos, abN, c0.fPos, cbN, &b0.fPos);
|
||||
|
||||
if (toSrc) {
|
||||
toSrc->mapPointsWithStride(&verts[0].fPos, sizeof(Vertex), kVertsPerQuad);
|
||||
}
|
||||
DevToUV.apply<kVertsPerQuad, sizeof(Vertex), sizeof(GrPoint)>(verts);
|
||||
}
|
||||
|
||||
void add_quads(const SkPoint p[3],
|
||||
int subdiv,
|
||||
const SkMatrix* toDevice,
|
||||
const SkMatrix* toSrc,
|
||||
Vertex** vert) {
|
||||
GrAssert(subdiv >= 0);
|
||||
if (subdiv) {
|
||||
SkPoint newP[5];
|
||||
SkChopQuadAtHalf(p, newP);
|
||||
add_quads(newP + 0, subdiv-1, toDevice, toSrc, vert);
|
||||
add_quads(newP + 2, subdiv-1, toDevice, toSrc, vert);
|
||||
} else {
|
||||
bloat_quad(p, toDevice, toSrc, *vert);
|
||||
*vert += kVertsPerQuad;
|
||||
}
|
||||
}
|
||||
|
||||
void add_line(const SkPoint p[2],
|
||||
int rtHeight,
|
||||
const SkMatrix* toSrc,
|
||||
Vertex** vert) {
|
||||
const SkPoint& a = p[0];
|
||||
const SkPoint& b = p[1];
|
||||
|
||||
SkVector orthVec = b;
|
||||
orthVec -= a;
|
||||
|
||||
if (orthVec.setLength(SK_Scalar1)) {
|
||||
orthVec.setOrthog(orthVec);
|
||||
|
||||
SkScalar lineC = -(a.dot(orthVec));
|
||||
for (int i = 0; i < kVertsPerLineSeg; ++i) {
|
||||
(*vert)[i].fPos = (i < 2) ? a : b;
|
||||
if (0 == i || 3 == i) {
|
||||
(*vert)[i].fPos -= orthVec;
|
||||
} else {
|
||||
(*vert)[i].fPos += orthVec;
|
||||
}
|
||||
(*vert)[i].fLine.fA = orthVec.fX;
|
||||
(*vert)[i].fLine.fB = orthVec.fY;
|
||||
(*vert)[i].fLine.fC = lineC;
|
||||
}
|
||||
if (NULL != toSrc) {
|
||||
toSrc->mapPointsWithStride(&(*vert)->fPos,
|
||||
sizeof(Vertex),
|
||||
kVertsPerLineSeg);
|
||||
}
|
||||
} else {
|
||||
// just make it degenerate and likely offscreen
|
||||
(*vert)[0].fPos.set(SK_ScalarMax, SK_ScalarMax);
|
||||
(*vert)[1].fPos.set(SK_ScalarMax, SK_ScalarMax);
|
||||
(*vert)[2].fPos.set(SK_ScalarMax, SK_ScalarMax);
|
||||
(*vert)[3].fPos.set(SK_ScalarMax, SK_ScalarMax);
|
||||
}
|
||||
|
||||
*vert += kVertsPerLineSeg;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/**
|
||||
* The output of this effect is a hairline edge for quadratics.
|
||||
* Quadratic specified by 0=u^2-v canonical coords. u and v are the first
|
||||
* two components of the vertex attribute. Uses unsigned distance.
|
||||
* Coverage is min(0, 1-distance). 3rd & 4th component unused.
|
||||
* Requires shader derivative instruction support.
|
||||
*/
|
||||
class HairQuadEdgeEffect : public GrEffect {
|
||||
public:
|
||||
|
||||
static GrEffectRef* Create() {
|
||||
// we go through this so we only have one copy of each effect
|
||||
static GrEffectRef* gHairQuadEdgeEffectRef =
|
||||
CreateEffectRef(AutoEffectUnref(SkNEW(HairQuadEdgeEffect)));
|
||||
static SkAutoTUnref<GrEffectRef> gUnref(gHairQuadEdgeEffectRef);
|
||||
|
||||
gHairQuadEdgeEffectRef->ref();
|
||||
return gHairQuadEdgeEffectRef;
|
||||
}
|
||||
|
||||
virtual ~HairQuadEdgeEffect() {}
|
||||
|
||||
static const char* Name() { return "HairQuadEdge"; }
|
||||
|
||||
virtual void getConstantColorComponents(GrColor* color,
|
||||
uint32_t* validFlags) const SK_OVERRIDE {
|
||||
*validFlags = 0;
|
||||
}
|
||||
|
||||
virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE {
|
||||
return GrTBackendEffectFactory<HairQuadEdgeEffect>::getInstance();
|
||||
}
|
||||
|
||||
class GLEffect : public GrGLEffect {
|
||||
public:
|
||||
GLEffect(const GrBackendEffectFactory& factory, const GrDrawEffect&)
|
||||
: INHERITED (factory) {}
|
||||
|
||||
virtual void emitCode(GrGLShaderBuilder* builder,
|
||||
const GrDrawEffect& drawEffect,
|
||||
EffectKey key,
|
||||
const char* outputColor,
|
||||
const char* inputColor,
|
||||
const TextureSamplerArray& samplers) SK_OVERRIDE {
|
||||
const char *vsName, *fsName;
|
||||
const SkString* attrName =
|
||||
builder->getEffectAttributeName(drawEffect.getVertexAttribIndices()[0]);
|
||||
builder->fsCodeAppendf("\t\tfloat edgeAlpha;\n");
|
||||
|
||||
SkAssertResult(builder->enableFeature(
|
||||
GrGLShaderBuilder::kStandardDerivatives_GLSLFeature));
|
||||
builder->addVarying(kVec4f_GrSLType, "HairQuadEdge", &vsName, &fsName);
|
||||
|
||||
builder->fsCodeAppendf("\t\tvec2 duvdx = dFdx(%s.xy);\n", fsName);
|
||||
builder->fsCodeAppendf("\t\tvec2 duvdy = dFdy(%s.xy);\n", fsName);
|
||||
builder->fsCodeAppendf("\t\tvec2 gF = vec2(2.0*%s.x*duvdx.x - duvdx.y,\n"
|
||||
"\t\t 2.0*%s.x*duvdy.x - duvdy.y);\n",
|
||||
fsName, fsName);
|
||||
builder->fsCodeAppendf("\t\tedgeAlpha = (%s.x*%s.x - %s.y);\n", fsName, fsName,
|
||||
fsName);
|
||||
builder->fsCodeAppend("\t\tedgeAlpha = sqrt(edgeAlpha*edgeAlpha / dot(gF, gF));\n");
|
||||
builder->fsCodeAppend("\t\tedgeAlpha = max(1.0 - edgeAlpha, 0.0);\n");
|
||||
|
||||
SkString modulate;
|
||||
GrGLSLModulate4f(&modulate, inputColor, "edgeAlpha");
|
||||
builder->fsCodeAppendf("\t%s = %s;\n", outputColor, modulate.c_str());
|
||||
|
||||
builder->vsCodeAppendf("\t%s = %s;\n", vsName, attrName->c_str());
|
||||
}
|
||||
|
||||
static inline EffectKey GenKey(const GrDrawEffect& drawEffect, const GrGLCaps&) {
|
||||
return 0x0;
|
||||
}
|
||||
|
||||
virtual void setData(const GrGLUniformManager&, const GrDrawEffect&) SK_OVERRIDE {}
|
||||
|
||||
private:
|
||||
typedef GrGLEffect INHERITED;
|
||||
};
|
||||
|
||||
private:
|
||||
HairQuadEdgeEffect() {
|
||||
this->addVertexAttrib(kVec4f_GrSLType);
|
||||
}
|
||||
|
||||
virtual bool onIsEqual(const GrEffect& other) const SK_OVERRIDE {
|
||||
return true;
|
||||
}
|
||||
|
||||
GR_DECLARE_EFFECT_TEST;
|
||||
|
||||
typedef GrEffect INHERITED;
|
||||
};
|
||||
|
||||
GR_DEFINE_EFFECT_TEST(HairQuadEdgeEffect);
|
||||
|
||||
GrEffectRef* HairQuadEdgeEffect::TestCreate(SkMWCRandom* random,
|
||||
GrContext*,
|
||||
const GrDrawTargetCaps& caps,
|
||||
GrTexture*[]) {
|
||||
// Doesn't work without derivative instructions.
|
||||
return caps.shaderDerivativeSupport() ? HairQuadEdgeEffect::Create() : NULL;}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/**
|
||||
* The output of this effect is a 1-pixel wide line.
|
||||
* Input is 2D implicit device coord line eq (a*x + b*y +c = 0). 4th component unused.
|
||||
*/
|
||||
class HairLineEdgeEffect : public GrEffect {
|
||||
public:
|
||||
|
||||
static GrEffectRef* Create() {
|
||||
// we go through this so we only have one copy of each effect
|
||||
static GrEffectRef* gHairLineEdgeEffectRef =
|
||||
CreateEffectRef(AutoEffectUnref(SkNEW(HairLineEdgeEffect)));
|
||||
static SkAutoTUnref<GrEffectRef> gUnref(gHairLineEdgeEffectRef);
|
||||
|
||||
gHairLineEdgeEffectRef->ref();
|
||||
return gHairLineEdgeEffectRef;
|
||||
}
|
||||
|
||||
virtual ~HairLineEdgeEffect() {}
|
||||
|
||||
static const char* Name() { return "HairLineEdge"; }
|
||||
|
||||
virtual void getConstantColorComponents(GrColor* color,
|
||||
uint32_t* validFlags) const SK_OVERRIDE {
|
||||
*validFlags = 0;
|
||||
}
|
||||
|
||||
virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE {
|
||||
return GrTBackendEffectFactory<HairLineEdgeEffect>::getInstance();
|
||||
}
|
||||
|
||||
class GLEffect : public GrGLEffect {
|
||||
public:
|
||||
GLEffect(const GrBackendEffectFactory& factory, const GrDrawEffect&)
|
||||
: INHERITED (factory) {}
|
||||
|
||||
virtual void emitCode(GrGLShaderBuilder* builder,
|
||||
const GrDrawEffect& drawEffect,
|
||||
EffectKey key,
|
||||
const char* outputColor,
|
||||
const char* inputColor,
|
||||
const TextureSamplerArray& samplers) SK_OVERRIDE {
|
||||
const char *vsName, *fsName;
|
||||
const SkString* attrName =
|
||||
builder->getEffectAttributeName(drawEffect.getVertexAttribIndices()[0]);
|
||||
builder->fsCodeAppendf("\t\tfloat edgeAlpha;\n");
|
||||
|
||||
builder->addVarying(kVec4f_GrSLType, "HairLineEdge", &vsName, &fsName);
|
||||
|
||||
builder->fsCodeAppendf("\t\tedgeAlpha = abs(dot(vec3(%s.xy,1), %s.xyz));\n",
|
||||
builder->fragmentPosition(), fsName);
|
||||
builder->fsCodeAppendf("\t\tedgeAlpha = max(1.0 - edgeAlpha, 0.0);\n");
|
||||
|
||||
SkString modulate;
|
||||
GrGLSLModulate4f(&modulate, inputColor, "edgeAlpha");
|
||||
builder->fsCodeAppendf("\t%s = %s;\n", outputColor, modulate.c_str());
|
||||
|
||||
builder->vsCodeAppendf("\t%s = %s;\n", vsName, attrName->c_str());
|
||||
}
|
||||
|
||||
static inline EffectKey GenKey(const GrDrawEffect& drawEffect, const GrGLCaps&) {
|
||||
return 0x0;
|
||||
}
|
||||
|
||||
virtual void setData(const GrGLUniformManager&, const GrDrawEffect&) SK_OVERRIDE {}
|
||||
|
||||
private:
|
||||
typedef GrGLEffect INHERITED;
|
||||
};
|
||||
|
||||
private:
|
||||
HairLineEdgeEffect() {
|
||||
this->addVertexAttrib(kVec4f_GrSLType);
|
||||
}
|
||||
|
||||
virtual bool onIsEqual(const GrEffect& other) const SK_OVERRIDE {
|
||||
return true;
|
||||
}
|
||||
|
||||
GR_DECLARE_EFFECT_TEST;
|
||||
|
||||
typedef GrEffect INHERITED;
|
||||
};
|
||||
|
||||
GR_DEFINE_EFFECT_TEST(HairLineEdgeEffect);
|
||||
|
||||
GrEffectRef* HairLineEdgeEffect::TestCreate(SkMWCRandom* random,
|
||||
GrContext*,
|
||||
const GrDrawTargetCaps& caps,
|
||||
GrTexture*[]) {
|
||||
return HairLineEdgeEffect::Create();
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool GrAAHairLinePathRenderer::createGeom(
|
||||
const SkPath& path,
|
||||
GrDrawTarget* target,
|
||||
int* lineCnt,
|
||||
int* quadCnt,
|
||||
GrDrawTarget::AutoReleaseGeometry* arg) {
|
||||
GrDrawState* drawState = target->drawState();
|
||||
int rtHeight = drawState->getRenderTarget()->height();
|
||||
|
||||
GrIRect devClipBounds;
|
||||
target->getClip()->getConservativeBounds(drawState->getRenderTarget(),
|
||||
&devClipBounds);
|
||||
|
||||
// position + edge
|
||||
static const GrVertexAttrib kAttribs[] = {
|
||||
{kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBinding},
|
||||
{kVec4f_GrVertexAttribType, sizeof(GrPoint), kEffect_GrVertexAttribBinding}
|
||||
};
|
||||
SkMatrix viewM = drawState->getViewMatrix();
|
||||
|
||||
PREALLOC_PTARRAY(128) lines;
|
||||
PREALLOC_PTARRAY(128) quads;
|
||||
IntArray qSubdivs;
|
||||
*quadCnt = generate_lines_and_quads(path, viewM, devClipBounds,
|
||||
&lines, &quads, &qSubdivs);
|
||||
|
||||
*lineCnt = lines.count() / 2;
|
||||
int vertCnt = kVertsPerLineSeg * *lineCnt + kVertsPerQuad * *quadCnt;
|
||||
|
||||
target->drawState()->setVertexAttribs(kAttribs, SK_ARRAY_COUNT(kAttribs));
|
||||
GrAssert(sizeof(Vertex) == target->getDrawState().getVertexSize());
|
||||
|
||||
if (!arg->set(target, vertCnt, 0)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Vertex* verts = reinterpret_cast<Vertex*>(arg->vertices());
|
||||
|
||||
const SkMatrix* toDevice = NULL;
|
||||
const SkMatrix* toSrc = NULL;
|
||||
SkMatrix ivm;
|
||||
|
||||
if (viewM.hasPerspective()) {
|
||||
if (viewM.invert(&ivm)) {
|
||||
toDevice = &viewM;
|
||||
toSrc = &ivm;
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < *lineCnt; ++i) {
|
||||
add_line(&lines[2*i], rtHeight, toSrc, &verts);
|
||||
}
|
||||
|
||||
int unsubdivQuadCnt = quads.count() / 3;
|
||||
for (int i = 0; i < unsubdivQuadCnt; ++i) {
|
||||
GrAssert(qSubdivs[i] >= 0);
|
||||
add_quads(&quads[3*i], qSubdivs[i], toDevice, toSrc, &verts);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GrAAHairLinePathRenderer::canDrawPath(const SkPath& path,
|
||||
const SkStrokeRec& stroke,
|
||||
const GrDrawTarget* target,
|
||||
bool antiAlias) const {
|
||||
if (!stroke.isHairlineStyle() || !antiAlias) {
|
||||
return false;
|
||||
}
|
||||
|
||||
static const uint32_t gReqDerivMask = SkPath::kCubic_SegmentMask |
|
||||
SkPath::kQuad_SegmentMask;
|
||||
if (!target->caps()->shaderDerivativeSupport() &&
|
||||
(gReqDerivMask & path.getSegmentMasks())) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GrAAHairLinePathRenderer::onDrawPath(const SkPath& path,
|
||||
const SkStrokeRec&,
|
||||
GrDrawTarget* target,
|
||||
bool antiAlias) {
|
||||
|
||||
int lineCnt;
|
||||
int quadCnt;
|
||||
GrDrawTarget::AutoReleaseGeometry arg;
|
||||
if (!this->createGeom(path,
|
||||
target,
|
||||
&lineCnt,
|
||||
&quadCnt,
|
||||
&arg)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
GrDrawTarget::AutoStateRestore asr(target, GrDrawTarget::kPreserve_ASRInit);
|
||||
GrDrawState* drawState = target->drawState();
|
||||
|
||||
GrDrawState::AutoDeviceCoordDraw adcd;
|
||||
// createGeom transforms the geometry to device space when the matrix does not have
|
||||
// perspective.
|
||||
if (!drawState->getViewMatrix().hasPerspective()) {
|
||||
adcd.set(drawState);
|
||||
if (!adcd.succeeded()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: See whether rendering lines as degenerate quads improves perf
|
||||
// when we have a mix
|
||||
|
||||
enum {
|
||||
// the edge effects share this stage with glyph rendering
|
||||
// (kGlyphMaskStage in GrTextContext) && SW path rendering
|
||||
// (kPathMaskStage in GrSWMaskHelper)
|
||||
kEdgeEffectStage = GrPaint::kTotalStages,
|
||||
};
|
||||
static const int kEdgeAttrIndex = 1;
|
||||
|
||||
GrEffectRef* hairLineEffect = HairLineEdgeEffect::Create();
|
||||
GrEffectRef* hairQuadEffect = HairQuadEdgeEffect::Create();
|
||||
|
||||
target->setIndexSourceToBuffer(fLinesIndexBuffer);
|
||||
int lines = 0;
|
||||
int nBufLines = fLinesIndexBuffer->maxQuads();
|
||||
drawState->setEffect(kEdgeEffectStage, hairLineEffect, kEdgeAttrIndex)->unref();
|
||||
while (lines < lineCnt) {
|
||||
int n = GrMin(lineCnt - lines, nBufLines);
|
||||
target->drawIndexed(kTriangles_GrPrimitiveType,
|
||||
kVertsPerLineSeg*lines, // startV
|
||||
0, // startI
|
||||
kVertsPerLineSeg*n, // vCount
|
||||
kIdxsPerLineSeg*n); // iCount
|
||||
lines += n;
|
||||
}
|
||||
|
||||
target->setIndexSourceToBuffer(fQuadsIndexBuffer);
|
||||
int quads = 0;
|
||||
drawState->setEffect(kEdgeEffectStage, hairQuadEffect, kEdgeAttrIndex)->unref();
|
||||
while (quads < quadCnt) {
|
||||
int n = GrMin(quadCnt - quads, kNumQuadsInIdxBuffer);
|
||||
target->drawIndexed(kTriangles_GrPrimitiveType,
|
||||
4 * lineCnt + kVertsPerQuad*quads, // startV
|
||||
0, // startI
|
||||
kVertsPerQuad*n, // vCount
|
||||
kIdxsPerQuad*n); // iCount
|
||||
quads += n;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
|
@ -1,273 +0,0 @@
|
|||
/*
|
||||
* 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 "GrAARectRenderer.h"
|
||||
#include "GrRefCnt.h"
|
||||
#include "GrGpu.h"
|
||||
|
||||
SK_DEFINE_INST_COUNT(GrAARectRenderer)
|
||||
|
||||
namespace {
|
||||
|
||||
static void aa_rect_attributes(bool useCoverage, const GrVertexAttrib** attribs, int* count) {
|
||||
static const GrVertexAttrib kCoverageAttribs[] = {
|
||||
{kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBinding},
|
||||
{kVec4ub_GrVertexAttribType, sizeof(GrPoint), kCoverage_GrVertexAttribBinding},
|
||||
};
|
||||
static const GrVertexAttrib kColorAttribs[] = {
|
||||
{kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBinding},
|
||||
{kVec4ub_GrVertexAttribType, sizeof(GrPoint), kColor_GrVertexAttribBinding},
|
||||
};
|
||||
*attribs = useCoverage ? kCoverageAttribs : kColorAttribs;
|
||||
*count = 2;
|
||||
}
|
||||
|
||||
static void set_inset_fan(GrPoint* pts, size_t stride,
|
||||
const GrRect& r, SkScalar dx, SkScalar dy) {
|
||||
pts->setRectFan(r.fLeft + dx, r.fTop + dy,
|
||||
r.fRight - dx, r.fBottom - dy, stride);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
void GrAARectRenderer::reset() {
|
||||
GrSafeSetNull(fAAFillRectIndexBuffer);
|
||||
GrSafeSetNull(fAAStrokeRectIndexBuffer);
|
||||
}
|
||||
|
||||
static const uint16_t gFillAARectIdx[] = {
|
||||
0, 1, 5, 5, 4, 0,
|
||||
1, 2, 6, 6, 5, 1,
|
||||
2, 3, 7, 7, 6, 2,
|
||||
3, 0, 4, 4, 7, 3,
|
||||
4, 5, 6, 6, 7, 4,
|
||||
};
|
||||
|
||||
static const int kIndicesPerAAFillRect = GR_ARRAY_COUNT(gFillAARectIdx);
|
||||
static const int kVertsPerAAFillRect = 8;
|
||||
static const int kNumAAFillRectsInIndexBuffer = 256;
|
||||
|
||||
GrIndexBuffer* GrAARectRenderer::aaFillRectIndexBuffer(GrGpu* gpu) {
|
||||
static const size_t kAAFillRectIndexBufferSize = kIndicesPerAAFillRect *
|
||||
sizeof(uint16_t) *
|
||||
kNumAAFillRectsInIndexBuffer;
|
||||
|
||||
if (NULL == fAAFillRectIndexBuffer) {
|
||||
fAAFillRectIndexBuffer = gpu->createIndexBuffer(kAAFillRectIndexBufferSize, false);
|
||||
if (NULL != fAAFillRectIndexBuffer) {
|
||||
uint16_t* data = (uint16_t*) fAAFillRectIndexBuffer->lock();
|
||||
bool useTempData = (NULL == data);
|
||||
if (useTempData) {
|
||||
data = SkNEW_ARRAY(uint16_t, kNumAAFillRectsInIndexBuffer * kIndicesPerAAFillRect);
|
||||
}
|
||||
for (int i = 0; i < kNumAAFillRectsInIndexBuffer; ++i) {
|
||||
// Each AA filled rect is drawn with 8 vertices and 10 triangles (8 around
|
||||
// the inner rect (for AA) and 2 for the inner rect.
|
||||
int baseIdx = i * kIndicesPerAAFillRect;
|
||||
uint16_t baseVert = (uint16_t)(i * kVertsPerAAFillRect);
|
||||
for (int j = 0; j < kIndicesPerAAFillRect; ++j) {
|
||||
data[baseIdx+j] = baseVert + gFillAARectIdx[j];
|
||||
}
|
||||
}
|
||||
if (useTempData) {
|
||||
if (!fAAFillRectIndexBuffer->updateData(data, kAAFillRectIndexBufferSize)) {
|
||||
GrCrash("Can't get AA Fill Rect indices into buffer!");
|
||||
}
|
||||
SkDELETE_ARRAY(data);
|
||||
} else {
|
||||
fAAFillRectIndexBuffer->unlock();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return fAAFillRectIndexBuffer;
|
||||
}
|
||||
|
||||
static const uint16_t gStrokeAARectIdx[] = {
|
||||
0 + 0, 1 + 0, 5 + 0, 5 + 0, 4 + 0, 0 + 0,
|
||||
1 + 0, 2 + 0, 6 + 0, 6 + 0, 5 + 0, 1 + 0,
|
||||
2 + 0, 3 + 0, 7 + 0, 7 + 0, 6 + 0, 2 + 0,
|
||||
3 + 0, 0 + 0, 4 + 0, 4 + 0, 7 + 0, 3 + 0,
|
||||
|
||||
0 + 4, 1 + 4, 5 + 4, 5 + 4, 4 + 4, 0 + 4,
|
||||
1 + 4, 2 + 4, 6 + 4, 6 + 4, 5 + 4, 1 + 4,
|
||||
2 + 4, 3 + 4, 7 + 4, 7 + 4, 6 + 4, 2 + 4,
|
||||
3 + 4, 0 + 4, 4 + 4, 4 + 4, 7 + 4, 3 + 4,
|
||||
|
||||
0 + 8, 1 + 8, 5 + 8, 5 + 8, 4 + 8, 0 + 8,
|
||||
1 + 8, 2 + 8, 6 + 8, 6 + 8, 5 + 8, 1 + 8,
|
||||
2 + 8, 3 + 8, 7 + 8, 7 + 8, 6 + 8, 2 + 8,
|
||||
3 + 8, 0 + 8, 4 + 8, 4 + 8, 7 + 8, 3 + 8,
|
||||
};
|
||||
|
||||
int GrAARectRenderer::aaStrokeRectIndexCount() {
|
||||
return GR_ARRAY_COUNT(gStrokeAARectIdx);
|
||||
}
|
||||
|
||||
GrIndexBuffer* GrAARectRenderer::aaStrokeRectIndexBuffer(GrGpu* gpu) {
|
||||
if (NULL == fAAStrokeRectIndexBuffer) {
|
||||
fAAStrokeRectIndexBuffer =
|
||||
gpu->createIndexBuffer(sizeof(gStrokeAARectIdx), false);
|
||||
if (NULL != fAAStrokeRectIndexBuffer) {
|
||||
#if GR_DEBUG
|
||||
bool updated =
|
||||
#endif
|
||||
fAAStrokeRectIndexBuffer->updateData(gStrokeAARectIdx,
|
||||
sizeof(gStrokeAARectIdx));
|
||||
GR_DEBUGASSERT(updated);
|
||||
}
|
||||
}
|
||||
return fAAStrokeRectIndexBuffer;
|
||||
}
|
||||
|
||||
void GrAARectRenderer::fillAARect(GrGpu* gpu,
|
||||
GrDrawTarget* target,
|
||||
const GrRect& devRect,
|
||||
bool useVertexCoverage) {
|
||||
GrDrawState* drawState = target->drawState();
|
||||
|
||||
const GrVertexAttrib* attribs;
|
||||
int attribCount;
|
||||
aa_rect_attributes(useVertexCoverage, &attribs, &attribCount);
|
||||
drawState->setVertexAttribs(attribs, attribCount);
|
||||
|
||||
GrDrawTarget::AutoReleaseGeometry geo(target, 8, 0);
|
||||
if (!geo.succeeded()) {
|
||||
GrPrintf("Failed to get space for vertices!\n");
|
||||
return;
|
||||
}
|
||||
|
||||
GrIndexBuffer* indexBuffer = this->aaFillRectIndexBuffer(gpu);
|
||||
if (NULL == indexBuffer) {
|
||||
GrPrintf("Failed to create index buffer!\n");
|
||||
return;
|
||||
}
|
||||
|
||||
intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
|
||||
size_t vsize = drawState->getVertexSize();
|
||||
GrAssert(sizeof(GrPoint) + sizeof(GrColor) == vsize);
|
||||
|
||||
GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts);
|
||||
GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + 4 * vsize);
|
||||
|
||||
set_inset_fan(fan0Pos, vsize, devRect, -SK_ScalarHalf, -SK_ScalarHalf);
|
||||
set_inset_fan(fan1Pos, vsize, devRect, SK_ScalarHalf, SK_ScalarHalf);
|
||||
|
||||
verts += sizeof(GrPoint);
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
*reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
|
||||
}
|
||||
|
||||
GrColor innerColor;
|
||||
if (useVertexCoverage) {
|
||||
innerColor = 0xffffffff;
|
||||
} else {
|
||||
innerColor = target->getDrawState().getColor();
|
||||
}
|
||||
|
||||
verts += 4 * vsize;
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
*reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
|
||||
}
|
||||
|
||||
target->setIndexSourceToBuffer(indexBuffer);
|
||||
target->drawIndexedInstances(kTriangles_GrPrimitiveType, 1,
|
||||
kVertsPerAAFillRect,
|
||||
kIndicesPerAAFillRect);
|
||||
}
|
||||
|
||||
void GrAARectRenderer::strokeAARect(GrGpu* gpu,
|
||||
GrDrawTarget* target,
|
||||
const GrRect& devRect,
|
||||
const GrVec& devStrokeSize,
|
||||
bool useVertexCoverage) {
|
||||
GrDrawState* drawState = target->drawState();
|
||||
|
||||
const SkScalar& dx = devStrokeSize.fX;
|
||||
const SkScalar& dy = devStrokeSize.fY;
|
||||
const SkScalar rx = SkScalarMul(dx, SK_ScalarHalf);
|
||||
const SkScalar ry = SkScalarMul(dy, SK_ScalarHalf);
|
||||
|
||||
SkScalar spare;
|
||||
{
|
||||
SkScalar w = devRect.width() - dx;
|
||||
SkScalar h = devRect.height() - dy;
|
||||
spare = GrMin(w, h);
|
||||
}
|
||||
|
||||
if (spare <= 0) {
|
||||
GrRect r(devRect);
|
||||
r.inset(-rx, -ry);
|
||||
this->fillAARect(gpu, target, r, useVertexCoverage);
|
||||
return;
|
||||
}
|
||||
|
||||
const GrVertexAttrib* attribs;
|
||||
int attribCount;
|
||||
aa_rect_attributes(useVertexCoverage, &attribs, &attribCount);
|
||||
drawState->setVertexAttribs(attribs, attribCount);
|
||||
|
||||
GrDrawTarget::AutoReleaseGeometry geo(target, 16, 0);
|
||||
if (!geo.succeeded()) {
|
||||
GrPrintf("Failed to get space for vertices!\n");
|
||||
return;
|
||||
}
|
||||
GrIndexBuffer* indexBuffer = this->aaStrokeRectIndexBuffer(gpu);
|
||||
if (NULL == indexBuffer) {
|
||||
GrPrintf("Failed to create index buffer!\n");
|
||||
return;
|
||||
}
|
||||
|
||||
intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
|
||||
size_t vsize = drawState->getVertexSize();
|
||||
GrAssert(sizeof(GrPoint) + sizeof(GrColor) == vsize);
|
||||
|
||||
// We create vertices for four nested rectangles. There are two ramps from 0 to full
|
||||
// coverage, one on the exterior of the stroke and the other on the interior.
|
||||
// The following pointers refer to the four rects, from outermost to innermost.
|
||||
GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts);
|
||||
GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + 4 * vsize);
|
||||
GrPoint* fan2Pos = reinterpret_cast<GrPoint*>(verts + 8 * vsize);
|
||||
GrPoint* fan3Pos = reinterpret_cast<GrPoint*>(verts + 12 * vsize);
|
||||
|
||||
set_inset_fan(fan0Pos, vsize, devRect,
|
||||
-rx - SK_ScalarHalf, -ry - SK_ScalarHalf);
|
||||
set_inset_fan(fan1Pos, vsize, devRect,
|
||||
-rx + SK_ScalarHalf, -ry + SK_ScalarHalf);
|
||||
set_inset_fan(fan2Pos, vsize, devRect,
|
||||
rx - SK_ScalarHalf, ry - SK_ScalarHalf);
|
||||
set_inset_fan(fan3Pos, vsize, devRect,
|
||||
rx + SK_ScalarHalf, ry + SK_ScalarHalf);
|
||||
|
||||
// The outermost rect has 0 coverage
|
||||
verts += sizeof(GrPoint);
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
*reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
|
||||
}
|
||||
|
||||
// The inner two rects have full coverage
|
||||
GrColor innerColor;
|
||||
if (useVertexCoverage) {
|
||||
innerColor = 0xffffffff;
|
||||
} else {
|
||||
innerColor = target->getDrawState().getColor();
|
||||
}
|
||||
verts += 4 * vsize;
|
||||
for (int i = 0; i < 8; ++i) {
|
||||
*reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
|
||||
}
|
||||
|
||||
// The innermost rect has full coverage
|
||||
verts += 8 * vsize;
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
*reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
|
||||
}
|
||||
|
||||
target->setIndexSourceToBuffer(indexBuffer);
|
||||
target->drawIndexed(kTriangles_GrPrimitiveType,
|
||||
0, 0, 16, aaStrokeRectIndexCount());
|
||||
}
|
|
@ -1,206 +0,0 @@
|
|||
|
||||
/*
|
||||
* Copyright 2010 Google Inc.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
#include "GrAtlas.h"
|
||||
#include "GrContext.h"
|
||||
#include "GrGpu.h"
|
||||
#include "GrRectanizer.h"
|
||||
#include "GrPlotMgr.h"
|
||||
|
||||
#if 0
|
||||
#define GR_PLOT_WIDTH 8
|
||||
#define GR_PLOT_HEIGHT 4
|
||||
#define GR_ATLAS_WIDTH 256
|
||||
#define GR_ATLAS_HEIGHT 256
|
||||
|
||||
#define GR_ATLAS_TEXTURE_WIDTH (GR_PLOT_WIDTH * GR_ATLAS_WIDTH)
|
||||
#define GR_ATLAS_TEXTURE_HEIGHT (GR_PLOT_HEIGHT * GR_ATLAS_HEIGHT)
|
||||
|
||||
#else
|
||||
|
||||
#define GR_ATLAS_TEXTURE_WIDTH 1024
|
||||
#define GR_ATLAS_TEXTURE_HEIGHT 2048
|
||||
|
||||
#define GR_ATLAS_WIDTH 341
|
||||
#define GR_ATLAS_HEIGHT 341
|
||||
|
||||
#define GR_PLOT_WIDTH (GR_ATLAS_TEXTURE_WIDTH / GR_ATLAS_WIDTH)
|
||||
#define GR_PLOT_HEIGHT (GR_ATLAS_TEXTURE_HEIGHT / GR_ATLAS_HEIGHT)
|
||||
|
||||
#endif
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#define BORDER 1
|
||||
|
||||
#if GR_DEBUG
|
||||
static int gCounter;
|
||||
#endif
|
||||
|
||||
GrAtlas::GrAtlas(GrAtlasMgr* mgr, int plotX, int plotY, GrMaskFormat format) {
|
||||
fAtlasMgr = mgr; // just a pointer, not an owner
|
||||
fNext = NULL;
|
||||
fTexture = mgr->getTexture(format); // we're not an owner, just a pointer
|
||||
fPlot.set(plotX, plotY);
|
||||
|
||||
fRects = GrRectanizer::Factory(GR_ATLAS_WIDTH - BORDER,
|
||||
GR_ATLAS_HEIGHT - BORDER);
|
||||
|
||||
fMaskFormat = format;
|
||||
|
||||
#if GR_DEBUG
|
||||
// GrPrintf(" GrAtlas %p [%d %d] %d\n", this, plotX, plotY, gCounter);
|
||||
gCounter += 1;
|
||||
#endif
|
||||
}
|
||||
|
||||
GrAtlas::~GrAtlas() {
|
||||
fAtlasMgr->freePlot(fPlot.fX, fPlot.fY);
|
||||
|
||||
delete fRects;
|
||||
|
||||
#if GR_DEBUG
|
||||
--gCounter;
|
||||
// GrPrintf("~GrAtlas %p [%d %d] %d\n", this, fPlot.fX, fPlot.fY, gCounter);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void adjustForPlot(GrIPoint16* loc, const GrIPoint16& plot) {
|
||||
loc->fX += plot.fX * GR_ATLAS_WIDTH;
|
||||
loc->fY += plot.fY * GR_ATLAS_HEIGHT;
|
||||
}
|
||||
|
||||
static uint8_t* zerofill(uint8_t* ptr, int count) {
|
||||
while (--count >= 0) {
|
||||
*ptr++ = 0;
|
||||
}
|
||||
return ptr;
|
||||
}
|
||||
|
||||
bool GrAtlas::addSubImage(int width, int height, const void* image,
|
||||
GrIPoint16* loc) {
|
||||
if (!fRects->addRect(width + BORDER, height + BORDER, loc)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
SkAutoSMalloc<1024> storage;
|
||||
int dstW = width + 2*BORDER;
|
||||
int dstH = height + 2*BORDER;
|
||||
if (BORDER) {
|
||||
const int bpp = GrMaskFormatBytesPerPixel(fMaskFormat);
|
||||
const size_t dstRB = dstW * bpp;
|
||||
uint8_t* dst = (uint8_t*)storage.reset(dstH * dstRB);
|
||||
Gr_bzero(dst, dstRB); // zero top row
|
||||
dst += dstRB;
|
||||
for (int y = 0; y < height; y++) {
|
||||
dst = zerofill(dst, bpp); // zero left edge
|
||||
memcpy(dst, image, width * bpp);
|
||||
dst += width * bpp;
|
||||
dst = zerofill(dst, bpp); // zero right edge
|
||||
image = (const void*)((const char*)image + width * bpp);
|
||||
}
|
||||
Gr_bzero(dst, dstRB); // zero bottom row
|
||||
image = storage.get();
|
||||
}
|
||||
adjustForPlot(loc, fPlot);
|
||||
GrContext* context = fTexture->getContext();
|
||||
// We pass the flag that does not force a flush. We assume our caller is
|
||||
// smart and hasn't referenced the part of the texture we're about to update
|
||||
// since the last flush.
|
||||
context->writeTexturePixels(fTexture,
|
||||
loc->fX, loc->fY, dstW, dstH,
|
||||
fTexture->config(), image, 0,
|
||||
GrContext::kDontFlush_PixelOpsFlag);
|
||||
|
||||
// now tell the caller to skip the top/left BORDER
|
||||
loc->fX += BORDER;
|
||||
loc->fY += BORDER;
|
||||
return true;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
GrAtlasMgr::GrAtlasMgr(GrGpu* gpu) {
|
||||
fGpu = gpu;
|
||||
gpu->ref();
|
||||
Gr_bzero(fTexture, sizeof(fTexture));
|
||||
fPlotMgr = SkNEW_ARGS(GrPlotMgr, (GR_PLOT_WIDTH, GR_PLOT_HEIGHT));
|
||||
}
|
||||
|
||||
GrAtlasMgr::~GrAtlasMgr() {
|
||||
for (size_t i = 0; i < GR_ARRAY_COUNT(fTexture); i++) {
|
||||
GrSafeUnref(fTexture[i]);
|
||||
}
|
||||
delete fPlotMgr;
|
||||
fGpu->unref();
|
||||
}
|
||||
|
||||
static GrPixelConfig maskformat2pixelconfig(GrMaskFormat format) {
|
||||
switch (format) {
|
||||
case kA8_GrMaskFormat:
|
||||
return kAlpha_8_GrPixelConfig;
|
||||
case kA565_GrMaskFormat:
|
||||
return kRGB_565_GrPixelConfig;
|
||||
case kA888_GrMaskFormat:
|
||||
return kSkia8888_GrPixelConfig;
|
||||
default:
|
||||
GrAssert(!"unknown maskformat");
|
||||
}
|
||||
return kUnknown_GrPixelConfig;
|
||||
}
|
||||
|
||||
GrAtlas* GrAtlasMgr::addToAtlas(GrAtlas* atlas,
|
||||
int width, int height, const void* image,
|
||||
GrMaskFormat format,
|
||||
GrIPoint16* loc) {
|
||||
GrAssert(NULL == atlas || atlas->getMaskFormat() == format);
|
||||
|
||||
if (atlas && atlas->addSubImage(width, height, image, loc)) {
|
||||
return atlas;
|
||||
}
|
||||
|
||||
// If the above fails, then either we have no starting atlas, or the current
|
||||
// one is full. Either way we need to allocate a new atlas
|
||||
|
||||
GrIPoint16 plot;
|
||||
if (!fPlotMgr->newPlot(&plot)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
GrAssert(0 == kA8_GrMaskFormat);
|
||||
GrAssert(1 == kA565_GrMaskFormat);
|
||||
if (NULL == fTexture[format]) {
|
||||
// TODO: Update this to use the cache rather than directly creating a texture.
|
||||
GrTextureDesc desc;
|
||||
desc.fFlags = kDynamicUpdate_GrTextureFlagBit;
|
||||
desc.fWidth = GR_ATLAS_TEXTURE_WIDTH;
|
||||
desc.fHeight = GR_ATLAS_TEXTURE_HEIGHT;
|
||||
desc.fConfig = maskformat2pixelconfig(format);
|
||||
|
||||
fTexture[format] = fGpu->createTexture(desc, NULL, 0);
|
||||
if (NULL == fTexture[format]) {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
GrAtlas* newAtlas = SkNEW_ARGS(GrAtlas, (this, plot.fX, plot.fY, format));
|
||||
if (!newAtlas->addSubImage(width, height, image, loc)) {
|
||||
delete newAtlas;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
newAtlas->fNext = atlas;
|
||||
return newAtlas;
|
||||
}
|
||||
|
||||
void GrAtlasMgr::freePlot(int x, int y) {
|
||||
GrAssert(fPlotMgr->isBusy(x, y));
|
||||
fPlotMgr->freePlot(x, y);
|
||||
}
|
|
@ -1,81 +0,0 @@
|
|||
|
||||
/*
|
||||
* Copyright 2010 Google Inc.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
#ifndef GrAtlas_DEFINED
|
||||
#define GrAtlas_DEFINED
|
||||
|
||||
#include "GrPoint.h"
|
||||
#include "GrTexture.h"
|
||||
|
||||
class GrGpu;
|
||||
class GrRectanizer;
|
||||
class GrAtlasMgr;
|
||||
|
||||
class GrAtlas {
|
||||
public:
|
||||
GrAtlas(GrAtlasMgr*, int plotX, int plotY, GrMaskFormat);
|
||||
|
||||
int getPlotX() const { return fPlot.fX; }
|
||||
int getPlotY() const { return fPlot.fY; }
|
||||
GrMaskFormat getMaskFormat() const { return fMaskFormat; }
|
||||
|
||||
GrTexture* texture() const { return fTexture; }
|
||||
|
||||
bool addSubImage(int width, int height, const void*, GrIPoint16*);
|
||||
|
||||
static void FreeLList(GrAtlas* atlas) {
|
||||
while (atlas) {
|
||||
GrAtlas* next = atlas->fNext;
|
||||
delete atlas;
|
||||
atlas = next;
|
||||
}
|
||||
}
|
||||
|
||||
// testing
|
||||
GrAtlas* nextAtlas() const { return fNext; }
|
||||
|
||||
private:
|
||||
~GrAtlas(); // does not try to delete the fNext field
|
||||
|
||||
GrAtlas* fNext;
|
||||
GrTexture* fTexture;
|
||||
GrRectanizer* fRects;
|
||||
GrAtlasMgr* fAtlasMgr;
|
||||
GrIPoint16 fPlot;
|
||||
GrMaskFormat fMaskFormat;
|
||||
|
||||
friend class GrAtlasMgr;
|
||||
};
|
||||
|
||||
class GrPlotMgr;
|
||||
|
||||
class GrAtlasMgr {
|
||||
public:
|
||||
GrAtlasMgr(GrGpu*);
|
||||
~GrAtlasMgr();
|
||||
|
||||
GrAtlas* addToAtlas(GrAtlas*, int width, int height, const void*,
|
||||
GrMaskFormat, GrIPoint16*);
|
||||
|
||||
GrTexture* getTexture(GrMaskFormat format) const {
|
||||
GrAssert((unsigned)format < kCount_GrMaskFormats);
|
||||
return fTexture[format];
|
||||
}
|
||||
|
||||
// to be called by ~GrAtlas()
|
||||
void freePlot(int x, int y);
|
||||
|
||||
private:
|
||||
GrGpu* fGpu;
|
||||
GrTexture* fTexture[kCount_GrMaskFormats];
|
||||
GrPlotMgr* fPlotMgr;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -1,110 +0,0 @@
|
|||
|
||||
/*
|
||||
* Copyright 2011 Google Inc.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef GrBinHashKey_DEFINED
|
||||
#define GrBinHashKey_DEFINED
|
||||
|
||||
#include "GrTypes.h"
|
||||
|
||||
/**
|
||||
* Hash function class that can take a data chunk of any predetermined length. The hash function
|
||||
* used is the One-at-a-Time Hash (http://burtleburtle.net/bob/hash/doobs.html).
|
||||
*
|
||||
* Keys are computed from ENTRY objects. ENTRY must be fully ordered by a member:
|
||||
* int compare(const GrTBinHashKey<ENTRY, ..>& k);
|
||||
* which returns negative if the ENTRY < k, 0 if it equals k, and positive if k < the ENTRY.
|
||||
* Additionally, ENTRY must be flattenable into the key using setKeyData.
|
||||
*
|
||||
* This class satisfies the requirements to be a key for a GrTHashTable.
|
||||
*/
|
||||
template<typename ENTRY, size_t KEY_SIZE>
|
||||
class GrTBinHashKey {
|
||||
public:
|
||||
enum { kKeySize = KEY_SIZE };
|
||||
|
||||
GrTBinHashKey() {
|
||||
this->reset();
|
||||
}
|
||||
|
||||
GrTBinHashKey(const GrTBinHashKey<ENTRY, KEY_SIZE>& other) {
|
||||
*this = other;
|
||||
}
|
||||
|
||||
GrTBinHashKey<ENTRY, KEY_SIZE>& operator=(const GrTBinHashKey<ENTRY, KEY_SIZE>& other) {
|
||||
memcpy(this, &other, sizeof(*this));
|
||||
return *this;
|
||||
}
|
||||
|
||||
~GrTBinHashKey() {
|
||||
}
|
||||
|
||||
void reset() {
|
||||
fHash = 0;
|
||||
#if GR_DEBUG
|
||||
fIsValid = false;
|
||||
#endif
|
||||
}
|
||||
|
||||
void setKeyData(const uint32_t* SK_RESTRICT data) {
|
||||
GrAssert(GrIsALIGN4(KEY_SIZE));
|
||||
memcpy(&fData, data, KEY_SIZE);
|
||||
|
||||
uint32_t hash = 0;
|
||||
size_t len = KEY_SIZE;
|
||||
while (len >= 4) {
|
||||
hash += *data++;
|
||||
hash += (fHash << 10);
|
||||
hash ^= (hash >> 6);
|
||||
len -= 4;
|
||||
}
|
||||
hash += (fHash << 3);
|
||||
hash ^= (fHash >> 11);
|
||||
hash += (fHash << 15);
|
||||
#if GR_DEBUG
|
||||
fIsValid = true;
|
||||
#endif
|
||||
fHash = hash;
|
||||
}
|
||||
|
||||
int compare(const GrTBinHashKey<ENTRY, KEY_SIZE>& key) const {
|
||||
GrAssert(fIsValid && key.fIsValid);
|
||||
return memcmp(fData, key.fData, KEY_SIZE);
|
||||
}
|
||||
|
||||
static bool EQ(const ENTRY& entry, const GrTBinHashKey<ENTRY, KEY_SIZE>& key) {
|
||||
GrAssert(key.fIsValid);
|
||||
return 0 == entry.compare(key);
|
||||
}
|
||||
|
||||
static bool LT(const ENTRY& entry, const GrTBinHashKey<ENTRY, KEY_SIZE>& key) {
|
||||
GrAssert(key.fIsValid);
|
||||
return entry.compare(key) < 0;
|
||||
}
|
||||
|
||||
uint32_t getHash() const {
|
||||
GrAssert(fIsValid);
|
||||
return fHash;
|
||||
}
|
||||
|
||||
const uint8_t* getData() const {
|
||||
GrAssert(fIsValid);
|
||||
return fData;
|
||||
}
|
||||
|
||||
private:
|
||||
uint32_t fHash;
|
||||
uint8_t fData[KEY_SIZE]; // Buffer for key storage
|
||||
|
||||
#if GR_DEBUG
|
||||
public:
|
||||
bool fIsValid;
|
||||
#endif
|
||||
};
|
||||
|
||||
#endif
|
|
@ -1,10 +0,0 @@
|
|||
/*
|
||||
* 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 "GrGeometryBuffer.h"
|
||||
|
||||
SK_DEFINE_INST_COUNT(GrGeometryBuffer)
|
|
@ -1,524 +0,0 @@
|
|||
/*
|
||||
* Copyright 2013 Google Inc.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include "GrOvalRenderer.h"
|
||||
|
||||
#include "GrEffect.h"
|
||||
#include "gl/GrGLEffect.h"
|
||||
#include "gl/GrGLSL.h"
|
||||
#include "GrTBackendEffectFactory.h"
|
||||
|
||||
#include "GrDrawState.h"
|
||||
#include "GrDrawTarget.h"
|
||||
#include "SkStrokeRec.h"
|
||||
|
||||
SK_DEFINE_INST_COUNT(GrOvalRenderer)
|
||||
|
||||
namespace {
|
||||
|
||||
struct CircleVertex {
|
||||
GrPoint fPos;
|
||||
GrPoint fCenter;
|
||||
SkScalar fOuterRadius;
|
||||
SkScalar fInnerRadius;
|
||||
};
|
||||
|
||||
struct EllipseVertex {
|
||||
GrPoint fPos;
|
||||
GrPoint fCenter;
|
||||
SkScalar fOuterXRadius;
|
||||
SkScalar fOuterXYRatio;
|
||||
SkScalar fInnerXRadius;
|
||||
SkScalar fInnerXYRatio;
|
||||
};
|
||||
|
||||
inline bool circle_stays_circle(const SkMatrix& m) {
|
||||
return m.isSimilarity();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/**
|
||||
* The output of this effect is a modulation of the input color and coverage for a circle,
|
||||
* specified as center_x, center_y, x_radius, inner radius and outer radius in window space
|
||||
* (y-down).
|
||||
*/
|
||||
|
||||
class CircleEdgeEffect : public GrEffect {
|
||||
public:
|
||||
static GrEffectRef* Create(bool stroke) {
|
||||
// we go through this so we only have one copy of each effect (stroked/filled)
|
||||
static SkAutoTUnref<GrEffectRef> gCircleStrokeEdgeEffectRef(
|
||||
CreateEffectRef(AutoEffectUnref(SkNEW_ARGS(CircleEdgeEffect, (true)))));
|
||||
static SkAutoTUnref<GrEffectRef> gCircleFillEdgeEffectRef(
|
||||
CreateEffectRef(AutoEffectUnref(SkNEW_ARGS(CircleEdgeEffect, (false)))));
|
||||
|
||||
if (stroke) {
|
||||
gCircleStrokeEdgeEffectRef.get()->ref();
|
||||
return gCircleStrokeEdgeEffectRef;
|
||||
} else {
|
||||
gCircleFillEdgeEffectRef.get()->ref();
|
||||
return gCircleFillEdgeEffectRef;
|
||||
}
|
||||
}
|
||||
|
||||
virtual void getConstantColorComponents(GrColor* color,
|
||||
uint32_t* validFlags) const SK_OVERRIDE {
|
||||
*validFlags = 0;
|
||||
}
|
||||
|
||||
virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE {
|
||||
return GrTBackendEffectFactory<CircleEdgeEffect>::getInstance();
|
||||
}
|
||||
|
||||
virtual ~CircleEdgeEffect() {}
|
||||
|
||||
static const char* Name() { return "CircleEdge"; }
|
||||
|
||||
inline bool isStroked() const { return fStroke; }
|
||||
|
||||
class GLEffect : public GrGLEffect {
|
||||
public:
|
||||
GLEffect(const GrBackendEffectFactory& factory, const GrDrawEffect&)
|
||||
: INHERITED (factory) {}
|
||||
|
||||
virtual void emitCode(GrGLShaderBuilder* builder,
|
||||
const GrDrawEffect& drawEffect,
|
||||
EffectKey key,
|
||||
const char* outputColor,
|
||||
const char* inputColor,
|
||||
const TextureSamplerArray& samplers) SK_OVERRIDE {
|
||||
const CircleEdgeEffect& circleEffect = drawEffect.castEffect<CircleEdgeEffect>();
|
||||
const char *vsName, *fsName;
|
||||
builder->addVarying(kVec4f_GrSLType, "CircleEdge", &vsName, &fsName);
|
||||
|
||||
const SkString* attrName =
|
||||
builder->getEffectAttributeName(drawEffect.getVertexAttribIndices()[0]);
|
||||
builder->vsCodeAppendf("\t%s = %s;\n", vsName, attrName->c_str());
|
||||
|
||||
builder->fsCodeAppendf("\tfloat d = distance(%s.xy, %s.xy);\n",
|
||||
builder->fragmentPosition(), fsName);
|
||||
builder->fsCodeAppendf("\tfloat edgeAlpha = clamp(%s.z - d, 0.0, 1.0);\n", fsName);
|
||||
if (circleEffect.isStroked()) {
|
||||
builder->fsCodeAppendf("\tfloat innerAlpha = clamp(d - %s.w, 0.0, 1.0);\n", fsName);
|
||||
builder->fsCodeAppend("\tedgeAlpha *= innerAlpha;\n");
|
||||
}
|
||||
SkString modulate;
|
||||
GrGLSLModulate4f(&modulate, inputColor, "edgeAlpha");
|
||||
builder->fsCodeAppendf("\t%s = %s;\n", outputColor, modulate.c_str());
|
||||
}
|
||||
|
||||
static inline EffectKey GenKey(const GrDrawEffect& drawEffect, const GrGLCaps&) {
|
||||
const CircleEdgeEffect& circleEffect = drawEffect.castEffect<CircleEdgeEffect>();
|
||||
|
||||
return circleEffect.isStroked() ? 0x1 : 0x0;
|
||||
}
|
||||
|
||||
virtual void setData(const GrGLUniformManager&, const GrDrawEffect&) SK_OVERRIDE {}
|
||||
|
||||
private:
|
||||
typedef GrGLEffect INHERITED;
|
||||
};
|
||||
|
||||
|
||||
private:
|
||||
CircleEdgeEffect(bool stroke) : GrEffect() {
|
||||
this->addVertexAttrib(kVec4f_GrSLType);
|
||||
fStroke = stroke;
|
||||
}
|
||||
|
||||
virtual bool onIsEqual(const GrEffect& other) const SK_OVERRIDE {
|
||||
const CircleEdgeEffect& cee = CastEffect<CircleEdgeEffect>(other);
|
||||
return cee.fStroke == fStroke;
|
||||
}
|
||||
|
||||
bool fStroke;
|
||||
|
||||
GR_DECLARE_EFFECT_TEST;
|
||||
|
||||
typedef GrEffect INHERITED;
|
||||
};
|
||||
|
||||
GR_DEFINE_EFFECT_TEST(CircleEdgeEffect);
|
||||
|
||||
GrEffectRef* CircleEdgeEffect::TestCreate(SkMWCRandom* random,
|
||||
GrContext* context,
|
||||
const GrDrawTargetCaps&,
|
||||
GrTexture* textures[]) {
|
||||
return CircleEdgeEffect::Create(random->nextBool());
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/**
|
||||
* The output of this effect is a modulation of the input color and coverage for an axis-aligned
|
||||
* ellipse, specified as center_x, center_y, x_radius, x_radius/y_radius in window space (y-down).
|
||||
*/
|
||||
|
||||
class EllipseEdgeEffect : public GrEffect {
|
||||
public:
|
||||
static GrEffectRef* Create(bool stroke) {
|
||||
// we go through this so we only have one copy of each effect (stroked/filled)
|
||||
static SkAutoTUnref<GrEffectRef> gEllipseStrokeEdgeEffectRef(
|
||||
CreateEffectRef(AutoEffectUnref(SkNEW_ARGS(EllipseEdgeEffect, (true)))));
|
||||
static SkAutoTUnref<GrEffectRef> gEllipseFillEdgeEffectRef(
|
||||
CreateEffectRef(AutoEffectUnref(SkNEW_ARGS(EllipseEdgeEffect, (false)))));
|
||||
|
||||
if (stroke) {
|
||||
gEllipseStrokeEdgeEffectRef.get()->ref();
|
||||
return gEllipseStrokeEdgeEffectRef;
|
||||
} else {
|
||||
gEllipseFillEdgeEffectRef.get()->ref();
|
||||
return gEllipseFillEdgeEffectRef;
|
||||
}
|
||||
}
|
||||
|
||||
virtual void getConstantColorComponents(GrColor* color,
|
||||
uint32_t* validFlags) const SK_OVERRIDE {
|
||||
*validFlags = 0;
|
||||
}
|
||||
|
||||
virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE {
|
||||
return GrTBackendEffectFactory<EllipseEdgeEffect>::getInstance();
|
||||
}
|
||||
|
||||
virtual ~EllipseEdgeEffect() {}
|
||||
|
||||
static const char* Name() { return "EllipseEdge"; }
|
||||
|
||||
inline bool isStroked() const { return fStroke; }
|
||||
|
||||
class GLEffect : public GrGLEffect {
|
||||
public:
|
||||
GLEffect(const GrBackendEffectFactory& factory, const GrDrawEffect&)
|
||||
: INHERITED (factory) {}
|
||||
|
||||
virtual void emitCode(GrGLShaderBuilder* builder,
|
||||
const GrDrawEffect& drawEffect,
|
||||
EffectKey key,
|
||||
const char* outputColor,
|
||||
const char* inputColor,
|
||||
const TextureSamplerArray& samplers) SK_OVERRIDE {
|
||||
const EllipseEdgeEffect& ellipseEffect = drawEffect.castEffect<EllipseEdgeEffect>();
|
||||
|
||||
const char *vsCenterName, *fsCenterName;
|
||||
const char *vsEdgeName, *fsEdgeName;
|
||||
|
||||
builder->addVarying(kVec2f_GrSLType, "EllipseCenter", &vsCenterName, &fsCenterName);
|
||||
const SkString* attr0Name =
|
||||
builder->getEffectAttributeName(drawEffect.getVertexAttribIndices()[0]);
|
||||
builder->vsCodeAppendf("\t%s = %s;\n", vsCenterName, attr0Name->c_str());
|
||||
|
||||
builder->addVarying(kVec4f_GrSLType, "EllipseEdge", &vsEdgeName, &fsEdgeName);
|
||||
const SkString* attr1Name =
|
||||
builder->getEffectAttributeName(drawEffect.getVertexAttribIndices()[1]);
|
||||
builder->vsCodeAppendf("\t%s = %s;\n", vsEdgeName, attr1Name->c_str());
|
||||
|
||||
// translate to origin
|
||||
builder->fsCodeAppendf("\tvec2 outerOffset = (%s.xy - %s.xy);\n",
|
||||
builder->fragmentPosition(), fsCenterName);
|
||||
builder->fsCodeAppend("\tvec2 innerOffset = outerOffset;\n");
|
||||
// scale y by xRadius/yRadius
|
||||
builder->fsCodeAppendf("\touterOffset.y *= %s.y;\n", fsEdgeName);
|
||||
builder->fsCodeAppend("\tfloat dOuter = length(outerOffset);\n");
|
||||
// compare outer lengths against xOuterRadius
|
||||
builder->fsCodeAppendf("\tfloat edgeAlpha = clamp(%s.x-dOuter, 0.0, 1.0);\n",
|
||||
fsEdgeName);
|
||||
|
||||
if (ellipseEffect.isStroked()) {
|
||||
builder->fsCodeAppendf("\tinnerOffset.y *= %s.w;\n", fsEdgeName);
|
||||
builder->fsCodeAppend("\tfloat dInner = length(innerOffset);\n");
|
||||
|
||||
// compare inner lengths against xInnerRadius
|
||||
builder->fsCodeAppendf("\tfloat innerAlpha = clamp(dInner-%s.z, 0.0, 1.0);\n",
|
||||
fsEdgeName);
|
||||
builder->fsCodeAppend("\tedgeAlpha *= innerAlpha;\n");
|
||||
}
|
||||
|
||||
SkString modulate;
|
||||
GrGLSLModulate4f(&modulate, inputColor, "edgeAlpha");
|
||||
builder->fsCodeAppendf("\t%s = %s;\n", outputColor, modulate.c_str());
|
||||
}
|
||||
|
||||
static inline EffectKey GenKey(const GrDrawEffect& drawEffect, const GrGLCaps&) {
|
||||
const EllipseEdgeEffect& ellipseEffect = drawEffect.castEffect<EllipseEdgeEffect>();
|
||||
|
||||
return ellipseEffect.isStroked() ? 0x1 : 0x0;
|
||||
}
|
||||
|
||||
virtual void setData(const GrGLUniformManager&, const GrDrawEffect&) SK_OVERRIDE {
|
||||
}
|
||||
|
||||
private:
|
||||
typedef GrGLEffect INHERITED;
|
||||
};
|
||||
|
||||
private:
|
||||
EllipseEdgeEffect(bool stroke) : GrEffect() {
|
||||
this->addVertexAttrib(kVec2f_GrSLType);
|
||||
this->addVertexAttrib(kVec4f_GrSLType);
|
||||
fStroke = stroke;
|
||||
}
|
||||
|
||||
virtual bool onIsEqual(const GrEffect& other) const SK_OVERRIDE {
|
||||
const EllipseEdgeEffect& eee = CastEffect<EllipseEdgeEffect>(other);
|
||||
return eee.fStroke == fStroke;
|
||||
}
|
||||
|
||||
bool fStroke;
|
||||
|
||||
GR_DECLARE_EFFECT_TEST;
|
||||
|
||||
typedef GrEffect INHERITED;
|
||||
};
|
||||
|
||||
GR_DEFINE_EFFECT_TEST(EllipseEdgeEffect);
|
||||
|
||||
GrEffectRef* EllipseEdgeEffect::TestCreate(SkMWCRandom* random,
|
||||
GrContext* context,
|
||||
const GrDrawTargetCaps&,
|
||||
GrTexture* textures[]) {
|
||||
return EllipseEdgeEffect::Create(random->nextBool());
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool GrOvalRenderer::drawOval(GrDrawTarget* target, const GrContext* context, const GrPaint& paint,
|
||||
const GrRect& oval, const SkStrokeRec& stroke)
|
||||
{
|
||||
if (!paint.isAntiAlias()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const SkMatrix& vm = context->getMatrix();
|
||||
|
||||
// we can draw circles
|
||||
if (SkScalarNearlyEqual(oval.width(), oval.height())
|
||||
&& circle_stays_circle(vm)) {
|
||||
drawCircle(target, paint, oval, stroke);
|
||||
|
||||
// and axis-aligned ellipses only
|
||||
} else if (vm.rectStaysRect()) {
|
||||
drawEllipse(target, paint, oval, stroke);
|
||||
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void GrOvalRenderer::drawCircle(GrDrawTarget* target,
|
||||
const GrPaint& paint,
|
||||
const GrRect& circle,
|
||||
const SkStrokeRec& stroke)
|
||||
{
|
||||
GrDrawState* drawState = target->drawState();
|
||||
|
||||
const SkMatrix& vm = drawState->getViewMatrix();
|
||||
GrPoint center = GrPoint::Make(circle.centerX(), circle.centerY());
|
||||
vm.mapPoints(¢er, 1);
|
||||
SkScalar radius = vm.mapRadius(SkScalarHalf(circle.width()));
|
||||
SkScalar strokeWidth = vm.mapRadius(stroke.getWidth());
|
||||
|
||||
GrDrawState::AutoDeviceCoordDraw adcd(drawState);
|
||||
if (!adcd.succeeded()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// position + edge
|
||||
static const GrVertexAttrib kVertexAttribs[] = {
|
||||
{kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBinding},
|
||||
{kVec4f_GrVertexAttribType, sizeof(GrPoint), kEffect_GrVertexAttribBinding}
|
||||
};
|
||||
drawState->setVertexAttribs(kVertexAttribs, SK_ARRAY_COUNT(kVertexAttribs));
|
||||
GrAssert(sizeof(CircleVertex) == drawState->getVertexSize());
|
||||
|
||||
GrDrawTarget::AutoReleaseGeometry geo(target, 4, 0);
|
||||
if (!geo.succeeded()) {
|
||||
GrPrintf("Failed to get space for vertices!\n");
|
||||
return;
|
||||
}
|
||||
|
||||
CircleVertex* verts = reinterpret_cast<CircleVertex*>(geo.vertices());
|
||||
|
||||
SkStrokeRec::Style style = stroke.getStyle();
|
||||
bool isStroked = (SkStrokeRec::kStroke_Style == style || SkStrokeRec::kHairline_Style == style);
|
||||
enum {
|
||||
// the edge effects share this stage with glyph rendering
|
||||
// (kGlyphMaskStage in GrTextContext) && SW path rendering
|
||||
// (kPathMaskStage in GrSWMaskHelper)
|
||||
kEdgeEffectStage = GrPaint::kTotalStages,
|
||||
};
|
||||
|
||||
GrEffectRef* effect = CircleEdgeEffect::Create(isStroked);
|
||||
static const int kCircleEdgeAttrIndex = 1;
|
||||
drawState->setEffect(kEdgeEffectStage, effect, kCircleEdgeAttrIndex)->unref();
|
||||
|
||||
SkScalar innerRadius = 0.0f;
|
||||
SkScalar outerRadius = radius;
|
||||
SkScalar halfWidth = 0;
|
||||
if (style != SkStrokeRec::kFill_Style) {
|
||||
if (SkScalarNearlyZero(strokeWidth)) {
|
||||
halfWidth = SK_ScalarHalf;
|
||||
} else {
|
||||
halfWidth = SkScalarHalf(strokeWidth);
|
||||
}
|
||||
|
||||
outerRadius += halfWidth;
|
||||
if (isStroked) {
|
||||
innerRadius = SkMaxScalar(0, radius - halfWidth);
|
||||
}
|
||||
}
|
||||
|
||||
// The radii are outset for two reasons. First, it allows the shader to simply perform
|
||||
// clamp(distance-to-center - radius, 0, 1). Second, the outer radius is used to compute the
|
||||
// verts of the bounding box that is rendered and the outset ensures the box will cover all
|
||||
// pixels partially covered by the circle.
|
||||
outerRadius += SK_ScalarHalf;
|
||||
innerRadius -= SK_ScalarHalf;
|
||||
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
verts[i].fCenter = center;
|
||||
verts[i].fOuterRadius = outerRadius;
|
||||
verts[i].fInnerRadius = innerRadius;
|
||||
}
|
||||
|
||||
SkRect bounds = SkRect::MakeLTRB(
|
||||
center.fX - outerRadius,
|
||||
center.fY - outerRadius,
|
||||
center.fX + outerRadius,
|
||||
center.fY + outerRadius
|
||||
);
|
||||
|
||||
verts[0].fPos = SkPoint::Make(bounds.fLeft, bounds.fTop);
|
||||
verts[1].fPos = SkPoint::Make(bounds.fRight, bounds.fTop);
|
||||
verts[2].fPos = SkPoint::Make(bounds.fLeft, bounds.fBottom);
|
||||
verts[3].fPos = SkPoint::Make(bounds.fRight, bounds.fBottom);
|
||||
|
||||
target->drawNonIndexed(kTriangleStrip_GrPrimitiveType, 0, 4, &bounds);
|
||||
}
|
||||
|
||||
void GrOvalRenderer::drawEllipse(GrDrawTarget* target,
|
||||
const GrPaint& paint,
|
||||
const GrRect& ellipse,
|
||||
const SkStrokeRec& stroke)
|
||||
{
|
||||
GrDrawState* drawState = target->drawState();
|
||||
#ifdef SK_DEBUG
|
||||
{
|
||||
// we should have checked for this previously
|
||||
bool isAxisAlignedEllipse = drawState->getViewMatrix().rectStaysRect();
|
||||
SkASSERT(paint.isAntiAlias() && isAxisAlignedEllipse);
|
||||
}
|
||||
#endif
|
||||
|
||||
const SkMatrix& vm = drawState->getViewMatrix();
|
||||
GrPoint center = GrPoint::Make(ellipse.centerX(), ellipse.centerY());
|
||||
vm.mapPoints(¢er, 1);
|
||||
SkRect xformedRect;
|
||||
vm.mapRect(&xformedRect, ellipse);
|
||||
|
||||
GrDrawState::AutoDeviceCoordDraw adcd(drawState);
|
||||
if (!adcd.succeeded()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// position + edge
|
||||
static const GrVertexAttrib kVertexAttribs[] = {
|
||||
{kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBinding},
|
||||
{kVec2f_GrVertexAttribType, sizeof(GrPoint), kEffect_GrVertexAttribBinding},
|
||||
{kVec4f_GrVertexAttribType, 2*sizeof(GrPoint), kEffect_GrVertexAttribBinding}
|
||||
};
|
||||
drawState->setVertexAttribs(kVertexAttribs, SK_ARRAY_COUNT(kVertexAttribs));
|
||||
GrAssert(sizeof(EllipseVertex) == drawState->getVertexSize());
|
||||
|
||||
GrDrawTarget::AutoReleaseGeometry geo(target, 4, 0);
|
||||
if (!geo.succeeded()) {
|
||||
GrPrintf("Failed to get space for vertices!\n");
|
||||
return;
|
||||
}
|
||||
|
||||
EllipseVertex* verts = reinterpret_cast<EllipseVertex*>(geo.vertices());
|
||||
|
||||
SkStrokeRec::Style style = stroke.getStyle();
|
||||
bool isStroked = (SkStrokeRec::kStroke_Style == style || SkStrokeRec::kHairline_Style == style);
|
||||
enum {
|
||||
// the edge effects share this stage with glyph rendering
|
||||
// (kGlyphMaskStage in GrTextContext) && SW path rendering
|
||||
// (kPathMaskStage in GrSWMaskHelper)
|
||||
kEdgeEffectStage = GrPaint::kTotalStages,
|
||||
};
|
||||
|
||||
GrEffectRef* effect = EllipseEdgeEffect::Create(isStroked);
|
||||
static const int kEllipseCenterAttrIndex = 1;
|
||||
static const int kEllipseEdgeAttrIndex = 2;
|
||||
drawState->setEffect(kEdgeEffectStage, effect,
|
||||
kEllipseCenterAttrIndex, kEllipseEdgeAttrIndex)->unref();
|
||||
|
||||
SkScalar xRadius = SkScalarHalf(xformedRect.width());
|
||||
SkScalar yRadius = SkScalarHalf(xformedRect.height());
|
||||
SkScalar innerXRadius = 0.0f;
|
||||
SkScalar innerRatio = 1.0f;
|
||||
|
||||
if (SkStrokeRec::kFill_Style != style) {
|
||||
SkScalar strokeWidth = stroke.getWidth();
|
||||
|
||||
// do (potentially) anisotropic mapping
|
||||
SkVector scaledStroke;
|
||||
scaledStroke.set(strokeWidth, strokeWidth);
|
||||
vm.mapVectors(&scaledStroke, 1);
|
||||
|
||||
if (SkScalarNearlyZero(scaledStroke.length())) {
|
||||
scaledStroke.set(SK_ScalarHalf, SK_ScalarHalf);
|
||||
} else {
|
||||
scaledStroke.scale(0.5f);
|
||||
}
|
||||
|
||||
// this is legit only if scale & translation (which should be the case at the moment)
|
||||
if (SkStrokeRec::kStroke_Style == style || SkStrokeRec::kHairline_Style == style) {
|
||||
SkScalar innerYRadius = SkMaxScalar(0, yRadius - scaledStroke.fY);
|
||||
if (innerYRadius > SK_ScalarNearlyZero) {
|
||||
innerXRadius = SkMaxScalar(0, xRadius - scaledStroke.fX);
|
||||
innerRatio = innerXRadius/innerYRadius;
|
||||
}
|
||||
}
|
||||
xRadius += scaledStroke.fX;
|
||||
yRadius += scaledStroke.fY;
|
||||
}
|
||||
|
||||
SkScalar outerRatio = SkScalarDiv(xRadius, yRadius);
|
||||
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
verts[i].fCenter = center;
|
||||
verts[i].fOuterXRadius = xRadius + 0.5f;
|
||||
verts[i].fOuterXYRatio = outerRatio;
|
||||
verts[i].fInnerXRadius = innerXRadius - 0.5f;
|
||||
verts[i].fInnerXYRatio = innerRatio;
|
||||
}
|
||||
|
||||
SkScalar L = -xRadius;
|
||||
SkScalar R = +xRadius;
|
||||
SkScalar T = -yRadius;
|
||||
SkScalar B = +yRadius;
|
||||
|
||||
// We've extended the outer x radius out half a pixel to antialias.
|
||||
// Expand the drawn rect here so all the pixels will be captured.
|
||||
L += center.fX - SK_ScalarHalf;
|
||||
R += center.fX + SK_ScalarHalf;
|
||||
T += center.fY - SK_ScalarHalf;
|
||||
B += center.fY + SK_ScalarHalf;
|
||||
|
||||
verts[0].fPos = SkPoint::Make(L, T);
|
||||
verts[1].fPos = SkPoint::Make(R, T);
|
||||
verts[2].fPos = SkPoint::Make(L, B);
|
||||
verts[3].fPos = SkPoint::Make(R, B);
|
||||
|
||||
target->drawNonIndexed(kTriangleStrip_GrPrimitiveType, 0, 4);
|
||||
}
|
|
@ -1,10 +0,0 @@
|
|||
/*
|
||||
* 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 "GrPath.h"
|
||||
|
||||
SK_DEFINE_INST_COUNT(GrPath)
|
|
@ -1,30 +0,0 @@
|
|||
|
||||
/*
|
||||
* 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 GrPath_DEFINED
|
||||
#define GrPath_DEFINED
|
||||
|
||||
#include "GrResource.h"
|
||||
#include "GrRect.h"
|
||||
|
||||
class GrPath : public GrResource {
|
||||
public:
|
||||
SK_DECLARE_INST_COUNT(GrPath);
|
||||
|
||||
GrPath(GrGpu* gpu, bool isWrapped) : INHERITED(gpu, isWrapped) {}
|
||||
|
||||
const GrRect& getBounds() const { return fBounds; }
|
||||
|
||||
protected:
|
||||
GrRect fBounds;
|
||||
|
||||
private:
|
||||
typedef GrResource INHERITED;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -1,14 +0,0 @@
|
|||
|
||||
/*
|
||||
* Copyright 2011 Google Inc.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include "GrPathRenderer.h"
|
||||
|
||||
SK_DEFINE_INST_COUNT(GrPathRenderer)
|
||||
|
||||
GrPathRenderer::GrPathRenderer() {
|
||||
}
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче