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