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