1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2  *
3  * This Source Code Form is subject to the terms of the Mozilla Public
4  * License, v. 2.0. If a copy of the MPL was not distributed with this
5  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 
7 #ifndef mozilla_image_decoders_nsPNGDecoder_h
8 #define mozilla_image_decoders_nsPNGDecoder_h
9 
10 #include "Decoder.h"
11 #include "png.h"
12 #include "qcms.h"
13 #include "StreamingLexer.h"
14 #include "SurfacePipe.h"
15 
16 namespace mozilla {
17 namespace image {
18 class RasterImage;
19 
20 class nsPNGDecoder : public Decoder {
21  public:
22   virtual ~nsPNGDecoder();
23 
24   /// @return true if this PNG is a valid ICO resource.
25   bool IsValidICOResource() const override;
26 
GetType()27   DecoderType GetType() const override { return DecoderType::PNG; }
28 
29  protected:
30   nsresult InitInternal() override;
31   nsresult FinishInternal() override;
32   LexerResult DoDecode(SourceBufferIterator& aIterator,
33                        IResumable* aOnResume) override;
34 
35   Maybe<Telemetry::HistogramID> SpeedHistogram() const override;
36 
37  private:
38   friend class DecoderFactory;
39 
40   // Decoders should only be instantiated via DecoderFactory.
41   explicit nsPNGDecoder(RasterImage* aImage);
42 
43   /// The information necessary to create a frame.
44   struct FrameInfo {
45     gfx::IntRect mFrameRect;
46     bool mIsInterlaced;
47   };
48 
49   nsresult CreateFrame(const FrameInfo& aFrameInfo);
50   void EndImageFrame();
51 
HasAlphaChannel()52   bool HasAlphaChannel() const { return mChannels == 2 || mChannels == 4; }
53 
54   enum class TransparencyType { eNone, eAlpha, eFrameRect };
55 
56   TransparencyType GetTransparencyType(const gfx::IntRect& aFrameRect);
57   void PostHasTransparencyIfNeeded(TransparencyType aTransparencyType);
58 
59   void PostInvalidationIfNeeded();
60 
61   void WriteRow(uint8_t* aRow);
62 
63   // Convenience methods to make interacting with StreamingLexer from inside
64   // a libpng callback easier.
65   void DoTerminate(png_structp aPNGStruct, TerminalState aState);
66   void DoYield(png_structp aPNGStruct);
67 
68   enum class State { PNG_DATA, FINISHED_PNG_DATA };
69 
70   LexerTransition<State> ReadPNGData(const char* aData, size_t aLength);
71   LexerTransition<State> FinishedPNGData();
72 
73   StreamingLexer<State> mLexer;
74 
75   // The next lexer state transition. We need to store it here because we can't
76   // directly return arbitrary values from libpng callbacks.
77   LexerTransition<State> mNextTransition;
78 
79   // We yield to the caller every time we finish decoding a frame. When this
80   // happens, we need to allocate the next frame after returning from the yield.
81   // |mNextFrameInfo| is used to store the information needed to allocate the
82   // next frame.
83   Maybe<FrameInfo> mNextFrameInfo;
84 
85   // The length of the last chunk of data passed to ReadPNGData(). We use this
86   // to arrange to arrive back at the correct spot in the data after yielding.
87   size_t mLastChunkLength;
88 
89  public:
90   png_structp mPNG;
91   png_infop mInfo;
92   nsIntRect mFrameRect;
93   uint8_t* mCMSLine;
94   uint8_t* interlacebuf;
95   qcms_profile* mInProfile;
96   qcms_transform* mTransform;
97   gfx::SurfaceFormat mFormat;
98 
99   // whether CMS or premultiplied alpha are forced off
100   uint32_t mCMSMode;
101 
102   uint8_t mChannels;
103   uint8_t mPass;
104   bool mFrameIsHidden;
105   bool mDisablePremultipliedAlpha;
106 
107   struct AnimFrameInfo {
108     AnimFrameInfo();
109 #ifdef PNG_APNG_SUPPORTED
110     AnimFrameInfo(png_structp aPNG, png_infop aInfo);
111 #endif
112 
113     DisposalMethod mDispose;
114     BlendMethod mBlend;
115     int32_t mTimeout;
116   };
117 
118   AnimFrameInfo mAnimInfo;
119 
120   SurfacePipe mPipe;  /// The SurfacePipe used to write to the output surface.
121 
122   // The number of frames we've finished.
123   uint32_t mNumFrames;
124 
125   // libpng callbacks
126   // We put these in the class so that they can access protected members.
127   static void PNGAPI info_callback(png_structp png_ptr, png_infop info_ptr);
128   static void PNGAPI row_callback(png_structp png_ptr, png_bytep new_row,
129                                   png_uint_32 row_num, int pass);
130 #ifdef PNG_APNG_SUPPORTED
131   static void PNGAPI frame_info_callback(png_structp png_ptr,
132                                          png_uint_32 frame_num);
133 #endif
134   static void PNGAPI end_callback(png_structp png_ptr, png_infop info_ptr);
135   static void PNGAPI error_callback(png_structp png_ptr,
136                                     png_const_charp error_msg);
137   static void PNGAPI warning_callback(png_structp png_ptr,
138                                       png_const_charp warning_msg);
139 
140   // This is defined in the PNG spec as an invariant. We use it to
141   // do manual validation without libpng.
142   static const uint8_t pngSignatureBytes[];
143 };
144 
145 }  // namespace image
146 }  // namespace mozilla
147 
148 #endif  // mozilla_image_decoders_nsPNGDecoder_h
149