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 "SkBmpMaskCodec.h"
9 #include "SkCodecPriv.h"
10 #include "SkColorPriv.h"
11 
12 /*
13  * Creates an instance of the decoder
14  */
SkBmpMaskCodec(const SkImageInfo & info,SkStream * stream,uint16_t bitsPerPixel,SkMasks * masks,SkCodec::SkScanlineOrder rowOrder)15 SkBmpMaskCodec::SkBmpMaskCodec(const SkImageInfo& info, SkStream* stream,
16                                uint16_t bitsPerPixel, SkMasks* masks,
17                                SkCodec::SkScanlineOrder rowOrder)
18     : INHERITED(info, stream, bitsPerPixel, rowOrder)
19     , fMasks(masks)
20     , fMaskSwizzler(nullptr)
21     , fSrcBuffer(new uint8_t [this->srcRowBytes()])
22 {}
23 
24 /*
25  * Initiates the bitmap decode
26  */
onGetPixels(const SkImageInfo & dstInfo,void * dst,size_t dstRowBytes,const Options & opts,SkPMColor * inputColorPtr,int * inputColorCount,int * rowsDecoded)27 SkCodec::Result SkBmpMaskCodec::onGetPixels(const SkImageInfo& dstInfo,
28                                             void* dst, size_t dstRowBytes,
29                                             const Options& opts,
30                                             SkPMColor* inputColorPtr,
31                                             int* inputColorCount,
32                                             int* rowsDecoded) {
33     if (opts.fSubset) {
34         // Subsets are not supported.
35         return kUnimplemented;
36     }
37     if (dstInfo.dimensions() != this->getInfo().dimensions()) {
38         SkCodecPrintf("Error: scaling not supported.\n");
39         return kInvalidScale;
40     }
41 
42     if (!conversion_possible(dstInfo, this->getInfo())) {
43         SkCodecPrintf("Error: cannot convert input type to output type.\n");
44         return kInvalidConversion;
45     }
46 
47     Result result = this->prepareToDecode(dstInfo, opts, inputColorPtr, inputColorCount);
48     if (kSuccess != result) {
49         return result;
50     }
51 
52     int rows = this->decodeRows(dstInfo, dst, dstRowBytes, opts);
53     if (rows != dstInfo.height()) {
54         *rowsDecoded = rows;
55         return kIncompleteInput;
56     }
57     return kSuccess;
58 }
59 
prepareToDecode(const SkImageInfo & dstInfo,const SkCodec::Options & options,SkPMColor inputColorPtr[],int * inputColorCount)60 SkCodec::Result SkBmpMaskCodec::prepareToDecode(const SkImageInfo& dstInfo,
61         const SkCodec::Options& options, SkPMColor inputColorPtr[], int* inputColorCount) {
62     // Initialize the mask swizzler
63     fMaskSwizzler.reset(SkMaskSwizzler::CreateMaskSwizzler(dstInfo, this->getInfo(), fMasks,
64             this->bitsPerPixel(), options));
65     SkASSERT(fMaskSwizzler);
66 
67     return SkCodec::kSuccess;
68 }
69 
70 /*
71  * Performs the decoding
72  */
decodeRows(const SkImageInfo & dstInfo,void * dst,size_t dstRowBytes,const Options & opts)73 int SkBmpMaskCodec::decodeRows(const SkImageInfo& dstInfo,
74                                            void* dst, size_t dstRowBytes,
75                                            const Options& opts) {
76     // Iterate over rows of the image
77     uint8_t* srcRow = fSrcBuffer.get();
78     const int height = dstInfo.height();
79     for (int y = 0; y < height; y++) {
80         // Read a row of the input
81         if (this->stream()->read(srcRow, this->srcRowBytes()) != this->srcRowBytes()) {
82             SkCodecPrintf("Warning: incomplete input stream.\n");
83             return y;
84         }
85 
86         // Decode the row in destination format
87         uint32_t row = this->getDstRow(y, height);
88         void* dstRow = SkTAddOffset<void>(dst, row * dstRowBytes);
89         fMaskSwizzler->swizzle(dstRow, srcRow);
90     }
91 
92     // Finished decoding the entire image
93     return height;
94 }
95