gecko-dev/image/decoders/nsPNGDecoder.h
Andrew Osmond da72652618 Bug 1620600 - Add flags to allow image decoders to produce sRGB output. r=tnikkel
Currently we can only use the gfx.color_management.force_srgb pref to
force all images to sRGB, or just accept device space. It would be nice
to be able to test device space in our tests, as well as sRGB. This
patch adds a surface flag which allows us to selectively output sRGB.

This will also be useful for clipboard and re-encoding purposes, since
they want a neutral output. In an ideal world we would just output the
color profile and the pixel data in the original color space, but for
now this is a relatively simple approach that works on all platforms and
interops well with all applications.

Differential Revision: https://phabricator.services.mozilla.com/D65734

--HG--
extra : moz-landing-system : lando
2020-04-10 16:26:33 +00:00

149 lines
4.6 KiB
C++

/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_image_decoders_nsPNGDecoder_h
#define mozilla_image_decoders_nsPNGDecoder_h
#include "Decoder.h"
#include "png.h"
#include "StreamingLexer.h"
#include "SurfacePipe.h"
#include "mozilla/gfx/Swizzle.h"
namespace mozilla {
namespace image {
class RasterImage;
class nsPNGDecoder : public Decoder {
public:
virtual ~nsPNGDecoder();
/// @return true if this PNG is a valid ICO resource.
bool IsValidICOResource() const override;
DecoderType GetType() const override { return DecoderType::PNG; }
protected:
nsresult InitInternal() override;
nsresult FinishInternal() override;
LexerResult DoDecode(SourceBufferIterator& aIterator,
IResumable* aOnResume) override;
Maybe<Telemetry::HistogramID> SpeedHistogram() const override;
private:
friend class DecoderFactory;
// Decoders should only be instantiated via DecoderFactory.
explicit nsPNGDecoder(RasterImage* aImage);
/// The information necessary to create a frame.
struct FrameInfo {
gfx::IntRect mFrameRect;
bool mIsInterlaced;
};
nsresult CreateFrame(const FrameInfo& aFrameInfo);
void EndImageFrame();
uint32_t ReadColorProfile(png_structp png_ptr, png_infop info_ptr,
int color_type, bool* sRGBTag);
bool HasAlphaChannel() const { return mChannels == 2 || mChannels == 4; }
enum class TransparencyType { eNone, eAlpha, eFrameRect };
TransparencyType GetTransparencyType(const gfx::IntRect& aFrameRect);
void PostHasTransparencyIfNeeded(TransparencyType aTransparencyType);
void PostInvalidationIfNeeded();
void WriteRow(uint8_t* aRow);
// Convenience methods to make interacting with StreamingLexer from inside
// a libpng callback easier.
void DoTerminate(png_structp aPNGStruct, TerminalState aState);
void DoYield(png_structp aPNGStruct);
enum class State { PNG_DATA, FINISHED_PNG_DATA };
LexerTransition<State> ReadPNGData(const char* aData, size_t aLength);
LexerTransition<State> FinishedPNGData();
StreamingLexer<State> mLexer;
// The next lexer state transition. We need to store it here because we can't
// directly return arbitrary values from libpng callbacks.
LexerTransition<State> mNextTransition;
// We yield to the caller every time we finish decoding a frame. When this
// happens, we need to allocate the next frame after returning from the yield.
// |mNextFrameInfo| is used to store the information needed to allocate the
// next frame.
Maybe<FrameInfo> mNextFrameInfo;
// The length of the last chunk of data passed to ReadPNGData(). We use this
// to arrange to arrive back at the correct spot in the data after yielding.
size_t mLastChunkLength;
public:
png_structp mPNG;
png_infop mInfo;
nsIntRect mFrameRect;
uint8_t* mCMSLine;
uint8_t* interlacebuf;
gfx::SurfaceFormat mFormat;
uint8_t mChannels;
uint8_t mPass;
bool mFrameIsHidden;
bool mDisablePremultipliedAlpha;
bool mGotInfoCallback;
bool mUsePipeTransform;
struct AnimFrameInfo {
AnimFrameInfo();
#ifdef PNG_APNG_SUPPORTED
AnimFrameInfo(png_structp aPNG, png_infop aInfo);
#endif
DisposalMethod mDispose;
BlendMethod mBlend;
int32_t mTimeout;
};
AnimFrameInfo mAnimInfo;
SurfacePipe mPipe; /// The SurfacePipe used to write to the output surface.
// The number of frames we've finished.
uint32_t mNumFrames;
// libpng callbacks
// We put these in the class so that they can access protected members.
static void PNGAPI info_callback(png_structp png_ptr, png_infop info_ptr);
static void PNGAPI row_callback(png_structp png_ptr, png_bytep new_row,
png_uint_32 row_num, int pass);
#ifdef PNG_APNG_SUPPORTED
static void PNGAPI frame_info_callback(png_structp png_ptr,
png_uint_32 frame_num);
#endif
static void PNGAPI end_callback(png_structp png_ptr, png_infop info_ptr);
static void PNGAPI error_callback(png_structp png_ptr,
png_const_charp error_msg);
static void PNGAPI warning_callback(png_structp png_ptr,
png_const_charp warning_msg);
// This is defined in the PNG spec as an invariant. We use it to
// do manual validation without libpng.
static const uint8_t pngSignatureBytes[];
};
} // namespace image
} // namespace mozilla
#endif // mozilla_image_decoders_nsPNGDecoder_h