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