| Index: src/core/SkBitmapController.cpp
|
| diff --git a/src/core/SkBitmapController.cpp b/src/core/SkBitmapController.cpp
|
| index 3c3e69413ab2e12f3dbbc66ca28fd56aa996a446..c75d2ea6bc825c497862c7193b7d74815b105669 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) {
|
|
|