// Copyright 2014 PDFium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
 
// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com

#ifndef _FPDF_RENDER_
#define _FPDF_RENDER_
#ifndef _FPDF_PAGE_
#include "fpdf_page.h"
#endif
#ifndef _FX_GE_H_
#include "../fxge/fx_ge.h"
#endif
class CPDF_RenderContext;
class CPDF_RenderOptions;
class CPDF_ImageCache;
class IPDF_OCContext;
class CPDF_QuickStretcher;
class CFX_PathData;
class CFX_GraphStateData;
class CFX_RenderDevice;
class CPDF_TextObject;
class CPDF_PathObject;
class CPDF_ImageObject;
class CPDF_ShadingObject;
class CPDF_FormObject;
class IPDF_OCContext
{
public:

    virtual ~IPDF_OCContext() {}

    virtual FX_BOOL	CheckOCGVisible(const CPDF_Dictionary* pOCG) = 0;

    FX_BOOL CheckObjectVisible(const CPDF_PageObject* pObj);
};
#define RENDER_COLOR_NORMAL		0
#define RENDER_COLOR_GRAY		1
#define RENDER_COLOR_TWOCOLOR	2
#define RENDER_COLOR_ALPHA		3
#define RENDER_CLEARTYPE			0x00000001
#define RENDER_PRINTGRAPHICTEXT		0x00000002
#define RENDER_FORCE_DOWNSAMPLE		0x00000004
#define RENDER_PRINTPREVIEW			0x00000008
#define RENDER_BGR_STRIPE			0x00000010
#define RENDER_NO_NATIVETEXT		0x00000020
#define RENDER_FORCE_HALFTONE		0x00000040
#define RENDER_RECT_AA				0x00000080
#define RENDER_FILL_FULLCOVER		0x00000100
#define RENDER_PRINTIMAGETEXT       0x00000200
#define RENDER_OVERPRINT            0x00000400
#define RENDER_THINLINE             0x00000800
#define RENDER_NOTEXTSMOOTH			0x10000000
#define RENDER_NOPATHSMOOTH			0x20000000
#define RENDER_NOIMAGESMOOTH		0x40000000
#define RENDER_LIMITEDIMAGECACHE	0x80000000
class CPDF_RenderOptions : public CFX_Object
{
public:

    CPDF_RenderOptions();

    int				m_ColorMode;

    FX_COLORREF		m_BackColor;

    FX_COLORREF		m_ForeColor;

    FX_DWORD		m_Flags;

    int				m_Interpolation;

    FX_DWORD		m_AddFlags;

    IPDF_OCContext*	m_pOCContext;

    FX_DWORD		m_dwLimitCacheSize;

    int				m_HalftoneLimit;

    FX_ARGB			TranslateColor(FX_ARGB argb) const;
};
class CPDF_RenderContext : public CFX_Object
{
public:

    CPDF_RenderContext();

    void			Create(CPDF_Page* pPage, FX_BOOL bFirstLayer = TRUE);

    void			Create(CPDF_Document* pDoc = NULL, CPDF_PageRenderCache* pPageCache = NULL,
                           CPDF_Dictionary* pPageResources = NULL, FX_BOOL bFirstLayer = TRUE);

    ~CPDF_RenderContext();

    void			Clear();

    void			AppendObjectList(CPDF_PageObjects* pObjs, const CFX_AffineMatrix* pObject2Device);

    void			SetBackground(class IPDF_BackgroundDraw* pBackground);

    void			Render(CFX_RenderDevice* pDevice, const CPDF_RenderOptions* pOptions = NULL,
                           const CFX_AffineMatrix* pFinalMatrix = NULL);

    void			DrawObjectList(CFX_RenderDevice* pDevice, CPDF_PageObjects* pObjs,
                                   const CFX_AffineMatrix* pObject2Device, const CPDF_RenderOptions* pOptions);

