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