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