1cb93a386Sopenharmony_ci/* 2cb93a386Sopenharmony_ci * Copyright 2015 Google Inc. 3cb93a386Sopenharmony_ci * 4cb93a386Sopenharmony_ci * Use of this source code is governed by a BSD-style license that can be 5cb93a386Sopenharmony_ci * found in the LICENSE file. 6cb93a386Sopenharmony_ci */ 7cb93a386Sopenharmony_ci 8cb93a386Sopenharmony_ci#include "include/core/SkBitmap.h" 9cb93a386Sopenharmony_ci#include "include/core/SkMatrix.h" 10cb93a386Sopenharmony_ci#include "include/private/SkTemplates.h" 11cb93a386Sopenharmony_ci#include "src/core/SkArenaAlloc.h" 12cb93a386Sopenharmony_ci#include "src/core/SkBitmapCache.h" 13cb93a386Sopenharmony_ci#include "src/core/SkMipmap.h" 14cb93a386Sopenharmony_ci#include "src/core/SkMipmapAccessor.h" 15cb93a386Sopenharmony_ci#include "src/image/SkImage_Base.h" 16cb93a386Sopenharmony_ci 17cb93a386Sopenharmony_ci// Try to load from the base image, or from the cache 18cb93a386Sopenharmony_cistatic sk_sp<const SkMipmap> try_load_mips(const SkImage_Base* image) { 19cb93a386Sopenharmony_ci sk_sp<const SkMipmap> mips = image->refMips(); 20cb93a386Sopenharmony_ci if (!mips) { 21cb93a386Sopenharmony_ci mips.reset(SkMipmapCache::FindAndRef(SkBitmapCacheDesc::Make(image))); 22cb93a386Sopenharmony_ci } 23cb93a386Sopenharmony_ci if (!mips) { 24cb93a386Sopenharmony_ci mips.reset(SkMipmapCache::AddAndRef(image)); 25cb93a386Sopenharmony_ci } 26cb93a386Sopenharmony_ci return mips; 27cb93a386Sopenharmony_ci} 28cb93a386Sopenharmony_ci 29cb93a386Sopenharmony_ciSkMipmapAccessor::SkMipmapAccessor(const SkImage_Base* image, const SkMatrix& inv, 30cb93a386Sopenharmony_ci SkMipmapMode requestedMode) { 31cb93a386Sopenharmony_ci fResolvedMode = requestedMode; 32cb93a386Sopenharmony_ci fLowerWeight = 0; 33cb93a386Sopenharmony_ci 34cb93a386Sopenharmony_ci auto load_upper_from_base = [&]() { 35cb93a386Sopenharmony_ci // only do this once 36cb93a386Sopenharmony_ci if (fBaseStorage.getPixels() == nullptr) { 37cb93a386Sopenharmony_ci (void)image->getROPixels(nullptr, &fBaseStorage); 38cb93a386Sopenharmony_ci fUpper.reset(fBaseStorage.info(), fBaseStorage.getPixels(), fBaseStorage.rowBytes()); 39cb93a386Sopenharmony_ci } 40cb93a386Sopenharmony_ci }; 41cb93a386Sopenharmony_ci 42cb93a386Sopenharmony_ci float level = 0; 43cb93a386Sopenharmony_ci if (requestedMode != SkMipmapMode::kNone) { 44cb93a386Sopenharmony_ci SkSize scale; 45cb93a386Sopenharmony_ci if (!inv.decomposeScale(&scale, nullptr)) { 46cb93a386Sopenharmony_ci fResolvedMode = SkMipmapMode::kNone; 47cb93a386Sopenharmony_ci } else { 48cb93a386Sopenharmony_ci level = SkMipmap::ComputeLevel({1/scale.width(), 1/scale.height()}); 49cb93a386Sopenharmony_ci if (level <= 0) { 50cb93a386Sopenharmony_ci fResolvedMode = SkMipmapMode::kNone; 51cb93a386Sopenharmony_ci level = 0; 52cb93a386Sopenharmony_ci } 53cb93a386Sopenharmony_ci } 54cb93a386Sopenharmony_ci } 55cb93a386Sopenharmony_ci 56cb93a386Sopenharmony_ci auto post_scale = [image, inv](const SkPixmap& pm) { 57cb93a386Sopenharmony_ci return SkMatrix::Scale(SkIntToScalar(pm.width()) / image->width(), 58cb93a386Sopenharmony_ci SkIntToScalar(pm.height()) / image->height()) * inv; 59cb93a386Sopenharmony_ci }; 60cb93a386Sopenharmony_ci 61cb93a386Sopenharmony_ci int levelNum = sk_float_floor2int(level); 62cb93a386Sopenharmony_ci float lowerWeight = level - levelNum; // fract(level) 63cb93a386Sopenharmony_ci SkASSERT(levelNum >= 0); 64cb93a386Sopenharmony_ci 65cb93a386Sopenharmony_ci if (levelNum == 0) { 66cb93a386Sopenharmony_ci load_upper_from_base(); 67cb93a386Sopenharmony_ci } 68cb93a386Sopenharmony_ci // load fCurrMip if needed 69cb93a386Sopenharmony_ci if (levelNum > 0 || (fResolvedMode == SkMipmapMode::kLinear && lowerWeight > 0)) { 70cb93a386Sopenharmony_ci fCurrMip = try_load_mips(image); 71cb93a386Sopenharmony_ci if (!fCurrMip) { 72cb93a386Sopenharmony_ci load_upper_from_base(); 73cb93a386Sopenharmony_ci fResolvedMode = SkMipmapMode::kNone; 74cb93a386Sopenharmony_ci } else { 75cb93a386Sopenharmony_ci SkMipmap::Level levelRec; 76cb93a386Sopenharmony_ci 77cb93a386Sopenharmony_ci SkASSERT(fResolvedMode != SkMipmapMode::kNone); 78cb93a386Sopenharmony_ci if (levelNum > 0) { 79cb93a386Sopenharmony_ci if (fCurrMip->getLevel(levelNum - 1, &levelRec)) { 80cb93a386Sopenharmony_ci fUpper = levelRec.fPixmap; 81cb93a386Sopenharmony_ci } else { 82cb93a386Sopenharmony_ci load_upper_from_base(); 83cb93a386Sopenharmony_ci fResolvedMode = SkMipmapMode::kNone; 84cb93a386Sopenharmony_ci } 85cb93a386Sopenharmony_ci } 86cb93a386Sopenharmony_ci 87cb93a386Sopenharmony_ci if (fResolvedMode == SkMipmapMode::kLinear) { 88cb93a386Sopenharmony_ci if (fCurrMip->getLevel(levelNum, &levelRec)) { 89cb93a386Sopenharmony_ci fLower = levelRec.fPixmap; 90cb93a386Sopenharmony_ci fLowerWeight = lowerWeight; 91cb93a386Sopenharmony_ci fLowerInv = post_scale(fLower); 92cb93a386Sopenharmony_ci } else { 93cb93a386Sopenharmony_ci fResolvedMode = SkMipmapMode::kNearest; 94cb93a386Sopenharmony_ci } 95cb93a386Sopenharmony_ci } 96cb93a386Sopenharmony_ci } 97cb93a386Sopenharmony_ci } 98cb93a386Sopenharmony_ci fUpperInv = post_scale(fUpper); 99cb93a386Sopenharmony_ci} 100cb93a386Sopenharmony_ci 101cb93a386Sopenharmony_ciSkMipmapAccessor* SkMipmapAccessor::Make(SkArenaAlloc* alloc, const SkImage* image, 102cb93a386Sopenharmony_ci const SkMatrix& inv, SkMipmapMode mipmap) { 103cb93a386Sopenharmony_ci auto* access = alloc->make<SkMipmapAccessor>(as_IB(image), inv, mipmap); 104cb93a386Sopenharmony_ci // return null if we failed to get the level (so the caller won't try to use it) 105cb93a386Sopenharmony_ci return access->fUpper.addr() ? access : nullptr; 106cb93a386Sopenharmony_ci} 107