• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "include/core/SkImageEncoder.h"
9 #include "include/core/SkPaint.h"
10 #include "include/core/SkShader.h"
11 #include "include/private/SkColorData.h"
12 #include "include/private/base/SkMacros.h"
13 #include "include/private/base/SkTPin.h"
14 #include "src/core/SkBitmapCache.h"
15 #include "src/core/SkBitmapProcState.h"
16 #include "src/core/SkMipmap.h"
17 #include "src/core/SkMipmapAccessor.h"
18 #include "src/core/SkOpts.h"
19 #include "src/core/SkResourceCache.h"
20 
21 // One-stop-shop shader for,
22 //   - nearest-neighbor sampling (_nofilter_),
23 //   - clamp tiling in X and Y both (Clamp_),
24 //   - with at most a scale and translate matrix (_DX_),
25 //   - and no extra alpha applied (_opaque_),
26 //   - sampling from 8888 (_S32_) and drawing to 8888 (_S32_).
Clamp_S32_opaque_D32_nofilter_DX_shaderproc(const void * sIn,int x,int y,SkPMColor * dst,int count)27 static void Clamp_S32_opaque_D32_nofilter_DX_shaderproc(const void* sIn, int x, int y,
28                                                         SkPMColor* dst, int count) {
29     const SkBitmapProcState& s = *static_cast<const SkBitmapProcState*>(sIn);
30     SkASSERT(s.fInvMatrix.isScaleTranslate());
31     SkASSERT(s.fAlphaScale == 256);
32 
33     const unsigned maxX = s.fPixmap.width() - 1;
34     SkFractionalInt fx;
35     int dstY;
36     {
37         const SkBitmapProcStateAutoMapper mapper(s, x, y);
38         const unsigned maxY = s.fPixmap.height() - 1;
39         dstY = SkTPin<int>(mapper.intY(), 0, maxY);
40         fx = mapper.fractionalIntX();
41     }
42 
43     const SkPMColor* src = s.fPixmap.addr32(0, dstY);
44     const SkFractionalInt dx = s.fInvSxFractionalInt;
45 
46     // Check if we're safely inside [0...maxX] so no need to clamp each computed index.
47     //
48     if ((uint64_t)SkFractionalIntToInt(fx) <= maxX &&
49         (uint64_t)SkFractionalIntToInt(fx + dx * (count - 1)) <= maxX)
50     {
51         int count4 = count >> 2;
52         for (int i = 0; i < count4; ++i) {
53             SkPMColor src0 = src[SkFractionalIntToInt(fx)]; fx += dx;
54             SkPMColor src1 = src[SkFractionalIntToInt(fx)]; fx += dx;
55             SkPMColor src2 = src[SkFractionalIntToInt(fx)]; fx += dx;
56             SkPMColor src3 = src[SkFractionalIntToInt(fx)]; fx += dx;
57             dst[0] = src0;
58             dst[1] = src1;
59             dst[2] = src2;
60             dst[3] = src3;
61             dst += 4;
62         }
63         for (int i = (count4 << 2); i < count; ++i) {
64             unsigned index = SkFractionalIntToInt(fx);
65             SkASSERT(index <= maxX);
66             *dst++ = src[index];
67             fx += dx;
68         }
69     } else {
70         for (int i = 0; i < count; ++i) {
71             dst[i] = src[SkTPin<int>(SkFractionalIntToInt(fx), 0, maxX)];
72             fx += dx;
73         }
74     }
75 }
76 
S32_alpha_D32_nofilter_DX(const SkBitmapProcState & s,const uint32_t * xy,int count,SkPMColor * colors)77 static void S32_alpha_D32_nofilter_DX(const SkBitmapProcState& s,
78                                       const uint32_t* xy, int count, SkPMColor* colors) {
79     SkASSERT(count > 0 && colors != nullptr);
80     SkASSERT(s.fInvMatrix.isScaleTranslate());
81     SkASSERT(!s.fBilerp);
82     SkASSERT(4 == s.fPixmap.info().bytesPerPixel());
83     SkASSERT(s.fAlphaScale <= 256);
84 
85     // xy is a 32-bit y-coordinate, followed by 16-bit x-coordinates.
86     unsigned y = *xy++;
87     SkASSERT(y < (unsigned)s.fPixmap.height());
88 
89     auto row = (const SkPMColor*)( (const char*)s.fPixmap.addr() + y * s.fPixmap.rowBytes() );
90 
91     if (1 == s.fPixmap.width()) {
92         SkOpts::memset32(colors, SkAlphaMulQ(row[0], s.fAlphaScale), count);
93         return;
94     }
95 
96     // Step 4 xs == 2 uint32_t at a time.
97     while (count >= 4) {
98         uint32_t x01 = *xy++,
99                  x23 = *xy++;
100 
101         SkPMColor p0 = row[UNPACK_PRIMARY_SHORT  (x01)];
102         SkPMColor p1 = row[UNPACK_SECONDARY_SHORT(x01)];
103         SkPMColor p2 = row[UNPACK_PRIMARY_SHORT  (x23)];
104         SkPMColor p3 = row[UNPACK_SECONDARY_SHORT(x23)];
105 
106         *colors++ = SkAlphaMulQ(p0, s.fAlphaScale);
107         *colors++ = SkAlphaMulQ(p1, s.fAlphaScale);
108         *colors++ = SkAlphaMulQ(p2, s.fAlphaScale);
109         *colors++ = SkAlphaMulQ(p3, s.fAlphaScale);
110 
111         count -= 4;
112     }
113 
114     // Step 1 x == 1 uint16_t at a time.
115     auto x = (const uint16_t*)xy;
116     while (count --> 0) {
117         *colors++ = SkAlphaMulQ(row[*x++], s.fAlphaScale);
118     }
119 }
120 
S32_alpha_D32_nofilter_DXDY(const SkBitmapProcState & s,const uint32_t * xy,int count,SkPMColor * colors)121 static void S32_alpha_D32_nofilter_DXDY(const SkBitmapProcState& s,
122                                         const uint32_t* xy, int count, SkPMColor* colors) {
123     SkASSERT(count > 0 && colors != nullptr);
124     SkASSERT(!s.fBilerp);
125     SkASSERT(4 == s.fPixmap.info().bytesPerPixel());
126     SkASSERT(s.fAlphaScale <= 256);
127 
128     auto src = (const char*)s.fPixmap.addr();
129     size_t rb = s.fPixmap.rowBytes();
130 
131     while (count --> 0) {
132         uint32_t XY = *xy++,
133                  x  = XY & 0xffff,
134                  y  = XY >> 16;
135         SkASSERT(x < (unsigned)s.fPixmap.width ());
136         SkASSERT(y < (unsigned)s.fPixmap.height());
137         *colors++ = ((const SkPMColor*)(src + y*rb))[x];
138     }
139 }
140 
SkBitmapProcState(const SkImage_Base * image,SkTileMode tmx,SkTileMode tmy)141 SkBitmapProcState::SkBitmapProcState(const SkImage_Base* image, SkTileMode tmx, SkTileMode tmy)
142     : fImage(image)
143     , fTileModeX(tmx)
144     , fTileModeY(tmy)
145 {}
146 
147 // true iff the matrix has a scale and no more than an optional translate.
matrix_only_scale_translate(const SkMatrix & m)148 static bool matrix_only_scale_translate(const SkMatrix& m) {
149     return (m.getType() & ~SkMatrix::kTranslate_Mask) == SkMatrix::kScale_Mask;
150 }
151 
152 /**
153  *  For the purposes of drawing bitmaps, if a matrix is "almost" translate
154  *  go ahead and treat it as if it were, so that subsequent code can go fast.
155  */
just_trans_general(const SkMatrix & matrix)156 static bool just_trans_general(const SkMatrix& matrix) {
157     SkASSERT(matrix_only_scale_translate(matrix));
158 
159     const SkScalar tol = SK_Scalar1 / 32768;
160 
161     return SkScalarNearlyZero(matrix[SkMatrix::kMScaleX] - SK_Scalar1, tol)
162         && SkScalarNearlyZero(matrix[SkMatrix::kMScaleY] - SK_Scalar1, tol);
163 }
164 
165 /**
166  *  Determine if the matrix can be treated as integral-only-translate,
167  *  for the purpose of filtering.
168  */
just_trans_integral(const SkMatrix & m)169 static bool just_trans_integral(const SkMatrix& m) {
170     static constexpr SkScalar tol = SK_Scalar1 / 256;
171 
172     return m.getType() <= SkMatrix::kTranslate_Mask
173         && SkScalarNearlyEqual(m.getTranslateX(), SkScalarRoundToScalar(m.getTranslateX()), tol)
174         && SkScalarNearlyEqual(m.getTranslateY(), SkScalarRoundToScalar(m.getTranslateY()), tol);
175 }
176 
valid_for_filtering(unsigned dimension)177 static bool valid_for_filtering(unsigned dimension) {
178     // for filtering, width and height must fit in 14bits, since we use steal
179     // 2 bits from each to store our 4bit subpixel data
180     return (dimension & ~0x3FFF) == 0;
181 }
182 
init(const SkMatrix & inv,SkAlpha paintAlpha,const SkSamplingOptions & sampling)183 bool SkBitmapProcState::init(const SkMatrix& inv, SkAlpha paintAlpha,
184                              const SkSamplingOptions& sampling) {
185     SkASSERT(!inv.hasPerspective());
186     SkASSERT(SkOpts::S32_alpha_D32_filter_DXDY || inv.isScaleTranslate());
187     SkASSERT(!sampling.isAniso());
188     SkASSERT(!sampling.useCubic);
189     SkASSERT(sampling.mipmap != SkMipmapMode::kLinear);
190 
191     fPixmap.reset();
192     fBilerp = false;
193 
194     auto* access = SkMipmapAccessor::Make(&fAlloc, (const SkImage*)fImage, inv, sampling.mipmap);
195     if (!access) {
196         return false;
197     }
198     std::tie(fPixmap, fInvMatrix) = access->level();
199     fInvMatrix.preConcat(inv);
200 
201     fPaintAlpha = paintAlpha;
202     fBilerp = sampling.filter == SkFilterMode::kLinear;
203     SkASSERT(fPixmap.addr());
204 
205     bool integral_translate_only = just_trans_integral(fInvMatrix);
206     if (!integral_translate_only) {
207         // Most of the scanline procs deal with "unit" texture coordinates, as this
208         // makes it easy to perform tiling modes (repeat = (x & 0xFFFF)). To generate
209         // those, we divide the matrix by its dimensions here.
210         //
211         // We don't do this if we're either trivial (can ignore the matrix) or clamping
212         // in both X and Y since clamping to width,height is just as easy as to 0xFFFF.
213 
214         if (fTileModeX != SkTileMode::kClamp || fTileModeY != SkTileMode::kClamp) {
215             SkMatrixPriv::PostIDiv(&fInvMatrix, fPixmap.width(), fPixmap.height());
216         }
217 
218         // Now that all possible changes to the matrix have taken place, check
219         // to see if we're really close to a no-scale matrix.  If so, explicitly
220         // set it to be so.  Subsequent code may inspect this matrix to choose
221         // a faster path in this case.
222 
223         // This code will only execute if the matrix has some scale component;
224         // if it's already pure translate then we won't do this inversion.
225 
226         if (matrix_only_scale_translate(fInvMatrix)) {
227             SkMatrix forward;
228             if (fInvMatrix.invert(&forward) && just_trans_general(forward)) {
229                 fInvMatrix.setTranslate(-forward.getTranslateX(), -forward.getTranslateY());
230             }
231         }
232 
233         // Recompute the flag after matrix adjustments.
234         integral_translate_only = just_trans_integral(fInvMatrix);
235     }
236 
237     if (fBilerp &&
238         (!valid_for_filtering(fPixmap.width() | fPixmap.height()) || integral_translate_only)) {
239         fBilerp = false;
240     }
241 
242     return true;
243 }
244 
245 /*
246  *  Analyze filter-quality and matrix, and decide how to implement that.
247  *
248  *  In general, we cascade down the request level [ High ... None ]
249  *  - for a given level, if we can fulfill it, fine, else
250  *    - else we downgrade to the next lower level and try again.
251  *  We can always fulfill requests for Low and None
252  *  - sometimes we will "ignore" Low and give None, but this is likely a legacy perf hack
253  *    and may be removed.
254  */
chooseProcs()255 bool SkBitmapProcState::chooseProcs() {
256     SkASSERT(!fInvMatrix.hasPerspective());
257     SkASSERT(SkOpts::S32_alpha_D32_filter_DXDY || fInvMatrix.isScaleTranslate());
258     SkASSERT(fPixmap.colorType() == kN32_SkColorType);
259     SkASSERT(fPixmap.alphaType() == kPremul_SkAlphaType ||
260              fPixmap.alphaType() == kOpaque_SkAlphaType);
261 
262     SkASSERT(fTileModeX != SkTileMode::kDecal);
263 
264     fInvProc            = SkMatrixPriv::GetMapXYProc(fInvMatrix);
265     fInvSxFractionalInt = SkScalarToFractionalInt(fInvMatrix.getScaleX());
266     fInvKyFractionalInt = SkScalarToFractionalInt(fInvMatrix.getSkewY ());
267 
268     fAlphaScale = SkAlpha255To256(fPaintAlpha);
269 
270     bool translate_only = (fInvMatrix.getType() & ~SkMatrix::kTranslate_Mask) == 0;
271     fMatrixProc = this->chooseMatrixProc(translate_only);
272     SkASSERT(fMatrixProc);
273 
274     if (fInvMatrix.isScaleTranslate()) {
275         fSampleProc32 = fBilerp ? SkOpts::S32_alpha_D32_filter_DX   : S32_alpha_D32_nofilter_DX  ;
276     } else {
277         fSampleProc32 = fBilerp ? SkOpts::S32_alpha_D32_filter_DXDY : S32_alpha_D32_nofilter_DXDY;
278     }
279     SkASSERT(fSampleProc32);
280 
281     // our special-case shaderprocs
282     // TODO: move this one into chooseShaderProc32() or pull all that in here.
283     if (fAlphaScale == 256
284             && !fBilerp
285             && SkTileMode::kClamp == fTileModeX
286             && SkTileMode::kClamp == fTileModeY
287             && fInvMatrix.isScaleTranslate()) {
288         fShaderProc32 = Clamp_S32_opaque_D32_nofilter_DX_shaderproc;
289     } else {
290         fShaderProc32 = this->chooseShaderProc32();
291     }
292 
293     return true;
294 }
295 
Clamp_S32_D32_nofilter_trans_shaderproc(const void * sIn,int x,int y,SkPMColor * colors,int count)296 static void Clamp_S32_D32_nofilter_trans_shaderproc(const void* sIn,
297                                                     int x, int y,
298                                                     SkPMColor* colors,
299                                                     int count) {
300     const SkBitmapProcState& s = *static_cast<const SkBitmapProcState*>(sIn);
301     SkASSERT(s.fInvMatrix.isTranslate());
302     SkASSERT(count > 0 && colors != nullptr);
303     SkASSERT(!s.fBilerp);
304 
305     const int maxX = s.fPixmap.width() - 1;
306     const int maxY = s.fPixmap.height() - 1;
307     int ix = s.fFilterOneX + x;
308     int iy = SkTPin(s.fFilterOneY + y, 0, maxY);
309     const SkPMColor* row = s.fPixmap.addr32(0, iy);
310 
311     // clamp to the left
312     if (ix < 0) {
313         int n = std::min(-ix, count);
314         SkOpts::memset32(colors, row[0], n);
315         count -= n;
316         if (0 == count) {
317             return;
318         }
319         colors += n;
320         SkASSERT(-ix == n);
321         ix = 0;
322     }
323     // copy the middle
324     if (ix <= maxX) {
325         int n = std::min(maxX - ix + 1, count);
326         memcpy(colors, row + ix, n * sizeof(SkPMColor));
327         count -= n;
328         if (0 == count) {
329             return;
330         }
331         colors += n;
332     }
333     SkASSERT(count > 0);
334     // clamp to the right
335     SkOpts::memset32(colors, row[maxX], count);
336 }
337 
sk_int_mod(int x,int n)338 static inline int sk_int_mod(int x, int n) {
339     SkASSERT(n > 0);
340     if ((unsigned)x >= (unsigned)n) {
341         if (x < 0) {
342             x = n + ~(~x % n);
343         } else {
344             x = x % n;
345         }
346     }
347     return x;
348 }
349 
sk_int_mirror(int x,int n)350 static inline int sk_int_mirror(int x, int n) {
351     x = sk_int_mod(x, 2 * n);
352     if (x >= n) {
353         x = n + ~(x - n);
354     }
355     return x;
356 }
357 
Repeat_S32_D32_nofilter_trans_shaderproc(const void * sIn,int x,int y,SkPMColor * colors,int count)358 static void Repeat_S32_D32_nofilter_trans_shaderproc(const void* sIn,
359                                                      int x, int y,
360                                                      SkPMColor* colors,
361                                                      int count) {
362     const SkBitmapProcState& s = *static_cast<const SkBitmapProcState*>(sIn);
363     SkASSERT(s.fInvMatrix.isTranslate());
364     SkASSERT(count > 0 && colors != nullptr);
365     SkASSERT(!s.fBilerp);
366 
367     const int stopX = s.fPixmap.width();
368     const int stopY = s.fPixmap.height();
369     int ix = s.fFilterOneX + x;
370     int iy = sk_int_mod(s.fFilterOneY + y, stopY);
371     const SkPMColor* row = s.fPixmap.addr32(0, iy);
372 
373     ix = sk_int_mod(ix, stopX);
374     for (;;) {
375         int n = std::min(stopX - ix, count);
376         memcpy(colors, row + ix, n * sizeof(SkPMColor));
377         count -= n;
378         if (0 == count) {
379             return;
380         }
381         colors += n;
382         ix = 0;
383     }
384 }
385 
filter_32_alpha(unsigned t,SkPMColor color0,SkPMColor color1,SkPMColor * dstColor,unsigned alphaScale)386 static inline void filter_32_alpha(unsigned t,
387                                    SkPMColor color0,
388                                    SkPMColor color1,
389                                    SkPMColor* dstColor,
390                                    unsigned alphaScale) {
391     SkASSERT((unsigned)t <= 0xF);
392     SkASSERT(alphaScale <= 256);
393 
394     const uint32_t mask = 0xFF00FF;
395 
396     int scale = 256 - 16*t;
397     uint32_t lo = (color0 & mask) * scale;
398     uint32_t hi = ((color0 >> 8) & mask) * scale;
399 
400     scale = 16*t;
401     lo += (color1 & mask) * scale;
402     hi += ((color1 >> 8) & mask) * scale;
403 
404     // TODO: if (alphaScale < 256) ...
405     lo = ((lo >> 8) & mask) * alphaScale;
406     hi = ((hi >> 8) & mask) * alphaScale;
407 
408     *dstColor = ((lo >> 8) & mask) | (hi & ~mask);
409 }
410 
S32_D32_constX_shaderproc(const void * sIn,int x,int y,SkPMColor * colors,int count)411 static void S32_D32_constX_shaderproc(const void* sIn,
412                                       int x, int y,
413                                       SkPMColor* colors,
414                                       int count) {
415     const SkBitmapProcState& s = *static_cast<const SkBitmapProcState*>(sIn);
416     SkASSERT(s.fInvMatrix.isScaleTranslate());
417     SkASSERT(count > 0 && colors != nullptr);
418     SkASSERT(1 == s.fPixmap.width());
419 
420     int iY0;
421     int iY1   SK_INIT_TO_AVOID_WARNING;
422     int iSubY SK_INIT_TO_AVOID_WARNING;
423 
424     if (s.fBilerp) {
425         SkBitmapProcState::MatrixProc mproc = s.getMatrixProc();
426         uint32_t xy[2];
427 
428         mproc(s, xy, 1, x, y);
429 
430         iY0 = xy[0] >> 18;
431         iY1 = xy[0] & 0x3FFF;
432         iSubY = (xy[0] >> 14) & 0xF;
433     } else {
434         int yTemp;
435 
436         if (s.fInvMatrix.isTranslate()) {
437             yTemp = s.fFilterOneY + y;
438         } else{
439             const SkBitmapProcStateAutoMapper mapper(s, x, y);
440 
441             // When the matrix has a scale component the setup code in
442             // chooseProcs multiples the inverse matrix by the inverse of the
443             // bitmap's width and height. Since this method is going to do
444             // its own tiling and sampling we need to undo that here.
445             if (SkTileMode::kClamp != s.fTileModeX || SkTileMode::kClamp != s.fTileModeY) {
446                 yTemp = SkFractionalIntToInt(mapper.fractionalIntY() * s.fPixmap.height());
447             } else {
448                 yTemp = mapper.intY();
449             }
450         }
451 
452         const int stopY = s.fPixmap.height();
453         switch (s.fTileModeY) {
454             case SkTileMode::kClamp:
455                 iY0 = SkTPin(yTemp, 0, stopY-1);
456                 break;
457             case SkTileMode::kRepeat:
458                 iY0 = sk_int_mod(yTemp, stopY);
459                 break;
460             case SkTileMode::kMirror:
461             default:
462                 iY0 = sk_int_mirror(yTemp, stopY);
463                 break;
464         }
465 
466 #ifdef SK_DEBUG
467         {
468             const SkBitmapProcStateAutoMapper mapper(s, x, y);
469             int iY2;
470 
471             if (!s.fInvMatrix.isTranslate() &&
472                 (SkTileMode::kClamp != s.fTileModeX || SkTileMode::kClamp != s.fTileModeY)) {
473                 iY2 = SkFractionalIntToInt(mapper.fractionalIntY() * s.fPixmap.height());
474             } else {
475                 iY2 = mapper.intY();
476             }
477 
478             switch (s.fTileModeY) {
479             case SkTileMode::kClamp:
480                 iY2 = SkTPin(iY2, 0, stopY-1);
481                 break;
482             case SkTileMode::kRepeat:
483                 iY2 = sk_int_mod(iY2, stopY);
484                 break;
485             case SkTileMode::kMirror:
486             default:
487                 iY2 = sk_int_mirror(iY2, stopY);
488                 break;
489             }
490 
491             SkASSERT(iY0 == iY2);
492         }
493 #endif
494     }
495 
496     const SkPMColor* row0 = s.fPixmap.addr32(0, iY0);
497     SkPMColor color;
498 
499     if (s.fBilerp) {
500         const SkPMColor* row1 = s.fPixmap.addr32(0, iY1);
501         filter_32_alpha(iSubY, *row0, *row1, &color, s.fAlphaScale);
502     } else {
503         if (s.fAlphaScale < 256) {
504             color = SkAlphaMulQ(*row0, s.fAlphaScale);
505         } else {
506             color = *row0;
507         }
508     }
509 
510     SkOpts::memset32(colors, color, count);
511 }
512 
DoNothing_shaderproc(const void *,int x,int y,SkPMColor * colors,int count)513 static void DoNothing_shaderproc(const void*, int x, int y,
514                                  SkPMColor* colors, int count) {
515     // if we get called, the matrix is too tricky, so we just draw nothing
516     SkOpts::memset32(colors, 0, count);
517 }
518 
setupForTranslate()519 bool SkBitmapProcState::setupForTranslate() {
520     SkPoint pt;
521     const SkBitmapProcStateAutoMapper mapper(*this, 0, 0, &pt);
522 
523     /*
524      *  if the translate is larger than our ints, we can get random results, or
525      *  worse, we might get 0x80000000, which wreaks havoc on us, since we can't
526      *  negate it.
527      */
528     const SkScalar too_big = SkIntToScalar(1 << 30);
529     if (SkScalarAbs(pt.fX) > too_big || SkScalarAbs(pt.fY) > too_big) {
530         return false;
531     }
532 
533     // Since we know we're not filtered, we re-purpose these fields allow
534     // us to go from device -> src coordinates w/ just an integer add,
535     // rather than running through the inverse-matrix
536     fFilterOneX = mapper.intX();
537     fFilterOneY = mapper.intY();
538 
539     return true;
540 }
541 
chooseShaderProc32()542 SkBitmapProcState::ShaderProc32 SkBitmapProcState::chooseShaderProc32() {
543 
544     if (kN32_SkColorType != fPixmap.colorType()) {
545         return nullptr;
546     }
547 
548     if (1 == fPixmap.width() && fInvMatrix.isScaleTranslate()) {
549         if (!fBilerp && fInvMatrix.isTranslate() && !this->setupForTranslate()) {
550             return DoNothing_shaderproc;
551         }
552         return S32_D32_constX_shaderproc;
553     }
554 
555     if (fAlphaScale < 256) {
556         return nullptr;
557     }
558     if (!fInvMatrix.isTranslate()) {
559         return nullptr;
560     }
561     if (fBilerp) {
562         return nullptr;
563     }
564 
565     SkTileMode tx = fTileModeX;
566     SkTileMode ty = fTileModeY;
567 
568     if (SkTileMode::kClamp == tx && SkTileMode::kClamp == ty) {
569         if (this->setupForTranslate()) {
570             return Clamp_S32_D32_nofilter_trans_shaderproc;
571         }
572         return DoNothing_shaderproc;
573     }
574     if (SkTileMode::kRepeat == tx && SkTileMode::kRepeat == ty) {
575         if (this->setupForTranslate()) {
576             return Repeat_S32_D32_nofilter_trans_shaderproc;
577         }
578         return DoNothing_shaderproc;
579     }
580     return nullptr;
581 }
582 
583 #ifdef SK_DEBUG
584 
check_scale_nofilter(uint32_t bitmapXY[],int count,unsigned mx,unsigned my)585 static void check_scale_nofilter(uint32_t bitmapXY[], int count,
586                                  unsigned mx, unsigned my) {
587     unsigned y = *bitmapXY++;
588     SkASSERT(y < my);
589 
590     const uint16_t* xptr = reinterpret_cast<const uint16_t*>(bitmapXY);
591     for (int i = 0; i < count; ++i) {
592         SkASSERT(xptr[i] < mx);
593     }
594 }
595 
check_scale_filter(uint32_t bitmapXY[],int count,unsigned mx,unsigned my)596 static void check_scale_filter(uint32_t bitmapXY[], int count,
597                                  unsigned mx, unsigned my) {
598     uint32_t YY = *bitmapXY++;
599     unsigned y0 = YY >> 18;
600     unsigned y1 = YY & 0x3FFF;
601     SkASSERT(y0 < my);
602     SkASSERT(y1 < my);
603 
604     for (int i = 0; i < count; ++i) {
605         uint32_t XX = bitmapXY[i];
606         unsigned x0 = XX >> 18;
607         unsigned x1 = XX & 0x3FFF;
608         SkASSERT(x0 < mx);
609         SkASSERT(x1 < mx);
610     }
611 }
612 
check_affine_nofilter(uint32_t bitmapXY[],int count,unsigned mx,unsigned my)613 static void check_affine_nofilter(uint32_t bitmapXY[], int count, unsigned mx, unsigned my) {
614     for (int i = 0; i < count; ++i) {
615         uint32_t XY = bitmapXY[i];
616         unsigned x = XY & 0xFFFF;
617         unsigned y = XY >> 16;
618         SkASSERT(x < mx);
619         SkASSERT(y < my);
620     }
621 }
622 
check_affine_filter(uint32_t bitmapXY[],int count,unsigned mx,unsigned my)623 static void check_affine_filter(uint32_t bitmapXY[], int count, unsigned mx, unsigned my) {
624     for (int i = 0; i < count; ++i) {
625         uint32_t YY = *bitmapXY++;
626         unsigned y0 = YY >> 18;
627         unsigned y1 = YY & 0x3FFF;
628         SkASSERT(y0 < my);
629         SkASSERT(y1 < my);
630 
631         uint32_t XX = *bitmapXY++;
632         unsigned x0 = XX >> 18;
633         unsigned x1 = XX & 0x3FFF;
634         SkASSERT(x0 < mx);
635         SkASSERT(x1 < mx);
636     }
637 }
638 
DebugMatrixProc(const SkBitmapProcState & state,uint32_t bitmapXY[],int count,int x,int y)639 void SkBitmapProcState::DebugMatrixProc(const SkBitmapProcState& state,
640                                         uint32_t bitmapXY[], int count,
641                                         int x, int y) {
642     SkASSERT(bitmapXY);
643     SkASSERT(count > 0);
644 
645     state.fMatrixProc(state, bitmapXY, count, x, y);
646 
647     void (*proc)(uint32_t bitmapXY[], int count, unsigned mx, unsigned my);
648 
649     if (state.fInvMatrix.isScaleTranslate()) {
650         proc = state.fBilerp ? check_scale_filter : check_scale_nofilter;
651     } else {
652         proc = state.fBilerp ? check_affine_filter : check_affine_nofilter;
653     }
654 
655     proc(bitmapXY, count, state.fPixmap.width(), state.fPixmap.height());
656 }
657 
getMatrixProc() const658 SkBitmapProcState::MatrixProc SkBitmapProcState::getMatrixProc() const {
659     return DebugMatrixProc;
660 }
661 
662 #endif
663 
664 /*
665     The storage requirements for the different matrix procs are as follows,
666     where each X or Y is 2 bytes, and N is the number of pixels/elements:
667 
668     scale/translate     nofilter      Y(4bytes) + N * X
669     affine/perspective  nofilter      N * (X Y)
670     scale/translate     filter        Y Y + N * (X X)
671     affine              filter        N * (Y Y X X)
672  */
maxCountForBufferSize(size_t bufferSize) const673 int SkBitmapProcState::maxCountForBufferSize(size_t bufferSize) const {
674     int32_t size = static_cast<int32_t>(bufferSize);
675 
676     size &= ~3; // only care about 4-byte aligned chunks
677     if (fInvMatrix.isScaleTranslate()) {
678         size -= 4;   // the shared Y (or YY) coordinate
679         if (size < 0) {
680             size = 0;
681         }
682         size >>= 1;
683     } else {
684         size >>= 2;
685     }
686 
687     if (fBilerp) {
688         size >>= 1;
689     }
690 
691     return size;
692 }
693 
694