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 "SkBitmapProcState.h"
10 #include "SkColorPriv.h"
11 #include "SkFilterProc.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 !SK_ARM_NEON_IS_NONE
22 // These are defined in src/opts/SkBitmapProcState_arm_neon.cpp
23 extern const SkBitmapProcState::SampleProc16 gSkBitmapProcStateSample16_neon[];
24 extern const SkBitmapProcState::SampleProc32 gSkBitmapProcStateSample32_neon[];
25 extern void  S16_D16_filter_DX_neon(const SkBitmapProcState&, const uint32_t*, int, uint16_t*);
26 extern void  Clamp_S16_D16_filter_DX_shaderproc_neon(const SkBitmapProcState&, int, int, uint16_t*, int);
27 extern void  Repeat_S16_D16_filter_DX_shaderproc_neon(const SkBitmapProcState&, int, int, uint16_t*, int);
28 extern void  SI8_opaque_D32_filter_DX_neon(const SkBitmapProcState&, const uint32_t*, int, SkPMColor*);
29 extern void  SI8_opaque_D32_filter_DX_shaderproc_neon(const SkBitmapProcState&, int, int, uint32_t*, int);
30 extern void  Clamp_SI8_opaque_D32_filter_DX_shaderproc_neon(const SkBitmapProcState&, int, int, uint32_t*, int);
31 #endif
32 
33 extern void Clamp_S32_opaque_D32_nofilter_DX_shaderproc(const SkBitmapProcState&, int, int, uint32_t*, int);
34 
35 #define   NAME_WRAP(x)  x
36 #include "SkBitmapProcState_filter.h"
37 #include "SkBitmapProcState_procs.h"
38 
39 ///////////////////////////////////////////////////////////////////////////////
40 
41 // true iff the matrix contains, at most, scale and translate elements
matrix_only_scale_translate(const SkMatrix & m)42 static bool matrix_only_scale_translate(const SkMatrix& m) {
43     return m.getType() <= (SkMatrix::kScale_Mask | SkMatrix::kTranslate_Mask);
44 }
45 
46 /**
47  *  For the purposes of drawing bitmaps, if a matrix is "almost" translate
48  *  go ahead and treat it as if it were, so that subsequent code can go fast.
49  */
just_trans_clamp(const SkMatrix & matrix,const SkBitmap & bitmap)50 static bool just_trans_clamp(const SkMatrix& matrix, const SkBitmap& bitmap) {
51     SkASSERT(matrix_only_scale_translate(matrix));
52 
53     if (matrix.getType() & SkMatrix::kScale_Mask) {
54         SkRect src, dst;
55         bitmap.getBounds(&src);
56 
57         // Can't call mapRect(), since that will fix up inverted rectangles,
58         // e.g. when scale is negative, and we don't want to return true for
59         // those.
60         matrix.mapPoints(SkTCast<SkPoint*>(&dst),
61                          SkTCast<const SkPoint*>(&src),
62                          2);
63 
64         // Now round all 4 edges to device space, and then compare the device
65         // width/height to the original. Note: we must map all 4 and subtract
66         // rather than map the "width" and compare, since we care about the
67         // phase (in pixel space) that any translate in the matrix might impart.
68         SkIRect idst;
69         dst.round(&idst);
70         return idst.width() == bitmap.width() && idst.height() == bitmap.height();
71     }
72     // if we got here, we're either kTranslate_Mask or identity
73     return true;
74 }
75 
just_trans_general(const SkMatrix & matrix)76 static bool just_trans_general(const SkMatrix& matrix) {
77     SkASSERT(matrix_only_scale_translate(matrix));
78 
79     if (matrix.getType() & SkMatrix::kScale_Mask) {
80         const SkScalar tol = SK_Scalar1 / 32768;
81 
82         if (!SkScalarNearlyZero(matrix[SkMatrix::kMScaleX] - SK_Scalar1, tol)) {
83             return false;
84         }
85         if (!SkScalarNearlyZero(matrix[SkMatrix::kMScaleY] - SK_Scalar1, tol)) {
86             return false;
87         }
88     }
89     // if we got here, treat us as either kTranslate_Mask or identity
90     return true;
91 }
92 
93 ///////////////////////////////////////////////////////////////////////////////
94 
valid_for_filtering(unsigned dimension)95 static bool valid_for_filtering(unsigned dimension) {
96     // for filtering, width and height must fit in 14bits, since we use steal
97     // 2 bits from each to store our 4bit subpixel data
98     return (dimension & ~0x3FFF) == 0;
99 }
100 
101 // Check to see that the size of the bitmap that would be produced by
102 // scaling by the given inverted matrix is less than the maximum allowed.
cache_size_okay(const SkBitmap & bm,const SkMatrix & invMat)103 static inline bool cache_size_okay(const SkBitmap& bm, const SkMatrix& invMat) {
104     size_t maximumAllocation = SkResourceCache::GetEffectiveSingleAllocationByteLimit();
105     if (0 == maximumAllocation) {
106         return true;
107     }
108     // float matrixScaleFactor = 1.0 / (invMat.scaleX * invMat.scaleY);
109     // return ((origBitmapSize * matrixScaleFactor) < maximumAllocationSize);
110     // Skip the division step:
111     return bm.info().getSafeSize(bm.info().minRowBytes())
112         < (maximumAllocation * invMat.getScaleX() * invMat.getScaleY());
113 }
114 
115 /*
116  *  High quality is implemented by performing up-right scale-only filtering and then
117  *  using bilerp for any remaining transformations.
118  */
processHQRequest()119 void SkBitmapProcState::processHQRequest() {
120     SkASSERT(kHigh_SkFilterQuality == fFilterLevel);
121 
122     // Our default return state is to downgrade the request to Medium, w/ or w/o setting fBitmap
123     // to a valid bitmap. If we succeed, we will set this to Low instead.
124     fFilterLevel = kMedium_SkFilterQuality;
125 
126     if (kN32_SkColorType != fOrigBitmap.colorType() || !cache_size_okay(fOrigBitmap, fInvMatrix) ||
127         fInvMatrix.hasPerspective())
128     {
129         return; // can't handle the reqeust
130     }
131 
132     SkScalar invScaleX = fInvMatrix.getScaleX();
133     SkScalar invScaleY = fInvMatrix.getScaleY();
134     if (fInvMatrix.getType() & SkMatrix::kAffine_Mask) {
135         SkSize scale;
136         if (!fInvMatrix.decomposeScale(&scale)) {
137             return;
138         }
139         invScaleX = scale.width();
140         invScaleY = scale.height();
141     }
142     if (SkScalarNearlyEqual(invScaleX, 1) && SkScalarNearlyEqual(invScaleY, 1)) {
143         return; // no need for HQ
144     }
145 
146     SkScalar trueDestWidth  = fOrigBitmap.width() / invScaleX;
147     SkScalar trueDestHeight = fOrigBitmap.height() / invScaleY;
148     SkScalar roundedDestWidth = SkScalarRoundToScalar(trueDestWidth);
149     SkScalar roundedDestHeight = SkScalarRoundToScalar(trueDestHeight);
150 
151     if (!SkBitmapCache::Find(fOrigBitmap, roundedDestWidth, roundedDestHeight, &fScaledBitmap)) {
152         if (!SkBitmapScaler::Resize(&fScaledBitmap,
153                                     fOrigBitmap,
154                                     SkBitmapScaler::RESIZE_BEST,
155                                     roundedDestWidth,
156                                     roundedDestHeight,
157                                     SkResourceCache::GetAllocator())) {
158             return; // we failed to create fScaledBitmap
159         }
160 
161         SkASSERT(fScaledBitmap.getPixels());
162         fScaledBitmap.setImmutable();
163         SkBitmapCache::Add(fOrigBitmap, roundedDestWidth, roundedDestHeight, fScaledBitmap);
164     }
165 
166     SkASSERT(fScaledBitmap.getPixels());
167     fBitmap = &fScaledBitmap;
168 
169     fInvMatrix.postScale(roundedDestWidth / fOrigBitmap.width(),
170                          roundedDestHeight / fOrigBitmap.height());
171     fFilterLevel = kLow_SkFilterQuality;
172 }
173 
174 /*
175  *  Modulo internal errors, this should always succeed *if* the matrix is downscaling
176  *  (in this case, we have the inverse, so it succeeds if fInvMatrix is upscaling)
177  */
processMediumRequest()178 void SkBitmapProcState::processMediumRequest() {
179     SkASSERT(kMedium_SkFilterQuality == fFilterLevel);
180 
181     // Our default return state is to downgrade the request to Low, w/ or w/o setting fBitmap
182     // to a valid bitmap.
183     fFilterLevel = kLow_SkFilterQuality;
184 
185     SkSize invScaleSize;
186     if (!fInvMatrix.decomposeScale(&invScaleSize, NULL)) {
187         return;
188     }
189     SkScalar invScale = SkScalarSqrt(invScaleSize.width() * invScaleSize.height());
190 
191     if (invScale > SK_Scalar1) {
192         fCurrMip.reset(SkMipMapCache::FindAndRef(fOrigBitmap));
193         if (NULL == fCurrMip.get()) {
194             fCurrMip.reset(SkMipMapCache::AddAndRef(fOrigBitmap));
195             if (NULL == fCurrMip.get()) {
196                 return;
197             }
198         }
199         // diagnostic for a crasher...
200         if (NULL == fCurrMip->data()) {
201             sk_throw();
202         }
203 
204         SkScalar levelScale = SkScalarInvert(invScale);
205         SkMipMap::Level level;
206         if (fCurrMip->extractLevel(levelScale, &level)) {
207             SkScalar invScaleFixup = level.fScale;
208             fInvMatrix.postScale(invScaleFixup, invScaleFixup);
209 
210             const SkImageInfo info = fOrigBitmap.info().makeWH(level.fWidth, level.fHeight);
211             // todo: if we could wrap the fCurrMip in a pixelref, then we could just install
212             //       that here, and not need to explicitly track it ourselves.
213             fScaledBitmap.installPixels(info, level.fPixels, level.fRowBytes);
214             fBitmap = &fScaledBitmap;
215         } else {
216             // failed to extract, so release the mipmap
217             fCurrMip.reset(NULL);
218         }
219     }
220 }
221 
lockBaseBitmap()222 bool SkBitmapProcState::lockBaseBitmap() {
223     // TODO(reed): use bitmap cache here?
224     fScaledBitmap = fOrigBitmap;
225     fScaledBitmap.lockPixels();
226     if (NULL == fScaledBitmap.getPixels()) {
227         return false;
228     }
229     fBitmap = &fScaledBitmap;
230     return true;
231 }
232 
valid_for_drawing(const SkBitmap & bm)233 static bool valid_for_drawing(const SkBitmap& bm) {
234     if (0 == bm.width() || 0 == bm.height()) {
235         return false;   // nothing to draw
236     }
237     if (NULL == bm.pixelRef()) {
238         return false;   // no pixels to read
239     }
240     if (bm.getTexture()) {
241         // we can handle texture (ugh) since lockPixels will perform a read-back
242         return true;
243     }
244     if (kIndex_8_SkColorType == bm.colorType()) {
245         SkAutoLockPixels alp(bm); // but we need to call it before getColorTable() is safe.
246         if (!bm.getColorTable()) {
247             return false;
248         }
249     }
250     return true;
251 }
252 
253 /*
254  *  Analyze filter-quality and matrix, and decide how to implement that.
255  *
256  *  In general, we cascade down the request level [ High ... None ]
257  *  - for a given level, if we can fulfill it, fine, else
258  *    - else we downgrade to the next lower level and try again.
259  *  We can always fulfill requests for Low and None
260  *  - sometimes we will "ignore" Low and give None, but this is likely a legacy perf hack
261  *    and may be removed.
262  */
chooseProcs(const SkMatrix & inv,const SkPaint & paint)263 bool SkBitmapProcState::chooseProcs(const SkMatrix& inv, const SkPaint& paint) {
264     if (!valid_for_drawing(fOrigBitmap)) {
265         return false;
266     }
267 
268     fBitmap = NULL;
269     fInvMatrix = inv;
270     fFilterLevel = paint.getFilterQuality();
271 
272     if (kHigh_SkFilterQuality == fFilterLevel) {
273         this->processHQRequest();
274     }
275     SkASSERT(fFilterLevel < kHigh_SkFilterQuality);
276 
277     if (kMedium_SkFilterQuality == fFilterLevel) {
278         this->processMediumRequest();
279     }
280     SkASSERT(fFilterLevel < kMedium_SkFilterQuality);
281 
282     if (NULL == fBitmap) {
283         if (!this->lockBaseBitmap()) {
284             return false;
285         }
286     }
287     SkASSERT(fBitmap);
288 
289     bool trivialMatrix = (fInvMatrix.getType() & ~SkMatrix::kTranslate_Mask) == 0;
290     bool clampClamp = SkShader::kClamp_TileMode == fTileModeX &&
291                       SkShader::kClamp_TileMode == fTileModeY;
292 
293     // Most of the scanline procs deal with "unit" texture coordinates, as this
294     // makes it easy to perform tiling modes (repeat = (x & 0xFFFF)). To generate
295     // those, we divide the matrix by its dimensions here.
296     //
297     // We don't do this if we're either trivial (can ignore the matrix) or clamping
298     // in both X and Y since clamping to width,height is just as easy as to 0xFFFF.
299 
300     if (!(clampClamp || trivialMatrix)) {
301         fInvMatrix.postIDiv(fBitmap->width(), fBitmap->height());
302     }
303 
304     // Now that all possible changes to the matrix have taken place, check
305     // to see if we're really close to a no-scale matrix.  If so, explicitly
306     // set it to be so.  Subsequent code may inspect this matrix to choose
307     // a faster path in this case.
308 
309     // This code will only execute if the matrix has some scale component;
310     // if it's already pure translate then we won't do this inversion.
311 
312     if (matrix_only_scale_translate(fInvMatrix)) {
313         SkMatrix forward;
314         if (fInvMatrix.invert(&forward)) {
315             if (clampClamp ? just_trans_clamp(forward, *fBitmap)
316                            : just_trans_general(forward)) {
317                 SkScalar tx = -SkScalarRoundToScalar(forward.getTranslateX());
318                 SkScalar ty = -SkScalarRoundToScalar(forward.getTranslateY());
319                 fInvMatrix.setTranslate(tx, ty);
320             }
321         }
322     }
323 
324     fInvProc        = fInvMatrix.getMapXYProc();
325     fInvType        = fInvMatrix.getType();
326     fInvSx          = SkScalarToFixed(fInvMatrix.getScaleX());
327     fInvSxFractionalInt = SkScalarToFractionalInt(fInvMatrix.getScaleX());
328     fInvKy          = SkScalarToFixed(fInvMatrix.getSkewY());
329     fInvKyFractionalInt = SkScalarToFractionalInt(fInvMatrix.getSkewY());
330 
331     fAlphaScale = SkAlpha255To256(paint.getAlpha());
332 
333     fShaderProc32 = NULL;
334     fShaderProc16 = NULL;
335     fSampleProc32 = NULL;
336     fSampleProc16 = NULL;
337 
338     // recompute the triviality of the matrix here because we may have
339     // changed it!
340 
341     trivialMatrix = (fInvMatrix.getType() & ~SkMatrix::kTranslate_Mask) == 0;
342 
343     if (kLow_SkFilterQuality == fFilterLevel) {
344         // Only try bilerp if the matrix is "interesting" and
345         // the image has a suitable size.
346 
347         if (fInvType <= SkMatrix::kTranslate_Mask ||
348             !valid_for_filtering(fBitmap->width() | fBitmap->height()))
349         {
350             fFilterLevel = kNone_SkFilterQuality;
351         }
352     }
353 
354     return this->chooseScanlineProcs(trivialMatrix, clampClamp, paint);
355 }
356 
chooseScanlineProcs(bool trivialMatrix,bool clampClamp,const SkPaint & paint)357 bool SkBitmapProcState::chooseScanlineProcs(bool trivialMatrix, bool clampClamp,
358                                             const SkPaint& paint) {
359     fMatrixProc = this->chooseMatrixProc(trivialMatrix);
360     // TODO(dominikg): SkASSERT(fMatrixProc) instead? chooseMatrixProc never returns NULL.
361     if (NULL == fMatrixProc) {
362         return false;
363     }
364 
365     ///////////////////////////////////////////////////////////////////////
366 
367     const SkAlphaType at = fBitmap->alphaType();
368 
369     // No need to do this if we're doing HQ sampling; if filter quality is
370     // still set to HQ by the time we get here, then we must have installed
371     // the shader procs above and can skip all this.
372 
373     if (fFilterLevel < kHigh_SkFilterQuality) {
374 
375         int index = 0;
376         if (fAlphaScale < 256) {  // note: this distinction is not used for D16
377             index |= 1;
378         }
379         if (fInvType <= (SkMatrix::kTranslate_Mask | SkMatrix::kScale_Mask)) {
380             index |= 2;
381         }
382         if (fFilterLevel > kNone_SkFilterQuality) {
383             index |= 4;
384         }
385         // bits 3,4,5 encoding the source bitmap format
386         switch (fBitmap->colorType()) {
387             case kN32_SkColorType:
388                 if (kPremul_SkAlphaType != at && kOpaque_SkAlphaType != at) {
389                     return false;
390                 }
391                 index |= 0;
392                 break;
393             case kRGB_565_SkColorType:
394                 index |= 8;
395                 break;
396             case kIndex_8_SkColorType:
397                 if (kPremul_SkAlphaType != at && kOpaque_SkAlphaType != at) {
398                     return false;
399                 }
400                 index |= 16;
401                 break;
402             case kARGB_4444_SkColorType:
403                 if (kPremul_SkAlphaType != at && kOpaque_SkAlphaType != at) {
404                     return false;
405                 }
406                 index |= 24;
407                 break;
408             case kAlpha_8_SkColorType:
409                 index |= 32;
410                 fPaintPMColor = SkPreMultiplyColor(paint.getColor());
411                 break;
412             case kGray_8_SkColorType:
413                 index |= 40;
414                 fPaintPMColor = SkPreMultiplyColor(paint.getColor());
415                 break;
416             default:
417                 // TODO(dominikg): Should we ever get here? SkASSERT(false) instead?
418                 return false;
419         }
420 
421 #if !SK_ARM_NEON_IS_ALWAYS
422         static const SampleProc32 gSkBitmapProcStateSample32[] = {
423             S32_opaque_D32_nofilter_DXDY,
424             S32_alpha_D32_nofilter_DXDY,
425             S32_opaque_D32_nofilter_DX,
426             S32_alpha_D32_nofilter_DX,
427             S32_opaque_D32_filter_DXDY,
428             S32_alpha_D32_filter_DXDY,
429             S32_opaque_D32_filter_DX,
430             S32_alpha_D32_filter_DX,
431 
432             S16_opaque_D32_nofilter_DXDY,
433             S16_alpha_D32_nofilter_DXDY,
434             S16_opaque_D32_nofilter_DX,
435             S16_alpha_D32_nofilter_DX,
436             S16_opaque_D32_filter_DXDY,
437             S16_alpha_D32_filter_DXDY,
438             S16_opaque_D32_filter_DX,
439             S16_alpha_D32_filter_DX,
440 
441             SI8_opaque_D32_nofilter_DXDY,
442             SI8_alpha_D32_nofilter_DXDY,
443             SI8_opaque_D32_nofilter_DX,
444             SI8_alpha_D32_nofilter_DX,
445             SI8_opaque_D32_filter_DXDY,
446             SI8_alpha_D32_filter_DXDY,
447             SI8_opaque_D32_filter_DX,
448             SI8_alpha_D32_filter_DX,
449 
450             S4444_opaque_D32_nofilter_DXDY,
451             S4444_alpha_D32_nofilter_DXDY,
452             S4444_opaque_D32_nofilter_DX,
453             S4444_alpha_D32_nofilter_DX,
454             S4444_opaque_D32_filter_DXDY,
455             S4444_alpha_D32_filter_DXDY,
456             S4444_opaque_D32_filter_DX,
457             S4444_alpha_D32_filter_DX,
458 
459             // A8 treats alpha/opaque the same (equally efficient)
460             SA8_alpha_D32_nofilter_DXDY,
461             SA8_alpha_D32_nofilter_DXDY,
462             SA8_alpha_D32_nofilter_DX,
463             SA8_alpha_D32_nofilter_DX,
464             SA8_alpha_D32_filter_DXDY,
465             SA8_alpha_D32_filter_DXDY,
466             SA8_alpha_D32_filter_DX,
467             SA8_alpha_D32_filter_DX,
468 
469             // todo: possibly specialize on opaqueness
470             SG8_alpha_D32_nofilter_DXDY,
471             SG8_alpha_D32_nofilter_DXDY,
472             SG8_alpha_D32_nofilter_DX,
473             SG8_alpha_D32_nofilter_DX,
474             SG8_alpha_D32_filter_DXDY,
475             SG8_alpha_D32_filter_DXDY,
476             SG8_alpha_D32_filter_DX,
477             SG8_alpha_D32_filter_DX
478         };
479 
480         static const SampleProc16 gSkBitmapProcStateSample16[] = {
481             S32_D16_nofilter_DXDY,
482             S32_D16_nofilter_DX,
483             S32_D16_filter_DXDY,
484             S32_D16_filter_DX,
485 
486             S16_D16_nofilter_DXDY,
487             S16_D16_nofilter_DX,
488             S16_D16_filter_DXDY,
489             S16_D16_filter_DX,
490 
491             SI8_D16_nofilter_DXDY,
492             SI8_D16_nofilter_DX,
493             SI8_D16_filter_DXDY,
494             SI8_D16_filter_DX,
495 
496             // Don't support 4444 -> 565
497             NULL, NULL, NULL, NULL,
498             // Don't support A8 -> 565
499             NULL, NULL, NULL, NULL,
500             // Don't support G8 -> 565 (but we could)
501             NULL, NULL, NULL, NULL
502         };
503 #endif
504 
505         fSampleProc32 = SK_ARM_NEON_WRAP(gSkBitmapProcStateSample32)[index];
506         index >>= 1;    // shift away any opaque/alpha distinction
507         fSampleProc16 = SK_ARM_NEON_WRAP(gSkBitmapProcStateSample16)[index];
508 
509         // our special-case shaderprocs
510         if (SK_ARM_NEON_WRAP(S16_D16_filter_DX) == fSampleProc16) {
511             if (clampClamp) {
512                 fShaderProc16 = SK_ARM_NEON_WRAP(Clamp_S16_D16_filter_DX_shaderproc);
513             } else if (SkShader::kRepeat_TileMode == fTileModeX &&
514                        SkShader::kRepeat_TileMode == fTileModeY) {
515                 fShaderProc16 = SK_ARM_NEON_WRAP(Repeat_S16_D16_filter_DX_shaderproc);
516             }
517         } else if (SK_ARM_NEON_WRAP(SI8_opaque_D32_filter_DX) == fSampleProc32 && clampClamp) {
518             fShaderProc32 = SK_ARM_NEON_WRAP(Clamp_SI8_opaque_D32_filter_DX_shaderproc);
519         } else if (S32_opaque_D32_nofilter_DX == fSampleProc32 && clampClamp) {
520             fShaderProc32 = Clamp_S32_opaque_D32_nofilter_DX_shaderproc;
521         }
522 
523         if (NULL == fShaderProc32) {
524             fShaderProc32 = this->chooseShaderProc32();
525         }
526     }
527 
528     // see if our platform has any accelerated overrides
529     this->platformProcs();
530 
531     return true;
532 }
533 
Clamp_S32_D32_nofilter_trans_shaderproc(const SkBitmapProcState & s,int x,int y,SkPMColor * SK_RESTRICT colors,int count)534 static void Clamp_S32_D32_nofilter_trans_shaderproc(const SkBitmapProcState& s,
535                                                     int x, int y,
536                                                     SkPMColor* SK_RESTRICT colors,
537                                                     int count) {
538     SkASSERT(((s.fInvType & ~SkMatrix::kTranslate_Mask)) == 0);
539     SkASSERT(s.fInvKy == 0);
540     SkASSERT(count > 0 && colors != NULL);
541     SkASSERT(kNone_SkFilterQuality == s.fFilterLevel);
542 
543     const int maxX = s.fBitmap->width() - 1;
544     const int maxY = s.fBitmap->height() - 1;
545     int ix = s.fFilterOneX + x;
546     int iy = SkClampMax(s.fFilterOneY + y, maxY);
547 #ifdef SK_DEBUG
548     {
549         SkPoint pt;
550         s.fInvProc(s.fInvMatrix, SkIntToScalar(x) + SK_ScalarHalf,
551                    SkIntToScalar(y) + SK_ScalarHalf, &pt);
552         int iy2 = SkClampMax(SkScalarFloorToInt(pt.fY), maxY);
553         int ix2 = SkScalarFloorToInt(pt.fX);
554 
555         SkASSERT(iy == iy2);
556         SkASSERT(ix == ix2);
557     }
558 #endif
559     const SkPMColor* row = s.fBitmap->getAddr32(0, iy);
560 
561     // clamp to the left
562     if (ix < 0) {
563         int n = SkMin32(-ix, count);
564         sk_memset32(colors, row[0], n);
565         count -= n;
566         if (0 == count) {
567             return;
568         }
569         colors += n;
570         SkASSERT(-ix == n);
571         ix = 0;
572     }
573     // copy the middle
574     if (ix <= maxX) {
575         int n = SkMin32(maxX - ix + 1, count);
576         memcpy(colors, row + ix, n * sizeof(SkPMColor));
577         count -= n;
578         if (0 == count) {
579             return;
580         }
581         colors += n;
582     }
583     SkASSERT(count > 0);
584     // clamp to the right
585     sk_memset32(colors, row[maxX], count);
586 }
587 
sk_int_mod(int x,int n)588 static inline int sk_int_mod(int x, int n) {
589     SkASSERT(n > 0);
590     if ((unsigned)x >= (unsigned)n) {
591         if (x < 0) {
592             x = n + ~(~x % n);
593         } else {
594             x = x % n;
595         }
596     }
597     return x;
598 }
599 
sk_int_mirror(int x,int n)600 static inline int sk_int_mirror(int x, int n) {
601     x = sk_int_mod(x, 2 * n);
602     if (x >= n) {
603         x = n + ~(x - n);
604     }
605     return x;
606 }
607 
Repeat_S32_D32_nofilter_trans_shaderproc(const SkBitmapProcState & s,int x,int y,SkPMColor * SK_RESTRICT colors,int count)608 static void Repeat_S32_D32_nofilter_trans_shaderproc(const SkBitmapProcState& s,
609                                                      int x, int y,
610                                                      SkPMColor* SK_RESTRICT colors,
611                                                      int count) {
612     SkASSERT(((s.fInvType & ~SkMatrix::kTranslate_Mask)) == 0);
613     SkASSERT(s.fInvKy == 0);
614     SkASSERT(count > 0 && colors != NULL);
615     SkASSERT(kNone_SkFilterQuality == s.fFilterLevel);
616 
617     const int stopX = s.fBitmap->width();
618     const int stopY = s.fBitmap->height();
619     int ix = s.fFilterOneX + x;
620     int iy = sk_int_mod(s.fFilterOneY + y, stopY);
621 #ifdef SK_DEBUG
622     {
623         SkPoint pt;
624         s.fInvProc(s.fInvMatrix, SkIntToScalar(x) + SK_ScalarHalf,
625                    SkIntToScalar(y) + SK_ScalarHalf, &pt);
626         int iy2 = sk_int_mod(SkScalarFloorToInt(pt.fY), stopY);
627         int ix2 = SkScalarFloorToInt(pt.fX);
628 
629         SkASSERT(iy == iy2);
630         SkASSERT(ix == ix2);
631     }
632 #endif
633     const SkPMColor* row = s.fBitmap->getAddr32(0, iy);
634 
635     ix = sk_int_mod(ix, stopX);
636     for (;;) {
637         int n = SkMin32(stopX - ix, count);
638         memcpy(colors, row + ix, n * sizeof(SkPMColor));
639         count -= n;
640         if (0 == count) {
641             return;
642         }
643         colors += n;
644         ix = 0;
645     }
646 }
647 
S32_D32_constX_shaderproc(const SkBitmapProcState & s,int x,int y,SkPMColor * SK_RESTRICT colors,int count)648 static void S32_D32_constX_shaderproc(const SkBitmapProcState& s,
649                                       int x, int y,
650                                       SkPMColor* SK_RESTRICT colors,
651                                       int count) {
652     SkASSERT((s.fInvType & ~(SkMatrix::kTranslate_Mask | SkMatrix::kScale_Mask)) == 0);
653     SkASSERT(s.fInvKy == 0);
654     SkASSERT(count > 0 && colors != NULL);
655     SkASSERT(1 == s.fBitmap->width());
656 
657     int iY0;
658     int iY1   SK_INIT_TO_AVOID_WARNING;
659     int iSubY SK_INIT_TO_AVOID_WARNING;
660 
661     if (kNone_SkFilterQuality != s.fFilterLevel) {
662         SkBitmapProcState::MatrixProc mproc = s.getMatrixProc();
663         uint32_t xy[2];
664 
665         mproc(s, xy, 1, x, y);
666 
667         iY0 = xy[0] >> 18;
668         iY1 = xy[0] & 0x3FFF;
669         iSubY = (xy[0] >> 14) & 0xF;
670     } else {
671         int yTemp;
672 
673         if (s.fInvType > SkMatrix::kTranslate_Mask) {
674             SkPoint pt;
675             s.fInvProc(s.fInvMatrix,
676                        SkIntToScalar(x) + SK_ScalarHalf,
677                        SkIntToScalar(y) + SK_ScalarHalf,
678                        &pt);
679             // When the matrix has a scale component the setup code in
680             // chooseProcs multiples the inverse matrix by the inverse of the
681             // bitmap's width and height. Since this method is going to do
682             // its own tiling and sampling we need to undo that here.
683             if (SkShader::kClamp_TileMode != s.fTileModeX ||
684                 SkShader::kClamp_TileMode != s.fTileModeY) {
685                 yTemp = SkScalarFloorToInt(pt.fY * s.fBitmap->height());
686             } else {
687                 yTemp = SkScalarFloorToInt(pt.fY);
688             }
689         } else {
690             yTemp = s.fFilterOneY + y;
691         }
692 
693         const int stopY = s.fBitmap->height();
694         switch (s.fTileModeY) {
695             case SkShader::kClamp_TileMode:
696                 iY0 = SkClampMax(yTemp, stopY-1);
697                 break;
698             case SkShader::kRepeat_TileMode:
699                 iY0 = sk_int_mod(yTemp, stopY);
700                 break;
701             case SkShader::kMirror_TileMode:
702             default:
703                 iY0 = sk_int_mirror(yTemp, stopY);
704                 break;
705         }
706 
707 #ifdef SK_DEBUG
708         {
709             SkPoint pt;
710             s.fInvProc(s.fInvMatrix,
711                        SkIntToScalar(x) + SK_ScalarHalf,
712                        SkIntToScalar(y) + SK_ScalarHalf,
713                        &pt);
714             if (s.fInvType > SkMatrix::kTranslate_Mask &&
715                 (SkShader::kClamp_TileMode != s.fTileModeX ||
716                  SkShader::kClamp_TileMode != s.fTileModeY)) {
717                 pt.fY *= s.fBitmap->height();
718             }
719             int iY2;
720 
721             switch (s.fTileModeY) {
722             case SkShader::kClamp_TileMode:
723                 iY2 = SkClampMax(SkScalarFloorToInt(pt.fY), stopY-1);
724                 break;
725             case SkShader::kRepeat_TileMode:
726                 iY2 = sk_int_mod(SkScalarFloorToInt(pt.fY), stopY);
727                 break;
728             case SkShader::kMirror_TileMode:
729             default:
730                 iY2 = sk_int_mirror(SkScalarFloorToInt(pt.fY), stopY);
731                 break;
732             }
733 
734             SkASSERT(iY0 == iY2);
735         }
736 #endif
737     }
738 
739     const SkPMColor* row0 = s.fBitmap->getAddr32(0, iY0);
740     SkPMColor color;
741 
742     if (kNone_SkFilterQuality != s.fFilterLevel) {
743         const SkPMColor* row1 = s.fBitmap->getAddr32(0, iY1);
744 
745         if (s.fAlphaScale < 256) {
746             Filter_32_alpha(iSubY, *row0, *row1, &color, s.fAlphaScale);
747         } else {
748             Filter_32_opaque(iSubY, *row0, *row1, &color);
749         }
750     } else {
751         if (s.fAlphaScale < 256) {
752             color = SkAlphaMulQ(*row0, s.fAlphaScale);
753         } else {
754             color = *row0;
755         }
756     }
757 
758     sk_memset32(colors, color, count);
759 }
760 
DoNothing_shaderproc(const SkBitmapProcState &,int x,int y,SkPMColor * SK_RESTRICT colors,int count)761 static void DoNothing_shaderproc(const SkBitmapProcState&, int x, int y,
762                                  SkPMColor* SK_RESTRICT colors, int count) {
763     // if we get called, the matrix is too tricky, so we just draw nothing
764     sk_memset32(colors, 0, count);
765 }
766 
setupForTranslate()767 bool SkBitmapProcState::setupForTranslate() {
768     SkPoint pt;
769     fInvProc(fInvMatrix, SK_ScalarHalf, SK_ScalarHalf, &pt);
770 
771     /*
772      *  if the translate is larger than our ints, we can get random results, or
773      *  worse, we might get 0x80000000, which wreaks havoc on us, since we can't
774      *  negate it.
775      */
776     const SkScalar too_big = SkIntToScalar(1 << 30);
777     if (SkScalarAbs(pt.fX) > too_big || SkScalarAbs(pt.fY) > too_big) {
778         return false;
779     }
780 
781     // Since we know we're not filtered, we re-purpose these fields allow
782     // us to go from device -> src coordinates w/ just an integer add,
783     // rather than running through the inverse-matrix
784     fFilterOneX = SkScalarFloorToInt(pt.fX);
785     fFilterOneY = SkScalarFloorToInt(pt.fY);
786     return true;
787 }
788 
chooseShaderProc32()789 SkBitmapProcState::ShaderProc32 SkBitmapProcState::chooseShaderProc32() {
790 
791     if (kN32_SkColorType != fBitmap->colorType()) {
792         return NULL;
793     }
794 
795     static const unsigned kMask = SkMatrix::kTranslate_Mask | SkMatrix::kScale_Mask;
796 
797     if (1 == fBitmap->width() && 0 == (fInvType & ~kMask)) {
798         if (kNone_SkFilterQuality == fFilterLevel &&
799             fInvType <= SkMatrix::kTranslate_Mask &&
800             !this->setupForTranslate()) {
801             return DoNothing_shaderproc;
802         }
803         return S32_D32_constX_shaderproc;
804     }
805 
806     if (fAlphaScale < 256) {
807         return NULL;
808     }
809     if (fInvType > SkMatrix::kTranslate_Mask) {
810         return NULL;
811     }
812     if (kNone_SkFilterQuality != fFilterLevel) {
813         return NULL;
814     }
815 
816     SkShader::TileMode tx = (SkShader::TileMode)fTileModeX;
817     SkShader::TileMode ty = (SkShader::TileMode)fTileModeY;
818 
819     if (SkShader::kClamp_TileMode == tx && SkShader::kClamp_TileMode == ty) {
820         if (this->setupForTranslate()) {
821             return Clamp_S32_D32_nofilter_trans_shaderproc;
822         }
823         return DoNothing_shaderproc;
824     }
825     if (SkShader::kRepeat_TileMode == tx && SkShader::kRepeat_TileMode == ty) {
826         if (this->setupForTranslate()) {
827             return Repeat_S32_D32_nofilter_trans_shaderproc;
828         }
829         return DoNothing_shaderproc;
830     }
831     return NULL;
832 }
833 
834 ///////////////////////////////////////////////////////////////////////////////
835 
836 #ifdef SK_DEBUG
837 
check_scale_nofilter(uint32_t bitmapXY[],int count,unsigned mx,unsigned my)838 static void check_scale_nofilter(uint32_t bitmapXY[], int count,
839                                  unsigned mx, unsigned my) {
840     unsigned y = *bitmapXY++;
841     SkASSERT(y < my);
842 
843     const uint16_t* xptr = reinterpret_cast<const uint16_t*>(bitmapXY);
844     for (int i = 0; i < count; ++i) {
845         SkASSERT(xptr[i] < mx);
846     }
847 }
848 
check_scale_filter(uint32_t bitmapXY[],int count,unsigned mx,unsigned my)849 static void check_scale_filter(uint32_t bitmapXY[], int count,
850                                  unsigned mx, unsigned my) {
851     uint32_t YY = *bitmapXY++;
852     unsigned y0 = YY >> 18;
853     unsigned y1 = YY & 0x3FFF;
854     SkASSERT(y0 < my);
855     SkASSERT(y1 < my);
856 
857     for (int i = 0; i < count; ++i) {
858         uint32_t XX = bitmapXY[i];
859         unsigned x0 = XX >> 18;
860         unsigned x1 = XX & 0x3FFF;
861         SkASSERT(x0 < mx);
862         SkASSERT(x1 < mx);
863     }
864 }
865 
check_affine_nofilter(uint32_t bitmapXY[],int count,unsigned mx,unsigned my)866 static void check_affine_nofilter(uint32_t bitmapXY[], int count,
867                                  unsigned mx, unsigned my) {
868     for (int i = 0; i < count; ++i) {
869         uint32_t XY = bitmapXY[i];
870         unsigned x = XY & 0xFFFF;
871         unsigned y = XY >> 16;
872         SkASSERT(x < mx);
873         SkASSERT(y < my);
874     }
875 }
876 
check_affine_filter(uint32_t bitmapXY[],int count,unsigned mx,unsigned my)877 static void check_affine_filter(uint32_t bitmapXY[], int count,
878                                  unsigned mx, unsigned my) {
879     for (int i = 0; i < count; ++i) {
880         uint32_t YY = *bitmapXY++;
881         unsigned y0 = YY >> 18;
882         unsigned y1 = YY & 0x3FFF;
883         SkASSERT(y0 < my);
884         SkASSERT(y1 < my);
885 
886         uint32_t XX = *bitmapXY++;
887         unsigned x0 = XX >> 18;
888         unsigned x1 = XX & 0x3FFF;
889         SkASSERT(x0 < mx);
890         SkASSERT(x1 < mx);
891     }
892 }
893 
DebugMatrixProc(const SkBitmapProcState & state,uint32_t bitmapXY[],int count,int x,int y)894 void SkBitmapProcState::DebugMatrixProc(const SkBitmapProcState& state,
895                                         uint32_t bitmapXY[], int count,
896                                         int x, int y) {
897     SkASSERT(bitmapXY);
898     SkASSERT(count > 0);
899 
900     state.fMatrixProc(state, bitmapXY, count, x, y);
901 
902     void (*proc)(uint32_t bitmapXY[], int count, unsigned mx, unsigned my);
903 
904     // There are four formats possible:
905     //  scale -vs- affine
906     //  filter -vs- nofilter
907     if (state.fInvType <= (SkMatrix::kTranslate_Mask | SkMatrix::kScale_Mask)) {
908         proc = state.fFilterLevel != kNone_SkFilterQuality ? check_scale_filter : check_scale_nofilter;
909     } else {
910         proc = state.fFilterLevel != kNone_SkFilterQuality ? check_affine_filter : check_affine_nofilter;
911     }
912     proc(bitmapXY, count, state.fBitmap->width(), state.fBitmap->height());
913 }
914 
getMatrixProc() const915 SkBitmapProcState::MatrixProc SkBitmapProcState::getMatrixProc() const {
916     return DebugMatrixProc;
917 }
918 
919 #endif
920 
921 ///////////////////////////////////////////////////////////////////////////////
922 /*
923     The storage requirements for the different matrix procs are as follows,
924     where each X or Y is 2 bytes, and N is the number of pixels/elements:
925 
926     scale/translate     nofilter      Y(4bytes) + N * X
927     affine/perspective  nofilter      N * (X Y)
928     scale/translate     filter        Y Y + N * (X X)
929     affine/perspective  filter        N * (Y Y X X)
930  */
maxCountForBufferSize(size_t bufferSize) const931 int SkBitmapProcState::maxCountForBufferSize(size_t bufferSize) const {
932     int32_t size = static_cast<int32_t>(bufferSize);
933 
934     size &= ~3; // only care about 4-byte aligned chunks
935     if (fInvType <= (SkMatrix::kTranslate_Mask | SkMatrix::kScale_Mask)) {
936         size -= 4;   // the shared Y (or YY) coordinate
937         if (size < 0) {
938             size = 0;
939         }
940         size >>= 1;
941     } else {
942         size >>= 2;
943     }
944 
945     if (fFilterLevel != kNone_SkFilterQuality) {
946         size >>= 1;
947     }
948 
949     return size;
950 }
951 
952 ///////////////////////
953 
Clamp_S32_opaque_D32_nofilter_DX_shaderproc(const SkBitmapProcState & s,int x,int y,SkPMColor * SK_RESTRICT dst,int count)954 void  Clamp_S32_opaque_D32_nofilter_DX_shaderproc(const SkBitmapProcState& s, int x, int y,
955                                                   SkPMColor* SK_RESTRICT dst, int count) {
956     SkASSERT((s.fInvType & ~(SkMatrix::kTranslate_Mask |
957                              SkMatrix::kScale_Mask)) == 0);
958 
959     const unsigned maxX = s.fBitmap->width() - 1;
960     SkFractionalInt fx;
961     int dstY;
962     {
963         SkPoint pt;
964         s.fInvProc(s.fInvMatrix, SkIntToScalar(x) + SK_ScalarHalf, SkIntToScalar(y) + SK_ScalarHalf,
965                    &pt);
966         fx = SkScalarToFractionalInt(pt.fY);
967         const unsigned maxY = s.fBitmap->height() - 1;
968         dstY = SkClampMax(SkFractionalIntToInt(fx), maxY);
969         fx = SkScalarToFractionalInt(pt.fX);
970     }
971 
972     const SkPMColor* SK_RESTRICT src = s.fBitmap->getAddr32(0, dstY);
973     const SkFractionalInt dx = s.fInvSxFractionalInt;
974 
975     // Check if we're safely inside [0...maxX] so no need to clamp each computed index.
976     //
977     if ((uint64_t)SkFractionalIntToInt(fx) <= maxX &&
978         (uint64_t)SkFractionalIntToInt(fx + dx * (count - 1)) <= maxX)
979     {
980         int count4 = count >> 2;
981         for (int i = 0; i < count4; ++i) {
982             SkPMColor src0 = src[SkFractionalIntToInt(fx)]; fx += dx;
983             SkPMColor src1 = src[SkFractionalIntToInt(fx)]; fx += dx;
984             SkPMColor src2 = src[SkFractionalIntToInt(fx)]; fx += dx;
985             SkPMColor src3 = src[SkFractionalIntToInt(fx)]; fx += dx;
986             dst[0] = src0;
987             dst[1] = src1;
988             dst[2] = src2;
989             dst[3] = src3;
990             dst += 4;
991         }
992         for (int i = (count4 << 2); i < count; ++i) {
993             unsigned index = SkFractionalIntToInt(fx);
994             SkASSERT(index <= maxX);
995             *dst++ = src[index];
996             fx += dx;
997         }
998     } else {
999         for (int i = 0; i < count; ++i) {
1000             dst[i] = src[SkClampMax(SkFractionalIntToInt(fx), maxX)];
1001             fx += dx;
1002         }
1003     }
1004 }
1005 
1006