LCOV - code coverage report
Current view: top level - gfx/skia/skia/src/core - SkBitmapProcState.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 239 367 65.1 %
Date: 2017-07-14 16:53:18 Functions: 20 25 80.0 %
Legend: Lines: hit not hit

          Line data    Source code
       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         141 : SkBitmapProcInfo::SkBitmapProcInfo(const SkBitmapProvider& provider,
      40         141 :                                    SkShader::TileMode tmx, SkShader::TileMode tmy)
      41             :     : fProvider(provider)
      42             :     , fTileModeX(tmx)
      43             :     , fTileModeY(tmy)
      44         141 :     , fBMState(nullptr)
      45         141 : {}
      46             : 
      47         282 : SkBitmapProcInfo::~SkBitmapProcInfo() {
      48         141 :     SkInPlaceDeleteCheck(fBMState, fBMStateStorage.get());
      49         141 : }
      50             : 
      51             : ///////////////////////////////////////////////////////////////////////////////
      52             : 
      53             : // true iff the matrix has a scale and no more than an optional translate.
      54         183 : static bool matrix_only_scale_translate(const SkMatrix& m) {
      55         183 :     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          25 : static bool just_trans_clamp(const SkMatrix& matrix, const SkPixmap& pixmap) {
      63          25 :     SkASSERT(matrix_only_scale_translate(matrix));
      64             : 
      65             :     SkRect dst;
      66          25 :     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          25 :     matrix.mapPoints(SkTCast<SkPoint*>(&dst),
      72             :                      SkTCast<const SkPoint*>(&src),
      73          25 :                      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          25 :     dst.round(&idst);
      81          25 :     return idst.width() == pixmap.width() && idst.height() == pixmap.height();
      82             : }
      83             : 
      84          17 : static bool just_trans_general(const SkMatrix& matrix) {
      85          17 :     SkASSERT(matrix_only_scale_translate(matrix));
      86             : 
      87          17 :     const SkScalar tol = SK_Scalar1 / 32768;
      88             : 
      89          17 :     return SkScalarNearlyZero(matrix[SkMatrix::kMScaleX] - SK_Scalar1, tol)
      90          17 :         && SkScalarNearlyZero(matrix[SkMatrix::kMScaleY] - SK_Scalar1, tol);
      91             : }
      92             : 
      93          42 : 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          42 :     return (dimension & ~0x3FFF) == 0;
      97             : }
      98             : 
      99         141 : bool SkBitmapProcInfo::init(const SkMatrix& inv, const SkPaint& paint) {
     100         141 :     const int origW = fProvider.info().width();
     101         141 :     const int origH = fProvider.info().height();
     102             : 
     103         141 :     fPixmap.reset();
     104         141 :     fInvMatrix = inv;
     105         141 :     fFilterQuality = paint.getFilterQuality();
     106             : 
     107         141 :     bool allow_ignore_fractional_translate = true;  // historical default
     108         141 :     if (kMedium_SkFilterQuality == fFilterQuality) {
     109           0 :         allow_ignore_fractional_translate = false;
     110             :     }
     111             : 
     112         282 :     SkDefaultBitmapController controller(SkDefaultBitmapController::CanShadeHQ::kNo);
     113         141 :     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         141 :     if (nullptr == fBMState || fBMState->pixmap().info().isEmpty()) {
     117           0 :         return false;
     118             :     }
     119         141 :     fPixmap = fBMState->pixmap();
     120         141 :     fInvMatrix = fBMState->invMatrix();
     121         141 :     fRealInvMatrix = fBMState->invMatrix();
     122         141 :     fPaintColor = paint.getColor();
     123         141 :     fFilterQuality = fBMState->quality();
     124         141 :     SkASSERT(fPixmap.addr());
     125             : 
     126         141 :     bool trivialMatrix = (fInvMatrix.getType() & ~SkMatrix::kTranslate_Mask) == 0;
     127         239 :     bool clampClamp = SkShader::kClamp_TileMode == fTileModeX &&
     128         239 :                       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         141 :     if (!(clampClamp || (trivialMatrix && allow_ignore_fractional_translate))) {
     140          17 :         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         141 :     if (matrix_only_scale_translate(fInvMatrix)) {
     152             :         SkMatrix forward;
     153          42 :         if (fInvMatrix.invert(&forward)) {
     154          67 :             if ((clampClamp && allow_ignore_fractional_translate)
     155          67 :                 ? just_trans_clamp(forward, fPixmap)
     156             :                 : just_trans_general(forward)) {
     157           0 :                 fInvMatrix.setTranslate(-forward.getTranslateX(), -forward.getTranslateY());
     158             :             }
     159             :         }
     160             :     }
     161             : 
     162         141 :     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         141 :     if (fPixmap.width() == origW && fPixmap.height() == origH) {
     171         141 :         allow_ignore_fractional_translate = true;
     172             :     }
     173             : 
     174         141 :     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         172 :         if (fInvType <= SkMatrix::kTranslate_Mask ||
     179          42 :             !valid_for_filtering(fPixmap.width() | fPixmap.height()))
     180             :         {
     181          88 :             fFilterQuality = kNone_SkFilterQuality;
     182             :         }
     183             :     }
     184             : 
     185         141 :     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         141 : bool SkBitmapProcState::chooseProcs() {
     199         141 :     fInvProc            = fInvMatrix.getMapXYProc();
     200         141 :     fInvSx              = SkScalarToFixed(fInvMatrix.getScaleX());
     201         141 :     fInvSxFractionalInt = SkScalarToFractionalInt(fInvMatrix.getScaleX());
     202         141 :     fInvKy              = SkScalarToFixed(fInvMatrix.getSkewY());
     203         141 :     fInvKyFractionalInt = SkScalarToFractionalInt(fInvMatrix.getSkewY());
     204             : 
     205         141 :     fAlphaScale = SkAlpha255To256(SkColorGetA(fPaintColor));
     206             : 
     207         141 :     fShaderProc32 = nullptr;
     208         141 :     fShaderProc16 = nullptr;
     209         141 :     fSampleProc32 = nullptr;
     210             : 
     211         141 :     const bool trivialMatrix = (fInvMatrix.getType() & ~SkMatrix::kTranslate_Mask) == 0;
     212         239 :     const bool clampClamp = SkShader::kClamp_TileMode == fTileModeX &&
     213         239 :                             SkShader::kClamp_TileMode == fTileModeY;
     214             : 
     215         141 :     return this->chooseScanlineProcs(trivialMatrix, clampClamp);
     216             : }
     217             : 
     218         141 : bool SkBitmapProcState::chooseScanlineProcs(bool trivialMatrix, bool clampClamp) {
     219         141 :     fMatrixProc = this->chooseMatrixProc(trivialMatrix);
     220             :     // TODO(dominikg): SkASSERT(fMatrixProc) instead? chooseMatrixProc never returns nullptr.
     221         141 :     if (nullptr == fMatrixProc) {
     222           0 :         return false;
     223             :     }
     224             : 
     225             :     ///////////////////////////////////////////////////////////////////////
     226             : 
     227         141 :     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         141 :     if (fFilterQuality < kHigh_SkFilterQuality) {
     234             : 
     235         141 :         int index = 0;
     236         141 :         if (fAlphaScale < 256) {  // note: this distinction is not used for D16
     237           8 :             index |= 1;
     238             :         }
     239         141 :         if (fInvType <= (SkMatrix::kTranslate_Mask | SkMatrix::kScale_Mask)) {
     240         141 :             index |= 2;
     241             :         }
     242         141 :         if (fFilterQuality > kNone_SkFilterQuality) {
     243          42 :             index |= 4;
     244             :         }
     245             :         // bits 3,4,5 encoding the source bitmap format
     246         141 :         switch (fPixmap.colorType()) {
     247             :             case kN32_SkColorType:
     248         141 :                 if (kPremul_SkAlphaType != at && kOpaque_SkAlphaType != at) {
     249           0 :                     return false;
     250             :                 }
     251         141 :                 index |= 0;
     252         141 :                 break;
     253             :             case kRGB_565_SkColorType:
     254           0 :                 index |= 8;
     255           0 :                 break;
     256             :             case kIndex_8_SkColorType:
     257           0 :                 if (kPremul_SkAlphaType != at && kOpaque_SkAlphaType != at) {
     258           0 :                     return false;
     259             :                 }
     260           0 :                 index |= 16;
     261           0 :                 break;
     262             :             case kARGB_4444_SkColorType:
     263           0 :                 if (kPremul_SkAlphaType != at && kOpaque_SkAlphaType != at) {
     264           0 :                     return false;
     265             :                 }
     266           0 :                 index |= 24;
     267           0 :                 break;
     268             :             case kAlpha_8_SkColorType:
     269           0 :                 index |= 32;
     270           0 :                 fPaintPMColor = SkPreMultiplyColor(fPaintColor);
     271           0 :                 break;
     272             :             case kGray_8_SkColorType:
     273           0 :                 index |= 40;
     274           0 :                 fPaintPMColor = SkPreMultiplyColor(fPaintColor);
     275           0 :                 break;
     276             :             default:
     277             :                 // TODO(dominikg): Should we ever get here? SkASSERT(false) instead?
     278           0 :                 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         141 :         fSampleProc32 = SK_ARM_NEON_WRAP(gSkBitmapProcStateSample32)[index];
     342             : 
     343         141 :         fShaderProc32 = this->chooseShaderProc32();
     344         141 :         if (nullptr == fShaderProc32) {
     345             :             // our special-case shaderprocs
     346          49 :             if (SK_ARM_NEON_WRAP(SI8_opaque_D32_filter_DX) == fSampleProc32 && clampClamp) {
     347           0 :                 fShaderProc32 = SK_ARM_NEON_WRAP(Clamp_SI8_opaque_D32_filter_DX_shaderproc);
     348          49 :             } else if (S32_opaque_D32_nofilter_DX == fSampleProc32 && clampClamp) {
     349           0 :                 fShaderProc32 = Clamp_S32_opaque_D32_nofilter_DX_shaderproc;
     350             :             }
     351             :         }
     352             :     }
     353             : 
     354             :     // see if our platform has any accelerated overrides
     355         141 :     this->platformProcs();
     356             : 
     357         141 :     return true;
     358             : }
     359             : 
     360       13235 : static void Clamp_S32_D32_nofilter_trans_shaderproc(const void* sIn,
     361             :                                                     int x, int y,
     362             :                                                     SkPMColor* SK_RESTRICT colors,
     363             :                                                     int count) {
     364       13235 :     const SkBitmapProcState& s = *static_cast<const SkBitmapProcState*>(sIn);
     365       13235 :     SkASSERT(((s.fInvType & ~SkMatrix::kTranslate_Mask)) == 0);
     366       13235 :     SkASSERT(s.fInvKy == 0);
     367       13235 :     SkASSERT(count > 0 && colors != nullptr);
     368       13235 :     SkASSERT(kNone_SkFilterQuality == s.fFilterQuality);
     369             : 
     370       13235 :     const int maxX = s.fPixmap.width() - 1;
     371       13235 :     const int maxY = s.fPixmap.height() - 1;
     372       13235 :     int ix = s.fFilterOneX + x;
     373       13235 :     int iy = SkClampMax(s.fFilterOneY + y, maxY);
     374       13235 :     const SkPMColor* row = s.fPixmap.addr32(0, iy);
     375             : 
     376             :     // clamp to the left
     377       13235 :     if (ix < 0) {
     378           0 :         int n = SkMin32(-ix, count);
     379           0 :         sk_memset32(colors, row[0], n);
     380           0 :         count -= n;
     381           0 :         if (0 == count) {
     382           0 :             return;
     383             :         }
     384           0 :         colors += n;
     385           0 :         SkASSERT(-ix == n);
     386           0 :         ix = 0;
     387             :     }
     388             :     // copy the middle
     389       13235 :     if (ix <= maxX) {
     390       13235 :         int n = SkMin32(maxX - ix + 1, count);
     391       13235 :         memcpy(colors, row + ix, n * sizeof(SkPMColor));
     392       13235 :         count -= n;
     393       13235 :         if (0 == count) {
     394       13235 :             return;
     395             :         }
     396           0 :         colors += n;
     397             :     }
     398           0 :     SkASSERT(count > 0);
     399             :     // clamp to the right
     400           0 :     sk_memset32(colors, row[maxX], count);
     401             : }
     402             : 
     403        1324 : static inline int sk_int_mod(int x, int n) {
     404        1324 :     SkASSERT(n > 0);
     405        1324 :     if ((unsigned)x >= (unsigned)n) {
     406         261 :         if (x < 0) {
     407           0 :             x = n + ~(~x % n);
     408             :         } else {
     409         261 :             x = x % n;
     410             :         }
     411             :     }
     412        1324 :     return x;
     413             : }
     414             : 
     415           0 : static inline int sk_int_mirror(int x, int n) {
     416           0 :     x = sk_int_mod(x, 2 * n);
     417           0 :     if (x >= n) {
     418           0 :         x = n + ~(x - n);
     419             :     }
     420           0 :     return x;
     421             : }
     422             : 
     423         270 : static void Repeat_S32_D32_nofilter_trans_shaderproc(const void* sIn,
     424             :                                                      int x, int y,
     425             :                                                      SkPMColor* SK_RESTRICT colors,
     426             :                                                      int count) {
     427         270 :     const SkBitmapProcState& s = *static_cast<const SkBitmapProcState*>(sIn);
     428         270 :     SkASSERT(((s.fInvType & ~SkMatrix::kTranslate_Mask)) == 0);
     429         270 :     SkASSERT(s.fInvKy == 0);
     430         270 :     SkASSERT(count > 0 && colors != nullptr);
     431         270 :     SkASSERT(kNone_SkFilterQuality == s.fFilterQuality);
     432             : 
     433         270 :     const int stopX = s.fPixmap.width();
     434         270 :     const int stopY = s.fPixmap.height();
     435         270 :     int ix = s.fFilterOneX + x;
     436         270 :     int iy = sk_int_mod(s.fFilterOneY + y, stopY);
     437         270 :     const SkPMColor* row = s.fPixmap.addr32(0, iy);
     438             : 
     439         270 :     ix = sk_int_mod(ix, stopX);
     440             :     for (;;) {
     441         270 :         int n = SkMin32(stopX - ix, count);
     442         270 :         memcpy(colors, row + ix, n * sizeof(SkPMColor));
     443         270 :         count -= n;
     444         270 :         if (0 == count) {
     445         540 :             return;
     446             :         }
     447           0 :         colors += n;
     448           0 :         ix = 0;
     449           0 :     }
     450             : }
     451             : 
     452         772 : static void S32_D32_constX_shaderproc(const void* sIn,
     453             :                                       int x, int y,
     454             :                                       SkPMColor* SK_RESTRICT colors,
     455             :                                       int count) {
     456         772 :     const SkBitmapProcState& s = *static_cast<const SkBitmapProcState*>(sIn);
     457         772 :     SkASSERT((s.fInvType & ~(SkMatrix::kTranslate_Mask | SkMatrix::kScale_Mask)) == 0);
     458         772 :     SkASSERT(s.fInvKy == 0);
     459         772 :     SkASSERT(count > 0 && colors != nullptr);
     460         772 :     SkASSERT(1 == s.fPixmap.width());
     461             : 
     462             :     int iY0;
     463         772 :     int iY1   SK_INIT_TO_AVOID_WARNING;
     464         772 :     int iSubY SK_INIT_TO_AVOID_WARNING;
     465             : 
     466         772 :     if (kNone_SkFilterQuality != s.fFilterQuality) {
     467         380 :         SkBitmapProcState::MatrixProc mproc = s.getMatrixProc();
     468             :         uint32_t xy[2];
     469             : 
     470         380 :         mproc(s, xy, 1, x, y);
     471             : 
     472         380 :         iY0 = xy[0] >> 18;
     473         380 :         iY1 = xy[0] & 0x3FFF;
     474         380 :         iSubY = (xy[0] >> 14) & 0xF;
     475             :     } else {
     476             :         int yTemp;
     477             : 
     478         392 :         if (s.fInvType > SkMatrix::kTranslate_Mask) {
     479           0 :             const SkBitmapProcStateAutoMapper mapper(s, x, y);
     480             : 
     481             :             // When the matrix has a scale component the setup code in
     482             :             // chooseProcs multiples the inverse matrix by the inverse of the
     483             :             // bitmap's width and height. Since this method is going to do
     484             :             // its own tiling and sampling we need to undo that here.
     485           0 :             if (SkShader::kClamp_TileMode != s.fTileModeX ||
     486           0 :                 SkShader::kClamp_TileMode != s.fTileModeY) {
     487           0 :                 yTemp = SkFractionalIntToInt(mapper.fractionalIntY() * s.fPixmap.height());
     488             :             } else {
     489           0 :                 yTemp = mapper.intY();
     490             :             }
     491             :         } else {
     492         392 :             yTemp = s.fFilterOneY + y;
     493             :         }
     494             : 
     495         392 :         const int stopY = s.fPixmap.height();
     496         392 :         switch (s.fTileModeY) {
     497             :             case SkShader::kClamp_TileMode:
     498           0 :                 iY0 = SkClampMax(yTemp, stopY-1);
     499           0 :                 break;
     500             :             case SkShader::kRepeat_TileMode:
     501         392 :                 iY0 = sk_int_mod(yTemp, stopY);
     502         392 :                 break;
     503             :             case SkShader::kMirror_TileMode:
     504             :             default:
     505           0 :                 iY0 = sk_int_mirror(yTemp, stopY);
     506           0 :                 break;
     507             :         }
     508             : 
     509             : #ifdef SK_DEBUG
     510             :         {
     511         392 :             const SkBitmapProcStateAutoMapper mapper(s, x, y);
     512             :             int iY2;
     513             : 
     514         392 :             if (s.fInvType > SkMatrix::kTranslate_Mask &&
     515           0 :                 (SkShader::kClamp_TileMode != s.fTileModeX ||
     516           0 :                  SkShader::kClamp_TileMode != s.fTileModeY)) {
     517           0 :                 iY2 = SkFractionalIntToInt(mapper.fractionalIntY() * s.fPixmap.height());
     518             :             } else {
     519         392 :                 iY2 = mapper.intY();
     520             :             }
     521             : 
     522         392 :             switch (s.fTileModeY) {
     523             :             case SkShader::kClamp_TileMode:
     524           0 :                 iY2 = SkClampMax(iY2, stopY-1);
     525           0 :                 break;
     526             :             case SkShader::kRepeat_TileMode:
     527         392 :                 iY2 = sk_int_mod(iY2, stopY);
     528         392 :                 break;
     529             :             case SkShader::kMirror_TileMode:
     530             :             default:
     531           0 :                 iY2 = sk_int_mirror(iY2, stopY);
     532           0 :                 break;
     533             :             }
     534             : 
     535         392 :             SkASSERT(iY0 == iY2);
     536             :         }
     537             : #endif
     538             :     }
     539             : 
     540         772 :     const SkPMColor* row0 = s.fPixmap.addr32(0, iY0);
     541             :     SkPMColor color;
     542             : 
     543         772 :     if (kNone_SkFilterQuality != s.fFilterQuality) {
     544         380 :         const SkPMColor* row1 = s.fPixmap.addr32(0, iY1);
     545             : 
     546         380 :         if (s.fAlphaScale < 256) {
     547           0 :             Filter_32_alpha(iSubY, *row0, *row1, &color, s.fAlphaScale);
     548             :         } else {
     549         380 :             Filter_32_opaque(iSubY, *row0, *row1, &color);
     550             :         }
     551             :     } else {
     552         392 :         if (s.fAlphaScale < 256) {
     553           0 :             color = SkAlphaMulQ(*row0, s.fAlphaScale);
     554             :         } else {
     555         392 :             color = *row0;
     556             :         }
     557             :     }
     558             : 
     559         772 :     sk_memset32(colors, color, count);
     560         772 : }
     561             : 
     562           0 : static void DoNothing_shaderproc(const void*, int x, int y,
     563             :                                  SkPMColor* SK_RESTRICT colors, int count) {
     564             :     // if we get called, the matrix is too tricky, so we just draw nothing
     565           0 :     sk_memset32(colors, 0, count);
     566           0 : }
     567             : 
     568          83 : bool SkBitmapProcState::setupForTranslate() {
     569             :     SkPoint pt;
     570          83 :     const SkBitmapProcStateAutoMapper mapper(*this, 0, 0, &pt);
     571             : 
     572             :     /*
     573             :      *  if the translate is larger than our ints, we can get random results, or
     574             :      *  worse, we might get 0x80000000, which wreaks havoc on us, since we can't
     575             :      *  negate it.
     576             :      */
     577          83 :     const SkScalar too_big = SkIntToScalar(1 << 30);
     578          83 :     if (SkScalarAbs(pt.fX) > too_big || SkScalarAbs(pt.fY) > too_big) {
     579           0 :         return false;
     580             :     }
     581             : 
     582             :     // Since we know we're not filtered, we re-purpose these fields allow
     583             :     // us to go from device -> src coordinates w/ just an integer add,
     584             :     // rather than running through the inverse-matrix
     585          83 :     fFilterOneX = mapper.intX();
     586          83 :     fFilterOneY = mapper.intY();
     587             : 
     588          83 :     return true;
     589             : }
     590             : 
     591         141 : SkBitmapProcState::ShaderProc32 SkBitmapProcState::chooseShaderProc32() {
     592             : 
     593         141 :     if (kN32_SkColorType != fPixmap.colorType()) {
     594           0 :         return nullptr;
     595             :     }
     596             : 
     597             :     static const unsigned kMask = SkMatrix::kTranslate_Mask | SkMatrix::kScale_Mask;
     598             : 
     599         141 :     if (1 == fPixmap.width() && 0 == (fInvType & ~kMask)) {
     600          45 :         if (kNone_SkFilterQuality == fFilterQuality &&
     601          27 :             fInvType <= SkMatrix::kTranslate_Mask &&
     602           9 :             !this->setupForTranslate()) {
     603           0 :             return DoNothing_shaderproc;
     604             :         }
     605          18 :         return S32_D32_constX_shaderproc;
     606             :     }
     607             : 
     608         123 :     if (fAlphaScale < 256) {
     609           8 :         return nullptr;
     610             :     }
     611         115 :     if (fInvType > SkMatrix::kTranslate_Mask) {
     612          33 :         return nullptr;
     613             :     }
     614          82 :     if (kNone_SkFilterQuality != fFilterQuality) {
     615           0 :         return nullptr;
     616             :     }
     617             : 
     618          82 :     SkShader::TileMode tx = (SkShader::TileMode)fTileModeX;
     619          82 :     SkShader::TileMode ty = (SkShader::TileMode)fTileModeY;
     620             : 
     621          82 :     if (SkShader::kClamp_TileMode == tx && SkShader::kClamp_TileMode == ty) {
     622          65 :         if (this->setupForTranslate()) {
     623          65 :             return Clamp_S32_D32_nofilter_trans_shaderproc;
     624             :         }
     625           0 :         return DoNothing_shaderproc;
     626             :     }
     627          17 :     if (SkShader::kRepeat_TileMode == tx && SkShader::kRepeat_TileMode == ty) {
     628           9 :         if (this->setupForTranslate()) {
     629           9 :             return Repeat_S32_D32_nofilter_trans_shaderproc;
     630             :         }
     631           0 :         return DoNothing_shaderproc;
     632             :     }
     633           8 :     return nullptr;
     634             : }
     635             : 
     636             : ///////////////////////////////////////////////////////////////////////////////
     637             : 
     638             : #ifdef SK_DEBUG
     639             : 
     640        1104 : static void check_scale_nofilter(uint32_t bitmapXY[], int count,
     641             :                                  unsigned mx, unsigned my) {
     642        1104 :     unsigned y = *bitmapXY++;
     643        1104 :     SkASSERT(y < my);
     644             : 
     645        1104 :     const uint16_t* xptr = reinterpret_cast<const uint16_t*>(bitmapXY);
     646      122256 :     for (int i = 0; i < count; ++i) {
     647      121152 :         SkASSERT(xptr[i] < mx);
     648             :     }
     649        1104 : }
     650             : 
     651        1346 : static void check_scale_filter(uint32_t bitmapXY[], int count,
     652             :                                  unsigned mx, unsigned my) {
     653        1346 :     uint32_t YY = *bitmapXY++;
     654        1346 :     unsigned y0 = YY >> 18;
     655        1346 :     unsigned y1 = YY & 0x3FFF;
     656        1346 :     SkASSERT(y0 < my);
     657        1346 :     SkASSERT(y1 < my);
     658             : 
     659       13537 :     for (int i = 0; i < count; ++i) {
     660       12191 :         uint32_t XX = bitmapXY[i];
     661       12191 :         unsigned x0 = XX >> 18;
     662       12191 :         unsigned x1 = XX & 0x3FFF;
     663       12191 :         SkASSERT(x0 < mx);
     664       12191 :         SkASSERT(x1 < mx);
     665             :     }
     666        1346 : }
     667             : 
     668           0 : static void check_affine_nofilter(uint32_t bitmapXY[], int count,
     669             :                                  unsigned mx, unsigned my) {
     670           0 :     for (int i = 0; i < count; ++i) {
     671           0 :         uint32_t XY = bitmapXY[i];
     672           0 :         unsigned x = XY & 0xFFFF;
     673           0 :         unsigned y = XY >> 16;
     674           0 :         SkASSERT(x < mx);
     675           0 :         SkASSERT(y < my);
     676             :     }
     677           0 : }
     678             : 
     679           0 : static void check_affine_filter(uint32_t bitmapXY[], int count,
     680             :                                  unsigned mx, unsigned my) {
     681           0 :     for (int i = 0; i < count; ++i) {
     682           0 :         uint32_t YY = *bitmapXY++;
     683           0 :         unsigned y0 = YY >> 18;
     684           0 :         unsigned y1 = YY & 0x3FFF;
     685           0 :         SkASSERT(y0 < my);
     686           0 :         SkASSERT(y1 < my);
     687             : 
     688           0 :         uint32_t XX = *bitmapXY++;
     689           0 :         unsigned x0 = XX >> 18;
     690           0 :         unsigned x1 = XX & 0x3FFF;
     691           0 :         SkASSERT(x0 < mx);
     692           0 :         SkASSERT(x1 < mx);
     693             :     }
     694           0 : }
     695             : 
     696        2450 : void SkBitmapProcState::DebugMatrixProc(const SkBitmapProcState& state,
     697             :                                         uint32_t bitmapXY[], int count,
     698             :                                         int x, int y) {
     699        2450 :     SkASSERT(bitmapXY);
     700        2450 :     SkASSERT(count > 0);
     701             : 
     702        2450 :     state.fMatrixProc(state, bitmapXY, count, x, y);
     703             : 
     704             :     void (*proc)(uint32_t bitmapXY[], int count, unsigned mx, unsigned my);
     705             : 
     706             :     // There are four formats possible:
     707             :     //  scale -vs- affine
     708             :     //  filter -vs- nofilter
     709        2450 :     if (state.fInvType <= (SkMatrix::kTranslate_Mask | SkMatrix::kScale_Mask)) {
     710        2450 :         proc = state.fFilterQuality != kNone_SkFilterQuality ?
     711             :                     check_scale_filter : check_scale_nofilter;
     712             :     } else {
     713           0 :         proc = state.fFilterQuality != kNone_SkFilterQuality ?
     714             :                     check_affine_filter : check_affine_nofilter;
     715             :     }
     716        2450 :     proc(bitmapXY, count, state.fPixmap.width(), state.fPixmap.height());
     717        2450 : }
     718             : 
     719        2234 : SkBitmapProcState::MatrixProc SkBitmapProcState::getMatrixProc() const {
     720        2234 :     return DebugMatrixProc;
     721             : }
     722             : 
     723             : #endif
     724             : 
     725             : ///////////////////////////////////////////////////////////////////////////////
     726             : /*
     727             :     The storage requirements for the different matrix procs are as follows,
     728             :     where each X or Y is 2 bytes, and N is the number of pixels/elements:
     729             : 
     730             :     scale/translate     nofilter      Y(4bytes) + N * X
     731             :     affine/perspective  nofilter      N * (X Y)
     732             :     scale/translate     filter        Y Y + N * (X X)
     733             :     affine/perspective  filter        N * (Y Y X X)
     734             :  */
     735        1854 : int SkBitmapProcState::maxCountForBufferSize(size_t bufferSize) const {
     736        1854 :     int32_t size = static_cast<int32_t>(bufferSize);
     737             : 
     738        1854 :     size &= ~3; // only care about 4-byte aligned chunks
     739        1854 :     if (fInvType <= (SkMatrix::kTranslate_Mask | SkMatrix::kScale_Mask)) {
     740        1854 :         size -= 4;   // the shared Y (or YY) coordinate
     741        1854 :         if (size < 0) {
     742           0 :             size = 0;
     743             :         }
     744        1854 :         size >>= 1;
     745             :     } else {
     746           0 :         size >>= 2;
     747             :     }
     748             : 
     749        1854 :     if (fFilterQuality != kNone_SkFilterQuality) {
     750         966 :         size >>= 1;
     751             :     }
     752             : 
     753        1854 :     return size;
     754             : }
     755             : 
     756             : ///////////////////////
     757             : 
     758           0 : void  Clamp_S32_opaque_D32_nofilter_DX_shaderproc(const void* sIn, int x, int y,
     759             :                                                   SkPMColor* SK_RESTRICT dst, int count) {
     760           0 :     const SkBitmapProcState& s = *static_cast<const SkBitmapProcState*>(sIn);
     761           0 :     SkASSERT((s.fInvType & ~(SkMatrix::kTranslate_Mask |
     762             :                              SkMatrix::kScale_Mask)) == 0);
     763             : 
     764           0 :     const unsigned maxX = s.fPixmap.width() - 1;
     765             :     SkFractionalInt fx;
     766             :     int dstY;
     767             :     {
     768           0 :         const SkBitmapProcStateAutoMapper mapper(s, x, y);
     769           0 :         const unsigned maxY = s.fPixmap.height() - 1;
     770           0 :         dstY = SkClampMax(mapper.intY(), maxY);
     771           0 :         fx = mapper.fractionalIntX();
     772             :     }
     773             : 
     774           0 :     const SkPMColor* SK_RESTRICT src = s.fPixmap.addr32(0, dstY);
     775           0 :     const SkFractionalInt dx = s.fInvSxFractionalInt;
     776             : 
     777             :     // Check if we're safely inside [0...maxX] so no need to clamp each computed index.
     778             :     //
     779           0 :     if ((uint64_t)SkFractionalIntToInt(fx) <= maxX &&
     780           0 :         (uint64_t)SkFractionalIntToInt(fx + dx * (count - 1)) <= maxX)
     781             :     {
     782           0 :         int count4 = count >> 2;
     783           0 :         for (int i = 0; i < count4; ++i) {
     784           0 :             SkPMColor src0 = src[SkFractionalIntToInt(fx)]; fx += dx;
     785           0 :             SkPMColor src1 = src[SkFractionalIntToInt(fx)]; fx += dx;
     786           0 :             SkPMColor src2 = src[SkFractionalIntToInt(fx)]; fx += dx;
     787           0 :             SkPMColor src3 = src[SkFractionalIntToInt(fx)]; fx += dx;
     788           0 :             dst[0] = src0;
     789           0 :             dst[1] = src1;
     790           0 :             dst[2] = src2;
     791           0 :             dst[3] = src3;
     792           0 :             dst += 4;
     793             :         }
     794           0 :         for (int i = (count4 << 2); i < count; ++i) {
     795           0 :             unsigned index = SkFractionalIntToInt(fx);
     796           0 :             SkASSERT(index <= maxX);
     797           0 :             *dst++ = src[index];
     798           0 :             fx += dx;
     799           0 :         }
     800             :     } else {
     801           0 :         for (int i = 0; i < count; ++i) {
     802           0 :             dst[i] = src[SkClampMax(SkFractionalIntToInt(fx), maxX)];
     803           0 :             fx += dx;
     804             :         }
     805             :     }
     806           0 : }

Generated by: LCOV version 1.13