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