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