Coverage Report

Created: 2024-09-14 07:19

/src/skia/src/codec/SkBmpRLECodec.cpp
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright 2015 Google Inc.
3
 *
4
 * Use of this source code is governed by a BSD-style license that can be
5
 * found in the LICENSE file.
6
 */
7
8
#include "src/codec/SkBmpRLECodec.h"
9
10
#include "include/core/SkAlphaType.h"
11
#include "include/core/SkColor.h"
12
#include "include/core/SkColorPriv.h"
13
#include "include/core/SkColorType.h"
14
#include "include/core/SkImageInfo.h"
15
#include "include/core/SkSize.h"
16
#include "include/core/SkStream.h"
17
#include "include/private/SkColorData.h"
18
#include "include/private/SkEncodedInfo.h"
19
#include "include/private/base/SkAlign.h"
20
#include "include/private/base/SkMalloc.h"
21
#include "include/private/base/SkTemplates.h"
22
#include "src/codec/SkCodecPriv.h"
23
24
#include <algorithm>
25
#include <cstring>
26
#include <memory>
27
#include <utility>
28
29
/*
30
 * Creates an instance of the decoder
31
 * Called only by NewFromStream
32
 */
33
SkBmpRLECodec::SkBmpRLECodec(SkEncodedInfo&& info,
34
                             std::unique_ptr<SkStream> stream,
35
                             uint16_t bitsPerPixel, uint32_t numColors,
36
                             uint32_t bytesPerColor, uint32_t offset,
37
                             SkCodec::SkScanlineOrder rowOrder)
38
    : INHERITED(std::move(info), std::move(stream), bitsPerPixel, rowOrder)
39
    , fColorTable(nullptr)
40
    , fNumColors(numColors)
41
    , fBytesPerColor(bytesPerColor)
42
    , fOffset(offset)
43
    , fBytesBuffered(0)
44
    , fCurrRLEByte(0)
45
    , fSampleX(1)
46
1.10k
{}
47
48
/*
49
 * Initiates the bitmap decode
50
 */
51
SkCodec::Result SkBmpRLECodec::onGetPixels(const SkImageInfo& dstInfo,
52
                                           void* dst, size_t dstRowBytes,
53
                                           const Options& opts,
54
646
                                           int* rowsDecoded) {
55
646
    if (opts.fSubset) {
56
        // Subsets are not supported.
57
0
        return kUnimplemented;
58
0
    }
59
60
646
    Result result = this->prepareToDecode(dstInfo, opts);
61
646
    if (kSuccess != result) {
62
242
        return result;
63
242
    }
64
65
    // Perform the decode
66
404
    int rows = this->decodeRows(dstInfo, dst, dstRowBytes, opts);
67
404
    if (rows != dstInfo.height()) {
68
        // We set rowsDecoded equal to the height because the background has already
69
        // been filled.  RLE encodings sometimes skip pixels, so we always start by
70
        // filling the background.
71
349
        *rowsDecoded = dstInfo.height();
72
349
        return kIncompleteInput;
73
349
    }
74
75
55
    return kSuccess;
76
404
}
77
78
/*
79
 * Process the color table for the bmp input
80
 */
