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