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/SkBmpCodec.h"
9
10#include <memory>
11
12#include "include/core/SkStream.h"
13#include "include/private/SkColorData.h"
14#include "src/codec/SkBmpMaskCodec.h"
15#include "src/codec/SkBmpRLECodec.h"
16#include "src/codec/SkBmpStandardCodec.h"
17#include "src/codec/SkCodecPriv.h"
18
19/*
20 * Defines the version and type of the second bitmap header
21 */
22enum BmpHeaderType {
23 kInfoV1_BmpHeaderType,
24 kInfoV2_BmpHeaderType,
25 kInfoV3_BmpHeaderType,
26 kInfoV4_BmpHeaderType,
27 kInfoV5_BmpHeaderType,
28 kOS2V1_BmpHeaderType,
29 kOS2VX_BmpHeaderType,
30 kUnknown_BmpHeaderType
31};
32
33/*
34 * Possible bitmap compression types
35 */
36enum BmpCompressionMethod {
37 kNone_BmpCompressionMethod = 0,
38 k8BitRLE_BmpCompressionMethod = 1,
39 k4BitRLE_BmpCompressionMethod = 2,
40 kBitMasks_BmpCompressionMethod = 3,
41 kJpeg_BmpCompressionMethod = 4,
42 kPng_BmpCompressionMethod = 5,
43 kAlphaBitMasks_BmpCompressionMethod = 6,
44 kCMYK_BmpCompressionMethod = 11,
45 kCMYK8BitRLE_BmpCompressionMethod = 12,
46 kCMYK4BitRLE_BmpCompressionMethod = 13
47};
48
49/*
50 * Used to define the input format of the bmp
51 */
52enum BmpInputFormat {
53 kStandard_BmpInputFormat,
54 kRLE_BmpInputFormat,
55 kBitMask_BmpInputFormat,
56 kUnknown_BmpInputFormat
57};
58
59/*
60 * Checks the start of the stream to see if the image is a bitmap
61 */
62bool SkBmpCodec::IsBmp(const void* buffer, size_t bytesRead) {
63 // TODO: Support "IC", "PT", "CI", "CP", "BA"
64 const char bmpSig[] = { 'B', 'M' };
65 return bytesRead >= sizeof(bmpSig) && !memcmp(buffer, bmpSig, sizeof(bmpSig));
66}
67
68/*
69 * Assumes IsBmp was called and returned true
70 * Creates a bmp decoder
71 * Reads enough of the stream to determine the image format
72 */
73std::unique_ptr<SkCodec> SkBmpCodec::MakeFromStream(std::unique_ptr<SkStream> stream,
74 Result* result) {
75 return SkBmpCodec::MakeFromStream(std::move(stream), result, false);
76}
77
78/*
79 * Creates a bmp decoder for a bmp embedded in ico
80 * Reads enough of the stream to determine the image format
81 */
82std::unique_ptr<SkCodec> SkBmpCodec::MakeFromIco(std::unique_ptr<SkStream> stream, Result* result) {
83 return SkBmpCodec::MakeFromStream(std::move(stream), result, true);
84}
85
86// Header size constants
87static constexpr uint32_t kBmpHeaderBytes = 14;
88static constexpr uint32_t kBmpHeaderBytesPlusFour = kBmpHeaderBytes + 4;
89static constexpr uint32_t kBmpOS2V1Bytes = 12;
90static constexpr uint32_t kBmpOS2V2Bytes = 64;
91static constexpr uint32_t kBmpInfoBaseBytes = 16;
92static constexpr uint32_t kBmpInfoV1Bytes = 40;
93static constexpr uint32_t kBmpInfoV2Bytes = 52;
94static constexpr uint32_t kBmpInfoV3Bytes = 56;
95static constexpr uint32_t kBmpInfoV4Bytes = 108;
96static constexpr uint32_t kBmpInfoV5Bytes = 124;
97static constexpr uint32_t kBmpMaskBytes = 12;
98
99static BmpHeaderType get_header_type(size_t infoBytes) {
100 if (infoBytes >= kBmpInfoBaseBytes) {
101 // Check the version of the header
102 switch (infoBytes) {
103 case kBmpInfoV1Bytes:
104 return kInfoV1_BmpHeaderType;
105 case kBmpInfoV2Bytes:
106 return kInfoV2_BmpHeaderType;
107 case kBmpInfoV3Bytes:
108 return kInfoV3_BmpHeaderType;
109 case kBmpInfoV4Bytes:
110 return kInfoV4_BmpHeaderType;
111 case kBmpInfoV5Bytes:
112 return kInfoV5_BmpHeaderType;
113 case 16:
114 case 20:
115 case 24:
116 case 28:
117 case 32:
118 case 36:
119 case 42:
120 case 46:
121 case 48:
122 case 60:
123 case kBmpOS2V2Bytes:
124 return kOS2VX_BmpHeaderType;
125 default:
126 SkCodecPrintf("Error: unknown bmp header format.\n");
127 return kUnknown_BmpHeaderType;
128 }
129 } if (infoBytes >= kBmpOS2V1Bytes) {
130 // The OS2V1 is treated separately because it has a unique format
131 return kOS2V1_BmpHeaderType;
132 } else {
133 // There are no valid bmp headers
134 SkCodecPrintf("Error: second bitmap header size is invalid.\n");
135 return kUnknown_BmpHeaderType;
136 }
137}
138
139SkCodec::Result SkBmpCodec::ReadHeader(SkStream* stream, bool inIco,
140 std::unique_ptr<SkCodec>* codecOut) {
141 // The total bytes in the bmp file
142 // We only need to use this value for RLE decoding, so we will only
143 // check that it is valid in the RLE case.
144 uint32_t totalBytes;
145 // The offset from the start of the file where the pixel data begins
146 uint32_t offset;
147 // The size of the second (info) header in bytes
148 uint32_t infoBytes;
149
150 // Bmps embedded in Icos skip the first Bmp header
151 if (!inIco) {
152 // Read the first header and the size of the second header
153 uint8_t hBuffer[kBmpHeaderBytesPlusFour];
154 if (stream->read(hBuffer, kBmpHeaderBytesPlusFour) !=
155 kBmpHeaderBytesPlusFour) {
156 SkCodecPrintf("Error: unable to read first bitmap header.\n");
157 return kIncompleteInput;
158 }
159
160 totalBytes = get_int(hBuffer, 2);
161 offset = get_int(hBuffer, 10);
162 if (offset < kBmpHeaderBytes + kBmpOS2V1Bytes) {
163 SkCodecPrintf("Error: invalid starting location for pixel data\n");
164 return kInvalidInput;
165 }
166
167 // The size of the second (info) header in bytes
168 // The size is the first field of the second header, so we have already
169 // read the first four infoBytes.
170 infoBytes = get_int(hBuffer, 14);
171 if (infoBytes < kBmpOS2V1Bytes) {
172 SkCodecPrintf("Error: invalid second header size.\n");
173 return kInvalidInput;
174 }
175 } else {
176 // This value is only used by RLE compression. Bmp in Ico files do not
177 // use RLE. If the compression field is incorrectly signaled as RLE,
178 // we will catch this and signal an error below.
179 totalBytes = 0;
180
181 // Bmps in Ico cannot specify an offset. We will always assume that
182 // pixel data begins immediately after the color table. This value
183 // will be corrected below.
184 offset = 0;
185
186 // Read the size of the second header
187 uint8_t hBuffer[4];
188 if (stream->read(hBuffer, 4) != 4) {
189 SkCodecPrintf("Error: unable to read size of second bitmap header.\n");
190 return kIncompleteInput;
191 }
192 infoBytes = get_int(hBuffer, 0);
193 if (infoBytes < kBmpOS2V1Bytes) {
194 SkCodecPrintf("Error: invalid second header size.\n");
195 return kInvalidInput;
196 }
197 }
198
199 // Determine image information depending on second header format
200 const BmpHeaderType headerType = get_header_type(infoBytes);
201 if (kUnknown_BmpHeaderType == headerType) {
202 return kInvalidInput;
203 }
204
205 // We already read the first four bytes of the info header to get the size
206 const uint32_t infoBytesRemaining = infoBytes - 4;
207
208 // Read the second header
209 std::unique_ptr<uint8_t[]> iBuffer(new uint8_t[infoBytesRemaining]);
210 if (stream->read(iBuffer.get(), infoBytesRemaining) != infoBytesRemaining) {
211 SkCodecPrintf("Error: unable to read second bitmap header.\n");
212 return kIncompleteInput;
213 }
214
215 // The number of bits used per pixel in the pixel data
216 uint16_t bitsPerPixel;
217
218 // The compression method for the pixel data
219 uint32_t compression = kNone_BmpCompressionMethod;
220
221 // Number of colors in the color table, defaults to 0 or max (see below)
222 uint32_t numColors = 0;
223
224 // Bytes per color in the color table, early versions use 3, most use 4
225 uint32_t bytesPerColor;
226
227 // The image width and height
228 int width, height;
229
230 switch (headerType) {
231 case kInfoV1_BmpHeaderType:
232 case kInfoV2_BmpHeaderType:
233 case kInfoV3_BmpHeaderType:
234 case kInfoV4_BmpHeaderType:
235 case kInfoV5_BmpHeaderType:
236 case kOS2VX_BmpHeaderType:
237 // We check the size of the header before entering the if statement.
238 // We should not reach this point unless the size is large enough for
239 // these required fields.
240 SkASSERT(infoBytesRemaining >= 12);
241 width = get_int(iBuffer.get(), 0);
242 height = get_int(iBuffer.get(), 4);
243 bitsPerPixel = get_short(iBuffer.get(), 10);
244
245 // Some versions do not have these fields, so we check before
246 // overwriting the default value.
247 if (infoBytesRemaining >= 16) {
248 compression = get_int(iBuffer.get(), 12);
249 if (infoBytesRemaining >= 32) {
250 numColors = get_int(iBuffer.get(), 28);
251 }
252 }
253
254 // All of the headers that reach this point, store color table entries
255 // using 4 bytes per pixel.
256 bytesPerColor = 4;
257 break;
258 case kOS2V1_BmpHeaderType:
259 // The OS2V1 is treated separately because it has a unique format
260 width = (int) get_short(iBuffer.get(), 0);
261 height = (int) get_short(iBuffer.get(), 2);
262 bitsPerPixel = get_short(iBuffer.get(), 6);
263 bytesPerColor = 3;
264 break;
265 case kUnknown_BmpHeaderType:
266 // We'll exit above in this case.
267 SkASSERT(false);
268 return kInvalidInput;
269 }
270
271 // Check for valid dimensions from header
272 SkCodec::SkScanlineOrder rowOrder = SkCodec::kBottomUp_SkScanlineOrder;
273 if (height < 0) {
274 // We can't negate INT32_MIN.
275 if (height == INT32_MIN) {
276 return kInvalidInput;
277 }
278
279 height = -height;
280 rowOrder = SkCodec::kTopDown_SkScanlineOrder;
281 }
282 // The height field for bmp in ico is double the actual height because they
283 // contain an XOR mask followed by an AND mask
284 if (inIco) {
285 height /= 2;
286 }
287
288 // Arbitrary maximum. Matches Chromium.
289 constexpr int kMaxDim = 1 << 16;
290 if (width <= 0 || height <= 0 || width >= kMaxDim || height >= kMaxDim) {
291 SkCodecPrintf("Error: invalid bitmap dimensions.\n");
292 return kInvalidInput;
293 }
294
295 // Create mask struct
296 SkMasks::InputMasks inputMasks;
297 memset(&inputMasks, 0, sizeof(SkMasks::InputMasks));
298
299 // Determine the input compression format and set bit masks if necessary
300 uint32_t maskBytes = 0;
301 BmpInputFormat inputFormat = kUnknown_BmpInputFormat;
302 switch (compression) {
303 case kNone_BmpCompressionMethod:
304 inputFormat = kStandard_BmpInputFormat;
305
306 // In addition to more standard pixel compression formats, bmp supports
307 // the use of bit masks to determine pixel components. The standard
308 // format for representing 16-bit colors is 555 (XRRRRRGGGGGBBBBB),
309 // which does not map well to any Skia color formats. For this reason,
310 // we will always enable mask mode with 16 bits per pixel.
311 if (16 == bitsPerPixel) {
312 inputMasks.red = 0x7C00;
313 inputMasks.green = 0x03E0;
314 inputMasks.blue = 0x001F;
315 inputFormat = kBitMask_BmpInputFormat;
316 }
317 break;
318 case k8BitRLE_BmpCompressionMethod:
319 if (bitsPerPixel != 8) {
320 SkCodecPrintf("Warning: correcting invalid bitmap format.\n");
321 bitsPerPixel = 8;
322 }
323 inputFormat = kRLE_BmpInputFormat;
324 break;
325 case k4BitRLE_BmpCompressionMethod:
326 if (bitsPerPixel != 4) {
327 SkCodecPrintf("Warning: correcting invalid bitmap format.\n");
328 bitsPerPixel = 4;
329 }
330 inputFormat = kRLE_BmpInputFormat;
331 break;
332 case kAlphaBitMasks_BmpCompressionMethod:
333 case kBitMasks_BmpCompressionMethod:
334 // Load the masks
335 inputFormat = kBitMask_BmpInputFormat;
336 switch (headerType) {
337 case kInfoV1_BmpHeaderType: {
338 // The V1 header stores the bit masks after the header
339 uint8_t buffer[kBmpMaskBytes];
340 if (stream->read(buffer, kBmpMaskBytes) != kBmpMaskBytes) {
341 SkCodecPrintf("Error: unable to read bit inputMasks.\n");
342 return kIncompleteInput;
343 }
344 maskBytes = kBmpMaskBytes;
345 inputMasks.red = get_int(buffer, 0);
346 inputMasks.green = get_int(buffer, 4);
347 inputMasks.blue = get_int(buffer, 8);
348 break;
349 }
350 case kInfoV2_BmpHeaderType:
351 case kInfoV3_BmpHeaderType:
352 case kInfoV4_BmpHeaderType:
353 case kInfoV5_BmpHeaderType:
354 // Header types are matched based on size. If the header
355 // is V2+, we are guaranteed to be able to read at least
356 // this size.
357 SkASSERT(infoBytesRemaining >= 48);
358 inputMasks.red = get_int(iBuffer.get(), 36);
359 inputMasks.green = get_int(iBuffer.get(), 40);
360 inputMasks.blue = get_int(iBuffer.get(), 44);
361
362 if (kInfoV2_BmpHeaderType == headerType ||
363 (kInfoV3_BmpHeaderType == headerType && !inIco)) {
364 break;
365 }
366
367 // V3+ bmp files introduce an alpha mask and allow the creator of the image
368 // to use the alpha channels. However, many of these images leave the
369 // alpha channel blank and expect to be rendered as opaque. This is the
370 // case for almost all V3 images, so we ignore the alpha mask. For V4+
371 // images in kMask mode, we will use the alpha mask. Additionally, V3
372 // bmp-in-ico expect us to use the alpha mask.
373 //
374 // skbug.com/4116: We should perhaps also apply the alpha mask in kStandard
375 // mode. We just haven't seen any images that expect this
376 // behavior.
377 //
378 // Header types are matched based on size. If the header is
379 // V3+, we are guaranteed to be able to read at least this size.
380 SkASSERT(infoBytesRemaining >= 52);
381 inputMasks.alpha = get_int(iBuffer.get(), 48);
382 break;
383 case kOS2VX_BmpHeaderType:
384 // TODO: Decide if we intend to support this.
385 // It is unsupported in the previous version and
386 // in chromium. I have not come across a test case
387 // that uses this format.
388 SkCodecPrintf("Error: huffman format unsupported.\n");
389 return kUnimplemented;
390 default:
391 SkCodecPrintf("Error: invalid bmp bit masks header.\n");
392 return kInvalidInput;
393 }
394 break;
395 case kJpeg_BmpCompressionMethod:
396 if (24 == bitsPerPixel) {
397 inputFormat = kRLE_BmpInputFormat;
398 break;
399 }
400 [[fallthrough]];
401 case kPng_BmpCompressionMethod:
402 // TODO: Decide if we intend to support this.
403 // It is unsupported in the previous version and
404 // in chromium. I think it is used mostly for printers.
405 SkCodecPrintf("Error: compression format not supported.\n");
406 return kUnimplemented;
407 case kCMYK_BmpCompressionMethod:
408 case kCMYK8BitRLE_BmpCompressionMethod:
409 case kCMYK4BitRLE_BmpCompressionMethod:
410 // TODO: Same as above.
411 SkCodecPrintf("Error: CMYK not supported for bitmap decoding.\n");
412 return kUnimplemented;
413 default:
414 SkCodecPrintf("Error: invalid format for bitmap decoding.\n");
415 return kInvalidInput;
416 }
417 iBuffer.reset();
418
419 // Calculate the number of bytes read so far
420 const uint32_t bytesRead = kBmpHeaderBytes + infoBytes + maskBytes;
421 if (!inIco && offset < bytesRead) {
422 // TODO (msarett): Do we really want to fail if the offset in the header is invalid?
423 // Seems like we can just assume that the offset is zero and try to decode?
424 // Maybe we don't want to try to decode corrupt images?
425 SkCodecPrintf("Error: pixel data offset less than header size.\n");
426 return kInvalidInput;
427 }
428
429
430
431 switch (inputFormat) {
432 case kStandard_BmpInputFormat: {
433 // BMPs are generally opaque, however BMPs-in-ICOs may contain
434 // a transparency mask after the image. Therefore, we mark the
435 // alpha as kBinary if the BMP is contained in an ICO.
436 // We use |isOpaque| to indicate if the BMP itself is opaque.
437 SkEncodedInfo::Alpha alpha = inIco ? SkEncodedInfo::kBinary_Alpha :
438 SkEncodedInfo::kOpaque_Alpha;
439 bool isOpaque = true;
440
441 SkEncodedInfo::Color color;
442 uint8_t bitsPerComponent;
443 switch (bitsPerPixel) {
444 // Palette formats
445 case 1:
446 case 2:
447 case 4:
448 case 8:
449 // In the case of ICO, kBGRA is actually the closest match,
450 // since we will need to apply a transparency mask.
451 if (inIco) {
452 color = SkEncodedInfo::kBGRA_Color;
453 bitsPerComponent = 8;
454 } else {
455 color = SkEncodedInfo::kPalette_Color;
456 bitsPerComponent = (uint8_t) bitsPerPixel;
457 }
458 break;
459 case 24:
460 // In the case of ICO, kBGRA is actually the closest match,
461 // since we will need to apply a transparency mask.
462 color = inIco ? SkEncodedInfo::kBGRA_Color : SkEncodedInfo::kBGR_Color;
463 bitsPerComponent = 8;
464 break;
465 case 32:
466 // 32-bit BMP-in-ICOs actually use the alpha channel in place of a
467 // transparency mask.
468 if (inIco) {
469 isOpaque = false;
470 alpha = SkEncodedInfo::kUnpremul_Alpha;
471 color = SkEncodedInfo::kBGRA_Color;
472 } else {
473 color = SkEncodedInfo::kBGRX_Color;
474 }
475 bitsPerComponent = 8;
476 break;
477 default:
478 SkCodecPrintf("Error: invalid input value for bits per pixel.\n");
479 return kInvalidInput;
480 }
481
482 if (codecOut) {
483 // We require streams to have a memory base for Bmp-in-Ico decodes.
484 SkASSERT(!inIco || nullptr != stream->getMemoryBase());
485
486 // Set the image info and create a codec.
487 auto info = SkEncodedInfo::Make(width, height, color, alpha, bitsPerComponent);
488 *codecOut = std::make_unique<SkBmpStandardCodec>(std::move(info),
489 std::unique_ptr<SkStream>(stream),
490 bitsPerPixel, numColors, bytesPerColor,
491 offset - bytesRead, rowOrder, isOpaque,
492 inIco);
493 return static_cast<SkBmpStandardCodec*>(codecOut->get())->didCreateSrcBuffer()
494 ? kSuccess : kInvalidInput;
495 }
496 return kSuccess;
497 }
498
499 case kBitMask_BmpInputFormat: {
500 // Bmp-in-Ico must be standard mode
501 if (inIco) {
502 SkCodecPrintf("Error: Icos may not use bit mask format.\n");
503 return kInvalidInput;
504 }
505
506 switch (bitsPerPixel) {
507 case 16:
508 case 24:
509 case 32:
510 break;
511 default:
512 SkCodecPrintf("Error: invalid input value for bits per pixel.\n");
513 return kInvalidInput;
514 }
515
516 // Skip to the start of the pixel array.
517 // We can do this here because there is no color table to read
518 // in bit mask mode.
519 if (stream->skip(offset - bytesRead) != offset - bytesRead) {
520 SkCodecPrintf("Error: unable to skip to image data.\n");
521 return kIncompleteInput;
522 }
523
524 if (codecOut) {
525 // Check that input bit masks are valid and create the masks object
526 SkASSERT(bitsPerPixel % 8 == 0);
527 std::unique_ptr<SkMasks> masks(SkMasks::CreateMasks(inputMasks, bitsPerPixel/8));
528 if (nullptr == masks) {
529 SkCodecPrintf("Error: invalid input masks.\n");
530 return kInvalidInput;
531 }
532
533 // Masked bmps are not a great fit for SkEncodedInfo, since they have
534 // arbitrary component orderings and bits per component. Here we choose
535 // somewhat reasonable values - it's ok that we don't match exactly
536 // because SkBmpMaskCodec has its own mask swizzler anyway.
537 SkEncodedInfo::Color color;
538 SkEncodedInfo::Alpha alpha;
539 if (masks->getAlphaMask()) {
540 color = SkEncodedInfo::kBGRA_Color;
541 alpha = SkEncodedInfo::kUnpremul_Alpha;
542 } else {
543 color = SkEncodedInfo::kBGR_Color;
544 alpha = SkEncodedInfo::kOpaque_Alpha;
545 }
546 auto info = SkEncodedInfo::Make(width, height, color, alpha, 8);
547 *codecOut = std::make_unique<SkBmpMaskCodec>(std::move(info),
548 std::unique_ptr<SkStream>(stream), bitsPerPixel,
549 masks.release(), rowOrder);
550 return static_cast<SkBmpMaskCodec*>(codecOut->get())->didCreateSrcBuffer()
551 ? kSuccess : kInvalidInput;
552 }
553 return kSuccess;
554 }
555
556 case kRLE_BmpInputFormat: {
557 // We should not reach this point without a valid value of bitsPerPixel.
558 SkASSERT(4 == bitsPerPixel || 8 == bitsPerPixel || 24 == bitsPerPixel);
559
560 // Check for a valid number of total bytes when in RLE mode
561 if (totalBytes <= offset) {
562 SkCodecPrintf("Error: RLE requires valid input size.\n");
563 return kInvalidInput;
564 }
565
566 // Bmp-in-Ico must be standard mode
567 // When inIco is true, this line cannot be reached, since we
568 // require that RLE Bmps have a valid number of totalBytes, and
569 // Icos skip the header that contains totalBytes.
570 SkASSERT(!inIco);
571
572 if (codecOut) {
573 // RLE inputs may skip pixels, leaving them as transparent. This
574 // is uncommon, but we cannot be certain that an RLE bmp will be
575 // opaque or that we will be able to represent it with a palette.
576 // For that reason, we always indicate that we are kBGRA.
577 auto info = SkEncodedInfo::Make(width, height, SkEncodedInfo::kBGRA_Color,
578 SkEncodedInfo::kBinary_Alpha, 8);
579 *codecOut = std::make_unique<SkBmpRLECodec>(std::move(info),
580 std::unique_ptr<SkStream>(stream), bitsPerPixel,
581 numColors, bytesPerColor, offset - bytesRead,
582 rowOrder);
583 }
584 return kSuccess;
585 }
586 default:
587 SkASSERT(false);
588 return kInvalidInput;
589 }
590}
591
592/*
593 * Creates a bmp decoder
594 * Reads enough of the stream to determine the image format
595 */
596std::unique_ptr<SkCodec> SkBmpCodec::MakeFromStream(std::unique_ptr<SkStream> stream,
597 Result* result, bool inIco) {
598 std::unique_ptr<SkCodec> codec;
599 *result = ReadHeader(stream.get(), inIco, &codec);
600 if (codec) {
601 // codec has taken ownership of stream, so we do not need to delete it.
602 stream.release();
603 }
604 return kSuccess == *result ? std::move(codec) : nullptr;
605}
606
607SkBmpCodec::SkBmpCodec(SkEncodedInfo&& info, std::unique_ptr<SkStream> stream,
608 uint16_t bitsPerPixel, SkCodec::SkScanlineOrder rowOrder)
609 : INHERITED(std::move(info), kXformSrcColorFormat, std::move(stream))
610 , fBitsPerPixel(bitsPerPixel)
611 , fRowOrder(rowOrder)
612 , fSrcRowBytes(SkAlign4(compute_row_bytes(this->dimensions().width(), fBitsPerPixel)))
613 , fXformBuffer(nullptr)
614{}
615
616bool SkBmpCodec::onRewind() {
617 return SkBmpCodec::ReadHeader(this->stream(), this->inIco(), nullptr) == kSuccess;
618}
619
620int32_t SkBmpCodec::getDstRow(int32_t y, int32_t height) const {
621 if (SkCodec::kTopDown_SkScanlineOrder == fRowOrder) {
622 return y;
623 }
624 SkASSERT(SkCodec::kBottomUp_SkScanlineOrder == fRowOrder);
625 return height - y - 1;
626}
627
628SkCodec::Result SkBmpCodec::prepareToDecode(const SkImageInfo& dstInfo,
629 const SkCodec::Options& options) {
630 return this->onPrepareToDecode(dstInfo, options);
631}
632
633SkCodec::Result SkBmpCodec::onStartScanlineDecode(const SkImageInfo& dstInfo,
634 const SkCodec::Options& options) {
635 return prepareToDecode(dstInfo, options);
636}
637
638int SkBmpCodec::onGetScanlines(void* dst, int count, size_t rowBytes) {
639 // Create a new image info representing the portion of the image to decode
640 SkImageInfo rowInfo = this->dstInfo().makeWH(this->dstInfo().width(), count);
641
642 // Decode the requested rows
643 return this->decodeRows(rowInfo, dst, rowBytes, this->options());
644}
645
646bool SkBmpCodec::skipRows(int count) {
647 const size_t bytesToSkip = count * fSrcRowBytes;
648 return this->stream()->skip(bytesToSkip) == bytesToSkip;
649}
650
651bool SkBmpCodec::onSkipScanlines(int count) {
652 return this->skipRows(count);
653}
654