1 
2 /*
3  * Copyright 2011 Google Inc.
4  *
5  * Use of this source code is governed by a BSD-style license that can be
6  * found in the LICENSE file.
7  */
8 #include "SkColorPriv.h"
9 #include "SkReadBuffer.h"
10 #include "SkWriteBuffer.h"
11 #include "SkPixelRef.h"
12 #include "SkErrorInternals.h"
13 #include "SkBitmapProcShader.h"
14 
15 #if SK_SUPPORT_GPU
16 #include "effects/GrSimpleTextureEffect.h"
17 #include "effects/GrBicubicEffect.h"
18 #endif
19 
CanDo(const SkBitmap & bm,TileMode tx,TileMode ty)20 bool SkBitmapProcShader::CanDo(const SkBitmap& bm, TileMode tx, TileMode ty) {
21     switch (bm.colorType()) {
22         case kAlpha_8_SkColorType:
23         case kRGB_565_SkColorType:
24         case kIndex_8_SkColorType:
25         case kN32_SkColorType:
26     //        if (tx == ty && (kClamp_TileMode == tx || kRepeat_TileMode == tx))
27                 return true;
28         default:
29             break;
30     }
31     return false;
32 }
33 
SkBitmapProcShader(const SkBitmap & src,TileMode tmx,TileMode tmy,const SkMatrix * localMatrix)34 SkBitmapProcShader::SkBitmapProcShader(const SkBitmap& src, TileMode tmx, TileMode tmy,
35                                        const SkMatrix* localMatrix)
36         : INHERITED(localMatrix) {
37     fRawBitmap = src;
38     fTileModeX = (uint8_t)tmx;
39     fTileModeY = (uint8_t)tmy;
40 }
41 
asABitmap(SkBitmap * texture,SkMatrix * texM,TileMode xy[]) const42 SkShader::BitmapType SkBitmapProcShader::asABitmap(SkBitmap* texture,
43                                                    SkMatrix* texM,
44                                                    TileMode xy[]) const {
45     if (texture) {
46         *texture = fRawBitmap;
47     }
48     if (texM) {
49         texM->reset();
50     }
51     if (xy) {
52         xy[0] = (TileMode)fTileModeX;
53         xy[1] = (TileMode)fTileModeY;
54     }
55     return kDefault_BitmapType;
56 }
57 
CreateProc(SkReadBuffer & buffer)58 SkFlattenable* SkBitmapProcShader::CreateProc(SkReadBuffer& buffer) {
59     SkMatrix lm;
60     buffer.readMatrix(&lm);
61     SkBitmap bm;
62     if (!buffer.readBitmap(&bm)) {
63         return NULL;
64     }
65     bm.setImmutable();
66     TileMode mx = (TileMode)buffer.readUInt();
67     TileMode my = (TileMode)buffer.readUInt();
68     return SkShader::CreateBitmapShader(bm, mx, my, &lm);
69 }
70 
flatten(SkWriteBuffer & buffer) const71 void SkBitmapProcShader::flatten(SkWriteBuffer& buffer) const {
72     buffer.writeMatrix(this->getLocalMatrix());
73     buffer.writeBitmap(fRawBitmap);
74     buffer.writeUInt(fTileModeX);
75     buffer.writeUInt(fTileModeY);
76 }
77 
only_scale_and_translate(const SkMatrix & matrix)78 static bool only_scale_and_translate(const SkMatrix& matrix) {
79     unsigned mask = SkMatrix::kTranslate_Mask | SkMatrix::kScale_Mask;
80     return (matrix.getType() & ~mask) == 0;
81 }
82 
isOpaque() const83 bool SkBitmapProcShader::isOpaque() const {
84     return fRawBitmap.isOpaque();
85 }
86 
onCreateContext(const ContextRec & rec,void * storage) const87 SkShader::Context* SkBitmapProcShader::onCreateContext(const ContextRec& rec, void* storage) const {
88     SkMatrix totalInverse;
89     // Do this first, so we know the matrix can be inverted.
90     if (!this->computeTotalInverse(rec, &totalInverse)) {
91         return NULL;
92     }
93 
94     void* stateStorage = (char*)storage + sizeof(BitmapProcShaderContext);
95     SkBitmapProcState* state = SkNEW_PLACEMENT(stateStorage, SkBitmapProcState);
96 
97     SkASSERT(state);
98     state->fTileModeX = fTileModeX;
99     state->fTileModeY = fTileModeY;
100     state->fOrigBitmap = fRawBitmap;
101     if (!state->chooseProcs(totalInverse, *rec.fPaint)) {
102         state->~SkBitmapProcState();
103         return NULL;
104     }
105 
106     return SkNEW_PLACEMENT_ARGS(storage, BitmapProcShaderContext, (*this, rec, state));
107 }
108 
contextSize() const109 size_t SkBitmapProcShader::contextSize() const {
110     // The SkBitmapProcState is stored outside of the context object, with the context holding
111     // a pointer to it.
112     return sizeof(BitmapProcShaderContext) + sizeof(SkBitmapProcState);
113 }
114 
BitmapProcShaderContext(const SkBitmapProcShader & shader,const ContextRec & rec,SkBitmapProcState * state)115 SkBitmapProcShader::BitmapProcShaderContext::BitmapProcShaderContext(
116         const SkBitmapProcShader& shader, const ContextRec& rec, SkBitmapProcState* state)
117     : INHERITED(shader, rec)
118     , fState(state)
119 {
120     const SkBitmap& bitmap = *fState->fBitmap;
121     bool bitmapIsOpaque = bitmap.isOpaque();
122 
123     // update fFlags
124     uint32_t flags = 0;
125     if (bitmapIsOpaque && (255 == this->getPaintAlpha())) {
126         flags |= kOpaqueAlpha_Flag;
127     }
128 
129     switch (bitmap.colorType()) {
130         case kRGB_565_SkColorType:
131             flags |= (kHasSpan16_Flag | kIntrinsicly16_Flag);
132             break;
133         case kIndex_8_SkColorType:
134         case kN32_SkColorType:
135             if (bitmapIsOpaque) {
136                 flags |= kHasSpan16_Flag;
137             }
138             break;
139         case kAlpha_8_SkColorType:
140             break;  // never set kHasSpan16_Flag
141         default:
142             break;
143     }
144 
145     if (rec.fPaint->isDither() && bitmap.colorType() != kRGB_565_SkColorType) {
146         // gradients can auto-dither in their 16bit sampler, but we don't so
147         // we clear the flag here.
148         flags &= ~kHasSpan16_Flag;
149     }
150 
151     // if we're only 1-pixel high, and we don't rotate, then we can claim this
152     if (1 == bitmap.height() &&
153             only_scale_and_translate(this->getTotalInverse())) {
154         flags |= kConstInY32_Flag;
155         if (flags & kHasSpan16_Flag) {
156             flags |= kConstInY16_Flag;
157         }
158     }
159 
160     fFlags = flags;
161 }
162 
~BitmapProcShaderContext()163 SkBitmapProcShader::BitmapProcShaderContext::~BitmapProcShaderContext() {
164     // The bitmap proc state has been created outside of the context on memory that will be freed
165     // elsewhere. Only call the destructor but leave the freeing of the memory to the caller.
166     fState->~SkBitmapProcState();
167 }
168 
169 #define BUF_MAX     128
170 
171 #define TEST_BUFFER_OVERRITEx
172 
173 #ifdef TEST_BUFFER_OVERRITE
174     #define TEST_BUFFER_EXTRA   32
175     #define TEST_PATTERN    0x88888888
176 #else
177     #define TEST_BUFFER_EXTRA   0
178 #endif
179 
shadeSpan(int x,int y,SkPMColor dstC[],int count)180 void SkBitmapProcShader::BitmapProcShaderContext::shadeSpan(int x, int y, SkPMColor dstC[],
181                                                             int count) {
182     const SkBitmapProcState& state = *fState;
183     if (state.getShaderProc32()) {
184         state.getShaderProc32()(state, x, y, dstC, count);
185         return;
186     }
187 
188     uint32_t buffer[BUF_MAX + TEST_BUFFER_EXTRA];
189     SkBitmapProcState::MatrixProc   mproc = state.getMatrixProc();
190     SkBitmapProcState::SampleProc32 sproc = state.getSampleProc32();
191     int max = state.maxCountForBufferSize(sizeof(buffer[0]) * BUF_MAX);
192 
193     SkASSERT(state.fBitmap->getPixels());
194     SkASSERT(state.fBitmap->pixelRef() == NULL ||
195              state.fBitmap->pixelRef()->isLocked());
196 
197     for (;;) {
198         int n = count;
199         if (n > max) {
200             n = max;
201         }
202         SkASSERT(n > 0 && n < BUF_MAX*2);
203 #ifdef TEST_BUFFER_OVERRITE
204         for (int i = 0; i < TEST_BUFFER_EXTRA; i++) {
205             buffer[BUF_MAX + i] = TEST_PATTERN;
206         }
207 #endif
208         mproc(state, buffer, n, x, y);
209 #ifdef TEST_BUFFER_OVERRITE
210         for (int j = 0; j < TEST_BUFFER_EXTRA; j++) {
211             SkASSERT(buffer[BUF_MAX + j] == TEST_PATTERN);
212         }
213 #endif
214         sproc(state, buffer, n, dstC);
215 
216         if ((count -= n) == 0) {
217             break;
218         }
219         SkASSERT(count > 0);
220         x += n;
221         dstC += n;
222     }
223 }
224 
asAShadeProc(void ** ctx)225 SkShader::Context::ShadeProc SkBitmapProcShader::BitmapProcShaderContext::asAShadeProc(void** ctx) {
226     if (fState->getShaderProc32()) {
227         *ctx = fState;
228         return (ShadeProc)fState->getShaderProc32();
229     }
230     return NULL;
231 }
232 
shadeSpan16(int x,int y,uint16_t dstC[],int count)233 void SkBitmapProcShader::BitmapProcShaderContext::shadeSpan16(int x, int y, uint16_t dstC[],
234                                                               int count) {
235     const SkBitmapProcState& state = *fState;
236     if (state.getShaderProc16()) {
237         state.getShaderProc16()(state, x, y, dstC, count);
238         return;
239     }
240 
241     uint32_t buffer[BUF_MAX];
242     SkBitmapProcState::MatrixProc   mproc = state.getMatrixProc();
243     SkBitmapProcState::SampleProc16 sproc = state.getSampleProc16();
244     int max = state.maxCountForBufferSize(sizeof(buffer));
245 
246     SkASSERT(state.fBitmap->getPixels());
247     SkASSERT(state.fBitmap->pixelRef() == NULL ||
248              state.fBitmap->pixelRef()->isLocked());
249 
250     for (;;) {
251         int n = count;
252         if (n > max) {
253             n = max;
254         }
255         mproc(state, buffer, n, x, y);
256         sproc(state, buffer, n, dstC);
257 
258         if ((count -= n) == 0) {
259             break;
260         }
261         x += n;
262         dstC += n;
263     }
264 }
265 
266 ///////////////////////////////////////////////////////////////////////////////
267 
268 #include "SkUnPreMultiply.h"
269 #include "SkColorShader.h"
270 #include "SkEmptyShader.h"
271 
272 // returns true and set color if the bitmap can be drawn as a single color
273 // (for efficiency)
canUseColorShader(const SkBitmap & bm,SkColor * color)274 static bool canUseColorShader(const SkBitmap& bm, SkColor* color) {
275 #ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK
276     // Android expects SkShaders constructed from a Bitmap to always be queryable with
277     // SkShader::asABitmap()
278     return false;
279 #endif
280 
281     if (1 != bm.width() || 1 != bm.height()) {
282         return false;
283     }
284 
285     SkAutoLockPixels alp(bm);
286     if (!bm.readyToDraw()) {
287         return false;
288     }
289 
290     switch (bm.colorType()) {
291         case kN32_SkColorType:
292             *color = SkUnPreMultiply::PMColorToColor(*bm.getAddr32(0, 0));
293             return true;
294         case kRGB_565_SkColorType:
295             *color = SkPixel16ToColor(*bm.getAddr16(0, 0));
296             return true;
297         case kIndex_8_SkColorType:
298             *color = SkUnPreMultiply::PMColorToColor(bm.getIndex8Color(0, 0));
299             return true;
300         default: // just skip the other configs for now
301             break;
302     }
303     return false;
304 }
305 
bitmapIsTooBig(const SkBitmap & bm)306 static bool bitmapIsTooBig(const SkBitmap& bm) {
307     // SkBitmapProcShader stores bitmap coordinates in a 16bit buffer, as it
308     // communicates between its matrix-proc and its sampler-proc. Until we can
309     // widen that, we have to reject bitmaps that are larger.
310     //
311     const int maxSize = 65535;
312 
313     return bm.width() > maxSize || bm.height() > maxSize;
314 }
315 
SkCreateBitmapShader(const SkBitmap & src,SkShader::TileMode tmx,SkShader::TileMode tmy,const SkMatrix * localMatrix,SkTBlitterAllocator * allocator)316 SkShader* SkCreateBitmapShader(const SkBitmap& src, SkShader::TileMode tmx,
317                                SkShader::TileMode tmy, const SkMatrix* localMatrix,
318                                SkTBlitterAllocator* allocator) {
319     SkShader* shader;
320     SkColor color;
321     if (src.isNull() || bitmapIsTooBig(src)) {
322         if (NULL == allocator) {
323             shader = SkNEW(SkEmptyShader);
324         } else {
325             shader = allocator->createT<SkEmptyShader>();
326         }
327     }
328     else if (canUseColorShader(src, &color)) {
329         if (NULL == allocator) {
330             shader = SkNEW_ARGS(SkColorShader, (color));
331         } else {
332             shader = allocator->createT<SkColorShader>(color);
333         }
334     } else {
335         if (NULL == allocator) {
336             shader = SkNEW_ARGS(SkBitmapProcShader, (src, tmx, tmy, localMatrix));
337         } else {
338             shader = allocator->createT<SkBitmapProcShader>(src, tmx, tmy, localMatrix);
339         }
340     }
341     return shader;
342 }
343 
344 ///////////////////////////////////////////////////////////////////////////////
345 
346 #ifndef SK_IGNORE_TO_STRING
toString(SkString * str) const347 void SkBitmapProcShader::toString(SkString* str) const {
348     static const char* gTileModeName[SkShader::kTileModeCount] = {
349         "clamp", "repeat", "mirror"
350     };
351 
352     str->append("BitmapShader: (");
353 
354     str->appendf("(%s, %s)",
355                  gTileModeName[fTileModeX],
356                  gTileModeName[fTileModeY]);
357 
358     str->append(" ");
359     fRawBitmap.toString(str);
360 
361     this->INHERITED::toString(str);
362 
363     str->append(")");
364 }
365 #endif
366 
367 ///////////////////////////////////////////////////////////////////////////////
368 
369 #if SK_SUPPORT_GPU
370 
371 #include "GrTextureAccess.h"
372 #include "effects/GrSimpleTextureEffect.h"
373 #include "SkGr.h"
374 
asFragmentProcessor(GrContext * context,const SkPaint & paint,const SkMatrix & viewM,const SkMatrix * localMatrix,GrColor * paintColor,GrFragmentProcessor ** fp) const375 bool SkBitmapProcShader::asFragmentProcessor(GrContext* context, const SkPaint& paint,
376                                              const SkMatrix& viewM,
377                                              const SkMatrix* localMatrix, GrColor* paintColor,
378                                              GrFragmentProcessor** fp) const {
379     SkMatrix matrix;
380     matrix.setIDiv(fRawBitmap.width(), fRawBitmap.height());
381 
382     SkMatrix lmInverse;
383     if (!this->getLocalMatrix().invert(&lmInverse)) {
384         return false;
385     }
386     if (localMatrix) {
387         SkMatrix inv;
388         if (!localMatrix->invert(&inv)) {
389             return false;
390         }
391         lmInverse.postConcat(inv);
392     }
393     matrix.preConcat(lmInverse);
394 
395     SkShader::TileMode tm[] = {
396         (TileMode)fTileModeX,
397         (TileMode)fTileModeY,
398     };
399 
400     // Must set wrap and filter on the sampler before requesting a texture. In two places below
401     // we check the matrix scale factors to determine how to interpret the filter quality setting.
402     // This completely ignores the complexity of the drawVertices case where explicit local coords
403     // are provided by the caller.
404     bool useBicubic = false;
405     GrTextureParams::FilterMode textureFilterMode;
406     switch(paint.getFilterQuality()) {
407         case kNone_SkFilterQuality:
408             textureFilterMode = GrTextureParams::kNone_FilterMode;
409             break;
410         case kLow_SkFilterQuality:
411             textureFilterMode = GrTextureParams::kBilerp_FilterMode;
412             break;
413         case kMedium_SkFilterQuality: {
414             SkMatrix matrix;
415             matrix.setConcat(viewM, this->getLocalMatrix());
416             if (matrix.getMinScale() < SK_Scalar1) {
417                 textureFilterMode = GrTextureParams::kMipMap_FilterMode;
418             } else {
419                 // Don't trigger MIP level generation unnecessarily.
420                 textureFilterMode = GrTextureParams::kBilerp_FilterMode;
421             }
422             break;
423         }
424         case kHigh_SkFilterQuality: {
425             SkMatrix matrix;
426             matrix.setConcat(viewM, this->getLocalMatrix());
427             useBicubic = GrBicubicEffect::ShouldUseBicubic(matrix, &textureFilterMode);
428             break;
429         }
430         default:
431             SkErrorInternals::SetError( kInvalidPaint_SkError,
432                                         "Sorry, I don't understand the filtering "
433                                         "mode you asked for.  Falling back to "
434                                         "MIPMaps.");
435             textureFilterMode = GrTextureParams::kMipMap_FilterMode;
436             break;
437 
438     }
439     GrTextureParams params(tm, textureFilterMode);
440     SkAutoTUnref<GrTexture> texture(GrRefCachedBitmapTexture(context, fRawBitmap, &params));
441 
442     if (!texture) {
443         SkErrorInternals::SetError( kInternalError_SkError,
444                                     "Couldn't convert bitmap to texture.");
445         return false;
446     }
447 
448     *paintColor = (kAlpha_8_SkColorType == fRawBitmap.colorType()) ?
449                                                 SkColor2GrColor(paint.getColor()) :
450                                                 SkColor2GrColorJustAlpha(paint.getColor());
451 
452     if (useBicubic) {
453         *fp = GrBicubicEffect::Create(texture, matrix, tm);
454     } else {
455         *fp = GrSimpleTextureEffect::Create(texture, matrix, params);
456     }
457 
458     return true;
459 }
460 
461 #else
462 
asFragmentProcessor(GrContext *,const SkPaint &,const SkMatrix &,const SkMatrix *,GrColor *,GrFragmentProcessor **) const463 bool SkBitmapProcShader::asFragmentProcessor(GrContext*, const SkPaint&, const SkMatrix&,
464                                              const SkMatrix*, GrColor*,
465                                              GrFragmentProcessor**) const {
466     SkDEBUGFAIL("Should not call in GPU-less build");
467     return false;
468 }
469 
470 #endif
471