LCOV - code coverage report
Current view: top level - libreoffice/vcl/source/fontsubset - cff.cxx (source / functions) Hit Total Coverage
Test: libreoffice_filtered.info Lines: 0 1010 0.0 %
Date: 2012-12-27 Functions: 0 57 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
       2             : /*
       3             :  * This file is part of the LibreOffice project.
       4             :  *
       5             :  * This Source Code Form is subject to the terms of the Mozilla Public
       6             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       7             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
       8             :  *
       9             :  * This file incorporates work covered by the following license notice:
      10             :  *
      11             :  *   Licensed to the Apache Software Foundation (ASF) under one or more
      12             :  *   contributor license agreements. See the NOTICE file distributed
      13             :  *   with this work for additional information regarding copyright
      14             :  *   ownership. The ASF licenses this file to you under the Apache
      15             :  *   License, Version 2.0 (the "License"); you may not use this file
      16             :  *   except in compliance with the License. You may obtain a copy of
      17             :  *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
      18             :  */
      19             : 
      20             : 
      21             : #include <cstdio>
      22             : #include <cstring>
      23             : #include <assert.h>
      24             : 
      25             : #include <fontsubset.hxx>
      26             : 
      27             : #include <vcl/strhelper.hxx>
      28             : 
      29             : //#define IGNORE_HINTS
      30             : 
      31             : typedef unsigned char U8;
      32             : typedef unsigned short U16;
      33             : typedef long long S64;
      34             : 
      35             : typedef sal_Int32 GlyphWidth;
      36             : 
      37             : typedef float RealType;
      38             : typedef RealType ValType;
      39             : #include <vector>
      40             : typedef std::vector<ValType> ValVector;
      41             : 
      42             : // ====================================================================
      43             : 
      44             : static const char* pStringIds[] = {
      45             : /*0*/   ".notdef",      "space",            "exclam",           "quotedbl",
      46             :     "numbersign",       "dollar",           "percent",          "ampersand",
      47             :     "quoteright",       "parenleft",        "parenright",       "asterisk",
      48             :     "plus",             "comma",            "hyphen",           "period",
      49             : /*16*/  "slash",        "zero",             "one",              "two",
      50             :     "three",            "four",             "five",             "six",
      51             :     "seven",            "eight",            "nine",             "colon",
      52             :     "semicolon",        "less",             "equal",            "greater",
      53             : /*32*/  "question",     "at",               "A",                "B",
      54             :     "C",                "D",                "E",                "F",
      55             :     "G",                "H",                "I",                "J",
      56             :     "K",                "L",                "M",                "N",
      57             : /*48*/  "O",            "P",                "Q",                "R",
      58             :     "S",                "T",                "U",                "V",
      59             :     "W",                "X",                "Y",                "Z",
      60             :     "bracketleft",      "backslash",        "bracketright",     "asciicircum",
      61             : /*64*/  "underscore",   "quoteleft",        "a",                "b",
      62             :     "c",                "d",                "e",                "f",
      63             :     "g",                "h",                "i",                "j",
      64             :     "k",                "l",                "m",                "n",
      65             : /*80*/  "o",            "p",                "q",                "r",
      66             :     "s",                "t",                "u",                "v",
      67             :     "w",                "x",                "y",                "z",
      68             :     "braceleft",        "bar",              "braceright",       "asciitilde",
      69             : /*96*/  "exclamdown",   "cent",             "sterlin",          "fraction",
      70             :     "yen",              "florin",           "section",          "currency",
      71             :     "quotesingle",      "quotedblleft",     "guillemotleft",    "guilsinglleft",
      72             :     "guilsinglright",   "fi",               "fl",               "endash",
      73             : /*112*/ "dagger",       "daggerdbl",        "periodcentered",   "paragraph",
      74             :     "bullet",           "quotesinglbase",   "quotedblbase",     "quotedblright",
      75             :     "guillemotright",   "ellipsis",         "perthousand",      "questiondown",
      76             :     "grave",            "acute",            "circumflex",       "tilde",
      77             : /*128*/ "macron",       "breve",            "dotaccent",        "dieresis",
      78             :     "ring",             "cedilla",          "hungarumlaut",     "ogonek",
      79             :     "caron",            "emdash",           "AE",               "ordfeminine",
      80             :     "Lslash",           "Oslash",           "OE",               "ordmasculine",
      81             : /*144*/ "ae",           "dotlessi",         "lslash",           "oslash",
      82             :     "oe",               "germandbls",       "onesuperior",      "logicalnot",
      83             :     "mu",               "trademark",        "Eth",              "onehalf",
      84             :     "plusminus",        "Thorn",            "onequarter",       "divide",
      85             : /*160*/ "brokenbar",    "degree",           "thorn",            "threequarters",
      86             :     "twosuperior",      "registered",       "minus",            "eth",
      87             :     "multiply",         "threesuperior",    "copyright",        "Aacute",
      88             :     "Acircumflex",      "Adieresis",        "Agrave",           "Aring",
      89             : /*176*/ "Atilde",       "Ccedilla",         "Eacute",           "Ecircumflex",
      90             :     "Edieresis",        "Egrave",           "Iacute",           "Icircumflex",
      91             :     "Idieresis",        "Igrave",           "Ntilde",           "Oacute",
      92             :     "Ocircumflex",      "Odieresis",        "Ograve",           "Otilde",
      93             : /*192*/ "Scaron",       "Uacute",           "Ucircumflex",      "Udieresis",
      94             :     "Ugrave",           "Yacute",           "Ydieresis",        "Zcaron",
      95             :     "aacute",           "acircumflex",      "adieresis",        "agrave",
      96             :     "aring",            "atilde",           "ccedilla",         "eacute",
      97             : /*208*/ "ecircumflex",  "edieresis",        "egrave",           "iacute",
      98             :     "icircumflex",      "idieresis",        "igrave",           "ntilde",
      99             :     "oacute",           "ocircumflex",      "odieresis",        "ograve",
     100             :     "otilde",           "scaron",           "uacute",           "ucircumflex",
     101             : /*224*/ "udieresis",    "ugrave",           "yacute",           "ydieresis",
     102             :     "zcaron",           "exclamsmall",      "Hungarumlautsmall","dollaroldstyle",
     103             :     "dollarsuperior",   "ampersandsmall",   "Acutesmall",       "parenleftsuperior",
     104             :     "parenrightsuperior","twodotenleader",  "onedotenleader",   "zerooldstyle",
     105             : /*240*/ "oneoldstyle",  "twooldstyle",      "threeoldstyle",    "fouroldstyle",
     106             :     "fiveoldstyle",     "sixoldstyle",      "sevenoldstyle",    "eightoldstyle",
     107             :     "nineoldstile",     "commasuperior",    "threequartersemdash","periodsuperior",
     108             :     "questionsmall",    "asuperior",        "bsuperior",        "centsuperior",
     109             : /*256*/ "dsuperior",    "esuperior",        "isuperior",        "lsuperior",
     110             :     "msuperior",        "nsuperior",        "osuperior",        "rsuperior",
     111             :     "ssuperior",        "tsuperior",        "ff",               "ffi",
     112             :     "ffl",              "parenleftinferior","parenrightinferior","Circumflexsmall",
     113             : /*272*/ "hyphensuperior","Gravesmall",      "Asmall",           "Bsmall",
     114             :     "Csmall",           "Dsmall",           "Esmall",           "Fsmall",
     115             :     "Gsmall",           "Hsmall",           "Ismall",           "Jsmall",
     116             :     "Ksmall",           "Lsmall",           "Msmall",           "Nsmall",
     117             : /*288*/ "Osmall",       "Psmall",           "Qsmall",           "Rsmall",
     118             :     "Ssmall",           "Tsmall",           "Usmall",           "Vsmall",
     119             :     "Wsmall",           "Xsmall",           "Ysmall",           "Zsmall",
     120             :     "colonmonetary",    "onefitted",        "rupia",            "Tildesmall",
     121             : /*304*/ "exclamdownsmall","centoldstyle",   "Lslashsmall",      "Scaronsmall",
     122             :     "Zcaronsmall",      "Dieresissmall",    "Brevesmall",       "Caronsmall",
     123             :     "Dotaccentsmall",   "Macronsmall",      "figuredash",       "hypheninferior",
     124             :     "Ogoneksmall",      "Ringsmall",        "Cedillasmall",     "questiondownsmall",
     125             : /*320*/ "oneeight",     "threeeights",      "fiveeights",       "seveneights",
     126             :     "onethird",         "twothirds",        "zerosuperior",     "foursuperior",
     127             :     "fivesuperior",     "sixsuperior",      "sevensuperior",    "eightsuperior",
     128             :     "ninesuperior",     "zeroinferior",     "oneinferior",      "twoinferior",
     129             : /*336*/ "threeinferior","fourinferior",     "fiveinferior",     "sixinferior",
     130             :     "seveninferior",    "eightinferior",    "nineinferior",     "centinferior",
     131             :     "dollarinferior",   "periodinferior",   "commainferior",    "Agravesmall",
     132             :     "Aacutesmall",      "Acircumflexsmall", "Atildesmall",      "Adieresissmall",
     133             : /*352*/ "Aringsmall",   "AEsmall",          "Ccedillasmall",    "Egravesmall",
     134             :     "Eacutesmall",      "Ecircumflexsmall", "Edieresissmall",   "Igravesmall",
     135             :     "Iacutesmall",      "Icircumflexsmall", "Idieresissmall",   "Ethsmall",
     136             :     "Ntildesmall",      "Ogravesmall",      "Oacutesmall",      "Ocircumflexsmall",
     137             : /*368*/ "Otildesmall",  "Odieressissmall",  "OEsmall",          "Oslashsmall",
     138             :     "Ugravesmall",      "Uacutesmall",      "Ucircumflexsmall", "Udieresissmall",
     139             :     "Yacutesmall",      "Thornsmall",       "Ydieresissmall",   "001.000",
     140             :     "001.001",          "001.002",          "001.003",          "Black",
     141             : /*384*/ "Bold",         "Book",             "Light",            "Medium",
     142             :     "Regular",          "Roman",            "Semibold"
     143             : };
     144             : 
     145             : // --------------------------------------------------------------------
     146             : 
     147             : // --------------------------------------------------------------------
     148             : 
     149             : // TOP DICT keywords (also covers PRIV DICT keywords)
     150             : static const char* pDictOps[] = {
     151             :     "sVersion",         "sNotice",              "sFullName",        "sFamilyName",
     152             :     "sWeight",          "aFontBBox",            "dBlueValues",      "dOtherBlues",
     153             :     "dFamilyBlues",     "dFamilyOtherBlues",    "nStdHW",           "nStdVW",
     154             :     "xESC",             "nUniqueID",            "aXUID",            "nCharset",
     155             :     "nEncoding",        "nCharStrings",         "PPrivate",         "nSubrs",
     156             :     "nDefaultWidthX",   "nNominalWidthX",       NULL,               NULL,
     157             :     NULL,               NULL,                   NULL,               NULL,
     158             :     "shortint",         "longint",              "BCD",              NULL
     159             : };
     160             : 
     161             : // --------------------------------------------------------------------
     162             : 
     163             : // TOP DICT escapes (also covers PRIV DICT escapes)
     164             : static const char* pDictEscs[] = {
     165             :     "sCopyright",           "bIsFixedPitch",    "nItalicAngle",     "nUnderlinePosition",
     166             :     "nUnderlineThickness",  "nPaintType",       "tCharstringType",  "aFontMatrix",
     167             :     "nStrokeWidth",         "nBlueScale",       "nBlueShift",       "nBlueFuzz",
     168             :     "dStemSnapH",           "dStemSnapV",       "bForceBold",       NULL,
     169             :     NULL,                   "nLanguageGroup",   "nExpansionFactor", "nInitialRandomSeed",
     170             :     "nSyntheticBase",       "sPostScript",      "sBaseFontName",    "dBaseFontBlend",
     171             :     NULL,                   NULL,               NULL,               NULL,
     172             :     NULL,                   NULL,               "rROS",             "nCIDFontVersion",
     173             :     "nCIDFontRevision",     "nCIDFontType",     "nCIDCount",        "nUIDBase",
     174             :     "nFDArray",             "nFDSelect",        "sFontName"
     175             : };
     176             : 
     177             : // --------------------------------------------------------------------
     178             : 
     179             : static const char* pType1Ops[] = {
     180             :     NULL,               "2hstem",           NULL,               "2vstem",
     181             :     "1vmoveto",         "Arlineto",         "1hlineto",         "1vlineto",
     182             :     "Crrcurveto",       "0closepath",       "Lcallsubr",        "0return",
     183             :     "xT1ESC",           "2hsbw",            "0endchar",         NULL,
     184             :     NULL,               NULL,               NULL,               NULL,
     185             :     NULL,               "2rmoveto",         "1hmoveto",         NULL,
     186             :     NULL,               NULL,               NULL,               NULL,
     187             :     NULL,               NULL,               "4vhcurveto",       "4hvcurveto"
     188             : };
     189             : 
     190             : // --------------------------------------------------------------------
     191             : 
     192             : static const char* pT1EscOps[] = {
     193             :     "0dotsection",      "6vstem3",          "6hstem3",          NULL,
     194             :     NULL,               NULL,               "5seac",            "4sbw",
     195             :     NULL,               "1abs",             "2add",             "2sub",
     196             :     "2div",             NULL,               NULL,               NULL,
     197             :     "Gcallothersubr",   "1pop",             NULL,               NULL,
     198             :     NULL,               NULL,               NULL,               NULL,
     199             :     NULL,               NULL,               NULL,               NULL,
     200             :     NULL,               NULL,               NULL,               NULL,
     201             :     NULL,               "2setcurrentpoint"
     202             : };
     203             : 
     204             : // --------------------------------------------------------------------
     205             : 
     206             : struct TYPE1OP
     207             : {
     208             :     enum OPS
     209             :     {
     210             :         HSTEM=1,        VSTEM=3,        VMOVETO=4,      RLINETO=5,
     211             :         HLINETO=6,      VLINETO=7,      RCURVETO=8,     CLOSEPATH=9,
     212             :         CALLSUBR=10,    RETURN=11,      T1ESC=12,       HSBW=13,
     213             :         ENDCHAR=14,     RMOVETO=21,     HMOVETO=22,     VHCURVETO=30,
     214             :         HVCURVETO=31
     215             :     };
     216             : 
     217             :     enum ESCS
     218             :     {
     219             :         DOTSECTION=0,   VSTEM3=1,           HSTEM3=2,   SEAC=6,
     220             :         SBW=7,          ABS=9,              ADD=10,     SUB=11,
     221             :         DIV=12,         CALLOTHERSUBR=16,   POP=17,     SETCURRENTPOINT=33
     222             :     };
     223             : };
     224             : 
     225             : // --------------------------------------------------------------------
     226             : 
     227             : static const char* pType2Ops[] = {
     228             :     NULL,           "hhstem",       NULL,           "vvstem",
     229             :     "mvmoveto",     "Arlineto",     "Ehlineto",     "Evlineto",
     230             :     "Crrcurveto",   NULL,           "Lcallsubr",    "Xreturn",
     231             :     "xT2ESC",       NULL,           "eendchar",     NULL,
     232             :     NULL,           NULL,           "Hhstemhm",     "Khintmask",
     233             :     "Kcntrmask",    "Mrmoveto",     "mhmoveto",     "Vvstemhm",
     234             :     ".rcurveline",  ".rlinecurve",  ".vvcurveto",   ".hhcurveto",
     235             :     ".shortint",    "Gcallgsubr",   ".vhcurveto",   ".hvcurveto"
     236             : };
     237             : 
     238             : // --------------------------------------------------------------------
     239             : 
     240             : static const char* pT2EscOps[] = {
     241             :     NULL,       NULL,       NULL,       "2and",
     242             :     "2or",      "1not",     NULL,       NULL,
     243             :     NULL,       "1abs",     "2add",     "2sub",
     244             :     "2div",     NULL,       "1neg",     "2eq",
     245             :     NULL,       NULL,       "1drop",    NULL,
     246             :     "1put",     "1get",     "4ifelse",  "0random",
     247             :     "2mul",     NULL,       "1sqrt",    "1dup",
     248             :     "2exch",    "Iindex",   "Rroll",    NULL,
     249             :     NULL,       NULL,       "7hflex",   "Fflex",
     250             :     "9hflex1",  "fflex1"
     251             : };
     252             : 
     253             : // --------------------------------------------------------------------
     254             : 
     255             : struct TYPE2OP
     256             : {
     257             :     enum OPS
     258             :     {
     259             :         HSTEM=1,        VSTEM=3,        VMOVETO=4,      RLINETO=5,
     260             :         HLINETO=6,      VLINETO=7,      RCURVETO=8,     CALLSUBR=10,
     261             :         RETURN=11,      T2ESC=12,       ENDCHAR=14,     HSTEMHM=18,
     262             :         HINTMASK=19,    CNTRMASK=20,    RMOVETO=21,     HMOVETO=22,
     263             :         VSTEMHM=23,     RCURVELINE=24,  RLINECURVE=25,  VVCURVETO=26,
     264             :         HHCURVETO=27,   SHORTINT=28,    CALLGSUBR=29,   VHCURVETO=30,
     265             :         HVCURVETO=31
     266             :     };
     267             : 
     268             :     enum ESCS
     269             :     {
     270             :         AND=3,      OR=4,       NOT=5,      ABS=9,
     271             :         ADD=10,     SUB=11,     DIV=12,     NEG=14,
     272             :         EQ=15,      DROP=18,    PUT=20,     GET=21,
     273             :         IFELSE=22,  RANDOM=23,  MUL=24,     SQRT=26,
     274             :         DUP=27,     EXCH=28,    INDEX=29,   ROLL=30,
     275             :         HFLEX=34,   FLEX=35,    HFLEX1=36,  FLEX1=37
     276             :     };
     277             : };
     278             : 
     279             : // ====================================================================
     280             : 
     281           0 : struct CffGlobal
     282             : {
     283             :     explicit CffGlobal();
     284             : 
     285             :     int     mnNameIdxBase;
     286             :     int     mnNameIdxCount;
     287             :     int     mnStringIdxBase;
     288             :     int     mnStringIdxCount;
     289             :     bool    mbCIDFont;
     290             :     int     mnCharStrBase;
     291             :     int     mnCharStrCount;
     292             :     int     mnEncodingBase;
     293             :     int     mnCharsetBase;
     294             :     int     mnGlobalSubrBase;
     295             :     int     mnGlobalSubrCount;
     296             :     int     mnGlobalSubrBias;
     297             :     int     mnFDSelectBase;
     298             :     int     mnFontDictBase;
     299             :     int     mnFDAryCount;
     300             : 
     301             :     ValVector   maFontBBox;
     302             :     ValVector   maFontMatrix;
     303             : 
     304             :     int     mnFontNameSID;
     305             :     int     mnFullNameSID;
     306             :     int     mnFamilyNameSID;
     307             : };
     308             : 
     309             : // ====================================================================
     310             : 
     311           0 : struct CffLocal
     312             : {
     313             :     explicit CffLocal();
     314             : 
     315             :     int     mnPrivDictBase;
     316             :     int     mnPrivDictSize;
     317             :     int     mnLocalSubrOffs;
     318             :     int     mnLocalSubrBase;
     319             :     int     mnLocalSubrCount;
     320             :     int     mnLocalSubrBias;
     321             : 
     322             :     ValType maNominalWidth;
     323             :     ValType maDefaultWidth;
     324             : 
     325             :     // ATM hinting related values
     326             :     ValType     maStemStdHW;
     327             :     ValType     maStemStdVW;
     328             :     ValVector   maStemSnapH;
     329             :     ValVector   maStemSnapV;
     330             :     ValVector   maBlueValues;
     331             :     ValVector   maOtherBlues;
     332             :     ValVector   maFamilyBlues;
     333             :     ValVector   maFamilyOtherBlues;
     334             :     RealType    mfBlueScale;
     335             :     RealType    mfBlueShift;
     336             :     RealType    mfBlueFuzz;
     337             :     RealType    mfExpFactor;
     338             :     int         mnLangGroup;
     339             :     bool        mbForceBold;
     340             : };
     341             : 
     342             : // ====================================================================
     343             : 
     344           0 : class SubsetterContext
     345             : {
     346             : public:
     347             :     virtual ~SubsetterContext( void);
     348             :     virtual bool emitAsType1( class Type1Emitter&,
     349             :                 const long* pGlyphIDs, const U8* pEncoding,
     350             :                 GlyphWidth* pGlyphWidths, int nGlyphCount, FontSubsetInfo& ) = 0;
     351             : };
     352             : 
     353             : // --------------------------------------------------------------------
     354             : 
     355           0 : SubsetterContext::~SubsetterContext( void)
     356           0 : {}
     357             : 
     358             : // ====================================================================
     359             : 
     360             : class CffSubsetterContext
     361             : :   public SubsetterContext
     362             : ,   private CffGlobal
     363             : {
     364             : public:
     365             :     static const int NMAXSTACK = 48;    // see CFF.appendixB
     366             :     static const int NMAXHINTS = 2*96;  // see CFF.appendixB
     367             :     static const int NMAXTRANS = 32;    // see CFF.appendixB
     368             : public:
     369             :     explicit CffSubsetterContext( const U8* pBasePtr, int nBaseLen);
     370             :     virtual ~CffSubsetterContext( void);
     371             : 
     372             :     void    initialCffRead( void);
     373             :     bool    emitAsType1( class Type1Emitter&,
     374             :                 const long* pGlyphIDs, const U8* pEncoding,
     375             :                 GlyphWidth* pGlyphWidths, int nGlyphCount, FontSubsetInfo& );
     376             : 
     377             :     // used by charstring converter
     378             :     void    setCharStringType( int);
     379             :     void    fakeLocalSubrCount( int nLocalSubrs ) { maCffLocal[0].mnLocalSubrCount=nLocalSubrs;}
     380             : protected:
     381             :     int     convert2Type1Ops( CffLocal*, const U8* pType2Ops, int nType2Len, U8* pType1Ops);
     382             : private:
     383             :     void    convertOneTypeOp( void);
     384             :     void    convertOneTypeEsc( void);
     385             :     void    callType2Subr( bool bGlobal, int nSubrNumber);
     386           0 :     long    getReadOfs( void) const { return (long)(mpReadPtr - mpBasePtr);}
     387             : 
     388             :     const U8* mpBasePtr;
     389             :     const U8* mpBaseEnd;
     390             : 
     391             :     const U8* mpReadPtr;
     392             :     const U8* mpReadEnd;
     393             : 
     394             :     U8*     mpWritePtr;
     395             :     bool    mbSawError;
     396             :     bool    mbNeedClose;
     397             :     bool    mbIgnoreHints;
     398             :     long    mnCntrMask;
     399             : 
     400             : private:
     401             :     int     seekIndexData( int nIndexBase, int nDataIndex);
     402             :     void    seekIndexEnd( int nIndexBase);
     403             : 
     404             : private:
     405             :     const char**    mpCharStringOps;
     406             :     const char**    mpCharStringEscs;
     407             : 
     408             :     CffLocal    maCffLocal[16];
     409             :     CffLocal*   mpCffLocal;
     410             : 
     411             :     void        readDictOp( void);
     412             :     RealType    readRealVal( void);
     413             :     const char* getString( int nStringID);
     414             :     int         getFDSelect( int nGlyphIndex) const;
     415             :     int         getGlyphSID( int nGlyphIndex) const;
     416             :     const char* getGlyphName( int nGlyphIndex);
     417             : 
     418             :     void    read2push( void);
     419             :     void    pop2write( void);
     420             :     void    writeType1Val( ValType);
     421             :     void    writeTypeOp( int nTypeOp);
     422             :     void    writeTypeEsc( int nTypeOp);
     423             :     void    writeCurveTo( int nStackPos, int nIX1, int nIY1, int nIX2, int nIY2, int nIX3, int nIY3);
     424             :     void    pop2MultiWrite( int nArgsPerTypo, int nTypeOp, int nTypeXor=0);
     425             :     void    popAll2Write( int nTypeOp);
     426             : 
     427             : public: // TODO: is public really needed?
     428             :     // accessing the value stack
     429             :     // TODO: add more checks
     430           0 :     void    push( ValType nVal) { mnValStack[ mnStackIdx++] = nVal;}
     431           0 :     ValType popVal( void) { return ((mnStackIdx>0) ? mnValStack[ --mnStackIdx] : 0);}
     432             :     ValType peekVal( void) const { return ((mnStackIdx>0) ? mnValStack[ mnStackIdx-1] : 0);}
     433           0 :     ValType getVal( int nIndex) const { return mnValStack[ nIndex];}
     434             :     int     popInt( void);
     435             :     int     peekInt( void) const;
     436             :     int     getInt( int nIndex) const;
     437           0 :     int     size( void) const { return mnStackIdx;}
     438             :     bool    empty( void) const { return !mnStackIdx;}
     439           0 :     void    clear( void) { mnStackIdx = 0;}
     440             : 
     441             :     // accessing the charstring hints
     442             :     void    addHints( bool bVerticalHints);
     443             :     int     getHorzHintCount( void) const { return (mnHorzHintSize/2);}
     444             :     int     getVertHintCount( void) const { return (mnHintSize-mnHorzHintSize)/2;}
     445             : 
     446             :     // accessing other charstring specifics
     447           0 :     bool    hasCharWidth( void) const { return (maCharWidth > 0);}
     448           0 :     ValType getCharWidth( void) const { return maCharWidth;}
     449           0 :     void    setNominalWidth( ValType aWidth) { mpCffLocal->maNominalWidth = aWidth;}
     450           0 :     void    setDefaultWidth( ValType aWidth) { mpCffLocal->maDefaultWidth = aWidth;}
     451             :     void    updateWidth( bool bUseFirstVal);
     452             : 
     453             : private:
     454             :     // typeop exceution context
     455             :     int mnStackIdx;
     456             :     ValType mnValStack[ NMAXSTACK+4];
     457             :     ValType mnTransVals[ NMAXTRANS];
     458             : 
     459             :     int mnHintSize;
     460             :     int mnHorzHintSize;
     461             :     ValType mnHintStack[ NMAXHINTS];
     462             : 
     463             :     ValType maCharWidth;
     464             : };
     465             : 
     466             : // --------------------------------------------------------------------
     467             : 
     468           0 : CffSubsetterContext::CffSubsetterContext( const U8* pBasePtr, int nBaseLen)
     469             : :   mpBasePtr( pBasePtr)
     470           0 : ,   mpBaseEnd( pBasePtr+nBaseLen)
     471             : ,   mnStackIdx(0)
     472             : ,   mnHintSize(0)
     473             : ,   mnHorzHintSize(0)
     474           0 : ,   maCharWidth(-1)
     475             : {
     476             : //  setCharStringType( 1);
     477             :     // TODO: new CffLocal[ mnFDAryCount];
     478           0 :     mpCffLocal = &maCffLocal[0];
     479           0 : }
     480             : 
     481             : // --------------------------------------------------------------------
     482             : 
     483           0 : CffSubsetterContext::~CffSubsetterContext( void)
     484             : {
     485             :     // TODO: delete[] maCffLocal;
     486           0 : }
     487             : 
     488             : // --------------------------------------------------------------------
     489             : 
     490           0 : inline int CffSubsetterContext::popInt( void)
     491             : {
     492           0 :     const ValType aVal = popVal();
     493           0 :     const int nInt = static_cast<int>(aVal);
     494             :     assert( nInt == aVal);
     495           0 :     return nInt;
     496             : }
     497             : 
     498             : // --------------------------------------------------------------------
     499             : 
     500             : inline int CffSubsetterContext::peekInt( void) const
     501             : {
     502             :     const ValType aVal = peekVal();
     503             :     const int nInt = static_cast<int>(aVal);
     504             :     assert( nInt == aVal);
     505             :     return nInt;
     506             : }
     507             : 
     508             : // --------------------------------------------------------------------
     509             : 
     510             : inline int CffSubsetterContext::getInt( int nIndex) const
     511             : {
     512             :     const ValType aVal = getVal( nIndex);
     513             :     const int nInt = static_cast<int>(aVal);
     514             :     assert( nInt == aVal);
     515             :     return nInt;
     516             : }
     517             : 
     518             : // --------------------------------------------------------------------
     519             : 
     520           0 : inline void CffSubsetterContext::updateWidth( bool bUseFirstVal)
     521             : {
     522             : #if 1 // TODO: is this still needed?
     523             :     // the first value is not a hint but the charwidth
     524           0 :     if( hasCharWidth())
     525           0 :         return;
     526             : #endif
     527           0 :     if( bUseFirstVal) {
     528           0 :         maCharWidth = mpCffLocal->maNominalWidth + mnValStack[0];
     529             :         // remove bottom stack entry
     530           0 :         --mnStackIdx;
     531           0 :         for( int i = 0; i < mnStackIdx; ++i)
     532           0 :             mnValStack[ i] = mnValStack[ i+1];
     533             :     } else {
     534           0 :         maCharWidth = mpCffLocal->maDefaultWidth;
     535             :     }
     536             : }
     537             : 
     538             : // --------------------------------------------------------------------
     539             : 
     540           0 : void CffSubsetterContext::addHints( bool bVerticalHints)
     541             : {
     542             :     // the first charstring value may a charwidth instead of a charwidth
     543           0 :     updateWidth( (mnStackIdx & 1) != 0);
     544             :     // return early (e.g. no implicit hints for hintmask)
     545           0 :     if( !mnStackIdx)
     546           0 :         return;
     547             : 
     548             :     // copy the remaining values to the hint arrays
     549             :     // assert( (mnStackIdx & 1) == 0); // depends on called subrs
     550           0 :     if( mnStackIdx & 1) --mnStackIdx;//#######
     551             :     // TODO: if( !bSubr) assert( mnStackIdx >= 2);
     552             : 
     553             :     assert( (mnHintSize + mnStackIdx) <= 2*NMAXHINTS);
     554             : 
     555             : #ifdef IGNORE_HINTS
     556             :     mnHintSize += mnStackIdx;
     557             : #else
     558           0 :     ValType nHintOfs = 0;
     559           0 :     for( int i = 0; i < mnStackIdx; ++i) {
     560           0 :         nHintOfs += mnValStack[ i ];
     561           0 :         mnHintStack[ mnHintSize++] = nHintOfs;
     562             :     }
     563             : #endif // IGNORE_HINTS
     564           0 :     if( !bVerticalHints)
     565           0 :         mnHorzHintSize = mnHintSize;
     566             : 
     567             :     // clear all values from the stack
     568           0 :     mnStackIdx = 0;
     569             : }
     570             : 
     571             : // --------------------------------------------------------------------
     572             : 
     573           0 : void CffSubsetterContext::setCharStringType( int nVal)
     574             : {
     575           0 :     switch( nVal) {
     576           0 :         case 1: mpCharStringOps=pType1Ops; mpCharStringEscs=pT1EscOps; break;
     577           0 :         case 2: mpCharStringOps=pType2Ops; mpCharStringEscs=pT2EscOps; break;
     578           0 :         default: fprintf( stderr, "Unknown CharstringType=%d\n",nVal); break;
     579             :     }
     580           0 : }
     581             : 
     582             : // --------------------------------------------------------------------
     583             : 
     584           0 : void CffSubsetterContext::readDictOp( void)
     585             : {
     586           0 :     ValType nVal = 0;
     587           0 :     const U8 c = *mpReadPtr;
     588           0 :     if( c <= 21 ) {
     589           0 :         int nOpId = *(mpReadPtr++);
     590           0 :         const char* pCmdName = 0;
     591           0 :         if( nOpId != 12)
     592           0 :             pCmdName = pDictOps[nOpId];
     593             :         else {
     594           0 :             const U8 nExtId = *(mpReadPtr++);
     595           0 :             if (nExtId < 39)
     596           0 :                pCmdName = pDictEscs[nExtId];
     597           0 :             nOpId = 900 + nExtId;
     598             :         }
     599             : 
     600           0 :         if (!pCmdName)  // skip reserved operators
     601             :             return;
     602             : 
     603             :         //TODO: if( nStackIdx > 0)
     604           0 :         int nInt = 0;
     605           0 :         switch( *pCmdName) {
     606           0 :         default: fprintf( stderr, "unsupported DictOp.type=\'%c\'\n", *pCmdName); break;
     607             :         case 'b':   // bool
     608           0 :             nInt = popInt();
     609           0 :             switch( nOpId) {
     610           0 :             case 915: mpCffLocal->mbForceBold = nInt; break;    // "ForceBold"
     611           0 :             default: break; // TODO: handle more boolean dictops?
     612             :             }
     613           0 :             break;
     614             :         case 'n':   // dict-op number
     615           0 :             nVal = popVal();
     616           0 :             nInt = static_cast<int>(nVal);
     617           0 :             switch( nOpId) {
     618           0 :             case  10: mpCffLocal->maStemStdHW = nVal; break;    // "StdHW"
     619           0 :             case  11: mpCffLocal->maStemStdVW = nVal; break;    // "StdVW"
     620           0 :             case  15: mnCharsetBase = nInt; break;              // "charset"
     621           0 :             case  16: mnEncodingBase = nInt; break;             // "nEncoding"
     622           0 :             case  17: mnCharStrBase = nInt; break;              // "nCharStrings"
     623           0 :             case  19: mpCffLocal->mnLocalSubrOffs = nInt; break;// "nSubrs"
     624           0 :             case  20: setDefaultWidth( nVal ); break;           // "defaultWidthX"
     625           0 :             case  21: setNominalWidth( nVal ); break;           // "nominalWidthX"
     626           0 :             case 909: mpCffLocal->mfBlueScale = nVal; break;    // "BlueScale"
     627           0 :             case 910: mpCffLocal->mfBlueShift = nVal; break;    // "BlueShift"
     628           0 :             case 911: mpCffLocal->mfBlueFuzz = nVal; break;     // "BlueFuzz"
     629           0 :             case 912: mpCffLocal->mfExpFactor = nVal; break;    // "ExpansionFactor"
     630           0 :             case 917: mpCffLocal->mnLangGroup = nInt; break;    // "LanguageGroup"
     631           0 :             case 936: mnFontDictBase = nInt; break;             // "nFDArray"
     632           0 :             case 937: mnFDSelectBase = nInt; break;             // "nFDSelect"
     633           0 :             default: break; // TODO: handle more numeric dictops?
     634             :             }
     635           0 :             break;
     636             :         case 'a': { // array
     637           0 :             switch( nOpId) {
     638           0 :             case   5: maFontBBox.clear(); break;     // "FontBBox"
     639           0 :             case 907: maFontMatrix.clear(); break; // "FontMatrix"
     640           0 :             default: break; // TODO: reset other arrays?
     641             :             }
     642           0 :             for( int i = 0; i < size(); ++i ) {
     643           0 :                 nVal = getVal(i);
     644           0 :                 switch( nOpId) {
     645           0 :                 case   5: maFontBBox.push_back( nVal); break;     // "FontBBox"
     646           0 :                 case 907: maFontMatrix.push_back( nVal); break; // "FontMatrix"
     647           0 :                 default: break; // TODO: handle more array dictops?
     648             :                 }
     649             :             }
     650           0 :             clear();
     651           0 :             } break;
     652             :         case 'd': { // delta array
     653           0 :             nVal = 0;
     654           0 :             for( int i = 0; i < size(); ++i ) {
     655           0 :                 nVal += getVal(i);
     656           0 :                 switch( nOpId) {
     657           0 :                 case   6: mpCffLocal->maBlueValues.push_back( nVal); break;     // "BlueValues"
     658           0 :                 case   7: mpCffLocal->maOtherBlues.push_back( nVal); break;     // "OtherBlues"
     659           0 :                 case   8: mpCffLocal->maFamilyBlues.push_back( nVal); break;    // "FamilyBlues"
     660           0 :                 case   9: mpCffLocal->maFamilyOtherBlues.push_back( nVal); break;// "FamilyOtherBlues"
     661           0 :                 case 912: mpCffLocal->maStemSnapH.push_back( nVal); break;      // "StemSnapH"
     662           0 :                 case 913: mpCffLocal->maStemSnapV.push_back( nVal); break;      // "StemSnapV"
     663           0 :                 default: break; // TODO: handle more delta-array dictops?
     664             :                 }
     665             :             }
     666           0 :             clear();
     667           0 :             } break;
     668             :         case 's':   // stringid (SID)
     669           0 :             nInt = popInt();
     670           0 :             switch( nOpId ) {
     671           0 :             case   2: mnFullNameSID = nInt; break;      // "FullName"
     672           0 :             case   3: mnFamilyNameSID = nInt; break;    // "FamilyName"
     673           0 :             case 938: mnFontNameSID = nInt; break;      // "FontName"
     674           0 :             default: break; // TODO: handle more string dictops?
     675             :             }
     676           0 :             break;
     677             :         case 'P':   // private dict
     678           0 :             mpCffLocal->mnPrivDictBase = popInt();
     679           0 :             mpCffLocal->mnPrivDictSize = popInt();
     680           0 :             break;
     681             :         case 'r': { // ROS operands
     682           0 :             int nSid1 = popInt();
     683           0 :             int nSid2 = popInt();
     684             :             (void)nSid1; // TODO: use
     685             :             (void)nSid2; // TODO: use
     686           0 :             nVal = popVal();
     687           0 :             mbCIDFont = true;
     688           0 :             } break;
     689             :         case 't':   // CharstringType
     690           0 :             nInt = popInt();
     691           0 :             setCharStringType( nInt );
     692           0 :             break;
     693             :         }
     694             : 
     695             :         return;
     696             :     }
     697             : 
     698           0 :     if( (c >= 32) || (c == 28) ) {
     699             : //      --mpReadPtr;
     700           0 :         read2push();
     701           0 :     } else if( c == 29 ) {      // longint
     702           0 :         ++mpReadPtr;            // skip 29
     703           0 :         int nS32 = mpReadPtr[0] << 24;
     704           0 :         nS32 += mpReadPtr[1] << 16;
     705           0 :         nS32 += mpReadPtr[2] << 8;
     706           0 :         nS32 += mpReadPtr[3] << 0;
     707             :         if( (sizeof(nS32) != 4) && (nS32 & (1<<31)))
     708             :             nS32 |= (~0U) << 31;    // assuming 2s complement
     709           0 :         mpReadPtr += 4;
     710           0 :         nVal = static_cast<ValType>(nS32);
     711           0 :         push( nVal );
     712           0 :     } else if( c == 30) {       // real number
     713           0 :         ++mpReadPtr; // skip 30
     714           0 :         const RealType fReal = readRealVal();
     715             :         // push value onto stack
     716           0 :         nVal = fReal;
     717           0 :         push( nVal);
     718             :     }
     719             : }
     720             : 
     721             : // --------------------------------------------------------------------
     722             : 
     723           0 : void CffSubsetterContext::read2push()
     724             : {
     725           0 :     ValType aVal = 0;
     726             : 
     727           0 :     const U8*& p = mpReadPtr;
     728           0 :     const U8 c = *p;
     729           0 :     if( c == 28 ) {
     730           0 :         short nS16 = (p[1] << 8) + p[2];
     731             :         if( (sizeof(nS16) != 2) && (nS16 & (1<<15)))
     732             :             nS16 |= (~0U) << 15;    // assuming 2s complement
     733           0 :         aVal = nS16;
     734           0 :         p += 3;
     735           0 :     } else if( c <= 246 ) {     // -107..+107
     736           0 :         aVal = static_cast<ValType>(p[0] - 139);
     737           0 :         p += 1;
     738           0 :     } else if( c <= 250 ) {     // +108..+1131
     739           0 :         aVal = static_cast<ValType>(((p[0] << 8) + p[1]) - 63124);
     740           0 :         p += 2;
     741           0 :     } else if( c <= 254 ) {     // -108..-1131
     742           0 :         aVal = static_cast<ValType>(64148 - ((p[0] << 8) + p[1]));
     743           0 :         p += 2;
     744             :     } else /*if( c == 255)*/ {  // Fixed16.16
     745           0 :         int nS32 = (p[1] << 24) + (p[2] << 16) + (p[3] << 8) + p[4];
     746           0 :         if( (sizeof(nS32) != 2) && (nS32 & (1<<31)))
     747           0 :             nS32 |= (~0U) << 31;    // assuming 2s complement
     748           0 :         aVal = static_cast<ValType>(nS32 * (1.0 / 0x10000));
     749           0 :         p += 5;
     750             :     }
     751             : 
     752           0 :     push( aVal);
     753           0 : }
     754             : 
     755             : // --------------------------------------------------------------------
     756             : 
     757           0 : void CffSubsetterContext::writeType1Val( ValType aVal)
     758             : {
     759           0 :     U8* pOut = mpWritePtr;
     760             : 
     761           0 :     int nInt = static_cast<int>(aVal);
     762             :     static const int nOutCharstrType = 1;
     763             :     if( (nInt != aVal) && (nOutCharstrType == 2)) {
     764             :         // numtype==255 means int32 for Type1, but 16.16 for Type2 charstrings!!!
     765             :         *(pOut++) = 255;                            // Fixed 16.16
     766             :         *(pOut++) = static_cast<U8>(nInt >> 8);
     767             :         *(pOut++) = static_cast<U8>(nInt);
     768             :         nInt = static_cast<int>(aVal * 0x10000) & 0xFFFF;
     769             :         *(pOut++) = static_cast<U8>(nInt >> 8);
     770             :         *(pOut++) = static_cast<U8>(nInt);
     771           0 :     } else if( (nInt >= -107) && (nInt <= +107)) {
     772           0 :         *(pOut++) = static_cast<U8>(nInt + 139);    // -107..+107
     773           0 :     } else if( (nInt >= -1131) && (nInt <= +1131)) {
     774           0 :         if( nInt >= 0)
     775           0 :             nInt += 63124;                          // +108..+1131
     776             :         else
     777           0 :             nInt = 64148 - nInt;                    // -108..-1131
     778           0 :         *(pOut++) = static_cast<U8>(nInt >> 8);
     779           0 :         *(pOut++) = static_cast<U8>(nInt);
     780             :     } else if( nOutCharstrType == 1) {
     781             :         // numtype==255 means int32 for Type1, but 16.16 for Type2 charstrings!!!
     782           0 :         *(pOut++) = 255;
     783           0 :         *(pOut++) = static_cast<U8>(nInt >> 24);
     784           0 :         *(pOut++) = static_cast<U8>(nInt >> 16);
     785           0 :         *(pOut++) = static_cast<U8>(nInt >> 8);
     786           0 :         *(pOut++) = static_cast<U8>(nInt);
     787             :     }
     788             : 
     789           0 :     mpWritePtr = pOut;
     790           0 : }
     791             : 
     792             : // --------------------------------------------------------------------
     793             : 
     794             : inline void CffSubsetterContext::pop2write( void)
     795             : {
     796             :     const ValType aVal = popVal();
     797             :     writeType1Val( aVal);
     798             : }
     799             : 
     800             : // --------------------------------------------------------------------
     801             : 
     802           0 : inline void CffSubsetterContext::writeTypeOp( int nTypeOp)
     803             : {
     804           0 :     *(mpWritePtr++) = static_cast<U8>(nTypeOp);
     805           0 : }
     806             : 
     807             : // --------------------------------------------------------------------
     808             : 
     809           0 : inline void CffSubsetterContext::writeTypeEsc( int nTypeEsc)
     810             : {
     811           0 :     *(mpWritePtr++) = TYPE1OP::T1ESC;
     812           0 :     *(mpWritePtr++) = static_cast<U8>(nTypeEsc);
     813           0 : }
     814             : 
     815             : // --------------------------------------------------------------------
     816             : 
     817           0 : void CffSubsetterContext::pop2MultiWrite( int nArgsPerTypo, int nTypeOp, int nTypeXor)
     818             : {
     819           0 :     for( int i = 0; i < mnStackIdx;) {
     820           0 :         for( int j = 0; j < nArgsPerTypo; ++j) {
     821           0 :             const ValType aVal = mnValStack[i+j];
     822           0 :             writeType1Val( aVal);
     823             :         }
     824           0 :         i += nArgsPerTypo;
     825           0 :         writeTypeOp( nTypeOp);
     826           0 :         nTypeOp ^= nTypeXor;    // for toggling vlineto/hlineto
     827             :     }
     828           0 :     clear();
     829           0 : }
     830             : 
     831             : // --------------------------------------------------------------------
     832             : 
     833           0 : void CffSubsetterContext::popAll2Write( int nTypeOp)
     834             : {
     835             :     // pop in reverse order, then write
     836           0 :     for( int i = 0; i < mnStackIdx; ++i) {
     837           0 :         const ValType aVal = mnValStack[i];
     838           0 :         writeType1Val( aVal);
     839             :     }
     840           0 :     clear();
     841           0 :     writeTypeOp( nTypeOp);
     842           0 : }
     843             : 
     844             : // --------------------------------------------------------------------
     845             : 
     846           0 : void CffSubsetterContext::writeCurveTo( int nStackPos,
     847             :     int nIX1, int nIY1, int nIX2, int nIY2, int nIX3, int nIY3)
     848             : {
     849             :     // get the values from the stack
     850           0 :     const ValType nDX1 = nIX1 ? mnValStack[ nStackPos+nIX1 ] : 0;
     851           0 :     const ValType nDY1 = nIY1 ? mnValStack[ nStackPos+nIY1 ] : 0;
     852           0 :     const ValType nDX2 = nIX2 ? mnValStack[ nStackPos+nIX2 ] : 0;
     853           0 :     const ValType nDY2 = nIY2 ? mnValStack[ nStackPos+nIY2 ] : 0;
     854           0 :     const ValType nDX3 = nIX3 ? mnValStack[ nStackPos+nIX3 ] : 0;
     855           0 :     const ValType nDY3 = nIY3 ? mnValStack[ nStackPos+nIY3 ] : 0;
     856             : 
     857             :     // emit the curveto operator and operands
     858             :     // TODO: determine the most efficient curveto operator
     859             :     // TODO: depending on type1op or type2op target
     860           0 :     writeType1Val( nDX1 );
     861           0 :     writeType1Val( nDY1 );
     862           0 :     writeType1Val( nDX2 );
     863           0 :     writeType1Val( nDY2 );
     864           0 :     writeType1Val( nDX3 );
     865           0 :     writeType1Val( nDY3 );
     866           0 :     writeTypeOp( TYPE1OP::RCURVETO );
     867           0 : }
     868             : 
     869             : // --------------------------------------------------------------------
     870             : 
     871           0 : void CffSubsetterContext::convertOneTypeOp( void)
     872             : {
     873           0 :     const int nType2Op = *(mpReadPtr++);
     874             : 
     875             :     int i, nInt; // prevent WAE for declarations inside switch cases
     876             :     // convert each T2op
     877           0 :     switch( nType2Op) {
     878             :     case TYPE2OP::T2ESC:
     879           0 :         convertOneTypeEsc();
     880           0 :         break;
     881             :     case TYPE2OP::HSTEM:
     882             :     case TYPE2OP::VSTEM:
     883           0 :         addHints( nType2Op == TYPE2OP::VSTEM );
     884             : #ifndef IGNORE_HINTS
     885           0 :         for( i = 0; i < mnHintSize; i+=2 ) {
     886           0 :             writeType1Val( mnHintStack[i]);
     887           0 :             writeType1Val( mnHintStack[i+1] - mnHintStack[i]);
     888           0 :             writeTypeOp( nType2Op );
     889             :         }
     890             : #endif // IGNORE_HINTS
     891           0 :         break;
     892             :     case TYPE2OP::HSTEMHM:
     893             :     case TYPE2OP::VSTEMHM:
     894           0 :         addHints( nType2Op == TYPE2OP::VSTEMHM);
     895           0 :         break;
     896             :     case TYPE2OP::CNTRMASK:
     897             :         // TODO: replace cntrmask with vstem3/hstem3
     898           0 :         addHints( true);
     899             : #ifdef IGNORE_HINTS
     900             :         mpReadPtr += (mnHintSize + 15) / 16;
     901             :         mbIgnoreHints = true;
     902             : #else
     903             :         {
     904           0 :         U8 nMaskBit = 0;
     905           0 :         U8 nMaskByte = 0;
     906           0 :         for( i = 0; i < mnHintSize; i+=2, nMaskBit>>=1) {
     907           0 :             if( !nMaskBit) {
     908           0 :                 nMaskByte = *(mpReadPtr++);
     909           0 :                 nMaskBit = 0x80;
     910             :             }
     911           0 :             if( !(nMaskByte & nMaskBit))
     912           0 :                 continue;
     913           0 :             if( i >= 8*(int)sizeof(mnCntrMask))
     914           0 :                 mbIgnoreHints = true;
     915           0 :             if( mbIgnoreHints)
     916           0 :                 continue;
     917           0 :             mnCntrMask |= (1U << i);
     918             :         }
     919             :         }
     920             : #endif
     921           0 :         break;
     922             :     case TYPE2OP::HINTMASK:
     923           0 :         addHints( true);
     924             : #ifdef IGNORE_HINTS
     925             :         mpReadPtr += (mnHintSize + 15) / 16;
     926             : #else
     927             :         {
     928           0 :         long nHintMask = 0;
     929           0 :         int nCntrBits[2] = {0,0};
     930           0 :         U8 nMaskBit = 0;
     931           0 :         U8 nMaskByte = 0;
     932           0 :         for( i = 0; i < mnHintSize; i+=2, nMaskBit>>=1) {
     933           0 :             if( !nMaskBit) {
     934           0 :                 nMaskByte = *(mpReadPtr++);
     935           0 :                 nMaskBit = 0x80;
     936             :             }
     937           0 :             if( !(nMaskByte & nMaskBit))
     938           0 :                 continue;
     939           0 :             if( i >= 8*(int)sizeof(nHintMask))
     940           0 :                 mbIgnoreHints = true;
     941           0 :             if( mbIgnoreHints)
     942           0 :                 continue;
     943           0 :             nHintMask |= (1U << i);
     944           0 :             nCntrBits[ i < mnHorzHintSize] += (mnCntrMask >> i) & 1;
     945             :         }
     946             : 
     947           0 :         mbIgnoreHints |= (nCntrBits[0] && (nCntrBits[0] != 3));
     948           0 :         mbIgnoreHints |= (nCntrBits[1] && (nCntrBits[1] != 3));
     949           0 :         if( mbIgnoreHints)
     950             :             break;
     951             : 
     952           0 :         for( i = 0; i < mnHintSize; i+=2) {
     953           0 :             if( !(nHintMask & (1U << i)))
     954           0 :                 continue;
     955           0 :             writeType1Val( mnHintStack[i]);
     956           0 :             writeType1Val( mnHintStack[i+1] - mnHintStack[i]);
     957           0 :             const bool bHorz = (i < mnHorzHintSize);
     958           0 :             if( !nCntrBits[ bHorz])
     959           0 :                 writeTypeOp( bHorz ? TYPE1OP::HSTEM : TYPE1OP::VSTEM);
     960           0 :             else if( !--nCntrBits[ bHorz])
     961           0 :                 writeTypeEsc( bHorz ? TYPE1OP::HSTEM3 : TYPE1OP::VSTEM3);
     962             :         }
     963             :         }
     964             : #endif
     965           0 :         break;
     966             :     case TYPE2OP::CALLSUBR:
     967             :     case TYPE2OP::CALLGSUBR:
     968             :         {
     969           0 :         nInt = popInt();
     970           0 :         const bool bGlobal = (nType2Op == TYPE2OP::CALLGSUBR);
     971           0 :         callType2Subr( bGlobal, nInt);
     972             :         }
     973           0 :         break;
     974             :     case TYPE2OP::RETURN:
     975             :         // TODO: check that we are in a subroutine
     976           0 :         return;
     977             :     case TYPE2OP::VMOVETO:
     978             :     case TYPE2OP::HMOVETO:
     979           0 :         if( mbNeedClose)
     980           0 :             writeTypeOp( TYPE1OP::CLOSEPATH);
     981             :         else
     982           0 :             updateWidth( size() > 1);
     983           0 :         mbNeedClose = true;
     984           0 :         pop2MultiWrite( 1, nType2Op);
     985           0 :         break;
     986             :     case TYPE2OP::VLINETO:
     987             :     case TYPE2OP::HLINETO:
     988             :         pop2MultiWrite( 1, nType2Op,
     989           0 :             TYPE1OP::VLINETO ^ TYPE1OP::HLINETO);
     990           0 :         break;
     991             :     case TYPE2OP::RMOVETO:
     992             :         // TODO: convert rmoveto to vlineto/hlineto if possible
     993           0 :         if( mbNeedClose)
     994           0 :             writeTypeOp( TYPE1OP::CLOSEPATH);
     995             :         else
     996           0 :             updateWidth( size() > 2);
     997           0 :         mbNeedClose = true;
     998           0 :         pop2MultiWrite( 2, nType2Op);
     999           0 :         break;
    1000             :     case TYPE2OP::RLINETO:
    1001             :         // TODO: convert rlineto to vlineto/hlineto if possible
    1002           0 :         pop2MultiWrite( 2, nType2Op);
    1003           0 :         break;
    1004             :     case TYPE2OP::RCURVETO:
    1005             :         // TODO: convert rcurveto to vh/hv/hh/vv-curveto if possible
    1006           0 :         pop2MultiWrite( 6, nType2Op);
    1007           0 :         break;
    1008             :     case TYPE2OP::RCURVELINE:
    1009           0 :         i = 0;
    1010           0 :         while( (i += 6) <= mnStackIdx)
    1011           0 :             writeCurveTo( i, -6, -5, -4, -3, -2, -1 );
    1012           0 :         i -= 6;
    1013           0 :         while( (i += 2) <= mnStackIdx) {
    1014           0 :             writeType1Val( mnValStack[i-2]);
    1015           0 :             writeType1Val( mnValStack[i-1]);
    1016           0 :             writeTypeOp( TYPE2OP::RLINETO);
    1017             :         }
    1018           0 :         clear();
    1019           0 :         break;
    1020             :     case TYPE2OP::RLINECURVE:
    1021           0 :         i = 0;
    1022           0 :         while( (i += 2) <= mnStackIdx-6) {
    1023           0 :             writeType1Val( mnValStack[i-2]);
    1024           0 :             writeType1Val( mnValStack[i-1]);
    1025           0 :             writeTypeOp( TYPE2OP::RLINETO);
    1026             :         }
    1027           0 :         i -= 2;
    1028           0 :         while( (i += 6) <= mnStackIdx)
    1029           0 :             writeCurveTo( i, -6, -5, -4, -3, -2, -1 );
    1030           0 :         clear();
    1031           0 :         break;
    1032             :     case TYPE2OP::VHCURVETO:
    1033             :     case TYPE2OP::HVCURVETO:
    1034             :         {
    1035           0 :         bool bVert = (nType2Op == TYPE2OP::VHCURVETO);
    1036           0 :         i = 0;
    1037           0 :         nInt = 0;
    1038           0 :         if( mnStackIdx & 1 )
    1039           0 :             nInt = static_cast<int>(mnValStack[ --mnStackIdx ]);
    1040           0 :         while( (i += 4) <= mnStackIdx) {
    1041             :             // TODO: use writeCurveTo()
    1042           0 :             if( bVert ) writeType1Val( 0 );
    1043           0 :             writeType1Val( mnValStack[i-4] );
    1044           0 :             if( !bVert ) writeType1Val( 0);
    1045           0 :             writeType1Val( mnValStack[i-3] );
    1046           0 :             writeType1Val( mnValStack[i-2] );
    1047           0 :             if( !bVert ) writeType1Val( static_cast<ValType>((i==mnStackIdx) ? nInt : 0) );
    1048           0 :             writeType1Val( mnValStack[i-1] );
    1049           0 :             if( bVert ) writeType1Val( static_cast<ValType>((i==mnStackIdx) ? nInt : 0) );
    1050           0 :             bVert = !bVert;
    1051           0 :             writeTypeOp( TYPE2OP::RCURVETO);
    1052             :         }
    1053             :         }
    1054           0 :         clear();
    1055           0 :         break;
    1056             :     case TYPE2OP::HHCURVETO:
    1057           0 :         i = (mnStackIdx & 1);
    1058           0 :         while( (i += 4) <= mnStackIdx) {
    1059           0 :             if( i != 5)
    1060           0 :                 writeCurveTo( i, -4,  0, -3, -2, -1, 0);
    1061             :             else
    1062           0 :                 writeCurveTo( i, -4, -5, -3, -2, -1, 0);
    1063             :         }
    1064           0 :         clear();
    1065           0 :         break;
    1066             :     case TYPE2OP::VVCURVETO:
    1067           0 :         i = (mnStackIdx & 1);
    1068           0 :         while( (i += 4) <= mnStackIdx) {
    1069           0 :             if( i != 5)
    1070           0 :                 writeCurveTo( i,  0, -4, -3, -2, 0, -1);
    1071             :             else
    1072           0 :                 writeCurveTo( i, -5, -4, -3, -2, 0, -1);
    1073             :         }
    1074           0 :         clear();
    1075           0 :         break;
    1076             :     case TYPE2OP::ENDCHAR:
    1077           0 :         if( mbNeedClose)
    1078           0 :             writeTypeOp( TYPE1OP::CLOSEPATH);
    1079             :         else
    1080           0 :             updateWidth( size() >= 1);
    1081             :         // mbNeedClose = true;
    1082           0 :         writeTypeOp( TYPE1OP::ENDCHAR);
    1083           0 :         break;
    1084             :     default:
    1085           0 :         if( ((nType2Op >= 32) && (nType2Op <= 255)) || (nType2Op == 28)) {
    1086           0 :             --mpReadPtr;
    1087           0 :             read2push();
    1088             :         } else {
    1089           0 :             popAll2Write( nType2Op);
    1090             :             assert( false); // TODO?
    1091             :         }
    1092           0 :         break;
    1093             :     }
    1094             : }
    1095             : 
    1096             : // --------------------------------------------------------------------
    1097             : 
    1098           0 : void CffSubsetterContext::convertOneTypeEsc( void)
    1099             : {
    1100           0 :     const int nType2Esc = *(mpReadPtr++);
    1101           0 :     ValType* pTop = &mnValStack[ mnStackIdx-1];
    1102             :     // convert each T2op
    1103           0 :     switch( nType2Esc) {
    1104             :     case TYPE2OP::AND:
    1105             :         assert( mnStackIdx >= 2 );
    1106           0 :         pTop[0] = static_cast<ValType>(static_cast<int>(pTop[0]) & static_cast<int>(pTop[-1]));
    1107           0 :         --mnStackIdx;
    1108           0 :         break;
    1109             :     case TYPE2OP::OR:
    1110             :         assert( mnStackIdx >= 2 );
    1111           0 :         pTop[0] = static_cast<ValType>(static_cast<int>(pTop[0]) | static_cast<int>(pTop[-1]));
    1112           0 :         --mnStackIdx;
    1113           0 :         break;
    1114             :     case TYPE2OP::NOT:
    1115             :         assert( mnStackIdx >= 1 );
    1116           0 :         pTop[0] = (pTop[0] == 0);
    1117           0 :         break;
    1118             :     case TYPE2OP::ABS:
    1119             :         assert( mnStackIdx >= 1 );
    1120           0 :         if( pTop[0] >= 0)
    1121           0 :             break;
    1122             :         // fall through
    1123             :     case TYPE2OP::NEG:
    1124             :         assert( mnStackIdx >= 1 );
    1125           0 :         pTop[0] = -pTop[0];
    1126           0 :         break;
    1127             :     case TYPE2OP::ADD:
    1128             :         assert( mnStackIdx >= 2 );
    1129           0 :         pTop[0] += pTop[-1];
    1130           0 :         --mnStackIdx;
    1131           0 :         break;
    1132             :     case TYPE2OP::SUB:
    1133             :         assert( mnStackIdx >= 2 );
    1134           0 :         pTop[0] -= pTop[-1];
    1135           0 :         --mnStackIdx;
    1136           0 :         break;
    1137             :     case TYPE2OP::MUL:
    1138             :         assert( mnStackIdx >= 2 );
    1139           0 :         if( pTop[-1])
    1140           0 :             pTop[0] *= pTop[-1];
    1141           0 :         --mnStackIdx;
    1142           0 :         break;
    1143             :     case TYPE2OP::DIV:
    1144             :         assert( mnStackIdx >= 2 );
    1145           0 :         if( pTop[-1])
    1146           0 :             pTop[0] /= pTop[-1];
    1147           0 :         --mnStackIdx;
    1148           0 :         break;
    1149             :     case TYPE2OP::EQ:
    1150             :         assert( mnStackIdx >= 2 );
    1151           0 :         pTop[0] = (pTop[0] == pTop[-1]);
    1152           0 :         --mnStackIdx;
    1153           0 :         break;
    1154             :     case TYPE2OP::DROP:
    1155             :         assert( mnStackIdx >= 1 );
    1156           0 :         --mnStackIdx;
    1157           0 :         break;
    1158             :     case TYPE2OP::PUT: {
    1159             :         assert( mnStackIdx >= 2 );
    1160           0 :         const int nIdx = static_cast<int>(pTop[0]);
    1161             :         assert( nIdx >= 0 );
    1162             :         assert( nIdx < NMAXTRANS );
    1163           0 :         mnTransVals[ nIdx] = pTop[-1];
    1164           0 :         mnStackIdx -= 2;
    1165           0 :         break;
    1166             :         }
    1167             :     case TYPE2OP::GET: {
    1168             :         assert( mnStackIdx >= 1 );
    1169           0 :         const int nIdx = static_cast<int>(pTop[0]);
    1170             :         assert( nIdx >= 0 );
    1171             :         assert( nIdx < NMAXTRANS );
    1172           0 :         pTop[0] = mnTransVals[ nIdx ];
    1173           0 :         break;
    1174             :         }
    1175             :     case TYPE2OP::IFELSE: {
    1176             :         assert( mnStackIdx >= 4 );
    1177           0 :         if( pTop[-1] > pTop[0] )
    1178           0 :             pTop[-3] = pTop[-2];
    1179           0 :         mnStackIdx -= 3;
    1180           0 :         break;
    1181             :         }
    1182             :     case TYPE2OP::RANDOM:
    1183           0 :         pTop[+1] = 1234; // TODO
    1184           0 :         ++mnStackIdx;
    1185           0 :         break;
    1186             :     case TYPE2OP::SQRT:
    1187             :         // TODO: implement
    1188           0 :         break;
    1189             :     case TYPE2OP::DUP:
    1190             :         assert( mnStackIdx >= 1 );
    1191           0 :         pTop[+1] = pTop[0];
    1192           0 :         ++mnStackIdx;
    1193           0 :         break;
    1194             :     case TYPE2OP::EXCH: {
    1195             :         assert( mnStackIdx >= 2 );
    1196           0 :         const ValType nVal = pTop[0];
    1197           0 :         pTop[0] = pTop[-1];
    1198           0 :         pTop[-1] = nVal;
    1199           0 :         break;
    1200             :         }
    1201             :     case TYPE2OP::INDEX: {
    1202             :         assert( mnStackIdx >= 1 );
    1203           0 :         const int nVal = static_cast<int>(pTop[0]);
    1204             :         assert( nVal >= 0 );
    1205             :         assert( nVal < mnStackIdx-1 );
    1206           0 :         pTop[0] = pTop[-1-nVal];
    1207           0 :         break;
    1208             :         }
    1209             :     case TYPE2OP::ROLL: {
    1210             :         assert( mnStackIdx >= 1 );
    1211           0 :         const int nNum = static_cast<int>(pTop[0]);
    1212             :         assert( nNum >= 0);
    1213             :         assert( nNum < mnStackIdx-2 );
    1214             :         (void)nNum; // TODO: implement
    1215           0 :         const int nOfs = static_cast<int>(pTop[-1]);
    1216           0 :         mnStackIdx -= 2;
    1217             :         (void)nOfs;// TODO: implement
    1218           0 :         break;
    1219             :         }
    1220             :     case TYPE2OP::HFLEX1: {
    1221             :             assert( mnStackIdx == 9);
    1222             : 
    1223           0 :             writeCurveTo( mnStackIdx, -9, -8, -7, -6, -5,  0);
    1224           0 :             writeCurveTo( mnStackIdx, -4,  0, -3, -2, -1,  0);
    1225             :         // TODO: emulate hflex1 using othersubr call
    1226             : 
    1227           0 :             mnStackIdx -= 9;
    1228             :         }
    1229           0 :         break;
    1230             :     case TYPE2OP::HFLEX: {
    1231             :             assert( mnStackIdx == 7);
    1232           0 :             ValType* pX = &mnValStack[ mnStackIdx];
    1233             : 
    1234           0 :             pX[+1] = -pX[-5]; // temp: +dy5==-dy2
    1235           0 :             writeCurveTo( mnStackIdx, -7,  0, -6, -5, -4,  0);
    1236           0 :             writeCurveTo( mnStackIdx, -3,  0, -2, +1, -1,  0);
    1237             :         // TODO: emulate hflex using othersubr call
    1238             : 
    1239           0 :             mnStackIdx -= 7;
    1240             :         }
    1241           0 :         break;
    1242             :     case TYPE2OP::FLEX: {
    1243             :             assert( mnStackIdx == 13 );
    1244           0 :             writeCurveTo( mnStackIdx, -13, -12, -11, -10, -9, -8 );
    1245           0 :             writeCurveTo( mnStackIdx,  -7,  -6,  -5,  -4, -3, -2 );
    1246           0 :             const ValType nFlexDepth =  mnValStack[ mnStackIdx-1 ];
    1247             :             (void)nFlexDepth; // ignoring nFlexDepth
    1248           0 :             mnStackIdx -= 13;
    1249             :         }
    1250           0 :         break;
    1251             :     case TYPE2OP::FLEX1: {
    1252             :             assert( mnStackIdx == 11 );
    1253             :             // write the first part of the flex1-hinted curve
    1254           0 :             writeCurveTo( mnStackIdx, -11, -10, -9, -8, -7, -6 );
    1255             : 
    1256             :             // determine if nD6 is horizontal or vertical
    1257           0 :             const int i = mnStackIdx;
    1258           0 :             ValType nDeltaX = mnValStack[i-11] + mnValStack[i-9] + mnValStack[i-7] + mnValStack[i-5] + mnValStack[i-3];
    1259           0 :             if( nDeltaX < 0 ) nDeltaX = -nDeltaX;
    1260           0 :             ValType nDeltaY = mnValStack[i-10] + mnValStack[i-8] + mnValStack[i-6] + mnValStack[i-4] + mnValStack[i-2];
    1261           0 :             if( nDeltaY < 0 ) nDeltaY = -nDeltaY;
    1262           0 :             const bool bVertD6 = (nDeltaY > nDeltaX);
    1263             : 
    1264             :             // write the second part of the flex1-hinted curve
    1265           0 :             if( !bVertD6 )
    1266           0 :                 writeCurveTo( mnStackIdx, -5, -4, -3, -2, -1, 0);
    1267             :             else
    1268           0 :                 writeCurveTo( mnStackIdx, -5, -4, -3, -2, 0, -1);
    1269           0 :             mnStackIdx -= 11;
    1270             :         }
    1271           0 :         break;
    1272             :     default:
    1273           0 :         fprintf( stderr,"unhandled type2esc %d\n", nType2Esc);
    1274             :         assert( false);
    1275           0 :         break;
    1276             :     }
    1277           0 : }
    1278             : 
    1279             : // --------------------------------------------------------------------
    1280             : 
    1281           0 : void CffSubsetterContext::callType2Subr( bool bGlobal, int nSubrNumber)
    1282             : {
    1283           0 :     const U8* const pOldReadPtr = mpReadPtr;
    1284           0 :     const U8* const pOldReadEnd = mpReadEnd;
    1285             : 
    1286           0 :     if( bGlobal ) {
    1287           0 :         nSubrNumber += mnGlobalSubrBias;
    1288           0 :         seekIndexData( mnGlobalSubrBase, nSubrNumber);
    1289             :     } else {
    1290           0 :         nSubrNumber += mpCffLocal->mnLocalSubrBias;
    1291           0 :         seekIndexData( mpCffLocal->mnLocalSubrBase, nSubrNumber);
    1292             :     }
    1293             : 
    1294           0 :     while( mpReadPtr < mpReadEnd)
    1295           0 :         convertOneTypeOp();
    1296             : 
    1297           0 :     mpReadPtr = pOldReadPtr;
    1298           0 :     mpReadEnd = pOldReadEnd;
    1299           0 : }
    1300             : 
    1301             : // --------------------------------------------------------------------
    1302             : 
    1303             : static const int MAX_T1OPS_SIZE = 81920; // TODO: use dynamic value
    1304             : 
    1305           0 : int CffSubsetterContext::convert2Type1Ops( CffLocal* pCffLocal, const U8* const pT2Ops, int nT2Len, U8* const pT1Ops)
    1306             : {
    1307           0 :     mpCffLocal = pCffLocal;
    1308             : 
    1309             :     // prepare the charstring conversion
    1310           0 :     mpWritePtr = pT1Ops;
    1311             : #if 1   // TODO: update caller
    1312             :     U8 aType1Ops[ MAX_T1OPS_SIZE];
    1313           0 :     if( !pT1Ops)
    1314           0 :         mpWritePtr = aType1Ops;
    1315           0 :     *const_cast<U8**>(&pT1Ops) = mpWritePtr;
    1316             : #else
    1317             :     assert( pT1Ops);
    1318             : #endif
    1319             : 
    1320             :     // prepend random seed for T1crypt
    1321           0 :     *(mpWritePtr++) = 0x48;
    1322           0 :     *(mpWritePtr++) = 0x44;
    1323           0 :     *(mpWritePtr++) = 0x55;
    1324           0 :     *(mpWritePtr++) = ' ';
    1325             : #if 1 // convert the Type2 charstring to Type1
    1326           0 :     mpReadPtr = pT2Ops;
    1327           0 :     mpReadEnd = pT2Ops + nT2Len;
    1328             :     // prepend "hsbw" or "sbw"
    1329             :     // TODO: only emit hsbw when charwidth is known
    1330             :     // TODO: remove charwidth from T2 stack
    1331           0 :     writeType1Val( 0); // TODO: aSubsetterContext.getLeftSideBearing();
    1332           0 :     writeType1Val( 1000/*###getCharWidth()###*/);
    1333           0 :     writeTypeOp( TYPE1OP::HSBW);
    1334           0 : mbSawError = false;
    1335           0 : mbNeedClose = false;
    1336           0 : mbIgnoreHints = false;
    1337           0 : mnHintSize=mnHorzHintSize=mnStackIdx=0; maCharWidth=-1;//#######
    1338           0 : mnCntrMask = 0;
    1339           0 :     while( mpReadPtr < mpReadEnd)
    1340           0 :         convertOneTypeOp();
    1341             : //  if( bActivePath)
    1342             : //      writeTypeOp( TYPE1OP::CLOSEPATH);
    1343             : //  if( bSubRoutine)
    1344             : //      writeTypeOp( TYPE1OP::RETURN);
    1345           0 : if( mbSawError) {
    1346           0 :     mpWritePtr = pT1Ops+4;
    1347             :      // create an "idiotproof" charstring
    1348           0 :     writeType1Val( 0);
    1349           0 :     writeType1Val( 800);
    1350           0 :     writeTypeOp( TYPE1OP::HSBW);
    1351           0 :     writeType1Val( 50);
    1352           0 :     writeTypeOp( TYPE1OP::HMOVETO);
    1353           0 :     writeType1Val( 650);
    1354           0 :     writeType1Val( 100);
    1355           0 :     writeTypeOp( TYPE1OP::RLINETO);
    1356           0 :     writeType1Val( -350);
    1357           0 :     writeType1Val( 700);
    1358           0 :     writeTypeOp( TYPE1OP::RLINETO);
    1359           0 :     writeTypeOp( TYPE1OP::CLOSEPATH);
    1360           0 :     writeTypeOp( TYPE1OP::ENDCHAR);
    1361             : }
    1362             : #else // useful for manually encoding charstrings
    1363             :     mpWritePtr = pT1Ops;
    1364             :     mpWritePtr += sprintf( (char*)mpWritePtr, "OOo_\x8b\x8c\x0c\x10\x0b");
    1365             : #endif
    1366           0 :     const int nType1Len = mpWritePtr - pT1Ops;
    1367             : 
    1368             :     // encrypt the Type1 charstring
    1369           0 :     int nRDCryptR = 4330; // TODO: mnRDCryptSeed;
    1370           0 :     for( U8* p = pT1Ops; p < mpWritePtr; ++p) {
    1371           0 :         *p ^= (nRDCryptR >> 8);
    1372           0 :         nRDCryptR = (*(U8*)p + nRDCryptR) * 52845 + 22719;
    1373             :     }
    1374             : 
    1375           0 :     return nType1Len;
    1376             : }
    1377             : 
    1378             : // --------------------------------------------------------------------
    1379             : 
    1380           0 : RealType CffSubsetterContext::readRealVal()
    1381             : {
    1382             :     // TODO: more thorough number validity test
    1383           0 :     bool bComma = false;
    1384           0 :     int nExpVal = 0;
    1385           0 :     int nExpSign = 0;
    1386           0 :     S64 nNumber = 0;
    1387           0 :     RealType fReal = +1.0;
    1388           0 :     for(;;){
    1389           0 :         const U8 c = *(mpReadPtr++); // read nibbles
    1390             :         // parse high nibble
    1391           0 :         const U8 nH = c >> 4U;
    1392           0 :         if( nH <= 9) {
    1393           0 :             nNumber = nNumber * 10 + nH;
    1394           0 :             --nExpVal;
    1395           0 :         } else if( nH == 10) {  // comma
    1396           0 :             nExpVal = 0;
    1397           0 :             bComma = true;
    1398           0 :         } else if( nH == 11) {  // +exp
    1399           0 :             fReal *= nNumber;
    1400           0 :             nExpSign = +1;
    1401           0 :             nNumber = 0;
    1402           0 :         } else if( nH == 12) {  // -exp
    1403           0 :             fReal *= nNumber;
    1404           0 :             nExpSign = -1;
    1405           0 :             nNumber = 0;
    1406           0 :         } else if( nH == 13) {  // reserved
    1407             :             // TODO: ignore or error?
    1408           0 :         } else if( nH == 14)    // minus
    1409           0 :             fReal = -fReal;
    1410           0 :         else if( nH == 15)  // end
    1411           0 :             break;
    1412             :         // parse low nibble
    1413           0 :         const U8 nL = c & 0x0F;
    1414           0 :         if( nL <= 9) {
    1415           0 :             nNumber = nNumber * 10 + nL;
    1416           0 :             --nExpVal;
    1417           0 :         } else if( nL == 10) {  // comma
    1418           0 :             nExpVal = 0;
    1419           0 :             bComma = true;
    1420           0 :         } else if( nL == 11) {  // +exp
    1421           0 :             fReal *= nNumber;
    1422           0 :             nNumber = 0;
    1423           0 :             nExpSign = +1;
    1424           0 :         } else if( nL == 12) {  // -exp
    1425           0 :             fReal *= nNumber;
    1426           0 :             nNumber = 0;
    1427           0 :             nExpSign = -1;
    1428           0 :         } else if( nL == 13) {  // reserved
    1429             :             // TODO: ignore or error?
    1430           0 :         } else if( nL == 14)    // minus
    1431           0 :             fReal = -fReal;
    1432           0 :         else if( nL == 15)  // end
    1433           0 :             break;
    1434             :     }
    1435             : 
    1436             :     // merge exponents
    1437           0 :     if( !bComma)
    1438           0 :         nExpVal = 0;
    1439           0 :     if( !nExpSign) { fReal *= nNumber;}
    1440           0 :     else if( nExpSign > 0) { nExpVal += static_cast<int>(nNumber);}
    1441           0 :     else if( nExpSign < 0) { nExpVal -= static_cast<int>(nNumber);}
    1442             : 
    1443             :     // apply exponents
    1444           0 :     if( !nExpVal) { /*nothing to apply*/}
    1445           0 :     else if( nExpVal > 0) { while( --nExpVal >= 0) fReal *= 10.0;}
    1446           0 :     else if( nExpVal < 0) { while( ++nExpVal <= 0) fReal /= 10.0;}
    1447           0 :     return fReal;
    1448             : }
    1449             : 
    1450             : // --------------------------------------------------------------------
    1451             : 
    1452             : // prepare to access an element inside a CFF/CID index table
    1453           0 : int CffSubsetterContext::seekIndexData( int nIndexBase, int nDataIndex)
    1454             : {
    1455             :     assert( (nIndexBase > 0) && (mpBasePtr + nIndexBase + 3 <= mpBaseEnd));
    1456           0 :     if( nDataIndex < 0)
    1457           0 :         return -1;
    1458           0 :     mpReadPtr = mpBasePtr + nIndexBase;
    1459           0 :     const int nDataCount = (mpReadPtr[0]<<8) + mpReadPtr[1];
    1460           0 :     if( nDataIndex >= nDataCount)
    1461           0 :         return -1;
    1462           0 :     const int nDataOfsSz = mpReadPtr[2];
    1463           0 :     mpReadPtr += 3 + (nDataOfsSz * nDataIndex);
    1464           0 :     int nOfs1 = 0;
    1465           0 :     switch( nDataOfsSz) {
    1466           0 :         default: fprintf( stderr, "\tINVALID nDataOfsSz=%d\n\n", nDataOfsSz); return -1;
    1467           0 :         case 1: nOfs1 = mpReadPtr[0]; break;
    1468           0 :         case 2: nOfs1 = (mpReadPtr[0]<<8) + mpReadPtr[1]; break;
    1469           0 :         case 3: nOfs1 = (mpReadPtr[0]<<16) + (mpReadPtr[1]<<8) + mpReadPtr[2]; break;
    1470           0 :         case 4: nOfs1 = (mpReadPtr[0]<<24) + (mpReadPtr[1]<<16) + (mpReadPtr[2]<<8) + mpReadPtr[3]; break;
    1471             :     }
    1472           0 :     mpReadPtr += nDataOfsSz;
    1473             : 
    1474           0 :     int nOfs2 = 0;
    1475           0 :     switch( nDataOfsSz) {
    1476           0 :         case 1: nOfs2 = mpReadPtr[0]; break;
    1477           0 :         case 2: nOfs2 = (mpReadPtr[0]<<8) + mpReadPtr[1]; break;
    1478           0 :         case 3: nOfs2 = (mpReadPtr[0]<<16) + (mpReadPtr[1]<<8) + mpReadPtr[2]; break;
    1479           0 :         case 4: nOfs2 = (mpReadPtr[0]<<24) + (mpReadPtr[1]<<16) + (mpReadPtr[2]<<8) + mpReadPtr[3]; break;
    1480             :     }
    1481             : 
    1482           0 :     mpReadPtr = mpBasePtr + (nIndexBase + 2) + nDataOfsSz * (nDataCount + 1) + nOfs1;
    1483           0 :     mpReadEnd = mpReadPtr + (nOfs2 - nOfs1);
    1484             :     assert( nOfs1 >= 0);
    1485             :     assert( nOfs2 >= nOfs1);
    1486             :     assert( mpReadPtr <= mpBaseEnd);
    1487             :     assert( mpReadEnd <= mpBaseEnd);
    1488           0 :     return (nOfs2 - nOfs1);
    1489             : }
    1490             : 
    1491             : // --------------------------------------------------------------------
    1492             : 
    1493             : // skip over a CFF/CID index table
    1494           0 : void CffSubsetterContext::seekIndexEnd( int nIndexBase)
    1495             : {
    1496             :     assert( (nIndexBase > 0) && (mpBasePtr + nIndexBase + 3 <= mpBaseEnd));
    1497           0 :     mpReadPtr = mpBasePtr + nIndexBase;
    1498           0 :     const int nDataCount = (mpReadPtr[0]<<8) + mpReadPtr[1];
    1499           0 :     const int nDataOfsSz = mpReadPtr[2];
    1500           0 :     mpReadPtr += 3 + nDataOfsSz * nDataCount;
    1501             :     assert( mpReadPtr <= mpBaseEnd);
    1502           0 :     int nEndOfs = 0;
    1503           0 :     switch( nDataOfsSz) {
    1504           0 :         default: fprintf( stderr, "\tINVALID nDataOfsSz=%d\n\n", nDataOfsSz); return;
    1505           0 :         case 1: nEndOfs = mpReadPtr[0]; break;
    1506           0 :         case 2: nEndOfs = (mpReadPtr[0]<<8) + mpReadPtr[1]; break;
    1507           0 :         case 3: nEndOfs = (mpReadPtr[0]<<16) + (mpReadPtr[1]<<8) + mpReadPtr[2];break;
    1508           0 :         case 4: nEndOfs = (mpReadPtr[0]<<24) + (mpReadPtr[1]<<16) + (mpReadPtr[2]<<8) + mpReadPtr[3]; break;
    1509             :     }
    1510           0 :     mpReadPtr += nDataOfsSz;
    1511           0 :     mpReadPtr += nEndOfs - 1;
    1512           0 :     mpReadEnd = mpBaseEnd;
    1513             :     assert( nEndOfs >= 0);
    1514             :     assert( mpReadEnd <= mpBaseEnd);
    1515             : }
    1516             : 
    1517             : // ====================================================================
    1518             : 
    1519             : // initialize FONTDICT specific values
    1520           0 : CffLocal::CffLocal( void)
    1521             : :   mnPrivDictBase( 0)
    1522             : ,   mnPrivDictSize( 0)
    1523             : ,   mnLocalSubrOffs( 0)
    1524             : ,   mnLocalSubrBase( 0)
    1525             : ,   mnLocalSubrCount( 0)
    1526             : ,   mnLocalSubrBias( 0)
    1527             : ,   maNominalWidth( 0)
    1528             : ,   maDefaultWidth( 0)
    1529             : ,   maStemStdHW( 0)
    1530             : ,   maStemStdVW( 0)
    1531             : ,   mfBlueScale( 0.0)
    1532             : ,   mfBlueShift( 0.0)
    1533             : ,   mfBlueFuzz( 0.0)
    1534             : ,   mfExpFactor( 0.0)
    1535             : ,   mnLangGroup( 0)
    1536           0 : ,   mbForceBold( false)
    1537             : {
    1538           0 :     maStemSnapH.clear();
    1539           0 :     maStemSnapV.clear();
    1540           0 :     maBlueValues.clear();
    1541           0 :     maOtherBlues.clear();
    1542           0 :     maFamilyBlues.clear();
    1543           0 :     maFamilyOtherBlues.clear();
    1544           0 : }
    1545             : 
    1546             : // --------------------------------------------------------------------
    1547             : 
    1548           0 : CffGlobal::CffGlobal( void)
    1549             : :   mnNameIdxBase( 0)
    1550             : ,   mnNameIdxCount( 0)
    1551             : ,   mnStringIdxBase( 0)
    1552             : ,   mnStringIdxCount( 0)
    1553             : ,   mbCIDFont( false)
    1554             : ,   mnCharStrBase( 0)
    1555             : ,   mnCharStrCount( 0)
    1556             : ,   mnEncodingBase( 0)
    1557             : ,   mnCharsetBase( 0)
    1558             : ,   mnGlobalSubrBase( 0)
    1559             : ,   mnGlobalSubrCount( 0)
    1560             : ,   mnGlobalSubrBias( 0)
    1561             : ,   mnFDSelectBase( 0)
    1562             : ,   mnFontDictBase( 0)
    1563             : ,   mnFDAryCount( 1)
    1564             : ,   mnFontNameSID( 0)
    1565             : ,   mnFullNameSID( 0)
    1566           0 : ,   mnFamilyNameSID( 0)
    1567             : {
    1568           0 :     maFontBBox.clear();
    1569             :     // TODO; maFontMatrix.clear();
    1570           0 : }
    1571             : 
    1572             : // --------------------------------------------------------------------
    1573             : 
    1574           0 : void CffSubsetterContext::initialCffRead( void)
    1575             : {
    1576             :     // get the CFFHeader
    1577           0 :     mpReadPtr = mpBasePtr;
    1578           0 :     const U8 nVerMajor = *(mpReadPtr++);
    1579           0 :     const U8 nVerMinor = *(mpReadPtr++);
    1580           0 :     const U8 nHeaderSize = *(mpReadPtr++);
    1581           0 :     const U8 nOffsetSize = *(mpReadPtr++);
    1582             :     // TODO: is the version number useful for anything else?
    1583             :     assert( (nVerMajor == 1) && (nVerMinor == 0));
    1584             :     (void)(nVerMajor + nVerMinor + nOffsetSize); // avoid compiler warnings
    1585             : 
    1586             :     // prepare access to the NameIndex
    1587           0 :     mnNameIdxBase = nHeaderSize;
    1588           0 :     mpReadPtr = mpBasePtr + nHeaderSize;
    1589           0 :     mnNameIdxCount = (mpReadPtr[0]<<8) + mpReadPtr[1];
    1590           0 :     seekIndexEnd( mnNameIdxBase);
    1591             : 
    1592             :     // get the TopDict index
    1593           0 :     const long nTopDictBase = getReadOfs();
    1594           0 :     const int nTopDictCount = (mpReadPtr[0]<<8) + mpReadPtr[1];
    1595           0 :     if( nTopDictCount) {
    1596           0 :         for( int i = 0; i < nTopDictCount; ++i) {
    1597           0 :             seekIndexData( nTopDictBase, i);
    1598           0 :             while( mpReadPtr < mpReadEnd)
    1599           0 :                 readDictOp();
    1600             :             assert( mpReadPtr == mpReadEnd);
    1601             :         }
    1602             :     }
    1603             : 
    1604             :     // prepare access to the String index
    1605           0 :     mnStringIdxBase =  getReadOfs();
    1606           0 :     mnStringIdxCount = (mpReadPtr[0]<<8) + mpReadPtr[1];
    1607           0 :     seekIndexEnd( mnStringIdxBase);
    1608             : 
    1609             :     // prepare access to the GlobalSubr index
    1610           0 :     mnGlobalSubrBase =  getReadOfs();
    1611           0 :     mnGlobalSubrCount = (mpReadPtr[0]<<8) + mpReadPtr[1];
    1612           0 :     mnGlobalSubrBias = (mnGlobalSubrCount<1240)?107:(mnGlobalSubrCount<33900)?1131:32768;
    1613             :     // skip past the last GlobalSubr entry
    1614             : //  seekIndexEnd( mnGlobalSubrBase);
    1615             : 
    1616             :     // get/skip the Encodings (we got mnEncodingBase from TOPDICT)
    1617             : //  seekEncodingsEnd( mnEncodingBase);
    1618             :     // get/skip the Charsets (we got mnCharsetBase from TOPDICT)
    1619             : //  seekCharsetsEnd( mnCharStrBase);
    1620             :     // get/skip FDSelect (CID only) data
    1621             : 
    1622             :     // prepare access to the CharStrings index (we got the base from TOPDICT)
    1623           0 :     mpReadPtr = mpBasePtr + mnCharStrBase;
    1624           0 :     mnCharStrCount = (mpReadPtr[0]<<8) + mpReadPtr[1];
    1625             : //  seekIndexEnd( mnCharStrBase);
    1626             : 
    1627             :     // read the FDArray index (CID only)
    1628           0 :     if( mbCIDFont) {
    1629             : //      assert( mnFontDictBase == tellRel());
    1630           0 :         mpReadPtr = mpBasePtr + mnFontDictBase;
    1631           0 :         mnFDAryCount = (mpReadPtr[0]<<8) + mpReadPtr[1];
    1632             :         assert( mnFDAryCount < (int)(sizeof(maCffLocal)/sizeof(*maCffLocal)));
    1633             : 
    1634             :         // read FDArray details to get access to the PRIVDICTs
    1635           0 :         for( int i = 0; i < mnFDAryCount; ++i) {
    1636           0 :             mpCffLocal = &maCffLocal[i];
    1637           0 :             seekIndexData( mnFontDictBase, i);
    1638           0 :             while( mpReadPtr < mpReadEnd)
    1639           0 :                 readDictOp();
    1640             :             assert( mpReadPtr == mpReadEnd);
    1641             :         }
    1642             :     }
    1643             : 
    1644           0 :     for( int i = 0; i < mnFDAryCount; ++i) {
    1645           0 :         mpCffLocal = &maCffLocal[i];
    1646             : 
    1647             :         // get the PrivateDict index
    1648             :         // (we got mnPrivDictSize and mnPrivDictBase from TOPDICT or FDArray)
    1649           0 :         if( mpCffLocal->mnPrivDictSize != 0) {
    1650             :             assert( mpCffLocal->mnPrivDictSize > 0);
    1651             :             // get the PrivDict data
    1652           0 :             mpReadPtr = mpBasePtr + mpCffLocal->mnPrivDictBase;
    1653           0 :             mpReadEnd = mpReadPtr + mpCffLocal->mnPrivDictSize;
    1654             :             assert( mpReadEnd <= mpBaseEnd);
    1655             :             // read PrivDict details
    1656           0 :             while( mpReadPtr < mpReadEnd)
    1657           0 :                 readDictOp();
    1658             :         }
    1659             : 
    1660             :         // prepare access to the LocalSubrs (we got mnLocalSubrOffs from PRIVDICT)
    1661           0 :         if( mpCffLocal->mnLocalSubrOffs) {
    1662             :             // read LocalSubrs summary
    1663           0 :             mpCffLocal->mnLocalSubrBase = mpCffLocal->mnPrivDictBase + mpCffLocal->mnLocalSubrOffs;
    1664           0 :             mpReadPtr = mpBasePtr + mpCffLocal->mnLocalSubrBase;
    1665           0 :             const int nSubrCount = (mpReadPtr[0] << 8) + mpReadPtr[1];
    1666           0 :             mpCffLocal->mnLocalSubrCount = nSubrCount;
    1667           0 :             mpCffLocal->mnLocalSubrBias = (nSubrCount<1240)?107:(nSubrCount<33900)?1131:32768;
    1668             : //          seekIndexEnd( mpCffLocal->mnLocalSubrBase);
    1669             :         }
    1670             :     }
    1671             : 
    1672             :     // ignore the Notices info
    1673           0 : }
    1674             : 
    1675             : // --------------------------------------------------------------------
    1676             : 
    1677             : // get a cstring from a StringID
    1678           0 : const char* CffSubsetterContext::getString( int nStringID)
    1679             : {
    1680             :     // get a standard string if possible
    1681             :     const static int nStdStrings = sizeof(pStringIds)/sizeof(*pStringIds);
    1682           0 :     if( (nStringID >= 0) && (nStringID < nStdStrings))
    1683           0 :         return pStringIds[ nStringID];
    1684             : 
    1685             :     // else get the string from the StringIndex table
    1686           0 :     const U8* pReadPtr = mpReadPtr;
    1687           0 :     const U8* pReadEnd = mpReadEnd;
    1688           0 :     nStringID -= nStdStrings;
    1689           0 :     int nLen = seekIndexData( mnStringIdxBase, nStringID);
    1690             :     // assert( nLen >= 0);
    1691             :     // TODO: just return the undecorated name
    1692             :     // TODO: get rid of static char buffer
    1693             :     static char aNameBuf[ 2560];
    1694           0 :     if( nLen < 0) {
    1695           0 :         sprintf( aNameBuf, "name[%d].notfound!", nStringID);
    1696             :     } else {
    1697           0 :         const int nMaxLen = sizeof(aNameBuf) - 1;
    1698           0 :         if( nLen >= nMaxLen)
    1699           0 :             nLen = nMaxLen;
    1700           0 :         for( int i = 0; i < nLen; ++i)
    1701           0 :             aNameBuf[i] = *(mpReadPtr++);
    1702           0 :         aNameBuf[ nLen] = '\0';
    1703             :     }
    1704           0 :     mpReadPtr = pReadPtr;
    1705           0 :     mpReadEnd = pReadEnd;
    1706           0 :     return aNameBuf;
    1707             : }
    1708             : 
    1709             : // --------------------------------------------------------------------
    1710             : 
    1711             : // access a CID's FDSelect table
    1712           0 : int CffSubsetterContext::getFDSelect( int nGlyphIndex) const
    1713             : {
    1714             :     assert( nGlyphIndex >= 0);
    1715             :     assert( nGlyphIndex < mnCharStrCount);
    1716           0 :     if( !mbCIDFont)
    1717           0 :         return 0;
    1718             : 
    1719           0 :     const U8* pReadPtr = mpBasePtr + mnFDSelectBase;
    1720           0 :     const U8 nFDSelFormat = *(pReadPtr++);
    1721           0 :     switch( nFDSelFormat) {
    1722             :         case 0: { // FDSELECT format 0
    1723           0 :                 pReadPtr += nGlyphIndex;
    1724           0 :                 const U8 nFDIdx = *(pReadPtr++);
    1725           0 :                 return nFDIdx;
    1726             :             } //break;
    1727             :         case 3: { // FDSELECT format 3
    1728           0 :                 const U16 nRangeCount = (pReadPtr[0]<<8) + pReadPtr[1];
    1729             :                 assert( nRangeCount > 0);
    1730             :                 assert( nRangeCount <= mnCharStrCount);
    1731           0 :                 U16 nPrev = (pReadPtr[2]<<8) + pReadPtr[3];
    1732             :                 assert( nPrev == 0);
    1733             :                 (void)nPrev;
    1734           0 :                 pReadPtr += 4;
    1735             :                 // TODO? binary search
    1736           0 :                 for( int i = 0; i < nRangeCount; ++i) {
    1737           0 :                     const U8 nFDIdx = pReadPtr[0];
    1738           0 :                     const U16 nNext = (pReadPtr[1]<<8) + pReadPtr[2];
    1739             :                     assert( nPrev < nNext);
    1740           0 :                     if( nGlyphIndex < nNext)
    1741           0 :                         return nFDIdx;
    1742           0 :                     pReadPtr += 3;
    1743           0 :                     nPrev = nNext;
    1744             :                 }
    1745           0 :             } break;
    1746             :         default:    // invalid FDselect format
    1747           0 :             fprintf( stderr, "invalid CFF.FdselType=%d\n", nFDSelFormat);
    1748           0 :             break;
    1749             :     }
    1750             : 
    1751             :     assert( false);
    1752           0 :     return -1;
    1753             : }
    1754             : 
    1755             : // --------------------------------------------------------------------
    1756             : 
    1757           0 : int CffSubsetterContext::getGlyphSID( int nGlyphIndex) const
    1758             : {
    1759           0 :     if( nGlyphIndex == 0)
    1760           0 :         return 0;       // ".notdef"
    1761             :     assert( nGlyphIndex >= 0);
    1762             :     assert( nGlyphIndex < mnCharStrCount);
    1763           0 :     if( (nGlyphIndex < 0) || (nGlyphIndex >= mnCharStrCount))
    1764           0 :         return -1;
    1765             : 
    1766             :     // get the SID/CID from the Charset table
    1767           0 :      const U8* pReadPtr = mpBasePtr + mnCharsetBase;
    1768           0 :     const U8 nCSetFormat = *(pReadPtr++);
    1769           0 :     int nGlyphsToSkip = nGlyphIndex - 1;
    1770           0 :     switch( nCSetFormat) {
    1771             :         case 0: // charset format 0
    1772           0 :             pReadPtr += 2 * nGlyphsToSkip;
    1773           0 :             nGlyphsToSkip = 0;
    1774           0 :             break;
    1775             :         case 1: // charset format 1
    1776           0 :             while( nGlyphsToSkip >= 0) {
    1777           0 :                 const int nLeft = pReadPtr[2];
    1778           0 :                 if( nGlyphsToSkip <= nLeft)
    1779           0 :                     break;
    1780           0 :                 nGlyphsToSkip -= nLeft + 1;
    1781           0 :                 pReadPtr += 3;
    1782             :             }
    1783           0 :             break;
    1784             :         case 2: // charset format 2
    1785           0 :             while( nGlyphsToSkip >= 0) {
    1786           0 :                 const int nLeft = (pReadPtr[2]<<8) + pReadPtr[3];
    1787           0 :                 if( nGlyphsToSkip <= nLeft)
    1788           0 :                     break;
    1789           0 :                 nGlyphsToSkip -= nLeft + 1;
    1790           0 :                 pReadPtr += 4;
    1791             :             }
    1792           0 :             break;
    1793             :         default:
    1794           0 :             fprintf( stderr, "ILLEGAL CFF-Charset format %d\n", nCSetFormat);
    1795           0 :             return -2;
    1796             :     }
    1797             : 
    1798           0 :     int nSID = (pReadPtr[0]<<8) + pReadPtr[1];
    1799           0 :     nSID += nGlyphsToSkip;
    1800             :     // NOTE: for CID-fonts the resulting SID is interpreted as CID
    1801           0 :     return nSID;
    1802             : }
    1803             : 
    1804             : // --------------------------------------------------------------------
    1805             : 
    1806             : // NOTE: the result becomes invalid with the next call to this method
    1807           0 : const char* CffSubsetterContext::getGlyphName( int nGlyphIndex)
    1808             : {
    1809             :     // the first glyph is always the .notdef glyph
    1810           0 :     const char* pGlyphName = ".notdef";
    1811           0 :     if( nGlyphIndex == 0)
    1812           0 :         return pGlyphName;
    1813             : 
    1814             :     // prepare a result buffer
    1815             :     // TODO: get rid of static buffer
    1816             :     static char aDefaultGlyphName[64];
    1817           0 :     pGlyphName = aDefaultGlyphName;
    1818             : 
    1819             :     // get the glyph specific name
    1820           0 :     const int nSID = getGlyphSID( nGlyphIndex);
    1821           0 :     if( nSID < 0)           // default glyph name
    1822           0 :         sprintf( aDefaultGlyphName, "gly%03d", nGlyphIndex);
    1823           0 :     else if( mbCIDFont)     // default glyph name in CIDs
    1824           0 :          sprintf( aDefaultGlyphName, "cid%03d", nSID);
    1825             :     else {                  // glyph name from string table
    1826           0 :         const char* pSidName = getString( nSID);
    1827             :         // check validity of glyph name
    1828           0 :         if( pSidName) {
    1829           0 :             const char* p = pSidName;
    1830           0 :             while( (*p >= '0') && (*p <= 'z')) ++p;
    1831           0 :             if( (p >= pSidName+1) && (*p == '\0'))
    1832           0 :                 pGlyphName = pSidName;
    1833             :         }
    1834             :         // if needed invent a fallback name
    1835           0 :         if( pGlyphName != pSidName)
    1836           0 :              sprintf( aDefaultGlyphName, "bad%03d", nSID);
    1837             :     }
    1838             : 
    1839           0 :      return pGlyphName;
    1840             : }
    1841             : 
    1842             : // --------------------------------------------------------------------
    1843             : 
    1844             : class Type1Emitter
    1845             : {
    1846             : public:
    1847             :     explicit    Type1Emitter( FILE* pOutFile, bool bPfbSubset = true);
    1848             :     /*virtual*/ ~Type1Emitter( void);
    1849             :     void        setSubsetName( const char* );
    1850             : 
    1851             :     size_t      emitRawData( const char* pData, size_t nLength) const;
    1852             :     void        emitAllRaw( void);
    1853             :     void        emitAllHex( void);
    1854             :     void        emitAllCrypted( void);
    1855             :     int         tellPos( void) const;
    1856             :     size_t      updateLen( int nTellPos, size_t nLength);
    1857             :     void        emitValVector( const char* pLineHead, const char* pLineTail, const ValVector&);
    1858             : private:
    1859             :     FILE*       mpFileOut;
    1860             :     bool        mbCloseOutfile;
    1861             :     char        maBuffer[MAX_T1OPS_SIZE];   // TODO: dynamic allocation
    1862             :     int         mnEECryptR;
    1863             : public:
    1864             :     char*       mpPtr;
    1865             : 
    1866             :     char        maSubsetName[256];
    1867             :     bool        mbPfbSubset;
    1868             :     int         mnHexLineCol;
    1869             : };
    1870             : 
    1871             : // --------------------------------------------------------------------
    1872             : 
    1873           0 : Type1Emitter::Type1Emitter( FILE* pOutFile, bool bPfbSubset)
    1874             : :   mpFileOut( pOutFile)
    1875             : ,   mbCloseOutfile( false)
    1876             : ,   mnEECryptR( 55665)  // default eexec seed, TODO: mnEECryptSeed
    1877             : ,   mpPtr( maBuffer)
    1878             : ,   mbPfbSubset( bPfbSubset)
    1879           0 : ,   mnHexLineCol( 0)
    1880             : {
    1881           0 :     maSubsetName[0] = '\0';
    1882           0 : }
    1883             : 
    1884             : // --------------------------------------------------------------------
    1885             : 
    1886           0 : Type1Emitter::~Type1Emitter( void)
    1887             : {
    1888           0 :     if( !mpFileOut)
    1889           0 :         return;
    1890           0 :     if( mbCloseOutfile )
    1891           0 :         fclose( mpFileOut);
    1892           0 :     mpFileOut = NULL;
    1893           0 : }
    1894             : 
    1895             : // --------------------------------------------------------------------
    1896             : 
    1897           0 : void Type1Emitter::setSubsetName( const char* pSubsetName)
    1898             : {
    1899           0 :     maSubsetName[0] = '\0';
    1900           0 :     if( pSubsetName)
    1901           0 :         strncpy( maSubsetName, pSubsetName, sizeof(maSubsetName));
    1902           0 :     maSubsetName[sizeof(maSubsetName)-1] = '\0';
    1903           0 : }
    1904             : 
    1905             : // --------------------------------------------------------------------
    1906             : 
    1907           0 : int Type1Emitter::tellPos( void) const
    1908             : {
    1909           0 :     int nTellPos = ftell( mpFileOut);
    1910           0 :     return nTellPos;
    1911             : }
    1912             : 
    1913             : // --------------------------------------------------------------------
    1914             : 
    1915           0 : size_t Type1Emitter::updateLen( int nTellPos, size_t nLength)
    1916             : {
    1917             :     // update PFB segment header length
    1918             :     U8 cData[4];
    1919           0 :     cData[0] = static_cast<U8>(nLength >>  0);
    1920           0 :     cData[1] = static_cast<U8>(nLength >>  8);
    1921           0 :     cData[2] = static_cast<U8>(nLength >> 16);
    1922           0 :     cData[3] = static_cast<U8>(nLength >> 24);
    1923           0 :     const int nCurrPos = ftell( mpFileOut);
    1924           0 :     fseek( mpFileOut, nTellPos, SEEK_SET);
    1925           0 :     size_t nWrote = fwrite( cData, 1, sizeof(cData), mpFileOut);
    1926           0 :     fseek( mpFileOut, nCurrPos, SEEK_SET);
    1927           0 :     return nWrote;
    1928             : }
    1929             : 
    1930             : // --------------------------------------------------------------------
    1931             : 
    1932           0 : inline size_t Type1Emitter::emitRawData(const char* pData, size_t nLength) const
    1933             : {
    1934           0 :     return fwrite( pData, 1, nLength, mpFileOut);
    1935             : }
    1936             : 
    1937             : // --------------------------------------------------------------------
    1938             : 
    1939           0 : inline void Type1Emitter::emitAllRaw( void)
    1940             : {
    1941             :     // writeout raw data
    1942             :     assert( (mpPtr - maBuffer) < (int)sizeof(maBuffer));
    1943           0 :     emitRawData( maBuffer, mpPtr - maBuffer);
    1944             :     // reset the raw buffer
    1945           0 :     mpPtr = maBuffer;
    1946           0 : }
    1947             : 
    1948             : // --------------------------------------------------------------------
    1949             : 
    1950           0 : inline void Type1Emitter::emitAllHex( void)
    1951             : {
    1952             :     assert( (mpPtr - maBuffer) < (int)sizeof(maBuffer));
    1953           0 :     for( const char* p = maBuffer; p < mpPtr;) {
    1954             :         // convert binary chunk to hex
    1955             :         char aHexBuf[0x4000];
    1956           0 :         char* pOut = aHexBuf;
    1957           0 :         while( (p < mpPtr) && (pOut < aHexBuf+sizeof(aHexBuf)-4)) {
    1958             :             // convert each byte to hex
    1959           0 :             char cNibble = (*p >> 4) & 0x0F;
    1960           0 :             cNibble += (cNibble < 10) ? '0' : 'A'-10;
    1961           0 :             *(pOut++) = cNibble;
    1962           0 :             cNibble = *(p++) & 0x0F;
    1963           0 :             cNibble += (cNibble < 10) ? '0' : 'A'-10;
    1964           0 :             *(pOut++) = cNibble;
    1965             :             // limit the line length
    1966           0 :             if( (++mnHexLineCol & 0x3F) == 0)
    1967           0 :                 *(pOut++) = '\n';
    1968             :         }
    1969             :         // writeout hex-converted chunk
    1970           0 :         emitRawData( aHexBuf, pOut-aHexBuf);
    1971             :     }
    1972             :     // reset the raw buffer
    1973           0 :     mpPtr = maBuffer;
    1974           0 : }
    1975             : 
    1976             : // --------------------------------------------------------------------
    1977             : 
    1978           0 : void Type1Emitter::emitAllCrypted( void)
    1979             : {
    1980             :     // apply t1crypt
    1981           0 :     for( char* p = maBuffer; p < mpPtr; ++p) {
    1982           0 :         *p ^= (mnEECryptR >> 8);
    1983           0 :         mnEECryptR = (*(U8*)p + mnEECryptR) * 52845 + 22719;
    1984             :     }
    1985             : 
    1986             :     // emit the t1crypt result
    1987           0 :     if( mbPfbSubset)
    1988           0 :         emitAllRaw();
    1989             :     else
    1990           0 :         emitAllHex();
    1991           0 : }
    1992             : 
    1993             : // --------------------------------------------------------------------
    1994             : 
    1995             : // #i110387# quick-and-dirty double->ascii conversion
    1996             : // needed because sprintf/ecvt/etc. alone are too localized (LC_NUMERIC)
    1997             : // also strip off trailing zeros in fraction while we are at it
    1998           0 : inline int dbl2str( char* pOut, double fVal, int nPrecision=6)
    1999             : {
    2000           0 :     const int nLen = psp::getValueOfDouble( pOut, fVal, nPrecision);
    2001           0 :     return nLen;
    2002             : }
    2003             : 
    2004             : // --------------------------------------------------------------------
    2005             : 
    2006           0 : void Type1Emitter::emitValVector( const char* pLineHead, const char* pLineTail,
    2007             :     const ValVector& rVector)
    2008             : {
    2009             :     // ignore empty vectors
    2010           0 :     if( rVector.empty())
    2011           0 :         return;
    2012             : 
    2013             :     // emit the line head
    2014           0 :     mpPtr += sprintf( mpPtr, "%s", pLineHead);
    2015             :     // emit the vector values
    2016           0 :     ValVector::value_type aVal = 0;
    2017           0 :     for( ValVector::const_iterator it = rVector.begin();;) {
    2018           0 :         aVal = *it;
    2019           0 :         if( ++it == rVector.end() )
    2020           0 :             break;
    2021           0 :         mpPtr += dbl2str( mpPtr, aVal);
    2022           0 :         *(mpPtr++) = ' ';
    2023             :     }
    2024             :     // emit the last value
    2025           0 :     mpPtr += dbl2str( mpPtr, aVal);
    2026             :     // emit the line tail
    2027           0 :     mpPtr += sprintf( mpPtr, "%s", pLineTail);
    2028             : }
    2029             : 
    2030             : // --------------------------------------------------------------------
    2031             : 
    2032           0 : bool CffSubsetterContext::emitAsType1( Type1Emitter& rEmitter,
    2033             :     const long* pReqGlyphIDs, const U8* pReqEncoding,
    2034             :     GlyphWidth* pGlyphWidths, int nGlyphCount, FontSubsetInfo& rFSInfo)
    2035             : {
    2036             :     // prepare some fontdirectory details
    2037             :     static const int nUniqueIdBase = 4100000; // using private-interchange UniqueIds
    2038             :     static int nUniqueId = nUniqueIdBase;
    2039           0 :     ++nUniqueId;
    2040             : 
    2041           0 :     char* pFontName = rEmitter.maSubsetName;
    2042           0 :     if( !*pFontName ) {
    2043           0 :         if( mnFontNameSID) {
    2044             :             // get the fontname directly if available
    2045           0 :             strncpy( pFontName, getString( mnFontNameSID), sizeof(rEmitter.maSubsetName) - 1);
    2046           0 :             pFontName[sizeof(rEmitter.maSubsetName) - 1] = 0;
    2047           0 :         } else if( mnFullNameSID) {
    2048             :             // approximate fontname as fullname-whitespace
    2049           0 :             const char* pI = getString( mnFullNameSID);
    2050           0 :             char* pO = pFontName;
    2051           0 :             const char* pLimit = pFontName + sizeof(rEmitter.maSubsetName) - 1;
    2052           0 :             while( pO < pLimit) {
    2053           0 :                 const char c = *(pI++);
    2054           0 :                 if( c != ' ')
    2055           0 :                     *(pO++) = c;
    2056           0 :                 if( !c)
    2057           0 :                     break;
    2058             :             }
    2059           0 :             *pO = '\0';
    2060             :         } else {
    2061             :             // fallback name of last resort
    2062           0 :             strncpy( pFontName, "DummyName", sizeof(rEmitter.maSubsetName));
    2063             :         }
    2064             :     }
    2065           0 :     const char* pFullName = pFontName;
    2066           0 :     const char* pFamilyName = pFontName;
    2067             : 
    2068           0 :     char*& pOut = rEmitter.mpPtr; // convenience reference, TODO: cleanup
    2069             : 
    2070             :     // create a PFB+Type1 header
    2071           0 :     if( rEmitter.mbPfbSubset ) {
    2072             :         static const char aPfbHeader[] = "\x80\x01\x00\x00\x00\x00";
    2073           0 :         rEmitter.emitRawData( aPfbHeader, sizeof(aPfbHeader)-1);
    2074             :     }
    2075             : 
    2076           0 :     pOut += sprintf( pOut, "%%!FontType1-1.0: %s 001.003\n", rEmitter.maSubsetName);
    2077             :     // emit TOPDICT
    2078             :     pOut += sprintf( pOut,
    2079             :         "11 dict begin\n"   // TODO: dynamic entry count for TOPDICT
    2080             :         "/FontType 1 def\n"
    2081           0 :         "/PaintType 0 def\n");
    2082           0 :     pOut += sprintf( pOut, "/FontName /%s def\n", rEmitter.maSubsetName);
    2083           0 :     pOut += sprintf( pOut, "/UniqueID %d def\n", nUniqueId);
    2084             :     // emit FontMatrix
    2085           0 :     if( maFontMatrix.size() == 6)
    2086           0 :         rEmitter.emitValVector( "/FontMatrix [", "]readonly def\n", maFontMatrix);
    2087             :     else // emit default FontMatrix if needed
    2088           0 :         pOut += sprintf( pOut, "/FontMatrix [0.001 0 0 0.001 0 0]readonly def\n");
    2089             :     // emit FontBBox
    2090           0 :     if( maFontBBox.size() == 4)
    2091           0 :         rEmitter.emitValVector( "/FontBBox {", "}readonly def\n", maFontBBox);
    2092             :     else // emit default FontBBox if needed
    2093           0 :         pOut += sprintf( pOut, "/FontBBox {0 0 999 999}readonly def\n");
    2094             :     // emit FONTINFO into TOPDICT
    2095             :     pOut += sprintf( pOut,
    2096             :         "/FontInfo 2 dict dup begin\n"  // TODO: check fontinfo entry count
    2097             :         " /FullName (%s) readonly def\n"
    2098             :         " /FamilyName (%s) readonly def\n"
    2099             :         "end readonly def\n",
    2100           0 :             pFullName, pFamilyName);
    2101             : 
    2102             :     pOut += sprintf( pOut,
    2103             :         "/Encoding 256 array\n"
    2104           0 :         "0 1 255 {1 index exch /.notdef put} for\n");
    2105           0 :     for( int i = 1; (i < nGlyphCount) && (i < 256); ++i) {
    2106           0 :         const char* pGlyphName = getGlyphName( pReqGlyphIDs[i]);
    2107           0 :         pOut += sprintf( pOut, "dup %d /%s put\n", pReqEncoding[i], pGlyphName);
    2108             :     }
    2109           0 :     pOut += sprintf( pOut, "readonly def\n");
    2110             :     pOut += sprintf( pOut,
    2111             :         // TODO: more topdict entries
    2112             :         "currentdict end\n"
    2113           0 :         "currentfile eexec\n");
    2114             : 
    2115             :     // emit PFB header
    2116           0 :     rEmitter.emitAllRaw();
    2117           0 :     if( rEmitter.mbPfbSubset) {
    2118             :         // update PFB header segment
    2119           0 :         const int nPfbHeaderLen = rEmitter.tellPos() - 6;
    2120           0 :         rEmitter.updateLen( 2, nPfbHeaderLen);
    2121             : 
    2122             :         // prepare start of eexec segment
    2123           0 :         rEmitter.emitRawData( "\x80\x02\x00\x00\x00\x00", 6);   // segment start
    2124             :     }
    2125           0 :     const int nEExecSegTell = rEmitter.tellPos();
    2126             : 
    2127             :     // which always starts with a privdict
    2128             :     // count the privdict entries
    2129           0 :     int nPrivEntryCount = 9;
    2130             : #if !defined(IGNORE_HINTS)
    2131             :     // emit blue hints only if non-default values
    2132           0 :     nPrivEntryCount += !mpCffLocal->maOtherBlues.empty();
    2133           0 :     nPrivEntryCount += !mpCffLocal->maFamilyBlues.empty();
    2134           0 :     nPrivEntryCount += !mpCffLocal->maFamilyOtherBlues.empty();
    2135           0 :     nPrivEntryCount += (mpCffLocal->mfBlueScale != 0.0);
    2136           0 :     nPrivEntryCount += (mpCffLocal->mfBlueShift != 0.0);
    2137           0 :     nPrivEntryCount += (mpCffLocal->mfBlueFuzz != 0.0);
    2138             :     // emit stem hints only if non-default values
    2139           0 :     nPrivEntryCount += (mpCffLocal->maStemStdHW != 0);
    2140           0 :     nPrivEntryCount += (mpCffLocal->maStemStdVW != 0);
    2141           0 :     nPrivEntryCount += !mpCffLocal->maStemSnapH.empty();
    2142           0 :     nPrivEntryCount += !mpCffLocal->maStemSnapV.empty();
    2143             :     // emit other hints only if non-default values
    2144           0 :     nPrivEntryCount += (mpCffLocal->mfExpFactor != 0.0);
    2145           0 :     nPrivEntryCount += (mpCffLocal->mnLangGroup != 0);
    2146           0 :     nPrivEntryCount += (mpCffLocal->mnLangGroup == 1);
    2147           0 :     nPrivEntryCount += (mpCffLocal->mbForceBold != false);
    2148             : #endif // IGNORE_HINTS
    2149             :     // emit the privdict header
    2150             :     pOut += sprintf( pOut,
    2151             :         "\110\104\125 "
    2152             :         "dup\n/Private %d dict dup begin\n"
    2153             :         "/RD{string currentfile exch readstring pop}executeonly def\n"
    2154             :         "/ND{noaccess def}executeonly def\n"
    2155             :         "/NP{noaccess put}executeonly def\n"
    2156             :         "/MinFeature{16 16}ND\n"
    2157             :         "/password 5839 def\n",     // TODO: mnRDCryptSeed?
    2158           0 :             nPrivEntryCount);
    2159             : 
    2160             : #if defined(IGNORE_HINTS)
    2161             :     pOut += sprintf( pOut, "/BlueValues []ND\n");   // BlueValues are mandatory
    2162             : #else
    2163             :     // emit blue hint related privdict entries
    2164           0 :     if( !mpCffLocal->maBlueValues.empty())
    2165           0 :         rEmitter.emitValVector( "/BlueValues [", "]ND\n", mpCffLocal->maBlueValues);
    2166             :     else
    2167           0 :         pOut += sprintf( pOut, "/BlueValues []ND\n"); // default to empty BlueValues
    2168           0 :     rEmitter.emitValVector( "/OtherBlues [", "]ND\n", mpCffLocal->maOtherBlues);
    2169           0 :     rEmitter.emitValVector( "/FamilyBlues [", "]ND\n", mpCffLocal->maFamilyBlues);
    2170           0 :     rEmitter.emitValVector( "/FamilyOtherBlues [", "]ND\n", mpCffLocal->maFamilyOtherBlues);
    2171             : 
    2172           0 :     if( mpCffLocal->mfBlueScale) {
    2173           0 :         pOut += sprintf( pOut, "/BlueScale ");
    2174           0 :         pOut += dbl2str( pOut, mpCffLocal->mfBlueScale, 6);
    2175           0 :         pOut += sprintf( pOut, " def\n");
    2176             :     }
    2177           0 :     if( mpCffLocal->mfBlueShift) {  // default BlueShift==7
    2178           0 :         pOut += sprintf( pOut, "/BlueShift ");
    2179           0 :         pOut += dbl2str( pOut, mpCffLocal->mfBlueShift);
    2180           0 :         pOut += sprintf( pOut, " def\n");
    2181             :     }
    2182           0 :     if( mpCffLocal->mfBlueFuzz) {       // default BlueFuzz==1
    2183           0 :         pOut += sprintf( pOut, "/BlueFuzz ");
    2184           0 :         pOut += dbl2str( pOut, mpCffLocal->mfBlueFuzz);
    2185           0 :         pOut += sprintf( pOut, " def\n");
    2186             :     }
    2187             : 
    2188             :     // emit stem hint related privdict entries
    2189           0 :     if( mpCffLocal->maStemStdHW) {
    2190           0 :         pOut += sprintf( pOut, "/StdHW [");
    2191           0 :         pOut += dbl2str( pOut, mpCffLocal->maStemStdHW);
    2192           0 :         pOut += sprintf( pOut, "] def\n");
    2193             :     }
    2194           0 :     if( mpCffLocal->maStemStdVW) {
    2195           0 :         pOut += sprintf( pOut, "/StdVW [");
    2196           0 :         pOut += dbl2str( pOut, mpCffLocal->maStemStdVW);
    2197           0 :         pOut += sprintf( pOut, "] def\n");
    2198             :     }
    2199           0 :     rEmitter.emitValVector( "/StemSnapH [", "]ND\n", mpCffLocal->maStemSnapH);
    2200           0 :     rEmitter.emitValVector( "/StemSnapV [", "]ND\n", mpCffLocal->maStemSnapV);
    2201             : 
    2202             :     // emit other hints
    2203           0 :     if( mpCffLocal->mbForceBold)
    2204           0 :         pOut += sprintf( pOut, "/ForceBold true def\n");
    2205           0 :     if( mpCffLocal->mnLangGroup != 0)
    2206           0 :         pOut += sprintf( pOut, "/LanguageGroup %d def\n", mpCffLocal->mnLangGroup);
    2207           0 :     if( mpCffLocal->mnLangGroup == 1) // compatibility with ancient printers
    2208           0 :         pOut += sprintf( pOut, "/RndStemUp false def\n");
    2209           0 :     if( mpCffLocal->mfExpFactor) {
    2210           0 :         pOut += sprintf( pOut, "/ExpansionFactor ");
    2211           0 :         pOut += dbl2str( pOut, mpCffLocal->mfExpFactor);
    2212           0 :         pOut += sprintf( pOut, " def\n");
    2213             :     }
    2214             : #endif // IGNORE_HINTS
    2215             : 
    2216             :     // emit remaining privdict entries
    2217           0 :     pOut += sprintf( pOut, "/UniqueID %d def\n", nUniqueId);
    2218             :     // TODO?: more privdict entries?
    2219             : 
    2220             :     static const char aOtherSubrs[] =
    2221             :         "/OtherSubrs\n"
    2222             :         "% Dummy code for faking flex hints\n"
    2223             :         "[ {} {} {} {systemdict /internaldict known not {pop 3}\n"
    2224             :         "{1183615869 systemdict /internaldict get exec\n"
    2225             :         "dup /startlock known\n"
    2226             :         "{/startlock get exec}\n"
    2227             :         "{dup /strtlck known\n"
    2228             :         "{/strtlck get exec}\n"
    2229             :         "{pop 3}\nifelse}\nifelse}\nifelse\n} executeonly\n"
    2230             :         "] ND\n";
    2231           0 :     memcpy( pOut, aOtherSubrs, sizeof(aOtherSubrs)-1);
    2232           0 :     pOut += sizeof(aOtherSubrs)-1;
    2233             : 
    2234             :     // emit used GlobalSubr charstrings
    2235             :     // these are the just the default subrs
    2236             :     // TODO: do we need them as the flex hints are resolved differently?
    2237             :     static const char aSubrs[] =
    2238             :         "/Subrs 5 array\n"
    2239             :         "dup 0 15 RD \x5F\x3D\x6B\xAC\x3C\xBD\x74\x3D\x3E\x17\xA0\x86\x58\x08\x85 NP\n"
    2240             :         "dup 1 9 RD \x5F\x3D\x6B\xD8\xA6\xB5\x68\xB6\xA2 NP\n"
    2241             :         "dup 2 9 RD \x5F\x3D\x6B\xAC\x39\x46\xB9\x43\xF9 NP\n"
    2242             :         "dup 3 5 RD \x5F\x3D\x6B\xAC\xB9 NP\n"
    2243             :         "dup 4 12 RD \x5F\x3D\x6B\xAC\x3E\x5D\x48\x54\x62\x76\x39\x03 NP\n"
    2244             :         "ND\n";
    2245           0 :     memcpy( pOut, aSubrs, sizeof(aSubrs)-1);
    2246           0 :     pOut += sizeof(aSubrs)-1;
    2247             : 
    2248             :     // TODO: emit more GlobalSubr charstrings?
    2249             :     // TODO: emit used LocalSubr charstrings?
    2250             : 
    2251             :     // emit the CharStrings for the requested glyphs
    2252             :     pOut += sprintf( pOut,
    2253           0 :         "2 index /CharStrings %d dict dup begin\n", nGlyphCount);
    2254           0 :     rEmitter.emitAllCrypted();
    2255           0 :     for( int i = 0; i < nGlyphCount; ++i) {
    2256           0 :         const int nGlyphId = pReqGlyphIDs[i];
    2257             :         assert( (nGlyphId >= 0) && (nGlyphId < mnCharStrCount));
    2258             :         // get privdict context matching to the glyph
    2259           0 :         const int nFDSelect = getFDSelect( nGlyphId);
    2260           0 :         mpCffLocal = &maCffLocal[ nFDSelect];
    2261             :         // convert the Type2op charstring to its Type1op counterpart
    2262           0 :         const int nT2Len = seekIndexData( mnCharStrBase, nGlyphId);
    2263             :         assert( nT2Len > 0);
    2264             :         U8 aType1Ops[ MAX_T1OPS_SIZE]; // TODO: dynamic allocation
    2265           0 :         const int nT1Len = convert2Type1Ops( mpCffLocal, mpReadPtr, nT2Len, aType1Ops);
    2266             :         // get the glyph name
    2267           0 :         const char* pGlyphName = getGlyphName( nGlyphId);
    2268             :         // emit the encrypted Type1op charstring
    2269           0 :         pOut += sprintf( pOut, "/%s %d RD ", pGlyphName, nT1Len);
    2270           0 :         memcpy( pOut, aType1Ops, nT1Len);
    2271           0 :         pOut += nT1Len;
    2272           0 :         pOut += sprintf( pOut, " ND\n");
    2273           0 :         rEmitter.emitAllCrypted();
    2274             :         // provide individual glyphwidths if requested
    2275           0 :         if( pGlyphWidths ) {
    2276           0 :             ValType aCharWidth = getCharWidth();
    2277           0 :             if( maFontMatrix.size() >= 4)
    2278           0 :                 aCharWidth *= 1000.0F * maFontMatrix[0];
    2279           0 :             pGlyphWidths[i] = static_cast<GlyphWidth>(aCharWidth);
    2280             :         }
    2281             :     }
    2282           0 :     pOut += sprintf( pOut, "end end\nreadonly put\nput\n");
    2283           0 :     pOut += sprintf( pOut, "dup/FontName get exch definefont pop\n");
    2284           0 :     pOut += sprintf( pOut, "mark currentfile closefile\n");
    2285           0 :     rEmitter.emitAllCrypted();
    2286             : 
    2287             :     // mark stop of eexec encryption
    2288           0 :      if( rEmitter.mbPfbSubset) {
    2289           0 :         const int nEExecLen = rEmitter.tellPos() - nEExecSegTell;
    2290           0 :         rEmitter.updateLen( nEExecSegTell-4, nEExecLen);
    2291             :      }
    2292             : 
    2293             :     // create PFB footer
    2294             :     static const char aPfxFooter[] = "\x80\x01\x14\x02\x00\x00\n" // TODO: check segment len
    2295             :         "0000000000000000000000000000000000000000000000000000000000000000\n"
    2296             :         "0000000000000000000000000000000000000000000000000000000000000000\n"
    2297             :         "0000000000000000000000000000000000000000000000000000000000000000\n"
    2298             :         "0000000000000000000000000000000000000000000000000000000000000000\n"
    2299             :         "0000000000000000000000000000000000000000000000000000000000000000\n"
    2300             :         "0000000000000000000000000000000000000000000000000000000000000000\n"
    2301             :         "0000000000000000000000000000000000000000000000000000000000000000\n"
    2302             :         "0000000000000000000000000000000000000000000000000000000000000000\n"
    2303             :         "cleartomark\n"
    2304             :         "\x80\x03";
    2305           0 :      if( rEmitter.mbPfbSubset)
    2306           0 :         rEmitter.emitRawData( aPfxFooter, sizeof(aPfxFooter)-1);
    2307             :     else
    2308           0 :         rEmitter.emitRawData( aPfxFooter+6, sizeof(aPfxFooter)-9);
    2309             : 
    2310             :     // provide details to the subset requesters, TODO: move into own method?
    2311             :     // note: Top and Bottom are flipped between Type1 and VCL
    2312             :     // note: the rest of VCL expects the details below to be scaled like for an emUnits==1000 font
    2313           0 :     ValType fXFactor = 1.0;
    2314           0 :     ValType fYFactor = 1.0;
    2315           0 :     if( maFontMatrix.size() >= 4) {
    2316           0 :         fXFactor = 1000.0F * maFontMatrix[0];
    2317           0 :         fYFactor = 1000.0F * maFontMatrix[3];
    2318             :     }
    2319           0 :     rFSInfo.m_aFontBBox = Rectangle( Point( static_cast<long>(maFontBBox[0] * fXFactor),
    2320           0 :                                         static_cast<long>(maFontBBox[1] * fYFactor) ),
    2321           0 :                                     Point( static_cast<long>(maFontBBox[2] * fXFactor),
    2322           0 :                                         static_cast<long>(maFontBBox[3] * fYFactor) ) );
    2323             :     // PDF-Spec says the values below mean the ink bounds!
    2324             :     // TODO: use better approximations for these ink bounds
    2325           0 :     rFSInfo.m_nAscent  = +rFSInfo.m_aFontBBox.Bottom(); // for capital letters
    2326           0 :     rFSInfo.m_nDescent = -rFSInfo.m_aFontBBox.Top();    // for all letters
    2327           0 :     rFSInfo.m_nCapHeight = rFSInfo.m_nAscent;           // for top-flat capital letters
    2328             : 
    2329           0 :     rFSInfo.m_nFontType = rEmitter.mbPfbSubset ? FontSubsetInfo::TYPE1_PFB : FontSubsetInfo::TYPE1_PFA;
    2330           0 :     rFSInfo.m_aPSName   = String( rEmitter.maSubsetName, RTL_TEXTENCODING_UTF8 );
    2331             : 
    2332           0 :     return true;
    2333             : }
    2334             : 
    2335             : // ====================================================================
    2336             : 
    2337           0 : bool FontSubsetInfo::CreateFontSubsetFromCff( GlyphWidth* pOutGlyphWidths )
    2338             : {
    2339           0 :     CffSubsetterContext aCff( mpInFontBytes, mnInByteLength);
    2340           0 :     aCff.initialCffRead();
    2341             : 
    2342             :     // emit Type1 subset from the CFF input
    2343             :     // TODO: also support CFF->CFF subsetting (when PDF-export and PS-printing need it)
    2344           0 :     const bool bPfbSubset = (0 != (mnReqFontTypeMask & FontSubsetInfo::TYPE1_PFB));
    2345           0 :     Type1Emitter aType1Emitter( mpOutFile, bPfbSubset);
    2346           0 :     aType1Emitter.setSubsetName( mpReqFontName);
    2347             :     bool bRC = aCff.emitAsType1( aType1Emitter,
    2348             :         mpReqGlyphIds, mpReqEncodedIds,
    2349           0 :         pOutGlyphWidths, mnReqGlyphCount, *this);
    2350           0 :     return bRC;
    2351             : }
    2352             : 
    2353             : // ====================================================================
    2354             : 
    2355             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10