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