Home | History | Annotate | Download | only in core
      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
     24 extern const SkBitmapProcState::SampleProc32 gSkBitmapProcStateSample32_neon[];
     25 extern void  S16_D16_filter_DX_neon(const SkBitmapProcState&, const uint32_t*, int, uint16_t*);
     26 extern void  Clamp_S16_D16_filter_DX_shaderproc_neon(const void *, int, int, uint16_t*, int);
     27 extern void  Repeat_S16_D16_filter_DX_shaderproc_neon(const void *, int, int, uint16_t*, int);
     28 extern void  SI8_opaque_D32_filter_DX_neon(const SkBitmapProcState&, const uint32_t*, int, SkPMColor*);
     29 extern void  SI8_opaque_D32_filter_DX_shaderproc_neon(const void *, int, int, uint32_t*, int);
     30 extern void  Clamp_SI8_opaque_D32_filter_DX_shaderproc_neon(const void*, int, int, uint32_t*, int);
     31 #endif
     32 
     33 extern 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 
     39 SkBitmapProcInfo::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 
     47 SkBitmapProcInfo::~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.
     54 static 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  */
     62 static 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 
     84 static 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 
     93 static 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 
     99 bool 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  */
    198 bool 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 
    218 bool 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 
    361 static 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 
    404 static 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 
    416 static 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 
    424 static 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 
    453 static 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 
    563 static 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 
    569 bool 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 
    592 SkBitmapProcState::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 
    641 static 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 
    652 static 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 
    669 static 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 
    680 static 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 
    697 void 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 
    720 SkBitmapProcState::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  */
    736 int 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 
    759 void  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