    void			GetBackground(CFX_DIBitmap* pBuffer, const CPDF_PageObject* pObj,
                                  const CPDF_RenderOptions* pOptions, CFX_AffineMatrix* pFinalMatrix);

    CPDF_PageRenderCache*	GetPageCache() const
    {
        return m_pPageCache;
    }



    CPDF_Document*			m_pDocument;

    CPDF_Dictionary*		m_pPageResources;

    CPDF_PageRenderCache*	m_pPageCache;

protected:

    CFX_ArrayTemplate<struct _PDF_RenderItem>	m_ContentList;

    IPDF_BackgroundDraw*	m_pBackgroundDraw;

    FX_BOOL					m_bFirstLayer;

    void			Render(CFX_RenderDevice* pDevice, const CPDF_PageObject* pStopObj,
                           const CPDF_RenderOptions* pOptions, const CFX_AffineMatrix* pFinalMatrix);
    friend class CPDF_RenderStatus;
    friend class CPDF_ProgressiveRenderer;
};
class IPDF_BackgroundDraw
{
public:

    virtual	void	OnDrawBackground(
        CFX_RenderDevice* pBitmapDevice,
        const CFX_AffineMatrix* pOriginal2Bitmap
    ) = 0;
};
class CPDF_ProgressiveRenderer : public CFX_Object
{
public:

    CPDF_ProgressiveRenderer();

    ~CPDF_ProgressiveRenderer();

    typedef enum {
        Ready,
        ToBeContinued,
        Done,
        Failed
    } RenderStatus;

    RenderStatus		GetStatus()
    {
        return m_Status;
    }



    void				Start(CPDF_RenderContext* pContext, CFX_RenderDevice* pDevice,
                              const CPDF_RenderOptions* pOptions, class IFX_Pause* pPause, FX_BOOL bDropObjects = FALSE);

    void				Continue(class IFX_Pause* pPause);


    int					EstimateProgress();

    void				Clear();
protected:

    RenderStatus		m_Status;

    CPDF_RenderContext*	m_pContext;

    CFX_RenderDevice*	m_pDevice;

    const CPDF_RenderOptions*	m_pOptions;

    FX_BOOL				m_bDropObjects;

    class CPDF_RenderStatus*	m_pRenderer;

    CFX_FloatRect		m_ClipRect;

    FX_DWORD			m_LayerIndex;

    FX_DWORD			m_ObjectIndex;

    FX_POSITION			m_ObjectPos;

    FX_POSITION			m_PrevLastPos;

    void				RenderStep();
};
class CPDF_TextRenderer : public CFX_Object
{
public:

    static void		DrawTextString(CFX_RenderDevice* pDevice, int left, int top,
                                   CPDF_Font* pFont,
                                   int height,
                                   const CFX_ByteString& str,
                                   FX_ARGB argb);

    static void		DrawTextString(CFX_RenderDevice* pDevice, FX_FLOAT origin_x, FX_FLOAT origin_y,
                                   CPDF_Font* pFont,
                                   FX_FLOAT font_size,
                                   const CFX_AffineMatrix* matrix,
                                   const CFX_ByteString& str,
                                   FX_ARGB fill_argb,
                                   FX_ARGB stroke_argb = 0,
                                   const CFX_GraphStateData* pGraphState = NULL,
                                   const CPDF_RenderOptions* pOptions = NULL
                               );

    static FX_BOOL	DrawTextPath(CFX_RenderDevice* pDevice, int nChars, FX_DWORD* pCharCodes, FX_FLOAT* pCharPos,
                                 CPDF_Font* pFont, FX_FLOAT font_size,
                                 const CFX_AffineMatrix* pText2User, const CFX_AffineMatrix* pUser2Device,
                                 const CFX_GraphStateData* pGraphState,
                                 FX_ARGB fill_argb, FX_ARGB stroke_argb, CFX_PathData* pClippingPath, int nFlag = 0);

