/* ***** BEGIN LICENSE BLOCK *****
 * Source last modified: $Id: pxpngdec.h,v 1.1.26.1 2004/07/09 01:52:09 hubbe Exp $
 * 
 * Portions Copyright (c) 1995-2004 RealNetworks, Inc. All Rights Reserved.
 * 
 * The contents of this file, and the files included with this file,
 * are subject to the current version of the RealNetworks Public
 * Source License (the "RPSL") available at
 * http://www.helixcommunity.org/content/rpsl unless you have licensed
 * the file under the current version of the RealNetworks Community
 * Source License (the "RCSL") available at
 * http://www.helixcommunity.org/content/rcsl, in which case the RCSL
 * will apply. You may also obtain the license terms directly from
 * RealNetworks.  You may not use this file except in compliance with
 * the RPSL or, if you have a valid RCSL with RealNetworks applicable
 * to this file, the RCSL.  Please see the applicable RPSL or RCSL for
 * the rights, obligations and limitations governing use of the
 * contents of the file.
 * 
 * Alternatively, the contents of this file may be used under the
 * terms of the GNU General Public License Version 2 or later (the
 * "GPL") in which case the provisions of the GPL are applicable
 * instead of those above. If you wish to allow use of your version of
 * this file only under the terms of the GPL, and not to allow others
 * to use your version of this file under the terms of either the RPSL
 * or RCSL, indicate your decision by deleting the provisions above
 * and replace them with the notice and other provisions required by
 * the GPL. If you do not delete the provisions above, a recipient may
 * use your version of this file under the terms of any one of the
 * RPSL, the RCSL or the GPL.
 * 
 * This file is part of the Helix DNA Technology. RealNetworks is the
 * developer of the Original Code and owns the copyrights in the
 * portions it created.
 * 
 * This file, and the files included with this file, is distributed
 * and made available on an 'AS IS' basis, WITHOUT WARRANTY OF ANY
 * KIND, EITHER EXPRESS OR IMPLIED, AND REALNETWORKS HEREBY DISCLAIMS
 * ALL SUCH WARRANTIES, INCLUDING WITHOUT LIMITATION, ANY WARRANTIES
 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, QUIET
 * ENJOYMENT OR NON-INFRINGEMENT.
 * 
 * Technology Compatibility Kit Test Suite(s) Location:
 *    http://www.helixcommunity.org/content/tck
 * 
 * Contributor(s):
 * 
 * ***** END LICENSE BLOCK ***** */

#ifndef PXPNGDEC_H
#define PXPNGDEC_H

class PXPNGDecode : public CHXBaseCountingObject,
                    public IUnknown
{
public:
    PXPNGDecode();
    virtual ~PXPNGDecode();

    // IUnknown methods
    STDMETHOD(QueryInterface)  (THIS_ REFIID riid, void** ppvObj);
    STDMETHOD_(UINT32,AddRef)  (THIS);
    STDMETHOD_(UINT32,Release) (THIS);

    // PXPNGDecode methods
    static BOOL ValidInputData(IHXBuffer* pBuffer);
    HX_RESULT   Init(IUnknown*   pContext,
                     IHXBuffer* pBuffer,
                     BOOL        bDupFirstBuffer);
    HX_RESULT   SetDecompressParam(IHXBuffer* pOutputBuffer,
                                   UINT32      ulOutputWidth,
                                   UINT32      ulOutputHeight,
                                   UINT32      ulRowStride,
                                   UINT32      ulBitsPerPixel,
                                   UINT32      ulColorFormat,
                                   BOOL        bRowsInverted,
                                   BOOL        bTransparentIsZero = FALSE);
    HX_RESULT   Decompress(IHXBuffer* pBuffer);
    HX_RESULT   GetErrorString(REF(IHXBuffer*) rpErrStr);
    BOOL        IsFinished() const;
    UINT32      GetWidth()  const;
    UINT32      GetHeight() const;
    BYTE        GetBitDepth() const;
    BYTE        GetColorType() const;
    BYTE        GetFilterType() const;
    BYTE        GetCompressionType() const;
    BYTE        GetInterlaceType() const;
    BOOL        UsesAlphaChannel() const;
    UINT32      GetLastSeqNum() const;
    void        SetLastSeqNum(UINT32 ulSeqNum);
    BOOL        GetValid() const;
    void        SetValid(BOOL bValid);
    static BOOL IsChunkPresent(IHXBuffer* pBuffer, UINT32 ulChunkType,
                               REF(UINT32) rulOffset, REF(UINT32) ulNumBytes,
                               REF(BOOL) rbComplete);
    static BOOL IsCompleteChunkPresent(IHXBuffer* pBuffer, UINT32 ulChunkType);
    static BOOL GetIHDRInfo(IHXBuffer* pBuffer, REF(UINT32) rulWidth, REF(UINT32) rulHeight);
protected:
    enum
    {
        kAppStateConstructed,
        kAppStateInit,
        kAppStateSetParam,
        kAppStateDecompress,
        kDataStateConstructed,
        kDataStateInfoCallback,
        kDataStateRowCallback,
        kDataStateEndCallback,
        kMinIDATBytes = 8,
        kSig0         = 0x89504E47,
        kSig1         = 0x0D0A1A0A,
        kIHDR         = 0x49484452,
        kIEND         = 0x49454e44,
        kIDAT         = 0x49444154
    };

    struct PXUserError
    {
        IUnknown*   m_pContext;
        IHXBuffer* m_pErrorStr;
    };

    struct PXUserIOSingle
    {
        IHXBuffer* m_pBuffer;
        UINT32      m_ulOffset;
    };

    struct PXUserIOProgressive
    {
        UINT32 m_ulAppState;
        UINT32 m_ulDataState;
        UINT32 m_ulNumRows;
        BYTE** m_ppImageRow;
    };

    INT32        m_lRefCount;
    png_structp  m_pPNGStruct;
    png_infop    m_pPNGInfo;
    png_infop    m_pPNGEndInfo;
    IHXBuffer*  m_pOutputBuffer;
    BYTE**       m_ppImageRow;
    BOOL         m_bSingleBufferIO;
    BOOL         m_bDupFirstBuffer;
    BOOL         m_bFirstDecompress;
    BOOL         m_bDeferFirstBuffer;
    IHXBuffer*  m_pFirstBuffer;
    UINT32       m_ulFirstBufferOffset;
    BOOL         m_bFinished;
    // Decode-state members
    UINT32       m_ulLastSeqNum;
    BOOL         m_bValid;

    void          Reset();
    void          Deallocate();
    void          DeallocateErrorHandling(png_structp png_ptr);
    void          DeallocateIOHandling(png_structp png_ptr);
    HX_RESULT     SetupRowPointers(UINT32 ulHeight, IHXBuffer* pBuffer,
                                   UINT32 ulRowStride, BOOL bRowsInverted);
    static void   SetReadTransforms(png_structp png_ptr, png_infop info);
    static void   SingleBufferRead(png_structp png_ptr, png_bytep data, png_size_t length);
    static void   HandleError(png_structp png_ptr, png_const_charp message);
    static void   HandleWarning(png_structp png_ptr, png_const_charp message);
    static void   CopyErrorString(png_structp png_ptr, png_const_charp message);
    static void   InfoCallback(png_structp png_ptr, png_infop info);
    static void   RowCallback(png_structp png_ptr, png_bytep new_row,
                              png_uint_32 row_num, int pass);
    static void   EndCallback(png_structp png_ptr, png_infop info);
    static void   SetProgressiveAppState(png_structp png_ptr, UINT32 ulState);
    static void   SetProgressiveDataState(png_structp png_ptr, UINT32 ulState);
    static BOOL   IsDataStateEqual(png_structp png_ptr, UINT32 ulState);
};

