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