//========================================================================
//
// FoFiType1C.h
//
// Copyright 1999-2003 Glyph & Cog, LLC
//
//========================================================================

//========================================================================
//
// Modified under the Poppler project - http://poppler.freedesktop.org
//
// All changes made under the Poppler project to this file are licensed
// under GPL version 2 or later
//
// Copyright (C) 2006 Takashi Iwai <tiwai@suse.de>
// Copyright (C) 2012 Thomas Freitag <Thomas.Freitag@alfa.de>
// Copyright (C) 2018-2020 Albert Astals Cid <aacid@kde.org>
//
// To see a description of the changes please see the Changelog file that
// came with your tarball or type make ChangeLog if you are building from git
//
//========================================================================

#ifndef FOFITYPE1C_H
#define FOFITYPE1C_H

#include "FoFiBase.h"

class GooString;

//------------------------------------------------------------------------

struct Type1CIndex {
  int pos;			// absolute position in file
  int len;			// length (number of entries)
  int offSize;			// offset size
  int startPos;			// position of start of index data - 1
  int endPos;			// position one byte past end of the index
};

struct Type1CIndexVal {
  int pos;			// absolute position in file
  int len;			// length, in bytes
};

struct Type1CTopDict {
  int firstOp;

  int versionSID;
  int noticeSID;
  int copyrightSID;
  int fullNameSID;
  int familyNameSID;
  int weightSID;
  int isFixedPitch;
  double italicAngle;
  double underlinePosition;
  double underlineThickness;
  int paintType;
  int charstringType;
  double fontMatrix[6];
  bool hasFontMatrix;		// CID fonts are allowed to put their
				//   FontMatrix in the FD instead of the
				//   top dict
  int uniqueID;
  double fontBBox[4];
  double strokeWidth;
  int charsetOffset;
  int encodingOffset;
  int charStringsOffset;
  int privateSize;
  int privateOffset;

  // CIDFont entries
  int registrySID;
  int orderingSID;
  int supplement;
  int fdArrayOffset;
  int fdSelectOffset;
};

#define type1CMaxBlueValues 14
#define type1CMaxOtherBlues 10
#define type1CMaxStemSnap   12

struct Type1CPrivateDict {
  double fontMatrix[6];
  bool hasFontMatrix;
  int blueValues[type1CMaxBlueValues];
  int nBlueValues;
  int otherBlues[type1CMaxOtherBlues];
  int nOtherBlues;
  int familyBlues[type1CMaxBlueValues];
  int nFamilyBlues;
  int familyOtherBlues[type1CMaxOtherBlues];
  int nFamilyOtherBlues;
  double blueScale;
  int blueShift;
  int blueFuzz;
  double stdHW;
  bool hasStdHW;
  double stdVW;
  bool hasStdVW;
  double stemSnapH[type1CMaxStemSnap];
  int nStemSnapH;
  double stemSnapV[type1CMaxStemSnap];
  int nStemSnapV;
  bool forceBold;
  bool hasForceBold;
  double forceBoldThreshold;
  int languageGroup;
  double expansionFactor;
  int initialRandomSeed;
  int subrsOffset;
  double defaultWidthX;
  bool defaultWidthXFP;
  double nominalWidthX;
  bool nominalWidthXFP;
};

struct Type1COp {
  bool isNum = true;			// true -> number, false -> operator
  bool isFP = false;			// true -> floating point number, false -> int
  union {
    double num = 0;			// if num is true
    int op;			// if num is false
  };
};

struct Type1CEexecBuf {
  FoFiOutputFunc outputFunc;
  void *outputStream;
  bool ascii;			// ASCII encoding?
  unsigned short r1;		// eexec encryption key
  int line;			// number of eexec chars left on current line
};

//------------------------------------------------------------------------
// FoFiType1C
//------------------------------------------------------------------------

class FoFiType1C: public FoFiBase {
public:

  // Create a FoFiType1C object from a memory buffer.
  static FoFiType1C *make(const char *fileA, int lenA);

  // Create a FoFiType1C object from a file on disk.
  static FoFiType1C *load(const char *fileName);

  ~FoFiType1C() override;

  // Return the font name.
  const char *getName() const;

  // Return the encoding, as an array of 256 names (any of which may
  // be NULL).  This is only useful with 8-bit fonts.
  char **getEncoding() const;

  // Get the glyph names.
  int getNumGlyphs() const { return nGlyphs; }
  GooString *getGlyphName(int gid) const;

