Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
SkBmpRLECodec.cpp
Go to the documentation of this file.
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
9
15#include "include/core/SkSize.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 */
34 std::unique_ptr<SkStream> stream,
35 uint16_t bitsPerPixel, uint32_t numColors,
36 uint32_t bytesPerColor, uint32_t offset,
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{}
47
48/*
49 * Initiates the bitmap decode
50 */
52 void* dst, size_t dstRowBytes,
53 const Options& opts,
54 int* rowsDecoded) {
55 if (opts.fSubset) {
56 // Subsets are not supported.
57 return kUnimplemented;
58 }
59
60 Result result = this->prepareToDecode(dstInfo, opts);
61 if (kSuccess != result) {
62 return result;
63 }
64
65 // Perform the decode
66 int rows = this->decodeRows(dstInfo, dst, dstRowBytes, opts);
67 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 *rowsDecoded = dstInfo.height();
72 return kIncompleteInput;
73 }
74
75 return kSuccess;
76}
77
78/*
79 * Process the color table for the bmp input
80 */
81 bool SkBmpRLECodec::createColorTable(SkColorType dstColorType) {
82 // Allocate memory for color table
83 uint32_t colorBytes = 0;
84 SkPMColor colorTable[256];
85 if (this->bitsPerPixel() <= 8) {
86 // Inform the caller of the number of colors
87 uint32_t maxColors = 1 << this->bitsPerPixel();
88 // Don't bother reading more than maxColors.
89 const uint32_t numColorsToRead =
90 fNumColors == 0 ? maxColors : std::min(fNumColors, maxColors);
91
92 // Read the color table from the stream
93 colorBytes = numColorsToRead * fBytesPerColor;
94 std::unique_ptr<uint8_t[]> cBuffer(new uint8_t[colorBytes]);
95 if (stream()->read(cBuffer.get(), colorBytes) != colorBytes) {
96 SkCodecPrintf("Error: unable to read color table.\n");
97 return false;
98 }
99
100 // Fill in the color table
101 PackColorProc packARGB = choose_pack_color_proc(false, dstColorType);
102 uint32_t i = 0;
103 for (; i < numColorsToRead; i++) {
104 uint8_t blue = get_byte(cBuffer.get(), i*fBytesPerColor);
105 uint8_t green = get_byte(cBuffer.get(), i*fBytesPerColor + 1);
106 uint8_t red = get_byte(cBuffer.get(), i*fBytesPerColor + 2);
107 colorTable[i] = packARGB(0xFF, red, green, blue);
108 }
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 for (; i < maxColors; i++) {
114 colorTable[i] = SkPackARGB32NoCheck(0xFF, 0, 0, 0);
115 }
116
117 // Set the color table
118 fColorTable.reset(new SkColorPalette(colorTable, maxColors));
119 }
120
121 // Check that we have not read past the pixel array offset
122 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 SkCodecPrintf("Error: pixel data offset less than color table size.\n");
129 return false;
130 }
131
132 // After reading the color table, skip to the start of the pixel array
133 if (stream()->skip(fOffset - colorBytes) != fOffset - colorBytes) {
134 SkCodecPrintf("Error: unable to skip to image data.\n");
135 return false;
136 }
137
138 // Return true on success
139 return true;
140}
141
142bool SkBmpRLECodec::initializeStreamBuffer() {
143 fBytesBuffered = this->stream()->read(fStreamBuffer, kBufferSize);
144 if (fBytesBuffered == 0) {
145 SkCodecPrintf("Error: could not read RLE image data.\n");
146 return false;
147 }
148 fCurrRLEByte = 0;
149 return true;
150}
151
152/*
153 * @return the number of bytes remaining in the stream buffer after
154 * attempting to read more bytes from the stream
155 */
156size_t SkBmpRLECodec::checkForMoreData() {
157 const size_t remainingBytes = fBytesBuffered - fCurrRLEByte;
158 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 memmove(buffer, SkTAddOffset<uint8_t>(buffer, fCurrRLEByte), remainingBytes);
165
166 // Adjust the buffer ptr to the start of the unfilled data.
167 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 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 fCurrRLEByte = 0;
177 fBytesBuffered = remainingBytes + additionalBytes;
178 return fBytesBuffered;
179}
180
181/*
182 * Set an RLE pixel using the color table
183 */
184void SkBmpRLECodec::setPixel(void* dst, size_t dstRowBytes,
185 const SkImageInfo& dstInfo, uint32_t x, uint32_t y,
186 uint8_t index) {
187 if (dst && is_coord_necessary(x, fSampleX, dstInfo.width())) {
188 // Set the row
189 uint32_t row = this->getDstRow(y, dstInfo.height());
190
191 // Set the pixel based on destination color type
192 const int dstX = get_dst_coord(x, fSampleX);
193 switch (dstInfo.colorType()) {
196 SkPMColor* dstRow = SkTAddOffset<SkPMColor>(dst, row * (int) dstRowBytes);
197 dstRow[dstX] = fColorTable->operator[](index);
198 break;
199 }
201 uint16_t* dstRow = SkTAddOffset<uint16_t>(dst, row * (int) dstRowBytes);
202 dstRow[dstX] = SkPixel32ToPixel16(fColorTable->operator[](index));
203 break;
204 }
205 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 SkASSERT(false);
209 break;
210 }
211 }
212}
213
214/*
215 * Set an RLE pixel from R, G, B values
216 */
217void 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 uint8_t blue) {
221 if (dst && is_coord_necessary(x, fSampleX, dstInfo.width())) {
222 // Set the row
223 uint32_t row = this->getDstRow(y, dstInfo.height());
224
225 // Set the pixel based on destination color type
226 const int dstX = get_dst_coord(x, fSampleX);
227 switch (dstInfo.colorType()) {
229 SkPMColor* dstRow = SkTAddOffset<SkPMColor>(dst, row * (int) dstRowBytes);
230 dstRow[dstX] = SkPackARGB_as_RGBA(0xFF, red, green, blue);
231 break;
232 }
234 SkPMColor* dstRow = SkTAddOffset<SkPMColor>(dst, row * (int) dstRowBytes);
235 dstRow[dstX] = SkPackARGB_as_BGRA(0xFF, red, green, blue);
236 break;
237 }
239 uint16_t* dstRow = SkTAddOffset<uint16_t>(dst, row * (int) dstRowBytes);
240 dstRow[dstX] = SkPack888ToRGB16(red, green, blue);
241 break;
242 }
243 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 SkASSERT(false);
247 break;
248 }
249 }
250}
251
253 const SkCodec::Options& options) {
254 // FIXME: Support subsets for scanline decodes.
255 if (options.fSubset) {
256 // Subsets are not supported.
257 return kUnimplemented;
258 }
259
260 // Reset fSampleX. If it needs to be a value other than 1, it will get modified by
261 // the sampler.
262 fSampleX = 1;
263 fLinesToSkip = 0;
264
265 SkColorType colorTableColorType = dstInfo.colorType();
266 if (this->colorXform()) {
267 // Just set a known colorType for the colorTable. No need to actually transform
268 // the colors in the colorTable.
269 colorTableColorType = kBGRA_8888_SkColorType;
270 }
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 if (!this->createColorTable(colorTableColorType)) {
275 SkCodecPrintf("Error: could not create color table.\n");
277 }
278
279 // Initialize a buffer for encoded RLE data
280 if (!this->initializeStreamBuffer()) {
281 SkCodecPrintf("Error: cannot initialize stream buffer.\n");
283 }
284
285 return SkCodec::kSuccess;
286}
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 */
292int SkBmpRLECodec::decodeRows(const SkImageInfo& info, void* dst, size_t dstRowBytes,
293 const Options& opts) {
294 int height = info.height();
295
296 // Account for sampling.
297 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 if (dst) {
302 SkSampler::Fill(dstInfo, dst, dstRowBytes, opts.fZeroInitialized);
303 }
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 if (height > fLinesToSkip) {
308 height -= fLinesToSkip;
309 if (dst) {
310 dst = SkTAddOffset<void>(dst, fLinesToSkip * dstRowBytes);
311 }
312 fLinesToSkip = 0;
313
315 } else {
316 fLinesToSkip -= height;
317 return height;
318 }
319
320 void* decodeDst = dst;
321 size_t decodeRowBytes = dstRowBytes;
322 SkImageInfo decodeInfo = dstInfo;
323 if (decodeDst) {
324 if (this->colorXform()) {
325 decodeInfo = decodeInfo.makeColorType(kXformSrcColorType);
327 int count = height * dstInfo.width();
328 this->resetXformBuffer(count);
329 sk_bzero(this->xformBuffer(), count * sizeof(uint32_t));
330 decodeDst = this->xformBuffer();
331 decodeRowBytes = dstInfo.width() * sizeof(uint32_t);
332 }
333 }
334 }
335
336 int decodedHeight = this->decodeRLE(decodeInfo, decodeDst, decodeRowBytes);
337 if (this->colorXform() && decodeDst) {
338 for (int y = 0; y < decodedHeight; y++) {
339 this->applyColorXform(dst, decodeDst, dstInfo.width());
340 decodeDst = SkTAddOffset<void>(decodeDst, decodeRowBytes);
341 dst = SkTAddOffset<void>(dst, dstRowBytes);
342 }
343 }
344
345 return decodedHeight;
346}
347
348int 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 const int width = this->dimensions().width();
351
352 // This tells us the number of rows that we are meant to decode.
353 const int height = dstInfo.height();
354
355 // Set RLE flags
356 constexpr uint8_t RLE_ESCAPE = 0;
357 constexpr uint8_t RLE_EOL = 0;
358 constexpr uint8_t RLE_EOF = 1;
359 constexpr uint8_t RLE_DELTA = 2;
360
361 // Destination parameters
362 int x = 0;
363 int y = 0;
364
365 while (true) {
366 // If we have reached a row that is beyond the requested height, we have
367 // succeeded.
368 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 return height;
373 }
374
375 // Every entry takes at least two bytes
376 if ((int) fBytesBuffered - fCurrRLEByte < 2) {
377 if (this->checkForMoreData() < 2) {
378 return y;
379 }
380 }
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 const uint8_t flag = fStreamBuffer[fCurrRLEByte++];
387 const uint8_t task = fStreamBuffer[fCurrRLEByte++];
388
389 // Perform decoding
390 if (RLE_ESCAPE == flag) {
391 switch (task) {
392 case RLE_EOL:
393 x = 0;
394 y++;
395 break;
396 case RLE_EOF:
397 return height;
398 case RLE_DELTA: {
399 // Two bytes are needed to specify delta
400 if ((int) fBytesBuffered - fCurrRLEByte < 2) {
401 if (this->checkForMoreData() < 2) {
402 return y;
403 }
404 }
405 // Modify x and y
406 const uint8_t dx = fStreamBuffer[fCurrRLEByte++];
407 const uint8_t dy = fStreamBuffer[fCurrRLEByte++];
408 x += dx;
409 y += dy;
410 if (x > width) {
411 SkCodecPrintf("Warning: invalid RLE input.\n");
412 return y - dy;
413 } else if (y > height) {
414 fLinesToSkip = y - height;
415 return height;
416 }
417 break;
418 }
419 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 uint8_t numPixels = task;
425 const size_t rowBytes = compute_row_bytes(numPixels,
426 this->bitsPerPixel());
427 if (x + numPixels > width) {
428 SkCodecPrintf("Warning: invalid RLE input.\n");
429 }
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 static_assert(255 * 3 + 1 < kBufferSize,
439 "kBufferSize needs to be larger!");
440 const size_t alignedRowBytes = SkAlign2(rowBytes);
441 if ((int) fBytesBuffered - fCurrRLEByte < alignedRowBytes) {
442 SkASSERT(alignedRowBytes < kBufferSize);
443 if (this->checkForMoreData() < alignedRowBytes) {
444 return y;
445 }
446 }
447 // Set numPixels number of pixels
448 while ((numPixels > 0) && (x < width)) {
449 switch(this->bitsPerPixel()) {
450 case 4: {
451 SkASSERT(fCurrRLEByte < fBytesBuffered);
452 uint8_t val = fStreamBuffer[fCurrRLEByte++];
453 setPixel(dst, dstRowBytes, dstInfo, x++,
454 y, val >> 4);
455 numPixels--;
456 if (numPixels != 0) {
457 setPixel(dst, dstRowBytes, dstInfo,
458 x++, y, val & 0xF);
459 numPixels--;
460 }
461 break;
462 }
463 case 8:
464 SkASSERT(fCurrRLEByte < fBytesBuffered);
465 setPixel(dst, dstRowBytes, dstInfo, x++,
466 y, fStreamBuffer[fCurrRLEByte++]);
467 numPixels--;
468 break;
469 case 24: {
470 SkASSERT(fCurrRLEByte + 2 < fBytesBuffered);
471 uint8_t blue = fStreamBuffer[fCurrRLEByte++];
472 uint8_t green = fStreamBuffer[fCurrRLEByte++];
473 uint8_t red = fStreamBuffer[fCurrRLEByte++];
474 setRGBPixel(dst, dstRowBytes, dstInfo,
475 x++, y, red, green, blue);
476 numPixels--;
477 break;
478 }
479 default:
480 SkASSERT(false);
481 return y;
482 }
483 }
484 // Skip a byte if necessary to maintain alignment
485 if (!SkIsAlign2(rowBytes)) {
486 fCurrRLEByte++;
487 }
488 break;
489 }
490 }
491 } else {
492 // If the first byte read is not a flag, it indicates the number of
493 // pixels to set in RLE mode.
494 const uint8_t numPixels = flag;
495 const int endX = std::min<int>(x + numPixels, width);
496
497 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 if ((int) fBytesBuffered - fCurrRLEByte < 2) {
502 if (this->checkForMoreData() < 2) {
503 return y;
504 }
505 }
506
507 // Fill the pixels up to endX with the specified color
508 uint8_t blue = task;
509 uint8_t green = fStreamBuffer[fCurrRLEByte++];
510 uint8_t red = fStreamBuffer[fCurrRLEByte++];
511 while (x < endX) {
512 setRGBPixel(dst, dstRowBytes, dstInfo, x++, y, red, green, blue);
513 }
514 } 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 uint8_t indices[2] = { task, task };
521 if (4 == this->bitsPerPixel()) {
522 indices[0] >>= 4;
523 indices[1] &= 0xf;
524 }
525
526 // Set the indicated number of pixels
527 for (int which = 0; x < endX; x++) {
528 setPixel(dst, dstRowBytes, dstInfo, x, y, indices[which]);
529 which = !which;
530 }
531 }
532 }
533 }
534}
535
537 const SkImageInfo rowInfo = SkImageInfo::Make(this->dimensions().width(), count,
538 kN32_SkColorType, kUnpremul_SkAlphaType);
539 return count == this->decodeRows(rowInfo, nullptr, 0, this->options());
540}
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.
546public:
548 : fCodec(codec)
549 {
550 SkASSERT(fCodec);
551 }
552
553 int fillWidth() const override {
554 return fCodec->fillWidth();
555 }
556
557private:
558 int onSetSampleX(int sampleX) override {
559 return fCodec->setSampleX(sampleX);
560 }
561
562 // Unowned pointer. fCodec will delete this class in its destructor.
563 SkBmpRLECodec* fCodec;
564};
565
566SkSampler* SkBmpRLECodec::getSampler(bool createIfNecessary) {
567 if (!fSampler && createIfNecessary) {
568 fSampler = std::make_unique<SkBmpRLESampler>(this);
569 }
570
571 return fSampler.get();
572}
573
575 fSampleX = sampleX;
576 return this->fillWidth();
577}
578
580 return get_scaled_dimension(this->dimensions().width(), fSampleX);
581}
const char * options
static void info(const char *fmt,...) SK_PRINTF_LIKE(1
Definition DM.cpp:213
int count
kUnpremul_SkAlphaType
static constexpr bool SkIsAlign2(T x)
Definition SkAlign.h:19
static constexpr T SkAlign2(T x)
Definition SkAlign.h:15
#define SkASSERT(cond)
Definition SkAssert.h:116
static bool is_coord_necessary(int srcCoord, int sampleFactor, int scaledDim)
Definition SkCodecPriv.h:77
static uint8_t get_byte(const uint8_t *buffer, uint32_t i)
uint32_t(* PackColorProc)(U8CPU a, U8CPU r, U8CPU g, U8CPU b)
static PackColorProc choose_pack_color_proc(bool isPremul, SkColorType colorType)
static size_t compute_row_bytes(int width, uint32_t bitsPerPixel)
static int get_dst_coord(int srcCoord, int sampleFactor)
Definition SkCodecPriv.h:67
static int get_scaled_dimension(int srcDimension, int sampleSize)
Definition SkCodecPriv.h:44
#define SkCodecPrintf(...)
Definition SkCodecPriv.h:23
static uint32_t SkPackARGB_as_RGBA(U8CPU a, U8CPU r, U8CPU g, U8CPU b)
Definition SkColorData.h:65
static U16CPU SkPack888ToRGB16(U8CPU r, U8CPU g, U8CPU b)
static U16CPU SkPixel32ToPixel16(SkPMColor c)
static uint32_t SkPackARGB_as_BGRA(U8CPU a, U8CPU r, U8CPU g, U8CPU b)
Definition SkColorData.h:74
static SkPMColor SkPackARGB32NoCheck(U8CPU a, U8CPU r, U8CPU g, U8CPU b)
SkColorType
Definition SkColorType.h:19
@ kBGRA_8888_SkColorType
pixel with 8 bits for blue, green, red, alpha; in 32-bit word
Definition SkColorType.h:26
@ kRGBA_F16_SkColorType
pixel with half floats for red, green, blue, alpha;
Definition SkColorType.h:38
@ kRGB_565_SkColorType
pixel with 5 bits red, 6 bits green, 5 bits blue, in 16-bit word
Definition SkColorType.h:22
@ kRGBA_8888_SkColorType
pixel with 8 bits for red, green, blue, alpha; in 32-bit word
Definition SkColorType.h:24
uint32_t SkPMColor
Definition SkColor.h:205
static bool read(SkStream *stream, void *buffer, size_t amount)
static bool skip(SkStream *stream, size_t amount)
static void sk_bzero(void *buffer, size_t size)
Definition SkMalloc.h:105
void resetXformBuffer(int count)
Definition SkBmpCodec.h:105
int32_t getDstRow(int32_t y, int32_t height) const
SkCodec::Result prepareToDecode(const SkImageInfo &dstInfo, const SkCodec::Options &options)
uint32_t * xformBuffer() const
Definition SkBmpCodec.h:104
static constexpr SkColorType kXformSrcColorType
Definition SkBmpCodec.h:111
uint16_t bitsPerPixel() const
Definition SkBmpCodec.h:87
int fillWidth() const
Result onGetPixels(const SkImageInfo &dstInfo, void *dst, size_t dstRowBytes, const Options &, int *) override
SkCodec::Result onPrepareToDecode(const SkImageInfo &dstInfo, const SkCodec::Options &options) override
SkSampler * getSampler(bool createIfNecessary) override
bool skipRows(int count) override
SkBmpRLECodec(SkEncodedInfo &&info, std::unique_ptr< SkStream >, uint16_t bitsPerPixel, uint32_t numColors, uint32_t bytesPerColor, uint32_t offset, SkCodec::SkScanlineOrder rowOrder)
int decodeRows(const SkImageInfo &dstInfo, void *dst, size_t dstRowBytes, const Options &opts) override
SkBmpRLESampler(SkBmpRLECodec *codec)
int onSetSampleX(int sampleX) override
int fillWidth() const override
SkISize dimensions() const
Definition SkCodec.h:230
const SkImageInfo & dstInfo() const
Definition SkCodec.h:878
SkStream * stream()
Definition SkCodec.h:865
void applyColorXform(void *dst, const void *src, int count) const
Definition SkCodec.cpp:853
SkScanlineOrder
Definition SkCodec.h:575
@ kIncompleteInput
Definition SkCodec.h:84
@ kInvalidInput
Definition SkCodec.h:109
@ kUnimplemented
Definition SkCodec.h:123
@ kSuccess
Definition SkCodec.h:80
bool colorXform() const
Definition SkCodec.h:906
const Options & options() const
Definition SkCodec.h:880
static void Fill(const SkImageInfo &info, void *dst, size_t rowBytes, SkCodec::ZeroInitialized zeroInit)
Definition SkSampler.cpp:20
virtual size_t read(void *buffer, size_t size)=0
void reset(T *ptr=nullptr)
Definition SkRefCnt.h:310
FlutterSemanticsFlag flag
static const uint8_t buffer[]
GAsyncResult * result
double y
double x
skia_private::AutoTArray< sk_sp< SkImageFilter > > filters TypedMatrix matrix TypedMatrix matrix SkScalar dx
Definition SkRecords.h:208
Definition ref_ptr.h:256
int32_t height
int32_t width
Point offset
const SkIRect * fSubset
Definition SkCodec.h:347
ZeroInitialized fZeroInitialized
Definition SkCodec.h:329
constexpr int32_t width() const
Definition SkSize.h:36
SkImageInfo makeWH(int newWidth, int newHeight) const
int width() const
static SkImageInfo Make(int width, int height, SkColorType ct, SkAlphaType at)
SkColorType colorType() const
int height() const
SkImageInfo makeColorType(SkColorType newColorType) const