diff options
Diffstat (limited to 'src/core/SkBitmapController.cpp')
-rw-r--r-- | src/core/SkBitmapController.cpp | 144 |
1 files changed, 103 insertions, 41 deletions
diff --git a/src/core/SkBitmapController.cpp b/src/core/SkBitmapController.cpp index 3c3e69413a..c75d2ea6bc 100644 --- a/src/core/SkBitmapController.cpp +++ b/src/core/SkBitmapController.cpp @@ -7,7 +7,9 @@ #include "SkBitmap.h" #include "SkBitmapController.h" +#include "SkImage_Base.h" #include "SkMatrix.h" +#include "SkPixelRef.h" #include "SkTemplates.h" // RESIZE_LANCZOS3 is another good option, but chrome prefers mitchell at the moment @@ -15,36 +17,85 @@ /////////////////////////////////////////////////////////////////////////////////////////////////// -static bool valid_for_drawing(const SkBitmap& bm) { - if (0 == bm.width() || 0 == bm.height()) { - return false; // nothing to draw - } - if (nullptr == bm.pixelRef()) { - return false; // no pixels to read - } - if (bm.getTexture()) { - // we can handle texture (ugh) since lockPixels will perform a read-back - return true; - } - if (kIndex_8_SkColorType == bm.colorType()) { - SkAutoLockPixels alp(bm); // but we need to call it before getColorTable() is safe. - if (!bm.getColorTable()) { +int SkBitmapProvider::width() const { + return fImage ? fImage->width() : fBitmap.width(); +} + +int SkBitmapProvider::height() const { + return fImage ? fImage->height() : fBitmap.height(); +} + +uint32_t SkBitmapProvider::getID() const { + return fImage ? fImage->uniqueID() : fBitmap.getGenerationID(); +} + +bool SkBitmapProvider::validForDrawing() const { + if (!fImage) { + if (0 == fBitmap.width() || 0 == fBitmap.height()) { return false; } + if (nullptr == fBitmap.pixelRef()) { + return false; // no pixels to read + } + if (fBitmap.getTexture()) { + // we can handle texture (ugh) since lockPixels will perform a read-back + return true; + } + if (kIndex_8_SkColorType == fBitmap.colorType()) { + SkAutoLockPixels alp(fBitmap); // but we need to call it before getColorTable() is safe. + if (!fBitmap.getColorTable()) { + return false; + } + } } return true; } -SkBitmapController::State* SkBitmapController::requestBitmap(const SkBitmap& bm, +SkImageInfo SkBitmapProvider::info() const { + if (fImage) { + SkAlphaType at = fImage->isOpaque() ? kOpaque_SkAlphaType : kPremul_SkAlphaType; + return SkImageInfo::MakeN32(fImage->width(), fImage->height(), at); + } else { + return fBitmap.info(); + } +} + +SkBitmapCacheDesc SkBitmapProvider::makeCacheDesc(int w, int h) const { + return fImage ? SkBitmapCacheDesc::Make(fImage, w, h) : SkBitmapCacheDesc::Make(fBitmap, w, h); +} + +SkBitmapCacheDesc SkBitmapProvider::makeCacheDesc() const { + return fImage ? SkBitmapCacheDesc::Make(fImage) : SkBitmapCacheDesc::Make(fBitmap); +} + +void SkBitmapProvider::notifyAddedToCache() const { + if (fImage) { + // TODO + } else { + fBitmap.pixelRef()->notifyAddedToCache(); + } +} + +bool SkBitmapProvider::asBitmap(SkBitmap* bm) const { + if (fImage) { + return as_IB(fImage)->getROPixels(bm); + } else { + *bm = fBitmap; + return true; + } +} + +/////////////////////////////////////////////////////////////////////////////////////////////////// + +SkBitmapController::State* SkBitmapController::requestBitmap(const SkBitmapProvider& provider, const SkMatrix& inv, SkFilterQuality quality, void* storage, size_t storageSize) { - - if (!valid_for_drawing(bm)) { + if (!provider.validForDrawing()) { return nullptr; } - State* state = this->onRequestBitmap(bm, inv, quality, storage, storageSize); + State* state = this->onRequestBitmap(provider, inv, quality, storage, storageSize); if (state) { if (nullptr == state->fPixmap.addr()) { SkInPlaceDeleteCheck(state, storage); @@ -63,19 +114,19 @@ SkBitmapController::State* SkBitmapController::requestBitmap(const SkBitmap& bm, class SkDefaultBitmapControllerState : public SkBitmapController::State { public: - SkDefaultBitmapControllerState(const SkBitmap& src, const SkMatrix& inv, SkFilterQuality qual); + SkDefaultBitmapControllerState(const SkBitmapProvider&, const SkMatrix& inv, SkFilterQuality); private: SkBitmap fResultBitmap; SkAutoTUnref<const SkMipMap> fCurrMip; - bool processHQRequest(const SkBitmap& orig); - bool processMediumRequest(const SkBitmap& orig); + bool processHQRequest(const SkBitmapProvider&); + bool processMediumRequest(const SkBitmapProvider&); }; // Check to see that the size of the bitmap that would be produced by // scaling by the given inverted matrix is less than the maximum allowed. -static inline bool cache_size_okay(const SkBitmap& bm, const SkMatrix& invMat) { +static inline bool cache_size_okay(const SkBitmapProvider& provider, const SkMatrix& invMat) { size_t maximumAllocation = SkResourceCache::GetEffectiveSingleAllocationByteLimit(); if (0 == maximumAllocation) { return true; @@ -83,7 +134,7 @@ static inline bool cache_size_okay(const SkBitmap& bm, const SkMatrix& invMat) { // float matrixScaleFactor = 1.0 / (invMat.scaleX * invMat.scaleY); // return ((origBitmapSize * matrixScaleFactor) < maximumAllocationSize); // Skip the division step: - const size_t size = bm.info().getSafeSize(bm.info().minRowBytes()); + const size_t size = provider.info().getSafeSize(provider.info().minRowBytes()); return size < (maximumAllocation * invMat.getScaleX() * invMat.getScaleY()); } @@ -91,7 +142,7 @@ static inline bool cache_size_okay(const SkBitmap& bm, const SkMatrix& invMat) { * High quality is implemented by performing up-right scale-only filtering and then * using bilerp for any remaining transformations. */ -bool SkDefaultBitmapControllerState::processHQRequest(const SkBitmap& origBitmap) { +bool SkDefaultBitmapControllerState::processHQRequest(const SkBitmapProvider& provider) { if (fQuality != kHigh_SkFilterQuality) { return false; } @@ -100,7 +151,7 @@ bool SkDefaultBitmapControllerState::processHQRequest(const SkBitmap& origBitmap // to a valid bitmap. If we succeed, we will set this to Low instead. fQuality = kMedium_SkFilterQuality; - if (kN32_SkColorType != origBitmap.colorType() || !cache_size_okay(origBitmap, fInvMatrix) || + if (kN32_SkColorType != provider.info().colorType() || !cache_size_okay(provider, fInvMatrix) || fInvMatrix.hasPerspective()) { return false; // can't handle the reqeust @@ -120,12 +171,17 @@ bool SkDefaultBitmapControllerState::processHQRequest(const SkBitmap& origBitmap return false; // no need for HQ } - const int dstW = SkScalarRoundToScalar(origBitmap.width() / invScaleX); - const int dstH = SkScalarRoundToScalar(origBitmap.height() / invScaleY); - - if (!SkBitmapCache::FindWH(origBitmap, dstW, dstH, &fResultBitmap)) { + const int dstW = SkScalarRoundToScalar(provider.width() / invScaleX); + const int dstH = SkScalarRoundToScalar(provider.height() / invScaleY); + const SkBitmapCacheDesc desc = provider.makeCacheDesc(dstW, dstH); + + if (!SkBitmapCache::FindWH(desc, &fResultBitmap)) { + SkBitmap orig; + if (!provider.asBitmap(&orig)) { + return false; + } SkAutoPixmapUnlock src; - if (!origBitmap.requestLock(&src)) { + if (!orig.requestLock(&src)) { return false; } if (!SkBitmapScaler::Resize(&fResultBitmap, src.pixmap(), kHQ_RESIZE_METHOD, @@ -135,13 +191,15 @@ bool SkDefaultBitmapControllerState::processHQRequest(const SkBitmap& origBitmap SkASSERT(fResultBitmap.getPixels()); fResultBitmap.setImmutable(); - SkBitmapCache::AddWH(origBitmap, dstW, dstH, fResultBitmap); + if (SkBitmapCache::AddWH(desc, fResultBitmap)) { + provider.notifyAddedToCache(); + } } SkASSERT(fResultBitmap.getPixels()); - fInvMatrix.postScale(SkIntToScalar(dstW) / origBitmap.width(), - SkIntToScalar(dstH) / origBitmap.height()); + fInvMatrix.postScale(SkIntToScalar(dstW) / provider.width(), + SkIntToScalar(dstH) / provider.height()); fQuality = kLow_SkFilterQuality; return true; } @@ -150,7 +208,7 @@ bool SkDefaultBitmapControllerState::processHQRequest(const SkBitmap& origBitmap * Modulo internal errors, this should always succeed *if* the matrix is downscaling * (in this case, we have the inverse, so it succeeds if fInvMatrix is upscaling) */ -bool SkDefaultBitmapControllerState::processMediumRequest(const SkBitmap& origBitmap) { +bool SkDefaultBitmapControllerState::processMediumRequest(const SkBitmapProvider& provider) { SkASSERT(fQuality <= kMedium_SkFilterQuality); if (fQuality != kMedium_SkFilterQuality) { return false; @@ -167,9 +225,13 @@ bool SkDefaultBitmapControllerState::processMediumRequest(const SkBitmap& origBi SkScalar invScale = SkScalarSqrt(invScaleSize.width() * invScaleSize.height()); if (invScale > SK_Scalar1) { - fCurrMip.reset(SkMipMapCache::FindAndRef(origBitmap)); + fCurrMip.reset(SkMipMapCache::FindAndRef(provider.makeCacheDesc())); if (nullptr == fCurrMip.get()) { - fCurrMip.reset(SkMipMapCache::AddAndRef(origBitmap)); + SkBitmap orig; + if (!provider.asBitmap(&orig)) { + return false; + } + fCurrMip.reset(SkMipMapCache::AddAndRef(orig)); if (nullptr == fCurrMip.get()) { return false; } @@ -185,7 +247,7 @@ bool SkDefaultBitmapControllerState::processMediumRequest(const SkBitmap& origBi SkScalar invScaleFixup = level.fScale; fInvMatrix.postScale(invScaleFixup, invScaleFixup); - const SkImageInfo info = origBitmap.info().makeWH(level.fWidth, level.fHeight); + const SkImageInfo info = provider.info().makeWH(level.fWidth, level.fHeight); // todo: if we could wrap the fCurrMip in a pixelref, then we could just install // that here, and not need to explicitly track it ourselves. return fResultBitmap.installPixels(info, level.fPixels, level.fRowBytes); @@ -197,16 +259,16 @@ bool SkDefaultBitmapControllerState::processMediumRequest(const SkBitmap& origBi return false; } -SkDefaultBitmapControllerState::SkDefaultBitmapControllerState(const SkBitmap& src, +SkDefaultBitmapControllerState::SkDefaultBitmapControllerState(const SkBitmapProvider& provider, const SkMatrix& inv, SkFilterQuality qual) { fInvMatrix = inv; fQuality = qual; - if (this->processHQRequest(src) || this->processMediumRequest(src)) { + if (this->processHQRequest(provider) || this->processMediumRequest(provider)) { SkASSERT(fResultBitmap.getPixels()); } else { - fResultBitmap = src; + (void)provider.asBitmap(&fResultBitmap); fResultBitmap.lockPixels(); // lock may fail to give us pixels } @@ -218,7 +280,7 @@ SkDefaultBitmapControllerState::SkDefaultBitmapControllerState(const SkBitmap& s fResultBitmap.getColorTable()); } -SkBitmapController::State* SkDefaultBitmapController::onRequestBitmap(const SkBitmap& bm, +SkBitmapController::State* SkDefaultBitmapController::onRequestBitmap(const SkBitmapProvider& bm, const SkMatrix& inverse, SkFilterQuality quality, void* storage, size_t size) { |