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