  // Return the mapping from CIDs to GIDs, and return the number of
  // CIDs in *<nCIDs>.  This is only useful for CID fonts.
  int *getCIDToGIDMap(int *nCIDs) const;

  // Return the font matrix as an array of six numbers.
  void getFontMatrix(double *mat) const;

  // Convert to a Type 1 font, suitable for embedding in a PostScript
  // file.  This is only useful with 8-bit fonts.  If <newEncoding> is
  // not NULL, it will be used in place of the encoding in the Type 1C
  // font.  If <ascii> is true the eexec section will be hex-encoded,
  // otherwise it will be left as binary data.  If <psName> is non-NULL,
  // it will be used as the PostScript font name.
  void convertToType1(const char *psName, const char **newEncoding, bool ascii,
		      FoFiOutputFunc outputFunc, void *outputStream);

  // Convert to a Type 0 CIDFont, suitable for embedding in a
  // PostScript file.  <psName> will be used as the PostScript font
  // name.  There are three cases for the CID-to-GID mapping:
  // (1) if <codeMap> is non-NULL, then it is the CID-to-GID mapping
  // (2) if <codeMap> is NULL and this is a CID CFF font, then the
  //     font's internal CID-to-GID mapping is used
  // (3) is <codeMap> is NULL and this is an 8-bit CFF font, then
  //     the identity CID-to-GID mapping is used
  void convertToCIDType0(const char *psName, const int *codeMap, int nCodes,
			 FoFiOutputFunc outputFunc, void *outputStream);

  // Convert to a Type 0 (but non-CID) composite font, suitable for
  // embedding in a PostScript file.  <psName> will be used as the
  // PostScript font name.  There are three cases for the CID-to-GID
  // mapping:
  // (1) if <codeMap> is non-NULL, then it is the CID-to-GID mapping
  // (2) if <codeMap> is NULL and this is a CID CFF font, then the
  //     font's internal CID-to-GID mapping is used
  // (3) is <codeMap> is NULL and this is an 8-bit CFF font, then
  //     the identity CID-to-GID mapping is used
  void convertToType0(const char *psName, const int *codeMap, int nCodes,
		      FoFiOutputFunc outputFunc, void *outputStream);

private:

  FoFiType1C(const char *fileA, int lenA, bool freeFileDataA);
  void eexecCvtGlyph(Type1CEexecBuf *eb, const char *glyphName,
		     int offset, int nBytes,
		     const Type1CIndex *subrIdx,
		     const Type1CPrivateDict *pDict);
  void cvtGlyph(int offset, int nBytes, GooString *charBuf,
		const Type1CIndex *subrIdx, const Type1CPrivateDict *pDict,
		bool top);
  void cvtGlyphWidth(bool useOp, GooString *charBuf,
		     const Type1CPrivateDict *pDict);
  void cvtNum(double x, bool isFP, GooString *charBuf) const;
  void eexecWrite(Type1CEexecBuf *eb, const char *s) const;
  void eexecWriteCharstring(Type1CEexecBuf *eb, const unsigned char *s, int n) const;
  void writePSString(const char *s, FoFiOutputFunc outputFunc, void *outputStream) const;
  bool parse();
  void readTopDict();
  void readFD(int offset, int length, Type1CPrivateDict *pDict);
  void readPrivateDict(int offset, int length, Type1CPrivateDict *pDict);
  void readFDSelect();
  void buildEncoding();
  bool readCharset();
  int getOp(int pos, bool charstring, bool *ok);
  int getDeltaIntArray(int *arr, int maxLen) const;
  int getDeltaFPArray(double *arr, int maxLen) const;
  void getIndex(int pos, Type1CIndex *idx, bool *ok) const;
  void getIndexVal(const Type1CIndex *idx, int i, Type1CIndexVal *val, bool *ok) const;
  char *getString(int sid, char *buf, bool *ok) const;

  GooString *name;
  char **encoding;

  Type1CIndex nameIdx;
  Type1CIndex topDictIdx;
  Type1CIndex stringIdx;
  Type1CIndex gsubrIdx;
  Type1CIndex charStringsIdx;

  Type1CTopDict topDict;
  Type1CPrivateDict *privateDicts;

  int nGlyphs;
  int nFDs;
  unsigned char *fdSelect;
  const unsigned short *charset;
  unsigned short charsetLength;
  int gsubrBias;

  bool parsedOk;

  Type1COp ops[49];		// operands and operator
  int nOps;			// number of operands
  int nHints;			// number of hints for the current glyph
  bool firstOp;		// true if we haven't hit the first op yet
  bool openPath;		// true if there is an unclosed path
};

#endif
