Home | History | Annotate | Download | only in core
      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 "SkBitmapCache.h"
     10 #include "SkBitmapController.h"
     11 #include "SkBitmapProvider.h"
     12 #include "SkMatrix.h"
     13 #include "SkMipMap.h"
     14 #include "SkTemplates.h"
     15 
     16 ///////////////////////////////////////////////////////////////////////////////////////////////////
     17 
     18 SkBitmapController::State* SkBitmapController::requestBitmap(const SkBitmapProvider& provider,
     19                                                              const SkMatrix& inv,
     20                                                              SkFilterQuality quality,
     21                                                              void* storage, size_t storageSize) {
     22     State* state = this->onRequestBitmap(provider, inv, quality, storage, storageSize);
     23     if (state) {
     24         if (nullptr == state->fPixmap.addr()) {
     25             SkInPlaceDeleteCheck(state, storage);
     26             state = nullptr;
     27         }
     28     }
     29     return state;
     30 }
     31 
     32 ///////////////////////////////////////////////////////////////////////////////////////////////////
     33 
     34 class SkDefaultBitmapControllerState : public SkBitmapController::State {
     35 public:
     36     SkDefaultBitmapControllerState(const SkBitmapProvider&, const SkMatrix& inv, SkFilterQuality);
     37 
     38 private:
     39     SkBitmap                fResultBitmap;
     40     sk_sp<const SkMipMap>   fCurrMip;
     41 
     42     bool processHighRequest(const SkBitmapProvider&);
     43     bool processMediumRequest(const SkBitmapProvider&);
     44 };
     45 
     46 bool SkDefaultBitmapControllerState::processHighRequest(const SkBitmapProvider& provider) {
     47     if (fQuality != kHigh_SkFilterQuality) {
     48         return false;
     49     }
     50 
     51     fQuality = kMedium_SkFilterQuality;
     52 
     53     SkScalar invScaleX = fInvMatrix.getScaleX();
     54     SkScalar invScaleY = fInvMatrix.getScaleY();
     55     if (fInvMatrix.getType() & SkMatrix::kAffine_Mask) {
     56         SkSize scale;
     57         if (!fInvMatrix.decomposeScale(&scale)) {
     58             return false;
     59         }
     60         invScaleX = scale.width();
     61         invScaleY = scale.height();
     62     }
     63     invScaleX = SkScalarAbs(invScaleX);
     64     invScaleY = SkScalarAbs(invScaleY);
     65 
     66     if (invScaleX >= 1 - SK_ScalarNearlyZero || invScaleY >= 1 - SK_ScalarNearlyZero) {
     67         // we're down-scaling so abort HQ
     68         return false;
     69     }
     70 
     71     // Confirmed that we can use HQ (w/ rasterpipeline)
     72     fQuality = kHigh_SkFilterQuality;
     73     (void)provider.asBitmap(&fResultBitmap);
     74     return true;
     75 }
     76 
     77 /*
     78  *  Modulo internal errors, this should always succeed *if* the matrix is downscaling
     79  *  (in this case, we have the inverse, so it succeeds if fInvMatrix is upscaling)
     80  */
     81 bool SkDefaultBitmapControllerState::processMediumRequest(const SkBitmapProvider& provider) {
     82     SkASSERT(fQuality <= kMedium_SkFilterQuality);
     83     if (fQuality != kMedium_SkFilterQuality) {
     84         return false;
     85     }
     86 
     87     // Our default return state is to downgrade the request to Low, w/ or w/o setting fBitmap
     88     // to a valid bitmap.
     89     fQuality = kLow_SkFilterQuality;
     90 
     91     SkSize invScaleSize;
     92     if (!fInvMatrix.decomposeScale(&invScaleSize, nullptr)) {
     93         return false;
     94     }
     95 
     96     SkDestinationSurfaceColorMode colorMode = provider.dstColorSpace()
     97         ? SkDestinationSurfaceColorMode::kGammaAndColorSpaceAware
     98         : SkDestinationSurfaceColorMode::kLegacy;
     99     if (invScaleSize.width() > SK_Scalar1 || invScaleSize.height() > SK_Scalar1) {
    100         fCurrMip.reset(SkMipMapCache::FindAndRef(provider.makeCacheDesc(), colorMode));
    101         if (nullptr == fCurrMip.get()) {
    102             SkBitmap orig;
    103             if (!provider.asBitmap(&orig)) {
    104                 return false;
    105             }
    106             fCurrMip.reset(SkMipMapCache::AddAndRef(orig, colorMode));
    107             if (nullptr == fCurrMip.get()) {
    108                 return false;
    109             }
    110         }
    111         // diagnostic for a crasher...
    112         SkASSERT_RELEASE(fCurrMip->data());
    113 
    114         const SkSize scale = SkSize::Make(SkScalarInvert(invScaleSize.width()),
    115                                           SkScalarInvert(invScaleSize.height()));
    116         SkMipMap::Level level;
    117         if (fCurrMip->extractLevel(scale, &level)) {
    118             const SkSize& invScaleFixup = level.fScale;
    119             fInvMatrix.postScale(invScaleFixup.width(), invScaleFixup.height());
    120 
    121             // todo: if we could wrap the fCurrMip in a pixelref, then we could just install
    122             //       that here, and not need to explicitly track it ourselves.
    123             return fResultBitmap.installPixels(level.fPixmap);
    124         } else {
    125             // failed to extract, so release the mipmap
    126             fCurrMip.reset(nullptr);
    127         }
    128     }
    129     return false;
    130 }
    131 
    132 SkDefaultBitmapControllerState::SkDefaultBitmapControllerState(const SkBitmapProvider& provider,
    133                                                                const SkMatrix& inv,
    134                                                                SkFilterQuality qual) {
    135     fInvMatrix = inv;
    136     fQuality = qual;
    137 
    138     if (this->processHighRequest(provider) || this->processMediumRequest(provider)) {
    139         SkASSERT(fResultBitmap.getPixels());
    140     } else {
    141         (void)provider.asBitmap(&fResultBitmap);
    142     }
    143 
    144     // fResultBitmap.getPixels() may be null, but our caller knows to check fPixmap.addr()
    145     // and will destroy us if it is nullptr.
    146     fPixmap.reset(fResultBitmap.info(), fResultBitmap.getPixels(), fResultBitmap.rowBytes());
    147 }
    148 
    149 SkBitmapController::State* SkDefaultBitmapController::onRequestBitmap(const SkBitmapProvider& bm,
    150                                                                       const SkMatrix& inverse,
    151                                                                       SkFilterQuality quality,
    152                                                                       void* storage, size_t size) {
    153     return SkInPlaceNewCheck<SkDefaultBitmapControllerState>(storage, size, bm, inverse, quality);
    154 }
    155