aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/core
diff options
context:
space:
mode:
authorGravatar commit-bot@chromium.org <commit-bot@chromium.org@2bbb7eff-a529-9590-31e7-b0007b416f81>2014-04-16 10:16:39 +0000
committerGravatar commit-bot@chromium.org <commit-bot@chromium.org@2bbb7eff-a529-9590-31e7-b0007b416f81>2014-04-16 10:16:39 +0000
commit001f4ed2fb62ecdc98ce2884d925de11b7516d23 (patch)
tree1acb3cdef582b7a33a97e6c6631c62320ca39331 /src/core
parentd1061e254af7fa8267dc1a5ed444d1c4b1743b6d (diff)
Extract most of the mutable state of SkShader into a separate Context object.
SkShader currently stores some state during draw calls via setContext(...). Move that mutable state into a separate SkShader::Context class that is constructed on demand for the duration of the draw. Calls to setContext() are replaced with createContext() which returns a context corresponding to the shader object or NULL if the parameters to createContext are invalid. TEST=out/Debug/dm BUG=skia:1976 R=scroggo@google.com, skyostil@chromium.org, tomhudson@chromium.org, senorblanco@chromium.org, reed@google.com, bungeman@google.com Author: dominikg@chromium.org Review URL: https://codereview.chromium.org/207683004 git-svn-id: http://skia.googlecode.com/svn/trunk@14216 2bbb7eff-a529-9590-31e7-b0007b416f81
Diffstat (limited to 'src/core')
-rw-r--r--src/core/SkBitmapProcShader.cpp118
-rw-r--r--src/core/SkBitmapProcShader.h60
-rw-r--r--src/core/SkBitmapProcState.cpp3
-rw-r--r--src/core/SkBlitter.cpp277
-rw-r--r--src/core/SkBlitter.h7
-rw-r--r--src/core/SkBlitter_A8.cpp29
-rw-r--r--src/core/SkBlitter_ARGB32.cpp76
-rw-r--r--src/core/SkBlitter_RGB16.cpp105
-rw-r--r--src/core/SkCanvas.cpp46
-rw-r--r--src/core/SkComposeShader.cpp97
-rw-r--r--src/core/SkCoreBlitters.h30
-rw-r--r--src/core/SkDraw.cpp103
-rw-r--r--src/core/SkFilterShader.cpp80
-rw-r--r--src/core/SkFilterShader.h29
-rw-r--r--src/core/SkPictureShader.cpp125
-rw-r--r--src/core/SkPictureShader.h41
-rw-r--r--src/core/SkShader.cpp136
-rw-r--r--src/core/SkSmallAllocator.h23
18 files changed, 855 insertions, 530 deletions
diff --git a/src/core/SkBitmapProcShader.cpp b/src/core/SkBitmapProcShader.cpp
index a397b78439..5f5eb1866e 100644
--- a/src/core/SkBitmapProcShader.cpp
+++ b/src/core/SkBitmapProcShader.cpp
@@ -34,18 +34,16 @@ bool SkBitmapProcShader::CanDo(const SkBitmap& bm, TileMode tx, TileMode ty) {
SkBitmapProcShader::SkBitmapProcShader(const SkBitmap& src,
TileMode tmx, TileMode tmy) {
fRawBitmap = src;
- fState.fTileModeX = (uint8_t)tmx;
- fState.fTileModeY = (uint8_t)tmy;
- fFlags = 0; // computed in setContext
+ fTileModeX = (uint8_t)tmx;
+ fTileModeY = (uint8_t)tmy;
}
SkBitmapProcShader::SkBitmapProcShader(SkReadBuffer& buffer)
: INHERITED(buffer) {
buffer.readBitmap(&fRawBitmap);
fRawBitmap.setImmutable();
- fState.fTileModeX = buffer.readUInt();
- fState.fTileModeY = buffer.readUInt();
- fFlags = 0; // computed in setContext
+ fTileModeX = buffer.readUInt();
+ fTileModeY = buffer.readUInt();
}
SkShader::BitmapType SkBitmapProcShader::asABitmap(SkBitmap* texture,
@@ -58,8 +56,8 @@ SkShader::BitmapType SkBitmapProcShader::asABitmap(SkBitmap* texture,
texM->reset();
}
if (xy) {
- xy[0] = (TileMode)fState.fTileModeX;
- xy[1] = (TileMode)fState.fTileModeY;
+ xy[0] = (TileMode)fTileModeX;
+ xy[1] = (TileMode)fTileModeY;
}
return kDefault_BitmapType;
}
@@ -68,8 +66,8 @@ void SkBitmapProcShader::flatten(SkWriteBuffer& buffer) const {
this->INHERITED::flatten(buffer);
buffer.writeBitmap(fRawBitmap);
- buffer.writeUInt(fState.fTileModeX);
- buffer.writeUInt(fState.fTileModeY);
+ buffer.writeUInt(fTileModeX);
+ buffer.writeUInt(fTileModeY);
}
static bool only_scale_and_translate(const SkMatrix& matrix) {
@@ -98,25 +96,67 @@ static bool valid_for_drawing(const SkBitmap& bm) {
return true;
}
-bool SkBitmapProcShader::setContext(const SkBitmap& device,
- const SkPaint& paint,
- const SkMatrix& matrix) {
+bool SkBitmapProcShader::validInternal(const SkBitmap& device,
+ const SkPaint& paint,
+ const SkMatrix& matrix,
+ SkMatrix* totalInverse,
+ SkBitmapProcState* state) const {
if (!fRawBitmap.getTexture() && !valid_for_drawing(fRawBitmap)) {
return false;
}
- // do this first, so we have a correct inverse matrix
- if (!this->INHERITED::setContext(device, paint, matrix)) {
- return false;
+ // Make sure we can use totalInverse as a cache.
+ SkMatrix totalInverseLocal;
+ if (NULL == totalInverse) {
+ totalInverse = &totalInverseLocal;
}
- fState.fOrigBitmap = fRawBitmap;
- if (!fState.chooseProcs(this->getTotalInverse(), paint)) {
- this->INHERITED::endContext();
+ // Do this first, so we know the matrix can be inverted.
+ if (!this->INHERITED::validContext(device, paint, matrix, totalInverse)) {
return false;
}
- const SkBitmap& bitmap = *fState.fBitmap;
+ SkASSERT(state);
+ state->fTileModeX = fTileModeX;
+ state->fTileModeY = fTileModeY;
+ state->fOrigBitmap = fRawBitmap;
+ return state->chooseProcs(*totalInverse, paint);
+}
+
+bool SkBitmapProcShader::validContext(const SkBitmap& device,
+ const SkPaint& paint,
+ const SkMatrix& matrix,
+ SkMatrix* totalInverse) const {
+ SkBitmapProcState state;
+ return this->validInternal(device, paint, matrix, totalInverse, &state);
+}
+
+SkShader::Context* SkBitmapProcShader::createContext(const SkBitmap& device, const SkPaint& paint,
+ const SkMatrix& matrix, void* storage) const {
+ void* stateStorage = (char*)storage + sizeof(BitmapProcShaderContext);
+ SkBitmapProcState* state = SkNEW_PLACEMENT(stateStorage, SkBitmapProcState);
+ if (!this->validInternal(device, paint, matrix, NULL, state)) {
+ state->~SkBitmapProcState();
+ return NULL;
+ }
+
+ return SkNEW_PLACEMENT_ARGS(storage, BitmapProcShaderContext,
+ (*this, device, paint, matrix, state));
+}
+
+size_t SkBitmapProcShader::contextSize() const {
+ // The SkBitmapProcState is stored outside of the context object, with the context holding
+ // a pointer to it.
+ return sizeof(BitmapProcShaderContext) + sizeof(SkBitmapProcState);
+}
+
+SkBitmapProcShader::BitmapProcShaderContext::BitmapProcShaderContext(
+ const SkBitmapProcShader& shader, const SkBitmap& device,
+ const SkPaint& paint, const SkMatrix& matrix, SkBitmapProcState* state)
+ : INHERITED(shader, device, paint, matrix)
+ , fState(state)
+{
+ const SkBitmap& bitmap = *fState->fBitmap;
bool bitmapIsOpaque = bitmap.isOpaque();
// update fFlags
@@ -157,12 +197,12 @@ bool SkBitmapProcShader::setContext(const SkBitmap& device,
}
fFlags = flags;
- return true;
}
-void SkBitmapProcShader::endContext() {
- fState.endContext();
- this->INHERITED::endContext();
+SkBitmapProcShader::BitmapProcShaderContext::~BitmapProcShaderContext() {
+ // The bitmap proc state has been created outside of the context on memory that will be freed
+ // elsewhere. Only call the destructor but leave the freeing of the memory to the caller.
+ fState->~SkBitmapProcState();
}
#define BUF_MAX 128
@@ -176,8 +216,9 @@ void SkBitmapProcShader::endContext() {
#define TEST_BUFFER_EXTRA 0
#endif
-void SkBitmapProcShader::shadeSpan(int x, int y, SkPMColor dstC[], int count) {
- const SkBitmapProcState& state = fState;
+void SkBitmapProcShader::BitmapProcShaderContext::shadeSpan(int x, int y, SkPMColor dstC[],
+ int count) {
+ const SkBitmapProcState& state = *fState;
if (state.getShaderProc32()) {
state.getShaderProc32()(state, x, y, dstC, count);
return;
@@ -186,7 +227,7 @@ void SkBitmapProcShader::shadeSpan(int x, int y, SkPMColor dstC[], int count) {
uint32_t buffer[BUF_MAX + TEST_BUFFER_EXTRA];
SkBitmapProcState::MatrixProc mproc = state.getMatrixProc();
SkBitmapProcState::SampleProc32 sproc = state.getSampleProc32();
- int max = fState.maxCountForBufferSize(sizeof(buffer[0]) * BUF_MAX);
+ int max = state.maxCountForBufferSize(sizeof(buffer[0]) * BUF_MAX);
SkASSERT(state.fBitmap->getPixels());
SkASSERT(state.fBitmap->pixelRef() == NULL ||
@@ -220,16 +261,17 @@ void SkBitmapProcShader::shadeSpan(int x, int y, SkPMColor dstC[], int count) {
}
}
-SkShader::ShadeProc SkBitmapProcShader::asAShadeProc(void** ctx) {
- if (fState.getShaderProc32()) {
- *ctx = &fState;
- return (ShadeProc)fState.getShaderProc32();
+SkShader::Context::ShadeProc SkBitmapProcShader::BitmapProcShaderContext::asAShadeProc(void** ctx) {
+ if (fState->getShaderProc32()) {
+ *ctx = fState;
+ return (ShadeProc)fState->getShaderProc32();
}
return NULL;
}
-void SkBitmapProcShader::shadeSpan16(int x, int y, uint16_t dstC[], int count) {
- const SkBitmapProcState& state = fState;
+void SkBitmapProcShader::BitmapProcShaderContext::shadeSpan16(int x, int y, uint16_t dstC[],
+ int count) {
+ const SkBitmapProcState& state = *fState;
if (state.getShaderProc16()) {
state.getShaderProc16()(state, x, y, dstC, count);
return;
@@ -238,7 +280,7 @@ void SkBitmapProcShader::shadeSpan16(int x, int y, uint16_t dstC[], int count) {
uint32_t buffer[BUF_MAX];
SkBitmapProcState::MatrixProc mproc = state.getMatrixProc();
SkBitmapProcState::SampleProc16 sproc = state.getSampleProc16();
- int max = fState.maxCountForBufferSize(sizeof(buffer));
+ int max = state.maxCountForBufferSize(sizeof(buffer));
SkASSERT(state.fBitmap->getPixels());
SkASSERT(state.fBitmap->pixelRef() == NULL ||
@@ -342,8 +384,8 @@ void SkBitmapProcShader::toString(SkString* str) const {
str->append("BitmapShader: (");
str->appendf("(%s, %s)",
- gTileModeName[fState.fTileModeX],
- gTileModeName[fState.fTileModeY]);
+ gTileModeName[fTileModeX],
+ gTileModeName[fTileModeY]);
str->append(" ");
fRawBitmap.toString(str);
@@ -384,8 +426,8 @@ GrEffectRef* SkBitmapProcShader::asNewEffect(GrContext* context, const SkPaint&
matrix.preConcat(lmInverse);
SkShader::TileMode tm[] = {
- (TileMode)fState.fTileModeX,
- (TileMode)fState.fTileModeY,
+ (TileMode)fTileModeX,
+ (TileMode)fTileModeY,
};
// Must set wrap and filter on the sampler before requesting a texture. In two places below
diff --git a/src/core/SkBitmapProcShader.h b/src/core/SkBitmapProcShader.h
index 8e225a5e98..e0c78b8e45 100644
--- a/src/core/SkBitmapProcShader.h
+++ b/src/core/SkBitmapProcShader.h
@@ -20,14 +20,16 @@ public:
// overrides from SkShader
virtual bool isOpaque() const SK_OVERRIDE;
- virtual bool setContext(const SkBitmap&, const SkPaint&, const SkMatrix&) SK_OVERRIDE;
- virtual void endContext() SK_OVERRIDE;
- virtual uint32_t getFlags() SK_OVERRIDE { return fFlags; }
- virtual void shadeSpan(int x, int y, SkPMColor dstC[], int count) SK_OVERRIDE;
- virtual ShadeProc asAShadeProc(void** ctx) SK_OVERRIDE;
- virtual void shadeSpan16(int x, int y, uint16_t dstC[], int count) SK_OVERRIDE;
virtual BitmapType asABitmap(SkBitmap*, SkMatrix*, TileMode*) const SK_OVERRIDE;
+ virtual bool validContext(const SkBitmap& device,
+ const SkPaint& paint,
+ const SkMatrix& matrix,
+ SkMatrix* totalInverse = NULL) const SK_OVERRIDE;
+ virtual SkShader::Context* createContext(const SkBitmap&, const SkPaint&,
+ const SkMatrix&, void* storage) const SK_OVERRIDE;
+ virtual size_t contextSize() const SK_OVERRIDE;
+
static bool CanDo(const SkBitmap&, TileMode tx, TileMode ty);
SK_TO_STRING_OVERRIDE()
@@ -37,22 +39,54 @@ public:
GrEffectRef* asNewEffect(GrContext*, const SkPaint&) const SK_OVERRIDE;
#endif
+ class BitmapProcShaderContext : public SkShader::Context {
+ public:
+ // The context takes ownership of the state. It will call its destructor
+ // but will NOT free the memory.
+ BitmapProcShaderContext(const SkBitmapProcShader& shader,
+ const SkBitmap& device,
+ const SkPaint& paint,
+ const SkMatrix& matrix,
+ SkBitmapProcState* state);
+ virtual ~BitmapProcShaderContext();
+
+ virtual void shadeSpan(int x, int y, SkPMColor dstC[], int count) SK_OVERRIDE;
+ virtual ShadeProc asAShadeProc(void** ctx) SK_OVERRIDE;
+ virtual void shadeSpan16(int x, int y, uint16_t dstC[], int count) SK_OVERRIDE;
+
+ virtual uint32_t getFlags() const SK_OVERRIDE { return fFlags; }
+
+ private:
+ SkBitmapProcState* fState;
+ uint32_t fFlags;
+
+ typedef SkShader::Context INHERITED;
+ };
+
protected:
SkBitmapProcShader(SkReadBuffer& );
virtual void flatten(SkWriteBuffer&) const SK_OVERRIDE;
- SkBitmap fRawBitmap; // experimental for RLE encoding
- SkBitmapProcState fState;
- uint32_t fFlags;
+ SkBitmap fRawBitmap; // experimental for RLE encoding
+ uint8_t fTileModeX, fTileModeY;
private:
+ bool validInternal(const SkBitmap& device, const SkPaint& paint,
+ const SkMatrix& matrix, SkMatrix* totalInverse,
+ SkBitmapProcState* state) const;
+
typedef SkShader INHERITED;
};
-// Commonly used allocator. It currently is only used to allocate up to 2 objects. The total
-// bytes requested is calculated using one of our large shaders plus the size of an Sk3DBlitter
-// in SkDraw.cpp
-typedef SkSmallAllocator<2, sizeof(SkBitmapProcShader) + sizeof(void*) * 2> SkTBlitterAllocator;
+// Commonly used allocator. It currently is only used to allocate up to 3 objects. The total
+// bytes requested is calculated using one of our large shaders, its context size plus the size of
+// an Sk3DBlitter in SkDraw.cpp
+// Note that some contexts may contain other contexts (e.g. for compose shaders), but we've not
+// yet found a situation where the size below isn't big enough.
+typedef SkSmallAllocator<3, sizeof(SkBitmapProcShader) +
+ sizeof(SkBitmapProcShader::BitmapProcShaderContext) +
+ sizeof(SkBitmapProcState) +
+ sizeof(void*) * 2> SkTBlitterAllocator;
// If alloc is non-NULL, it will be used to allocate the returned SkShader, and MUST outlive
// the SkShader.
diff --git a/src/core/SkBitmapProcState.cpp b/src/core/SkBitmapProcState.cpp
index cdc582bfee..8874e7b445 100644
--- a/src/core/SkBitmapProcState.cpp
+++ b/src/core/SkBitmapProcState.cpp
@@ -398,6 +398,7 @@ bool SkBitmapProcState::chooseProcs(const SkMatrix& inv, const SkPaint& paint) {
}
// The above logic should have always assigned fBitmap, but in case it
// didn't, we check for that now...
+ // TODO(dominikg): Ask humper@ if we can just use an SkASSERT(fBitmap)?
if (NULL == fBitmap) {
return false;
}
@@ -480,6 +481,7 @@ bool SkBitmapProcState::chooseProcs(const SkMatrix& inv, const SkPaint& paint) {
// shader will perform.
fMatrixProc = this->chooseMatrixProc(trivialMatrix);
+ // TODO(dominikg): SkASSERT(fMatrixProc) instead? chooseMatrixProc never returns NULL.
if (NULL == fMatrixProc) {
return false;
}
@@ -521,6 +523,7 @@ bool SkBitmapProcState::chooseProcs(const SkMatrix& inv, const SkPaint& paint) {
fPaintPMColor = SkPreMultiplyColor(paint.getColor());
break;
default:
+ // TODO(dominikg): Should we ever get here? SkASSERT(false) instead?
return false;
}
diff --git a/src/core/SkBlitter.cpp b/src/core/SkBlitter.cpp
index 52a05eded8..ad51874271 100644
--- a/src/core/SkBlitter.cpp
+++ b/src/core/SkBlitter.cpp
@@ -26,6 +26,15 @@ SkBlitter::~SkBlitter() {}
bool SkBlitter::isNullBlitter() const { return false; }
+bool SkBlitter::resetShaderContext(const SkBitmap& device, const SkPaint& paint,
+ const SkMatrix& matrix) {
+ return true;
+}
+
+SkShader::Context* SkBlitter::getShaderContext() const {
+ return NULL;
+}
+
const SkBitmap* SkBlitter::justAnOpaqueColor(uint32_t* value) {
return NULL;
}
@@ -568,102 +577,149 @@ class Sk3DShader : public SkShader {
public:
Sk3DShader(SkShader* proxy) : fProxy(proxy) {
SkSafeRef(proxy);
- fMask = NULL;
}
virtual ~Sk3DShader() {
SkSafeUnref(fProxy);
}
- void setMask(const SkMask* mask) { fMask = mask; }
+ virtual size_t contextSize() const SK_OVERRIDE {
+ size_t size = sizeof(Sk3DShaderContext);
+ if (fProxy) {
+ size += fProxy->contextSize();
+ }
+ return size;
+ }
- virtual bool setContext(const SkBitmap& device, const SkPaint& paint,
- const SkMatrix& matrix) SK_OVERRIDE {
- if (!this->INHERITED::setContext(device, paint, matrix)) {
+ virtual bool validContext(const SkBitmap& device, const SkPaint& paint,
+ const SkMatrix& matrix, SkMatrix* totalInverse = NULL) const
+ SK_OVERRIDE
+ {
+ if (!this->INHERITED::validContext(device, paint, matrix, totalInverse)) {
return false;
}
if (fProxy) {
- if (!fProxy->setContext(device, paint, matrix)) {
- // must keep our set/end context calls balanced
- this->INHERITED::endContext();
- return false;
- }
- } else {
- fPMColor = SkPreMultiplyColor(paint.getColor());
+ return fProxy->validContext(device, paint, matrix);
}
return true;
}
- virtual void endContext() SK_OVERRIDE {
+ virtual SkShader::Context* createContext(const SkBitmap& device,
+ const SkPaint& paint,
+ const SkMatrix& matrix,
+ void* storage) const SK_OVERRIDE
+ {
+ if (!this->validContext(device, paint, matrix)) {
+ return NULL;
+ }
+
+ SkShader::Context* proxyContext;
if (fProxy) {
- fProxy->endContext();
+ char* proxyContextStorage = (char*) storage + sizeof(Sk3DShaderContext);
+ proxyContext = fProxy->createContext(device, paint, matrix, proxyContextStorage);
+ SkASSERT(proxyContext);
+ } else {
+ proxyContext = NULL;
}
- this->INHERITED::endContext();
+ return SkNEW_PLACEMENT_ARGS(storage, Sk3DShaderContext, (*this, device, paint, matrix,
+ proxyContext));
}
- virtual void shadeSpan(int x, int y, SkPMColor span[], int count) SK_OVERRIDE {
- if (fProxy) {
- fProxy->shadeSpan(x, y, span, count);
+ class Sk3DShaderContext : public SkShader::Context {
+ public:
+ // Calls proxyContext's destructor but will NOT free its memory.
+ Sk3DShaderContext(const Sk3DShader& shader, const SkBitmap& device, const SkPaint& paint,
+ const SkMatrix& matrix, SkShader::Context* proxyContext)
+ : INHERITED(shader, device, paint, matrix)
+ , fMask(NULL)
+ , fProxyContext(proxyContext)
+ {
+ if (!fProxyContext) {
+ fPMColor = SkPreMultiplyColor(paint.getColor());
+ }
}
- if (fMask == NULL) {
- if (fProxy == NULL) {
- sk_memset32(span, fPMColor, count);
+ virtual ~Sk3DShaderContext() {
+ if (fProxyContext) {
+ fProxyContext->SkShader::Context::~Context();
}
- return;
}
- SkASSERT(fMask->fBounds.contains(x, y));
- SkASSERT(fMask->fBounds.contains(x + count - 1, y));
+ void setMask(const SkMask* mask) { fMask = mask; }
- size_t size = fMask->computeImageSize();
- const uint8_t* alpha = fMask->getAddr8(x, y);
- const uint8_t* mulp = alpha + size;
- const uint8_t* addp = mulp + size;
+ virtual void shadeSpan(int x, int y, SkPMColor span[], int count) SK_OVERRIDE {
+ if (fProxyContext) {
+ fProxyContext->shadeSpan(x, y, span, count);
+ }
- if (fProxy) {
- for (int i = 0; i < count; i++) {
- if (alpha[i]) {
- SkPMColor c = span[i];
- if (c) {
- unsigned a = SkGetPackedA32(c);
- unsigned r = SkGetPackedR32(c);
- unsigned g = SkGetPackedG32(c);
- unsigned b = SkGetPackedB32(c);
+ if (fMask == NULL) {
+ if (fProxyContext == NULL) {
+ sk_memset32(span, fPMColor, count);
+ }
+ return;
+ }
+ SkASSERT(fMask->fBounds.contains(x, y));
+ SkASSERT(fMask->fBounds.contains(x + count - 1, y));
+
+ size_t size = fMask->computeImageSize();
+ const uint8_t* alpha = fMask->getAddr8(x, y);
+ const uint8_t* mulp = alpha + size;
+ const uint8_t* addp = mulp + size;
+
+ if (fProxyContext) {
+ for (int i = 0; i < count; i++) {
+ if (alpha[i]) {
+ SkPMColor c = span[i];
+ if (c) {
+ unsigned a = SkGetPackedA32(c);
+ unsigned r = SkGetPackedR32(c);
+ unsigned g = SkGetPackedG32(c);
+ unsigned b = SkGetPackedB32(c);
+
+ unsigned mul = SkAlpha255To256(mulp[i]);
+ unsigned add = addp[i];
+
+ r = SkFastMin32(SkAlphaMul(r, mul) + add, a);
+ g = SkFastMin32(SkAlphaMul(g, mul) + add, a);
+ b = SkFastMin32(SkAlphaMul(b, mul) + add, a);
+
+ span[i] = SkPackARGB32(a, r, g, b);
+ }
+ } else {
+ span[i] = 0;
+ }
+ }
+ } else { // color
+ unsigned a = SkGetPackedA32(fPMColor);
+ unsigned r = SkGetPackedR32(fPMColor);
+ unsigned g = SkGetPackedG32(fPMColor);
+ unsigned b = SkGetPackedB32(fPMColor);
+ for (int i = 0; i < count; i++) {
+ if (alpha[i]) {
unsigned mul = SkAlpha255To256(mulp[i]);
unsigned add = addp[i];
- r = SkFastMin32(SkAlphaMul(r, mul) + add, a);
- g = SkFastMin32(SkAlphaMul(g, mul) + add, a);
- b = SkFastMin32(SkAlphaMul(b, mul) + add, a);
-
- span[i] = SkPackARGB32(a, r, g, b);
+ span[i] = SkPackARGB32( a,
+ SkFastMin32(SkAlphaMul(r, mul) + add, a),
+ SkFastMin32(SkAlphaMul(g, mul) + add, a),
+ SkFastMin32(SkAlphaMul(b, mul) + add, a));
+ } else {
+ span[i] = 0;
}
- } else {
- span[i] = 0;
- }
- }
- } else { // color
- unsigned a = SkGetPackedA32(fPMColor);
- unsigned r = SkGetPackedR32(fPMColor);
- unsigned g = SkGetPackedG32(fPMColor);
- unsigned b = SkGetPackedB32(fPMColor);
- for (int i = 0; i < count; i++) {
- if (alpha[i]) {
- unsigned mul = SkAlpha255To256(mulp[i]);
- unsigned add = addp[i];
-
- span[i] = SkPackARGB32( a,
- SkFastMin32(SkAlphaMul(r, mul) + add, a),
- SkFastMin32(SkAlphaMul(g, mul) + add, a),
- SkFastMin32(SkAlphaMul(b, mul) + add, a));
- } else {
- span[i] = 0;
}
}
}
- }
+
+ private:
+ // Unowned.
+ const SkMask* fMask;
+ // Memory is unowned, but we need to call the destructor.
+ SkShader::Context* fProxyContext;
+ SkPMColor fPMColor;
+
+ typedef SkShader::Context INHERITED;
+ };
#ifndef SK_IGNORE_TO_STRING
virtual void toString(SkString* str) const SK_OVERRIDE {
@@ -685,29 +741,30 @@ public:
protected:
Sk3DShader(SkReadBuffer& buffer) : INHERITED(buffer) {
fProxy = buffer.readShader();
- fPMColor = buffer.readColor();
- fMask = NULL;
+ // Leaving this here until we bump the picture version, though this
+ // shader should never be recorded.
+ buffer.readColor();
}
virtual void flatten(SkWriteBuffer& buffer) const SK_OVERRIDE {
this->INHERITED::flatten(buffer);
buffer.writeFlattenable(fProxy);
- buffer.writeColor(fPMColor);
+ // Leaving this here until we bump the picture version, though this
+ // shader should never be recorded.
+ buffer.writeColor(SkColor());
}
private:
SkShader* fProxy;
- SkPMColor fPMColor;
- const SkMask* fMask;
typedef SkShader INHERITED;
};
class Sk3DBlitter : public SkBlitter {
public:
- Sk3DBlitter(SkBlitter* proxy, Sk3DShader* shader)
+ Sk3DBlitter(SkBlitter* proxy, Sk3DShader::Sk3DShaderContext* shaderContext)
: fProxy(proxy)
- , f3DShader(SkRef(shader))
+ , f3DShaderContext(shaderContext)
{}
virtual void blitH(int x, int y, int width) {
@@ -729,22 +786,22 @@ public:
virtual void blitMask(const SkMask& mask, const SkIRect& clip) {
if (mask.fFormat == SkMask::k3D_Format) {
- f3DShader->setMask(&mask);
+ f3DShaderContext->setMask(&mask);
((SkMask*)&mask)->fFormat = SkMask::kA8_Format;
fProxy->blitMask(mask, clip);
((SkMask*)&mask)->fFormat = SkMask::k3D_Format;
- f3DShader->setMask(NULL);
+ f3DShaderContext->setMask(NULL);
} else {
fProxy->blitMask(mask, clip);
}
}
private:
- // fProxy is unowned. It will be deleted by SkSmallAllocator.
- SkBlitter* fProxy;
- SkAutoTUnref<Sk3DShader> f3DShader;
+ // Both pointers are unowned. They will be deleted by SkSmallAllocator.
+ SkBlitter* fProxy;
+ Sk3DShader::Sk3DShaderContext* f3DShaderContext;
};
///////////////////////////////////////////////////////////////////////////////
@@ -754,8 +811,7 @@ private:
static bool just_solid_color(const SkPaint& paint) {
if (paint.getAlpha() == 0xFF && paint.getColorFilter() == NULL) {
SkShader* shader = paint.getShader();
- if (NULL == shader ||
- (shader->getFlags() & SkShader::kOpaqueAlpha_Flag)) {
+ if (NULL == shader) {
return true;
}
}
@@ -893,16 +949,22 @@ SkBlitter* SkBlitter::Choose(const SkBitmap& device,
}
/*
- * We need to have balanced calls to the shader:
- * setContext
- * endContext
- * We make the first call here, in case it fails we can abort the draw.
- * The endContext() call is made by the blitter (assuming setContext did
- * not fail) in its destructor.
+ * We create a SkShader::Context object, and store it on the blitter.
*/
- if (shader && !shader->setContext(device, *paint, matrix)) {
- blitter = allocator->createT<SkNullBlitter>();
- return blitter;
+ SkShader::Context* shaderContext;
+ if (shader) {
+ // Try to create the ShaderContext
+ void* storage = allocator->reserveT<SkShader::Context>(shader->contextSize());
+ shaderContext = shader->createContext(device, *paint, matrix, storage);
+ if (!shaderContext) {
+ allocator->freeLast();
+ blitter = allocator->createT<SkNullBlitter>();
+ return blitter;
+ }
+ SkASSERT(shaderContext);
+ SkASSERT((void*) shaderContext == storage);
+ } else {
+ shaderContext = NULL;
}
@@ -913,19 +975,20 @@ SkBlitter* SkBlitter::Choose(const SkBitmap& device,
SkASSERT(NULL == paint->getXfermode());
blitter = allocator->createT<SkA8_Coverage_Blitter>(device, *paint);
} else if (shader) {
- blitter = allocator->createT<SkA8_Shader_Blitter>(device, *paint);
+ blitter = allocator->createT<SkA8_Shader_Blitter>(device, *paint, shaderContext);
} else {
blitter = allocator->createT<SkA8_Blitter>(device, *paint);
}
break;
case kRGB_565_SkColorType:
- blitter = SkBlitter_ChooseD565(device, *paint, allocator);
+ blitter = SkBlitter_ChooseD565(device, *paint, shaderContext, allocator);
break;
case kN32_SkColorType:
if (shader) {
- blitter = allocator->createT<SkARGB32_Shader_Blitter>(device, *paint);
+ blitter = allocator->createT<SkARGB32_Shader_Blitter>(
+ device, *paint, shaderContext);
} else if (paint->getColor() == SK_ColorBLACK) {
blitter = allocator->createT<SkARGB32_Black_Blitter>(device, *paint);
} else if (paint->getAlpha() == 0xFF) {
@@ -944,7 +1007,9 @@ SkBlitter* SkBlitter::Choose(const SkBitmap& device,
if (shader3D) {
SkBlitter* innerBlitter = blitter;
// innerBlitter was allocated by allocator, which will delete it.
- blitter = allocator->createT<Sk3DBlitter>(innerBlitter, shader3D);
+ // We know shaderContext is of type Sk3DShaderContext because it belongs to shader3D.
+ blitter = allocator->createT<Sk3DBlitter>(innerBlitter,
+ static_cast<Sk3DShader::Sk3DShaderContext*>(shaderContext));
}
return blitter;
}
@@ -956,18 +1021,36 @@ const uint32_t gMask_00FF00FF = 0xFF00FF;
///////////////////////////////////////////////////////////////////////////////
-SkShaderBlitter::SkShaderBlitter(const SkBitmap& device, const SkPaint& paint)
- : INHERITED(device) {
- fShader = paint.getShader();
+SkShaderBlitter::SkShaderBlitter(const SkBitmap& device, const SkPaint& paint,
+ SkShader::Context* shaderContext)
+ : INHERITED(device)
+ , fShader(paint.getShader())
+ , fShaderContext(shaderContext) {
SkASSERT(fShader);
- SkASSERT(fShader->setContextHasBeenCalled());
+ SkASSERT(fShaderContext);
fShader->ref();
- fShaderFlags = fShader->getFlags();
+ fShaderFlags = fShaderContext->getFlags();
}
SkShaderBlitter::~SkShaderBlitter() {
- SkASSERT(fShader->setContextHasBeenCalled());
- fShader->endContext();
fShader->unref();
}
+
+bool SkShaderBlitter::resetShaderContext(const SkBitmap& device, const SkPaint& paint,
+ const SkMatrix& matrix) {
+ if (!fShader->validContext(device, paint, matrix)) {
+ return false;
+ }
+
+ // Only destroy the old context if we have a new one. We need to ensure to have a
+ // live context in fShaderContext because the storage is owned by an SkSmallAllocator
+ // outside of this class.
+ // The new context will be of the same size as the old one because we use the same
+ // shader to create it. It is therefore safe to re-use the storage.
+ fShaderContext->SkShader::Context::~Context();
+ fShaderContext = fShader->createContext(device, paint, matrix, (void*)fShaderContext);
+ SkASSERT(fShaderContext);
+
+ return true;
+}
diff --git a/src/core/SkBlitter.h b/src/core/SkBlitter.h
index d19a34badc..f76839e8b6 100644
--- a/src/core/SkBlitter.h
+++ b/src/core/SkBlitter.h
@@ -61,6 +61,13 @@ public:
*/
virtual bool isNullBlitter() const;
+ /**
+ * Special methods for SkShaderBlitter. On all other classes this is a no-op.
+ */
+ virtual bool resetShaderContext(const SkBitmap& device, const SkPaint& paint,
+ const SkMatrix& matrix);
+ virtual SkShader::Context* getShaderContext() const;
+
///@name non-virtual helpers
void blitMaskRegion(const SkMask& mask, const SkRegion& clip);
void blitRectRegion(const SkIRect& rect, const SkRegion& clip);
diff --git a/src/core/SkBlitter_A8.cpp b/src/core/SkBlitter_A8.cpp
index 983a226e34..11f425903b 100644
--- a/src/core/SkBlitter_A8.cpp
+++ b/src/core/SkBlitter_A8.cpp
@@ -228,11 +228,12 @@ void SkA8_Blitter::blitRect(int x, int y, int width, int height) {
///////////////////////////////////////////////////////////////////////
-SkA8_Shader_Blitter::SkA8_Shader_Blitter(const SkBitmap& device, const SkPaint& paint)
- : INHERITED(device, paint) {
+SkA8_Shader_Blitter::SkA8_Shader_Blitter(const SkBitmap& device, const SkPaint& paint,
+ SkShader::Context* shaderContext)
+ : INHERITED(device, paint, shaderContext) {
if ((fXfermode = paint.getXfermode()) != NULL) {
fXfermode->ref();
- SkASSERT(fShader);
+ SkASSERT(fShaderContext);
}
int width = device.width();
@@ -250,13 +251,14 @@ void SkA8_Shader_Blitter::blitH(int x, int y, int width) {
(unsigned)(x + width) <= (unsigned)fDevice.width());
uint8_t* device = fDevice.getAddr8(x, y);
+ SkShader::Context* shaderContext = fShaderContext;
- if ((fShader->getFlags() & SkShader::kOpaqueAlpha_Flag) && !fXfermode) {
+ if ((shaderContext->getFlags() & SkShader::kOpaqueAlpha_Flag) && !fXfermode) {
memset(device, 0xFF, width);
} else {
SkPMColor* span = fBuffer;
- fShader->shadeSpan(x, y, span, width);
+ shaderContext->shadeSpan(x, y, span, width);
if (fXfermode) {
fXfermode->xferA8(device, span, width, NULL);
} else {
@@ -282,12 +284,12 @@ static inline uint8_t aa_blend8(SkPMColor src, U8CPU da, int aa) {
void SkA8_Shader_Blitter::blitAntiH(int x, int y, const SkAlpha antialias[],
const int16_t runs[]) {
- SkShader* shader = fShader;
- SkXfermode* mode = fXfermode;
- uint8_t* aaExpand = fAAExpand;
- SkPMColor* span = fBuffer;
- uint8_t* device = fDevice.getAddr8(x, y);
- int opaque = fShader->getFlags() & SkShader::kOpaqueAlpha_Flag;
+ SkShader::Context* shaderContext = fShaderContext;
+ SkXfermode* mode = fXfermode;
+ uint8_t* aaExpand = fAAExpand;
+ SkPMColor* span = fBuffer;
+ uint8_t* device = fDevice.getAddr8(x, y);
+ int opaque = shaderContext->getFlags() & SkShader::kOpaqueAlpha_Flag;
for (;;) {
int count = *runs;
@@ -299,7 +301,7 @@ void SkA8_Shader_Blitter::blitAntiH(int x, int y, const SkAlpha antialias[],
if (opaque && aa == 255 && mode == NULL) {
memset(device, 0xFF, count);
} else {
- shader->shadeSpan(x, y, span, count);
+ shaderContext->shadeSpan(x, y, span, count);
if (mode) {
memset(aaExpand, aa, count);
mode->xferA8(device, span, count, aaExpand);
@@ -329,11 +331,12 @@ void SkA8_Shader_Blitter::blitMask(const SkMask& mask, const SkIRect& clip) {
int height = clip.height();
uint8_t* device = fDevice.getAddr8(x, y);
const uint8_t* alpha = mask.getAddr8(x, y);
+ SkShader::Context* shaderContext = fShaderContext;
SkPMColor* span = fBuffer;
while (--height >= 0) {
- fShader->shadeSpan(x, y, span, width);
+ shaderContext->shadeSpan(x, y, span, width);
if (fXfermode) {
fXfermode->xferA8(device, span, width, alpha);
} else {
diff --git a/src/core/SkBlitter_ARGB32.cpp b/src/core/SkBlitter_ARGB32.cpp
index d4bec1bc08..118a1d12f3 100644
--- a/src/core/SkBlitter_ARGB32.cpp
+++ b/src/core/SkBlitter_ARGB32.cpp
@@ -275,14 +275,16 @@ static void blend_srcmode(SkPMColor* SK_RESTRICT device,
}
SkARGB32_Shader_Blitter::SkARGB32_Shader_Blitter(const SkBitmap& device,
- const SkPaint& paint) : INHERITED(device, paint) {
+ const SkPaint& paint, SkShader::Context* shaderContext)
+ : INHERITED(device, paint, shaderContext)
+{
fBuffer = (SkPMColor*)sk_malloc_throw(device.width() * (sizeof(SkPMColor)));
fXfermode = paint.getXfermode();
SkSafeRef(fXfermode);
int flags = 0;
- if (!(fShader->getFlags() & SkShader::kOpaqueAlpha_Flag)) {
+ if (!(shaderContext->getFlags() & SkShader::kOpaqueAlpha_Flag)) {
flags |= SkBlitRow::kSrcPixelAlpha_Flag32;
}
// we call this on the output from the shader
@@ -292,7 +294,7 @@ SkARGB32_Shader_Blitter::SkARGB32_Shader_Blitter(const SkBitmap& device,
fShadeDirectlyIntoDevice = false;
if (fXfermode == NULL) {
- if (fShader->getFlags() & SkShader::kOpaqueAlpha_Flag) {
+ if (shaderContext->getFlags() & SkShader::kOpaqueAlpha_Flag) {
fShadeDirectlyIntoDevice = true;
}
} else {
@@ -305,7 +307,7 @@ SkARGB32_Shader_Blitter::SkARGB32_Shader_Blitter(const SkBitmap& device,
}
}
- fConstInY = SkToBool(fShader->getFlags() & SkShader::kConstInY32_Flag);
+ fConstInY = SkToBool(shaderContext->getFlags() & SkShader::kConstInY32_Flag);
}
SkARGB32_Shader_Blitter::~SkARGB32_Shader_Blitter() {
@@ -319,10 +321,10 @@ void SkARGB32_Shader_Blitter::blitH(int x, int y, int width) {
uint32_t* device = fDevice.getAddr32(x, y);
if (fShadeDirectlyIntoDevice) {
- fShader->shadeSpan(x, y, device, width);
+ fShaderContext->shadeSpan(x, y, device, width);
} else {
SkPMColor* span = fBuffer;
- fShader->shadeSpan(x, y, span, width);
+ fShaderContext->shadeSpan(x, y, span, width);
if (fXfermode) {
fXfermode->xfer32(device, span, width, NULL);
} else {
@@ -335,22 +337,22 @@ void SkARGB32_Shader_Blitter::blitRect(int x, int y, int width, int height) {
SkASSERT(x >= 0 && y >= 0 &&
x + width <= fDevice.width() && y + height <= fDevice.height());
- uint32_t* device = fDevice.getAddr32(x, y);
- size_t deviceRB = fDevice.rowBytes();
- SkShader* shader = fShader;
- SkPMColor* span = fBuffer;
+ uint32_t* device = fDevice.getAddr32(x, y);
+ size_t deviceRB = fDevice.rowBytes();
+ SkShader::Context* shaderContext = fShaderContext;
+ SkPMColor* span = fBuffer;
if (fConstInY) {
if (fShadeDirectlyIntoDevice) {
// shade the first row directly into the device
- fShader->shadeSpan(x, y, device, width);
+ shaderContext->shadeSpan(x, y, device, width);
span = device;
while (--height > 0) {
device = (uint32_t*)((char*)device + deviceRB);
memcpy(device, span, width << 2);
}
} else {
- fShader->shadeSpan(x, y, span, width);
+ shaderContext->shadeSpan(x, y, span, width);
SkXfermode* xfer = fXfermode;
if (xfer) {
do {
@@ -372,7 +374,7 @@ void SkARGB32_Shader_Blitter::blitRect(int x, int y, int width, int height) {
if (fShadeDirectlyIntoDevice) {
void* ctx;
- SkShader::ShadeProc shadeProc = fShader->asAShadeProc(&ctx);
+ SkShader::Context::ShadeProc shadeProc = shaderContext->asAShadeProc(&ctx);
if (shadeProc) {
do {
shadeProc(ctx, x, y, device, width);
@@ -381,7 +383,7 @@ void SkARGB32_Shader_Blitter::blitRect(int x, int y, int width, int height) {
} while (--height > 0);
} else {
do {
- shader->shadeSpan(x, y, device, width);
+ shaderContext->shadeSpan(x, y, device, width);
y += 1;
device = (uint32_t*)((char*)device + deviceRB);
} while (--height > 0);
@@ -390,7 +392,7 @@ void SkARGB32_Shader_Blitter::blitRect(int x, int y, int width, int height) {
SkXfermode* xfer = fXfermode;
if (xfer) {
do {
- shader->shadeSpan(x, y, span, width);
+ shaderContext->shadeSpan(x, y, span, width);
xfer->xfer32(device, span, width, NULL);
y += 1;
device = (uint32_t*)((char*)device + deviceRB);
@@ -398,7 +400,7 @@ void SkARGB32_Shader_Blitter::blitRect(int x, int y, int width, int height) {
} else {
SkBlitRow::Proc32 proc = fProc32;
do {
- shader->shadeSpan(x, y, span, width);
+ shaderContext->shadeSpan(x, y, span, width);
proc(device, span, width, 255);
y += 1;
device = (uint32_t*)((char*)device + deviceRB);
@@ -409,9 +411,9 @@ void SkARGB32_Shader_Blitter::blitRect(int x, int y, int width, int height) {
void SkARGB32_Shader_Blitter::blitAntiH(int x, int y, const SkAlpha antialias[],
const int16_t runs[]) {
- SkPMColor* span = fBuffer;
- uint32_t* device = fDevice.getAddr32(x, y);
- SkShader* shader = fShader;
+ SkPMColor* span = fBuffer;
+ uint32_t* device = fDevice.getAddr32(x, y);
+ SkShader::Context* shaderContext = fShaderContext;
if (fXfermode && !fShadeDirectlyIntoDevice) {
for (;;) {
@@ -422,7 +424,7 @@ void SkARGB32_Shader_Blitter::blitAntiH(int x, int y, const SkAlpha antialias[],
break;
int aa = *antialias;
if (aa) {
- shader->shadeSpan(x, y, span, count);
+ shaderContext->shadeSpan(x, y, span, count);
if (aa == 255) {
xfer->xfer32(device, span, count, NULL);
} else {
@@ -438,7 +440,7 @@ void SkARGB32_Shader_Blitter::blitAntiH(int x, int y, const SkAlpha antialias[],
x += count;
}
} else if (fShadeDirectlyIntoDevice ||
- (fShader->getFlags() & SkShader::kOpaqueAlpha_Flag)) {
+ (shaderContext->getFlags() & SkShader::kOpaqueAlpha_Flag)) {
for (;;) {
int count = *runs;
if (count <= 0) {
@@ -448,9 +450,9 @@ void SkARGB32_Shader_Blitter::blitAntiH(int x, int y, const SkAlpha antialias[],
if (aa) {
if (aa == 255) {
// cool, have the shader draw right into the device
- shader->shadeSpan(x, y, device, count);
+ shaderContext->shadeSpan(x, y, device, count);
} else {
- shader->shadeSpan(x, y, span, count);
+ shaderContext->shadeSpan(x, y, span, count);
fProc32Blend(device, span, count, aa);
}
}
@@ -467,7 +469,7 @@ void SkARGB32_Shader_Blitter::blitAntiH(int x, int y, const SkAlpha antialias[],
}
int aa = *antialias;
if (aa) {
- fShader->shadeSpan(x, y, span, count);
+ shaderContext->shadeSpan(x, y, span, count);
if (aa == 255) {
fProc32(device, span, count, 255);
} else {
@@ -491,10 +493,11 @@ void SkARGB32_Shader_Blitter::blitMask(const SkMask& mask, const SkIRect& clip)
SkASSERT(mask.fBounds.contains(clip));
+ SkShader::Context* shaderContext = fShaderContext;
SkBlitMask::RowProc proc = NULL;
if (!fXfermode) {
unsigned flags = 0;
- if (fShader->getFlags() & SkShader::kOpaqueAlpha_Flag) {
+ if (shaderContext->getFlags() & SkShader::kOpaqueAlpha_Flag) {
flags |= SkBlitMask::kSrcIsOpaque_RowFlag;
}
proc = SkBlitMask::RowFactory(SkBitmap::kARGB_8888_Config, mask.fFormat,
@@ -515,14 +518,13 @@ void SkARGB32_Shader_Blitter::blitMask(const SkMask& mask, const SkIRect& clip)
const uint8_t* maskRow = (const uint8_t*)mask.getAddr(x, y);
const size_t maskRB = mask.fRowBytes;
- SkShader* shader = fShader;
SkPMColor* span = fBuffer;
if (fXfermode) {
SkASSERT(SkMask::kA8_Format == mask.fFormat);
SkXfermode* xfer = fXfermode;
do {
- shader->shadeSpan(x, y, span, width);
+ shaderContext->shadeSpan(x, y, span, width);
xfer->xfer32((SkPMColor*)dstRow, span, width, maskRow);
dstRow += dstRB;
maskRow += maskRB;
@@ -530,7 +532,7 @@ void SkARGB32_Shader_Blitter::blitMask(const SkMask& mask, const SkIRect& clip)
} while (--height > 0);
} else {
do {
- shader->shadeSpan(x, y, span, width);
+ shaderContext->shadeSpan(x, y, span, width);
proc(dstRow, maskRow, span, width);
dstRow += dstRB;
maskRow += maskRB;
@@ -542,13 +544,13 @@ void SkARGB32_Shader_Blitter::blitMask(const SkMask& mask, const SkIRect& clip)
void SkARGB32_Shader_Blitter::blitV(int x, int y, int height, SkAlpha alpha) {
SkASSERT(x >= 0 && y >= 0 && y + height <= fDevice.height());
- uint32_t* device = fDevice.getAddr32(x, y);
- size_t deviceRB = fDevice.rowBytes();
- SkShader* shader = fShader;
+ uint32_t* device = fDevice.getAddr32(x, y);
+ size_t deviceRB = fDevice.rowBytes();
+ SkShader::Context* shaderContext = fShaderContext;
if (fConstInY) {
SkPMColor c;
- fShader->shadeSpan(x, y, &c, 1);
+ shaderContext->shadeSpan(x, y, &c, 1);
if (fShadeDirectlyIntoDevice) {
if (255 == alpha) {
@@ -582,7 +584,7 @@ void SkARGB32_Shader_Blitter::blitV(int x, int y, int height, SkAlpha alpha) {
if (fShadeDirectlyIntoDevice) {
void* ctx;
- SkShader::ShadeProc shadeProc = fShader->asAShadeProc(&ctx);
+ SkShader::Context::ShadeProc shadeProc = shaderContext->asAShadeProc(&ctx);
if (255 == alpha) {
if (shadeProc) {
do {
@@ -592,7 +594,7 @@ void SkARGB32_Shader_Blitter::blitV(int x, int y, int height, SkAlpha alpha) {
} while (--height > 0);
} else {
do {
- shader->shadeSpan(x, y, device, 1);
+ shaderContext->shadeSpan(x, y, device, 1);
y += 1;
device = (uint32_t*)((char*)device + deviceRB);
} while (--height > 0);
@@ -608,7 +610,7 @@ void SkARGB32_Shader_Blitter::blitV(int x, int y, int height, SkAlpha alpha) {
} while (--height > 0);
} else {
do {
- shader->shadeSpan(x, y, &c, 1);
+ shaderContext->shadeSpan(x, y, &c, 1);
*device = SkFourByteInterp(c, *device, alpha);
y += 1;
device = (uint32_t*)((char*)device + deviceRB);
@@ -620,7 +622,7 @@ void SkARGB32_Shader_Blitter::blitV(int x, int y, int height, SkAlpha alpha) {
SkXfermode* xfer = fXfermode;
if (xfer) {
do {
- shader->shadeSpan(x, y, span, 1);
+ shaderContext->shadeSpan(x, y, span, 1);
xfer->xfer32(device, span, 1, &alpha);
y += 1;
device = (uint32_t*)((char*)device + deviceRB);
@@ -628,7 +630,7 @@ void SkARGB32_Shader_Blitter::blitV(int x, int y, int height, SkAlpha alpha) {
} else {
SkBlitRow::Proc32 proc = (255 == alpha) ? fProc32 : fProc32Blend;
do {
- shader->shadeSpan(x, y, span, 1);
+ shaderContext->shadeSpan(x, y, span, 1);
proc(device, span, 1, alpha);
y += 1;
device = (uint32_t*)((char*)device + deviceRB);
diff --git a/src/core/SkBlitter_RGB16.cpp b/src/core/SkBlitter_RGB16.cpp
index 21b5a16e3c..e22aac4eda 100644
--- a/src/core/SkBlitter_RGB16.cpp
+++ b/src/core/SkBlitter_RGB16.cpp
@@ -107,7 +107,8 @@ private:
class SkRGB16_Shader_Blitter : public SkShaderBlitter {
public:
- SkRGB16_Shader_Blitter(const SkBitmap& device, const SkPaint& paint);
+ SkRGB16_Shader_Blitter(const SkBitmap& device, const SkPaint& paint,
+ SkShader::Context* shaderContext);
virtual ~SkRGB16_Shader_Blitter();
virtual void blitH(int x, int y, int width);
virtual void blitAntiH(int x, int y, const SkAlpha* antialias,
@@ -129,7 +130,8 @@ private:
// used only if the shader can perform shadSpan16
class SkRGB16_Shader16_Blitter : public SkRGB16_Shader_Blitter {
public:
- SkRGB16_Shader16_Blitter(const SkBitmap& device, const SkPaint& paint);
+ SkRGB16_Shader16_Blitter(const SkBitmap& device, const SkPaint& paint,
+ SkShader::Context* shaderContext);
virtual void blitH(int x, int y, int width);
virtual void blitAntiH(int x, int y, const SkAlpha* antialias,
const int16_t* runs);
@@ -141,7 +143,8 @@ private:
class SkRGB16_Shader_Xfermode_Blitter : public SkShaderBlitter {
public:
- SkRGB16_Shader_Xfermode_Blitter(const SkBitmap& device, const SkPaint& paint);
+ SkRGB16_Shader_Xfermode_Blitter(const SkBitmap& device, const SkPaint& paint,
+ SkShader::Context* shaderContext);
virtual ~SkRGB16_Shader_Xfermode_Blitter();
virtual void blitH(int x, int y, int width);
virtual void blitAntiH(int x, int y, const SkAlpha* antialias,
@@ -679,8 +682,9 @@ void SkRGB16_Blitter::blitRect(int x, int y, int width, int height) {
///////////////////////////////////////////////////////////////////////////////
SkRGB16_Shader16_Blitter::SkRGB16_Shader16_Blitter(const SkBitmap& device,
- const SkPaint& paint)
- : SkRGB16_Shader_Blitter(device, paint) {
+ const SkPaint& paint,
+ SkShader::Context* shaderContext)
+ : SkRGB16_Shader_Blitter(device, paint, shaderContext) {
SkASSERT(SkShader::CanCallShadeSpan16(fShaderFlags));
}
@@ -688,28 +692,28 @@ void SkRGB16_Shader16_Blitter::blitH(int x, int y, int width) {
SkASSERT(x + width <= fDevice.width());
uint16_t* SK_RESTRICT device = fDevice.getAddr16(x, y);
- SkShader* shader = fShader;
+ SkShader::Context* shaderContext = fShaderContext;
- int alpha = shader->getSpan16Alpha();
+ int alpha = shaderContext->getSpan16Alpha();
if (0xFF == alpha) {
- shader->shadeSpan16(x, y, device, width);
+ shaderContext->shadeSpan16(x, y, device, width);
} else {
uint16_t* span16 = (uint16_t*)fBuffer;
- shader->shadeSpan16(x, y, span16, width);
+ shaderContext->shadeSpan16(x, y, span16, width);
SkBlendRGB16(span16, device, SkAlpha255To256(alpha), width);
}
}
void SkRGB16_Shader16_Blitter::blitRect(int x, int y, int width, int height) {
- SkShader* shader = fShader;
- uint16_t* dst = fDevice.getAddr16(x, y);
- size_t dstRB = fDevice.rowBytes();
- int alpha = shader->getSpan16Alpha();
+ SkShader::Context* shaderContext = fShaderContext;
+ uint16_t* dst = fDevice.getAddr16(x, y);
+ size_t dstRB = fDevice.rowBytes();
+ int alpha = shaderContext->getSpan16Alpha();
if (0xFF == alpha) {
if (fShaderFlags & SkShader::kConstInY16_Flag) {
// have the shader blit directly into the device the first time
- shader->shadeSpan16(x, y, dst, width);
+ shaderContext->shadeSpan16(x, y, dst, width);
// and now just memcpy that line on the subsequent lines
if (--height > 0) {
const uint16_t* orig = dst;
@@ -720,7 +724,7 @@ void SkRGB16_Shader16_Blitter::blitRect(int x, int y, int width, int height) {
}
} else { // need to call shadeSpan16 for every line
do {
- shader->shadeSpan16(x, y, dst, width);
+ shaderContext->shadeSpan16(x, y, dst, width);
y += 1;
dst = (uint16_t*)((char*)dst + dstRB);
} while (--height);
@@ -729,14 +733,14 @@ void SkRGB16_Shader16_Blitter::blitRect(int x, int y, int width, int height) {
int scale = SkAlpha255To256(alpha);
uint16_t* span16 = (uint16_t*)fBuffer;
if (fShaderFlags & SkShader::kConstInY16_Flag) {
- shader->shadeSpan16(x, y, span16, width);
+ shaderContext->shadeSpan16(x, y, span16, width);
do {
SkBlendRGB16(span16, dst, scale, width);
dst = (uint16_t*)((char*)dst + dstRB);
} while (--height);
} else {
do {
- shader->shadeSpan16(x, y, span16, width);
+ shaderContext->shadeSpan16(x, y, span16, width);
SkBlendRGB16(span16, dst, scale, width);
y += 1;
dst = (uint16_t*)((char*)dst + dstRB);
@@ -748,11 +752,11 @@ void SkRGB16_Shader16_Blitter::blitRect(int x, int y, int width, int height) {
void SkRGB16_Shader16_Blitter::blitAntiH(int x, int y,
const SkAlpha* SK_RESTRICT antialias,
const int16_t* SK_RESTRICT runs) {
- SkShader* shader = fShader;
+ SkShader::Context* shaderContext = fShaderContext;
SkPMColor* SK_RESTRICT span = fBuffer;
- uint16_t* SK_RESTRICT device = fDevice.getAddr16(x, y);
+ uint16_t* SK_RESTRICT device = fDevice.getAddr16(x, y);
- int alpha = shader->getSpan16Alpha();
+ int alpha = shaderContext->getSpan16Alpha();
uint16_t* span16 = (uint16_t*)span;
if (0xFF == alpha) {
@@ -766,9 +770,9 @@ void SkRGB16_Shader16_Blitter::blitAntiH(int x, int y,
int aa = *antialias;
if (aa == 255) {
// go direct to the device!
- shader->shadeSpan16(x, y, device, count);
+ shaderContext->shadeSpan16(x, y, device, count);
} else if (aa) {
- shader->shadeSpan16(x, y, span16, count);
+ shaderContext->shadeSpan16(x, y, span16, count);
SkBlendRGB16(span16, device, SkAlpha255To256(aa), count);
}
device += count;
@@ -787,7 +791,7 @@ void SkRGB16_Shader16_Blitter::blitAntiH(int x, int y,
int aa = SkAlphaMul(*antialias, alpha);
if (aa) {
- shader->shadeSpan16(x, y, span16, count);
+ shaderContext->shadeSpan16(x, y, span16, count);
SkBlendRGB16(span16, device, SkAlpha255To256(aa), count);
}
@@ -802,8 +806,9 @@ void SkRGB16_Shader16_Blitter::blitAntiH(int x, int y,
///////////////////////////////////////////////////////////////////////////////
SkRGB16_Shader_Blitter::SkRGB16_Shader_Blitter(const SkBitmap& device,
- const SkPaint& paint)
-: INHERITED(device, paint) {
+ const SkPaint& paint,
+ SkShader::Context* shaderContext)
+: INHERITED(device, paint, shaderContext) {
SkASSERT(paint.getXfermode() == NULL);
fBuffer = (SkPMColor*)sk_malloc_throw(device.width() * sizeof(SkPMColor));
@@ -834,20 +839,20 @@ SkRGB16_Shader_Blitter::~SkRGB16_Shader_Blitter() {
void SkRGB16_Shader_Blitter::blitH(int x, int y, int width) {
SkASSERT(x + width <= fDevice.width());
- fShader->shadeSpan(x, y, fBuffer, width);
+ fShaderContext->shadeSpan(x, y, fBuffer, width);
// shaders take care of global alpha, so we pass 0xFF (should be ignored)
fOpaqueProc(fDevice.getAddr16(x, y), fBuffer, width, 0xFF, x, y);
}
void SkRGB16_Shader_Blitter::blitRect(int x, int y, int width, int height) {
- SkShader* shader = fShader;
- SkBlitRow::Proc proc = fOpaqueProc;
- SkPMColor* buffer = fBuffer;
- uint16_t* dst = fDevice.getAddr16(x, y);
- size_t dstRB = fDevice.rowBytes();
+ SkShader::Context* shaderContext = fShaderContext;
+ SkBlitRow::Proc proc = fOpaqueProc;
+ SkPMColor* buffer = fBuffer;
+ uint16_t* dst = fDevice.getAddr16(x, y);
+ size_t dstRB = fDevice.rowBytes();
if (fShaderFlags & SkShader::kConstInY32_Flag) {
- shader->shadeSpan(x, y, buffer, width);
+ shaderContext->shadeSpan(x, y, buffer, width);
do {
proc(dst, buffer, width, 0xFF, x, y);
y += 1;
@@ -855,7 +860,7 @@ void SkRGB16_Shader_Blitter::blitRect(int x, int y, int width, int height) {
} while (--height);
} else {
do {
- shader->shadeSpan(x, y, buffer, width);
+ shaderContext->shadeSpan(x, y, buffer, width);
proc(dst, buffer, width, 0xFF, x, y);
y += 1;
dst = (uint16_t*)((char*)dst + dstRB);
@@ -880,9 +885,9 @@ static inline int count_nonzero_span(const int16_t runs[], const SkAlpha aa[]) {
void SkRGB16_Shader_Blitter::blitAntiH(int x, int y,
const SkAlpha* SK_RESTRICT antialias,
const int16_t* SK_RESTRICT runs) {
- SkShader* shader = fShader;
+ SkShader::Context* shaderContext = fShaderContext;
SkPMColor* SK_RESTRICT span = fBuffer;
- uint16_t* SK_RESTRICT device = fDevice.getAddr16(x, y);
+ uint16_t* SK_RESTRICT device = fDevice.getAddr16(x, y);
for (;;) {
int count = *runs;
@@ -901,7 +906,7 @@ void SkRGB16_Shader_Blitter::blitAntiH(int x, int y,
int nonZeroCount = count + count_nonzero_span(runs + count, antialias + count);
SkASSERT(nonZeroCount <= fDevice.width()); // don't overrun fBuffer
- shader->shadeSpan(x, y, span, nonZeroCount);
+ shaderContext->shadeSpan(x, y, span, nonZeroCount);
SkPMColor* localSpan = span;
for (;;) {
@@ -928,8 +933,9 @@ void SkRGB16_Shader_Blitter::blitAntiH(int x, int y,
///////////////////////////////////////////////////////////////////////
SkRGB16_Shader_Xfermode_Blitter::SkRGB16_Shader_Xfermode_Blitter(
- const SkBitmap& device, const SkPaint& paint)
-: INHERITED(device, paint) {
+ const SkBitmap& device, const SkPaint& paint,
+ SkShader::Context* shaderContext)
+: INHERITED(device, paint, shaderContext) {
fXfermode = paint.getXfermode();
SkASSERT(fXfermode);
fXfermode->ref();
@@ -950,18 +956,18 @@ void SkRGB16_Shader_Xfermode_Blitter::blitH(int x, int y, int width) {
uint16_t* device = fDevice.getAddr16(x, y);
SkPMColor* span = fBuffer;
- fShader->shadeSpan(x, y, span, width);
+ fShaderContext->shadeSpan(x, y, span, width);
fXfermode->xfer16(device, span, width, NULL);
}
void SkRGB16_Shader_Xfermode_Blitter::blitAntiH(int x, int y,
const SkAlpha* SK_RESTRICT antialias,
const int16_t* SK_RESTRICT runs) {
- SkShader* shader = fShader;
- SkXfermode* mode = fXfermode;
+ SkShader::Context* shaderContext = fShaderContext;
+ SkXfermode* mode = fXfermode;
SkPMColor* SK_RESTRICT span = fBuffer;
- uint8_t* SK_RESTRICT aaExpand = fAAExpand;
- uint16_t* SK_RESTRICT device = fDevice.getAddr16(x, y);
+ uint8_t* SK_RESTRICT aaExpand = fAAExpand;
+ uint16_t* SK_RESTRICT device = fDevice.getAddr16(x, y);
for (;;) {
int count = *runs;
@@ -981,7 +987,7 @@ void SkRGB16_Shader_Xfermode_Blitter::blitAntiH(int x, int y,
antialias + count);
SkASSERT(nonZeroCount <= fDevice.width()); // don't overrun fBuffer
- shader->shadeSpan(x, y, span, nonZeroCount);
+ shaderContext->shadeSpan(x, y, span, nonZeroCount);
x += nonZeroCount;
SkPMColor* localSpan = span;
@@ -1012,6 +1018,7 @@ void SkRGB16_Shader_Xfermode_Blitter::blitAntiH(int x, int y,
///////////////////////////////////////////////////////////////////////////////
SkBlitter* SkBlitter_ChooseD565(const SkBitmap& device, const SkPaint& paint,
+ SkShader::Context* shaderContext,
SkTBlitterAllocator* allocator) {
SkASSERT(allocator != NULL);
@@ -1023,12 +1030,14 @@ SkBlitter* SkBlitter_ChooseD565(const SkBitmap& device, const SkPaint& paint,
SkASSERT(NULL == mode || NULL != shader);
if (shader) {
+ SkASSERT(shaderContext != NULL);
if (mode) {
- blitter = allocator->createT<SkRGB16_Shader_Xfermode_Blitter>(device, paint);
- } else if (shader->canCallShadeSpan16()) {
- blitter = allocator->createT<SkRGB16_Shader16_Blitter>(device, paint);
+ blitter = allocator->createT<SkRGB16_Shader_Xfermode_Blitter>(device, paint,
+ shaderContext);
+ } else if (shaderContext->canCallShadeSpan16()) {
+ blitter = allocator->createT<SkRGB16_Shader16_Blitter>(device, paint, shaderContext);
} else {
- blitter = allocator->createT<SkRGB16_Shader_Blitter>(device, paint);
+ blitter = allocator->createT<SkRGB16_Shader_Blitter>(device, paint, shaderContext);
}
} else {
// no shader, no xfermode, (and we always ignore colorfilter)
diff --git a/src/core/SkCanvas.cpp b/src/core/SkCanvas.cpp
index 569e9e59ba..c1d2726d8c 100644
--- a/src/core/SkCanvas.cpp
+++ b/src/core/SkCanvas.cpp
@@ -91,32 +91,10 @@ private:
};
#endif
-class AutoCheckNoSetContext {
-public:
- AutoCheckNoSetContext(const SkPaint& paint) : fPaint(paint) {
- this->assertNoSetContext(fPaint);
- }
- ~AutoCheckNoSetContext() {
- this->assertNoSetContext(fPaint);
- }
-
-private:
- const SkPaint& fPaint;
-
- void assertNoSetContext(const SkPaint& paint) {
- SkShader* s = paint.getShader();
- if (s) {
- SkASSERT(!s->setContextHasBeenCalled());
- }
- }
-};
-
#define CHECK_LOCKCOUNT_BALANCE(bitmap) AutoCheckLockCountBalance clcb(bitmap)
-#define CHECK_SHADER_NOSETCONTEXT(paint) AutoCheckNoSetContext cshsc(paint)
#else
#define CHECK_LOCKCOUNT_BALANCE(bitmap)
- #define CHECK_SHADER_NOSETCONTEXT(paint)
#endif
typedef SkTLazy<SkPaint> SkLazyPaint;
@@ -1935,8 +1913,6 @@ void SkCanvas::drawPaint(const SkPaint& paint) {
}
void SkCanvas::internalDrawPaint(const SkPaint& paint) {
- CHECK_SHADER_NOSETCONTEXT(paint);
-
LOOPER_BEGIN(paint, SkDrawFilter::kPaint_Type, NULL)
while (iter.next()) {
@@ -1952,8 +1928,6 @@ void SkCanvas::drawPoints(PointMode mode, size_t count, const SkPoint pts[],
return;
}
- CHECK_SHADER_NOSETCONTEXT(paint);
-
SkRect r, storage;
const SkRect* bounds = NULL;
if (paint.canComputeFastBounds()) {
@@ -1981,8 +1955,6 @@ void SkCanvas::drawPoints(PointMode mode, size_t count, const SkPoint pts[],
}
void SkCanvas::drawRect(const SkRect& r, const SkPaint& paint) {
- CHECK_SHADER_NOSETCONTEXT(paint);
-
SkRect storage;
const SkRect* bounds = NULL;
if (paint.canComputeFastBounds()) {
@@ -2002,8 +1974,6 @@ void SkCanvas::drawRect(const SkRect& r, const SkPaint& paint) {
}
void SkCanvas::drawOval(const SkRect& oval, const SkPaint& paint) {
- CHECK_SHADER_NOSETCONTEXT(paint);
-
SkRect storage;
const SkRect* bounds = NULL;
if (paint.canComputeFastBounds()) {
@@ -2023,8 +1993,6 @@ void SkCanvas::drawOval(const SkRect& oval, const SkPaint& paint) {
}
void SkCanvas::drawRRect(const SkRRect& rrect, const SkPaint& paint) {
- CHECK_SHADER_NOSETCONTEXT(paint);
-
SkRect storage;
const SkRect* bounds = NULL;
if (paint.canComputeFastBounds()) {
@@ -2055,8 +2023,6 @@ void SkCanvas::drawRRect(const SkRRect& rrect, const SkPaint& paint) {
void SkCanvas::onDrawDRRect(const SkRRect& outer, const SkRRect& inner,
const SkPaint& paint) {
- CHECK_SHADER_NOSETCONTEXT(paint);
-
SkRect storage;
const SkRect* bounds = NULL;
if (paint.canComputeFastBounds()) {
@@ -2076,8 +2042,6 @@ void SkCanvas::onDrawDRRect(const SkRRect& outer, const SkRRect& inner,
}
void SkCanvas::drawPath(const SkPath& path, const SkPaint& paint) {
- CHECK_SHADER_NOSETCONTEXT(paint);
-
if (!path.isFinite()) {
return;
}
@@ -2353,8 +2317,6 @@ void SkCanvas::DrawTextDecorations(const SkDraw& draw, const SkPaint& paint,
void SkCanvas::drawText(const void* text, size_t byteLength,
SkScalar x, SkScalar y, const SkPaint& paint) {
- CHECK_SHADER_NOSETCONTEXT(paint);
-
LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, NULL)
while (iter.next()) {
@@ -2369,8 +2331,6 @@ void SkCanvas::drawText(const void* text, size_t byteLength,
void SkCanvas::drawPosText(const void* text, size_t byteLength,
const SkPoint pos[], const SkPaint& paint) {
- CHECK_SHADER_NOSETCONTEXT(paint);
-
LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, NULL)
while (iter.next()) {
@@ -2385,8 +2345,6 @@ void SkCanvas::drawPosText(const void* text, size_t byteLength,
void SkCanvas::drawPosTextH(const void* text, size_t byteLength,
const SkScalar xpos[], SkScalar constY,
const SkPaint& paint) {
- CHECK_SHADER_NOSETCONTEXT(paint);
-
LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, NULL)
while (iter.next()) {
@@ -2401,8 +2359,6 @@ void SkCanvas::drawPosTextH(const void* text, size_t byteLength,
void SkCanvas::drawTextOnPath(const void* text, size_t byteLength,
const SkPath& path, const SkMatrix* matrix,
const SkPaint& paint) {
- CHECK_SHADER_NOSETCONTEXT(paint);
-
LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, NULL)
while (iter.next()) {
@@ -2418,8 +2374,6 @@ void SkCanvas::drawVertices(VertexMode vmode, int vertexCount,
const SkColor colors[], SkXfermode* xmode,
const uint16_t indices[], int indexCount,
const SkPaint& paint) {
- CHECK_SHADER_NOSETCONTEXT(paint);
-
LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, NULL)
while (iter.next()) {
diff --git a/src/core/SkComposeShader.cpp b/src/core/SkComposeShader.cpp
index f53eedf876..68c4646cf6 100644
--- a/src/core/SkComposeShader.cpp
+++ b/src/core/SkComposeShader.cpp
@@ -45,6 +45,10 @@ SkComposeShader::~SkComposeShader() {
fShaderA->unref();
}
+size_t SkComposeShader::contextSize() const {
+ return sizeof(ComposeShaderContext) + fShaderA->contextSize() + fShaderB->contextSize();
+}
+
class SkAutoAlphaRestore {
public:
SkAutoAlphaRestore(SkPaint* paint, uint8_t newAlpha) {
@@ -69,17 +73,16 @@ void SkComposeShader::flatten(SkWriteBuffer& buffer) const {
buffer.writeFlattenable(fMode);
}
-/* We call setContext on our two worker shaders. However, we
- always let them see opaque alpha, and if the paint really
- is translucent, then we apply that after the fact.
+/* We call validContext/createContext on our two worker shaders.
+ However, we always let them see opaque alpha, and if the paint
+ really is translucent, then we apply that after the fact.
- We need to keep the calls to setContext/endContext balanced, since if we
- return false, our endContext() will not be called.
*/
-bool SkComposeShader::setContext(const SkBitmap& device,
- const SkPaint& paint,
- const SkMatrix& matrix) {
- if (!this->INHERITED::setContext(device, paint, matrix)) {
+bool SkComposeShader::validContext(const SkBitmap& device,
+ const SkPaint& paint,
+ const SkMatrix& matrix,
+ SkMatrix* totalInverse) const {
+ if (!this->INHERITED::validContext(device, paint, matrix, totalInverse)) {
return false;
}
@@ -90,38 +93,62 @@ bool SkComposeShader::setContext(const SkBitmap& device,
tmpM.setConcat(matrix, this->getLocalMatrix());
- SkAutoAlphaRestore restore(const_cast<SkPaint*>(&paint), 0xFF);
+ return fShaderA->validContext(device, paint, tmpM) &&
+ fShaderB->validContext(device, paint, tmpM);
+}
- bool setContextA = fShaderA->setContext(device, paint, tmpM);
- bool setContextB = fShaderB->setContext(device, paint, tmpM);
- if (!setContextA || !setContextB) {
- if (setContextB) {
- fShaderB->endContext();
- }
- else if (setContextA) {
- fShaderA->endContext();
- }
- this->INHERITED::endContext();
- return false;
+SkShader::Context* SkComposeShader::createContext(const SkBitmap& device, const SkPaint& paint,
+ const SkMatrix& matrix, void* storage) const {
+ if (!this->validContext(device, paint, matrix)) {
+ return NULL;
}
- return true;
+
+ // we preconcat our localMatrix (if any) with the device matrix
+ // before calling our sub-shaders
+
+ SkMatrix tmpM;
+
+ tmpM.setConcat(matrix, this->getLocalMatrix());
+
+ SkAutoAlphaRestore restore(const_cast<SkPaint*>(&paint), 0xFF);
+
+ char* aStorage = (char*) storage + sizeof(ComposeShaderContext);
+ char* bStorage = aStorage + fShaderA->contextSize();
+
+ SkShader::Context* contextA = fShaderA->createContext(device, paint, tmpM, aStorage);
+ SkShader::Context* contextB = fShaderB->createContext(device, paint, tmpM, bStorage);
+
+ // Both functions must succeed; otherwise validContext should have returned
+ // false.
+ SkASSERT(contextA);
+ SkASSERT(contextB);
+
+ return SkNEW_PLACEMENT_ARGS(storage, ComposeShaderContext,
+ (*this, device, paint, matrix, contextA, contextB));
}
-void SkComposeShader::endContext() {
- fShaderB->endContext();
- fShaderA->endContext();
- this->INHERITED::endContext();
+SkComposeShader::ComposeShaderContext::ComposeShaderContext(
+ const SkComposeShader& shader, const SkBitmap& device,
+ const SkPaint& paint, const SkMatrix& matrix,
+ SkShader::Context* contextA, SkShader::Context* contextB)
+ : INHERITED(shader, device, paint, matrix)
+ , fShaderContextA(contextA)
+ , fShaderContextB(contextB) {}
+
+SkComposeShader::ComposeShaderContext::~ComposeShaderContext() {
+ fShaderContextA->SkShader::Context::~Context();
+ fShaderContextB->SkShader::Context::~Context();
}
// larger is better (fewer times we have to loop), but we shouldn't
// take up too much stack-space (each element is 4 bytes)
#define TMP_COLOR_COUNT 64
-void SkComposeShader::shadeSpan(int x, int y, SkPMColor result[], int count) {
- SkShader* shaderA = fShaderA;
- SkShader* shaderB = fShaderB;
- SkXfermode* mode = fMode;
- unsigned scale = SkAlpha255To256(this->getPaintAlpha());
+void SkComposeShader::ComposeShaderContext::shadeSpan(int x, int y, SkPMColor result[], int count) {
+ SkShader::Context* shaderContextA = fShaderContextA;
+ SkShader::Context* shaderContextB = fShaderContextB;
+ SkXfermode* mode = static_cast<const SkComposeShader&>(fShader).fMode;
+ unsigned scale = SkAlpha255To256(this->getPaintAlpha());
SkPMColor tmp[TMP_COLOR_COUNT];
@@ -134,8 +161,8 @@ void SkComposeShader::shadeSpan(int x, int y, SkPMColor result[], int count) {
n = TMP_COLOR_COUNT;
}
- shaderA->shadeSpan(x, y, result, n);
- shaderB->shadeSpan(x, y, tmp, n);
+ shaderContextA->shadeSpan(x, y, result, n);
+ shaderContextB->shadeSpan(x, y, tmp, n);
if (256 == scale) {
for (int i = 0; i < n; i++) {
@@ -159,8 +186,8 @@ void SkComposeShader::shadeSpan(int x, int y, SkPMColor result[], int count) {
n = TMP_COLOR_COUNT;
}
- shaderA->shadeSpan(x, y, result, n);
- shaderB->shadeSpan(x, y, tmp, n);
+ shaderContextA->shadeSpan(x, y, result, n);
+ shaderContextB->shadeSpan(x, y, tmp, n);
mode->xfer32(result, tmp, n, NULL);
if (256 == scale) {
diff --git a/src/core/SkCoreBlitters.h b/src/core/SkCoreBlitters.h
index 285184050b..2d22d38e78 100644
--- a/src/core/SkCoreBlitters.h
+++ b/src/core/SkCoreBlitters.h
@@ -27,12 +27,29 @@ private:
class SkShaderBlitter : public SkRasterBlitter {
public:
- SkShaderBlitter(const SkBitmap& device, const SkPaint& paint);
+ /**
+ * The storage for shaderContext is owned by the caller, but the object itself is not.
+ * The blitter only ensures that the storage always holds a live object, but it may
+ * exchange that object.
+ */
+ SkShaderBlitter(const SkBitmap& device, const SkPaint& paint,
+ SkShader::Context* shaderContext);
virtual ~SkShaderBlitter();
+ /**
+ * Create a new shader context and uses it instead of the old one if successful.
+ * Will create the context at the same location as the old one (this is safe
+ * because the shader itself is unchanged).
+ */
+ virtual bool resetShaderContext(const SkBitmap& device, const SkPaint& paint,
+ const SkMatrix& matrix) SK_OVERRIDE;
+
+ virtual SkShader::Context* getShaderContext() const SK_OVERRIDE { return fShaderContext; }
+
protected:
- uint32_t fShaderFlags;
- SkShader* fShader;
+ uint32_t fShaderFlags;
+ const SkShader* fShader;
+ SkShader::Context* fShaderContext;
private:
// illegal
@@ -75,7 +92,8 @@ private:
class SkA8_Shader_Blitter : public SkShaderBlitter {
public:
- SkA8_Shader_Blitter(const SkBitmap& device, const SkPaint& paint);
+ SkA8_Shader_Blitter(const SkBitmap& device, const SkPaint& paint,
+ SkShader::Context* shaderContext);
virtual ~SkA8_Shader_Blitter();
virtual void blitH(int x, int y, int width);
virtual void blitAntiH(int x, int y, const SkAlpha antialias[], const int16_t runs[]);
@@ -141,7 +159,8 @@ private:
class SkARGB32_Shader_Blitter : public SkShaderBlitter {
public:
- SkARGB32_Shader_Blitter(const SkBitmap& device, const SkPaint& paint);
+ SkARGB32_Shader_Blitter(const SkBitmap& device, const SkPaint& paint,
+ SkShader::Context* shaderContext);
virtual ~SkARGB32_Shader_Blitter();
virtual void blitH(int x, int y, int width) SK_OVERRIDE;
virtual void blitV(int x, int y, int height, SkAlpha alpha) SK_OVERRIDE;
@@ -179,6 +198,7 @@ private:
*/
SkBlitter* SkBlitter_ChooseD565(const SkBitmap& device, const SkPaint& paint,
+ SkShader::Context* shaderContext,
SkTBlitterAllocator* allocator);
#endif
diff --git a/src/core/SkDraw.cpp b/src/core/SkDraw.cpp
index 7eb0be6b6b..6ddd0d274f 100644
--- a/src/core/SkDraw.cpp
+++ b/src/core/SkDraw.cpp
@@ -2354,9 +2354,26 @@ class SkTriColorShader : public SkShader {
public:
SkTriColorShader() {}
- bool setup(const SkPoint pts[], const SkColor colors[], int, int, int);
+ virtual SkShader::Context* createContext(
+ const SkBitmap&, const SkPaint&, const SkMatrix&, void*) const SK_OVERRIDE;
+ virtual size_t contextSize() const SK_OVERRIDE;
- virtual void shadeSpan(int x, int y, SkPMColor dstC[], int count) SK_OVERRIDE;
+ class TriColorShaderContext : public SkShader::Context {
+ public:
+ TriColorShaderContext(const SkTriColorShader& shader, const SkBitmap& device,
+ const SkPaint& paint, const SkMatrix& matrix);
+ virtual ~TriColorShaderContext();
+
+ bool setup(const SkPoint pts[], const SkColor colors[], int, int, int);
+
+ virtual void shadeSpan(int x, int y, SkPMColor dstC[], int count) SK_OVERRIDE;
+
+ private:
+ SkMatrix fDstToUnit;
+ SkPMColor fColors[3];
+
+ typedef SkShader::Context INHERITED;
+ };
SK_TO_STRING_OVERRIDE()
SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkTriColorShader)
@@ -2365,14 +2382,20 @@ protected:
SkTriColorShader(SkReadBuffer& buffer) : SkShader(buffer) {}
private:
- SkMatrix fDstToUnit;
- SkPMColor fColors[3];
-
typedef SkShader INHERITED;
};
-bool SkTriColorShader::setup(const SkPoint pts[], const SkColor colors[],
- int index0, int index1, int index2) {
+SkShader::Context* SkTriColorShader::createContext(const SkBitmap& device, const SkPaint& paint,
+ const SkMatrix& matrix, void* storage) const {
+ if (!this->validContext(device, paint, matrix)) {
+ return NULL;
+ }
+
+ return SkNEW_PLACEMENT_ARGS(storage, TriColorShaderContext, (*this, device, paint, matrix));
+}
+
+bool SkTriColorShader::TriColorShaderContext::setup(const SkPoint pts[], const SkColor colors[],
+ int index0, int index1, int index2) {
fColors[0] = SkPreMultiplyColor(colors[index0]);
fColors[1] = SkPreMultiplyColor(colors[index1]);
@@ -2407,7 +2430,18 @@ static int ScalarTo256(SkScalar v) {
return SkAlpha255To256(scale);
}
-void SkTriColorShader::shadeSpan(int x, int y, SkPMColor dstC[], int count) {
+
+SkTriColorShader::TriColorShaderContext::TriColorShaderContext(
+ const SkTriColorShader& shader, const SkBitmap& device,
+ const SkPaint& paint, const SkMatrix& matrix)
+ : INHERITED(shader, device, paint, matrix) {}
+
+SkTriColorShader::TriColorShaderContext::~TriColorShaderContext() {}
+
+size_t SkTriColorShader::contextSize() const {
+ return sizeof(TriColorShaderContext);
+}
+void SkTriColorShader::TriColorShaderContext::shadeSpan(int x, int y, SkPMColor dstC[], int count) {
SkPoint src;
for (int i = 0; i < count; i++) {
@@ -2492,6 +2526,7 @@ void SkDraw::drawVertices(SkCanvas::VertexMode vmode, int count,
}
// setup the custom shader (if needed)
+ SkAutoTUnref<SkComposeShader> composeShader;
if (NULL != colors) {
if (NULL == textures) {
// just colors (no texture)
@@ -2504,9 +2539,8 @@ void SkDraw::drawVertices(SkCanvas::VertexMode vmode, int count,
xmode = SkXfermode::Create(SkXfermode::kModulate_Mode);
releaseMode = true;
}
- SkShader* compose = SkNEW_ARGS(SkComposeShader,
- (&triShader, shader, xmode));
- p.setShader(compose)->unref();
+ composeShader.reset(SkNEW_ARGS(SkComposeShader, (&triShader, shader, xmode)));
+ p.setShader(composeShader);
if (releaseMode) {
xmode->unref();
}
@@ -2514,9 +2548,7 @@ void SkDraw::drawVertices(SkCanvas::VertexMode vmode, int count,
}
SkAutoBlitterChoose blitter(*fBitmap, *fMatrix, p);
- // important that we abort early, as below we may manipulate the shader
- // and that is only valid if the shader returned true from setContext.
- // If it returned false, then our blitter will be the NullBlitter.
+ // Abort early if we failed to create a shader context.
if (blitter->isNullBlitter()) {
return;
}
@@ -2532,30 +2564,38 @@ void SkDraw::drawVertices(SkCanvas::VertexMode vmode, int count,
savedLocalM = shader->getLocalMatrix();
}
- // setContext has already been called and verified to return true
- // by the constructor of SkAutoBlitterChoose
- bool prevContextSuccess = true;
while (vertProc(&state)) {
if (NULL != textures) {
if (texture_to_matrix(state, vertices, textures, &tempM)) {
tempM.postConcat(savedLocalM);
shader->setLocalMatrix(tempM);
- // Need to recall setContext since we changed the local matrix.
- // However, we also need to balance the calls this with a
- // call to endContext which requires tracking the result of
- // the previous call to setContext.
- if (prevContextSuccess) {
- shader->endContext();
- }
- prevContextSuccess = shader->setContext(*fBitmap, p, *fMatrix);
- if (!prevContextSuccess) {
+ if (!blitter->resetShaderContext(*fBitmap, p, *fMatrix)) {
continue;
}
}
}
if (NULL != colors) {
- if (!triShader.setup(vertices, colors,
- state.f0, state.f1, state.f2)) {
+ // Find the context for triShader.
+ SkTriColorShader::TriColorShaderContext* triColorShaderContext;
+
+ SkShader::Context* shaderContext = blitter->getShaderContext();
+ SkASSERT(shaderContext);
+ if (p.getShader() == &triShader) {
+ triColorShaderContext =
+ static_cast<SkTriColorShader::TriColorShaderContext*>(shaderContext);
+ } else {
+ // The shader is a compose shader and triShader is its first shader.
+ SkASSERT(p.getShader() == composeShader);
+ SkASSERT(composeShader->getShaderA() == &triShader);
+ SkComposeShader::ComposeShaderContext* composeShaderContext =
+ static_cast<SkComposeShader::ComposeShaderContext*>(shaderContext);
+ SkShader::Context* shaderContextA = composeShaderContext->getShaderContextA();
+ triColorShaderContext =
+ static_cast<SkTriColorShader::TriColorShaderContext*>(shaderContextA);
+ }
+
+ if (!triColorShaderContext->setup(vertices, colors,
+ state.f0, state.f1, state.f2)) {
continue;
}
}
@@ -2570,13 +2610,6 @@ void SkDraw::drawVertices(SkCanvas::VertexMode vmode, int count,
if (NULL != shader) {
shader->setLocalMatrix(savedLocalM);
}
-
- // If the final call to setContext fails we must make it suceed so that the
- // call to endContext in the destructor for SkAutoBlitterChoose is balanced.
- if (!prevContextSuccess) {
- prevContextSuccess = shader->setContext(*fBitmap, paint, SkMatrix::I());
- SkASSERT(prevContextSuccess);
- }
} else {
// no colors[] and no texture
HairProc hairProc = ChooseHairProc(paint.isAntiAlias());
diff --git a/src/core/SkFilterShader.cpp b/src/core/SkFilterShader.cpp
index 58961913c8..1a0255157d 100644
--- a/src/core/SkFilterShader.cpp
+++ b/src/core/SkFilterShader.cpp
@@ -38,9 +38,11 @@ void SkFilterShader::flatten(SkWriteBuffer& buffer) const {
buffer.writeFlattenable(fFilter);
}
-uint32_t SkFilterShader::getFlags() {
- uint32_t shaderF = fShader->getFlags();
- uint32_t filterF = fFilter->getFlags();
+uint32_t SkFilterShader::FilterShaderContext::getFlags() const {
+ const SkFilterShader& filterShader = static_cast<const SkFilterShader&>(fShader);
+
+ uint32_t shaderF = fShaderContext->getFlags();
+ uint32_t filterF = filterShader.fFilter->getFlags();
// if the filter doesn't support 16bit, clear the matching bit in the shader
if (!(filterF & SkColorFilter::kHasFilter16_Flag)) {
@@ -53,38 +55,62 @@ uint32_t SkFilterShader::getFlags() {
return shaderF;
}
-bool SkFilterShader::setContext(const SkBitmap& device,
- const SkPaint& paint,
- const SkMatrix& matrix) {
- // we need to keep the setContext/endContext calls balanced. If we return
- // false, our endContext() will not be called.
-
- if (!this->INHERITED::setContext(device, paint, matrix)) {
- return false;
- }
- if (!fShader->setContext(device, paint, matrix)) {
- this->INHERITED::endContext();
- return false;
+SkShader::Context* SkFilterShader::createContext(const SkBitmap& device,
+ const SkPaint& paint,
+ const SkMatrix& matrix,
+ void* storage) const {
+ if (!this->validContext(device, paint, matrix)) {
+ return NULL;
}
- return true;
+
+ char* shaderContextStorage = (char*)storage + sizeof(FilterShaderContext);
+ SkShader::Context* shaderContext = fShader->createContext(device, paint, matrix,
+ shaderContextStorage);
+ SkASSERT(shaderContext);
+
+ return SkNEW_PLACEMENT_ARGS(storage, FilterShaderContext,
+ (*this, shaderContext, device, paint, matrix));
+}
+
+size_t SkFilterShader::contextSize() const {
+ return sizeof(FilterShaderContext) + fShader->contextSize();
+}
+
+bool SkFilterShader::validContext(const SkBitmap& device,
+ const SkPaint& paint,
+ const SkMatrix& matrix,
+ SkMatrix* totalInverse) const {
+ return this->INHERITED::validContext(device, paint, matrix, totalInverse) &&
+ fShader->validContext(device, paint, matrix);
}
-void SkFilterShader::endContext() {
- fShader->endContext();
- this->INHERITED::endContext();
+SkFilterShader::FilterShaderContext::FilterShaderContext(const SkFilterShader& filterShader,
+ SkShader::Context* shaderContext,
+ const SkBitmap& device,
+ const SkPaint& paint,
+ const SkMatrix& matrix)
+ : INHERITED(filterShader, device, paint, matrix)
+ , fShaderContext(shaderContext) {}
+
+SkFilterShader::FilterShaderContext::~FilterShaderContext() {
+ fShaderContext->SkShader::Context::~Context();
}
-void SkFilterShader::shadeSpan(int x, int y, SkPMColor result[], int count) {
- fShader->shadeSpan(x, y, result, count);
- fFilter->filterSpan(result, count, result);
+void SkFilterShader::FilterShaderContext::shadeSpan(int x, int y, SkPMColor result[], int count) {
+ const SkFilterShader& filterShader = static_cast<const SkFilterShader&>(fShader);
+
+ fShaderContext->shadeSpan(x, y, result, count);
+ filterShader.fFilter->filterSpan(result, count, result);
}
-void SkFilterShader::shadeSpan16(int x, int y, uint16_t result[], int count) {
- SkASSERT(fShader->getFlags() & SkShader::kHasSpan16_Flag);
- SkASSERT(fFilter->getFlags() & SkColorFilter::kHasFilter16_Flag);
+void SkFilterShader::FilterShaderContext::shadeSpan16(int x, int y, uint16_t result[], int count) {
+ const SkFilterShader& filterShader = static_cast<const SkFilterShader&>(fShader);
+
+ SkASSERT(fShaderContext->getFlags() & SkShader::kHasSpan16_Flag);
+ SkASSERT(filterShader.fFilter->getFlags() & SkColorFilter::kHasFilter16_Flag);
- fShader->shadeSpan16(x, y, result, count);
- fFilter->filterSpan16(result, count, result);
+ fShaderContext->shadeSpan16(x, y, result, count);
+ filterShader.fFilter->filterSpan16(result, count, result);
}
#ifndef SK_IGNORE_TO_STRING
diff --git a/src/core/SkFilterShader.h b/src/core/SkFilterShader.h
index 11add0cf17..4ef4577248 100644
--- a/src/core/SkFilterShader.h
+++ b/src/core/SkFilterShader.h
@@ -17,12 +17,29 @@ public:
SkFilterShader(SkShader* shader, SkColorFilter* filter);
virtual ~SkFilterShader();
- virtual uint32_t getFlags() SK_OVERRIDE;
- virtual bool setContext(const SkBitmap&, const SkPaint&,
- const SkMatrix&) SK_OVERRIDE;
- virtual void endContext() SK_OVERRIDE;
- virtual void shadeSpan(int x, int y, SkPMColor[], int count) SK_OVERRIDE;
- virtual void shadeSpan16(int x, int y, uint16_t[], int count) SK_OVERRIDE;
+ virtual bool validContext(const SkBitmap&, const SkPaint&,
+ const SkMatrix&, SkMatrix* totalInverse = NULL) const SK_OVERRIDE;
+ virtual SkShader::Context* createContext(const SkBitmap&, const SkPaint&,
+ const SkMatrix&, void* storage) const SK_OVERRIDE;
+ virtual size_t contextSize() const SK_OVERRIDE;
+
+ class FilterShaderContext : public SkShader::Context {
+ public:
+ // Takes ownership of shaderContext and calls its destructor.
+ FilterShaderContext(const SkFilterShader& filterShader, SkShader::Context* shaderContext,
+ const SkBitmap& device, const SkPaint& paint, const SkMatrix& matrix);
+ virtual ~FilterShaderContext();
+
+ virtual uint32_t getFlags() const SK_OVERRIDE;
+
+ virtual void shadeSpan(int x, int y, SkPMColor[], int count) SK_OVERRIDE;
+ virtual void shadeSpan16(int x, int y, uint16_t[], int count) SK_OVERRIDE;
+
+ private:
+ SkShader::Context* fShaderContext;
+
+ typedef SkShader::Context INHERITED;
+ };
SK_TO_STRING_OVERRIDE()
SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkFilterShader)
diff --git a/src/core/SkPictureShader.cpp b/src/core/SkPictureShader.cpp
index 15df3a37a5..1e9507190c 100644
--- a/src/core/SkPictureShader.cpp
+++ b/src/core/SkPictureShader.cpp
@@ -55,9 +55,9 @@ void SkPictureShader::flatten(SkWriteBuffer& buffer) const {
}
}
-bool SkPictureShader::buildBitmapShader(const SkMatrix& matrix) const {
+SkShader* SkPictureShader::buildBitmapShader(const SkMatrix& matrix) const {
if (!fPicture || (0 == fPicture->width() && 0 == fPicture->height())) {
- return false;
+ return NULL;
}
SkMatrix m;
@@ -78,17 +78,20 @@ bool SkPictureShader::buildBitmapShader(const SkMatrix& matrix) const {
SkISize tileSize = scaledSize.toRound();
if (tileSize.isEmpty()) {
- return false;
+ return NULL;
}
// The actual scale, compensating for rounding.
SkSize tileScale = SkSize::Make(SkIntToScalar(tileSize.width()) / fPicture->width(),
SkIntToScalar(tileSize.height()) / fPicture->height());
- if (!fCachedShader || tileScale != fCachedTileScale) {
+ SkAutoMutexAcquire ama(fCachedBitmapShaderMutex);
+
+ if (!fCachedBitmapShader || tileScale != fCachedTileScale ||
+ this->getLocalMatrix() != fCachedLocalMatrix) {
SkBitmap bm;
if (!bm.allocN32Pixels(tileSize.width(), tileSize.height())) {
- return false;
+ return NULL;
}
bm.eraseColor(SK_ColorTRANSPARENT);
@@ -96,66 +99,96 @@ bool SkPictureShader::buildBitmapShader(const SkMatrix& matrix) const {
canvas.scale(tileScale.width(), tileScale.height());
canvas.drawPicture(*fPicture);
- fCachedShader.reset(CreateBitmapShader(bm, fTmx, fTmy));
+ fCachedBitmapShader.reset(CreateBitmapShader(bm, fTmx, fTmy));
fCachedTileScale = tileScale;
- }
+ fCachedLocalMatrix = this->getLocalMatrix();
- SkMatrix shaderMatrix = this->getLocalMatrix();
- shaderMatrix.preScale(1 / tileScale.width(), 1 / tileScale.height());
- fCachedShader->setLocalMatrix(shaderMatrix);
+ SkMatrix shaderMatrix = this->getLocalMatrix();
+ shaderMatrix.preScale(1 / tileScale.width(), 1 / tileScale.height());
+ fCachedBitmapShader->setLocalMatrix(shaderMatrix);
+ }
- return true;
+ // Increment the ref counter inside the mutex to ensure the returned pointer is still valid.
+ // Otherwise, the pointer may have been overwritten on a different thread before the object's
+ // ref count was incremented.
+ fCachedBitmapShader.get()->ref();
+ return fCachedBitmapShader;
}
-bool SkPictureShader::setContext(const SkBitmap& device,
- const SkPaint& paint,
- const SkMatrix& matrix) {
- if (!this->buildBitmapShader(matrix)) {
- return false;
+SkShader* SkPictureShader::validInternal(const SkBitmap& device, const SkPaint& paint,
+ const SkMatrix& matrix, SkMatrix* totalInverse) const {
+ if (!this->INHERITED::validContext(device, paint, matrix, totalInverse)) {
+ return NULL;
}
- if (!this->INHERITED::setContext(device, paint, matrix)) {
- return false;
+ SkShader* bitmapShader = this->buildBitmapShader(matrix);
+ if (!bitmapShader) {
+ return NULL;
}
- SkASSERT(fCachedShader);
- if (!fCachedShader->setContext(device, paint, matrix)) {
- this->INHERITED::endContext();
- return false;
+ if (!bitmapShader->validContext(device, paint, matrix)) {
+ bitmapShader->unref();
+ return NULL;
}
- return true;
+ return bitmapShader;
}
-void SkPictureShader::endContext() {
- SkASSERT(fCachedShader);
- fCachedShader->endContext();
-
- this->INHERITED::endContext();
+bool SkPictureShader::validContext(const SkBitmap& device, const SkPaint& paint,
+ const SkMatrix& matrix, SkMatrix* totalInverse) const {
+ SkAutoTUnref<SkShader> shader(this->validInternal(device, paint, matrix, totalInverse));
+ return shader != NULL;
}
-uint32_t SkPictureShader::getFlags() {
- if (NULL != fCachedShader) {
- return fCachedShader->getFlags();
+SkShader::Context* SkPictureShader::createContext(const SkBitmap& device, const SkPaint& paint,
+ const SkMatrix& matrix, void* storage) const {
+ SkShader* bitmapShader = this->validInternal(device, paint, matrix, NULL);
+ if (!bitmapShader) {
+ return NULL;
}
- return 0;
+
+ return SkNEW_PLACEMENT_ARGS(storage, PictureShaderContext,
+ (*this, device, paint, matrix, bitmapShader));
}
-SkShader::ShadeProc SkPictureShader::asAShadeProc(void** ctx) {
- if (fCachedShader) {
- return fCachedShader->asAShadeProc(ctx);
- }
- return NULL;
+size_t SkPictureShader::contextSize() const {
+ return sizeof(PictureShaderContext);
+}
+
+SkPictureShader::PictureShaderContext::PictureShaderContext(
+ const SkPictureShader& shader, const SkBitmap& device,
+ const SkPaint& paint, const SkMatrix& matrix, SkShader* bitmapShader)
+ : INHERITED(shader, device, paint, matrix)
+ , fBitmapShader(bitmapShader)
+{
+ SkASSERT(fBitmapShader);
+ fBitmapShaderContextStorage = sk_malloc_throw(fBitmapShader->contextSize());
+ fBitmapShaderContext = fBitmapShader->createContext(
+ device, paint, matrix, fBitmapShaderContextStorage);
+ SkASSERT(fBitmapShaderContext);
+}
+
+SkPictureShader::PictureShaderContext::~PictureShaderContext() {
+ fBitmapShaderContext->SkShader::Context::~Context();
+ sk_free(fBitmapShaderContextStorage);
+}
+
+uint32_t SkPictureShader::PictureShaderContext::getFlags() const {
+ return fBitmapShaderContext->getFlags();
+}
+
+SkShader::Context::ShadeProc SkPictureShader::PictureShaderContext::asAShadeProc(void** ctx) {
+ return fBitmapShaderContext->asAShadeProc(ctx);
}
-void SkPictureShader::shadeSpan(int x, int y, SkPMColor dstC[], int count) {
- SkASSERT(fCachedShader);
- fCachedShader->shadeSpan(x, y, dstC, count);
+void SkPictureShader::PictureShaderContext::shadeSpan(int x, int y, SkPMColor dstC[], int count) {
+ SkASSERT(fBitmapShaderContext);
+ fBitmapShaderContext->shadeSpan(x, y, dstC, count);
}
-void SkPictureShader::shadeSpan16(int x, int y, uint16_t dstC[], int count) {
- SkASSERT(fCachedShader);
- fCachedShader->shadeSpan16(x, y, dstC, count);
+void SkPictureShader::PictureShaderContext::shadeSpan16(int x, int y, uint16_t dstC[], int count) {
+ SkASSERT(fBitmapShaderContext);
+ fBitmapShaderContext->shadeSpan16(x, y, dstC, count);
}
#ifndef SK_IGNORE_TO_STRING
@@ -176,10 +209,10 @@ void SkPictureShader::toString(SkString* str) const {
#if SK_SUPPORT_GPU
GrEffectRef* SkPictureShader::asNewEffect(GrContext* context, const SkPaint& paint) const {
- if (!this->buildBitmapShader(context->getMatrix())) {
+ SkAutoTUnref<SkShader> bitmapShader(this->buildBitmapShader(context->getMatrix()));
+ if (!bitmapShader) {
return NULL;
}
- SkASSERT(fCachedShader);
- return fCachedShader->asNewEffect(context, paint);
+ return bitmapShader->asNewEffect(context, paint);
}
#endif
diff --git a/src/core/SkPictureShader.h b/src/core/SkPictureShader.h
index ea74b56d73..a0a377d0cd 100644
--- a/src/core/SkPictureShader.h
+++ b/src/core/SkPictureShader.h
@@ -24,13 +24,33 @@ public:
static SkPictureShader* Create(SkPicture*, TileMode, TileMode);
virtual ~SkPictureShader();
- virtual bool setContext(const SkBitmap&, const SkPaint&, const SkMatrix&) SK_OVERRIDE;
- virtual void endContext() SK_OVERRIDE;
- virtual uint32_t getFlags() SK_OVERRIDE;
+ virtual bool validContext(const SkBitmap&, const SkPaint&,
+ const SkMatrix&, SkMatrix* totalInverse = NULL) const SK_OVERRIDE;
+ virtual SkShader::Context* createContext(const SkBitmap& device, const SkPaint& paint,
+ const SkMatrix& matrix, void* storage) const
+ SK_OVERRIDE;
+ virtual size_t contextSize() const SK_OVERRIDE;
- virtual ShadeProc asAShadeProc(void** ctx) SK_OVERRIDE;
- virtual void shadeSpan(int x, int y, SkPMColor dstC[], int count) SK_OVERRIDE;
- virtual void shadeSpan16(int x, int y, uint16_t dstC[], int count) SK_OVERRIDE;
+ class PictureShaderContext : public SkShader::Context {
+ public:
+ PictureShaderContext(const SkPictureShader& shader, const SkBitmap& device,
+ const SkPaint& paint, const SkMatrix& matrix,
+ SkShader* bitmapShader);
+ virtual ~PictureShaderContext();
+
+ virtual uint32_t getFlags() const SK_OVERRIDE;
+
+ virtual ShadeProc asAShadeProc(void** ctx) SK_OVERRIDE;
+ virtual void shadeSpan(int x, int y, SkPMColor dstC[], int count) SK_OVERRIDE;
+ virtual void shadeSpan16(int x, int y, uint16_t dstC[], int count) SK_OVERRIDE;
+
+ private:
+ SkAutoTUnref<SkShader> fBitmapShader;
+ SkShader::Context* fBitmapShaderContext;
+ void* fBitmapShaderContextStorage;
+
+ typedef SkShader::Context INHERITED;
+ };
SK_TO_STRING_OVERRIDE()
SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkPictureShader)
@@ -46,13 +66,18 @@ protected:
private:
SkPictureShader(SkPicture*, TileMode, TileMode);
- bool buildBitmapShader(const SkMatrix&) const;
+ SkShader* validInternal(const SkBitmap& device, const SkPaint& paint,
+ const SkMatrix& matrix, SkMatrix* totalInverse) const;
+
+ SkShader* buildBitmapShader(const SkMatrix&) const;
SkPicture* fPicture;
TileMode fTmx, fTmy;
- mutable SkAutoTUnref<SkShader> fCachedShader;
+ mutable SkMutex fCachedBitmapShaderMutex;
+ mutable SkAutoTUnref<SkShader> fCachedBitmapShader;
mutable SkSize fCachedTileScale;
+ mutable SkMatrix fCachedLocalMatrix;
typedef SkShader INHERITED;
};
diff --git a/src/core/SkShader.cpp b/src/core/SkShader.cpp
index e337b7d906..40e52a05cb 100644
--- a/src/core/SkShader.cpp
+++ b/src/core/SkShader.cpp
@@ -17,7 +17,6 @@
SkShader::SkShader() {
fLocalMatrix.reset();
- SkDEBUGCODE(fInSetContext = false;)
}
SkShader::SkShader(SkReadBuffer& buffer)
@@ -27,12 +26,9 @@ SkShader::SkShader(SkReadBuffer& buffer)
} else {
fLocalMatrix.reset();
}
-
- SkDEBUGCODE(fInSetContext = false;)
}
SkShader::~SkShader() {
- SkASSERT(!fInSetContext);
}
void SkShader::flatten(SkWriteBuffer& buffer) const {
@@ -44,39 +40,48 @@ void SkShader::flatten(SkWriteBuffer& buffer) const {
}
}
-bool SkShader::setContext(const SkBitmap& device,
- const SkPaint& paint,
- const SkMatrix& matrix) {
- SkASSERT(!this->setContextHasBeenCalled());
-
+bool SkShader::computeTotalInverse(const SkMatrix& matrix, SkMatrix* totalInverse) const {
const SkMatrix* m = &matrix;
SkMatrix total;
- fPaintAlpha = paint.getAlpha();
if (this->hasLocalMatrix()) {
total.setConcat(matrix, this->getLocalMatrix());
m = &total;
}
- if (m->invert(&fTotalInverse)) {
- fTotalInverseClass = (uint8_t)ComputeMatrixClass(fTotalInverse);
- SkDEBUGCODE(fInSetContext = true;)
- return true;
- }
- return false;
+
+ return m->invert(totalInverse);
+}
+
+bool SkShader::validContext(const SkBitmap& device,
+ const SkPaint& paint,
+ const SkMatrix& matrix,
+ SkMatrix* totalInverse) const {
+ return this->computeTotalInverse(matrix, totalInverse);
}
-void SkShader::endContext() {
- SkASSERT(fInSetContext);
- SkDEBUGCODE(fInSetContext = false;)
+SkShader::Context::Context(const SkShader& shader, const SkBitmap& device,
+ const SkPaint& paint, const SkMatrix& matrix)
+ : fShader(shader)
+{
+ SkASSERT(fShader.validContext(device, paint, matrix));
+
+ // Because the context parameters must be valid at this point, we know that the matrix is
+ // invertible.
+ SkAssertResult(fShader.computeTotalInverse(matrix, &fTotalInverse));
+ fTotalInverseClass = (uint8_t)ComputeMatrixClass(fTotalInverse);
+
+ fPaintAlpha = paint.getAlpha();
}
-SkShader::ShadeProc SkShader::asAShadeProc(void** ctx) {
+SkShader::Context::~Context() {}
+
+SkShader::Context::ShadeProc SkShader::Context::asAShadeProc(void** ctx) {
return NULL;
}
#include "SkColorPriv.h"
-void SkShader::shadeSpan16(int x, int y, uint16_t span16[], int count) {
+void SkShader::Context::shadeSpan16(int x, int y, uint16_t span16[], int count) {
SkASSERT(span16);
SkASSERT(count > 0);
SkASSERT(this->canCallShadeSpan16());
@@ -94,7 +99,7 @@ void SkShader::shadeSpan16(int x, int y, uint16_t span16[], int count) {
#define SkU32BitShiftToByteOffset(shift) ((shift) >> 3)
#endif
-void SkShader::shadeSpanAlpha(int x, int y, uint8_t alpha[], int count) {
+void SkShader::Context::shadeSpanAlpha(int x, int y, uint8_t alpha[], int count) {
SkASSERT(count > 0);
SkPMColor colors[kTempColorCount];
@@ -148,7 +153,7 @@ void SkShader::shadeSpanAlpha(int x, int y, uint8_t alpha[], int count) {
#endif
}
-SkShader::MatrixClass SkShader::ComputeMatrixClass(const SkMatrix& mat) {
+SkShader::Context::MatrixClass SkShader::Context::ComputeMatrixClass(const SkMatrix& mat) {
MatrixClass mc = kLinear_MatrixClass;
if (mat.hasPerspective()) {
@@ -163,8 +168,7 @@ SkShader::MatrixClass SkShader::ComputeMatrixClass(const SkMatrix& mat) {
//////////////////////////////////////////////////////////////////////////////
-SkShader::BitmapType SkShader::asABitmap(SkBitmap*, SkMatrix*,
- TileMode*) const {
+SkShader::BitmapType SkShader::asABitmap(SkBitmap*, SkMatrix*, TileMode*) const {
return kNone_BitmapType;
}
@@ -199,19 +203,16 @@ void SkShader::toString(SkString* str) const {
#include "SkColorShader.h"
#include "SkUtils.h"
-SkColorShader::SkColorShader() {
- fFlags = 0;
- fInheritColor = true;
+SkColorShader::SkColorShader()
+ : fColor()
+ , fInheritColor(true) {
}
-SkColorShader::SkColorShader(SkColor c) {
- fFlags = 0;
- fColor = c;
- fInheritColor = false;
+SkColorShader::SkColorShader(SkColor c)
+ : fColor(c)
+ , fInheritColor(false) {
}
-SkColorShader::~SkColorShader() {}
-
bool SkColorShader::isOpaque() const {
if (fInheritColor) {
return true; // using paint's alpha
@@ -220,8 +221,6 @@ bool SkColorShader::isOpaque() const {
}
SkColorShader::SkColorShader(SkReadBuffer& b) : INHERITED(b) {
- fFlags = 0; // computed in setContext
-
fInheritColor = b.readBool();
if (fInheritColor) {
return;
@@ -238,32 +237,43 @@ void SkColorShader::flatten(SkWriteBuffer& buffer) const {
buffer.writeColor(fColor);
}
-uint32_t SkColorShader::getFlags() {
+uint32_t SkColorShader::ColorShaderContext::getFlags() const {
return fFlags;
}
-uint8_t SkColorShader::getSpan16Alpha() const {
+uint8_t SkColorShader::ColorShaderContext::getSpan16Alpha() const {
return SkGetPackedA32(fPMColor);
}
-bool SkColorShader::setContext(const SkBitmap& device, const SkPaint& paint,
- const SkMatrix& matrix) {
- if (!this->INHERITED::setContext(device, paint, matrix)) {
- return false;
+SkShader::Context* SkColorShader::createContext(const SkBitmap& device, const SkPaint& paint,
+ const SkMatrix& matrix, void* storage) const {
+ if (!this->validContext(device, paint, matrix)) {
+ return NULL;
}
+ return SkNEW_PLACEMENT_ARGS(storage, ColorShaderContext, (*this, device, paint, matrix));
+}
+
+SkColorShader::ColorShaderContext::ColorShaderContext(const SkColorShader& shader,
+ const SkBitmap& device,
+ const SkPaint& paint,
+ const SkMatrix& matrix)
+ : INHERITED(shader, device, paint, matrix)
+{
unsigned a;
- if (fInheritColor) {
- fColor = paint.getColor();
- a = SkColorGetA(fColor);
+ SkColor color;
+ if (shader.fInheritColor) {
+ color = paint.getColor();
+ a = SkColorGetA(color);
} else {
- a = SkAlphaMul(SkColorGetA(fColor), SkAlpha255To256(paint.getAlpha()));
+ color = shader.fColor;
+ a = SkAlphaMul(SkColorGetA(color), SkAlpha255To256(paint.getAlpha()));
}
- unsigned r = SkColorGetR(fColor);
- unsigned g = SkColorGetG(fColor);
- unsigned b = SkColorGetB(fColor);
+ unsigned r = SkColorGetR(color);
+ unsigned g = SkColorGetG(color);
+ unsigned b = SkColorGetB(color);
// we want this before we apply any alpha
fColor16 = SkPack888ToRGB16(r, g, b);
@@ -282,19 +292,17 @@ bool SkColorShader::setContext(const SkBitmap& device, const SkPaint& paint,
fFlags |= kHasSpan16_Flag;
}
}
-
- return true;
}
-void SkColorShader::shadeSpan(int x, int y, SkPMColor span[], int count) {
+void SkColorShader::ColorShaderContext::shadeSpan(int x, int y, SkPMColor span[], int count) {
sk_memset32(span, fPMColor, count);
}
-void SkColorShader::shadeSpan16(int x, int y, uint16_t span[], int count) {
+void SkColorShader::ColorShaderContext::shadeSpan16(int x, int y, uint16_t span[], int count) {
sk_memset16(span, fColor16, count);
}
-void SkColorShader::shadeSpanAlpha(int x, int y, uint8_t alpha[], int count) {
+void SkColorShader::ColorShaderContext::shadeSpanAlpha(int x, int y, uint8_t alpha[], int count) {
memset(alpha, SkGetPackedA32(fPMColor), count);
}
@@ -334,27 +342,9 @@ void SkColorShader::toString(SkString* str) const {
///////////////////////////////////////////////////////////////////////////////
+#ifndef SK_IGNORE_TO_STRING
#include "SkEmptyShader.h"
-uint32_t SkEmptyShader::getFlags() { return 0; }
-uint8_t SkEmptyShader::getSpan16Alpha() const { return 0; }
-
-bool SkEmptyShader::setContext(const SkBitmap&, const SkPaint&,
- const SkMatrix&) { return false; }
-
-void SkEmptyShader::shadeSpan(int x, int y, SkPMColor span[], int count) {
- SkDEBUGFAIL("should never get called, since setContext() returned false");
-}
-
-void SkEmptyShader::shadeSpan16(int x, int y, uint16_t span[], int count) {
- SkDEBUGFAIL("should never get called, since setContext() returned false");
-}
-
-void SkEmptyShader::shadeSpanAlpha(int x, int y, uint8_t alpha[], int count) {
- SkDEBUGFAIL("should never get called, since setContext() returned false");
-}
-
-#ifndef SK_IGNORE_TO_STRING
void SkEmptyShader::toString(SkString* str) const {
str->append("SkEmptyShader: (");
diff --git a/src/core/SkSmallAllocator.h b/src/core/SkSmallAllocator.h
index 655008b706..8d4b53a707 100644
--- a/src/core/SkSmallAllocator.h
+++ b/src/core/SkSmallAllocator.h
@@ -117,10 +117,12 @@ public:
// but we're not sure we can catch all callers, so handle it but
// assert false in debug mode.
SkASSERT(false);
+ rec->fStorageSize = 0;
rec->fHeapStorage = sk_malloc_throw(storageRequired);
rec->fObj = static_cast<void*>(rec->fHeapStorage);
} else {
// There is space in fStorage.
+ rec->fStorageSize = storageRequired;
rec->fHeapStorage = NULL;
SkASSERT(SkIsAlign4(fStorageUsed));
rec->fObj = static_cast<void*>(fStorage + (fStorageUsed / 4));
@@ -131,11 +133,26 @@ public:
return rec->fObj;
}
+ /*
+ * Free the memory reserved last without calling the destructor.
+ * Can be used in a nested way, i.e. after reserving A and B, calling
+ * freeLast once will free B and calling it again will free A.
+ */
+ void freeLast() {
+ SkASSERT(fNumObjects > 0);
+ Rec* rec = &fRecs[fNumObjects - 1];
+ sk_free(rec->fHeapStorage);
+ fStorageUsed -= rec->fStorageSize;
+
+ fNumObjects--;
+ }
+
private:
struct Rec {
- void* fObj;
- void* fHeapStorage;
- void (*fKillProc)(void*);
+ size_t fStorageSize; // 0 if allocated on heap
+ void* fObj;
+ void* fHeapStorage;
+ void (*fKillProc)(void*);
};
// Number of bytes used so far.