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 */
15SkBmpMaskCodec::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 */
27SkCodec::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
60SkCodec::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 */
73int 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