// 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 CORE_INCLUDE_FPDFAPI_FPDF_PAGEOBJ_H_
#define CORE_INCLUDE_FPDFAPI_FPDF_PAGEOBJ_H_

#include "core/include/fxge/fx_ge.h"
#include "fpdf_resource.h"

class CPDF_ClipPath;
class CPDF_ClipPathData;
class CPDF_ColorState;
class CPDF_ColorStateData;
class CPDF_ContentMark;
class CPDF_ContentMarkItem;
class CPDF_FormObject;
class CPDF_GeneralState;
class CPDF_GeneralStateData;
class CPDF_GraphicStates;
class CPDF_GraphState;
class CPDF_ImageObject;
class CPDF_PageObject;
class CPDF_Path;
class CPDF_PathObject;
class CPDF_ShadingObject;
class CPDF_TextObject;
class CPDF_TextState;
class CPDF_TextStateData;
class CPDF_TransferFunc;

typedef CFX_PathData CPDF_PathData;

class CPDF_Path : public CFX_CountRef<CFX_PathData> {
 public:
  int GetPointCount() { return m_pObject->m_PointCount; }

  int GetFlag(int index) { return m_pObject->m_pPoints[index].m_Flag; }

  FX_FLOAT GetPointX(int index) { return m_pObject->m_pPoints[index].m_PointX; }

  FX_FLOAT GetPointY(int index) { return m_pObject->m_pPoints[index].m_PointY; }

  FX_PATHPOINT* GetPoints() { return m_pObject->m_pPoints; }

  CFX_FloatRect GetBoundingBox() const { return m_pObject->GetBoundingBox(); }

  CFX_FloatRect GetBoundingBox(FX_FLOAT line_width,
                               FX_FLOAT miter_limit) const {
    return m_pObject->GetBoundingBox(line_width, miter_limit);
  }

  void Transform(const CFX_Matrix* pMatrix) { GetModify()->Transform(pMatrix); }

  void Append(CPDF_Path src, const CFX_Matrix* pMatrix) {
    m_pObject->Append(src.m_pObject, pMatrix);
  }

  void AppendRect(FX_FLOAT left,
                  FX_FLOAT bottom,
                  FX_FLOAT right,
                  FX_FLOAT top) {
    m_pObject->AppendRect(left, bottom, right, top);
  }

  FX_BOOL IsRect() const { return m_pObject->IsRect(); }
};
class CPDF_ClipPathData {
 public:
  CPDF_ClipPathData();
  CPDF_ClipPathData(const CPDF_ClipPathData&);
  ~CPDF_ClipPathData();

  void SetCount(int path_count, int text_count);

 public:
  int m_PathCount;

  CPDF_Path* m_pPathList;

  uint8_t* m_pTypeList;

  int m_TextCount;

  CPDF_TextObject** m_pTextList;
};

class CPDF_ClipPath : public CFX_CountRef<CPDF_ClipPathData> {
 public:
  FX_DWORD GetPathCount() const { return m_pObject->m_PathCount; }

  CPDF_Path GetPath(int i) const { return m_pObject->m_pPathList[i]; }

  int GetClipType(int i) const { return m_pObject->m_pTypeList[i]; }

  FX_DWORD GetTextCount() const { return m_pObject->m_TextCount; }

  CPDF_TextObject* GetText(int i) const { return m_pObject->m_pTextList[i]; }

  CFX_FloatRect GetClipBox() const;

  void AppendPath(CPDF_Path path, int type, FX_BOOL bAutoMerge);

  void DeletePath(int layer_index);

  void AppendTexts(CPDF_TextObject** pTexts, int count);

  void Transform(const CFX_Matrix& matrix);
};
class CPDF_ColorStateData {
 public:
  CPDF_ColorStateData() : m_FillRGB(0), m_StrokeRGB(0) {}

  CPDF_ColorStateData(const CPDF_ColorStateData& src);

  void Default();

  CPDF_Color m_FillColor;

  FX_DWORD m_FillRGB;

  CPDF_Color m_StrokeColor;

  FX_DWORD m_StrokeRGB;
};
class CPDF_ColorState : public CFX_CountRef<CPDF_ColorStateData> {
 public:
  CPDF_Color* GetFillColor() const {
    return m_pObject ? &m_pObject->m_FillColor : NULL;
  }

