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