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/private/SkColorData.h"
9#include "src/codec/SkBmpMaskCodec.h"
10#include "src/codec/SkCodecPriv.h"
11
12/*
13 * Creates an instance of the decoder
14 */
15SkBmpMaskCodec::SkBmpMaskCodec(SkEncodedInfo&& info,
16                               std::unique_ptr<SkStream> stream,
17                               uint16_t bitsPerPixel, SkMasks* masks,
18                               SkCodec::SkScanlineOrder rowOrder)
19    : INHERITED(std::move(info), std::move(stream), bitsPerPixel, rowOrder)
20    , fMasks(masks)
21    , fMaskSwizzler(nullptr)
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                                            int* rowsDecoded) {
31    if (opts.fSubset) {
32        // Subsets are not supported.
33        return kUnimplemented;
34    }
35    if (dstInfo.dimensions() != this->dimensions()) {
36        SkCodecPrintf("Error: scaling not supported.\n");
37        return kInvalidScale;
38    }
39
40    Result result = this->prepareToDecode(dstInfo, opts);
41    if (kSuccess != result) {
42        return result;
43    }
44
45    int rows = this->decodeRows(dstInfo, dst, dstRowBytes, opts);
46    if (rows != dstInfo.height()) {
47        *rowsDecoded = rows;
48        return kIncompleteInput;
49    }
50    return kSuccess;
51}
52
53SkCodec::Result SkBmpMaskCodec::onPrepareToDecode(const SkImageInfo& dstInfo,
54        const SkCodec::Options& options) {
55    if (this->colorXform()) {
56        this->resetXformBuffer(dstInfo.width());
57    }
58
59    SkImageInfo swizzlerInfo = dstInfo;
60    if (this->colorXform()) {
61        swizzlerInfo = swizzlerInfo.makeColorType(kXformSrcColorType);
62        if (kPremul_SkAlphaType == dstInfo.alphaType()) {
63            swizzlerInfo = swizzlerInfo.makeAlphaType(kUnpremul_SkAlphaType);
64        }
65    }
66
67    bool srcIsOpaque = this->getEncodedInfo().opaque();
68    fMaskSwizzler.reset(SkMaskSwizzler::CreateMaskSwizzler(swizzlerInfo, srcIsOpaque,
69            fMasks.get(), this->bitsPerPixel(), options));
70    SkASSERT(fMaskSwizzler);
71
72    return SkCodec::kSuccess;
73}
74
75/*
76 * Performs the decoding
77 */
78int SkBmpMaskCodec::decodeRows(const SkImageInfo& dstInfo,
79                                           void* dst, size_t dstRowBytes,
80                                           const Options& opts) {
81    // Iterate over rows of the image
82    uint8_t* srcRow = this->srcBuffer();
83    const int height = dstInfo.height();
84    for (int y = 0; y < height; y++) {
85        // Read a row of the input
86        if (this->stream()->read(srcRow, this->srcRowBytes()) != this->srcRowBytes()) {
87            SkCodecPrintf("Warning: incomplete input stream.\n");
88            return y;
89        }
90
91        // Decode the row in destination format
92        uint32_t row = this->getDstRow(y, height);
93        void* dstRow = SkTAddOffset<void>(dst, row * dstRowBytes);
94
95        if (this->colorXform()) {
96            fMaskSwizzler->swizzle(this->xformBuffer(), srcRow);
97            this->applyColorXform(dstRow, this->xformBuffer(), fMaskSwizzler->swizzleWidth());
98        } else {
99            fMaskSwizzler->swizzle(dstRow, srcRow);
100        }
101    }
102
103    // Finished decoding the entire image
104    return height;
105}
106