  CPDF_Color* GetStrokeColor() const {
    return m_pObject ? &m_pObject->m_StrokeColor : NULL;
  }

  void SetFillColor(CPDF_ColorSpace* pCS, FX_FLOAT* pValue, int nValues);

  void SetStrokeColor(CPDF_ColorSpace* pCS, FX_FLOAT* pValue, int nValues);

  void SetFillPattern(CPDF_Pattern* pattern, FX_FLOAT* pValue, int nValues);

  void SetStrokePattern(CPDF_Pattern* pattern, FX_FLOAT* pValue, int nValues);

 private:
  void SetColor(CPDF_Color& color,
                FX_DWORD& rgb,
                CPDF_ColorSpace* pCS,
                FX_FLOAT* pValue,
                int nValues);
};
typedef CFX_GraphStateData CPDF_GraphStateData;
class CPDF_GraphState : public CFX_CountRef<CFX_GraphStateData> {
 public:
};
class CPDF_TextStateData {
 public:
  CPDF_TextStateData();

  CPDF_TextStateData(const CPDF_TextStateData& src);

  ~CPDF_TextStateData();

  CPDF_Font* m_pFont;

  CPDF_Document* m_pDocument;

  FX_FLOAT m_FontSize;

  FX_FLOAT m_CharSpace;

  FX_FLOAT m_WordSpace;

  FX_FLOAT m_Matrix[4];

  int m_TextMode;

  FX_FLOAT m_CTM[4];
};
class CPDF_TextState : public CFX_CountRef<CPDF_TextStateData> {
 public:
  CPDF_Font* GetFont() const { return m_pObject->m_pFont; }

  void SetFont(CPDF_Font* pFont);

  FX_FLOAT GetFontSize() const { return m_pObject->m_FontSize; }

  FX_FLOAT* GetMatrix() const { return m_pObject->m_Matrix; }

  FX_FLOAT GetFontSizeV() const;

  FX_FLOAT GetFontSizeH() const;

  FX_FLOAT GetBaselineAngle() const;

  FX_FLOAT GetShearAngle() const;
};

class CPDF_GeneralStateData {
 public:
  CPDF_GeneralStateData();

  CPDF_GeneralStateData(const CPDF_GeneralStateData& src);
  ~CPDF_GeneralStateData();

  void SetBlendMode(const CFX_ByteStringC& blend_mode);

  char m_BlendMode[16];

  int m_BlendType;

  CPDF_Object* m_pSoftMask;

  FX_FLOAT m_SMaskMatrix[6];

  FX_FLOAT m_StrokeAlpha;

  FX_FLOAT m_FillAlpha;

  CPDF_Object* m_pTR;

  CPDF_TransferFunc* m_pTransferFunc;

  CFX_Matrix m_Matrix;

  int m_RenderIntent;

  FX_BOOL m_StrokeAdjust;

  FX_BOOL m_AlphaSource;

  FX_BOOL m_TextKnockout;

  FX_BOOL m_StrokeOP;

  FX_BOOL m_FillOP;

  int m_OPMode;

  CPDF_Object* m_pBG;

  CPDF_Object* m_pUCR;

  CPDF_Object* m_pHT;

  FX_FLOAT m_Flatness;

  FX_FLOAT m_Smoothness;
};
class CPDF_GeneralState : public CFX_CountRef<CPDF_GeneralStateData> {
 public:
  void SetRenderIntent(const CFX_ByteString& ri);

  int GetBlendType() const {
    return m_pObject ? m_pObject->m_BlendType : FXDIB_BLEND_NORMAL;
  }

  int GetAlpha(FX_BOOL bStroke) const {
    return m_pObject ? FXSYS_round((bStroke ? m_pObject->m_StrokeAlpha
                                            : m_pObject->m_FillAlpha) *
                                   255)
                     : 255;
  }
};
class CPDF_ContentMarkItem {
 public:
  typedef enum { None, PropertiesDict, DirectDict, MCID } ParamType;

  CPDF_ContentMarkItem();

  CPDF_ContentMarkItem(const CPDF_ContentMarkItem& src);

  ~CPDF_ContentMarkItem();

