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