81
894
 bool SkBmpRLECodec::createColorTable(SkColorType dstColorType) {
82
    // Allocate memory for color table
83
894
    uint32_t colorBytes = 0;
84
894
    SkPMColor colorTable[256];
85
894
    if (this->bitsPerPixel() <= 8) {
86
        // Inform the caller of the number of colors
87
582
        uint32_t maxColors = 1 << this->bitsPerPixel();
88
        // Don't bother reading more than maxColors.
89
582
        const uint32_t numColorsToRead =
90
582
            fNumColors == 0 ? maxColors : std::min(fNumColors, maxColors);
91
92
        // Read the color table from the stream
93
582
        colorBytes = numColorsToRead * fBytesPerColor;
94
582
        std::unique_ptr<uint8_t[]> cBuffer(new uint8_t[colorBytes]);
95
582
        if (stream()->read(cBuffer.get(), colorBytes) != colorBytes) {
96
127
            SkCodecPrintf("Error: unable to read color table.\n");
97
127
            return false;
98
127
        }
99
100
        // Fill in the color table
101
455
        PackColorProc packARGB = choose_pack_color_proc(false, dstColorType);
102
455
        uint32_t i = 0;
103
3.81k
        for (; i < numColorsToRead; i++) {
104
3.36k
            uint8_t blue = get_byte(cBuffer.get(), i*fBytesPerColor);
105
3.36k
            uint8_t green = get_byte(cBuffer.get(), i*fBytesPerColor + 1);
106
3.36k
            uint8_t red = get_byte(cBuffer.get(), i*fBytesPerColor + 2);
107
3.36k
            colorTable[i] = packARGB(0xFF, red, green, blue);
108
3.36k
        }
109
110
        // To avoid segmentation faults on bad pixel data, fill the end of the
111
        // color table with black.  This is the same the behavior as the
112
        // chromium decoder.
113
47.3k
        for (; i < maxColors; i++) {
114
46.8k
            colorTable[i] = SkPackARGB32(0xFF, 0, 0, 0);
115
46.8k
        }
116
117
        // Set the color table
118
455
        fColorTable.reset(new SkColorPalette(colorTable, maxColors));
119
455
    }
120
121
    // Check that we have not read past the pixel array offset
122
767
    if(fOffset < colorBytes) {
123
        // This may occur on OS 2.1 and other old versions where the color
124
        // table defaults to max size, and the bmp tries to use a smaller
125
        // color table.  This is invalid, and our decision is to indicate
126
        // an error, rather than try to guess the intended size of the
127
        // color table.
128
39
        SkCodecPrintf("Error: pixel data offset less than color table size.\n");
129
39
        return false;
130
39
    }
131
132
    // After reading the color table, skip to the start of the pixel array
133
728
    if (stream()->skip(fOffset - colorBytes) != fOffset - colorBytes) {
134
124
        SkCodecPrintf("Error: unable to skip to image data.\n");
135
124
        return false;
136
124
    }
137
138
    // Return true on success
139
604
    return true;
140
728
}
141
142
604
bool SkBmpRLECodec::initializeStreamBuffer() {
143
604
    fBytesBuffered = this->stream()->read(fStreamBuffer, kBufferSize);
144
604
    if (fBytesBuffered == 0) {
145
6
        SkCodecPrintf("Error: could not read RLE image data.\n");
146
6
        return false;
147
6
    }
148
598
    fCurrRLEByte = 0;
149
598
    return true;
150
604
}
151
152
/*
153
 * @return the number of bytes remaining in the stream buffer after
154
 *         attempting to read more bytes from the stream
155
 */
156
552
size_t SkBmpRLECodec::checkForMoreData() {
157
552
    const size_t remainingBytes = fBytesBuffered - fCurrRLEByte;
158
552
    uint8_t* buffer = fStreamBuffer;
159
160
    // We will be reusing the same buffer, starting over from the beginning.
161
    // Move any remaining bytes to the start of the buffer.
162
    // We use memmove() instead of memcpy() because there is risk that the dst
163
    // and src memory will overlap in corrupt images.
164
552
    memmove(buffer, SkTAddOffset<uint8_t>(buffer, fCurrRLEByte), remainingBytes);
165
166
    // Adjust the buffer ptr to the start of the unfilled data.
167
552
    buffer += remainingBytes;
168
169
    // Try to read additional bytes from the stream.  There are fCurrRLEByte
170
    // bytes of additional space remaining in the buffer, assuming that we
171
    // have already copied remainingBytes to the start of the buffer.
172
552
    size_t additionalBytes = this->stream()->read(buffer, fCurrRLEByte);
173
174
    // Update counters and return the number of bytes we currently have
175
    // available.  We are at the start of the buffer again.
176
552
    fCurrRLEByte = 0;
177
552
    fBytesBuffered = remainingBytes + additionalBytes;
178
552
    return fBytesBuffered;
179
552
}
180
181
/*
182
 * Set an RLE pixel using the color table
183
 */
