LCOV - code coverage report
Current view: top level - gfx/skia/skia/src/core - SkBitmapController.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 29 122 23.8 %
Date: 2017-07-14 16:53:18 Functions: 7 8 87.5 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :  * Copyright 2015 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 "SkBitmap.h"
       9             : #include "SkBitmapController.h"
      10             : #include "SkBitmapProvider.h"
      11             : #include "SkMatrix.h"
      12             : #include "SkPixelRef.h"
      13             : #include "SkTemplates.h"
      14             : 
      15             : // RESIZE_LANCZOS3 is another good option, but chrome prefers mitchell at the moment
      16             : #define kHQ_RESIZE_METHOD   SkBitmapScaler::RESIZE_MITCHELL
      17             : 
      18             : ///////////////////////////////////////////////////////////////////////////////////////////////////
      19             : 
      20         141 : SkBitmapController::State* SkBitmapController::requestBitmap(const SkBitmapProvider& provider,
      21             :                                                              const SkMatrix& inv,
      22             :                                                              SkFilterQuality quality,
      23             :                                                              void* storage, size_t storageSize) {
      24         141 :     State* state = this->onRequestBitmap(provider, inv, quality, storage, storageSize);
      25         141 :     if (state) {
      26         141 :         if (nullptr == state->fPixmap.addr()) {
      27           0 :             SkInPlaceDeleteCheck(state, storage);
      28           0 :             state = nullptr;
      29             :         }
      30             :     }
      31         141 :     return state;
      32             : }
      33             : 
      34             : ///////////////////////////////////////////////////////////////////////////////////////////////////
      35             : 
      36             : #include "SkBitmapCache.h"
      37             : #include "SkBitmapScaler.h"
      38             : #include "SkMipMap.h"
      39             : #include "SkResourceCache.h"
      40             : 
      41         423 : class SkDefaultBitmapControllerState : public SkBitmapController::State {
      42             : public:
      43             :     SkDefaultBitmapControllerState(const SkBitmapProvider&,
      44             :                                    const SkMatrix& inv,
      45             :                                    SkFilterQuality,
      46             :                                    bool canShadeHQ);
      47             : 
      48             : private:
      49             :     SkBitmap                      fResultBitmap;
      50             :     sk_sp<const SkMipMap>         fCurrMip;
      51             :     bool                          fCanShadeHQ;
      52             : 
      53             :     bool processHQRequest(const SkBitmapProvider&);
      54             :     bool processMediumRequest(const SkBitmapProvider&);
      55             : };
      56             : 
      57             : // Check to see that the size of the bitmap that would be produced by
      58             : // scaling by the given inverted matrix is less than the maximum allowed.
      59           0 : static inline bool cache_size_okay(const SkBitmapProvider& provider, const SkMatrix& invMat) {
      60           0 :     size_t maximumAllocation = SkResourceCache::GetEffectiveSingleAllocationByteLimit();
      61           0 :     if (0 == maximumAllocation) {
      62           0 :         return true;
      63             :     }
      64             :     // float matrixScaleFactor = 1.0 / (invMat.scaleX * invMat.scaleY);
      65             :     // return ((origBitmapSize * matrixScaleFactor) < maximumAllocationSize);
      66             :     // Skip the division step:
      67           0 :     const size_t size = provider.info().getSafeSize(provider.info().minRowBytes());
      68           0 :     SkScalar invScaleSqr = invMat.getScaleX() * invMat.getScaleY();
      69           0 :     return size < (maximumAllocation * SkScalarAbs(invScaleSqr));
      70             : }
      71             : 
      72             : /*
      73             :  *  High quality is implemented by performing up-right scale-only filtering and then
      74             :  *  using bilerp for any remaining transformations.
      75             :  */
      76         141 : bool SkDefaultBitmapControllerState::processHQRequest(const SkBitmapProvider& provider) {
      77         141 :     if (fQuality != kHigh_SkFilterQuality) {
      78         141 :         return false;
      79             :     }
      80             : 
      81             :     // Our default return state is to downgrade the request to Medium, w/ or w/o setting fBitmap
      82             :     // to a valid bitmap. If we succeed, we will set this to Low instead.
      83           0 :     fQuality = kMedium_SkFilterQuality;
      84             : #ifdef SK_USE_MIP_FOR_DOWNSCALE_HQ
      85             :     return false;
      86             : #endif
      87             : 
      88           0 :     if (kN32_SkColorType != provider.info().colorType() || !cache_size_okay(provider, fInvMatrix) ||
      89           0 :         fInvMatrix.hasPerspective())
      90             :     {
      91           0 :         return false; // can't handle the reqeust
      92             :     }
      93             : 
      94           0 :     SkScalar invScaleX = fInvMatrix.getScaleX();
      95           0 :     SkScalar invScaleY = fInvMatrix.getScaleY();
      96           0 :     if (fInvMatrix.getType() & SkMatrix::kAffine_Mask) {
      97             :         SkSize scale;
      98           0 :         if (!fInvMatrix.decomposeScale(&scale)) {
      99           0 :             return false;
     100             :         }
     101           0 :         invScaleX = scale.width();
     102           0 :         invScaleY = scale.height();
     103             :     }
     104           0 :     invScaleX = SkScalarAbs(invScaleX);
     105           0 :     invScaleY = SkScalarAbs(invScaleY);
     106             : 
     107           0 :     if (SkScalarNearlyEqual(invScaleX, 1) && SkScalarNearlyEqual(invScaleY, 1)) {
     108           0 :         return false; // no need for HQ
     109             :     }
     110             : 
     111           0 :     if (invScaleX > 1 || invScaleY > 1) {
     112           0 :         return false; // only use HQ when upsampling
     113             :     }
     114             : 
     115             :     // If the shader can natively handle HQ filtering, let it do it.
     116           0 :     if (fCanShadeHQ) {
     117           0 :         fQuality = kHigh_SkFilterQuality;
     118           0 :         SkAssertResult(provider.asBitmap(&fResultBitmap));
     119           0 :         fResultBitmap.lockPixels();
     120           0 :         return true;
     121             :     }
     122             : 
     123           0 :     const int dstW = SkScalarRoundToScalar(provider.width() / invScaleX);
     124           0 :     const int dstH = SkScalarRoundToScalar(provider.height() / invScaleY);
     125           0 :     const SkBitmapCacheDesc desc = provider.makeCacheDesc(dstW, dstH);
     126             : 
     127           0 :     if (!SkBitmapCache::Find(desc, &fResultBitmap)) {
     128           0 :         SkBitmap orig;
     129           0 :         if (!provider.asBitmap(&orig)) {
     130           0 :             return false;
     131             :         }
     132           0 :         SkAutoPixmapUnlock src;
     133           0 :         if (!orig.requestLock(&src)) {
     134           0 :             return false;
     135             :         }
     136             : 
     137           0 :         SkPixmap dst;
     138           0 :         SkBitmapCache::RecPtr rec;
     139           0 :         const SkImageInfo info = SkImageInfo::MakeN32(desc.fScaledWidth, desc.fScaledHeight,
     140           0 :                                                       src.pixmap().alphaType());
     141           0 :         if (provider.isVolatile()) {
     142           0 :             if (!fResultBitmap.tryAllocPixels(info)) {
     143           0 :                 return false;
     144             :             }
     145           0 :             SkASSERT(fResultBitmap.getPixels());
     146           0 :             fResultBitmap.peekPixels(&dst);
     147           0 :             fResultBitmap.setImmutable();   // a little cheat, as we haven't resized yet, but ok
     148             :         } else {
     149           0 :             rec = SkBitmapCache::Alloc(desc, info, &dst);
     150           0 :             if (!rec) {
     151           0 :                 return false;
     152             :             }
     153             :         }
     154           0 :         if (!SkBitmapScaler::Resize(dst, src.pixmap(), kHQ_RESIZE_METHOD)) {
     155           0 :             return false; // we failed to create fScaledBitmap
     156             :         }
     157           0 :         if (rec) {
     158           0 :             SkBitmapCache::Add(std::move(rec), &fResultBitmap);
     159           0 :             SkASSERT(fResultBitmap.getPixels());
     160           0 :             provider.notifyAddedToCache();
     161             :         }
     162             :     }
     163             : 
     164           0 :     SkASSERT(fResultBitmap.getPixels());
     165           0 :     SkASSERT(fResultBitmap.isImmutable());
     166             : 
     167           0 :     fInvMatrix.postScale(SkIntToScalar(dstW) / provider.width(),
     168           0 :                          SkIntToScalar(dstH) / provider.height());
     169           0 :     fQuality = kLow_SkFilterQuality;
     170           0 :     return true;
     171             : }
     172             : 
     173             : /*
     174             :  *  Modulo internal errors, this should always succeed *if* the matrix is downscaling
     175             :  *  (in this case, we have the inverse, so it succeeds if fInvMatrix is upscaling)
     176             :  */
     177         141 : bool SkDefaultBitmapControllerState::processMediumRequest(const SkBitmapProvider& provider) {
     178         141 :     SkASSERT(fQuality <= kMedium_SkFilterQuality);
     179         141 :     if (fQuality != kMedium_SkFilterQuality) {
     180         141 :         return false;
     181             :     }
     182             : 
     183             :     // Our default return state is to downgrade the request to Low, w/ or w/o setting fBitmap
     184             :     // to a valid bitmap.
     185           0 :     fQuality = kLow_SkFilterQuality;
     186             : 
     187             :     SkSize invScaleSize;
     188           0 :     if (!fInvMatrix.decomposeScale(&invScaleSize, nullptr)) {
     189           0 :         return false;
     190             :     }
     191             : 
     192           0 :     SkDestinationSurfaceColorMode colorMode = provider.dstColorSpace()
     193           0 :         ? SkDestinationSurfaceColorMode::kGammaAndColorSpaceAware
     194           0 :         : SkDestinationSurfaceColorMode::kLegacy;
     195           0 :     if (invScaleSize.width() > SK_Scalar1 || invScaleSize.height() > SK_Scalar1) {
     196           0 :         fCurrMip.reset(SkMipMapCache::FindAndRef(provider.makeCacheDesc(), colorMode));
     197           0 :         if (nullptr == fCurrMip.get()) {
     198           0 :             SkBitmap orig;
     199           0 :             if (!provider.asBitmap(&orig)) {
     200           0 :                 return false;
     201             :             }
     202           0 :             fCurrMip.reset(SkMipMapCache::AddAndRef(orig, colorMode));
     203           0 :             if (nullptr == fCurrMip.get()) {
     204           0 :                 return false;
     205             :             }
     206             :         }
     207             :         // diagnostic for a crasher...
     208           0 :         if (nullptr == fCurrMip->data()) {
     209           0 :             sk_throw();
     210             :         }
     211             : 
     212           0 :         const SkSize scale = SkSize::Make(SkScalarInvert(invScaleSize.width()),
     213           0 :                                           SkScalarInvert(invScaleSize.height()));
     214           0 :         SkMipMap::Level level;
     215           0 :         if (fCurrMip->extractLevel(scale, &level)) {
     216           0 :             const SkSize& invScaleFixup = level.fScale;
     217           0 :             fInvMatrix.postScale(invScaleFixup.width(), invScaleFixup.height());
     218             : 
     219             :             // todo: if we could wrap the fCurrMip in a pixelref, then we could just install
     220             :             //       that here, and not need to explicitly track it ourselves.
     221           0 :             return fResultBitmap.installPixels(level.fPixmap);
     222             :         } else {
     223             :             // failed to extract, so release the mipmap
     224           0 :             fCurrMip.reset(nullptr);
     225             :         }
     226             :     }
     227           0 :     return false;
     228             : }
     229             : 
     230         141 : SkDefaultBitmapControllerState::SkDefaultBitmapControllerState(const SkBitmapProvider& provider,
     231             :                                                                const SkMatrix& inv,
     232             :                                                                SkFilterQuality qual,
     233         141 :                                                                bool canShadeHQ) {
     234         141 :     fInvMatrix = inv;
     235         141 :     fQuality = qual;
     236         141 :     fCanShadeHQ = canShadeHQ;
     237             : 
     238         141 :     bool processed = this->processHQRequest(provider) || this->processMediumRequest(provider);
     239             : 
     240         141 :     if (processed) {
     241           0 :         SkASSERT(fResultBitmap.getPixels());
     242             :     } else {
     243         141 :         (void)provider.asBitmap(&fResultBitmap);
     244         141 :         fResultBitmap.lockPixels();
     245             :         // lock may fail to give us pixels
     246             :     }
     247         141 :     SkASSERT(fCanShadeHQ || fQuality <= kLow_SkFilterQuality);
     248             : 
     249             :     // fResultBitmap.getPixels() may be null, but our caller knows to check fPixmap.addr()
     250             :     // and will destroy us if it is nullptr.
     251         141 :     fPixmap.reset(fResultBitmap.info(), fResultBitmap.getPixels(), fResultBitmap.rowBytes(),
     252         141 :                   fResultBitmap.getColorTable());
     253         141 : }
     254             : 
     255         141 : SkBitmapController::State* SkDefaultBitmapController::onRequestBitmap(const SkBitmapProvider& bm,
     256             :                                                                       const SkMatrix& inverse,
     257             :                                                                       SkFilterQuality quality,
     258             :                                                                       void* storage, size_t size) {
     259         141 :     return SkInPlaceNewCheck<SkDefaultBitmapControllerState>(storage, size,
     260         141 :                                                              bm, inverse, quality, fCanShadeHQ);
     261             : }

Generated by: LCOV version 1.13