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 "SkCodec.h"
9 #include "SkColorSpaceXform.h"
10 #include "SkColorTable.h"
11 #include "SkPngChunkReader.h"
12 #include "SkEncodedFormat.h"
13 #include "SkImageInfo.h"
14 #include "SkRefCnt.h"
15 #include "SkSwizzler.h"
16 
17 // FIXME (scroggo): GOOGLE3 is currently using an outdated version of libpng,
18 // so we need to work around the lack of the method png_process_data_pause.
19 // This code will be unnecessary once we update GOOGLE3. It would make more
20 // sense to condition this on the version of libpng being used, but we do not
21 // know that here because png.h is only included by the cpp file.
22 #define SK_GOOGLE3_PNG_HACK
23 
24 class SkStream;
25 
26 class SkPngCodec : public SkCodec {
27 public:
28     static bool IsPng(const char*, size_t);
29 
30     // Assume IsPng was called and returned true.
31     static SkCodec* NewFromStream(SkStream*, SkPngChunkReader* = NULL);
32 
33     virtual ~SkPngCodec();
34 
35 protected:
36     // We hold the png_ptr and info_ptr as voidp to avoid having to include png.h
37     // or forward declare their types here.  voidp auto-casts to the real pointer types.
38     struct voidp {
voidpvoidp39         voidp(void* ptr) : fPtr(ptr) {}
40 
41         template <typename T>
42         operator T*() const { return (T*)fPtr; }
43 
44         explicit operator bool() const { return fPtr != nullptr; }
45 
46         void* fPtr;
47     };
48 
49     SkPngCodec(const SkEncodedInfo&, const SkImageInfo&, SkStream*, SkPngChunkReader*,
50             void* png_ptr, void* info_ptr, int bitDepth);
51 
52     Result onGetPixels(const SkImageInfo&, void*, size_t, const Options&, SkPMColor*, int*, int*)
53             override;
onGetEncodedFormat()54     SkEncodedFormat onGetEncodedFormat() const override { return kPNG_SkEncodedFormat; }
55     bool onRewind() override;
56     uint64_t onGetFillValue(const SkImageInfo&) const override;
57 
58     SkSampler* getSampler(bool createIfNecessary) override;
59     void applyXformRow(void* dst, const void* src);
60 
png_ptr()61     voidp png_ptr() { return fPng_ptr; }
info_ptr()62     voidp info_ptr() { return fInfo_ptr; }
63 
swizzler()64     SkSwizzler* swizzler() { return fSwizzler; }
65 
66     // Initialize variables used by applyXformRow.
67     void initializeXformParams();
68 
69     /**
70      *  Pass available input to libpng to process it.
71      *
72      *  libpng will call any relevant callbacks installed. This will continue decoding
73      *  until it reaches the end of the file, or until a callback tells libpng to stop.
74      */
75     void processData();
76 
77 #ifdef SK_GOOGLE3_PNG_HACK
78     // In libpng 1.2.56, png_process_data_pause does not exist, so when we wanted to
79     // read the header, we may have read too far. In that case, we need to delete the
80     // png_ptr and info_ptr and recreate them. This method does that (and attaches the
81     // chunk reader.
82     bool rereadHeaderIfNecessary();
83 
84     // This method sets up the new png_ptr/info_ptr (created in rereadHeaderIfNecessary)
85     // the way we set up the old one the first time in AutoCleanPng.decodeBounds's callback.
86     void rereadInfoCallback();
87 #endif
88 
89     Result onStartIncrementalDecode(const SkImageInfo& dstInfo, void* pixels, size_t rowBytes,
90             const SkCodec::Options&,
91             SkPMColor* ctable, int* ctableCount) override;
92     Result onIncrementalDecode(int*) override;
93 
94     SkAutoTUnref<SkPngChunkReader> fPngChunkReader;
95     voidp                          fPng_ptr;
96     voidp                          fInfo_ptr;
97 
98     // These are stored here so they can be used both by normal decoding and scanline decoding.
99     SkAutoTUnref<SkColorTable>         fColorTable;    // May be unpremul.
100     SkAutoTDelete<SkSwizzler>          fSwizzler;
101     std::unique_ptr<SkColorSpaceXform> fColorXform;
102     SkAutoTMalloc<uint8_t>             fStorage;
103     uint32_t*                          fColorXformSrcRow;
104     const int                          fBitDepth;
105 
106 private:
107 
108     enum XformMode {
109         // Requires only a swizzle pass.
110         kSwizzleOnly_XformMode,
111 
112         // Requires only a color xform pass.
113         kColorOnly_XformMode,
114 
115         // Requires a swizzle and a color xform.
116         kSwizzleColor_XformMode,
117     };
118 
119     bool createColorTable(const SkImageInfo& dstInfo, int* ctableCount);
120     // Helper to set up swizzler, color xforms, and color table. Also calls png_read_update_info.
121     bool initializeXforms(const SkImageInfo& dstInfo, const Options&, SkPMColor* colorPtr,
122                           int* colorCount);
123     void initializeSwizzler(const SkImageInfo& dstInfo, const Options&);
124     void allocateStorage(const SkImageInfo& dstInfo);
125     void destroyReadStruct();
126 
127     virtual Result decodeAllRows(void* dst, size_t rowBytes, int* rowsDecoded) = 0;
128     virtual void setRange(int firstRow, int lastRow, void* dst, size_t rowBytes) = 0;
129     virtual Result decode(int* rowsDecoded) = 0;
130 
131     XformMode                      fXformMode;
132     SkColorSpaceXform::ColorFormat fXformColorFormat;
133     SkAlphaType                    fXformAlphaType;
134     int                            fXformWidth;
135 
136 #ifdef SK_GOOGLE3_PNG_HACK
137     bool        fNeedsToRereadHeader;
138 #endif
139 
140     typedef SkCodec INHERITED;
141 };
142