184
void SkBmpRLECodec::setPixel(void* dst, size_t dstRowBytes,
185
                             const SkImageInfo& dstInfo, uint32_t x, uint32_t y,
186
787k
                             uint8_t index) {
187
787k
    if (dst && is_coord_necessary(x, fSampleX, dstInfo.width())) {
188
        // Set the row
189
305k
        uint32_t row = this->getDstRow(y, dstInfo.height());
190
191
        // Set the pixel based on destination color type
192
305k
        const int dstX = get_dst_coord(x, fSampleX);
193
305k
        switch (dstInfo.colorType()) {
194
0
            case kRGBA_8888_SkColorType:
195
305k
            case kBGRA_8888_SkColorType: {
196
305k
                SkPMColor* dstRow = SkTAddOffset<SkPMColor>(dst, row * (int) dstRowBytes);
197
305k
                dstRow[dstX] = fColorTable->operator[](index);
198
305k
                break;
199
0
            }
200
0
            case kRGB_565_SkColorType: {
201
0
                uint16_t* dstRow = SkTAddOffset<uint16_t>(dst, row * (int) dstRowBytes);
202
0
                dstRow[dstX] = SkPixel32ToPixel16(fColorTable->operator[](index));
203
0
                break;
204
0
            }
205
0
            default:
206
                // This case should not be reached.  We should catch an invalid
207
                // color type when we check that the conversion is possible.
208
0
                SkASSERT(false);
209
0
                break;
210
305k
        }
211
305k
    }
212
787k
}
SkBmpRLECodec::setPixel(void*, unsigned long, SkImageInfo const&, unsigned int, unsigned int, unsigned char)
Line
Count
Source
186
787k
                             uint8_t index) {
187
787k
    if (dst && is_coord_necessary(x, fSampleX, dstInfo.width())) {
188
        // Set the row
189
305k
        uint32_t row = this->getDstRow(y, dstInfo.height());
190
191
        // Set the pixel based on destination color type
192
305k
        const int dstX = get_dst_coord(x, fSampleX);
193
305k
        switch (dstInfo.colorType()) {
194
0
            case kRGBA_8888_SkColorType:
195
305k
            case kBGRA_8888_SkColorType: {
196
305k
                SkPMColor* dstRow = SkTAddOffset<SkPMColor>(dst, row * (int) dstRowBytes);
197
305k
                dstRow[dstX] = fColorTable->operator[](index);
198
305k
                break;
199
0
            }
200
0
            case kRGB_565_SkColorType: {
201
0
                uint16_t* dstRow = SkTAddOffset<uint16_t>(dst, row * (int) dstRowBytes);
202
0
                dstRow[dstX] = SkPixel32ToPixel16(fColorTable->operator[](index));
203
0
                break;
204
0
            }
205
0
            default:
206
                // This case should not be reached.  We should catch an invalid
207
                // color type when we check that the conversion is possible.
208
0
                SkASSERT(false);
209
0
                break;
210
305k
        }
211
305k
    }
212
787k
}
Unexecuted instantiation: SkBmpRLECodec::setPixel(void*, unsigned long, SkImageInfo const&, unsigned int, unsigned int, unsigned char)
213
214
/*
215
 * Set an RLE pixel from R, G, B values
216
 */