  inline const CFX_ByteString& GetName() const { return m_MarkName; }

  inline ParamType GetParamType() const { return m_ParamType; }

  inline void* GetParam() const { return m_pParam; }

  inline FX_BOOL HasMCID() const;

  inline void SetName(const CFX_ByteString& name) { m_MarkName = name; }

  inline void SetParam(ParamType type, void* param) {
    m_ParamType = type;
    m_pParam = param;
  }

 private:
  CFX_ByteString m_MarkName;

  ParamType m_ParamType;

  void* m_pParam;
};
class CPDF_ContentMarkData {
 public:
  CPDF_ContentMarkData() {}

  CPDF_ContentMarkData(const CPDF_ContentMarkData& src);

  inline int CountItems() const { return m_Marks.GetSize(); }

  inline CPDF_ContentMarkItem& GetItem(int index) const {
    return m_Marks[index];
  }

  int GetMCID() const;

  void AddMark(const CFX_ByteString& name,
               CPDF_Dictionary* pDict,
               FX_BOOL bDictNeedClone);

  void DeleteLastMark();

 private:
  CFX_ObjectArray<CPDF_ContentMarkItem> m_Marks;
};
class CPDF_ContentMark : public CFX_CountRef<CPDF_ContentMarkData> {
 public:
  int GetMCID() const { return m_pObject ? m_pObject->GetMCID() : -1; }

  FX_BOOL HasMark(const CFX_ByteStringC& mark) const;

  FX_BOOL LookupMark(const CFX_ByteStringC& mark,
                     CPDF_Dictionary*& pDict) const;
};

#define PDFPAGE_TEXT 1
#define PDFPAGE_PATH 2
#define PDFPAGE_IMAGE 3
#define PDFPAGE_SHADING 4
#define PDFPAGE_FORM 5

class CPDF_GraphicStates {
 public:
  void CopyStates(const CPDF_GraphicStates& src);

  void DefaultStates();

  CPDF_ClipPath m_ClipPath;

  CPDF_GraphState m_GraphState;

  CPDF_ColorState m_ColorState;

  CPDF_TextState m_TextState;

  CPDF_GeneralState m_GeneralState;
};

class CPDF_PageObject : public CPDF_GraphicStates {
 public:
  static CPDF_PageObject* Create(int type);
  virtual ~CPDF_PageObject();

  CPDF_PageObject* Clone() const;

  void Copy(const CPDF_PageObject* pSrcObject);

  virtual void Transform(const CFX_Matrix& matrix) = 0;

  void RemoveClipPath();

  void AppendClipPath(CPDF_Path path, int type, FX_BOOL bAutoMerge);

  void CopyClipPath(CPDF_PageObject* pObj);

  void TransformClipPath(CFX_Matrix& matrix);

  void TransformGeneralState(CFX_Matrix& matrix);

  void SetColorState(CPDF_ColorState state) { m_ColorState = state; }

  FX_RECT GetBBox(const CFX_Matrix* pMatrix) const;

  int m_Type;

  FX_FLOAT m_Left;

  FX_FLOAT m_Right;

  FX_FLOAT m_Top;

  FX_FLOAT m_Bottom;

  CPDF_ContentMark m_ContentMark;

 protected:
  virtual void CopyData(const CPDF_PageObject* pSrcObject) = 0;

  void RecalcBBox();

  CPDF_PageObject() {}
};

struct CPDF_TextObjectItem {
  FX_DWORD m_CharCode;
  FX_FLOAT m_OriginX;
  FX_FLOAT m_OriginY;
};

class CPDF_TextObject : public CPDF_PageObject {
 public:
  CPDF_TextObject();
  ~CPDF_TextObject() override;

  int CountItems() const { return m_nChars; }

  void GetItemInfo(int index, CPDF_TextObjectItem* pInfo) const;

  int CountChars() const;

  void GetCharInfo(int index, FX_DWORD& charcode, FX_FLOAT& kerning) const;
  void GetCharInfo(int index, CPDF_TextObjectItem* pInfo) const;

  void GetCharRect(int index, CFX_FloatRect& rect) const;

  FX_FLOAT GetCharWidth(FX_DWORD charcode) const;
  FX_FLOAT GetSpaceCharWidth() const;

