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
23extern const SkBitmapProcState::SampleProc16 gSkBitmapProcStateSample16_neon[];
24extern const SkBitmapProcState::SampleProc32 gSkBitmapProcStateSample32_neon[];
25extern void  S16_D16_filter_DX_neon(const SkBitmapProcState&, const uint32_t*, int, uint16_t*);
26extern void  Clamp_S16_D16_filter_DX_shaderproc_neon(const SkBitmapProcState&, int, int, uint16_t*, int);
27extern void  Repeat_S16_D16_filter_DX_shaderproc_neon(const SkBitmapProcState&, int, int, uint16_t*, int);
28extern void  SI8_opaque_D32_filter_DX_neon(const SkBitmapProcState&, const uint32_t*, int, SkPMColor*);
29extern void  SI8_opaque_D32_filter_DX_shaderproc_neon(const SkBitmapProcState&, int, int, uint32_t*, int);
30extern void  Clamp_SI8_opaque_D32_filter_DX_shaderproc_neon(const SkBitmapProcState&, int, int, uint32_t*, int);
31#endif
32
33extern 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
42static 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 */
50static 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
76static 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
95static 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.
103static 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 */
119void 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 */
178void 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
222bool 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
233static 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 */
263bool 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
357bool 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
534static 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
588static 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
600static 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
608static 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
648static 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
761static 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
767bool 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
789SkBitmapProcState::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
838static 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
849static 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
866static 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
877static 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
894void 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
915SkBitmapProcState::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 */
931int 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
954void  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