217
void SkBmpRLECodec::setRGBPixel(void* dst, size_t dstRowBytes,
218
                                const SkImageInfo& dstInfo, uint32_t x,
219
                                uint32_t y, uint8_t red, uint8_t green,
220
391k
                                uint8_t blue) {
221
391k
    if (dst && is_coord_necessary(x, fSampleX, dstInfo.width())) {
222
        // Set the row
223
119k
        uint32_t row = this->getDstRow(y, dstInfo.height());
224
225
        // Set the pixel based on destination color type
226
119k
        const int dstX = get_dst_coord(x, fSampleX);
227
119k
        switch (dstInfo.colorType()) {
228
0
            case kRGBA_8888_SkColorType: {
229
0
                SkPMColor* dstRow = SkTAddOffset<SkPMColor>(dst, row * (int) dstRowBytes);
230
0
                dstRow[dstX] = SkPackARGB_as_RGBA(0xFF, red, green, blue);
231
0
                break;
232
0
            }
233
119k
            case kBGRA_8888_SkColorType: {
234
119k
                SkPMColor* dstRow = SkTAddOffset<SkPMColor>(dst, row * (int) dstRowBytes);
235
119k
                dstRow[dstX] = SkPackARGB_as_BGRA(0xFF, red, green, blue);
236
119k
                break;
237
0
            }
238
0
            case kRGB_565_SkColorType: {
239
0
                uint16_t* dstRow = SkTAddOffset<uint16_t>(dst, row * (int) dstRowBytes);
240
0
                dstRow[dstX] = SkPack888ToRGB16(red, green, blue);
241
0
                break;
242
0
            }
243
0
            default:
244
                // This case should not be reached.  We should catch an invalid
245
                // color type when we check that the conversion is possible.
246
0
                SkASSERT(false);
247
0
                break;
248
119k
        }
249
119k
    }
250
391k
}
SkBmpRLECodec::setRGBPixel(void*, unsigned long, SkImageInfo const&, unsigned int, unsigned int, unsigned char, unsigned char, unsigned char)
Line
Count
Source
220
391k
                                uint8_t blue) {
221
391k
    if (dst && is_coord_necessary(x, fSampleX, dstInfo.width())) {
222
        // Set the row
223
119k
        uint32_t row = this->getDstRow(y, dstInfo.height());
224
225
        // Set the pixel based on destination color type
226
119k
        const int dstX = get_dst_coord(x, fSampleX);
227
119k
        switch (dstInfo.colorType()) {
228
0
            case kRGBA_8888_SkColorType: {
229
0
                SkPMColor* dstRow = SkTAddOffset<SkPMColor>(dst, row * (int) dstRowBytes);
230
0
                dstRow[dstX] = SkPackARGB_as_RGBA(0xFF, red, green, blue);
231
0
                break;
232
0
            }
233
119k
            case kBGRA_8888_SkColorType: {
234
119k
                SkPMColor* dstRow = SkTAddOffset<SkPMColor>(dst, row * (int) dstRowBytes);
235
119k
                dstRow[dstX] = SkPackARGB_as_BGRA(0xFF, red, green, blue);
236
119k
                break;
237
0
            }
238
0
            case kRGB_565_SkColorType: {
239
0
                uint16_t* dstRow = SkTAddOffset<uint16_t>(dst, row * (int) dstRowBytes);
240
0
                dstRow[dstX] = SkPack888ToRGB16(red, green, blue);
241
0
                break;
242
0
            }
243
0
            default:
244
                // This case should not be reached.  We should catch an invalid
245
                // color type when we check that the conversion is possible.
246
0
                SkASSERT(false);
247
0
                break;
248
119k
        }
249
119k
    }
250
391k
}
Unexecuted instantiation: SkBmpRLECodec::setRGBPixel(void*, unsigned long, SkImageInfo const&, unsigned int, unsigned int, unsigned char, unsigned char, unsigned char)
251
252
SkCodec::Result SkBmpRLECodec::onPrepareToDecode(const SkImageInfo& dstInfo,
253
894
        const SkCodec::Options& options) {
254
    // FIXME: Support subsets for scanline decodes.
255
894
    if (options.fSubset) {
256
        // Subsets are not supported.
257
0
        return kUnimplemented;
258
0
    }
259
260
    // Reset fSampleX. If it needs to be a value other than 1, it will get modified by
261
    // the sampler.
262
894
    fSampleX = 1;
263
894
    fLinesToSkip = 0;
264
265
894
    SkColorType colorTableColorType = dstInfo.colorType();
266
894
    if (this->colorXform()) {
267
        // Just set a known colorType for the colorTable.  No need to actually transform
268
        // the colors in the colorTable.
269
0
        colorTableColorType = kBGRA_8888_SkColorType;
270
0
    }
271
272
    // Create the color table if necessary and prepare the stream for decode
273
    // Note that if it is non-NULL, inputColorCount will be modified
274
894
    if (!this->createColorTable(colorTableColorType)) {
275
290
        SkCodecPrintf("Error: could not create color table.\n");
276
290
        return SkCodec::kInvalidInput;
277
290
    }
278
279
    // Initialize a buffer for encoded RLE data
280
604
    if (!this->initializeStreamBuffer()) {
281
6
        SkCodecPrintf("Error: cannot initialize stream buffer.\n");
282
6
        return SkCodec::kInvalidInput;
283
6
    }
284
285
598
    return SkCodec::kSuccess;
286
604
}
287
288
/*
289
 * Performs the bitmap decoding for RLE input format
290
 * RLE decoding is performed all at once, rather than a one row at a time
291
 */
