merge the formfield patch from ooo-build
[ooovba.git] / vcl / source / fontsubset / cff.cxx
blob281262b504c4fb9cc48d61896875b85c838c82a3
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2009 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * This file is part of OpenOffice.org.
11 * OpenOffice.org is free software: you can redistribute it and/or modify
12 * it under the terms of the GNU Lesser General Public License version 3
13 * only, as published by the Free Software Foundation.
15 * OpenOffice.org is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU Lesser General Public License version 3 for more details
19 * (a copy is included in the LICENSE file that accompanied this code).
21 * You should have received a copy of the GNU Lesser General Public License
22 * version 3 along with OpenOffice.org. If not, see
23 * <http://www.openoffice.org/license.html>
24 * for a copy of the LGPLv3 License.
26 ************************************************************************/
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_vcl.hxx"
31 #include <cstdio>
32 #include <cstring>
33 #include <assert.h>
35 #include <vcl/fontsubset.hxx>
37 //#define IGNORE_HINTS
39 typedef unsigned char U8;
40 typedef unsigned short U16;
41 typedef long long S64;
43 typedef sal_Int32 GlyphWidth;
45 typedef float RealType;
46 typedef RealType ValType;
47 #include <vector>
48 typedef std::vector<ValType> ValVector;
50 // ====================================================================
52 static const char* pStringIds[] = {
53 /*0*/ ".notdef", "space", "exclam", "quotedbl",
54 "numbersign", "dollar", "percent", "ampersand",
55 "quoteright", "parenleft", "parenright", "asterisk",
56 "plus", "comma", "hyphen", "period",
57 /*16*/ "slash", "zero", "one", "two",
58 "three", "four", "five", "six",
59 "seven", "eight", "nine", "colon",
60 "semicolon", "less", "equal", "greater",
61 /*32*/ "question", "at", "A", "B",
62 "C", "D", "E", "F",
63 "G", "H", "I", "J",
64 "K", "L", "M", "N",
65 /*48*/ "O", "P", "Q", "R",
66 "S", "T", "U", "V",
67 "W", "X", "Y", "Z",
68 "bracketleft", "backslash", "bracketright", "asciicircum",
69 /*64*/ "underscore", "quoteleft", "a", "b",
70 "c", "d", "e", "f",
71 "g", "h", "i", "j",
72 "k", "l", "m", "n",
73 /*80*/ "o", "p", "q", "r",
74 "s", "t", "u", "v",
75 "w", "x", "y", "z",
76 "braceleft", "bar", "braceright", "asciitilde",
77 /*96*/ "exclamdown", "cent", "sterlin", "fraction",
78 "yen", "florin", "section", "currency",
79 "quotesingle", "quotedblleft", "guillemotleft", "guilsinglleft",
80 "guilsinglright", "fi", "fl", "endash",
81 /*112*/ "dagger", "daggerdbl", "periodcentered", "paragraph",
82 "bullet", "quotesinglbase", "quotedblbase", "quotedblright",
83 "guillemotright", "ellipsis", "perthousand", "questiondown",
84 "grave", "acute", "circumflex", "tilde",
85 /*128*/ "macron", "breve", "dotaccent", "dieresis",
86 "ring", "cedilla", "hungarumlaut", "ogonek",
87 "caron", "endash", "AE", "ordfeminine",
88 "Lslash", "Oslash", "OE", "ordmasculine",
89 /*144*/ "ae", "dotlessi", "lslash", "oslash",
90 "oe", "germandbls", "onesuperior", "logicalnot",
91 "mu", "trademark", "Eth", "onehalf",
92 "plusminus", "Thorn", "onequarter", "divide",
93 /*160*/ "brokenbar", "degree", "thorn", "threequarters",
94 "twosuperior", "registered", "minus", "eth",
95 "multiply", "threesuperior", "copyright", "Aacute",
96 "Acircumflex", "Adieresis", "Agrave", "Aring",
97 /*176*/ "Atilde", "Ccedilla", "Eacute", "Ecircumflex",
98 "Edieresis", "Egrave", "Iacute", "Icircumflex",
99 "Idieresis", "Igrave", "Ntilde", "Oacute",
100 "Ocircumflex", "Odieresis", "Ograve", "Otilde",
101 /*192*/ "Scaron", "Uacute", "Ucircumflex", "Udieresis",
102 "Ugrave", "Yacute", "Ydieresis", "Zcaron",
103 "aacute", "acircumflex", "adieresis", "agrave",
104 "aring", "atilde", "ccedilla", "eacute",
105 /*208*/ "ecircumflex", "edieresis", "egrave", "iacute",
106 "icircumflex", "idieresis", "igrave", "ntilde",
107 "oacute", "ocircumflex", "odieresis", "ograve",
108 "otilde", "scaron", "uacute", "ucircumflex",
109 /*224*/ "udieresis", "ugrave", "yacute", "ydieresis",
110 "zcaron", "exclamsmall", "Hungarumlautsmall","dollaroldstyle",
111 "dollarsuperior", "ampersandsmall", "Acutesmall", "parenleftsuperior",
112 "parenrightsuperior","twodotenleader", "onedotenleader", "zerooldstyle",
113 /*240*/ "oneoldstyle", "twooldstyle", "threeoldstyle", "fouroldstyle",
114 "fiveoldstyle", "sixoldstyle", "sevenoldstyle", "eightoldstyle",
115 "nineoldstile", "commasuperior", "threequartersemdash","periodsuperior",
116 "questionsmall", "asuperior", "bsuperior", "centsuperior",
117 /*256*/ "dsuperior", "esuperior", "isuperior", "lsuperior",
118 "msuperior", "nsuperior", "osuperior", "rsuperior",
119 "ssuperior", "tsuperior", "ff", "ffi",
120 "ffl", "parenleftinferior","parenrightinferior","Circumflexsmall",
121 /*272*/ "hyphensuperior","Gravesmall", "Asmall", "Bsmall",
122 "Csmall", "Dsmall", "Esmall", "Fsmall",
123 "Gsmall", "Hsmall", "Ismall", "Jsmall",
124 "Ksmall", "Lsmall", "Msmall", "Nsmall",
125 /*288*/ "Osmall", "Psmall", "Qsmall", "Rsmall",
126 "Ssmall", "Tsmall", "Usmall", "Vsmall",
127 "Wsmall", "Xsmall", "Ysmall", "Zsmall",
128 "colonmonetary", "onefitted", "rupia", "Tildesmall",
129 /*304*/ "exclamdownsmall","centoldstyle", "Lslashsmall", "Scaronsmall",
130 "Zcaronsmall", "Dieresissmall", "Brevesmall", "Caronsmall",
131 "Dotaccentsmall", "Macronsmall", "figuredash", "hypheninferior",
132 "Ogoneksmall", "Ringsmall", "Cedillasmall", "questiondownsmall",
133 /*320*/ "oneeight", "threeeights", "fiveeights", "seveneights",
134 "onethird", "twothirds", "zerosuperior", "foursuperior",
135 "fivesuperior", "sixsuperior", "sevensuperior", "eightsuperior",
136 "ninesuperior", "zeroinferior", "oneinferior", "twoinferior",
137 /*336*/ "threeinferior","fourinferior", "fiveinferior", "sixinferior",
138 "seveninferior", "eightinferior", "nineinferior", "centinferior",
139 "dollarinferior", "periodinferior", "commainferior", "Agravesmall",
140 "Aacutesmall", "Acircumflexsmall", "Atildesmall", "Adieresissmall",
141 /*352*/ "Aringsmall", "AEsmall", "Ccedillasmall", "Egravesmall",
142 "Eacutesmall", "Ecircumflexsmall", "Edieresissmall", "Igravesmall",
143 "Iacutesmall", "Icircumflexsmall", "Idieresissmall", "Ethsmall",
144 "Ntildesmall", "Ogravesmall", "Oacutesmall", "Ocircumflexsmall",
145 /*368*/ "Otildesmall", "Odieressissmall", "OEsmall", "Oslashsmall",
146 "Ugravesmall", "Uacutesmall", "Ucircumflexsmall", "Udieresissmall",
147 "Yacutesmall", "Thornsmall", "Ydieresissmall", "001.000",
148 "001.001", "001.002", "001.003", "Black",
149 /*384*/ "Bold", "Book", "Light", "Medium",
150 "Regular", "Roman", "Semibold"
153 // --------------------------------------------------------------------
155 #if 0 // TODO: use them
156 static const char* pStdEncNames[] = {
157 "ISOAdobe", "Expert", "ExpertSubSet"
159 #endif
161 // --------------------------------------------------------------------
163 // TOP DICT keywords (also covers PRIV DICT keywords)
164 static const char* pDictOps[] = {
165 "sVersion", "sNotice", "sFullName", "sFamilyName",
166 "sWeight", "aFontBBox", "dBlueValues", "dOtherBlues",
167 "dFamilyBlues", "dFamilyOtherBlues", "nStdHW", "nStdVW",
168 "xESC", "nUniqueID", "aXUID", "nCharset",
169 "nEncoding", "nCharStrings", "PPrivate", "nSubrs",
170 "nDefaultWidthX", "nNominalWidthX", NULL, NULL,
171 NULL, NULL, NULL, NULL,
172 "shortint", "longint", "BCD", NULL
175 // --------------------------------------------------------------------
177 // TOP DICT escapes (also covers PRIV DICT escapes)
178 static const char* pDictEscs[] = {
179 "sCopyright", "bIsFixedPitch", "nItalicAngle", "nUnderlinePosition",
180 "nUnderlineThickness", "nPaintType", "tCharstringType", "aFontMatrix",
181 "nStrokeWidth", "nBlueScale", "nBlueShift", "nBlueFuzz",
182 "dStemSnapH", "dStemSnapV", "bForceBold", NULL,
183 NULL, "nLanguageGroup", "nExpansionFactor", "nInitialRandomSeed",
184 "nSyntheticBase", "sPostScript", "sBaseFontName", "dBaseFontBlend",
185 NULL, NULL, NULL, NULL,
186 NULL, NULL, "rROS", "nCIDFontVersion",
187 "nCIDFontRevision", "nCIDFontType", "nCIDCount", "nUIDBase",
188 "nFDArray", "nFDSelect", "sFontName"
191 // --------------------------------------------------------------------
193 static const char* pType1Ops[] = {
194 NULL, "2hstem", NULL, "2vstem",
195 "1vmoveto", "Arlineto", "1hlineto", "1vlineto",
196 "Crrcurveto", "0closepath", "Lcallsubr", "0return",
197 "xT1ESC", "2hsbw", "0endchar", NULL,
198 NULL, NULL, NULL, NULL,
199 NULL, "2rmoveto", "1hmoveto", NULL,
200 NULL, NULL, NULL, NULL,
201 NULL, NULL, "4vhcurveto", "4hvcurveto"
204 // --------------------------------------------------------------------
206 static const char* pT1EscOps[] = {
207 "0dotsection", "6vstem3", "6hstem3", NULL,
208 NULL, NULL, "5seac", "4sbw",
209 NULL, "1abs", "2add", "2sub",
210 "2div", NULL, NULL, NULL,
211 "Gcallothersubr", "1pop", NULL, NULL,
212 NULL, NULL, NULL, NULL,
213 NULL, NULL, NULL, NULL,
214 NULL, NULL, NULL, NULL,
215 NULL, "2setcurrentpoint"
218 // --------------------------------------------------------------------
220 struct TYPE1OP
222 enum OPS
224 HSTEM=1, VSTEM=3, VMOVETO=4, RLINETO=5,
225 HLINETO=6, VLINETO=7, RCURVETO=8, CLOSEPATH=9,
226 CALLSUBR=10, RETURN=11, T1ESC=12, HSBW=13,
227 ENDCHAR=14, RMOVETO=21, HMOVETO=22, VHCURVETO=30,
228 HVCURVETO=31
231 enum ESCS
233 DOTSECTION=0, VSTEM3=1, HSTEM3=2, SEAC=6,
234 SBW=7, ABS=9, ADD=10, SUB=11,
235 DIV=12, CALLOTHERSUBR=16, POP=17, SETCURRENTPOINT=33
239 // --------------------------------------------------------------------
241 static const char* pType2Ops[] = {
242 NULL, "hhstem", NULL, "vvstem",
243 "mvmoveto", "Arlineto", "Ehlineto", "Evlineto",
244 "Crrcurveto", NULL, "Lcallsubr", "Xreturn",
245 "xT2ESC", NULL, "eendchar", NULL,
246 NULL, NULL, "Hhstemhm", "Khintmask",
247 "Kcntrmask", "Mrmoveto", "mhmoveto", "Vvstemhm",
248 ".rcurveline", ".rlinecurve", ".vvcurveto", ".hhcurveto",
249 ".shortint", "Gcallgsubr", ".vhcurveto", ".hvcurveto"
252 // --------------------------------------------------------------------
254 static const char* pT2EscOps[] = {
255 NULL, NULL, NULL, "2and",
256 "2or", "1not", NULL, NULL,
257 NULL, "1abs", "2add", "2sub",
258 "2div", NULL, "1neg", "2eq",
259 NULL, NULL, "1drop", NULL,
260 "1put", "1get", "4ifelse", "0random",
261 "2mul", NULL, "1sqrt", "1dup",
262 "2exch", "Iindex", "Rroll", NULL,
263 NULL, NULL, "7hflex", "Fflex",
264 "9hflex1", "fflex1"
267 // --------------------------------------------------------------------
269 struct TYPE2OP
271 enum OPS
273 HSTEM=1, VSTEM=3, VMOVETO=4, RLINETO=5,
274 HLINETO=6, VLINETO=7, RCURVETO=8, CALLSUBR=10,
275 RETURN=11, T2ESC=12, ENDCHAR=14, HSTEMHM=18,
276 HINTMASK=19, CNTRMASK=20, RMOVETO=21, HMOVETO=22,
277 VSTEMHM=23, RCURVELINE=24, RLINECURVE=25, VVCURVETO=26,
278 HHCURVETO=27, SHORTINT=28, CALLGSUBR=29, VHCURVETO=30,
279 HVCURVETO=31
282 enum ESCS
284 AND=3, OR=4, NOT=5, ABS=9,
285 ADD=10, SUB=11, DIV=12, NEG=14,
286 EQ=15, DROP=18, PUT=20, GET=21,
287 IFELSE=22, RANDOM=23, MUL=24, SQRT=26,
288 DUP=27, EXCH=28, INDEX=29, ROLL=30,
289 HFLEX=34, FLEX=35, HFLEX1=36, FLEX1=37
293 // ====================================================================
295 struct CffGlobal
297 explicit CffGlobal();
299 int mnNameIdxBase;
300 int mnNameIdxCount;
301 int mnStringIdxBase;
302 int mnStringIdxCount;
303 bool mbCIDFont;
304 int mnCharStrBase;
305 int mnCharStrCount;
306 int mnEncodingBase;
307 int mnCharsetBase;
308 int mnGlobalSubrBase;
309 int mnGlobalSubrCount;
310 int mnGlobalSubrBias;
311 int mnFDSelectBase;
312 int mnFontDictBase;
313 int mnFDAryCount;
315 ValVector maFontBBox;
316 ValVector maFontMatrix;
318 int mnFontNameSID;
319 int mnFullNameSID;
320 int mnFamilyNameSID;
323 // ====================================================================
325 struct CffLocal
327 explicit CffLocal();
329 int mnPrivDictBase;
330 int mnPrivDictSize;
331 int mnLocalSubrOffs;
332 int mnLocalSubrBase;
333 int mnLocalSubrCount;
334 int mnLocalSubrBias;
335 int mnNominalWidth;
336 int mnDefaultWidth;
338 // ATM hinting related values
339 int mnStemStdHW;
340 int mnStemStdVW;
341 ValVector maStemSnapH;
342 ValVector maStemSnapV;
343 ValVector maBlueValues;
344 ValVector maOtherBlues;
345 ValVector maFamilyBlues;
346 ValVector maFamilyOtherBlues;
347 RealType mfBlueScale;
348 RealType mfBlueShift;
349 RealType mfBlueFuzz;
350 RealType mfExpFactor;
351 int mnLangGroup;
352 bool mbForceBold;
355 // ====================================================================
357 class SubsetterContext
359 public:
360 virtual ~SubsetterContext( void);
361 virtual bool emitAsType1( class Type1Emitter&,
362 const long* pGlyphIDs, const U8* pEncoding,
363 GlyphWidth* pGlyphWidths, int nGlyphCount, FontSubsetInfo& ) = 0;
366 // --------------------------------------------------------------------
368 SubsetterContext::~SubsetterContext( void)
371 // ====================================================================
373 class CffSubsetterContext
374 : public SubsetterContext
375 , private CffGlobal
377 public:
378 static const int NMAXSTACK = 48; // see CFF.appendixB
379 static const int NMAXHINTS = 2*96; // see CFF.appendixB
380 static const int NMAXTRANS = 32; // see CFF.appendixB
381 public:
382 explicit CffSubsetterContext( const U8* pBasePtr, int nBaseLen);
383 virtual ~CffSubsetterContext( void);
385 void initialCffRead( void);
386 bool emitAsType1( class Type1Emitter&,
387 const long* pGlyphIDs, const U8* pEncoding,
388 GlyphWidth* pGlyphWidths, int nGlyphCount, FontSubsetInfo& );
390 // used by charstring converter
391 void setCharStringType( int);
392 void fakeLocalSubrCount( int nLocalSubrs ) { maCffLocal[0].mnLocalSubrCount=nLocalSubrs;}
393 void readCharString( const U8* pTypeOps, int nTypeLen);
394 protected:
395 int convert2Type1Ops( CffLocal*, const U8* pType2Ops, int nType2Len, U8* pType1Ops);
396 private:
397 void readTypeOp( CffSubsetterContext&);
398 void convertOneTypeOp( void);
399 void convertOneTypeEsc( void);
400 void callType2Subr( bool bGlobal, int nSubrNumber);
401 long getReadOfs( void) const { return (long)(mpReadPtr - mpBasePtr);}
403 const U8* mpBasePtr;
404 const U8* mpBaseEnd;
406 const U8* mpReadPtr;
407 const U8* mpReadEnd;
409 U8* mpWritePtr;
410 bool mbSawError;
411 bool mbNeedClose;
412 bool mbIgnoreHints;
413 long mnCntrMask;
415 private:
416 int seekIndexData( int nIndexBase, int nDataIndex);
417 void seekIndexEnd( int nIndexBase);
419 private:
420 const char** mpCharStringOps;
421 const char** mpCharStringEscs;
423 CffLocal maCffLocal[16];
424 CffLocal* mpCffLocal;
426 void readDictOp( void);
427 RealType readRealVal( void);
428 const char* getString( int nStringID);
429 int getFDSelect( int nGlyphIndex) const;
430 int getGlyphSID( int nGlyphIndex) const;
431 const char* getGlyphName( int nGlyphIndex);
433 void readTypeOp( void);
434 void read2push( void);
435 void pop2write( void);
436 void writeType1Val( ValType);
437 void writeTypeOp( int nTypeOp);
438 void writeTypeEsc( int nTypeOp);
439 void writeCurveTo( int nStackPos, int nIX1, int nIY1, int nIX2, int nIY2, int nIX3, int nIY3);
440 void pop2MultiWrite( int nArgsPerTypo, int nTypeOp, int nTypeXor=0);
441 void popAll2Write( int nTypeOp);
443 public: // TODO: is public really needed?
444 // accessing the value stack
445 // TODO: add more checks
446 void push( ValType nVal) { mnValStack[ mnStackIdx++] = nVal;}
447 ValType popVal( void) { return ((mnStackIdx>0) ? mnValStack[ --mnStackIdx] : 0);}
448 ValType peekVal( void) const { return ((mnStackIdx>0) ? mnValStack[ mnStackIdx-1] : 0);}
449 ValType getVal( int nIndex) const { return mnValStack[ nIndex];}
450 int popInt( void);
451 int peekInt( void) const;
452 int getInt( int nIndex) const;
453 int size( void) const { return mnStackIdx;}
454 bool empty( void) const { return !mnStackIdx;}
455 void clear( void) { mnStackIdx = 0;}
457 // accessing the charstring hints
458 void addHints( bool bVerticalHints);
459 int getHorzHintCount( void) const { return (mnHorzHintSize/2);}
460 int getVertHintCount( void) const { return (mnHintSize-mnHorzHintSize)/2;}
461 void getHintPair( int nIndex, ValType* nMin, ValType* nEnd) const;
463 // accessing other charstring specifics
464 bool hasCharWidth( void) const { return (mnCharWidth != -1);}
465 int getCharWidth( void) const { return mnCharWidth;}
466 void setNominalWidth( int nWidth) { mpCffLocal->mnNominalWidth = nWidth;}
467 void setDefaultWidth( int nWidth) { mpCffLocal->mnDefaultWidth = nWidth;}
468 void updateWidth( bool bUseFirstVal);
470 private:
471 // typeop exceution context
472 int mnStackIdx;
473 ValType mnValStack[ NMAXSTACK];
474 ValType mnTransVals[ NMAXTRANS];
476 int mnHintSize;
477 int mnHorzHintSize;
478 ValType mnHintStack[ NMAXHINTS];
480 int mnCharWidth;
483 // --------------------------------------------------------------------
485 CffSubsetterContext::CffSubsetterContext( const U8* pBasePtr, int nBaseLen)
486 : mpBasePtr( pBasePtr)
487 , mpBaseEnd( pBasePtr+nBaseLen)
488 , mnStackIdx(0)
489 , mnHintSize(0)
490 , mnHorzHintSize(0)
491 , mnCharWidth(-1)
493 // setCharStringType( 1);
494 // TODO: new CffLocal[ mnFDAryCount];
495 mpCffLocal = &maCffLocal[0];
498 // --------------------------------------------------------------------
500 CffSubsetterContext::~CffSubsetterContext( void)
502 // TODO: delete[] maCffLocal;
505 // --------------------------------------------------------------------
507 inline int CffSubsetterContext::popInt( void)
509 const ValType aVal = popVal();
510 const int nInt = static_cast<int>(aVal);
511 assert( nInt == aVal);
512 return nInt;
515 // --------------------------------------------------------------------
517 inline int CffSubsetterContext::peekInt( void) const
519 const ValType aVal = peekVal();
520 const int nInt = static_cast<int>(aVal);
521 assert( nInt == aVal);
522 return nInt;
525 // --------------------------------------------------------------------
527 inline int CffSubsetterContext::getInt( int nIndex) const
529 const ValType aVal = getVal( nIndex);
530 const int nInt = static_cast<int>(aVal);
531 assert( nInt == aVal);
532 return nInt;
535 // --------------------------------------------------------------------
537 inline void CffSubsetterContext::updateWidth( bool bUseFirstVal)
539 #if 1 // TODO: is this still needed?
540 // the first value is not a hint but the charwidth
541 if( hasCharWidth())
542 return;
543 #endif
544 if( bUseFirstVal) {
545 mnCharWidth = static_cast<int>(mpCffLocal->mnNominalWidth + mnValStack[0]);
546 // remove bottom stack entry
547 --mnStackIdx;
548 for( int i = 0; i < mnStackIdx; ++i)
549 mnValStack[ i] = mnValStack[ i+1];
550 } else {
551 mnCharWidth = mpCffLocal->mnDefaultWidth;
555 // --------------------------------------------------------------------
557 void CffSubsetterContext::addHints( bool bVerticalHints)
559 // the first charstring value may a charwidth instead of a charwidth
560 updateWidth( (mnStackIdx & 1) != 0);
561 // return early (e.g. no implicit hints for hintmask)
562 if( !mnStackIdx)
563 return;
565 // copy the remaining values to the hint arrays
566 // assert( (mnStackIdx & 1) == 0); // depends on called subrs
567 if( mnStackIdx & 1) --mnStackIdx;//#######
568 // TODO: if( !bSubr) assert( mnStackIdx >= 2);
570 assert( (mnHintSize + mnStackIdx) <= 2*NMAXHINTS);
572 #ifdef IGNORE_HINTS
573 mnHintSize += mnStackIdx;
574 #else
575 ValType nHintOfs = 0;
576 for( int i = 0; i < mnStackIdx; ++i) {
577 nHintOfs += mnValStack[ i ];
578 mnHintStack[ mnHintSize++] = nHintOfs;
580 #endif // IGNORE_HINTS
581 if( !bVerticalHints)
582 mnHorzHintSize = mnHintSize;
584 // clear all values from the stack
585 mnStackIdx = 0;
588 // --------------------------------------------------------------------
590 void CffSubsetterContext::getHintPair( int nIndex, ValType* pMin, ValType* pEnd) const
592 nIndex *= 2;
593 assert( nIndex < mnHintSize);
594 assert( nIndex >= 0);
595 const ValType* pHint = &mnHintStack[ nIndex ];
596 *pMin = pHint[0];
597 *pEnd = pHint[1];
600 // --------------------------------------------------------------------
602 void CffSubsetterContext::setCharStringType( int nVal)
604 switch( nVal) {
605 case 1: mpCharStringOps=pType1Ops; mpCharStringEscs=pT1EscOps; break;
606 case 2: mpCharStringOps=pType2Ops; mpCharStringEscs=pT2EscOps; break;
607 default: fprintf( stderr, "Unknown CharstringType=%d\n",nVal); break;
611 // --------------------------------------------------------------------
613 void CffSubsetterContext::readCharString( const U8* pTypeOps, int nTypeLen)
615 mnStackIdx = 0;
616 mnHintSize = 0;
617 mnHorzHintSize = 0;
618 mnCharWidth = -1;
620 assert( nTypeLen >= 0);
621 // assert( nEnd <= getLength());
622 mpReadPtr = pTypeOps;
623 mpReadEnd = mpReadPtr + nTypeLen;
624 // reset the execution context
625 while( mpReadPtr < mpReadEnd)
626 readTypeOp();
627 //### assert( tellRel() == nEnd);
630 // --------------------------------------------------------------------
632 void CffSubsetterContext::readDictOp( void)
634 ValType nVal = 0;
635 int nInt = 0;
636 const U8 c = *mpReadPtr;
637 if( c <= 21 ) {
638 int nOpId = *(mpReadPtr++);
639 const char* pCmdName;
640 if( nOpId != 12)
641 pCmdName = pDictOps[ nOpId];
642 else {
643 const U8 nExtId = *(mpReadPtr++);
644 pCmdName = pDictEscs[ nExtId];
645 nOpId = 900 + nExtId;
648 //TODO: if( nStackIdx > 0)
649 switch( *pCmdName) {
650 default: fprintf( stderr, "unsupported DictOp.type=\'%c\'\n", *pCmdName); break;
651 case 'b': // bool
652 nInt = popInt();
653 switch( nOpId) {
654 case 915: mpCffLocal->mbForceBold = nInt; break; // "ForceBold"
655 default: break; // TODO: handle more boolean dictops?
657 break;
658 case 'n': // dict-op number
659 nVal = popVal();
660 nInt = static_cast<int>(nVal);
661 switch( nOpId) {
662 case 10: mpCffLocal->mnStemStdHW = nInt; break; // "StdHW"
663 case 11: mpCffLocal->mnStemStdVW = nInt; break; // "StdVW"
664 case 15: mnCharsetBase = nInt; break; // "charset"
665 case 16: mnEncodingBase = nInt; break; // "nEncoding"
666 case 17: mnCharStrBase = nInt; break; // "nCharStrings"
667 case 19: mpCffLocal->mnLocalSubrOffs = nInt; break;// "nSubrs"
668 case 20: setDefaultWidth( nInt ); break; // "defaultWidthX"
669 case 21: setNominalWidth( nInt ); break; // "nominalWidthX"
670 case 909: mpCffLocal->mfBlueScale = nVal; break; // "BlueScale"
671 case 910: mpCffLocal->mfBlueShift = nVal; break; // "BlueShift"
672 case 911: mpCffLocal->mfBlueFuzz = nVal; break; // "BlueFuzz"
673 case 912: mpCffLocal->mfExpFactor = nVal; break; // "ExpansionFactor"
674 case 917: mpCffLocal->mnLangGroup = nInt; break; // "LanguageGroup"
675 case 936: mnFontDictBase = nInt; break; // "nFDArray"
676 case 937: mnFDSelectBase = nInt; break; // "nFDSelect"
677 default: break; // TODO: handle more numeric dictops?
679 break;
680 case 'a': { // array
681 switch( nOpId) {
682 case 5: maFontBBox.clear(); break; // "FontBBox"
683 case 907: maFontMatrix.clear(); break; // "FontMatrix"
684 default: break; // TODO: reset other arrays?
686 for( int i = 0; i < size(); ++i ) {
687 nVal = getVal(i);
688 switch( nOpId) {
689 case 5: maFontBBox.push_back( nVal); break; // "FontBBox"
690 case 907: maFontMatrix.push_back( nVal); break; // "FontMatrix"
691 default: break; // TODO: handle more array dictops?
694 clear();
695 } break;
696 case 'd': { // delta array
697 nVal = 0;
698 for( int i = 0; i < size(); ++i ) {
699 nVal += getVal(i);
700 switch( nOpId) {
701 case 6: mpCffLocal->maBlueValues.push_back( nVal); break; // "BlueValues"
702 case 7: mpCffLocal->maOtherBlues.push_back( nVal); break; // "OtherBlues"
703 case 8: mpCffLocal->maFamilyBlues.push_back( nVal); break; // "FamilyBlues"
704 case 9: mpCffLocal->maFamilyOtherBlues.push_back( nVal); break;// "FamilyOtherBlues"
705 case 912: mpCffLocal->maStemSnapH.push_back( nVal); break; // "StemSnapH"
706 case 913: mpCffLocal->maStemSnapV.push_back( nVal); break; // "StemSnapV"
707 default: break; // TODO: handle more delta-array dictops?
710 clear();
711 } break;
712 case 's': // stringid (SID)
713 nInt = popInt();
714 switch( nOpId ) {
715 case 2: mnFullNameSID = nInt; break; // "FullName"
716 case 3: mnFamilyNameSID = nInt; break; // "FamilyName"
717 case 938: mnFontNameSID = nInt; break; // "FontName"
718 default: break; // TODO: handle more string dictops?
720 break;
721 case 'P': // private dict
722 mpCffLocal->mnPrivDictBase = popInt();
723 mpCffLocal->mnPrivDictSize = popInt();
724 break;
725 case 'r': { // ROS operands
726 int nSid1 = popInt();
727 int nSid2 = popInt();
728 (void)nSid1; // TODO: use
729 (void)nSid2; // TODO: use
730 nVal = popVal();
731 mbCIDFont = true;
732 } break;
733 case 't': // CharstringType
734 nInt = popInt();
735 setCharStringType( nInt );
736 break;
739 return;
742 if( (c >= 32) || (c == 28) ) {
743 // --mpReadPtr;
744 read2push();
745 } else if( c == 29 ) { // longint
746 ++mpReadPtr; // skip 29
747 int nS32 = mpReadPtr[0] << 24;
748 nS32 += mpReadPtr[1] << 16;
749 nS32 += mpReadPtr[2] << 8;
750 nS32 += mpReadPtr[3] << 0;
751 if( (sizeof(nS32) != 4) && (nS32 & (1<<31)))
752 nS32 |= (~0U) << 31; // assuming 2s complement
753 mpReadPtr += 4;
754 nVal = static_cast<ValType>(nS32);
755 push( nVal );
756 } else if( c == 30) { // real number
757 ++mpReadPtr; // skip 30
758 const RealType fReal = readRealVal();
759 // push value onto stack
760 nVal = fReal;
761 push( nVal);
765 // --------------------------------------------------------------------
767 void CffSubsetterContext::readTypeOp( void)
769 int nVal = 0;
770 const U8 c = *mpReadPtr;
771 if( (c <= 31) && (c != 28) ) {
772 const int nOpId = *(mpReadPtr++);
773 const char* pCmdName;
774 if( nOpId != 12)
775 pCmdName = mpCharStringOps[ nOpId];
776 else {
777 const int nExtId = *(mpReadPtr++);
778 pCmdName = mpCharStringEscs[ nExtId];
781 if( !pCmdName )
782 pCmdName = ".NULL";
783 // handle typeop parameters
784 int nMinStack = -1, nMaxStack = -1;
785 switch( *pCmdName) {
786 default: fprintf( stderr, "unsupported TypeOp.type=\'%c\'\n", *pCmdName); break;
787 case '.': nMinStack = 0; nMaxStack = 999; break;
788 case '0': nMinStack = nMaxStack = 0; break;
789 case '1': nMinStack = nMaxStack = 1; break;
790 case '2': nMinStack = nMaxStack = 2; break;
791 case '4': nMinStack = nMaxStack = 4; break;
792 case '5': nMinStack = nMaxStack = 5; break; // not used for Type2 ops
793 case '6': nMinStack = nMaxStack = 6; break;
794 case '7': nMinStack = nMaxStack = 7; break;
795 case '9': nMinStack = nMaxStack = 9; break;
796 case 'f': nMinStack = nMaxStack = 11; break;
797 case 'F': nMinStack = nMaxStack = 13; break;
798 case 'A': nMinStack = 2; nMaxStack = 999; break;
799 case 'C': nMinStack = 6; nMaxStack = 999; break;
800 case 'E': nMinStack = 1; nMaxStack = 999; break;
801 case 'G': nMinStack = 1; nMaxStack = 999; // global subr
802 nVal = peekInt();
803 // TODO global subr
804 break;
805 case 'L': // local subr
806 nMinStack = 1; nMaxStack = 999;
807 nVal = peekInt();
808 // TODO local subr
809 break;
810 case 'I': // operands for "index"
811 #if 0
812 nMinStack = nValStack[ nStackIdx-1];
813 if( nMinStack < 0) nMinStack = 0;
814 nMinStack += 1;
815 #else
816 fprintf( stderr, "TODO: Iindex op\n");
817 #endif
818 break;
819 case 'R': // operands for "rol"
820 #if 0
821 nMinStack = nValStack[ nStackIdx-2];
822 #else
823 fprintf( stderr, "TODO: Rrol op\n");
824 #endif
825 case 'X': // operands for "return"
826 nMinStack = 0;
827 nMaxStack = /*### (!bInSubrs)? 0 :###*/999;
828 break;
829 case 'H': // "hstemhm"
830 case 'h': // "hstem"
831 addHints( false);
832 nMinStack = nMaxStack = 0;
833 break;
834 case 'V': // "vstemhm"
835 case 'v': // "vstem"
836 addHints( true);
837 nMinStack = nMaxStack = 0;
838 break;
839 case 'K': // "hintmask" or "cntrmask"
840 addHints( true); // implicit vstemhm
841 nMinStack = nMaxStack = 0;
842 break;
843 case 'e': // endchar
844 updateWidth( (size() >= 1) && (size() != 4));
845 nMinStack = nMaxStack = 0;
846 if( size() == 4)
847 fprintf( stderr,"Deprecated SEAC-like endchar is not supported for CFF subsetting!\n"); // TODO: handle deprecated op
848 break;
849 case 'm': // hmoveto or vmoveto
850 updateWidth( size() > 1);
851 nMinStack = 1;
852 nMaxStack = nMinStack;
853 break;
854 case 'M': // rmoveto
855 updateWidth( size() > 2);
856 nMinStack = 2;
857 nMaxStack = nMinStack;
858 break;
861 clear();
862 return;
865 if( (c >= 32) || (c == 28)) {
866 // --mpReadPtr;
867 read2push();
871 // --------------------------------------------------------------------
873 void CffSubsetterContext::read2push()
875 ValType aVal = 0;
877 const U8*& p = mpReadPtr;
878 const U8 c = *p;
879 if( c == 28 ) {
880 short nS16 = (p[1] << 8) + p[2];
881 if( (sizeof(nS16) != 2) && (nS16 & (1<<15)))
882 nS16 |= (~0U) << 15; // assuming 2s complement
883 aVal = nS16;
884 p += 3;
885 } else if( c <= 246 ) { // -107..+107
886 aVal = static_cast<ValType>(p[0] - 139);
887 p += 1;
888 } else if( c <= 250 ) { // +108..+1131
889 aVal = static_cast<ValType>(((p[0] << 8) + p[1]) - 63124);
890 p += 2;
891 } else if( c <= 254 ) { // -108..-1131
892 aVal = static_cast<ValType>(64148 - ((p[0] << 8) + p[1]));
893 p += 2;
894 } else /*if( c == 255)*/ { // Fixed16.16
895 int nS32 = (p[1] << 24) + (p[2] << 16) + (p[3] << 8) + p[4];
896 if( (sizeof(nS32) != 2) && (nS32 & (1<<31)))
897 nS32 |= (~0U) << 31; // assuming 2s complement
898 aVal = static_cast<ValType>(nS32 * (1.0 / 0x10000));
899 p += 5;
902 push( aVal);
905 // --------------------------------------------------------------------
907 void CffSubsetterContext::writeType1Val( ValType aVal)
909 U8* pOut = mpWritePtr;
911 int nInt = static_cast<int>(aVal);
912 static const int nOutCharstrType = 1;
913 if( (nInt != aVal) && (nOutCharstrType == 2)) {
914 // numtype==255 means int32 for Type1, but 16.16 for Type2 charstrings!!!
915 *(pOut++) = 255; // Fixed 16.16
916 *(pOut++) = static_cast<U8>(nInt >> 8);
917 *(pOut++) = static_cast<U8>(nInt);
918 nInt = static_cast<int>(aVal * 0x10000) & 0xFFFF;
919 *(pOut++) = static_cast<U8>(nInt >> 8);
920 *(pOut++) = static_cast<U8>(nInt);
921 } else if( (nInt >= -107) && (nInt <= +107)) {
922 *(pOut++) = static_cast<U8>(nInt + 139); // -107..+107
923 } else if( (nInt >= -1131) && (nInt <= +1131)) {
924 if( nInt >= 0)
925 nInt += 63124; // +108..+1131
926 else
927 nInt = 64148 - nInt; // -108..-1131
928 *(pOut++) = static_cast<U8>(nInt >> 8);
929 *(pOut++) = static_cast<U8>(nInt);
930 } else if( nOutCharstrType == 1) {
931 // numtype==255 means int32 for Type1, but 16.16 for Type2 charstrings!!!
932 *(pOut++) = 255;
933 *(pOut++) = static_cast<U8>(nInt >> 24);
934 *(pOut++) = static_cast<U8>(nInt >> 16);
935 *(pOut++) = static_cast<U8>(nInt >> 8);
936 *(pOut++) = static_cast<U8>(nInt);
939 mpWritePtr = pOut;
942 // --------------------------------------------------------------------
944 inline void CffSubsetterContext::pop2write( void)
946 const ValType aVal = popVal();
947 writeType1Val( aVal);
950 // --------------------------------------------------------------------
952 inline void CffSubsetterContext::writeTypeOp( int nTypeOp)
954 *(mpWritePtr++) = static_cast<U8>(nTypeOp);
957 // --------------------------------------------------------------------
959 inline void CffSubsetterContext::writeTypeEsc( int nTypeEsc)
961 *(mpWritePtr++) = TYPE1OP::T1ESC;
962 *(mpWritePtr++) = static_cast<U8>(nTypeEsc);
965 // --------------------------------------------------------------------
967 void CffSubsetterContext::pop2MultiWrite( int nArgsPerTypo, int nTypeOp, int nTypeXor)
969 for( int i = 0; i < mnStackIdx;) {
970 for( int j = 0; j < nArgsPerTypo; ++j) {
971 const ValType aVal = mnValStack[i+j];
972 writeType1Val( aVal);
974 i += nArgsPerTypo;
975 writeTypeOp( nTypeOp);
976 nTypeOp ^= nTypeXor; // for toggling vlineto/hlineto
978 clear();
981 // --------------------------------------------------------------------
983 void CffSubsetterContext::popAll2Write( int nTypeOp)
985 // pop in reverse order, then write
986 for( int i = 0; i < mnStackIdx; ++i) {
987 const ValType aVal = mnValStack[i];
988 writeType1Val( aVal);
990 clear();
991 writeTypeOp( nTypeOp);
994 // --------------------------------------------------------------------
996 void CffSubsetterContext::writeCurveTo( int nStackPos,
997 int nIX1, int nIY1, int nIX2, int nIY2, int nIX3, int nIY3)
999 // get the values from the stack
1000 const ValType nDX1 = nIX1 ? mnValStack[ nStackPos+nIX1 ] : 0;
1001 const ValType nDY1 = nIY1 ? mnValStack[ nStackPos+nIY1 ] : 0;
1002 const ValType nDX2 = nIX2 ? mnValStack[ nStackPos+nIX2 ] : 0;
1003 const ValType nDY2 = nIY2 ? mnValStack[ nStackPos+nIY2 ] : 0;
1004 const ValType nDX3 = nIX3 ? mnValStack[ nStackPos+nIX3 ] : 0;
1005 const ValType nDY3 = nIY3 ? mnValStack[ nStackPos+nIY3 ] : 0;
1007 // emit the curveto operator and operands
1008 // TODO: determine the most efficient curveto operator
1009 // TODO: depending on type1op or type2op target
1010 writeType1Val( nDX1 );
1011 writeType1Val( nDY1 );
1012 writeType1Val( nDX2 );
1013 writeType1Val( nDY2 );
1014 writeType1Val( nDX3 );
1015 writeType1Val( nDY3 );
1016 writeTypeOp( TYPE1OP::RCURVETO );
1019 // --------------------------------------------------------------------
1021 void CffSubsetterContext::convertOneTypeOp( void)
1023 const int nType2Op = *(mpReadPtr++);
1025 int i, nInt; // prevent WAE for declarations inside switch cases
1026 // convert each T2op
1027 switch( nType2Op) {
1028 case TYPE2OP::T2ESC:
1029 convertOneTypeEsc();
1030 break;
1031 case TYPE2OP::HSTEM:
1032 case TYPE2OP::VSTEM:
1033 addHints( nType2Op == TYPE2OP::VSTEM );
1034 #ifndef IGNORE_HINTS
1035 for( i = 0; i < mnHintSize; i+=2 ) {
1036 writeType1Val( mnHintStack[i]);
1037 writeType1Val( mnHintStack[i+1] - mnHintStack[i]);
1038 writeTypeOp( nType2Op );
1040 #endif // IGNORE_HINTS
1041 break;
1042 case TYPE2OP::HSTEMHM:
1043 case TYPE2OP::VSTEMHM:
1044 addHints( nType2Op == TYPE2OP::VSTEMHM);
1045 break;
1046 case TYPE2OP::CNTRMASK:
1047 // TODO: replace cntrmask with vstem3/hstem3
1048 addHints( true);
1049 #ifdef IGNORE_HINTS
1050 mpReadPtr += (mnHintSize + 15) / 16;
1051 mbIgnoreHints = true;
1052 #else
1054 U8 nMaskBit = 0;
1055 U8 nMaskByte = 0;
1056 for( i = 0; i < mnHintSize; i+=2, nMaskBit>>=1) {
1057 if( !nMaskBit) {
1058 nMaskByte = *(mpReadPtr++);
1059 nMaskBit = 0x80;
1061 if( !(nMaskByte & nMaskBit))
1062 continue;
1063 if( i >= 8*(int)sizeof(mnCntrMask))
1064 mbIgnoreHints = true;
1065 if( mbIgnoreHints)
1066 continue;
1067 mnCntrMask |= (1U << i);
1070 #endif
1071 break;
1072 case TYPE2OP::HINTMASK:
1073 addHints( true);
1074 #ifdef IGNORE_HINTS
1075 mpReadPtr += (mnHintSize + 15) / 16;
1076 #else
1078 long nHintMask = 0;
1079 int nCntrBits[2] = {0,0};
1080 U8 nMaskBit = 0;
1081 U8 nMaskByte = 0;
1082 for( i = 0; i < mnHintSize; i+=2, nMaskBit>>=1) {
1083 if( !nMaskBit) {
1084 nMaskByte = *(mpReadPtr++);
1085 nMaskBit = 0x80;
1087 if( !(nMaskByte & nMaskBit))
1088 continue;
1089 if( i >= 8*(int)sizeof(nHintMask))
1090 mbIgnoreHints = true;
1091 if( mbIgnoreHints)
1092 continue;
1093 nHintMask |= (1U << i);
1094 nCntrBits[ i < mnHorzHintSize] += (mnCntrMask >> i) & 1;
1097 mbIgnoreHints |= (nCntrBits[0] && (nCntrBits[0] != 3));
1098 mbIgnoreHints |= (nCntrBits[1] && (nCntrBits[1] != 3));
1099 if( mbIgnoreHints)
1100 break;
1102 for( i = 0; i < mnHintSize; i+=2) {
1103 if( !(nHintMask & (1U << i)))
1104 continue;
1105 writeType1Val( mnHintStack[i]);
1106 writeType1Val( mnHintStack[i+1] - mnHintStack[i]);
1107 const bool bHorz = (i < mnHorzHintSize);
1108 if( !nCntrBits[ bHorz])
1109 writeTypeOp( bHorz ? TYPE1OP::HSTEM : TYPE1OP::VSTEM);
1110 else if( !--nCntrBits[ bHorz])
1111 writeTypeEsc( bHorz ? TYPE1OP::HSTEM3 : TYPE1OP::VSTEM3);
1114 #endif
1115 break;
1116 case TYPE2OP::CALLSUBR:
1117 case TYPE2OP::CALLGSUBR:
1119 nInt = popInt();
1120 const bool bGlobal = (nType2Op == TYPE2OP::CALLGSUBR);
1121 callType2Subr( bGlobal, nInt);
1123 break;
1124 case TYPE2OP::RETURN:
1125 // TODO: check that we are in a subroutine
1126 return;
1127 case TYPE2OP::VMOVETO:
1128 case TYPE2OP::HMOVETO:
1129 if( mbNeedClose)
1130 writeTypeOp( TYPE1OP::CLOSEPATH);
1131 else
1132 updateWidth( size() > 1);
1133 mbNeedClose = true;
1134 pop2MultiWrite( 1, nType2Op);
1135 break;
1136 case TYPE2OP::VLINETO:
1137 case TYPE2OP::HLINETO:
1138 pop2MultiWrite( 1, nType2Op,
1139 TYPE1OP::VLINETO ^ TYPE1OP::HLINETO);
1140 break;
1141 case TYPE2OP::RMOVETO:
1142 // TODO: convert rmoveto to vlineto/hlineto if possible
1143 if( mbNeedClose)
1144 writeTypeOp( TYPE1OP::CLOSEPATH);
1145 else
1146 updateWidth( size() > 2);
1147 mbNeedClose = true;
1148 pop2MultiWrite( 2, nType2Op);
1149 break;
1150 case TYPE2OP::RLINETO:
1151 // TODO: convert rlineto to vlineto/hlineto if possible
1152 pop2MultiWrite( 2, nType2Op);
1153 break;
1154 case TYPE2OP::RCURVETO:
1155 // TODO: convert rcurveto to vh/hv/hh/vv-curveto if possible
1156 pop2MultiWrite( 6, nType2Op);
1157 break;
1158 case TYPE2OP::RCURVELINE:
1159 i = 0;
1160 while( (i += 6) <= mnStackIdx)
1161 writeCurveTo( i, -6, -5, -4, -3, -2, -1 );
1162 i -= 6;
1163 while( (i += 2) <= mnStackIdx) {
1164 writeType1Val( mnValStack[i-2]);
1165 writeType1Val( mnValStack[i-1]);
1166 writeTypeOp( TYPE2OP::RLINETO);
1168 clear();
1169 break;
1170 case TYPE2OP::RLINECURVE:
1171 i = 0;
1172 while( (i += 2) <= mnStackIdx-6) {
1173 writeType1Val( mnValStack[i-2]);
1174 writeType1Val( mnValStack[i-1]);
1175 writeTypeOp( TYPE2OP::RLINETO);
1177 i -= 2;
1178 while( (i += 6) <= mnStackIdx)
1179 writeCurveTo( i, -6, -5, -4, -3, -2, -1 );
1180 clear();
1181 break;
1182 case TYPE2OP::VHCURVETO:
1183 case TYPE2OP::HVCURVETO:
1185 bool bVert = (nType2Op == TYPE2OP::VHCURVETO);
1186 i = 0;
1187 nInt = 0;
1188 if( mnStackIdx & 1 )
1189 nInt = static_cast<int>(mnValStack[ --mnStackIdx ]);
1190 while( (i += 4) <= mnStackIdx) {
1191 // TODO: use writeCurveTo()
1192 if( bVert ) writeType1Val( 0 );
1193 writeType1Val( mnValStack[i-4] );
1194 if( !bVert ) writeType1Val( 0);
1195 writeType1Val( mnValStack[i-3] );
1196 writeType1Val( mnValStack[i-2] );
1197 if( !bVert ) writeType1Val( static_cast<ValType>((i==mnStackIdx) ? nInt : 0) );
1198 writeType1Val( mnValStack[i-1] );
1199 if( bVert ) writeType1Val( static_cast<ValType>((i==mnStackIdx) ? nInt : 0) );
1200 bVert = !bVert;
1201 writeTypeOp( TYPE2OP::RCURVETO);
1204 clear();
1205 break;
1206 case TYPE2OP::HHCURVETO:
1207 i = (mnStackIdx & 1);
1208 while( (i += 4) <= mnStackIdx) {
1209 if( i != 5)
1210 writeCurveTo( i, -4, 0, -3, -2, -1, 0);
1211 else
1212 writeCurveTo( i, -4, -5, -3, -2, -1, 0);
1214 clear();
1215 break;
1216 case TYPE2OP::VVCURVETO:
1217 i = (mnStackIdx & 1);
1218 while( (i += 4) <= mnStackIdx) {
1219 if( i != 5)
1220 writeCurveTo( i, 0, -4, -3, -2, 0, -1);
1221 else
1222 writeCurveTo( i, -5, -4, -3, -2, 0, -1);
1224 clear();
1225 break;
1226 case TYPE2OP::ENDCHAR:
1227 if( mbNeedClose)
1228 writeTypeOp( TYPE1OP::CLOSEPATH);
1229 else
1230 updateWidth( size() >= 1);
1231 // mbNeedClose = true;
1232 writeTypeOp( TYPE1OP::ENDCHAR);
1233 break;
1234 default:
1235 if( ((nType2Op >= 32) && (nType2Op <= 255)) || (nType2Op == 28)) {
1236 --mpReadPtr;
1237 read2push();
1238 } else {
1239 popAll2Write( nType2Op);
1240 assert( false); // TODO?
1242 break;
1246 // --------------------------------------------------------------------
1248 void CffSubsetterContext::convertOneTypeEsc( void)
1250 const int nType2Esc = *(mpReadPtr++);
1251 ValType* pTop = &mnValStack[ mnStackIdx-1];
1252 // convert each T2op
1253 switch( nType2Esc) {
1254 case TYPE2OP::AND:
1255 assert( mnStackIdx >= 2 );
1256 pTop[0] = static_cast<ValType>(static_cast<int>(pTop[0]) & static_cast<int>(pTop[-1]));
1257 --mnStackIdx;
1258 break;
1259 case TYPE2OP::OR:
1260 assert( mnStackIdx >= 2 );
1261 pTop[0] = static_cast<ValType>(static_cast<int>(pTop[0]) | static_cast<int>(pTop[-1]));
1262 --mnStackIdx;
1263 break;
1264 case TYPE2OP::NOT:
1265 assert( mnStackIdx >= 1 );
1266 pTop[0] = (pTop[0] == 0);
1267 break;
1268 case TYPE2OP::ABS:
1269 assert( mnStackIdx >= 1 );
1270 if( pTop[0] >= 0)
1271 break;
1272 // fall through
1273 case TYPE2OP::NEG:
1274 assert( mnStackIdx >= 1 );
1275 pTop[0] = -pTop[0];
1276 break;
1277 case TYPE2OP::ADD:
1278 assert( mnStackIdx >= 2 );
1279 pTop[0] += pTop[-1];
1280 --mnStackIdx;
1281 break;
1282 case TYPE2OP::SUB:
1283 assert( mnStackIdx >= 2 );
1284 pTop[0] -= pTop[-1];
1285 --mnStackIdx;
1286 break;
1287 case TYPE2OP::MUL:
1288 assert( mnStackIdx >= 2 );
1289 if( pTop[-1])
1290 pTop[0] *= pTop[-1];
1291 --mnStackIdx;
1292 break;
1293 case TYPE2OP::DIV:
1294 assert( mnStackIdx >= 2 );
1295 if( pTop[-1])
1296 pTop[0] /= pTop[-1];
1297 --mnStackIdx;
1298 break;
1299 case TYPE2OP::EQ:
1300 assert( mnStackIdx >= 2 );
1301 pTop[0] = (pTop[0] == pTop[-1]);
1302 --mnStackIdx;
1303 break;
1304 case TYPE2OP::DROP:
1305 assert( mnStackIdx >= 1 );
1306 --mnStackIdx;
1307 break;
1308 case TYPE2OP::PUT: {
1309 assert( mnStackIdx >= 2 );
1310 const int nIdx = static_cast<int>(pTop[0]);
1311 assert( nIdx >= 0 );
1312 assert( nIdx < NMAXTRANS );
1313 mnTransVals[ nIdx] = pTop[-1];
1314 mnStackIdx -= 2;
1315 break;
1317 case TYPE2OP::GET: {
1318 assert( mnStackIdx >= 1 );
1319 const int nIdx = static_cast<int>(pTop[0]);
1320 assert( nIdx >= 0 );
1321 assert( nIdx < NMAXTRANS );
1322 pTop[0] = mnTransVals[ nIdx ];
1323 break;
1325 case TYPE2OP::IFELSE: {
1326 assert( mnStackIdx >= 4 );
1327 if( pTop[-1] > pTop[0] )
1328 pTop[-3] = pTop[-2];
1329 mnStackIdx -= 3;
1330 break;
1332 case TYPE2OP::RANDOM:
1333 pTop[+1] = 1234; // TODO
1334 ++mnStackIdx;
1335 break;
1336 case TYPE2OP::SQRT:
1337 // TODO: implement
1338 break;
1339 case TYPE2OP::DUP:
1340 assert( mnStackIdx >= 1 );
1341 pTop[+1] = pTop[0];
1342 ++mnStackIdx;
1343 break;
1344 case TYPE2OP::EXCH: {
1345 assert( mnStackIdx >= 2 );
1346 const ValType nVal = pTop[0];
1347 pTop[0] = pTop[-1];
1348 pTop[-1] = nVal;
1349 break;
1351 case TYPE2OP::INDEX: {
1352 assert( mnStackIdx >= 1 );
1353 const int nVal = static_cast<int>(pTop[0]);
1354 assert( nVal >= 0 );
1355 assert( nVal < mnStackIdx-1 );
1356 pTop[0] = pTop[-1-nVal];
1357 break;
1359 case TYPE2OP::ROLL: {
1360 assert( mnStackIdx >= 1 );
1361 const int nNum = static_cast<int>(pTop[0]);
1362 assert( nNum >= 0);
1363 assert( nNum < mnStackIdx-2 );
1364 (void)nNum; // TODO: implement
1365 const int nOfs = static_cast<int>(pTop[-1]);
1366 mnStackIdx -= 2;
1367 (void)nOfs;// TODO: implement
1368 break;
1370 case TYPE2OP::HFLEX1: {
1371 assert( mnStackIdx == 9 );
1372 writeCurveTo( mnStackIdx, -9, -8, -7, -6, -5, -6 );
1373 writeCurveTo( mnStackIdx, -4, -6, -3, -2, -1, -8 );
1374 mnStackIdx -= 9;
1376 break;
1377 case TYPE2OP::HFLEX: {
1378 assert( mnStackIdx == 7 );
1379 writeCurveTo( mnStackIdx, -7, 0, -6, -5, -4, -5 );
1380 writeCurveTo( mnStackIdx, -3, -5, -2, 0, -1, 0 );
1381 mnStackIdx -= 7;
1383 break;
1384 case TYPE2OP::FLEX: {
1385 assert( mnStackIdx == 13 );
1386 writeCurveTo( mnStackIdx, -13, -12, -11, -10, -9, -8 );
1387 writeCurveTo( mnStackIdx, -7, -6, -5, -4, -3, -2 );
1388 const ValType nFlexDepth = mnValStack[ mnStackIdx-1 ];
1389 (void)nFlexDepth; // ignoring nFlexDepth
1390 mnStackIdx -= 13;
1392 break;
1393 case TYPE2OP::FLEX1: {
1394 assert( mnStackIdx == 11 );
1395 // write the first part of the flex1-hinted curve
1396 writeCurveTo( mnStackIdx, -11, -10, -9, -8, -7, -6 );
1398 // determine if nD6 is horizontal or vertical
1399 const int i = mnStackIdx;
1400 ValType nDeltaX = mnValStack[i-11] + mnValStack[i-9] + mnValStack[i-7] + mnValStack[i-5] + mnValStack[i-3];
1401 if( nDeltaX < 0 ) nDeltaX = -nDeltaX;
1402 ValType nDeltaY = mnValStack[i-10] + mnValStack[i-8] + mnValStack[i-6] + mnValStack[i-4] + mnValStack[i-2];
1403 if( nDeltaY < 0 ) nDeltaY = -nDeltaY;
1404 const bool bVertD6 = (nDeltaY > nDeltaX);
1406 // write the second part of the flex1-hinted curve
1407 if( !bVertD6 )
1408 writeCurveTo( mnStackIdx, -5, -4, -3, -2, -1, 0);
1409 else
1410 writeCurveTo( mnStackIdx, -5, -4, -3, -2, 0, -1);
1411 mnStackIdx -= 11;
1413 break;
1414 default:
1415 fprintf( stderr,"unhandled type2esc %d\n", nType2Esc);
1416 assert( false);
1417 break;
1421 // --------------------------------------------------------------------
1423 void CffSubsetterContext::callType2Subr( bool bGlobal, int nSubrNumber)
1425 const U8* const pOldReadPtr = mpReadPtr;
1426 const U8* const pOldReadEnd = mpReadEnd;
1428 int nLen = 0;
1429 if( bGlobal ) {
1430 nSubrNumber += mnGlobalSubrBias;
1431 nLen = seekIndexData( mnGlobalSubrBase, nSubrNumber);
1432 } else {
1433 nSubrNumber += mpCffLocal->mnLocalSubrBias;
1434 nLen = seekIndexData( mpCffLocal->mnLocalSubrBase, nSubrNumber);
1437 while( mpReadPtr < mpReadEnd)
1438 convertOneTypeOp();
1440 mpReadPtr = pOldReadPtr;
1441 mpReadEnd = pOldReadEnd;
1444 // --------------------------------------------------------------------
1446 static const int MAX_T1OPS_SIZE = 81920; // TODO: use dynamic value
1448 int CffSubsetterContext::convert2Type1Ops( CffLocal* pCffLocal, const U8* const pT2Ops, int nT2Len, U8* const pT1Ops)
1450 mpCffLocal = pCffLocal;
1452 // prepare the charstring conversion
1453 mpWritePtr = pT1Ops;
1454 #if 1 // TODO: update caller
1455 U8 aType1Ops[ MAX_T1OPS_SIZE];
1456 if( !pT1Ops)
1457 mpWritePtr = aType1Ops;
1458 *const_cast<U8**>(&pT1Ops) = mpWritePtr;
1459 #else
1460 assert( pT1Ops);
1461 #endif
1463 // prepend random seed for T1crypt
1464 *(mpWritePtr++) = 0x48;
1465 *(mpWritePtr++) = 0x44;
1466 *(mpWritePtr++) = 0x55;
1467 *(mpWritePtr++) = ' ';
1468 #if 1 // convert the Type2 charstring to Type1
1469 mpReadPtr = pT2Ops;
1470 mpReadEnd = pT2Ops + nT2Len;
1471 // prepend "hsbw" or "sbw"
1472 // TODO: only emit hsbw when charwidth is known
1473 // TODO: remove charwidth from T2 stack
1474 writeType1Val( 0); // TODO: aSubsetterContext.getLeftSideBearing();
1475 writeType1Val( 1000/*###getCharWidth()###*/);
1476 writeTypeOp( TYPE1OP::HSBW);
1477 mbSawError = false;
1478 mbNeedClose = false;
1479 mbIgnoreHints = false;
1480 mnHintSize=mnHorzHintSize=mnStackIdx=0; mnCharWidth=-1;//#######
1481 mnCntrMask = 0;
1482 while( mpReadPtr < mpReadEnd)
1483 convertOneTypeOp();
1484 // if( bActivePath)
1485 // writeTypeOp( TYPE1OP::CLOSEPATH);
1486 // if( bSubRoutine)
1487 // writeTypeOp( TYPE1OP::RETURN);
1488 if( mbSawError) {
1489 mpWritePtr = pT1Ops+4;
1490 // create an "idiotproof" charstring
1491 writeType1Val( 0);
1492 writeType1Val( 800);
1493 writeTypeOp( TYPE1OP::HSBW);
1494 writeType1Val( 50);
1495 writeTypeOp( TYPE1OP::HMOVETO);
1496 writeType1Val( 650);
1497 writeType1Val( 100);
1498 writeTypeOp( TYPE1OP::RLINETO);
1499 writeType1Val( -350);
1500 writeType1Val( 700);
1501 writeTypeOp( TYPE1OP::RLINETO);
1502 #if 0
1503 writeType1Val( -300);
1504 writeType1Val( -800);
1505 writeTypeOp( TYPE1OP::RLINETO);
1506 #else
1507 writeTypeOp( TYPE1OP::CLOSEPATH);
1508 #endif
1509 writeTypeOp( TYPE1OP::ENDCHAR);
1511 #else // useful for manually encoding charstrings
1512 mpWritePtr = pT1Ops;
1513 mpWritePtr += sprintf( (char*)mpWritePtr, "OOo_\x8b\x8c\x0c\x10\x0b");
1514 #endif
1515 const int nType1Len = mpWritePtr - pT1Ops;
1517 // encrypt the Type1 charstring
1518 int nRDCryptR = 4330; // TODO: mnRDCryptSeed;
1519 for( U8* p = pT1Ops; p < mpWritePtr; ++p) {
1520 *p ^= (nRDCryptR >> 8);
1521 nRDCryptR = (*(U8*)p + nRDCryptR) * 52845 + 22719;
1524 return nType1Len;
1527 // --------------------------------------------------------------------
1529 RealType CffSubsetterContext::readRealVal()
1531 // TODO: more thorough number validity test
1532 bool bComma = false;
1533 int nExpVal = 0;
1534 int nExpSign = 0;
1535 S64 nNumber = 0;
1536 RealType fReal = +1.0;
1537 for(;;){
1538 const U8 c = *(mpReadPtr++); // read nibbles
1539 // parse high nibble
1540 const U8 nH = c >> 4U;
1541 if( nH <= 9) {
1542 nNumber = nNumber * 10 + nH;
1543 --nExpVal;
1544 } else if( nH == 10) { // comma
1545 nExpVal = 0;
1546 bComma = true;
1547 } else if( nH == 11) { // +exp
1548 fReal *= nNumber;
1549 nExpSign = +1;
1550 nNumber = 0;
1551 } else if( nH == 12) { // -exp
1552 fReal *= nNumber;
1553 nExpSign = -1;
1554 nNumber = 0;
1555 } else if( nH == 13) { // reserved
1556 // TODO: ignore or error?
1557 } else if( nH == 14) // minus
1558 fReal = -fReal;
1559 else if( nH == 15) // end
1560 break;
1561 // parse low nibble
1562 const U8 nL = c & 0x0F;
1563 if( nL <= 9) {
1564 nNumber = nNumber * 10 + nL;
1565 --nExpVal;
1566 } else if( nL == 10) { // comma
1567 nExpVal = 0;
1568 bComma = true;
1569 } else if( nL == 11) { // +exp
1570 fReal *= nNumber;
1571 nNumber = 0;
1572 nExpSign = +1;
1573 } else if( nL == 12) { // -exp
1574 fReal *= nNumber;
1575 nNumber = 0;
1576 nExpSign = -1;
1577 } else if( nL == 13) { // reserved
1578 // TODO: ignore or error?
1579 } else if( nL == 14) // minus
1580 fReal = -fReal;
1581 else if( nL == 15) // end
1582 break;
1585 // merge exponents
1586 if( !bComma)
1587 nExpVal = 0;
1588 if( !nExpSign) { fReal *= nNumber;}
1589 else if( nExpSign > 0) { nExpVal += static_cast<int>(nNumber);}
1590 else if( nExpSign < 0) { nExpVal -= static_cast<int>(nNumber);}
1592 // apply exponents
1593 if( !nExpVal) { /*nothing to apply*/}
1594 else if( nExpVal > 0) { while( --nExpVal >= 0) fReal *= 10.0;}
1595 else if( nExpVal < 0) { while( ++nExpVal <= 0) fReal /= 10.0;}
1596 return fReal;
1599 // --------------------------------------------------------------------
1601 // prepare to access an element inside a CFF/CID index table
1602 int CffSubsetterContext::seekIndexData( int nIndexBase, int nDataIndex)
1604 assert( (nIndexBase > 0) && (mpBasePtr + nIndexBase + 3 <= mpBaseEnd));
1605 if( nDataIndex < 0)
1606 return -1;
1607 mpReadPtr = mpBasePtr + nIndexBase;
1608 const int nDataCount = (mpReadPtr[0]<<8) + mpReadPtr[1];
1609 if( nDataIndex >= nDataCount)
1610 return -1;
1611 const int nDataOfsSz = mpReadPtr[2];
1612 mpReadPtr += 3 + (nDataOfsSz * nDataIndex);
1613 int nOfs1 = 0;
1614 switch( nDataOfsSz) {
1615 default: fprintf( stderr, "\tINVALID nDataOfsSz=%d\n\n", nDataOfsSz); return -1;
1616 case 1: nOfs1 = mpReadPtr[0]; break;
1617 case 2: nOfs1 = (mpReadPtr[0]<<8) + mpReadPtr[1]; break;
1618 case 3: nOfs1 = (mpReadPtr[0]<<16) + (mpReadPtr[1]<<8) + mpReadPtr[2]; break;
1619 case 4: nOfs1 = (mpReadPtr[0]<<24) + (mpReadPtr[1]<<16) + (mpReadPtr[2]<<8) + mpReadPtr[3]; break;
1621 mpReadPtr += nDataOfsSz;
1623 int nOfs2 = 0;
1624 switch( nDataOfsSz) {
1625 case 1: nOfs2 = mpReadPtr[0]; break;
1626 case 2: nOfs2 = (mpReadPtr[0]<<8) + mpReadPtr[1]; break;
1627 case 3: nOfs2 = (mpReadPtr[0]<<16) + (mpReadPtr[1]<<8) + mpReadPtr[2]; break;
1628 case 4: nOfs2 = (mpReadPtr[0]<<24) + (mpReadPtr[1]<<16) + (mpReadPtr[2]<<8) + mpReadPtr[3]; break;
1631 mpReadPtr = mpBasePtr + (nIndexBase + 2) + nDataOfsSz * (nDataCount + 1) + nOfs1;
1632 mpReadEnd = mpReadPtr + (nOfs2 - nOfs1);
1633 assert( nOfs1 >= 0);
1634 assert( nOfs2 >= nOfs1);
1635 assert( mpReadPtr <= mpBaseEnd);
1636 assert( mpReadEnd <= mpBaseEnd);
1637 return (nOfs2 - nOfs1);
1640 // --------------------------------------------------------------------
1642 // skip over a CFF/CID index table
1643 void CffSubsetterContext::seekIndexEnd( int nIndexBase)
1645 assert( (nIndexBase > 0) && (mpBasePtr + nIndexBase + 3 <= mpBaseEnd));
1646 mpReadPtr = mpBasePtr + nIndexBase;
1647 const int nDataCount = (mpReadPtr[0]<<8) + mpReadPtr[1];
1648 const int nDataOfsSz = mpReadPtr[2];
1649 mpReadPtr += 3 + nDataOfsSz * nDataCount;
1650 assert( mpReadPtr <= mpBaseEnd);
1651 int nEndOfs = 0;
1652 switch( nDataOfsSz) {
1653 default: fprintf( stderr, "\tINVALID nDataOfsSz=%d\n\n", nDataOfsSz); return;
1654 case 1: nEndOfs = mpReadPtr[0]; break;
1655 case 2: nEndOfs = (mpReadPtr[0]<<8) + mpReadPtr[1]; break;
1656 case 3: nEndOfs = (mpReadPtr[0]<<16) + (mpReadPtr[1]<<8) + mpReadPtr[2];break;
1657 case 4: nEndOfs = (mpReadPtr[0]<<24) + (mpReadPtr[1]<<16) + (mpReadPtr[2]<<8) + mpReadPtr[3]; break;
1659 mpReadPtr += nDataOfsSz;
1660 mpReadPtr += nEndOfs - 1;
1661 mpReadEnd = mpBaseEnd;
1662 assert( nEndOfs >= 0);
1663 assert( mpReadEnd <= mpBaseEnd);
1666 // ====================================================================
1668 // initialize FONTDICT specific values
1669 CffLocal::CffLocal( void)
1670 : mnPrivDictBase( 0)
1671 , mnPrivDictSize( 0)
1672 , mnLocalSubrOffs( 0)
1673 , mnLocalSubrBase( 0)
1674 , mnLocalSubrCount( 0)
1675 , mnLocalSubrBias( 0)
1676 , mnNominalWidth( 0)
1677 , mnDefaultWidth( 0)
1678 , mnStemStdHW( 0)
1679 , mnStemStdVW( 0)
1680 , mfBlueScale( 0.0)
1681 , mfBlueShift( 0.0)
1682 , mfBlueFuzz( 0.0)
1683 , mfExpFactor( 0.0)
1684 , mnLangGroup( 0)
1685 , mbForceBold( false)
1687 maStemSnapH.clear();
1688 maStemSnapV.clear();
1689 maBlueValues.clear();
1690 maOtherBlues.clear();
1691 maFamilyBlues.clear();
1692 maFamilyOtherBlues.clear();
1695 // --------------------------------------------------------------------
1697 CffGlobal::CffGlobal( void)
1698 : mnNameIdxBase( 0)
1699 , mnNameIdxCount( 0)
1700 , mnStringIdxBase( 0)
1701 , mnStringIdxCount( 0)
1702 , mbCIDFont( false)
1703 , mnCharStrBase( 0)
1704 , mnCharStrCount( 0)
1705 , mnEncodingBase( 0)
1706 , mnCharsetBase( 0)
1707 , mnGlobalSubrBase( 0)
1708 , mnGlobalSubrCount( 0)
1709 , mnGlobalSubrBias( 0)
1710 , mnFDSelectBase( 0)
1711 , mnFontDictBase( 0)
1712 , mnFDAryCount( 1)
1713 , mnFontNameSID( 0)
1714 , mnFullNameSID( 0)
1715 , mnFamilyNameSID( 0)
1717 maFontBBox.clear();
1718 // TODO; maFontMatrix.clear();
1721 // --------------------------------------------------------------------
1723 void CffSubsetterContext::initialCffRead( void)
1725 // get the CFFHeader
1726 mpReadPtr = mpBasePtr;
1727 const U8 nVerMajor = *(mpReadPtr++);
1728 const U8 nVerMinor = *(mpReadPtr++);
1729 const U8 nHeaderSize = *(mpReadPtr++);
1730 const U8 nOffsetSize = *(mpReadPtr++);
1731 // TODO: is the version number useful for anything else?
1732 assert( (nVerMajor == 1) && (nVerMinor == 0));
1733 (void)(nVerMajor + nVerMinor + nOffsetSize); // avoid compiler warnings
1735 // prepare access to the NameIndex
1736 mnNameIdxBase = nHeaderSize;
1737 mpReadPtr = mpBasePtr + nHeaderSize;
1738 mnNameIdxCount = (mpReadPtr[0]<<8) + mpReadPtr[1];
1739 seekIndexEnd( mnNameIdxBase);
1741 // get the TopDict index
1742 const long nTopDictBase = getReadOfs();
1743 const int nTopDictCount = (mpReadPtr[0]<<8) + mpReadPtr[1];
1744 if( nTopDictCount) {
1745 for( int i = 0; i < nTopDictCount; ++i) {
1746 seekIndexData( nTopDictBase, i);
1747 while( mpReadPtr < mpReadEnd)
1748 readDictOp();
1749 assert( mpReadPtr == mpReadEnd);
1753 // prepare access to the String index
1754 mnStringIdxBase = getReadOfs();
1755 mnStringIdxCount = (mpReadPtr[0]<<8) + mpReadPtr[1];
1756 seekIndexEnd( mnStringIdxBase);
1758 // prepare access to the GlobalSubr index
1759 mnGlobalSubrBase = getReadOfs();
1760 mnGlobalSubrCount = (mpReadPtr[0]<<8) + mpReadPtr[1];
1761 mnGlobalSubrBias = (mnGlobalSubrCount<1240)?107:(mnGlobalSubrCount<33900)?1131:32768;
1762 // skip past the last GlobalSubr entry
1763 // seekIndexEnd( mnGlobalSubrBase);
1765 // get/skip the Encodings (we got mnEncodingBase from TOPDICT)
1766 // seekEncodingsEnd( mnEncodingBase);
1767 // get/skip the Charsets (we got mnCharsetBase from TOPDICT)
1768 // seekCharsetsEnd( mnCharStrBase);
1769 // get/skip FDSelect (CID only) data
1771 // prepare access to the CharStrings index (we got the base from TOPDICT)
1772 mpReadPtr = mpBasePtr + mnCharStrBase;
1773 mnCharStrCount = (mpReadPtr[0]<<8) + mpReadPtr[1];
1774 // seekIndexEnd( mnCharStrBase);
1776 // read the FDArray index (CID only)
1777 if( mbCIDFont) {
1778 // assert( mnFontDictBase == tellRel());
1779 mpReadPtr = mpBasePtr + mnFontDictBase;
1780 mnFDAryCount = (mpReadPtr[0]<<8) + mpReadPtr[1];
1781 assert( mnFDAryCount < (int)(sizeof(maCffLocal)/sizeof(*maCffLocal)));
1783 // read FDArray details to get access to the PRIVDICTs
1784 for( int i = 0; i < mnFDAryCount; ++i) {
1785 mpCffLocal = &maCffLocal[i];
1786 seekIndexData( mnFontDictBase, i);
1787 while( mpReadPtr < mpReadEnd)
1788 readDictOp();
1789 assert( mpReadPtr == mpReadEnd);
1793 for( int i = 0; i < mnFDAryCount; ++i) {
1794 mpCffLocal = &maCffLocal[i];
1796 // get the PrivateDict index
1797 // (we got mnPrivDictSize and mnPrivDictBase from TOPDICT or FDArray)
1798 if( mpCffLocal->mnPrivDictSize != 0) {
1799 assert( mpCffLocal->mnPrivDictSize > 0);
1800 // get the PrivDict data
1801 mpReadPtr = mpBasePtr + mpCffLocal->mnPrivDictBase;
1802 mpReadEnd = mpReadPtr + mpCffLocal->mnPrivDictSize;
1803 assert( mpReadEnd <= mpBaseEnd);
1804 // read PrivDict details
1805 while( mpReadPtr < mpReadEnd)
1806 readDictOp();
1809 // prepare access to the LocalSubrs (we got mnLocalSubrOffs from PRIVDICT)
1810 if( mpCffLocal->mnLocalSubrOffs) {
1811 // read LocalSubrs summary
1812 mpCffLocal->mnLocalSubrBase = mpCffLocal->mnPrivDictBase + mpCffLocal->mnLocalSubrOffs;
1813 mpReadPtr = mpBasePtr + mpCffLocal->mnLocalSubrBase;
1814 const int nSubrCount = (mpReadPtr[0] << 8) + mpReadPtr[1];
1815 mpCffLocal->mnLocalSubrCount = nSubrCount;
1816 mpCffLocal->mnLocalSubrBias = (nSubrCount<1240)?107:(nSubrCount<33900)?1131:32768;
1817 // seekIndexEnd( mpCffLocal->mnLocalSubrBase);
1821 // ignore the Notices info
1824 // --------------------------------------------------------------------
1826 // get a cstring from a StringID
1827 const char* CffSubsetterContext::getString( int nStringID)
1829 // get a standard string if possible
1830 const static int nStdStrings = sizeof(pStringIds)/sizeof(*pStringIds);
1831 if( (nStringID >= 0) && (nStringID < nStdStrings))
1832 return pStringIds[ nStringID];
1834 // else get the string from the StringIndex table
1835 const U8* pReadPtr = mpReadPtr;
1836 const U8* pReadEnd = mpReadEnd;
1837 nStringID -= nStdStrings;
1838 int nLen = seekIndexData( mnStringIdxBase, nStringID);
1839 // assert( nLen >= 0);
1840 // TODO: just return the undecorated name
1841 // TODO: get rid of static char buffer
1842 static char aNameBuf[ 2560];
1843 if( nLen < 0) {
1844 sprintf( aNameBuf, "name[%d].notfound!", nStringID);
1845 } else {
1846 const int nMaxLen = sizeof(aNameBuf) - 1;
1847 if( nLen >= nMaxLen)
1848 nLen = nMaxLen;
1849 for( int i = 0; i < nLen; ++i)
1850 aNameBuf[i] = *(mpReadPtr++);
1851 aNameBuf[ nLen] = '\0';
1853 mpReadPtr = pReadPtr;
1854 mpReadEnd = pReadEnd;
1855 return aNameBuf;
1858 // --------------------------------------------------------------------
1860 // access a CID's FDSelect table
1861 int CffSubsetterContext::getFDSelect( int nGlyphIndex) const
1863 assert( nGlyphIndex >= 0);
1864 assert( nGlyphIndex < mnCharStrCount);
1865 if( !mbCIDFont)
1866 return 0;
1868 const U8* pReadPtr = mpBasePtr + mnFDSelectBase;
1869 const U8 nFDSelFormat = *(pReadPtr++);
1870 switch( nFDSelFormat) {
1871 case 0: { // FDSELECT format 0
1872 pReadPtr += nGlyphIndex;
1873 const U8 nFDIdx = *(pReadPtr++);
1874 return nFDIdx;
1875 } //break;
1876 case 3: { // FDSELECT format 3
1877 const U16 nRangeCount = (pReadPtr[0]<<8) + pReadPtr[1];
1878 assert( nRangeCount > 0);
1879 assert( nRangeCount <= mnCharStrCount);
1880 U16 nPrev = (pReadPtr[2]<<8) + pReadPtr[3];
1881 assert( nPrev == 0);
1882 pReadPtr += 4;
1883 // TODO? binary search
1884 for( int i = 0; i < nRangeCount; ++i) {
1885 const U8 nFDIdx = pReadPtr[0];
1886 const U16 nNext = (pReadPtr[1]<<8) + pReadPtr[2];
1887 assert( nPrev < nNext);
1888 if( nGlyphIndex < nNext)
1889 return nFDIdx;
1890 pReadPtr += 3;
1891 nPrev = nNext;
1893 } break;
1894 default: // invalid FDselect format
1895 fprintf( stderr, "invalid CFF.FdselType=%d\n", nFDSelFormat);
1896 break;
1899 assert( false);
1900 return -1;
1903 // --------------------------------------------------------------------
1905 int CffSubsetterContext::getGlyphSID( int nGlyphIndex) const
1907 if( nGlyphIndex == 0)
1908 return 0; // ".notdef"
1909 assert( nGlyphIndex >= 0);
1910 assert( nGlyphIndex < mnCharStrCount);
1911 if( (nGlyphIndex < 0) || (nGlyphIndex >= mnCharStrCount))
1912 return -1;
1914 // get the SID/CID from the Charset table
1915 const U8* pReadPtr = mpBasePtr + mnCharsetBase;
1916 const U8 nCSetFormat = *(pReadPtr++);
1917 int nGlyphsToSkip = nGlyphIndex - 1;
1918 switch( nCSetFormat) {
1919 case 0: // charset format 0
1920 pReadPtr += 2 * nGlyphsToSkip;
1921 nGlyphsToSkip = 0;
1922 break;
1923 case 1: // charset format 1
1924 while( nGlyphsToSkip >= 0) {
1925 const int nLeft = pReadPtr[2];
1926 if( nGlyphsToSkip <= nLeft)
1927 break;
1928 nGlyphsToSkip -= nLeft + 1;
1929 pReadPtr += 3;
1931 break;
1932 case 2: // charset format 2
1933 while( nGlyphsToSkip >= 0) {
1934 const int nLeft = (pReadPtr[2]<<8) + pReadPtr[3];
1935 if( nGlyphsToSkip <= nLeft)
1936 break;
1937 nGlyphsToSkip -= nLeft + 1;
1938 pReadPtr += 4;
1940 break;
1941 default:
1942 fprintf( stderr, "ILLEGAL CFF-Charset format %d\n", nCSetFormat);
1943 return -2;
1946 int nSID = (pReadPtr[0]<<8) + pReadPtr[1];
1947 nSID += nGlyphsToSkip;
1948 // NOTE: for CID-fonts the resulting SID is interpreted as CID
1949 return nSID;
1952 // --------------------------------------------------------------------
1954 // NOTE: the result becomes invalid with the next call to this method
1955 const char* CffSubsetterContext::getGlyphName( int nGlyphIndex)
1957 // the first glyph is always the .notdef glyph
1958 const char* pGlyphName = ".notdef";
1959 if( nGlyphIndex == 0)
1960 return pGlyphName;
1962 // prepare a result buffer
1963 // TODO: get rid of static buffer
1964 static char aDefaultGlyphName[64];
1965 pGlyphName = aDefaultGlyphName;
1967 // get the glyph specific name
1968 const int nSID = getGlyphSID( nGlyphIndex);
1969 if( nSID < 0) // default glyph name
1970 sprintf( aDefaultGlyphName, "gly%03d", nGlyphIndex);
1971 else if( mbCIDFont) // default glyph name in CIDs
1972 sprintf( aDefaultGlyphName, "cid%03d", nSID);
1973 else { // glyph name from string table
1974 const char* pSidName = getString( nSID);
1975 // check validity of glyph name
1976 if( pSidName) {
1977 const char* p = pSidName;
1978 while( (*p >= '0') && (*p <= 'z')) ++p;
1979 if( (p >= pSidName+1) && (*p == '\0'))
1980 pGlyphName = pSidName;
1982 // if needed invent a fallback name
1983 if( pGlyphName != pSidName)
1984 sprintf( aDefaultGlyphName, "bad%03d", nSID);
1987 return pGlyphName;
1990 // --------------------------------------------------------------------
1992 class Type1Emitter
1994 public:
1995 explicit Type1Emitter( const char* pOutFileName, bool bPfbSubset = true);
1996 explicit Type1Emitter( FILE* pOutFile, bool bPfbSubset = true);
1997 /*virtual*/ ~Type1Emitter( void);
1998 void setSubsetName( const char* );
2000 void emitRawData( const char* pData, int nLength) const;
2001 void emitAllRaw( void);
2002 void emitAllHex( void);
2003 void emitAllCrypted( void);
2004 int tellPos( void) const;
2005 void updateLen( int nTellPos, int nLength);
2006 void emitValVector( const char* pLineHead, const char* pLineTail, const ValVector&);
2007 private:
2008 FILE* mpFileOut;
2009 bool mbCloseOutfile;
2010 char maBuffer[MAX_T1OPS_SIZE]; // TODO: dynamic allocation
2011 int mnEECryptR;
2012 public:
2013 char* mpPtr;
2015 char maSubsetName[256];
2016 bool mbPfbSubset;
2017 int mnHexLineCol;
2020 // --------------------------------------------------------------------
2022 Type1Emitter::Type1Emitter( const char* pPfbFileName, bool bPfbSubset)
2023 : mpFileOut( NULL)
2024 , mbCloseOutfile( true)
2025 , mnEECryptR( 55665) // default eexec seed, TODO: mnEECryptSeed
2026 , mpPtr( maBuffer)
2027 , mbPfbSubset( bPfbSubset)
2028 , mnHexLineCol( 0)
2030 mpFileOut = fopen( pPfbFileName, "wb");
2031 maSubsetName[0] = '\0';
2034 // --------------------------------------------------------------------
2036 Type1Emitter::Type1Emitter( FILE* pOutFile, bool bPfbSubset)
2037 : mpFileOut( pOutFile)
2038 , mbCloseOutfile( false)
2039 , mnEECryptR( 55665) // default eexec seed, TODO: mnEECryptSeed
2040 , mpPtr( maBuffer)
2041 , mbPfbSubset( bPfbSubset)
2042 , mnHexLineCol( 0)
2044 maSubsetName[0] = '\0';
2047 // --------------------------------------------------------------------
2049 Type1Emitter::~Type1Emitter( void)
2051 if( !mpFileOut)
2052 return;
2053 if( mbCloseOutfile )
2054 fclose( mpFileOut);
2055 mpFileOut = NULL;
2058 // --------------------------------------------------------------------
2060 void Type1Emitter::setSubsetName( const char* pSubsetName)
2062 maSubsetName[0] = '\0';
2063 if( pSubsetName)
2064 strncpy( maSubsetName, pSubsetName, sizeof(maSubsetName));
2065 maSubsetName[sizeof(maSubsetName)-1] = '\0';
2068 // --------------------------------------------------------------------
2070 int Type1Emitter::tellPos( void) const
2072 int nTellPos = ftell( mpFileOut);
2073 return nTellPos;
2076 // --------------------------------------------------------------------
2078 void Type1Emitter::updateLen( int nTellPos, int nLength)
2080 // update PFB segment header length
2081 U8 cData[4];
2082 cData[0] = static_cast<U8>(nLength >> 0);
2083 cData[1] = static_cast<U8>(nLength >> 8);
2084 cData[2] = static_cast<U8>(nLength >> 16);
2085 cData[3] = static_cast<U8>(nLength >> 24);
2086 const int nCurrPos = ftell( mpFileOut);
2087 fseek( mpFileOut, nTellPos, SEEK_SET);
2088 fwrite( cData, 1, sizeof(cData), mpFileOut);
2089 fseek( mpFileOut, nCurrPos, SEEK_SET);
2092 // --------------------------------------------------------------------
2094 inline void Type1Emitter::emitRawData( const char* pData, int nLength) const
2096 fwrite( pData, 1, nLength, mpFileOut);
2099 // --------------------------------------------------------------------
2101 inline void Type1Emitter::emitAllRaw( void)
2103 // writeout raw data
2104 assert( (mpPtr - maBuffer) < (int)sizeof(maBuffer));
2105 emitRawData( maBuffer, mpPtr - maBuffer);
2106 // reset the raw buffer
2107 mpPtr = maBuffer;
2110 // --------------------------------------------------------------------
2112 inline void Type1Emitter::emitAllHex( void)
2114 assert( (mpPtr - maBuffer) < (int)sizeof(maBuffer));
2115 for( const char* p = maBuffer; p < mpPtr;) {
2116 // convert binary chunk to hex
2117 char aHexBuf[0x4000];
2118 char* pOut = aHexBuf;
2119 while( (p < mpPtr) && (pOut < aHexBuf+sizeof(aHexBuf)-4)) {
2120 // convert each byte to hex
2121 char cNibble = (*p >> 4) & 0x0F;
2122 cNibble += (cNibble < 10) ? '0' : 'A'-10;
2123 *(pOut++) = cNibble;
2124 cNibble = *(p++) & 0x0F;
2125 cNibble += (cNibble < 10) ? '0' : 'A'-10;
2126 *(pOut++) = cNibble;
2127 // limit the line length
2128 if( (++mnHexLineCol & 0x3F) == 0)
2129 *(pOut++) = '\n';
2131 // writeout hex-converted chunk
2132 emitRawData( aHexBuf, pOut-aHexBuf);
2134 // reset the raw buffer
2135 mpPtr = maBuffer;
2138 // --------------------------------------------------------------------
2140 void Type1Emitter::emitAllCrypted( void)
2142 // apply t1crypt
2143 for( char* p = maBuffer; p < mpPtr; ++p) {
2144 *p ^= (mnEECryptR >> 8);
2145 mnEECryptR = (*(U8*)p + mnEECryptR) * 52845 + 22719;
2148 // emit the t1crypt result
2149 if( mbPfbSubset)
2150 emitAllRaw();
2151 else
2152 emitAllHex();
2155 // --------------------------------------------------------------------
2157 void Type1Emitter::emitValVector( const char* pLineHead, const char* pLineTail,
2158 const ValVector& rVector)
2160 // ignore empty vectors
2161 if( rVector.empty())
2162 return;
2164 // emit the line head
2165 mpPtr += sprintf( mpPtr, pLineHead);
2166 // emit the vector values
2167 ValVector::value_type aVal = 0;
2168 for( ValVector::const_iterator it = rVector.begin();;) {
2169 aVal = *it;
2170 if( ++it == rVector.end() )
2171 break;
2172 mpPtr += sprintf( mpPtr, "%g ", aVal);
2174 // emit the last value
2175 mpPtr += sprintf( mpPtr, "%g", aVal);
2176 // emit the line tail
2177 mpPtr += sprintf( mpPtr, pLineTail);
2180 // --------------------------------------------------------------------
2182 bool CffSubsetterContext::emitAsType1( Type1Emitter& rEmitter,
2183 const long* pReqGlyphIDs, const U8* pReqEncoding,
2184 GlyphWidth* pGlyphWidths, int nGlyphCount, FontSubsetInfo& rFSInfo)
2186 // prepare some fontdirectory details
2187 static const int nUniqueIdBase = 4100000; // using private-interchange UniqueIds
2188 static int nUniqueId = nUniqueIdBase;
2189 ++nUniqueId;
2191 char* pFontName = rEmitter.maSubsetName;
2192 if( !*pFontName ) {
2193 if( mnFontNameSID) {
2194 // get the fontname directly if available
2195 strncpy( pFontName, getString( mnFontNameSID), sizeof(rEmitter.maSubsetName));
2196 } else if( mnFullNameSID) {
2197 // approximate fontname as fullname-whitespace
2198 const char* pI = getString( mnFullNameSID);
2199 char* pO = pFontName;
2200 const char* pLimit = pFontName + sizeof(rEmitter.maSubsetName) - 1;
2201 while( pO < pLimit) {
2202 const char c = *(pI++);
2203 if( c != ' ')
2204 *(pO++) = c;
2205 if( !c)
2206 break;
2208 *pO = '\0';
2209 } else {
2210 // fallback name of last resort
2211 strncpy( pFontName, "DummyName", sizeof(rEmitter.maSubsetName));
2214 const char* pFullName = pFontName;
2215 const char* pFamilyName = pFontName;
2217 char*& pOut = rEmitter.mpPtr; // convenience reference, TODO: cleanup
2219 // create a PFB+Type1 header
2220 if( rEmitter.mbPfbSubset ) {
2221 static const char aPfbHeader[] = "\x80\x01\x00\x00\x00\x00";
2222 rEmitter.emitRawData( aPfbHeader, sizeof(aPfbHeader)-1);
2225 pOut += sprintf( pOut, "%%!FontType1-1.0: %s 001.003\n", rEmitter.maSubsetName);
2226 // emit TOPDICT
2227 #if 0 // improve PS Type1 caching?
2228 nOfs += sprintf( &aT1Str[nOfs],
2229 "FontDirectory/%s known{/%s findfont dup/UniqueID known{dup\n"
2230 "/UniqueID get %d eq exch/FontType get 1 eq and}{pop false}ifelse\n"
2231 "{save true}{false}ifelse}\n{false}ifelse\n",
2232 pFamilyName, pFamilyName, nUniqueId);
2233 #endif
2234 pOut += sprintf( pOut,
2235 "11 dict begin\n" // TODO: dynamic entry count for TOPDICT
2236 "/FontType 1 def\n"
2237 "/PaintType 0 def\n");
2238 pOut += sprintf( pOut, "/FontName /%s def\n", rEmitter.maSubsetName);
2239 pOut += sprintf( pOut, "/UniqueID %d def\n", nUniqueId);
2240 // emit FontMatrix
2241 if( maFontMatrix.size() == 6)
2242 rEmitter.emitValVector( "/FontMatrix [", "]readonly def\n", maFontMatrix);
2243 else // emit default FontMatrix if needed
2244 pOut += sprintf( pOut, "/FontMatrix [0.001 0 0 0.001 0 0]readonly def\n");
2245 // emit FontBBox
2246 if( maFontBBox.size() == 4)
2247 rEmitter.emitValVector( "/FontBBox {", "}readonly def\n", maFontBBox);
2248 else // emit default FontBBox if needed
2249 pOut += sprintf( pOut, "/FontBBox {0 0 999 999}readonly def\n");
2250 // emit FONTINFO into TOPDICT
2251 pOut += sprintf( pOut,
2252 "/FontInfo 2 dict dup begin\n" // TODO: check fontinfo entry count
2253 " /FullName (%s) readonly def\n"
2254 " /FamilyName (%s) readonly def\n"
2255 "end readonly def\n",
2256 pFullName, pFamilyName);
2257 #if 0 // TODO: use an standard Type1 encoding if possible
2258 pOut += sprintf( pOut,
2259 "/Encoding StandardEncoding def\n");
2260 #else
2261 pOut += sprintf( pOut,
2262 "/Encoding 256 array\n"
2263 "0 1 255 {1 index exch /.notdef put} for\n");
2264 for( int i = 1; (i < nGlyphCount) && (i < 256); ++i) {
2265 const char* pGlyphName = getGlyphName( pReqGlyphIDs[i]);
2266 pOut += sprintf( pOut, "dup %d /%s put\n", pReqEncoding[i], pGlyphName);
2268 pOut += sprintf( pOut, "readonly def\n");
2269 #endif
2270 pOut += sprintf( pOut,
2271 // TODO: more topdict entries
2272 "currentdict end\n"
2273 "currentfile eexec\n");
2275 // emit PFB header
2276 rEmitter.emitAllRaw();
2277 if( rEmitter.mbPfbSubset) {
2278 // update PFB header segment
2279 const int nPfbHeaderLen = rEmitter.tellPos() - 6;
2280 rEmitter.updateLen( 2, nPfbHeaderLen);
2282 // prepare start of eexec segment
2283 rEmitter.emitRawData( "\x80\x02\x00\x00\x00\x00", 6); // segment start
2285 const int nEExecSegTell = rEmitter.tellPos();
2287 // which always starts with a privdict
2288 // count the privdict entries
2289 int nPrivEntryCount = 9;
2290 #if !defined(IGNORE_HINTS)
2291 // emit blue hints only if non-default values
2292 nPrivEntryCount += !mpCffLocal->maOtherBlues.empty();
2293 nPrivEntryCount += !mpCffLocal->maFamilyBlues.empty();
2294 nPrivEntryCount += !mpCffLocal->maFamilyOtherBlues.empty();
2295 nPrivEntryCount += (mpCffLocal->mfBlueScale != 0.0);
2296 nPrivEntryCount += (mpCffLocal->mfBlueShift != 0.0);
2297 nPrivEntryCount += (mpCffLocal->mfBlueFuzz != 0.0);
2298 // emit stem hints only if non-default values
2299 nPrivEntryCount += (mpCffLocal->mnStemStdHW != 0);
2300 nPrivEntryCount += (mpCffLocal->mnStemStdVW != 0);
2301 nPrivEntryCount += !mpCffLocal->maStemSnapH.empty();
2302 nPrivEntryCount += !mpCffLocal->maStemSnapV.empty();
2303 // emit other hints only if non-default values
2304 nPrivEntryCount += (mpCffLocal->mfExpFactor != 0.0);
2305 nPrivEntryCount += (mpCffLocal->mnLangGroup != 0);
2306 nPrivEntryCount += (mpCffLocal->mnLangGroup == 1);
2307 nPrivEntryCount += (mpCffLocal->mbForceBold != false);
2308 #endif // IGNORE_HINTS
2309 // emit the privdict header
2310 pOut += sprintf( pOut,
2311 "\110\104\125 "
2312 "dup\n/Private %d dict dup begin\n"
2313 "/RD{string currentfile exch readstring pop}executeonly def\n"
2314 "/ND{noaccess def}executeonly def\n"
2315 "/NP{noaccess put}executeonly def\n"
2316 "/MinFeature{16 16}ND\n"
2317 "/password 5839 def\n", // TODO: mnRDCryptSeed?
2318 nPrivEntryCount);
2320 #if defined(IGNORE_HINTS)
2321 pOut += sprintf( pOut, "/BlueValues []ND\n"); // BlueValues are mandatory
2322 #else
2323 // emit blue hint related privdict entries
2324 if( !mpCffLocal->maBlueValues.empty())
2325 rEmitter.emitValVector( "/BlueValues [", "]ND\n", mpCffLocal->maBlueValues);
2326 else
2327 pOut += sprintf( pOut, "/BlueValues []ND\n"); // default to empty BlueValues
2328 rEmitter.emitValVector( "/OtherBlues [", "]ND\n", mpCffLocal->maOtherBlues);
2329 rEmitter.emitValVector( "/FamilyBlues [", "]ND\n", mpCffLocal->maFamilyBlues);
2330 rEmitter.emitValVector( "/FamilyOtherBlues [", "]ND\n", mpCffLocal->maFamilyOtherBlues);
2332 if( mpCffLocal->mfBlueScale)
2333 pOut += sprintf( pOut, "/BlueScale %.6f def\n", mpCffLocal->mfBlueScale);
2334 if( mpCffLocal->mfBlueShift) // default BlueShift==7
2335 pOut += sprintf( pOut, "/BlueShift %.1f def\n", mpCffLocal->mfBlueShift);
2336 if( mpCffLocal->mfBlueFuzz) // default BlueFuzz==1
2337 pOut += sprintf( pOut, "/BlueFuzz %.1f def\n", mpCffLocal->mfBlueFuzz);
2339 // emit stem hint related privdict entries
2340 if( mpCffLocal->mnStemStdHW)
2341 pOut += sprintf( pOut, "/StdHW [%d] def\n", mpCffLocal->mnStemStdHW);
2342 if( mpCffLocal->mnStemStdVW)
2343 pOut += sprintf( pOut, "/StdVW [%d] def\n", mpCffLocal->mnStemStdVW);
2344 rEmitter.emitValVector( "/StemSnapH [", "]ND\n", mpCffLocal->maStemSnapH);
2345 rEmitter.emitValVector( "/StemSnapV [", "]ND\n", mpCffLocal->maStemSnapV);
2347 // emit other hints
2348 if( mpCffLocal->mbForceBold)
2349 pOut += sprintf( pOut, "/ForceBold true def\n");
2350 if( mpCffLocal->mnLangGroup != 0)
2351 pOut += sprintf( pOut, "/LanguageGroup %d def\n", mpCffLocal->mnLangGroup);
2352 if( mpCffLocal->mnLangGroup == 1) // compatibility with ancient printers
2353 pOut += sprintf( pOut, "/RndStemUp false def\n");
2354 if( mpCffLocal->mfExpFactor)
2355 pOut += sprintf( pOut, "/ExpansionFactor %.2f def\n", mpCffLocal->mfExpFactor);
2356 #endif // IGNORE_HINTS
2358 // emit remaining privdict entries
2359 pOut += sprintf( pOut, "/UniqueID %d def\n", nUniqueId);
2360 // TODO?: more privdict entries?
2362 static const char aOtherSubrs[] =
2363 "/OtherSubrs\n"
2364 "% Dummy code for faking flex hints\n"
2365 "[ {} {} {} {systemdict /internaldict known not {pop 3}\n"
2366 "{1183615869 systemdict /internaldict get exec\n"
2367 "dup /startlock known\n"
2368 "{/startlock get exec}\n"
2369 "{dup /strtlck known\n"
2370 "{/strtlck get exec}\n"
2371 "{pop 3}\nifelse}\nifelse}\nifelse\n} executeonly\n"
2372 "] ND\n";
2373 memcpy( pOut, aOtherSubrs, sizeof(aOtherSubrs)-1);
2374 pOut += sizeof(aOtherSubrs)-1;
2376 // emit used GlobalSubr charstrings
2377 // these are the just the default subrs
2378 static const char aSubrs[] =
2379 "/Subrs 5 array\n"
2380 "dup 0 15 RD \x5F\x3D\x6B\xAC\x3C\xBD\x74\x3D\x3E\x17\xA0\x86\x58\x08\x85 NP\n"
2381 "dup 1 9 RD \x5F\x3D\x6B\xD8\xA6\xB5\x68\xB6\xA2 NP\n"
2382 "dup 2 9 RD \x5F\x3D\x6B\xAC\x39\x46\xB9\x43\xF9 NP\n"
2383 "dup 3 5 RD \x5F\x3D\x6B\xAC\xB9 NP\n"
2384 "dup 4 12 RD \x5F\x3D\x6B\xAC\x3E\x5D\x48\x54\x62\x76\x39\x03 NP\n"
2385 "ND\n";
2386 memcpy( pOut, aSubrs, sizeof(aSubrs)-1);
2387 pOut += sizeof(aSubrs)-1;
2389 // TODO: emit more GlobalSubr charstrings?
2390 // TODO: emit used LocalSubr charstrings?
2392 // emit the CharStrings for the requested glyphs
2393 pOut += sprintf( pOut,
2394 "2 index /CharStrings %d dict dup begin\n", nGlyphCount);
2395 rEmitter.emitAllCrypted();
2396 for( int i = 0; i < nGlyphCount; ++i) {
2397 const int nGlyphId = pReqGlyphIDs[i];
2398 assert( (nGlyphId >= 0) && (nGlyphId < mnCharStrCount));
2399 // get privdict context matching to the glyph
2400 const int nFDSelect = getFDSelect( nGlyphId);
2401 mpCffLocal = &maCffLocal[ nFDSelect];
2402 // convert the Type2op charstring to its Type1op counterpart
2403 const int nT2Len = seekIndexData( mnCharStrBase, nGlyphId);
2404 assert( nT2Len > 0);
2405 U8 aType1Ops[ MAX_T1OPS_SIZE]; // TODO: dynamic allocation
2406 const int nT1Len = convert2Type1Ops( mpCffLocal, mpReadPtr, nT2Len, aType1Ops);
2407 // get the glyph name
2408 const char* pGlyphName = getGlyphName( nGlyphId);
2409 // emit the encrypted Type1op charstring
2410 pOut += sprintf( pOut, "/%s %d RD ", pGlyphName, nT1Len);
2411 memcpy( pOut, aType1Ops, nT1Len);
2412 pOut += nT1Len;
2413 pOut += sprintf( pOut, " ND\n");
2414 rEmitter.emitAllCrypted();
2415 // provide individual glyphwidths if requested
2416 if( pGlyphWidths )
2417 pGlyphWidths[i] = getCharWidth();
2419 pOut += sprintf( pOut, "end end\nreadonly put\nput\n");
2420 pOut += sprintf( pOut, "dup/FontName get exch definefont pop\n");
2421 pOut += sprintf( pOut, "mark currentfile closefile\n");
2422 rEmitter.emitAllCrypted();
2424 // mark stop of eexec encryption
2425 if( rEmitter.mbPfbSubset) {
2426 const int nEExecLen = rEmitter.tellPos() - nEExecSegTell;
2427 rEmitter.updateLen( nEExecSegTell-4, nEExecLen);
2430 // create PFB footer
2431 static const char aPfxFooter[] = "\x80\x01\x14\x02\x00\x00\n" // TODO: check segment len
2432 "0000000000000000000000000000000000000000000000000000000000000000\n"
2433 "0000000000000000000000000000000000000000000000000000000000000000\n"
2434 "0000000000000000000000000000000000000000000000000000000000000000\n"
2435 "0000000000000000000000000000000000000000000000000000000000000000\n"
2436 "0000000000000000000000000000000000000000000000000000000000000000\n"
2437 "0000000000000000000000000000000000000000000000000000000000000000\n"
2438 "0000000000000000000000000000000000000000000000000000000000000000\n"
2439 "0000000000000000000000000000000000000000000000000000000000000000\n"
2440 "cleartomark\n"
2441 "\x80\x03";
2442 if( rEmitter.mbPfbSubset)
2443 rEmitter.emitRawData( aPfxFooter, sizeof(aPfxFooter)-1);
2444 else
2445 rEmitter.emitRawData( aPfxFooter+6, sizeof(aPfxFooter)-9);
2447 // provide details to the subset requesters, TODO: move into own method?
2448 // note: Top and Bottom are flipped between Type1 and VCL
2449 rFSInfo.m_aFontBBox = Rectangle( Point( static_cast<long>(maFontBBox[0]), static_cast<long>(maFontBBox[1]) ),
2450 Point( static_cast<long>(maFontBBox[2]), static_cast<long>(maFontBBox[3]) ) );
2451 // PDF-Spec says the values below mean the ink bounds!
2452 // TODO: use better approximations for these ink bounds
2453 rFSInfo.m_nAscent = +rFSInfo.m_aFontBBox.Bottom(); // for capital letters
2454 rFSInfo.m_nDescent = -rFSInfo.m_aFontBBox.Top(); // for all letters
2455 rFSInfo.m_nCapHeight = rFSInfo.m_nAscent; // for top-flat capital letters
2457 rFSInfo.m_nFontType = rEmitter.mbPfbSubset ? FontSubsetInfo::TYPE1_PFB : FontSubsetInfo::TYPE1_PFA;
2458 rFSInfo.m_aPSName = String( rEmitter.maSubsetName, RTL_TEXTENCODING_UTF8 );
2460 return true;
2463 // ====================================================================
2465 bool FontSubsetInfo::CreateFontSubsetFromCff( GlyphWidth* pOutGlyphWidths )
2467 CffSubsetterContext aCff( mpInFontBytes, mnInByteLength);
2468 aCff.initialCffRead();
2470 // emit Type1 subset from the CFF input
2471 // TODO: also support CFF->CFF subsetting (when PDF-export and PS-printing need it)
2472 const bool bPfbSubset = (0 != (mnReqFontTypeMask & FontSubsetInfo::TYPE1_PFB));
2473 Type1Emitter aType1Emitter( mpOutFile, bPfbSubset);
2474 aType1Emitter.setSubsetName( mpReqFontName);
2475 bool bRC = aCff.emitAsType1( aType1Emitter,
2476 mpReqGlyphIds, mpReqEncodedIds,
2477 pOutGlyphWidths, mnReqGlyphCount, *this);
2478 return bRC;
2481 // ====================================================================