xref: /AOO41X/main/vcl/source/fontsubset/cff.cxx (revision 41919c97b323a66d7e3a6686c38c568ed6a52cd0)
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 sal_GlyphId* 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 sal_GlyphId* 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 long nCurrPos = ftell( mpFileOut);
1975     fseek( mpFileOut, nTellPos, SEEK_SET);
1976     fwrite( cData, 1, sizeof(cData), mpFileOut);
1977     if( nCurrPos >= 0)
1978         fseek( mpFileOut, nCurrPos, SEEK_SET);
1979 }
1980 
1981 // --------------------------------------------------------------------
1982 
1983 inline void Type1Emitter::emitRawData( const char* pData, int nLength) const
1984 {
1985     fwrite( pData, 1, nLength, mpFileOut);
1986 }
1987 
1988 // --------------------------------------------------------------------
1989 
1990 inline void Type1Emitter::emitAllRaw( void)
1991 {
1992     // writeout raw data
1993     assert( (mpPtr - maBuffer) < (int)sizeof(maBuffer));
1994     emitRawData( maBuffer, mpPtr - maBuffer);
1995     // reset the raw buffer
1996     mpPtr = maBuffer;
1997 }
1998 
1999 // --------------------------------------------------------------------
2000 
2001 inline void Type1Emitter::emitAllHex( void)
2002 {
2003     assert( (mpPtr - maBuffer) < (int)sizeof(maBuffer));
2004     for( const char* p = maBuffer; p < mpPtr;) {
2005         // convert binary chunk to hex
2006         char aHexBuf[0x4000];
2007         char* pOut = aHexBuf;
2008         while( (p < mpPtr) && (pOut < aHexBuf+sizeof(aHexBuf)-4)) {
2009             // convert each byte to hex
2010             char cNibble = (*p >> 4) & 0x0F;
2011             cNibble += (cNibble < 10) ? '0' : 'A'-10;
2012             *(pOut++) = cNibble;
2013             cNibble = *(p++) & 0x0F;
2014             cNibble += (cNibble < 10) ? '0' : 'A'-10;
2015             *(pOut++) = cNibble;
2016             // limit the line length
2017             if( (++mnHexLineCol & 0x3F) == 0)
2018                 *(pOut++) = '\n';
2019         }
2020         // writeout hex-converted chunk
2021         emitRawData( aHexBuf, pOut-aHexBuf);
2022     }
2023     // reset the raw buffer
2024     mpPtr = maBuffer;
2025 }
2026 
2027 // --------------------------------------------------------------------
2028 
2029 void Type1Emitter::emitAllCrypted( void)
2030 {
2031     // apply t1crypt
2032     for( char* p = maBuffer; p < mpPtr; ++p) {
2033         *p ^= (mnEECryptR >> 8);
2034         mnEECryptR = (*(U8*)p + mnEECryptR) * 52845 + 22719;
2035     }
2036 
2037     // emit the t1crypt result
2038     if( mbPfbSubset)
2039         emitAllRaw();
2040     else
2041         emitAllHex();
2042 }
2043 
2044 // --------------------------------------------------------------------
2045 
2046 // #i110387# quick-and-dirty double->ascii conversion
2047 // needed because sprintf/ecvt/etc. alone are too localized (LC_NUMERIC)
2048 // also strip off trailing zeros in fraction while we are at it
2049 inline int dbl2str( char* pOut, double fVal, int nPrecision=6)
2050 {
2051     const int nLen = psp::getValueOfDouble( pOut, fVal, nPrecision);
2052     return nLen;
2053 }
2054 
2055 // --------------------------------------------------------------------
2056 
2057 void Type1Emitter::emitValVector( const char* pLineHead, const char* pLineTail,
2058     const ValVector& rVector)
2059 {
2060     // ignore empty vectors
2061     if( rVector.empty())
2062         return;
2063 
2064     // emit the line head
2065     mpPtr += sprintf( mpPtr, pLineHead);
2066     // emit the vector values
2067     ValVector::value_type aVal = 0;
2068     for( ValVector::const_iterator it = rVector.begin();;) {
2069         aVal = *it;
2070         if( ++it == rVector.end() )
2071             break;
2072         mpPtr += dbl2str( mpPtr, aVal);
2073         *(mpPtr++) = ' ';
2074     }
2075     // emit the last value
2076     mpPtr += dbl2str( mpPtr, aVal);
2077     // emit the line tail
2078     mpPtr += sprintf( mpPtr, pLineTail);
2079 }
2080 
2081 // --------------------------------------------------------------------
2082 
2083 bool CffSubsetterContext::emitAsType1( Type1Emitter& rEmitter,
2084     const sal_GlyphId* pReqGlyphIds, const U8* pReqEncoding,
2085     GlyphWidth* pGlyphWidths, int nGlyphCount, FontSubsetInfo& rFSInfo)
2086 {
2087     // prepare some fontdirectory details
2088     static const int nUniqueIdBase = 4100000; // using private-interchange UniqueIds
2089     static int nUniqueId = nUniqueIdBase;
2090     ++nUniqueId;
2091 
2092     char* pFontName = rEmitter.maSubsetName;
2093     if( !*pFontName ) {
2094         if( mnFontNameSID) {
2095             // get the fontname directly if available
2096             strncpy( pFontName, getString( mnFontNameSID), sizeof(rEmitter.maSubsetName));
2097         } else if( mnFullNameSID) {
2098             // approximate fontname as fullname-whitespace
2099             const char* pI = getString( mnFullNameSID);
2100             char* pO = pFontName;
2101             const char* pLimit = pFontName + sizeof(rEmitter.maSubsetName) - 1;
2102             while( pO < pLimit) {
2103                 const char c = *(pI++);
2104                 if( c != ' ')
2105                     *(pO++) = c;
2106                 if( !c)
2107                     break;
2108             }
2109             *pO = '\0';
2110         } else {
2111             // fallback name of last resort
2112             strncpy( pFontName, "DummyName", sizeof(rEmitter.maSubsetName));
2113         }
2114     }
2115     const char* pFullName = pFontName;
2116     const char* pFamilyName = pFontName;
2117 
2118     char*& pOut = rEmitter.mpPtr; // convenience reference, TODO: cleanup
2119 
2120     // create a PFB+Type1 header
2121     if( rEmitter.mbPfbSubset ) {
2122         static const char aPfbHeader[] = "\x80\x01\x00\x00\x00\x00";
2123         rEmitter.emitRawData( aPfbHeader, sizeof(aPfbHeader)-1);
2124     }
2125 
2126     pOut += sprintf( pOut, "%%!FontType1-1.0: %s 001.003\n", rEmitter.maSubsetName);
2127     // emit TOPDICT
2128 #if 0 // improve PS Type1 caching?
2129     nOfs += sprintf( &aT1Str[nOfs],
2130         "FontDirectory/%s known{/%s findfont dup/UniqueID known{dup\n"
2131         "/UniqueID get %d eq exch/FontType get 1 eq and}{pop false}ifelse\n"
2132         "{save true}{false}ifelse}\n{false}ifelse\n",
2133             pFamilyName, pFamilyName, nUniqueId);
2134 #endif
2135     pOut += sprintf( pOut,
2136         "11 dict begin\n"   // TODO: dynamic entry count for TOPDICT
2137         "/FontType 1 def\n"
2138         "/PaintType 0 def\n");
2139     pOut += sprintf( pOut, "/FontName /%s def\n", rEmitter.maSubsetName);
2140     pOut += sprintf( pOut, "/UniqueID %d def\n", nUniqueId);
2141     // emit FontMatrix
2142     if( maFontMatrix.size() == 6)
2143         rEmitter.emitValVector( "/FontMatrix [", "]readonly def\n", maFontMatrix);
2144     else // emit default FontMatrix if needed
2145         pOut += sprintf( pOut, "/FontMatrix [0.001 0 0 0.001 0 0]readonly def\n");
2146     // emit FontBBox
2147     if( maFontBBox.size() == 4)
2148         rEmitter.emitValVector( "/FontBBox {", "}readonly def\n", maFontBBox);
2149     else // emit default FontBBox if needed
2150         pOut += sprintf( pOut, "/FontBBox {0 0 999 999}readonly def\n");
2151     // emit FONTINFO into TOPDICT
2152     pOut += sprintf( pOut,
2153         "/FontInfo 2 dict dup begin\n"  // TODO: check fontinfo entry count
2154         " /FullName (%s) readonly def\n"
2155         " /FamilyName (%s) readonly def\n"
2156         "end readonly def\n",
2157             pFullName, pFamilyName);
2158 #if 0   // TODO: use an standard Type1 encoding if possible
2159     pOut += sprintf( pOut,
2160         "/Encoding StandardEncoding def\n");
2161 #else
2162     pOut += sprintf( pOut,
2163         "/Encoding 256 array\n"
2164         "0 1 255 {1 index exch /.notdef put} for\n");
2165     for( int i = 1; (i < nGlyphCount) && (i < 256); ++i) {
2166         const char* pGlyphName = getGlyphName( pReqGlyphIds[i]);
2167         pOut += sprintf( pOut, "dup %d /%s put\n", pReqEncoding[i], pGlyphName);
2168     }
2169     pOut += sprintf( pOut, "readonly def\n");
2170 #endif
2171     pOut += sprintf( pOut,
2172         // TODO: more topdict entries
2173         "currentdict end\n"
2174         "currentfile eexec\n");
2175 
2176     // emit PFB header
2177     rEmitter.emitAllRaw();
2178     if( rEmitter.mbPfbSubset) {
2179         // update PFB header segment
2180         const int nPfbHeaderLen = rEmitter.tellPos() - 6;
2181         rEmitter.updateLen( 2, nPfbHeaderLen);
2182 
2183         // prepare start of eexec segment
2184         rEmitter.emitRawData( "\x80\x02\x00\x00\x00\x00", 6);   // segment start
2185     }
2186     const int nEExecSegTell = rEmitter.tellPos();
2187 
2188     // which always starts with a privdict
2189     // count the privdict entries
2190     int nPrivEntryCount = 9;
2191 #if !defined(IGNORE_HINTS)
2192     // emit blue hints only if non-default values
2193     nPrivEntryCount += !mpCffLocal->maOtherBlues.empty();
2194     nPrivEntryCount += !mpCffLocal->maFamilyBlues.empty();
2195     nPrivEntryCount += !mpCffLocal->maFamilyOtherBlues.empty();
2196     nPrivEntryCount += (mpCffLocal->mfBlueScale != 0.0);
2197     nPrivEntryCount += (mpCffLocal->mfBlueShift != 0.0);
2198     nPrivEntryCount += (mpCffLocal->mfBlueFuzz != 0.0);
2199     // emit stem hints only if non-default values
2200     nPrivEntryCount += (mpCffLocal->maStemStdHW != 0);
2201     nPrivEntryCount += (mpCffLocal->maStemStdVW != 0);
2202     nPrivEntryCount += !mpCffLocal->maStemSnapH.empty();
2203     nPrivEntryCount += !mpCffLocal->maStemSnapV.empty();
2204     // emit other hints only if non-default values
2205     nPrivEntryCount += (mpCffLocal->mfExpFactor != 0.0);
2206     nPrivEntryCount += (mpCffLocal->mnLangGroup != 0);
2207     nPrivEntryCount += (mpCffLocal->mnLangGroup == 1);
2208     nPrivEntryCount += (mpCffLocal->mbForceBold != false);
2209 #endif // IGNORE_HINTS
2210     // emit the privdict header
2211     pOut += sprintf( pOut,
2212         "\110\104\125 "
2213         "dup\n/Private %d dict dup begin\n"
2214         "/RD{string currentfile exch readstring pop}executeonly def\n"
2215         "/ND{noaccess def}executeonly def\n"
2216         "/NP{noaccess put}executeonly def\n"
2217         "/MinFeature{16 16}ND\n"
2218         "/password 5839 def\n",     // TODO: mnRDCryptSeed?
2219             nPrivEntryCount);
2220 
2221 #if defined(IGNORE_HINTS)
2222     pOut += sprintf( pOut, "/BlueValues []ND\n");   // BlueValues are mandatory
2223 #else
2224     // emit blue hint related privdict entries
2225     if( !mpCffLocal->maBlueValues.empty())
2226         rEmitter.emitValVector( "/BlueValues [", "]ND\n", mpCffLocal->maBlueValues);
2227     else
2228         pOut += sprintf( pOut, "/BlueValues []ND\n"); // default to empty BlueValues
2229     rEmitter.emitValVector( "/OtherBlues [", "]ND\n", mpCffLocal->maOtherBlues);
2230     rEmitter.emitValVector( "/FamilyBlues [", "]ND\n", mpCffLocal->maFamilyBlues);
2231     rEmitter.emitValVector( "/FamilyOtherBlues [", "]ND\n", mpCffLocal->maFamilyOtherBlues);
2232 
2233     if( mpCffLocal->mfBlueScale) {
2234         pOut += sprintf( pOut, "/BlueScale ");
2235         pOut += dbl2str( pOut, mpCffLocal->mfBlueScale, 6);
2236         pOut += sprintf( pOut, " def\n");
2237     }
2238     if( mpCffLocal->mfBlueShift) {  // default BlueShift==7
2239         pOut += sprintf( pOut, "/BlueShift ");
2240         pOut += dbl2str( pOut, mpCffLocal->mfBlueShift);
2241         pOut += sprintf( pOut, " def\n");
2242     }
2243     if( mpCffLocal->mfBlueFuzz) {       // default BlueFuzz==1
2244         pOut += sprintf( pOut, "/BlueFuzz ");
2245         pOut += dbl2str( pOut, mpCffLocal->mfBlueFuzz);
2246         pOut += sprintf( pOut, " def\n");
2247     }
2248 
2249     // emit stem hint related privdict entries
2250     if( mpCffLocal->maStemStdHW) {
2251         pOut += sprintf( pOut, "/StdHW [");
2252         pOut += dbl2str( pOut, mpCffLocal->maStemStdHW);
2253         pOut += sprintf( pOut, "] def\n");
2254     }
2255     if( mpCffLocal->maStemStdVW) {
2256         pOut += sprintf( pOut, "/StdVW [");
2257         pOut += dbl2str( pOut, mpCffLocal->maStemStdVW);
2258         pOut += sprintf( pOut, "] def\n");
2259     }
2260     rEmitter.emitValVector( "/StemSnapH [", "]ND\n", mpCffLocal->maStemSnapH);
2261     rEmitter.emitValVector( "/StemSnapV [", "]ND\n", mpCffLocal->maStemSnapV);
2262 
2263     // emit other hints
2264     if( mpCffLocal->mbForceBold)
2265         pOut += sprintf( pOut, "/ForceBold true def\n");
2266     if( mpCffLocal->mnLangGroup != 0)
2267         pOut += sprintf( pOut, "/LanguageGroup %d def\n", mpCffLocal->mnLangGroup);
2268     if( mpCffLocal->mnLangGroup == 1) // compatibility with ancient printers
2269         pOut += sprintf( pOut, "/RndStemUp false def\n");
2270     if( mpCffLocal->mfExpFactor) {
2271         pOut += sprintf( pOut, "/ExpansionFactor ");
2272         pOut += dbl2str( pOut, mpCffLocal->mfExpFactor);
2273         pOut += sprintf( pOut, " def\n");
2274     }
2275 #endif // IGNORE_HINTS
2276 
2277     // emit remaining privdict entries
2278     pOut += sprintf( pOut, "/UniqueID %d def\n", nUniqueId);
2279     // TODO?: more privdict entries?
2280 
2281     static const char aOtherSubrs[] =
2282         "/OtherSubrs\n"
2283         "% Dummy code for faking flex hints\n"
2284         "[ {} {} {} {systemdict /internaldict known not {pop 3}\n"
2285         "{1183615869 systemdict /internaldict get exec\n"
2286         "dup /startlock known\n"
2287         "{/startlock get exec}\n"
2288         "{dup /strtlck known\n"
2289         "{/strtlck get exec}\n"
2290         "{pop 3}\nifelse}\nifelse}\nifelse\n} executeonly\n"
2291         "] ND\n";
2292     memcpy( pOut, aOtherSubrs, sizeof(aOtherSubrs)-1);
2293     pOut += sizeof(aOtherSubrs)-1;
2294 
2295     // emit used GlobalSubr charstrings
2296     // these are the just the default subrs
2297     // TODO: do we need them as the flex hints are resolved differently?
2298     static const char aSubrs[] =
2299         "/Subrs 5 array\n"
2300         "dup 0 15 RD \x5F\x3D\x6B\xAC\x3C\xBD\x74\x3D\x3E\x17\xA0\x86\x58\x08\x85 NP\n"
2301         "dup 1 9 RD \x5F\x3D\x6B\xD8\xA6\xB5\x68\xB6\xA2 NP\n"
2302         "dup 2 9 RD \x5F\x3D\x6B\xAC\x39\x46\xB9\x43\xF9 NP\n"
2303         "dup 3 5 RD \x5F\x3D\x6B\xAC\xB9 NP\n"
2304         "dup 4 12 RD \x5F\x3D\x6B\xAC\x3E\x5D\x48\x54\x62\x76\x39\x03 NP\n"
2305         "ND\n";
2306     memcpy( pOut, aSubrs, sizeof(aSubrs)-1);
2307     pOut += sizeof(aSubrs)-1;
2308 
2309     // TODO: emit more GlobalSubr charstrings?
2310     // TODO: emit used LocalSubr charstrings?
2311 
2312     // emit the CharStrings for the requested glyphs
2313     pOut += sprintf( pOut,
2314         "2 index /CharStrings %d dict dup begin\n", nGlyphCount);
2315     rEmitter.emitAllCrypted();
2316     for( int i = 0; i < nGlyphCount; ++i) {
2317         const int nCffGlyphId = pReqGlyphIds[i];
2318         assert( (nCffGlyphId >= 0) && (nCffGlyphId < mnCharStrCount));
2319         // get privdict context matching to the glyph
2320         const int nFDSelect = getFDSelect( nCffGlyphId);
2321         if( nFDSelect < 0)
2322             continue;
2323         mpCffLocal = &maCffLocal[ nFDSelect];
2324         // convert the Type2op charstring to its Type1op counterpart
2325         const int nT2Len = seekIndexData( mnCharStrBase, nCffGlyphId);
2326         assert( nT2Len > 0);
2327         U8 aType1Ops[ MAX_T1OPS_SIZE]; // TODO: dynamic allocation
2328         const int nT1Len = convert2Type1Ops( mpCffLocal, mpReadPtr, nT2Len, aType1Ops);
2329         // get the glyph name
2330         const char* pGlyphName = getGlyphName( nCffGlyphId);
2331         // emit the encrypted Type1op charstring
2332         pOut += sprintf( pOut, "/%s %d RD ", pGlyphName, nT1Len);
2333         memcpy( pOut, aType1Ops, nT1Len);
2334         pOut += nT1Len;
2335         pOut += sprintf( pOut, " ND\n");
2336         rEmitter.emitAllCrypted();
2337         // provide individual glyphwidths if requested
2338         if( pGlyphWidths ) {
2339             ValType aCharWidth = getCharWidth();
2340             if( maFontMatrix.size() >= 4)
2341                 aCharWidth *= 1000.0F * maFontMatrix[0];
2342             pGlyphWidths[i] = static_cast<GlyphWidth>(aCharWidth);
2343         }
2344     }
2345     pOut += sprintf( pOut, "end end\nreadonly put\nput\n");
2346     pOut += sprintf( pOut, "dup/FontName get exch definefont pop\n");
2347     pOut += sprintf( pOut, "mark currentfile closefile\n");
2348     rEmitter.emitAllCrypted();
2349 
2350     // mark stop of eexec encryption
2351     if( rEmitter.mbPfbSubset) {
2352         const int nEExecLen = rEmitter.tellPos() - nEExecSegTell;
2353         rEmitter.updateLen( nEExecSegTell-4, nEExecLen);
2354     }
2355 
2356     // create PFB footer
2357     static const char aPfxFooter[] = "\x80\x01\x14\x02\x00\x00\n" // TODO: check segment len
2358         "0000000000000000000000000000000000000000000000000000000000000000\n"
2359         "0000000000000000000000000000000000000000000000000000000000000000\n"
2360         "0000000000000000000000000000000000000000000000000000000000000000\n"
2361         "0000000000000000000000000000000000000000000000000000000000000000\n"
2362         "0000000000000000000000000000000000000000000000000000000000000000\n"
2363         "0000000000000000000000000000000000000000000000000000000000000000\n"
2364         "0000000000000000000000000000000000000000000000000000000000000000\n"
2365         "0000000000000000000000000000000000000000000000000000000000000000\n"
2366         "cleartomark\n"
2367         "\x80\x03";
2368     if( rEmitter.mbPfbSubset)
2369         rEmitter.emitRawData( aPfxFooter, sizeof(aPfxFooter)-1);
2370     else
2371         rEmitter.emitRawData( aPfxFooter+6, sizeof(aPfxFooter)-9);
2372 
2373     // provide details to the subset requesters, TODO: move into own method?
2374     // note: Top and Bottom are flipped between Type1 and VCL
2375     // note: the rest of VCL expects the details below to be scaled like for an emUnits==1000 font
2376     ValType fXFactor = 1.0;
2377     ValType fYFactor = 1.0;
2378     if( maFontMatrix.size() >= 4) {
2379         fXFactor = 1000.0F * maFontMatrix[0];
2380         fYFactor = 1000.0F * maFontMatrix[3];
2381     }
2382     rFSInfo.m_aFontBBox = Rectangle( Point( static_cast<long>(maFontBBox[0] * fXFactor),
2383                                         static_cast<long>(maFontBBox[1] * fYFactor) ),
2384                                     Point( static_cast<long>(maFontBBox[2] * fXFactor),
2385                                         static_cast<long>(maFontBBox[3] * fYFactor) ) );
2386     // PDF-Spec says the values below mean the ink bounds!
2387     // TODO: use better approximations for these ink bounds
2388     rFSInfo.m_nAscent  = +rFSInfo.m_aFontBBox.Bottom(); // for capital letters
2389     rFSInfo.m_nDescent = -rFSInfo.m_aFontBBox.Top();    // for all letters
2390     rFSInfo.m_nCapHeight = rFSInfo.m_nAscent;           // for top-flat capital letters
2391 
2392     rFSInfo.m_nFontType = rEmitter.mbPfbSubset ? FontSubsetInfo::TYPE1_PFB : FontSubsetInfo::TYPE1_PFA;
2393     rFSInfo.m_aPSName   = String( rEmitter.maSubsetName, RTL_TEXTENCODING_UTF8 );
2394 
2395     return true;
2396 }
2397 
2398 // ====================================================================
2399 
2400 bool FontSubsetInfo::CreateFontSubsetFromCff( GlyphWidth* pOutGlyphWidths )
2401 {
2402     CffSubsetterContext aCff( mpInFontBytes, mnInByteLength);
2403     aCff.initialCffRead();
2404 
2405     // emit Type1 subset from the CFF input
2406     // TODO: also support CFF->CFF subsetting (when PDF-export and PS-printing need it)
2407     const bool bPfbSubset = (0 != (mnReqFontTypeMask & FontSubsetInfo::TYPE1_PFB));
2408     Type1Emitter aType1Emitter( mpOutFile, bPfbSubset);
2409     aType1Emitter.setSubsetName( mpReqFontName);
2410     bool bRC = aCff.emitAsType1( aType1Emitter,
2411         mpReqGlyphIds, mpReqEncodedIds,
2412         pOutGlyphWidths, mnReqGlyphCount, *this);
2413     return bRC;
2414 }
2415 
2416 // ====================================================================
2417 
2418