aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/codec/SkPngCodec.h
blob: 1fc451757eef4dcafb7bf5586d69a5800b3d5cac (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
/*
 * Copyright 2015 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "SkCodec.h"
#include "SkColorSpaceXform.h"
#include "SkColorTable.h"
#include "SkPngChunkReader.h"
#include "SkEncodedFormat.h"
#include "SkImageInfo.h"
#include "SkRefCnt.h"
#include "SkSwizzler.h"

// FIXME (scroggo): GOOGLE3 is currently using an outdated version of libpng,
// so we need to work around the lack of the method png_process_data_pause.
// This code will be unnecessary once we update GOOGLE3. It would make more
// sense to condition this on the version of libpng being used, but we do not
// know that here because png.h is only included by the cpp file.
#define SK_GOOGLE3_PNG_HACK

class SkStream;

class SkPngCodec : public SkCodec {
public:
    static bool IsPng(const char*, size_t);

    // Assume IsPng was called and returned true.
    static SkCodec* NewFromStream(SkStream*, SkPngChunkReader* = NULL);

    virtual ~SkPngCodec();

protected:
    // We hold the png_ptr and info_ptr as voidp to avoid having to include png.h
    // or forward declare their types here.  voidp auto-casts to the real pointer types.
    struct voidp {
        voidp(void* ptr) : fPtr(ptr) {}

        template <typename T>
        operator T*() const { return (T*)fPtr; }

        explicit operator bool() const { return fPtr != nullptr; }

        void* fPtr;
    };

    SkPngCodec(const SkEncodedInfo&, const SkImageInfo&, SkStream*, SkPngChunkReader*,
            void* png_ptr, void* info_ptr, int bitDepth);

    Result onGetPixels(const SkImageInfo&, void*, size_t, const Options&, SkPMColor*, int*, int*)
            override;
    SkEncodedFormat onGetEncodedFormat() const override { return kPNG_SkEncodedFormat; }
    bool onRewind() override;
    uint64_t onGetFillValue(const SkImageInfo&) const override;

    SkSampler* getSampler(bool createIfNecessary) override;
    void applyXformRow(void* dst, const void* src);

    voidp png_ptr() { return fPng_ptr; }
    voidp info_ptr() { return fInfo_ptr; }

    SkSwizzler* swizzler() { return fSwizzler; }

    // Initialize variables used by applyXformRow.
    void initializeXformParams();

    /**
     *  Pass available input to libpng to process it.
     *
     *  libpng will call any relevant callbacks installed. This will continue decoding
     *  until it reaches the end of the file, or until a callback tells libpng to stop.
     */
    void processData();

#ifdef SK_GOOGLE3_PNG_HACK
    // In libpng 1.2.56, png_process_data_pause does not exist, so when we wanted to
    // read the header, we may have read too far. In that case, we need to delete the
    // png_ptr and info_ptr and recreate them. This method does that (and attaches the
    // chunk reader.
    bool rereadHeaderIfNecessary();

    // This method sets up the new png_ptr/info_ptr (created in rereadHeaderIfNecessary)
    // the way we set up the old one the first time in AutoCleanPng.decodeBounds's callback.
    void rereadInfoCallback();
#endif

    Result onStartIncrementalDecode(const SkImageInfo& dstInfo, void* pixels, size_t rowBytes,
            const SkCodec::Options&,
            SkPMColor* ctable, int* ctableCount) override;
    Result onIncrementalDecode(int*) override;

    SkAutoTUnref<SkPngChunkReader> fPngChunkReader;
    voidp                          fPng_ptr;
    voidp                          fInfo_ptr;

    // These are stored here so they can be used both by normal decoding and scanline decoding.
    SkAutoTUnref<SkColorTable>         fColorTable;    // May be unpremul.
    SkAutoTDelete<SkSwizzler>          fSwizzler;
    std::unique_ptr<SkColorSpaceXform> fColorXform;
    SkAutoTMalloc<uint8_t>             fStorage;
    uint32_t*                          fColorXformSrcRow;
    const int                          fBitDepth;

private:

    enum XformMode {
        // Requires only a swizzle pass.
        kSwizzleOnly_XformMode,

        // Requires only a color xform pass.
        kColorOnly_XformMode,

        // Requires a swizzle and a color xform.
        kSwizzleColor_XformMode,
    };

    bool createColorTable(const SkImageInfo& dstInfo, int* ctableCount);
    // Helper to set up swizzler, color xforms, and color table. Also calls png_read_update_info.
    bool initializeXforms(const SkImageInfo& dstInfo, const Options&, SkPMColor* colorPtr,
                          int* colorCount);
    void initializeSwizzler(const SkImageInfo& dstInfo, const Options&);
    void allocateStorage(const SkImageInfo& dstInfo);
    void destroyReadStruct();

    virtual Result decodeAllRows(void* dst, size_t rowBytes, int* rowsDecoded) = 0;
    virtual void setRange(int firstRow, int lastRow, void* dst, size_t rowBytes) = 0;
    virtual Result decode(int* rowsDecoded) = 0;

    XformMode                      fXformMode;
    SkColorSpaceXform::ColorFormat fXformColorFormat;
    SkAlphaType                    fXformAlphaType;
    int                            fXformWidth;

#ifdef SK_GOOGLE3_PNG_HACK
    bool        fNeedsToRereadHeader;
#endif

    typedef SkCodec INHERITED;
};