  FX_FLOAT GetPosX() const { return m_PosX; }

  FX_FLOAT GetPosY() const { return m_PosY; }

  void GetTextMatrix(CFX_Matrix* pMatrix) const;

  CPDF_Font* GetFont() const { return m_TextState.GetFont(); }

  FX_FLOAT GetFontSize() const { return m_TextState.GetFontSize(); }

  void SetEmpty();

  void SetText(const CFX_ByteString& text);

  void SetText(CFX_ByteString* pStrs, FX_FLOAT* pKerning, int nSegs);

  void SetText(int nChars, FX_DWORD* pCharCodes, FX_FLOAT* pKernings);

  void SetPosition(FX_FLOAT x, FX_FLOAT y);

  void SetTextState(CPDF_TextState TextState);

  // CPDF_PageObject:
  void Transform(const CFX_Matrix& matrix) override;

  void CalcCharPos(FX_FLOAT* pPosArray) const;

  void SetData(int nChars,
               FX_DWORD* pCharCodes,
               FX_FLOAT* pCharPos,
               FX_FLOAT x,
               FX_FLOAT y);

  void GetData(int& nChars, FX_DWORD*& pCharCodes, FX_FLOAT*& pCharPos) {
    nChars = m_nChars;
    pCharCodes = m_pCharCodes;
    pCharPos = m_pCharPos;
  }

  void RecalcPositionData() { CalcPositionData(nullptr, nullptr, 1); }

 protected:
  friend class CPDF_RenderStatus;
  friend class CPDF_StreamContentParser;
  friend class CPDF_TextRenderer;
  friend class CTextPage;

  // CPDF_PageObject:
  void CopyData(const CPDF_PageObject* pSrcObject) override;

  void SetSegments(const CFX_ByteString* pStrs, FX_FLOAT* pKerning, int nSegs);

  void CalcPositionData(FX_FLOAT* pTextAdvanceX,
                        FX_FLOAT* pTextAdvanceY,
                        FX_FLOAT horz_scale,
                        int level = 0);

  FX_FLOAT m_PosX;
  FX_FLOAT m_PosY;

  int m_nChars;

  FX_DWORD* m_pCharCodes;

  FX_FLOAT* m_pCharPos;
};

class CPDF_PathObject : public CPDF_PageObject {
 public:
  CPDF_PathObject() { m_Type = PDFPAGE_PATH; }
  ~CPDF_PathObject() override {}

  void Transform(const CFX_Matrix& maxtrix) override;

  void SetGraphState(CPDF_GraphState GraphState);

  void CalcBoundingBox();

  CPDF_Path m_Path;

  int m_FillType;

  FX_BOOL m_bStroke;

  CFX_Matrix m_Matrix;

 protected:
  void CopyData(const CPDF_PageObject* pSrcObject) override;
};

class CPDF_ImageObject : public CPDF_PageObject {
 public:
  CPDF_ImageObject();
  ~CPDF_ImageObject() override;

  void Transform(const CFX_Matrix& matrix) override;

  CPDF_Image* m_pImage;

  CFX_Matrix m_Matrix;

  void CalcBoundingBox();

 private:
  void CopyData(const CPDF_PageObject* pSrcObject) override;
};

class CPDF_ShadingObject : public CPDF_PageObject {
 public:
  CPDF_ShadingObject();
  ~CPDF_ShadingObject() override;

  CPDF_ShadingPattern* m_pShading;

  CFX_Matrix m_Matrix;

  void Transform(const CFX_Matrix& matrix) override;

  void CalcBoundingBox();

 protected:
  void CopyData(const CPDF_PageObject* pSrcObject) override;
};

class CPDF_FormObject : public CPDF_PageObject {
 public:
  CPDF_FormObject() {
    m_Type = PDFPAGE_FORM;
    m_pForm = NULL;
  }
  ~CPDF_FormObject() override;

  void Transform(const CFX_Matrix& matrix) override;

  CPDF_Form* m_pForm;

  CFX_Matrix m_FormMatrix;

  void CalcBoundingBox();

 protected:
  void CopyData(const CPDF_PageObject* pSrcObject) override;
};

#endif  // CORE_INCLUDE_FPDFAPI_FPDF_PAGEOBJ_H_