    static FX_BOOL	DrawNormalText(CFX_RenderDevice* pDevice, int nChars, FX_DWORD* pCharCodes, FX_FLOAT* pCharPos,
                                   CPDF_Font* pFont, FX_FLOAT font_size, const CFX_AffineMatrix* pText2Device,
                                   FX_ARGB fill_argb, const CPDF_RenderOptions* pOptions);

    static FX_BOOL	DrawType3Text(CFX_RenderDevice* pDevice, int nChars, FX_DWORD* pCharCodes, FX_FLOAT* pCharPos,
                                  CPDF_Font* pFont, FX_FLOAT font_size, const CFX_AffineMatrix* pText2Device,
                                  FX_ARGB fill_argb);
};
class IPDF_PageImageCache
{
public:

    static IPDF_PageImageCache* Create();

    virtual ~IPDF_PageImageCache() {}

    virtual void		OutputPage(CFX_RenderDevice* pDevice, CPDF_Page* pPage,
                                   int pos_x, int pos_y, int size_x, int size_y, int rotate) = 0;

    virtual void		SetCacheLimit(FX_DWORD limit) = 0;
};
class CPDF_PageRenderCache : public CFX_Object
{
public:
    CPDF_PageRenderCache(CPDF_Page* pPage)
    {
        m_pPage = pPage;
        m_nTimeCount = 0;
        m_nCacheSize = 0;
        m_pCurImageCache = NULL;
        m_bCurFindCache = FALSE;
        m_pCurImageCaches = NULL;
    }
    ~CPDF_PageRenderCache()
    {
        ClearAll();
    }
    void				ClearAll();
    void				ClearImageData();

    FX_DWORD			EstimateSize();
    void				CacheOptimization(FX_INT32 dwLimitCacheSize);
    FX_DWORD			GetCachedSize(CPDF_Stream* pStream) const;
    FX_DWORD			GetTimeCount() const
    {
        return m_nTimeCount;
    }
    void				SetTimeCount(FX_DWORD dwTimeCount)
    {
        m_nTimeCount = dwTimeCount;
    }

    void				GetCachedBitmap(CPDF_Stream* pStream, CFX_DIBSource*& pBitmap, CFX_DIBSource*& pMask, FX_DWORD& MatteColor,
                                        FX_BOOL bStdCS = FALSE, FX_DWORD GroupFamily = 0, FX_BOOL bLoadMask = FALSE,
                                        CPDF_RenderStatus* pRenderStatus = NULL, FX_INT32 downsampleWidth = 0, FX_INT32 downsampleHeight = 0);

    void				ResetBitmap(CPDF_Stream* pStream, const CFX_DIBitmap* pBitmap);
    void				ClearImageCache(CPDF_Stream* pStream);
    CPDF_Page*			GetPage()
    {
        return m_pPage;
    }
    CFX_MapPtrToPtr		m_ImageCaches;
public:
    FX_BOOL				StartGetCachedBitmap(CPDF_Stream* pStream, FX_BOOL bStdCS = FALSE, FX_DWORD GroupFamily = 0,
            FX_BOOL bLoadMask = FALSE, CPDF_RenderStatus* pRenderStatus = NULL,
            FX_INT32 downsampleWidth = 0, FX_INT32 downsampleHeight = 0);

    FX_BOOL				Continue(IFX_Pause* pPause);
    CPDF_ImageCache*	m_pCurImageCache;
    CFX_PtrArray*       m_pCurImageCaches;
protected:
    friend class		CPDF_Page;
    CPDF_Page*			m_pPage;

    FX_DWORD			m_nTimeCount;
    FX_DWORD			m_nCacheSize;
    FX_BOOL				m_bCurFindCache;
};
class CPDF_RenderConfig : public CFX_Object
{
public:
    CPDF_RenderConfig();
    ~CPDF_RenderConfig();
    int					m_HalftoneLimit;
    int					m_RenderStepLimit;
};
#endif