inline BOOL PXPNGDecode::IsFinished() const
{
    return m_bFinished;
}

inline UINT32 PXPNGDecode::GetWidth() const
{
    UINT32 ulRet = 0;
    if (m_pPNGStruct && m_pPNGInfo)
    {
        ulRet = (UINT32) png_get_image_width(m_pPNGStruct, m_pPNGInfo);
    }
    return ulRet;
}

inline UINT32 PXPNGDecode::GetHeight() const
{
    UINT32 ulRet = 0;
    if (m_pPNGStruct && m_pPNGInfo)
    {
        ulRet = (UINT32) png_get_image_height(m_pPNGStruct, m_pPNGInfo);
    }
    return ulRet;
}

inline BYTE PXPNGDecode::GetBitDepth() const
{
    BYTE ucRet = 0;
    if (m_pPNGStruct && m_pPNGInfo)
    {
        ucRet = png_get_bit_depth(m_pPNGStruct, m_pPNGInfo);
    }
    return ucRet;
}

inline BYTE PXPNGDecode::GetColorType() const
{
    BYTE ucRet = 0;
    if (m_pPNGStruct && m_pPNGInfo)
    {
        ucRet = png_get_color_type(m_pPNGStruct, m_pPNGInfo);
    }
    return ucRet;
}

inline BYTE PXPNGDecode::GetFilterType() const
{
    BYTE ucRet = 0;
    if (m_pPNGStruct && m_pPNGInfo)
    {
        ucRet = png_get_filter_type(m_pPNGStruct, m_pPNGInfo);
    }
    return ucRet;
}

inline BYTE PXPNGDecode::GetCompressionType() const
{
    BYTE ucRet = 0;
    if (m_pPNGStruct && m_pPNGInfo)
    {
        ucRet = png_get_compression_type(m_pPNGStruct, m_pPNGInfo);
    }
    return ucRet;
}

inline BYTE PXPNGDecode::GetInterlaceType() const
{
    BYTE ucRet = 0;
    if (m_pPNGStruct && m_pPNGInfo)
    {
        ucRet = png_get_interlace_type(m_pPNGStruct, m_pPNGInfo);
    }
    return ucRet;
}

inline BOOL PXPNGDecode::UsesAlphaChannel() const
{
    BOOL bRet = FALSE;
    if (m_pPNGStruct && m_pPNGInfo)
    {
        UINT32 ulColorType = (UINT32) png_get_color_type(m_pPNGStruct, m_pPNGInfo);
        if (ulColorType == PNG_COLOR_TYPE_GRAY_ALPHA ||
            ulColorType == PNG_COLOR_TYPE_RGB_ALPHA)
        {
            // This image has an encoded alpha channel, so
            // it definitely has alpha channel data.
            bRet = TRUE;
        }
        else
        {
            // This image does not have an encoded alpha channel,
            // but it COULD have a tRNS (transparency) chunk, which
            // would result in an alpha channel when we expand
            // the chunk.
            if (png_get_valid(m_pPNGStruct, m_pPNGInfo, PNG_INFO_tRNS))
            {
                bRet = TRUE;
            }
        }
    }
    return bRet;
}

inline UINT32 PXPNGDecode::GetLastSeqNum() const
{
    return m_ulLastSeqNum;
}

inline void PXPNGDecode::SetLastSeqNum(UINT32 ulSeqNum)
{
    m_ulLastSeqNum = ulSeqNum;
}

inline BOOL PXPNGDecode::GetValid() const
{
    return m_bValid;
}

inline void PXPNGDecode::SetValid(BOOL bValid)
{
    m_bValid = bValid;
}

#endif