292
int SkBmpRLECodec::decodeRows(const SkImageInfo& info, void* dst, size_t dstRowBytes,
293
15.6k
        const Options& opts) {
294
15.6k
    int height = info.height();
295
296
    // Account for sampling.
297
15.6k
    SkImageInfo dstInfo = info.makeWH(this->fillWidth(), height);
298
299
    // Set the background as transparent.  Then, if the RLE code skips pixels,
300
    // the skipped pixels will be transparent.
301
15.6k
    if (dst) {
302
3.58k
        SkSampler::Fill(dstInfo, dst, dstRowBytes, opts.fZeroInitialized);
303
3.58k
    }
304
305
    // Adjust the height and the dst if the previous call to decodeRows() left us
306
    // with lines that need to be skipped.
307
15.6k
    if (height > fLinesToSkip) {
308
7.01k
        height -= fLinesToSkip;
309
7.01k
        if (dst) {
310
2.44k
            dst = SkTAddOffset<void>(dst, fLinesToSkip * dstRowBytes);
311
2.44k
        }
312
7.01k
        fLinesToSkip = 0;
313
314
7.01k
        dstInfo = dstInfo.makeWH(dstInfo.width(), height);
315
8.65k
    } else {
316
8.65k
        fLinesToSkip -= height;
317
8.65k
        return height;
318
8.65k
    }
319
320
7.01k
    void* decodeDst = dst;
321
7.01k
    size_t decodeRowBytes = dstRowBytes;
322
7.01k
    SkImageInfo decodeInfo = dstInfo;
323
7.01k
    if (decodeDst) {
324
2.44k
        if (this->colorXform()) {
325
0
            decodeInfo = decodeInfo.makeColorType(kXformSrcColorType);
326
0
            if (kRGBA_F16_SkColorType == dstInfo.colorType()) {
327
0
                int count = height * dstInfo.width();
328
0
                this->resetXformBuffer(count);
329
0
                sk_bzero(this->xformBuffer(), count * sizeof(uint32_t));
330
0
                decodeDst = this->xformBuffer();
331
0
                decodeRowBytes = dstInfo.width() * sizeof(uint32_t);
332
0
            }
333
0
        }
334
2.44k
    }
335
336
7.01k
    int decodedHeight = this->decodeRLE(decodeInfo, decodeDst, decodeRowBytes);
337
7.01k
    if (this->colorXform() && decodeDst) {
338
0
        for (int y = 0; y < decodedHeight; y++) {
339
0
            this->applyColorXform(dst, decodeDst, dstInfo.width());
340
0
            decodeDst = SkTAddOffset<void>(decodeDst, decodeRowBytes);
341
0
            dst = SkTAddOffset<void>(dst, dstRowBytes);
342
0
        }
343
0
    }
344
345
7.01k
    return decodedHeight;
346
15.6k
}
347
348
7.01k
int SkBmpRLECodec::decodeRLE(const SkImageInfo& dstInfo, void* dst, size_t dstRowBytes) {
349
    // Use the original width to count the number of pixels in each row.
350
7.01k
    const int width = this->dimensions().width();
351
352
    // This tells us the number of rows that we are meant to decode.
353
7.01k
    const int height = dstInfo.height();
354
355
    // Set RLE flags
356
7.01k
    constexpr uint8_t RLE_ESCAPE = 0;
357
7.01k
    constexpr uint8_t RLE_EOL = 0;
358
7.01k
    constexpr uint8_t RLE_EOF = 1;
359
7.01k
    constexpr uint8_t RLE_DELTA = 2;
360
361
    // Destination parameters
362
7.01k
    int x = 0;
363
7.01k
    int y = 0;
364
365
79.2k
    while (true) {
366
        // If we have reached a row that is beyond the requested height, we have
367
        // succeeded.
368
79.2k
        if (y >= height) {
369
            // It would be better to check for the EOF marker before indicating
370
            // success, but we may be performing a scanline decode, which
371
            // would require us to stop before decoding the full height.
372
5.32k
            return height;
373
5.32k
        }
374
375
        // Every entry takes at least two bytes
376
73.8k
        if ((int) fBytesBuffered - fCurrRLEByte < 2) {
377
222
            if (this->checkForMoreData() < 2) {
378
213
                return y;
379
213
            }
380
222
        }
381
382
        // Read the next two bytes.  These bytes have different meanings
383
        // depending on their values.  In the first interpretation, the first
384
        // byte is an escape flag and the second byte indicates what special
385
        // task to perform.
386
73.6k
        const uint8_t flag = fStreamBuffer[fCurrRLEByte++];
387
73.6k
        const uint8_t task = fStreamBuffer[fCurrRLEByte++];
388
389
        // Perform decoding
390
73.6k
        if (RLE_ESCAPE == flag) {
391
24.7k
            switch (task) {
392
13.9k
                case RLE_EOL:
393
13.9k
                    x = 0;
394
13.9k
                    y++;
395
13.9k
                    break;
396
675
                case RLE_EOF:
397
675
                    return height;
398
2.05k
                case RLE_DELTA: {
399
                    // Two bytes are needed to specify delta
400
2.05k
                    if ((int) fBytesBuffered - fCurrRLEByte < 2) {
401
13
                        if (this->checkForMoreData() < 2) {
402
9
                            return y;
403
9
                        }
404
13
                    }
405
                    // Modify x and y
406
2.04k
                    const uint8_t dx = fStreamBuffer[fCurrRLEByte++];
407
2.04k
                    const uint8_t dy = fStreamBuffer[fCurrRLEByte++];
408
2.04k
                    x += dx;
409
2.04k
                    y += dy;
410
2.04k
                    if (x > width) {
411
18
                        SkCodecPrintf("Warning: invalid RLE input.\n");
412
18
                        return y - dy;
413
2.03k
                    } else if (y > height) {
414
483
                        fLinesToSkip = y - height;
415
483
                        return height;
416
483
                    }
417
1.54k
                    break;
418
2.04k
                }
419
8.09k
                default: {
420
                    // If task does not match any of the above signals, it
421
                    // indicates that we have a sequence of non-RLE pixels.
422
                    // Furthermore, the value of task is equal to the number
423
                    // of pixels to interpret.
424
8.09k
                    uint8_t numPixels = task;
425
8.09k
                    const size_t rowBytes = compute_row_bytes(numPixels,
426
8.09k
                            this->bitsPerPixel());
427
8.09k
                    if (x + numPixels > width) {
428
6.13k
                        SkCodecPrintf("Warning: invalid RLE input.\n");
429
6.13k
                    }
430
431
                    // Abort if there are not enough bytes
432
                    // remaining in the stream to set numPixels.
433
434
                    // At most, alignedRowBytes can be 255 (max uint8_t) *
435
                    // 3 (max bytes per pixel) + 1 (aligned) = 766. If
436
                    // fStreamBuffer was smaller than this,
437
                    // checkForMoreData would never succeed for some bmps.
438
8.09k
                    static_assert(255 * 3 + 1 < kBufferSize,
439
8.09k
                                  "kBufferSize needs to be larger!");
440
8.09k
                    const size_t alignedRowBytes = SkAlign2(rowBytes);
441
8.09k
                    if ((int) fBytesBuffered - fCurrRLEByte < alignedRowBytes) {
442
269
                        SkASSERT(alignedRowBytes < kBufferSize);
443
269
                        if (this->checkForMoreData() < alignedRowBytes) {
444
254
                            return y;
445
254
                        }
446
269
                    }
447
                    // Set numPixels number of pixels
448
52.6k
                    while ((numPixels > 0) && (x < width)) {
449
44.8k
                        switch(this->bitsPerPixel()) {
450
18.5k
                            case 4: {
451
18.5k
                                SkASSERT(fCurrRLEByte < fBytesBuffered);
452
18.5k
                                uint8_t val = fStreamBuffer[fCurrRLEByte++];
453
18.5k
                                setPixel(dst, dstRowBytes, dstInfo, x++,
454
18.5k
                                        y, val >> 4);
455
18.5k
                                numPixels--;
456
18.5k
                                if (numPixels != 0) {
457
17.4k
                                    setPixel(dst, dstRowBytes, dstInfo,
458
17.4k
                                            x++, y, val & 0xF);
459
17.4k
                                    numPixels--;
460
17.4k
                                }
461
18.5k
                                break;
462
0
                            }
463
5.24k
                            case 8:
464
5.24k
                                SkASSERT(fCurrRLEByte < fBytesBuffered);
465
5.24k
                                setPixel(dst, dstRowBytes, dstInfo, x++,
466
5.24k
                                        y, fStreamBuffer[fCurrRLEByte++]);
467
5.24k
                                numPixels--;
468
5.24k
                                break;
469
21.0k
                            case 24: {
470
21.0k
                                SkASSERT(fCurrRLEByte + 2 < fBytesBuffered);
471
21.0k
                                uint8_t blue = fStreamBuffer[fCurrRLEByte++];
472
21.0k
                                uint8_t green = fStreamBuffer[fCurrRLEByte++];
473
21.0k
                                uint8_t red = fStreamBuffer[fCurrRLEByte++];
474
21.0k
                                setRGBPixel(dst, dstRowBytes, dstInfo,
475
21.0k
                                            x++, y, red, green, blue);
476
21.0k
                                numPixels--;
477
21.0k
                                break;
478
0
                            }
479
0
                            default:
480
0
                                SkASSERT(false);
481
0
                                return y;
482
44.8k
                        }
483
44.8k
                    }
484
                    // Skip a byte if necessary to maintain alignment
485
7.84k
                    if (!SkIsAlign2(rowBytes)) {
486
3.71k
                        fCurrRLEByte++;
487
3.71k
                    }
488
7.84k
                    break;
489
7.84k
                }
490
24.7k
            }
491
48.9k
        } else {
492
            // If the first byte read is not a flag, it indicates the number of
493
            // pixels to set in RLE mode.
494
48.9k
            const uint8_t numPixels = flag;
495
48.9k
            const int endX = std::min<int>(x + numPixels, width);
496
497
48.9k
            if (24 == this->bitsPerPixel()) {
498
                // In RLE24, the second byte read is part of the pixel color.
499
                // There are two more required bytes to finish encoding the
500
                // color.
501
22.2k
                if ((int) fBytesBuffered - fCurrRLEByte < 2) {
502
48
                    if (this->checkForMoreData() < 2) {
503
40
                        return y;
504
40
                    }
505
48
                }
506
507
                // Fill the pixels up to endX with the specified color
508
22.1k
                uint8_t blue = task;
509
22.1k
                uint8_t green = fStreamBuffer[fCurrRLEByte++];
510
22.1k
                uint8_t red = fStreamBuffer[fCurrRLEByte++];
511
392k
                while (x < endX) {
512
370k
                    setRGBPixel(dst, dstRowBytes, dstInfo, x++, y, red, green, blue);
513
370k
                }
514
26.6k
            } else {
515
                // In RLE8 or RLE4, the second byte read gives the index in the
516
                // color table to look up the pixel color.
517
                // RLE8 has one color index that gets repeated
518
                // RLE4 has two color indexes in the upper and lower 4 bits of
519
                // the bytes, which are alternated
520
26.6k
                uint8_t indices[2] = { task, task };
521
26.6k
                if (4 == this->bitsPerPixel()) {
522
18.4k
                    indices[0] >>= 4;
523
18.4k
                    indices[1] &= 0xf;
524
18.4k
                }
525
526
                // Set the indicated number of pixels
527
773k
                for (int which = 0; x < endX; x++) {
528
746k
                    setPixel(dst, dstRowBytes, dstInfo, x, y, indices[which]);
529
746k
                    which = !which;
530
746k
                }
531
26.6k
            }
532
48.9k
        }
533
73.6k
    }
534
7.01k
}
535
536
12.0k
bool SkBmpRLECodec::skipRows(int count) {
537
12.0k
    const SkImageInfo rowInfo = SkImageInfo::Make(this->dimensions().width(), count,
538
12.0k
                                                  kN32_SkColorType, kUnpremul_SkAlphaType);
539
12.0k
    return count == this->decodeRows(rowInfo, nullptr, 0, this->options());
540
12.0k
}
541
542
// FIXME: Make SkBmpRLECodec have no knowledge of sampling.
543
//        Or it should do all sampling natively.
544
//        It currently is a hybrid that needs to know what SkScaledCodec is doing.
545
class SkBmpRLESampler : public SkSampler {
546
public:
547
    SkBmpRLESampler(SkBmpRLECodec* codec)
548
        : fCodec(codec)
549
194
    {
550
194
        SkASSERT(fCodec);
551
194
    }
552
553
156
    int fillWidth() const override {
554
156
        return fCodec->fillWidth();
555
156
    }
556
557
private:
558
194
    int onSetSampleX(int sampleX) override {
559
194
        return fCodec->setSampleX(sampleX);
560
194
    }
561
562
    // Unowned pointer. fCodec will delete this class in its destructor.
563
    SkBmpRLECodec* fCodec;
564
};
565
566
350
SkSampler* SkBmpRLECodec::getSampler(bool createIfNecessary) {
567
350
    if (!fSampler && createIfNecessary) {
568
194
        fSampler = std::make_unique<SkBmpRLESampler>(this);
569
194
    }
570
571
350
    return fSampler.get();
572
350
}
573
574
194
int SkBmpRLECodec::setSampleX(int sampleX) {
575
194
    fSampleX = sampleX;
576
194
    return this->fillWidth();
577
194
}
578
579
16.0k
int SkBmpRLECodec::fillWidth() const {
580
16.0k
    return get_scaled_dimension(this->dimensions().width(), fSampleX);
581
16.0k
}