1 /*
2  * Copyright 2011 Google Inc.
3  *
4  * Use of this source code is governed by a BSD-style license that can be
5  * found in the LICENSE file.
6  */
7 
8 #include "SkBitmapProcShader.h"
9 #include "SkBitmapProcState.h"
10 #include "SkBitmapProvider.h"
11 #include "SkColorPriv.h"
12 #include "SkErrorInternals.h"
13 #include "SkPixelRef.h"
14 #include "SkReadBuffer.h"
15 #include "SkWriteBuffer.h"
16 
17 #if SK_SUPPORT_GPU
18 #include "SkGrPriv.h"
19 #include "effects/GrBicubicEffect.h"
20 #include "effects/GrSimpleTextureEffect.h"
21 #endif
22 
ContextSize()23 size_t SkBitmapProcShader::ContextSize() {
24     // The SkBitmapProcState is stored outside of the context object, with the context holding
25     // a pointer to it.
26     return sizeof(BitmapProcShaderContext) + sizeof(SkBitmapProcState);
27 }
28 
SkBitmapProcShader(const SkBitmap & src,TileMode tmx,TileMode tmy,const SkMatrix * localMatrix)29 SkBitmapProcShader::SkBitmapProcShader(const SkBitmap& src, TileMode tmx, TileMode tmy,
30                                        const SkMatrix* localMatrix)
31         : INHERITED(localMatrix) {
32     fRawBitmap = src;
33     fTileModeX = (uint8_t)tmx;
34     fTileModeY = (uint8_t)tmy;
35 }
36 
onIsABitmap(SkBitmap * texture,SkMatrix * texM,TileMode xy[]) const37 bool SkBitmapProcShader::onIsABitmap(SkBitmap* texture, SkMatrix* texM, TileMode xy[]) const {
38     if (texture) {
39         *texture = fRawBitmap;
40     }
41     if (texM) {
42         texM->reset();
43     }
44     if (xy) {
45         xy[0] = (TileMode)fTileModeX;
46         xy[1] = (TileMode)fTileModeY;
47     }
48     return true;
49 }
50 
CreateProc(SkReadBuffer & buffer)51 SkFlattenable* SkBitmapProcShader::CreateProc(SkReadBuffer& buffer) {
52     SkMatrix lm;
53     buffer.readMatrix(&lm);
54     SkBitmap bm;
55     if (!buffer.readBitmap(&bm)) {
56         return nullptr;
57     }
58     bm.setImmutable();
59     TileMode mx = (TileMode)buffer.readUInt();
60     TileMode my = (TileMode)buffer.readUInt();
61     return SkShader::CreateBitmapShader(bm, mx, my, &lm);
62 }
63 
flatten(SkWriteBuffer & buffer) const64 void SkBitmapProcShader::flatten(SkWriteBuffer& buffer) const {
65     buffer.writeMatrix(this->getLocalMatrix());
66     buffer.writeBitmap(fRawBitmap);
67     buffer.writeUInt(fTileModeX);
68     buffer.writeUInt(fTileModeY);
69 }
70 
isOpaque() const71 bool SkBitmapProcShader::isOpaque() const {
72     return fRawBitmap.isOpaque();
73 }
74 
MakeContext(const SkShader & shader,TileMode tmx,TileMode tmy,const SkBitmapProvider & provider,const ContextRec & rec,void * storage)75 SkShader::Context* SkBitmapProcShader::MakeContext(const SkShader& shader,
76                                                    TileMode tmx, TileMode tmy,
77                                                    const SkBitmapProvider& provider,
78                                                    const ContextRec& rec, void* storage) {
79     SkMatrix totalInverse;
80     // Do this first, so we know the matrix can be inverted.
81     if (!shader.computeTotalInverse(rec, &totalInverse)) {
82         return nullptr;
83     }
84 
85     void* stateStorage = (char*)storage + sizeof(BitmapProcShaderContext);
86     SkBitmapProcState* state = new (stateStorage) SkBitmapProcState(provider, tmx, tmy);
87 
88     SkASSERT(state);
89     if (!state->chooseProcs(totalInverse, *rec.fPaint)) {
90         state->~SkBitmapProcState();
91         return nullptr;
92     }
93 
94     return new (storage) BitmapProcShaderContext(shader, rec, state);
95 }
96 
onCreateContext(const ContextRec & rec,void * storage) const97 SkShader::Context* SkBitmapProcShader::onCreateContext(const ContextRec& rec, void* storage) const {
98     return MakeContext(*this, (TileMode)fTileModeX, (TileMode)fTileModeY,
99                        SkBitmapProvider(fRawBitmap), rec, storage);
100 }
101 
only_scale_and_translate(const SkMatrix & matrix)102 static bool only_scale_and_translate(const SkMatrix& matrix) {
103     unsigned mask = SkMatrix::kTranslate_Mask | SkMatrix::kScale_Mask;
104     return (matrix.getType() & ~mask) == 0;
105 }
106 
BitmapProcShaderContext(const SkShader & shader,const ContextRec & rec,SkBitmapProcState * state)107 SkBitmapProcShader::BitmapProcShaderContext::BitmapProcShaderContext(const SkShader& shader,
108                                                                      const ContextRec& rec,
109                                                                      SkBitmapProcState* state)
110     : INHERITED(shader, rec)
111     , fState(state)
112 {
113     fFlags = 0;
114     if (fState->fPixmap.isOpaque() && (255 == this->getPaintAlpha())) {
115         fFlags |= kOpaqueAlpha_Flag;
116     }
117 
118     if (1 == fState->fPixmap.height() && only_scale_and_translate(this->getTotalInverse())) {
119         fFlags |= kConstInY32_Flag;
120     }
121 }
122 
~BitmapProcShaderContext()123 SkBitmapProcShader::BitmapProcShaderContext::~BitmapProcShaderContext() {
124     // The bitmap proc state has been created outside of the context on memory that will be freed
125     // elsewhere. Only call the destructor but leave the freeing of the memory to the caller.
126     fState->~SkBitmapProcState();
127 }
128 
129 #define BUF_MAX     128
130 
131 #define TEST_BUFFER_OVERRITEx
132 
133 #ifdef TEST_BUFFER_OVERRITE
134     #define TEST_BUFFER_EXTRA   32
135     #define TEST_PATTERN    0x88888888
136 #else
137     #define TEST_BUFFER_EXTRA   0
138 #endif
139 
shadeSpan(int x,int y,SkPMColor dstC[],int count)140 void SkBitmapProcShader::BitmapProcShaderContext::shadeSpan(int x, int y, SkPMColor dstC[],
141                                                             int count) {
142     const SkBitmapProcState& state = *fState;
143     if (state.getShaderProc32()) {
144         state.getShaderProc32()(&state, x, y, dstC, count);
145         return;
146     }
147 
148     uint32_t buffer[BUF_MAX + TEST_BUFFER_EXTRA];
149     SkBitmapProcState::MatrixProc   mproc = state.getMatrixProc();
150     SkBitmapProcState::SampleProc32 sproc = state.getSampleProc32();
151     int max = state.maxCountForBufferSize(sizeof(buffer[0]) * BUF_MAX);
152 
153     SkASSERT(state.fPixmap.addr());
154 
155     for (;;) {
156         int n = count;
157         if (n > max) {
158             n = max;
159         }
160         SkASSERT(n > 0 && n < BUF_MAX*2);
161 #ifdef TEST_BUFFER_OVERRITE
162         for (int i = 0; i < TEST_BUFFER_EXTRA; i++) {
163             buffer[BUF_MAX + i] = TEST_PATTERN;
164         }
165 #endif
166         mproc(state, buffer, n, x, y);
167 #ifdef TEST_BUFFER_OVERRITE
168         for (int j = 0; j < TEST_BUFFER_EXTRA; j++) {
169             SkASSERT(buffer[BUF_MAX + j] == TEST_PATTERN);
170         }
171 #endif
172         sproc(state, buffer, n, dstC);
173 
174         if ((count -= n) == 0) {
175             break;
176         }
177         SkASSERT(count > 0);
178         x += n;
179         dstC += n;
180     }
181 }
182 
asAShadeProc(void ** ctx)183 SkShader::Context::ShadeProc SkBitmapProcShader::BitmapProcShaderContext::asAShadeProc(void** ctx) {
184     if (fState->getShaderProc32()) {
185         *ctx = fState;
186         return (ShadeProc)fState->getShaderProc32();
187     }
188     return nullptr;
189 }
190 
191 ///////////////////////////////////////////////////////////////////////////////
192 
193 #include "SkUnPreMultiply.h"
194 #include "SkColorShader.h"
195 #include "SkEmptyShader.h"
196 
197 // returns true and set color if the bitmap can be drawn as a single color
198 // (for efficiency)
can_use_color_shader(const SkBitmap & bm,SkColor * color)199 static bool can_use_color_shader(const SkBitmap& bm, SkColor* color) {
200 #ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK
201     // HWUI does not support color shaders (see b/22390304)
202     return false;
203 #endif
204 
205     if (1 != bm.width() || 1 != bm.height()) {
206         return false;
207     }
208 
209     SkAutoLockPixels alp(bm);
210     if (!bm.readyToDraw()) {
211         return false;
212     }
213 
214     switch (bm.colorType()) {
215         case kN32_SkColorType:
216             *color = SkUnPreMultiply::PMColorToColor(*bm.getAddr32(0, 0));
217             return true;
218         case kRGB_565_SkColorType:
219             *color = SkPixel16ToColor(*bm.getAddr16(0, 0));
220             return true;
221         case kIndex_8_SkColorType:
222             *color = SkUnPreMultiply::PMColorToColor(bm.getIndex8Color(0, 0));
223             return true;
224         default: // just skip the other configs for now
225             break;
226     }
227     return false;
228 }
229 
bitmap_is_too_big(const SkBitmap & bm)230 static bool bitmap_is_too_big(const SkBitmap& bm) {
231     // SkBitmapProcShader stores bitmap coordinates in a 16bit buffer, as it
232     // communicates between its matrix-proc and its sampler-proc. Until we can
233     // widen that, we have to reject bitmaps that are larger.
234     //
235     static const int kMaxSize = 65535;
236 
237     return bm.width() > kMaxSize || bm.height() > kMaxSize;
238 }
239 
SkCreateBitmapShader(const SkBitmap & src,SkShader::TileMode tmx,SkShader::TileMode tmy,const SkMatrix * localMatrix,SkTBlitterAllocator * allocator)240 SkShader* SkCreateBitmapShader(const SkBitmap& src, SkShader::TileMode tmx,
241                                SkShader::TileMode tmy, const SkMatrix* localMatrix,
242                                SkTBlitterAllocator* allocator) {
243     SkShader* shader;
244     SkColor color;
245     if (src.isNull() || bitmap_is_too_big(src)) {
246         if (nullptr == allocator) {
247             shader = new SkEmptyShader;
248         } else {
249             shader = allocator->createT<SkEmptyShader>();
250         }
251     } else if (can_use_color_shader(src, &color)) {
252         if (nullptr == allocator) {
253             shader = new SkColorShader(color);
254         } else {
255             shader = allocator->createT<SkColorShader>(color);
256         }
257     } else {
258         if (nullptr == allocator) {
259             shader = new SkBitmapProcShader(src, tmx, tmy, localMatrix);
260         } else {
261             shader = allocator->createT<SkBitmapProcShader>(src, tmx, tmy, localMatrix);
262         }
263     }
264     return shader;
265 }
266 
267 ///////////////////////////////////////////////////////////////////////////////
268 
269 #ifndef SK_IGNORE_TO_STRING
toString(SkString * str) const270 void SkBitmapProcShader::toString(SkString* str) const {
271     static const char* gTileModeName[SkShader::kTileModeCount] = {
272         "clamp", "repeat", "mirror"
273     };
274 
275     str->append("BitmapShader: (");
276 
277     str->appendf("(%s, %s)",
278                  gTileModeName[fTileModeX],
279                  gTileModeName[fTileModeY]);
280 
281     str->append(" ");
282     fRawBitmap.toString(str);
283 
284     this->INHERITED::toString(str);
285 
286     str->append(")");
287 }
288 #endif
289 
290 ///////////////////////////////////////////////////////////////////////////////
291 
292 #if SK_SUPPORT_GPU
293 
294 #include "GrTextureAccess.h"
295 #include "SkGr.h"
296 #include "effects/GrSimpleTextureEffect.h"
297 
asFragmentProcessor(GrContext * context,const SkMatrix & viewM,const SkMatrix * localMatrix,SkFilterQuality filterQuality) const298 const GrFragmentProcessor* SkBitmapProcShader::asFragmentProcessor(GrContext* context,
299                                              const SkMatrix& viewM, const SkMatrix* localMatrix,
300                                              SkFilterQuality filterQuality) const {
301     SkMatrix matrix;
302     matrix.setIDiv(fRawBitmap.width(), fRawBitmap.height());
303 
304     SkMatrix lmInverse;
305     if (!this->getLocalMatrix().invert(&lmInverse)) {
306         return nullptr;
307     }
308     if (localMatrix) {
309         SkMatrix inv;
310         if (!localMatrix->invert(&inv)) {
311             return nullptr;
312         }
313         lmInverse.postConcat(inv);
314     }
315     matrix.preConcat(lmInverse);
316 
317     SkShader::TileMode tm[] = {
318         (TileMode)fTileModeX,
319         (TileMode)fTileModeY,
320     };
321 
322     // Must set wrap and filter on the sampler before requesting a texture. In two places below
323     // we check the matrix scale factors to determine how to interpret the filter quality setting.
324     // This completely ignores the complexity of the drawVertices case where explicit local coords
325     // are provided by the caller.
326     bool doBicubic;
327     GrTextureParams::FilterMode textureFilterMode =
328             GrSkFilterQualityToGrFilterMode(filterQuality, viewM, this->getLocalMatrix(),
329                                             &doBicubic);
330     GrTextureParams params(tm, textureFilterMode);
331     SkAutoTUnref<GrTexture> texture(GrRefCachedBitmapTexture(context, fRawBitmap, params));
332 
333     if (!texture) {
334         SkErrorInternals::SetError( kInternalError_SkError,
335                                     "Couldn't convert bitmap to texture.");
336         return nullptr;
337     }
338 
339     SkAutoTUnref<const GrFragmentProcessor> inner;
340     if (doBicubic) {
341         inner.reset(GrBicubicEffect::Create(texture, matrix, tm));
342     } else {
343         inner.reset(GrSimpleTextureEffect::Create(texture, matrix, params));
344     }
345 
346     if (kAlpha_8_SkColorType == fRawBitmap.colorType()) {
347         return GrFragmentProcessor::MulOutputByInputUnpremulColor(inner);
348     }
349     return GrFragmentProcessor::MulOutputByInputAlpha(inner);
350 }
351 
352 #endif
353