1cb93a386Sopenharmony_ci/*
2cb93a386Sopenharmony_ci * Copyright 2020 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 "src/core/SkCompressedDataUtils.h"
9cb93a386Sopenharmony_ci
10cb93a386Sopenharmony_ci#include "include/core/SkBitmap.h"
11cb93a386Sopenharmony_ci#include "include/core/SkColorPriv.h"
12cb93a386Sopenharmony_ci#include "include/core/SkData.h"
13cb93a386Sopenharmony_ci#include "include/private/SkColorData.h"
14cb93a386Sopenharmony_ci#include "include/private/SkTPin.h"
15cb93a386Sopenharmony_ci#include "src/core/SkMathPriv.h"
16cb93a386Sopenharmony_ci#include "src/core/SkMipmap.h"
17cb93a386Sopenharmony_ci
18cb93a386Sopenharmony_cistruct ETC1Block {
19cb93a386Sopenharmony_ci    uint32_t fHigh;
20cb93a386Sopenharmony_ci    uint32_t fLow;
21cb93a386Sopenharmony_ci};
22cb93a386Sopenharmony_ci
23cb93a386Sopenharmony_ciconstexpr uint32_t kFlipBit = 0x1; // set -> T/B sub-blocks; not-set -> L/R sub-blocks
24cb93a386Sopenharmony_ciconstexpr uint32_t kDiffBit = 0x2; // set -> differential; not-set -> individual
25cb93a386Sopenharmony_ci
26cb93a386Sopenharmony_cistatic inline int extend_4To8bits(int b) {
27cb93a386Sopenharmony_ci    int c = b & 0xf;
28cb93a386Sopenharmony_ci    return (c << 4) | c;
29cb93a386Sopenharmony_ci}
30cb93a386Sopenharmony_ci
31cb93a386Sopenharmony_cistatic inline int extend_5To8bits(int b) {
32cb93a386Sopenharmony_ci    int c = b & 0x1f;
33cb93a386Sopenharmony_ci    return (c << 3) | (c >> 2);
34cb93a386Sopenharmony_ci}
35cb93a386Sopenharmony_ci
36cb93a386Sopenharmony_cistatic inline int extend_5plus3To8Bits(int base, int diff) {
37cb93a386Sopenharmony_ci    static const int kLookup[8] = { 0, 1, 2, 3, -4, -3, -2, -1 };
38cb93a386Sopenharmony_ci
39cb93a386Sopenharmony_ci    return extend_5To8bits((0x1f & base) + kLookup[0x7 & diff]);
40cb93a386Sopenharmony_ci}
41cb93a386Sopenharmony_ci
42cb93a386Sopenharmony_cistatic const int kNumETC1ModifierTables = 8;
43cb93a386Sopenharmony_cistatic const int kNumETC1PixelIndices = 4;
44cb93a386Sopenharmony_ci
45cb93a386Sopenharmony_ci// The index of each row in this table is the ETC1 table codeword
46cb93a386Sopenharmony_ci// The index of each column in this table is the ETC1 pixel index value
47cb93a386Sopenharmony_cistatic const int kETC1ModifierTables[kNumETC1ModifierTables][kNumETC1PixelIndices] = {
48cb93a386Sopenharmony_ci    /* 0 */ { 2,    8,  -2,   -8 },
49cb93a386Sopenharmony_ci    /* 1 */ { 5,   17,  -5,  -17 },
50cb93a386Sopenharmony_ci    /* 2 */ { 9,   29,  -9,  -29 },
51cb93a386Sopenharmony_ci    /* 3 */ { 13,  42, -13,  -42 },
52cb93a386Sopenharmony_ci    /* 4 */ { 18,  60, -18,  -60 },
53cb93a386Sopenharmony_ci    /* 5 */ { 24,  80, -24,  -80 },
54cb93a386Sopenharmony_ci    /* 6 */ { 33, 106, -33, -106 },
55cb93a386Sopenharmony_ci    /* 7 */ { 47, 183, -47, -183 }
56cb93a386Sopenharmony_ci};
57cb93a386Sopenharmony_ci
58cb93a386Sopenharmony_cistatic int num_4x4_blocks(int size) {
59cb93a386Sopenharmony_ci    return ((size + 3) & ~3) >> 2;
60cb93a386Sopenharmony_ci}
61cb93a386Sopenharmony_ci
62cb93a386Sopenharmony_ci// Return which sub-block a given x,y location in the overall 4x4 block belongs to
63cb93a386Sopenharmony_cistatic int xy_to_subblock_index(int x, int y, bool flip) {
64cb93a386Sopenharmony_ci    SkASSERT(x >= 0 && x < 4);
65cb93a386Sopenharmony_ci    SkASSERT(y >= 0 && y < 4);
66cb93a386Sopenharmony_ci
67cb93a386Sopenharmony_ci    if (flip) {
68cb93a386Sopenharmony_ci        return y < 2 ? 0 : 1; // sub-block 1 is on top of sub-block 2
69cb93a386Sopenharmony_ci    } else {
70cb93a386Sopenharmony_ci        return x < 2 ? 0 : 1; // sub-block 1 is to the left of sub-block 2
71cb93a386Sopenharmony_ci    }
72cb93a386Sopenharmony_ci}
73cb93a386Sopenharmony_ci
74cb93a386Sopenharmony_cistruct IColor {
75cb93a386Sopenharmony_ci    int fR, fG, fB;
76cb93a386Sopenharmony_ci};
77cb93a386Sopenharmony_ci
78cb93a386Sopenharmony_cistatic SkPMColor add_delta_and_clamp(const IColor& col, int delta) {
79cb93a386Sopenharmony_ci    int r8 = SkTPin(col.fR + delta, 0, 255);
80cb93a386Sopenharmony_ci    int g8 = SkTPin(col.fG + delta, 0, 255);
81cb93a386Sopenharmony_ci    int b8 = SkTPin(col.fB + delta, 0, 255);
82cb93a386Sopenharmony_ci
83cb93a386Sopenharmony_ci    return SkPackARGB32(0xFF, r8, g8, b8);
84cb93a386Sopenharmony_ci}
85cb93a386Sopenharmony_ci
86cb93a386Sopenharmony_cistatic bool decompress_etc1(SkISize dimensions, const uint8_t* srcData, SkBitmap* dst) {
87cb93a386Sopenharmony_ci    const ETC1Block* srcBlocks = reinterpret_cast<const ETC1Block*>(srcData);
88cb93a386Sopenharmony_ci
89cb93a386Sopenharmony_ci    int numXBlocks = num_4x4_blocks(dimensions.width());
90cb93a386Sopenharmony_ci    int numYBlocks = num_4x4_blocks(dimensions.height());
91cb93a386Sopenharmony_ci
92cb93a386Sopenharmony_ci    for (int y = 0; y < numYBlocks; ++y) {
93cb93a386Sopenharmony_ci        for (int x = 0; x < numXBlocks; ++x) {
94cb93a386Sopenharmony_ci            const ETC1Block* curBlock1 = &srcBlocks[y * numXBlocks + x];
95cb93a386Sopenharmony_ci            uint32_t high = SkBSwap32(curBlock1->fHigh);
96cb93a386Sopenharmony_ci            uint32_t low = SkBSwap32(curBlock1->fLow);
97cb93a386Sopenharmony_ci
98cb93a386Sopenharmony_ci            bool flipped = SkToBool(high & kFlipBit);
99cb93a386Sopenharmony_ci            bool differential = SkToBool(high & kDiffBit);
100cb93a386Sopenharmony_ci
101cb93a386Sopenharmony_ci            IColor colors[2];
102cb93a386Sopenharmony_ci
103cb93a386Sopenharmony_ci            if (differential) {
104cb93a386Sopenharmony_ci                colors[0].fR = extend_5To8bits(high >> 27);
105cb93a386Sopenharmony_ci                colors[1].fR = extend_5plus3To8Bits(high >> 27, high >> 24);
106cb93a386Sopenharmony_ci                colors[0].fG = extend_5To8bits(high >> 19);
107cb93a386Sopenharmony_ci                colors[1].fG = extend_5plus3To8Bits(high >> 19, high >> 16);
108cb93a386Sopenharmony_ci                colors[0].fB = extend_5To8bits(high >> 11);
109cb93a386Sopenharmony_ci                colors[1].fB = extend_5plus3To8Bits(high >> 11, high >> 8);
110cb93a386Sopenharmony_ci            } else {
111cb93a386Sopenharmony_ci                colors[0].fR = extend_4To8bits(high >> 28);
112cb93a386Sopenharmony_ci                colors[1].fR = extend_4To8bits(high >> 24);
113cb93a386Sopenharmony_ci                colors[0].fG = extend_4To8bits(high >> 20);
114cb93a386Sopenharmony_ci                colors[1].fG = extend_4To8bits(high >> 16);
115cb93a386Sopenharmony_ci                colors[0].fB = extend_4To8bits(high >> 12);
116cb93a386Sopenharmony_ci                colors[1].fB = extend_4To8bits(high >> 8);
117cb93a386Sopenharmony_ci            }
118cb93a386Sopenharmony_ci
119cb93a386Sopenharmony_ci            int tableIndex0 = (high >> 5) & 0x7;
120cb93a386Sopenharmony_ci            int tableIndex1 = (high >> 2) & 0x7;
121cb93a386Sopenharmony_ci            const int* tables[2] = {
122cb93a386Sopenharmony_ci                kETC1ModifierTables[tableIndex0],
123cb93a386Sopenharmony_ci                kETC1ModifierTables[tableIndex1]
124cb93a386Sopenharmony_ci            };
125cb93a386Sopenharmony_ci
126cb93a386Sopenharmony_ci            int baseShift = 0;
127cb93a386Sopenharmony_ci            int offsetX = 4 * x, offsetY = 4 * y;
128cb93a386Sopenharmony_ci            for (int i = 0; i < 4; ++i, ++baseShift) {
129cb93a386Sopenharmony_ci                for (int j = 0; j < 4; ++j) {
130cb93a386Sopenharmony_ci                    if (offsetX + j >= dst->width() || offsetY + i >= dst->height()) {
131cb93a386Sopenharmony_ci                        // This can happen for the topmost levels of a mipmap and for
132cb93a386Sopenharmony_ci                        // non-multiple of 4 textures
133cb93a386Sopenharmony_ci                        continue;
134cb93a386Sopenharmony_ci                    }
135cb93a386Sopenharmony_ci
136cb93a386Sopenharmony_ci                    int subBlockIndex = xy_to_subblock_index(j, i, flipped);
137cb93a386Sopenharmony_ci                    int pixelIndex = ((low >> (baseShift+(j*4))) & 0x1) |
138cb93a386Sopenharmony_ci                                     (low >> (baseShift+(j*4)+15) & 0x2);
139cb93a386Sopenharmony_ci
140cb93a386Sopenharmony_ci                    SkASSERT(subBlockIndex == 0 || subBlockIndex == 1);
141cb93a386Sopenharmony_ci                    SkASSERT(pixelIndex >= 0 && pixelIndex < 4);
142cb93a386Sopenharmony_ci
143cb93a386Sopenharmony_ci                    int delta = tables[subBlockIndex][pixelIndex];
144cb93a386Sopenharmony_ci                    *dst->getAddr32(offsetX + j, offsetY + i) =
145cb93a386Sopenharmony_ci                                                add_delta_and_clamp(colors[subBlockIndex], delta);
146cb93a386Sopenharmony_ci                }
147cb93a386Sopenharmony_ci            }
148cb93a386Sopenharmony_ci        }
149cb93a386Sopenharmony_ci    }
150cb93a386Sopenharmony_ci
151cb93a386Sopenharmony_ci    return true;
152cb93a386Sopenharmony_ci}
153cb93a386Sopenharmony_ci
154cb93a386Sopenharmony_ci//------------------------------------------------------------------------------------------------
155cb93a386Sopenharmony_cistruct BC1Block {
156cb93a386Sopenharmony_ci    uint16_t fColor0;
157cb93a386Sopenharmony_ci    uint16_t fColor1;
158cb93a386Sopenharmony_ci    uint32_t fIndices;
159cb93a386Sopenharmony_ci};
160cb93a386Sopenharmony_ci
161cb93a386Sopenharmony_cistatic SkPMColor from565(uint16_t rgb565) {
162cb93a386Sopenharmony_ci    uint8_t r8 = SkR16ToR32((rgb565 >> 11) & 0x1F);
163cb93a386Sopenharmony_ci    uint8_t g8 = SkG16ToG32((rgb565 >> 5) & 0x3F);
164cb93a386Sopenharmony_ci    uint8_t b8 = SkB16ToB32(rgb565 & 0x1F);
165cb93a386Sopenharmony_ci
166cb93a386Sopenharmony_ci    return SkPackARGB32(0xFF, r8, g8, b8);
167cb93a386Sopenharmony_ci}
168cb93a386Sopenharmony_ci
169cb93a386Sopenharmony_ci// return t*col0 + (1-t)*col1
170cb93a386Sopenharmony_cistatic SkPMColor lerp(float t, SkPMColor col0, SkPMColor col1) {
171cb93a386Sopenharmony_ci    SkASSERT(SkGetPackedA32(col0) == 0xFF && SkGetPackedA32(col1) == 0xFF);
172cb93a386Sopenharmony_ci
173cb93a386Sopenharmony_ci    // TODO: given 't' is only either 1/3 or 2/3 this could be done faster
174cb93a386Sopenharmony_ci    uint8_t r8 = SkScalarRoundToInt(t * SkGetPackedR32(col0) + (1.0f - t) * SkGetPackedR32(col1));
175cb93a386Sopenharmony_ci    uint8_t g8 = SkScalarRoundToInt(t * SkGetPackedG32(col0) + (1.0f - t) * SkGetPackedG32(col1));
176cb93a386Sopenharmony_ci    uint8_t b8 = SkScalarRoundToInt(t * SkGetPackedB32(col0) + (1.0f - t) * SkGetPackedB32(col1));
177cb93a386Sopenharmony_ci    return SkPackARGB32(0xFF, r8, g8, b8);
178cb93a386Sopenharmony_ci}
179cb93a386Sopenharmony_ci
180cb93a386Sopenharmony_cistatic bool decompress_bc1(SkISize dimensions, const uint8_t* srcData,
181cb93a386Sopenharmony_ci                           bool isOpaque, SkBitmap* dst) {
182cb93a386Sopenharmony_ci    const BC1Block* srcBlocks = reinterpret_cast<const BC1Block*>(srcData);
183cb93a386Sopenharmony_ci
184cb93a386Sopenharmony_ci    int numXBlocks = num_4x4_blocks(dimensions.width());
185cb93a386Sopenharmony_ci    int numYBlocks = num_4x4_blocks(dimensions.height());
186cb93a386Sopenharmony_ci
187cb93a386Sopenharmony_ci    SkPMColor colors[4];
188cb93a386Sopenharmony_ci
189cb93a386Sopenharmony_ci    for (int y = 0; y < numYBlocks; ++y) {
190cb93a386Sopenharmony_ci        for (int x = 0; x < numXBlocks; ++x) {
191cb93a386Sopenharmony_ci            const BC1Block* curBlock = &srcBlocks[y * numXBlocks + x];
192cb93a386Sopenharmony_ci
193cb93a386Sopenharmony_ci            colors[0] = from565(curBlock->fColor0);
194cb93a386Sopenharmony_ci            colors[1] = from565(curBlock->fColor1);
195cb93a386Sopenharmony_ci            if (curBlock->fColor0 <= curBlock->fColor1) {        // signal for a transparent block
196cb93a386Sopenharmony_ci                colors[2] = SkPackARGB32(
197cb93a386Sopenharmony_ci                    0xFF,
198cb93a386Sopenharmony_ci                    (SkGetPackedR32(colors[0]) + SkGetPackedR32(colors[1])) >> 1,
199cb93a386Sopenharmony_ci                    (SkGetPackedG32(colors[0]) + SkGetPackedG32(colors[1])) >> 1,
200cb93a386Sopenharmony_ci                    (SkGetPackedB32(colors[0]) + SkGetPackedB32(colors[1])) >> 1);
201cb93a386Sopenharmony_ci                // The opacity of the overall texture trumps the per-block transparency
202cb93a386Sopenharmony_ci                colors[3] = SkPackARGB32(isOpaque ? 0xFF : 0, 0, 0, 0);
203cb93a386Sopenharmony_ci            } else {
204cb93a386Sopenharmony_ci                colors[2] = lerp(2.0f/3.0f, colors[0], colors[1]);
205cb93a386Sopenharmony_ci                colors[3] = lerp(1.0f/3.0f, colors[0], colors[1]);
206cb93a386Sopenharmony_ci            }
207cb93a386Sopenharmony_ci
208cb93a386Sopenharmony_ci            int shift = 0;
209cb93a386Sopenharmony_ci            int offsetX = 4 * x, offsetY = 4 * y;
210cb93a386Sopenharmony_ci            for (int i = 0; i < 4; ++i) {
211cb93a386Sopenharmony_ci                for (int j = 0; j < 4; ++j, shift += 2) {
212cb93a386Sopenharmony_ci                    if (offsetX + j >= dst->width() || offsetY + i >= dst->height()) {
213cb93a386Sopenharmony_ci                        // This can happen for the topmost levels of a mipmap and for
214cb93a386Sopenharmony_ci                        // non-multiple of 4 textures
215cb93a386Sopenharmony_ci                        continue;
216cb93a386Sopenharmony_ci                    }
217cb93a386Sopenharmony_ci
218cb93a386Sopenharmony_ci                    int index = (curBlock->fIndices >> shift) & 0x3;
219cb93a386Sopenharmony_ci                    *dst->getAddr32(offsetX + j, offsetY + i) = colors[index];
220cb93a386Sopenharmony_ci                }
221cb93a386Sopenharmony_ci            }
222cb93a386Sopenharmony_ci        }
223cb93a386Sopenharmony_ci    }
224cb93a386Sopenharmony_ci
225cb93a386Sopenharmony_ci    return true;
226cb93a386Sopenharmony_ci}
227cb93a386Sopenharmony_ci
228cb93a386Sopenharmony_cibool SkDecompress(sk_sp<SkData> data,
229cb93a386Sopenharmony_ci                  SkISize dimensions,
230cb93a386Sopenharmony_ci                  SkImage::CompressionType compressionType,
231cb93a386Sopenharmony_ci                  SkBitmap* dst) {
232cb93a386Sopenharmony_ci    using Type = SkImage::CompressionType;
233cb93a386Sopenharmony_ci
234cb93a386Sopenharmony_ci    const uint8_t* bytes = data->bytes();
235cb93a386Sopenharmony_ci    switch (compressionType) {
236cb93a386Sopenharmony_ci        case Type::kNone:             return false;
237cb93a386Sopenharmony_ci        case Type::kETC2_RGB8_UNORM:  return decompress_etc1(dimensions, bytes, dst);
238cb93a386Sopenharmony_ci        case Type::kBC1_RGB8_UNORM:   return decompress_bc1(dimensions, bytes, true, dst);
239cb93a386Sopenharmony_ci        case Type::kBC1_RGBA8_UNORM:  return decompress_bc1(dimensions, bytes, false, dst);
240cb93a386Sopenharmony_ci        case Type::kASTC_RGBA8_4x4: return true;
241cb93a386Sopenharmony_ci        case Type::kASTC_RGBA8_6x6: return true;
242cb93a386Sopenharmony_ci        case Type::kASTC_RGBA8_8x8: return true;
243cb93a386Sopenharmony_ci    }
244cb93a386Sopenharmony_ci
245cb93a386Sopenharmony_ci    SkUNREACHABLE;
246cb93a386Sopenharmony_ci    return false;
247cb93a386Sopenharmony_ci}
248cb93a386Sopenharmony_ci
249cb93a386Sopenharmony_cisize_t SkCompressedDataSize(SkImage::CompressionType type, SkISize dimensions,
250cb93a386Sopenharmony_ci                            SkTArray<size_t>* individualMipOffsets, bool mipMapped) {
251cb93a386Sopenharmony_ci    SkASSERT(!individualMipOffsets || !individualMipOffsets->count());
252cb93a386Sopenharmony_ci
253cb93a386Sopenharmony_ci    int numMipLevels = 1;
254cb93a386Sopenharmony_ci    if (mipMapped) {
255cb93a386Sopenharmony_ci        numMipLevels = SkMipmap::ComputeLevelCount(dimensions.width(), dimensions.height()) + 1;
256cb93a386Sopenharmony_ci    }
257cb93a386Sopenharmony_ci
258cb93a386Sopenharmony_ci    size_t totalSize = 0;
259cb93a386Sopenharmony_ci    switch (type) {
260cb93a386Sopenharmony_ci        case SkImage::CompressionType::kNone:
261cb93a386Sopenharmony_ci            break;
262cb93a386Sopenharmony_ci        case SkImage::CompressionType::kETC2_RGB8_UNORM:
263cb93a386Sopenharmony_ci        case SkImage::CompressionType::kBC1_RGB8_UNORM:
264cb93a386Sopenharmony_ci        case SkImage::CompressionType::kBC1_RGBA8_UNORM: {
265cb93a386Sopenharmony_ci            for (int i = 0; i < numMipLevels; ++i) {
266cb93a386Sopenharmony_ci                int numBlocks = num_4x4_blocks(dimensions.width()) *
267cb93a386Sopenharmony_ci                                num_4x4_blocks(dimensions.height());
268cb93a386Sopenharmony_ci
269cb93a386Sopenharmony_ci                if (individualMipOffsets) {
270cb93a386Sopenharmony_ci                    individualMipOffsets->push_back(totalSize);
271cb93a386Sopenharmony_ci                }
272cb93a386Sopenharmony_ci
273cb93a386Sopenharmony_ci                static_assert(sizeof(ETC1Block) == sizeof(BC1Block));
274cb93a386Sopenharmony_ci                totalSize += numBlocks * sizeof(ETC1Block);
275cb93a386Sopenharmony_ci
276cb93a386Sopenharmony_ci                dimensions = {std::max(1, dimensions.width()/2), std::max(1, dimensions.height()/2)};
277cb93a386Sopenharmony_ci            }
278cb93a386Sopenharmony_ci            break;
279cb93a386Sopenharmony_ci        }
280cb93a386Sopenharmony_ci        case SkImage::CompressionType::kASTC_RGBA8_4x4: {
281cb93a386Sopenharmony_ci            // The evil number 16 here is the size of each ASTC block, which is constant for the ASTC 4x4 format,
282cb93a386Sopenharmony_ci            // while the ASTC 4x4 format also explain the evil number 4.0f above
283cb93a386Sopenharmony_ci            totalSize = std::ceil(dimensions.width() / 4.0f) * std::ceil(dimensions.height() / 4.0f) * 16;
284cb93a386Sopenharmony_ci            if (individualMipOffsets) {
285cb93a386Sopenharmony_ci                individualMipOffsets->push_back(0);
286cb93a386Sopenharmony_ci            }
287cb93a386Sopenharmony_ci            break;
288cb93a386Sopenharmony_ci        }
289cb93a386Sopenharmony_ci        case SkImage::CompressionType::kASTC_RGBA8_6x6: {
290cb93a386Sopenharmony_ci            // The evil number 16 here is the size of each ASTC block, which is constant for the ASTC 4x4 format,
291cb93a386Sopenharmony_ci            // while the ASTC 6x6 format also explain the evil number 6.0f above
292cb93a386Sopenharmony_ci            totalSize = std::ceil(dimensions.width() / 6.0f) * std::ceil(dimensions.height() / 6.0f) * 16;
293cb93a386Sopenharmony_ci            if (individualMipOffsets) {
294cb93a386Sopenharmony_ci                individualMipOffsets->push_back(0);
295cb93a386Sopenharmony_ci            }
296cb93a386Sopenharmony_ci            break;
297cb93a386Sopenharmony_ci        }
298cb93a386Sopenharmony_ci        case SkImage::CompressionType::kASTC_RGBA8_8x8: {
299cb93a386Sopenharmony_ci            // The evil number 16 here is the size of each ASTC block, which is constant for the ASTC 4x4 format,
300cb93a386Sopenharmony_ci            // while the ASTC 8x8 format also explain the evil number 8.0f above
301cb93a386Sopenharmony_ci            totalSize = std::ceil(dimensions.width() / 8.0f) * std::ceil(dimensions.height() / 8.0f) * 16;
302cb93a386Sopenharmony_ci            if (individualMipOffsets) {
303cb93a386Sopenharmony_ci                individualMipOffsets->push_back(0);
304cb93a386Sopenharmony_ci            }
305cb93a386Sopenharmony_ci            break;
306cb93a386Sopenharmony_ci        }
307cb93a386Sopenharmony_ci    }
308cb93a386Sopenharmony_ci
309cb93a386Sopenharmony_ci    return totalSize;
310cb93a386Sopenharmony_ci}
311cb93a386Sopenharmony_ci
312cb93a386Sopenharmony_cisize_t SkCompressedBlockSize(SkImage::CompressionType type) {
313cb93a386Sopenharmony_ci    switch (type) {
314cb93a386Sopenharmony_ci        case SkImage::CompressionType::kNone:
315cb93a386Sopenharmony_ci            return 0;
316cb93a386Sopenharmony_ci        case SkImage::CompressionType::kETC2_RGB8_UNORM:
317cb93a386Sopenharmony_ci            return sizeof(ETC1Block);
318cb93a386Sopenharmony_ci        case SkImage::CompressionType::kBC1_RGB8_UNORM:
319cb93a386Sopenharmony_ci        case SkImage::CompressionType::kBC1_RGBA8_UNORM:
320cb93a386Sopenharmony_ci            return sizeof(BC1Block);
321cb93a386Sopenharmony_ci        case SkImage::CompressionType::kASTC_RGBA8_4x4:
322cb93a386Sopenharmony_ci        case SkImage::CompressionType::kASTC_RGBA8_6x6:
323cb93a386Sopenharmony_ci        case SkImage::CompressionType::kASTC_RGBA8_8x8:
324cb93a386Sopenharmony_ci            // The evil number 16 here is the constant size of ASTC format
325cb93a386Sopenharmony_ci            return 16;
326cb93a386Sopenharmony_ci    }
327cb93a386Sopenharmony_ci    SkUNREACHABLE;
328cb93a386Sopenharmony_ci}
329cb93a386Sopenharmony_ci
330cb93a386Sopenharmony_cisize_t SkCompressedFormatDataSize(SkImage::CompressionType compressionType,
331cb93a386Sopenharmony_ci                                  SkISize dimensions, bool mipMapped) {
332cb93a386Sopenharmony_ci    return SkCompressedDataSize(compressionType, dimensions, nullptr, mipMapped);
333cb93a386Sopenharmony_ci}
334