update dev300-m57
[ooovba.git] / vcl / source / fontsubset / cff.cxx
blob912dee9fdaf98608937440f76f39f996597a4670
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 #include <vector>
46 typedef std::vector<int> IntVector;
48 // ====================================================================
50 static const char* pStringIds[] = {
51 /*0*/ ".notdef", "space", "exclam", "quotedbl",
52 "numbersign", "dollar", "percent", "ampersand",
53 "quoteright", "parenleft", "parenright", "asterisk",
54 "plus", "comma", "hyphen", "period",
55 /*16*/ "slash", "zero", "one", "two",
56 "three", "four", "five", "six",
57 "seven", "eight", "nine", "colon",
58 "semicolon", "less", "equal", "greater",
59 /*32*/ "question", "at", "A", "B",
60 "C", "D", "E", "F",
61 "G", "H", "I", "J",
62 "K", "L", "M", "N",
63 /*48*/ "O", "P", "Q", "R",
64 "S", "T", "U", "V",
65 "W", "X", "Y", "Z",
66 "bracketleft", "backslash", "bracketright", "asciicircum",
67 /*64*/ "underscore", "quoteleft", "a", "b",
68 "c", "d", "e", "f",
69 "g", "h", "i", "j",
70 "k", "l", "m", "n",
71 /*80*/ "o", "p", "q", "r",
72 "s", "t", "u", "v",
73 "w", "x", "y", "z",
74 "braceleft", "bar", "braceright", "asciitilde",
75 /*96*/ "exclamdown", "cent", "sterlin", "fraction",
76 "yen", "florin", "section", "currency",
77 "quotesingle", "quotedblleft", "guillemotleft", "guilsinglleft",
78 "guilsinglright", "fi", "fl", "endash",
79 /*112*/ "dagger", "daggerdbl", "periodcentered", "paragraph",
80 "bullet", "quotesinglbase", "quotedblbase", "quotedblright",
81 "guillemotright", "ellipsis", "perthousand", "questiondown",
82 "grave", "acute", "circumflex", "tilde",
83 /*128*/ "macron", "breve", "dotaccent", "dieresis",
84 "ring", "cedilla", "hungarumlaut", "ogonek",
85 "caron", "endash", "AE", "ordfeminine",
86 "Lslash", "Oslash", "OE", "ordmasculine",
87 /*144*/ "ae", "dotlessi", "lslash", "oslash",
88 "oe", "germandbls", "onesuperior", "logicalnot",
89 "mu", "trademark", "Eth", "onehalf",
90 "plusminus", "Thorn", "onequarter", "divide",
91 /*160*/ "brokenbar", "degree", "thorn", "threequarters",
92 "twosuperior", "registered", "minus", "eth",
93 "multiply", "threesuperior", "copyright", "Aacute",
94 "Acircumflex", "Adieresis", "Agrave", "Aring",
95 /*176*/ "Atilde", "Ccedilla", "Eacute", "Ecircumflex",
96 "Edieresis", "Egrave", "Iacute", "Icircumflex",
97 "Idieresis", "Igrave", "Ntilde", "Oacute",
98 "Ocircumflex", "Odieresis", "Ograve", "Otilde",
99 /*192*/ "Scaron", "Uacute", "Ucircumflex", "Udieresis",
100 "Ugrave", "Yacute", "Ydieresis", "Zcaron",
101 "aacute", "acircumflex", "adieresis", "agrave",
102 "aring", "atilde", "ccedilla", "eacute",
103 /*208*/ "ecircumflex", "edieresis", "egrave", "iacute",
104 "icircumflex", "idieresis", "igrave", "ntilde",
105 "oacute", "ocircumflex", "odieresis", "ograve",
106 "otilde", "scaron", "uacute", "ucircumflex",
107 /*224*/ "udieresis", "ugrave", "yacute", "ydieresis",
108 "zcaron", "exclamsmall", "Hungarumlautsmall","dollaroldstyle",
109 "dollarsuperior", "ampersandsmall", "Acutesmall", "parenleftsuperior",
110 "parenrightsuperior","twodotenleader", "onedotenleader", "zerooldstyle",
111 /*240*/ "oneoldstyle", "twooldstyle", "threeoldstyle", "fouroldstyle",
112 "fiveoldstyle", "sixoldstyle", "sevenoldstyle", "eightoldstyle",
113 "nineoldstile", "commasuperior", "threequartersemdash","periodsuperior",
114 "questionsmall", "asuperior", "bsuperior", "centsuperior",
115 /*256*/ "dsuperior", "esuperior", "isuperior", "lsuperior",
116 "msuperior", "nsuperior", "osuperior", "rsuperior",
117 "ssuperior", "tsuperior", "ff", "ffi",
118 "ffl", "parenleftinferior","parenrightinferior","Circumflexsmall",
119 /*272*/ "hyphensuperior","Gravesmall", "Asmall", "Bsmall",
120 "Csmall", "Dsmall", "Esmall", "Fsmall",
121 "Gsmall", "Hsmall", "Ismall", "Jsmall",
122 "Ksmall", "Lsmall", "Msmall", "Nsmall",
123 /*288*/ "Osmall", "Psmall", "Qsmall", "Rsmall",
124 "Ssmall", "Tsmall", "Usmall", "Vsmall",
125 "Wsmall", "Xsmall", "Ysmall", "Zsmall",
126 "colonmonetary", "onefitted", "rupia", "Tildesmall",
127 /*304*/ "exclamdownsmall","centoldstyle", "Lslashsmall", "Scaronsmall",
128 "Zcaronsmall", "Dieresissmall", "Brevesmall", "Caronsmall",
129 "Dotaccentsmall", "Macronsmall", "figuredash", "hypheninferior",
130 "Ogoneksmall", "Ringsmall", "Cedillasmall", "questiondownsmall",
131 /*320*/ "oneeight", "threeeights", "fiveeights", "seveneights",
132 "onethird", "twothirds", "zerosuperior", "foursuperior",
133 "fivesuperior", "sixsuperior", "sevensuperior", "eightsuperior",
134 "ninesuperior", "zeroinferior", "oneinferior", "twoinferior",
135 /*336*/ "threeinferior","fourinferior", "fiveinferior", "sixinferior",
136 "seveninferior", "eightinferior", "nineinferior", "centinferior",
137 "dollarinferior", "periodinferior", "commainferior", "Agravesmall",
138 "Aacutesmall", "Acircumflexsmall", "Atildesmall", "Adieresissmall",
139 /*352*/ "Aringsmall", "AEsmall", "Ccedillasmall", "Egravesmall",
140 "Eacutesmall", "Ecircumflexsmall", "Edieresissmall", "Igravesmall",
141 "Iacutesmall", "Icircumflexsmall", "Idieresissmall", "Ethsmall",
142 "Ntildesmall", "Ogravesmall", "Oacutesmall", "Ocircumflexsmall",
143 /*368*/ "Otildesmall", "Odieressissmall", "OEsmall", "Oslashsmall",
144 "Ugravesmall", "Uacutesmall", "Ucircumflexsmall", "Udieresissmall",
145 "Yacutesmall", "Thornsmall", "Ydieresissmall", "001.000",
146 "001.001", "001.002", "001.003", "Black",
147 /*384*/ "Bold", "Book", "Light", "Medium",
148 "Regular", "Roman", "Semibold"
151 // --------------------------------------------------------------------
153 #if 0 // TODO: use them
154 static const char* pStdEncNames[] = {
155 "ISOAdobe", "Expert", "ExpertSubSet"
157 #endif
159 // --------------------------------------------------------------------
161 // TOP DICT keywords (also covers PRIV DICT keywords)
162 static const char* pDictOps[] = {
163 "sVersion", "sNotice", "sFullName", "sFamilyName",
164 "sWeight", "aFontBBox", "dBlueValues", "dOtherBlues",
165 "dFamilyBlues", "dFamilyOtherBlues", "nStdHW", "nStdVW",
166 "xESC", "nUniqueID", "aXUID", "nCharset",
167 "nEncoding", "nCharStrings", "PPrivate", "nSubrs",
168 "nDefaultWidthX", "nNominalWidthX", NULL, NULL,
169 NULL, NULL, NULL, NULL,
170 "shortint", "longint", "BCD", NULL
173 // --------------------------------------------------------------------
175 // TOP DICT escapes (also covers PRIV DICT escapes)
176 static const char* pDictEscs[] = {
177 "sCopyright", "bIsFixedPitch", "nItalicAngle", "nUnderlinePosition",
178 "nUnderlineThickness", "nPaintType", "tCharstringType", "aFontMatrix",
179 "nStrokeWidth", "nBlueScale", "nBlueShift", "nBlueFuzz",
180 "dStemSnapH", "dStemSnapV", "bForceBold", NULL,
181 NULL, "nLanguageGroup", "nExpansionFactor", "nInitialRandomSeed",
182 "nSyntheticBase", "sPostScript", "sBaseFontName", "dBaseFontBlend",
183 NULL, NULL, NULL, NULL,
184 NULL, NULL, "rROS", "nCIDFontVersion",
185 "nCIDFontRevision", "nCIDFontType", "nCIDCount", "nUIDBase",
186 "nFDArray", "nFDSelect", "sFontName"
189 // --------------------------------------------------------------------
191 static const char* pType1Ops[] = {
192 NULL, "2hstem", NULL, "2vstem",
193 "1vmoveto", "Arlineto", "1hlineto", "1vlineto",
194 "Crrcurveto", "0closepath", "Lcallsubr", "0return",
195 "xT1ESC", "2hsbw", "0endchar", NULL,
196 NULL, NULL, NULL, NULL,
197 NULL, "2rmoveto", "1hmoveto", NULL,
198 NULL, NULL, NULL, NULL,
199 NULL, NULL, "4vhcurveto", "4hvcurveto"
202 // --------------------------------------------------------------------
204 static const char* pT1EscOps[] = {
205 "0dotsection", "6vstem3", "6hstem3", NULL,
206 NULL, NULL, "5seac", "4sbw",
207 NULL, "1abs", "2add", "2sub",
208 "2div", NULL, NULL, NULL,
209 "Gcallothersubr", "1pop", NULL, NULL,
210 NULL, NULL, NULL, NULL,
211 NULL, NULL, NULL, NULL,
212 NULL, NULL, NULL, NULL,
213 NULL, "2setcurrentpoint"
216 // --------------------------------------------------------------------
218 struct TYPE1OP
220 enum OPS
222 HSTEM=1, VSTEM=3, VMOVETO=4, RLINETO=5,
223 HLINETO=6, VLINETO=7, RCURVETO=8, CLOSEPATH=9,
224 CALLSUBR=10, RETURN=11, T1ESC=12, HSBW=13,
225 ENDCHAR=14, RMOVETO=21, HMOVETO=22, VHCURVETO=30,
226 HVCURVETO=31
229 enum ESCS
231 DOTSECTION=0, VSTEM3=1, HSTEM3=2, SEAC=6,
232 SBW=7, ABS=9, ADD=10, SUB=11,
233 DIV=12, CALLOTHERSUBR=16, POP=17, SETCURRENTPOINT=33
237 // --------------------------------------------------------------------
239 static const char* pType2Ops[] = {
240 NULL, "hhstem", NULL, "vvstem",
241 "mvmoveto", "Arlineto", "Ehlineto", "Evlineto",
242 "Crrcurveto", NULL, "Lcallsubr", "Xreturn",
243 "xT2ESC", NULL, "eendchar", NULL,
244 NULL, NULL, "Hhstemhm", "Khintmask",
245 "Kcntrmask", "Mrmoveto", "mhmoveto", "Vvstemhm",
246 ".rcurveline", ".rlinecurve", ".vvcurveto", ".hhcurveto",
247 ".shortint", "Gcallgsubr", ".vhcurveto", ".hvcurveto"
250 // --------------------------------------------------------------------
252 static const char* pT2EscOps[] = {
253 NULL, NULL, NULL, "2and",
254 "2or", "1not", NULL, NULL,
255 NULL, "1abs", "2add", "2sub",
256 "2div", NULL, "1neg", "2eq",
257 NULL, NULL, "1drop", NULL,
258 "1put", "1get", "4ifelse", "0random",
259 "2mul", NULL, "1sqrt", "1dup",
260 "2exch", "Iindex", "Rroll", NULL,
261 NULL, NULL, "7hflex", "Fflex",
262 "9hflex1", "fflex1"
265 // --------------------------------------------------------------------
267 struct TYPE2OP
269 enum OPS
271 HSTEM=1, VSTEM=3, VMOVETO=4, RLINETO=5,
272 HLINETO=6, VLINETO=7, RCURVETO=8, CALLSUBR=10,
273 RETURN=11, T2ESC=12, ENDCHAR=14, HSTEMHM=18,
274 HINTMASK=19, CNTRMASK=20, RMOVETO=21, HMOVETO=22,
275 VSTEMHM=23, RCURVELINE=24, RLINECURVE=25, VVCURVETO=26,
276 HHCURVETO=27, SHORTINT=28, CALLGSUBR=29, VHCURVETO=30,
277 HVCURVETO=31
280 enum ESCS
282 AND=3, OR=4, NOT=5, ABS=9,
283 ADD=10, SUB=11, DIV=12, NEG=14,
284 EQ=15, DROP=18, PUT=20, GET=21,
285 IFELSE=22, RANDOM=23, MUL=24, SQRT=26,
286 DUP=27, EXCH=28, INDEX=29, ROLL=30,
287 HFLEX=34, FLEX=35, HFLEX1=36, FLEX1=37
291 // ====================================================================
293 struct CffGlobal
295 explicit CffGlobal();
297 int mnNameIdxBase;
298 int mnNameIdxCount;
299 int mnStringIdxBase;
300 int mnStringIdxCount;
301 bool mbCIDFont;
302 int mnCharStrBase;
303 int mnCharStrCount;
304 int mnEncodingBase;
305 int mnCharsetBase;
306 int mnGlobalSubrBase;
307 int mnGlobalSubrCount;
308 int mnGlobalSubrBias;
309 int mnFDSelectBase;
310 int mnFontDictBase;
311 int mnFDAryCount;
313 IntVector maFontBBox;
314 //FloatVector maFontMatrix;
316 int mnFontNameSID;
317 int mnFullNameSID;
318 int mnFamilyNameSID;
321 // ====================================================================
323 struct CffLocal
325 explicit CffLocal();
327 int mnPrivDictBase;
328 int mnPrivDictSize;
329 int mnLocalSubrOffs;
330 int mnLocalSubrBase;
331 int mnLocalSubrCount;
332 int mnLocalSubrBias;
333 int mnNominalWidth;
334 int mnDefaultWidth;
336 // ATM hinting related values
337 int mnStemStdHW;
338 int mnStemStdVW;
339 IntVector maStemSnapH;
340 IntVector maStemSnapV;
341 IntVector maBlueValues;
342 IntVector maOtherBlues;
343 IntVector maFamilyBlues;
344 IntVector maFamilyOtherBlues;
345 double mfBlueScale;
346 double mfBlueShift;
347 double mfBlueFuzz;
348 double mfExpFactor;
349 int mnLangGroup;
350 bool mbForceBold;
353 // ====================================================================
355 class SubsetterContext
357 public:
358 virtual ~SubsetterContext( void);
359 virtual bool emitAsType1( class Type1Emitter&,
360 const long* pGlyphIDs, const U8* pEncoding,
361 GlyphWidth* pGlyphWidths, int nGlyphCount, FontSubsetInfo& ) = 0;
364 // --------------------------------------------------------------------
366 SubsetterContext::~SubsetterContext( void)
369 // ====================================================================
371 class CffSubsetterContext
372 : public SubsetterContext
373 , private CffGlobal
375 public:
376 static const int NMAXSTACK = 48; // see CFF.appendixB
377 static const int NMAXHINTS = 2*96; // see CFF.appendixB
378 static const int NMAXTRANS = 32; // see CFF.appendixB
379 public:
380 explicit CffSubsetterContext( const U8* pBasePtr, int nBaseLen);
381 virtual ~CffSubsetterContext( void);
383 void initialCffRead( void);
384 bool emitAsType1( class Type1Emitter&,
385 const long* pGlyphIDs, const U8* pEncoding,
386 GlyphWidth* pGlyphWidths, int nGlyphCount, FontSubsetInfo& );
388 // used by charstring converter
389 void setCharStringType( int);
390 void fakeLocalSubrCount( int nLocalSubrs ) { maCffLocal[0].mnLocalSubrCount=nLocalSubrs;}
391 void readCharString( const U8* pTypeOps, int nTypeLen);
392 protected:
393 int convert2Type1Ops( CffLocal*, const U8* pType2Ops, int nType2Len, U8* pType1Ops);
394 private:
395 void readTypeOp( CffSubsetterContext&);
396 void convertOneTypeOp( void);
397 void convertOneTypeEsc( void);
398 void callType2Subr( bool bGlobal, int nSubrNumber);
399 long getReadOfs( void) const { return (long)(mpReadPtr - mpBasePtr);}
401 const U8* mpBasePtr;
402 const U8* mpBaseEnd;
404 const U8* mpReadPtr;
405 const U8* mpReadEnd;
407 U8* mpWritePtr;
408 bool mbSawError;
409 bool mbNeedClose;
410 bool mbIgnoreHints;
411 long mnCntrMask;
413 private:
414 int seekIndexData( int nIndexBase, int nDataIndex);
415 void seekIndexEnd( int nIndexBase);
417 private:
418 const char** mpCharStringOps;
419 const char** mpCharStringEscs;
421 CffLocal maCffLocal[16];
422 CffLocal* mpCffLocal;
424 void readDictOp( void);
425 double readRealVal( void);
426 const char* getString( int nStringID);
427 int getFDSelect( int nGlyphIndex) const;
428 int getGlyphSID( int nGlyphIndex) const;
429 const char* getGlyphName( int nGlyphIndex);
431 void readTypeOp( void);
432 void read2push( void);
433 void pop2write( void);
434 void writeType1Val( int/*TODO: double*/ nVal);
435 void writeTypeOp( int nTypeOp);
436 void writeTypeEsc( int nTypeOp);
437 void writeCurveTo( int nStackPos, int nIX1, int nIY1, int nIX2, int nIY2, int nIX3, int nIY3);
438 void pop2MultiWrite( int nArgsPerTypo, int nTypeOp, int nTypeXor=0);
439 void popAll2Write( int nTypeOp);
441 public: // TODO: is public really needed?
442 // accessing the value stack
443 // TODO: add more checks
444 void push( int nVal) { mnValStack[ mnStackIdx++] = nVal;}
445 int pop( void) { return ((mnStackIdx>0) ? mnValStack[ --mnStackIdx] : 0);}
446 int peek( void) { return ((mnStackIdx>0) ? mnValStack[ mnStackIdx-1] : 0);}
447 int get( int nIndex) { return mnValStack[ nIndex];}
448 int size( void) const { return mnStackIdx;}
449 bool empty( void) const { return !mnStackIdx;}
450 void clear( void) { mnStackIdx = 0;}
452 // accessing the charstring hints
453 void addHints( bool bVerticalHints);
454 int getHorzHintCount( void) const { return (mnHorzHintSize/2);}
455 int getVertHintCount( void) const { return (mnHintSize-mnHorzHintSize)/2;}
456 void getHintPair( int nIndex, int* nMin, int* nEnd) const;
458 // accessing other charstring specifics
459 bool hasCharWidth( void) const { return (mnCharWidth != -1);}
460 int getCharWidth( void) const { return mnCharWidth;}
461 void setNominalWidth( int nWidth) { mpCffLocal->mnNominalWidth = nWidth;}
462 void setDefaultWidth( int nWidth) { mpCffLocal->mnDefaultWidth = nWidth;}
463 void updateWidth( bool bUseFirstVal);
465 private:
466 // typeop exceution context
467 int mnStackIdx;
468 int mnValStack[ NMAXSTACK];
469 int mnTransVals[ NMAXTRANS];
471 int mnHintSize;
472 int mnHorzHintSize;
473 int mnHintStack[ NMAXHINTS];
475 int mnCharWidth;
478 // --------------------------------------------------------------------
480 CffSubsetterContext::CffSubsetterContext( const U8* pBasePtr, int nBaseLen)
481 : mpBasePtr( pBasePtr)
482 , mpBaseEnd( pBasePtr+nBaseLen)
483 , mnStackIdx(0)
484 , mnHintSize(0)
485 , mnHorzHintSize(0)
486 , mnCharWidth(-1)
488 // setCharStringType( 1);
489 // TODO: new CffLocal[ mnFDAryCount];
490 mpCffLocal = &maCffLocal[0];
493 // --------------------------------------------------------------------
495 CffSubsetterContext::~CffSubsetterContext( void)
497 // TODO: delete[] maCffLocal;
500 // --------------------------------------------------------------------
502 inline void CffSubsetterContext::updateWidth( bool bUseFirstVal)
504 #if 1 // TODO: is this still needed?
505 // the first value is not a hint but the charwidth
506 if( hasCharWidth())
507 return;
508 #endif
509 if( bUseFirstVal) {
510 mnCharWidth = mpCffLocal->mnNominalWidth + mnValStack[0];
511 // remove bottom stack entry
512 --mnStackIdx;
513 for( int i = 0; i < mnStackIdx; ++i)
514 mnValStack[ i] = mnValStack[ i+1];
515 } else {
516 mnCharWidth = mpCffLocal->mnDefaultWidth;
520 // --------------------------------------------------------------------
522 void CffSubsetterContext::addHints( bool bVerticalHints)
524 // the first charstring value may a charwidth instead of a charwidth
525 updateWidth( (mnStackIdx & 1) != 0);
526 // return early (e.g. no implicit hints for hintmask)
527 if( !mnStackIdx)
528 return;
530 // copy the remaining values to the hint arrays
531 // assert( (mnStackIdx & 1) == 0); // depends on called subrs
532 if( mnStackIdx & 1) --mnStackIdx;//#######
533 // TODO: if( !bSubr) assert( mnStackIdx >= 2);
535 assert( (mnHintSize + mnStackIdx) <= 2*NMAXHINTS);
537 #ifdef IGNORE_HINTS
538 mnHorzHintSize += mnStackIdx;
539 #else
540 int nHintOfs = 0;
541 for( int i = 0; i < mnStackIdx; ++i) {
542 nHintOfs += mnValStack[ i];
543 mnHintStack[ mnHintSize++] = nHintOfs;
545 if( !bVerticalHints)
546 mnHorzHintSize = mnHintSize;
547 #endif // IGNORE_HINTS
549 // clear all values from the stack
550 mnStackIdx = 0;
553 // --------------------------------------------------------------------
555 void CffSubsetterContext::getHintPair( int nIndex, int* pMin, int* pEnd) const
557 nIndex *= 2;
558 assert( nIndex < mnHintSize);
559 assert( nIndex >= 0);
560 const int* pHint = &mnHintStack[ nIndex];
561 *pMin = pHint[0];
562 *pEnd = pHint[1];
565 // --------------------------------------------------------------------
567 void CffSubsetterContext::setCharStringType( int nVal)
569 switch( nVal) {
570 case 1: mpCharStringOps=pType1Ops; mpCharStringEscs=pT1EscOps; break;
571 case 2: mpCharStringOps=pType2Ops; mpCharStringEscs=pT2EscOps; break;
572 default: fprintf( stderr, "Unknown CharstringType=%d\n",nVal); break;
576 // --------------------------------------------------------------------
578 void CffSubsetterContext::readCharString( const U8* pTypeOps, int nTypeLen)
580 mnStackIdx = 0;
581 mnHintSize = 0;
582 mnHorzHintSize = 0;
583 mnCharWidth = -1;
585 assert( nTypeLen >= 0);
586 // assert( nEnd <= getLength());
587 mpReadPtr = pTypeOps;
588 mpReadEnd = mpReadPtr + nTypeLen;
589 // reset the execution context
590 while( mpReadPtr < mpReadEnd)
591 readTypeOp();
592 //### assert( tellRel() == nEnd);
595 // --------------------------------------------------------------------
597 void CffSubsetterContext::readDictOp( void)
599 int nVal = 0;
600 const U8 c = *mpReadPtr;
601 if( c <= 21 ) {
602 int nOpId = *(mpReadPtr++);
603 const char* pCmdName;
604 if( nOpId != 12)
605 pCmdName = pDictOps[ nOpId];
606 else {
607 const U8 nExtId = *(mpReadPtr++);
608 pCmdName = pDictEscs[ nExtId];
609 nOpId = 900 + nExtId;
612 //TODO: if( nStackIdx > 0)
613 switch( *pCmdName) {
614 default: fprintf( stderr, "unsupported DictOp.type=\'%c\'\n", *pCmdName); break;
615 case 'b': // bool
616 nVal = pop();
617 switch( nOpId) {
618 case 915: mpCffLocal->mbForceBold = nVal; break; // "ForceBold"
619 default: break; // TODO: handle more boolean dictops?
621 break;
622 case 'n': // dict-op number
623 nVal = pop();
624 switch( nOpId) {
625 case 10: mpCffLocal->mnStemStdHW = nVal; break; // "StdHW"
626 case 11: mpCffLocal->mnStemStdVW = nVal; break; // "StdVW"
627 case 15: mnCharsetBase = nVal; break; // "charset"
628 case 16: mnEncodingBase = nVal; break; // "nEncoding"
629 case 17: mnCharStrBase = nVal; break; // "nCharStrings"
630 case 19: mpCffLocal->mnLocalSubrOffs = nVal; break;// "nSubrs"
631 case 20: setDefaultWidth( nVal); break; // "defaultWidthX"
632 case 21: setNominalWidth( nVal); break; // "nominalWidthX"
633 case 909: mpCffLocal->mfBlueScale = nVal; break; // "BlueScale"
634 case 910: mpCffLocal->mfBlueShift = nVal; break; // "BlueShift"
635 case 911: mpCffLocal->mfBlueFuzz = nVal; break; // "BlueFuzz"
636 case 912: mpCffLocal->mfExpFactor = nVal; break; // "ExpansionFactor"
637 case 917: mpCffLocal->mnLangGroup = nVal; break; // "LanguageGroup"
638 case 936: mnFontDictBase = nVal; break; // "nFDArray"
639 case 937: mnFDSelectBase = nVal; break; // "nFDSelect"
640 default: break; // TODO: handle more numeric dictops?
642 break;
643 case 'a': { // array
644 for( int i = 0; i < size(); ++i ) {
645 nVal = get(i);
646 switch( nOpId) {
647 case 5: maFontBBox.push_back( nVal); break; // "FontBBox"
648 #if 0 // TODO
649 case 907: maFontMatrix.push_back( nVal); break; // "FontMatrix"
650 #endif
651 default: break; // TODO: handle more array dictops?
654 clear();
655 } break;
656 case 'd': { // delta array
657 nVal = 0;
658 for( int i = 0; i < size(); ++i ) {
659 nVal += get(i);
660 switch( nOpId) {
661 case 6: mpCffLocal->maBlueValues.push_back( nVal); break; // "BlueValues"
662 case 7: mpCffLocal->maOtherBlues.push_back( nVal); break; // "OtherBlues"
663 case 8: mpCffLocal->maFamilyBlues.push_back( nVal); break; // "FamilyBlues"
664 case 9: mpCffLocal->maFamilyOtherBlues.push_back( nVal); break;// "FamilyOtherBlues"
665 case 912: mpCffLocal->maStemSnapH.push_back( nVal); break; // "StemSnapH"
666 case 913: mpCffLocal->maStemSnapV.push_back( nVal); break; // "StemSnapV"
667 default: break; // TODO: handle more delta-array dictops?
670 clear();
671 } break;
672 case 's': // stringid (SID)
673 nVal = pop();
674 switch( nOpId) {
675 case 2: mnFullNameSID = nVal; break; // "FullName"
676 case 3: mnFamilyNameSID = nVal; break; // "FamilyName"
677 case 938: mnFontNameSID = nVal; break; // "FontName"
678 default: break; // TODO: handle more string dictops?
680 break;
681 case 'P': // private dict
682 mpCffLocal->mnPrivDictBase = pop();
683 mpCffLocal->mnPrivDictSize = pop();
684 break;
685 case 'r': { // ROS operands
686 int nSid1 = pop();
687 int nSid2 = pop();
688 (void)nSid1; // TODO: use
689 (void)nSid2; // TODO: use
690 nVal = pop();
691 mbCIDFont = true;
692 } break;
693 case 't': // CharstringType
694 nVal = pop();
695 setCharStringType( nVal);
696 break;
699 return;
702 if( (c >= 32) || (c == 28)) {
703 // --mpReadPtr;
704 read2push();
705 } else if( c == 29) { // longint
706 ++mpReadPtr; // skip 29
707 int nS32 = mpReadPtr[0] << 24;
708 nS32 += mpReadPtr[1] << 16;
709 nS32 += mpReadPtr[2] << 8;
710 nS32 += mpReadPtr[3] << 0;
711 if( (sizeof(nS32) != 4) && (nS32 & (1<<31)))
712 nS32 |= (~0U) << 31; // assuming 2s complement
713 mpReadPtr += 4;
714 nVal = nS32;
715 push( nVal);
716 } else if( c == 30) { // real number
717 ++mpReadPtr; // skip 30
718 const double fReal = readRealVal();
719 // push value onto stack
720 nVal = static_cast<int>(fReal+0.5); //TODO!!! allow float on operand stack!
721 push( nVal);
725 // --------------------------------------------------------------------
727 void CffSubsetterContext::readTypeOp( void)
729 int nVal = 0;
730 const U8 c = *mpReadPtr;
731 if( (c <= 31) && (c != 28) ) {
732 const int nOpId = *(mpReadPtr++);
733 const char* pCmdName;
734 if( nOpId != 12)
735 pCmdName = mpCharStringOps[ nOpId];
736 else {
737 const int nExtId = *(mpReadPtr++);
738 pCmdName = mpCharStringEscs[ nExtId];
741 if( !pCmdName )
742 pCmdName = ".NULL";
743 // handle typeop parameters
744 int nMinStack = -1, nMaxStack = -1;
745 switch( *pCmdName) {
746 default: fprintf( stderr, "unsupported TypeOp.type=\'%c\'\n", *pCmdName); break;
747 case '.': nMinStack = 0; nMaxStack = 999; break;
748 case '0': nMinStack = nMaxStack = 0; break;
749 case '1': nMinStack = nMaxStack = 1; break;
750 case '2': nMinStack = nMaxStack = 2; break;
751 case '4': nMinStack = nMaxStack = 4; break;
752 case '5': nMinStack = nMaxStack = 5; break; // not used for Type2 ops
753 case '6': nMinStack = nMaxStack = 6; break;
754 case '7': nMinStack = nMaxStack = 7; break;
755 case '9': nMinStack = nMaxStack = 9; break;
756 case 'f': nMinStack = nMaxStack = 11; break;
757 case 'F': nMinStack = nMaxStack = 13; break;
758 case 'A': nMinStack = 2; nMaxStack = 999; break;
759 case 'C': nMinStack = 6; nMaxStack = 999; break;
760 case 'E': nMinStack = 1; nMaxStack = 999; break;
761 case 'G': nMinStack = 1; nMaxStack = 999; // global subr
762 nVal = peek();
763 // TODO global subr
764 break;
765 case 'L': // local subr
766 nMinStack = 1; nMaxStack = 999;
767 nVal = peek();
768 // TODO local subr
769 break;
770 case 'I': // operands for "index"
771 #if 0
772 nMinStack = nValStack[ nStackIdx-1];
773 if( nMinStack < 0) nMinStack = 0;
774 nMinStack += 1;
775 #else
776 fprintf( stderr, "TODO: Iindex op\n");
777 #endif
778 break;
779 case 'R': // operands for "rol"
780 #if 0
781 nMinStack = nValStack[ nStackIdx-2];
782 #else
783 fprintf( stderr, "TODO: Rrol op\n");
784 #endif
785 case 'X': // operands for "return"
786 nMinStack = 0;
787 nMaxStack = /*### (!bInSubrs)? 0 :###*/999;
788 break;
789 case 'H': // "hstemhm"
790 case 'h': // "hstem"
791 addHints( false);
792 nMinStack = nMaxStack = 0;
793 break;
794 case 'V': // "vstemhm"
795 case 'v': // "vstem"
796 addHints( true);
797 nMinStack = nMaxStack = 0;
798 break;
799 case 'K': // "hintmask" or "cntrmask"
800 addHints( true); // implicit vstemhm
801 nMinStack = nMaxStack = 0;
802 break;
803 case 'e': // endchar
804 updateWidth( (size() >= 1) && (size() != 4));
805 nMinStack = nMaxStack = 0;
806 if( size() == 4)
807 fprintf( stderr,"Deprecated SEAC-like endchar is not supported for CFF subsetting!\n"); // TODO: handle deprecated op
808 break;
809 case 'm': // hmoveto or vmoveto
810 updateWidth( size() > 1);
811 nMinStack = 1;
812 nMaxStack = nMinStack;
813 break;
814 case 'M': // rmoveto
815 updateWidth( size() > 2);
816 nMinStack = 2;
817 nMaxStack = nMinStack;
818 break;
821 clear();
822 return;
825 if( (c >= 32) || (c == 28)) {
826 // --mpReadPtr;
827 read2push();
831 // --------------------------------------------------------------------
833 void CffSubsetterContext::read2push( void)
835 int nVal = 0;
837 const U8*& p = mpReadPtr;
838 const U8 c = *p;
839 if( c == 28) {
840 short nS16 = (p[1] << 8) + p[2];
841 if( (sizeof(nS16) != 2) && (nS16 & (1<<15)))
842 nS16 |= (~0U) << 15; // assuming 2s complement
843 nVal = nS16;
844 p += 3;
845 } else if( c <= 246) { // -107..+107
846 nVal = p[0] - 139;
847 p += 1;
848 } else if( c <= 250) { // +108..+1131
849 nVal = ((p[0] << 8) + p[1]) - 63124;
850 p += 2;
851 } else if( c <= 254) { // -108..-1131
852 nVal = 64148 - ((p[0] << 8) + p[1]);
853 p += 2;
854 } else /*if( c == 255)*/ { // Fixed16.16
855 nVal = (p[1] << 8) + p[2];
856 // TODO: read non-integer part
857 p += 5;
860 push( nVal);
863 // --------------------------------------------------------------------
865 void CffSubsetterContext::writeType1Val( int/*TODO: double*/ nVal)
867 U8* pOut = mpWritePtr;
868 if( (nVal >= -107) && (nVal <= +107)) {
869 *(pOut++) = static_cast<U8>(nVal + 139); // -107..+107
870 } else if( (nVal >= -1131) && (nVal <= +1131)) {
871 if( nVal >= 0)
872 nVal += 63124; // +108..+1131
873 else
874 nVal = 64148 - nVal; // -108..-1131
875 *(pOut++) = static_cast<U8>(nVal >> 8);
876 *(pOut++) = static_cast<U8>(nVal);
877 } else {
878 // numtype==255 means int32 for Type1, but 16.16 for Type2 charstrings!!!
879 *(pOut++) = 255;
880 *(pOut++) = static_cast<U8>(nVal >> 24);
881 *(pOut++) = static_cast<U8>(nVal >> 16);
882 *(pOut++) = static_cast<U8>(nVal >> 8);
883 *(pOut++) = static_cast<U8>(nVal);
886 mpWritePtr = pOut;
889 // --------------------------------------------------------------------
891 inline void CffSubsetterContext::pop2write( void)
893 int nVal = pop();
894 writeType1Val( nVal);
897 // --------------------------------------------------------------------
899 inline void CffSubsetterContext::writeTypeOp( int nTypeOp)
901 *(mpWritePtr++) = static_cast<U8>(nTypeOp);
904 // --------------------------------------------------------------------
906 inline void CffSubsetterContext::writeTypeEsc( int nTypeEsc)
908 *(mpWritePtr++) = TYPE1OP::T1ESC;
909 *(mpWritePtr++) = static_cast<U8>(nTypeEsc);
912 // --------------------------------------------------------------------
914 void CffSubsetterContext::pop2MultiWrite( int nArgsPerTypo, int nTypeOp, int nTypeXor)
916 for( int i = 0; i < mnStackIdx;) {
917 for( int j = 0; j < nArgsPerTypo; ++j) {
918 int nVal = mnValStack[i+j];
919 writeType1Val( nVal);
921 i += nArgsPerTypo;
922 writeTypeOp( nTypeOp);
923 nTypeOp ^= nTypeXor; // for toggling vlineto/hlineto
925 clear();
928 // --------------------------------------------------------------------
930 void CffSubsetterContext::popAll2Write( int nTypeOp)
932 // pop in reverse order, then write
933 for( int i = 0; i < mnStackIdx; ++i) {
934 int nVal = mnValStack[i];
935 writeType1Val( nVal);
937 clear();
938 writeTypeOp( nTypeOp);
941 // --------------------------------------------------------------------
943 void CffSubsetterContext::writeCurveTo( int nStackPos,
944 int nIX1, int nIY1, int nIX2, int nIY2, int nIX3, int nIY3)
946 // get the values from the stack
947 const int nDX1 = nIX1 ? mnValStack[ nStackPos+nIX1] : 0;
948 const int nDY1 = nIY1 ? mnValStack[ nStackPos+nIY1] : 0;
949 const int nDX2 = nIX2 ? mnValStack[ nStackPos+nIX2] : 0;
950 const int nDY2 = nIY2 ? mnValStack[ nStackPos+nIY2] : 0;
951 const int nDX3 = nIX3 ? mnValStack[ nStackPos+nIX3] : 0;
952 const int nDY3 = nIY3 ? mnValStack[ nStackPos+nIY3] : 0;
954 // emit the curveto operator and operands
955 // TODO: determine the most efficient curveto operator
956 // TODO: depending on type1op or type2op target
957 writeType1Val( nDX1);
958 writeType1Val( nDY1);
959 writeType1Val( nDX2);
960 writeType1Val( nDY2);
961 writeType1Val( nDX3);
962 writeType1Val( nDY3);
963 writeTypeOp( TYPE1OP::RCURVETO);
966 // --------------------------------------------------------------------
968 void CffSubsetterContext::convertOneTypeOp( void)
970 const int nType2Op = *(mpReadPtr++);
972 int i, nVal; // prevent WAE for declarations inside switch cases
973 // convert each T2op
974 switch( nType2Op) {
975 case TYPE2OP::T2ESC:
976 convertOneTypeEsc();
977 break;
978 case TYPE2OP::HSTEM:
979 case TYPE2OP::VSTEM:
980 addHints( nType2Op == TYPE2OP::VSTEM);
981 #ifndef IGNORE_HINTS
982 for( i = 0; i < mnHintSize; i+=2) {
983 writeType1Val( mnHintStack[i]);
984 writeType1Val( mnHintStack[i+1] - mnHintStack[i]);
985 writeTypeOp( nType2Op);
987 #endif // IGNORE_HINTS
988 break;
989 case TYPE2OP::HSTEMHM:
990 case TYPE2OP::VSTEMHM:
991 addHints( nType2Op == TYPE2OP::VSTEMHM);
992 break;
993 case TYPE2OP::CNTRMASK:
994 // TODO: replace cntrmask with vstem3/hstem3
995 addHints( true);
996 #ifdef IGNORE_HINTS
997 mpReadPtr += (mnHintSize + 15) / 16;
998 mbIgnoreHints = true;
999 #else
1001 U8 nMaskBit = 0;
1002 U8 nMaskByte = 0;
1003 for( i = 0; i < mnHintSize; i+=2, nMaskBit>>=1) {
1004 if( !nMaskBit) {
1005 nMaskByte = *(mpReadPtr++);
1006 nMaskBit = 0x80;
1008 if( !(nMaskByte & nMaskBit))
1009 continue;
1010 if( i >= 8*(int)sizeof(mnCntrMask))
1011 mbIgnoreHints = true;
1012 if( mbIgnoreHints)
1013 continue;
1014 mnCntrMask |= (1U << i);
1017 #endif
1018 break;
1019 case TYPE2OP::HINTMASK:
1020 addHints( true);
1021 #ifdef IGNORE_HINTS
1022 mpReadPtr += (mnHintSize + 15) / 16;
1023 #else
1025 long nHintMask = 0;
1026 int nCntrBits[2] = {0,0};
1027 U8 nMaskBit = 0;
1028 U8 nMaskByte = 0;
1029 for( i = 0; i < mnHintSize; i+=2, nMaskBit>>=1) {
1030 if( !nMaskBit) {
1031 nMaskByte = *(mpReadPtr++);
1032 nMaskBit = 0x80;
1034 if( !(nMaskByte & nMaskBit))
1035 continue;
1036 if( i >= 8*(int)sizeof(nHintMask))
1037 mbIgnoreHints = true;
1038 if( mbIgnoreHints)
1039 continue;
1040 nHintMask |= (1U << i);
1041 nCntrBits[ i < mnHorzHintSize] += (mnCntrMask >> i) & 1;
1044 mbIgnoreHints |= (nCntrBits[0] && (nCntrBits[0] != 3));
1045 mbIgnoreHints |= (nCntrBits[1] && (nCntrBits[1] != 3));
1046 if( mbIgnoreHints)
1047 break;
1049 for( i = 0; i < mnHintSize; i+=2) {
1050 if( !(nHintMask & (1U << i)))
1051 continue;
1052 writeType1Val( mnHintStack[i]);
1053 writeType1Val( mnHintStack[i+1] - mnHintStack[i]);
1054 const bool bHorz = (i < mnHorzHintSize);
1055 if( !nCntrBits[ bHorz])
1056 writeTypeOp( bHorz ? TYPE1OP::HSTEM : TYPE1OP::VSTEM);
1057 else if( !--nCntrBits[ bHorz])
1058 writeTypeEsc( bHorz ? TYPE1OP::HSTEM3 : TYPE1OP::VSTEM3);
1061 #endif
1062 break;
1063 case TYPE2OP::CALLSUBR:
1064 case TYPE2OP::CALLGSUBR:
1066 nVal = pop();
1067 const bool bGlobal = (nType2Op == TYPE2OP::CALLGSUBR);
1068 callType2Subr( bGlobal, nVal);
1070 break;
1071 case TYPE2OP::RETURN:
1072 // TODO: check that we are in a subroutine
1073 return;
1074 case TYPE2OP::VMOVETO:
1075 case TYPE2OP::HMOVETO:
1076 if( mbNeedClose)
1077 writeTypeOp( TYPE1OP::CLOSEPATH);
1078 else
1079 updateWidth( size() > 1);
1080 mbNeedClose = true;
1081 pop2MultiWrite( 1, nType2Op);
1082 break;
1083 case TYPE2OP::VLINETO:
1084 case TYPE2OP::HLINETO:
1085 pop2MultiWrite( 1, nType2Op,
1086 TYPE1OP::VLINETO ^ TYPE1OP::HLINETO);
1087 break;
1088 case TYPE2OP::RMOVETO:
1089 // TODO: convert rmoveto to vlineto/hlineto if possible
1090 if( mbNeedClose)
1091 writeTypeOp( TYPE1OP::CLOSEPATH);
1092 else
1093 updateWidth( size() > 2);
1094 mbNeedClose = true;
1095 pop2MultiWrite( 2, nType2Op);
1096 break;
1097 case TYPE2OP::RLINETO:
1098 // TODO: convert rlineto to vlineto/hlineto if possible
1099 pop2MultiWrite( 2, nType2Op);
1100 break;
1101 case TYPE2OP::RCURVETO:
1102 // TODO: convert rcurveto to vh/hv/hh/vv-curveto if possible
1103 pop2MultiWrite( 6, nType2Op);
1104 break;
1105 case TYPE2OP::RCURVELINE:
1106 i = 0;
1107 while( (i += 6) <= mnStackIdx)
1108 writeCurveTo( i, -6, -5, -4, -3, -2, -1 );
1109 i -= 6;
1110 while( (i += 2) <= mnStackIdx) {
1111 writeType1Val( mnValStack[i-2]);
1112 writeType1Val( mnValStack[i-1]);
1113 writeTypeOp( TYPE2OP::RLINETO);
1115 clear();
1116 break;
1117 case TYPE2OP::RLINECURVE:
1118 i = 0;
1119 while( (i += 2) <= mnStackIdx-6) {
1120 writeType1Val( mnValStack[i-2]);
1121 writeType1Val( mnValStack[i-1]);
1122 writeTypeOp( TYPE2OP::RLINETO);
1124 i -= 2;
1125 while( (i += 6) <= mnStackIdx)
1126 writeCurveTo( i, -6, -5, -4, -3, -2, -1 );
1127 clear();
1128 break;
1129 case TYPE2OP::VHCURVETO:
1130 case TYPE2OP::HVCURVETO:
1132 bool bVert = (nType2Op == TYPE2OP::VHCURVETO);
1133 i = 0;
1134 nVal = 0;
1135 if( mnStackIdx & 1)
1136 nVal = mnValStack[ --mnStackIdx];
1137 while( (i += 4) <= mnStackIdx) {
1138 // TODO: use writeCurveTo()
1139 if( bVert) writeType1Val( 0);
1140 writeType1Val( mnValStack[i-4]);
1141 if( !bVert) writeType1Val( 0);
1142 writeType1Val( mnValStack[i-3]);
1143 writeType1Val( mnValStack[i-2]);
1144 if( !bVert) writeType1Val( (i==mnStackIdx) ? nVal : 0);
1145 writeType1Val( mnValStack[i-1]);
1146 if( bVert) writeType1Val( (i==mnStackIdx) ? nVal : 0 );
1147 bVert = !bVert;
1148 writeTypeOp( TYPE2OP::RCURVETO);
1151 clear();
1152 break;
1153 case TYPE2OP::HHCURVETO:
1154 i = (mnStackIdx & 1);
1155 while( (i += 4) <= mnStackIdx) {
1156 if( i != 5)
1157 writeCurveTo( i, -4, 0, -3, -2, -1, 0);
1158 else
1159 writeCurveTo( i, -4, -5, -3, -2, -1, 0);
1161 clear();
1162 break;
1163 case TYPE2OP::VVCURVETO:
1164 i = (mnStackIdx & 1);
1165 while( (i += 4) <= mnStackIdx) {
1166 if( i != 5)
1167 writeCurveTo( i, 0, -4, -3, -2, 0, -1);
1168 else
1169 writeCurveTo( i, -5, -4, -3, -2, 0, -1);
1171 clear();
1172 break;
1173 case TYPE2OP::ENDCHAR:
1174 if( mbNeedClose)
1175 writeTypeOp( TYPE1OP::CLOSEPATH);
1176 else
1177 updateWidth( size() >= 1);
1178 // mbNeedClose = true;
1179 writeTypeOp( TYPE1OP::ENDCHAR);
1180 break;
1181 default:
1182 if( ((nType2Op >= 32) && (nType2Op <= 255)) || (nType2Op == 28)) {
1183 --mpReadPtr;
1184 read2push();
1185 } else {
1186 popAll2Write( nType2Op);
1187 assert( false); // TODO?
1189 break;
1193 // --------------------------------------------------------------------
1195 void CffSubsetterContext::convertOneTypeEsc( void)
1197 const int nType2Esc = *(mpReadPtr++);
1198 int* pTop = &mnValStack[ mnStackIdx-1];
1199 // convert each T2op
1200 switch( nType2Esc) {
1201 case TYPE2OP::AND:
1202 assert( mnStackIdx >= 2);
1203 pTop[0] &= pTop[-1];
1204 --mnStackIdx;
1205 break;
1206 case TYPE2OP::OR:
1207 assert( mnStackIdx >= 2);
1208 pTop[0] |= pTop[-1];
1209 --mnStackIdx;
1210 break;
1211 case TYPE2OP::NOT:
1212 assert( mnStackIdx >= 1);
1213 pTop[0] = !pTop[0];
1214 break;
1215 case TYPE2OP::ABS:
1216 assert( mnStackIdx >= 1);
1217 if( pTop[0] >= 0)
1218 break;
1219 // fall through
1220 case TYPE2OP::NEG:
1221 assert( mnStackIdx >= 1);
1222 pTop[0] = -pTop[0];
1223 break;
1224 case TYPE2OP::ADD:
1225 assert( mnStackIdx >= 2);
1226 pTop[0] += pTop[-1];
1227 --mnStackIdx;
1228 break;
1229 case TYPE2OP::SUB:
1230 assert( mnStackIdx >= 2);
1231 pTop[0] -= pTop[-1];
1232 --mnStackIdx;
1233 break;
1234 case TYPE2OP::MUL:
1235 assert( mnStackIdx >= 2);
1236 if( pTop[-1])
1237 pTop[0] *= pTop[-1];
1238 --mnStackIdx;
1239 break;
1240 case TYPE2OP::DIV:
1241 assert( mnStackIdx >= 2);
1242 if( pTop[-1])
1243 pTop[0] /= pTop[-1];
1244 --mnStackIdx;
1245 break;
1246 case TYPE2OP::EQ:
1247 assert( mnStackIdx >= 2);
1248 pTop[0] = (pTop[0] == pTop[-1]);
1249 --mnStackIdx;
1250 break;
1251 case TYPE2OP::DROP:
1252 assert( mnStackIdx >= 1);
1253 --mnStackIdx;
1254 break;
1255 case TYPE2OP::PUT: {
1256 assert( mnStackIdx >= 2);
1257 const int nIdx = pTop[0];
1258 assert( nIdx >= 0);
1259 assert( nIdx < NMAXTRANS);
1260 mnTransVals[ nIdx] = pTop[-1];
1261 mnStackIdx -= 2;
1262 break;
1264 case TYPE2OP::GET: {
1265 assert( mnStackIdx >= 1);
1266 const int nIdx = pTop[0];
1267 assert( nIdx >= 0);
1268 assert( nIdx < NMAXTRANS);
1269 pTop[0] = mnTransVals[ nIdx];
1270 break;
1272 case TYPE2OP::IFELSE: {
1273 assert( mnStackIdx >= 4);
1274 if( pTop[-1] > pTop[0])
1275 pTop[-3] = pTop[-2];
1276 mnStackIdx -= 3;
1277 break;
1279 case TYPE2OP::RANDOM:
1280 pTop[+1] = 1234; // TODO
1281 ++mnStackIdx;
1282 break;
1283 case TYPE2OP::SQRT:
1284 // TODO: implement
1285 break;
1286 case TYPE2OP::DUP:
1287 assert( mnStackIdx >= 1);
1288 pTop[+1] = pTop[0];
1289 ++mnStackIdx;
1290 break;
1291 case TYPE2OP::EXCH: {
1292 assert( mnStackIdx >= 2);
1293 const int nVal = pTop[0];
1294 pTop[0] = pTop[-1];
1295 pTop[-1] = nVal;
1296 break;
1298 case TYPE2OP::INDEX: {
1299 assert( mnStackIdx >= 1);
1300 const int nVal = pTop[0];
1301 assert( nVal >= 0);
1302 assert( nVal < mnStackIdx-1);
1303 pTop[0] = pTop[-1-nVal];
1304 break;
1306 case TYPE2OP::ROLL: {
1307 assert( mnStackIdx >= 1);
1308 const int nNum = pTop[0];
1309 assert( nNum >= 0);
1310 assert( nNum < mnStackIdx-2);
1311 (void)nNum; // TODO: implement
1312 const int nOfs = pTop[-1];
1313 mnStackIdx -= 2;
1314 (void)nOfs;// TODO: implement
1315 break;
1317 case TYPE2OP::HFLEX1: {
1318 assert( mnStackIdx == 9);
1319 writeCurveTo( mnStackIdx, -9, -8, -7, -6, -5, -6);
1320 writeCurveTo( mnStackIdx, -4, -6, -3, -2, -1, -8);
1321 mnStackIdx -= 9;
1323 break;
1324 case TYPE2OP::HFLEX: {
1325 assert( mnStackIdx == 7);
1326 writeCurveTo( mnStackIdx, -7, 0, -6, -5, -4, -5);
1327 writeCurveTo( mnStackIdx, -3, -5, -2, 0, -1, 0);
1328 mnStackIdx -= 7;
1330 break;
1331 case TYPE2OP::FLEX: {
1332 assert( mnStackIdx == 13);
1333 writeCurveTo( mnStackIdx, -13, -12, -11, -10, -9, -8);
1334 writeCurveTo( mnStackIdx, -7, -6, -5, -4, -3, -2);
1335 const int nFlexDepth = mnValStack[ mnStackIdx-1];
1336 (void)nFlexDepth; // ignoring nFlexDepth
1337 mnStackIdx -= 13;
1339 break;
1340 case TYPE2OP::FLEX1: {
1341 assert( mnStackIdx == 11);
1342 // write the first part of the flex1-hinted curve
1343 writeCurveTo( mnStackIdx, -11, -10, -9, -8, -7, -6);
1345 // determine if nD6 is horizontal or vertical
1346 const int i = mnStackIdx;
1347 int nDeltaX = mnValStack[i-11] + mnValStack[i-9] + mnValStack[i-7] + mnValStack[i-5] + mnValStack[i-3];
1348 if( nDeltaX < 0 ) nDeltaX = -nDeltaX;
1349 int nDeltaY = mnValStack[i-10] + mnValStack[i-8] + mnValStack[i-6] + mnValStack[i-4] + mnValStack[i-2];
1350 if( nDeltaY < 0 ) nDeltaY = -nDeltaY;
1351 const bool bVertD6 = (nDeltaY > nDeltaX);
1353 // write the second part of the flex1-hinted curve
1354 if( !bVertD6 )
1355 writeCurveTo( mnStackIdx, -5, -4, -3, -2, -1, 0);
1356 else
1357 writeCurveTo( mnStackIdx, -5, -4, -3, -2, 0, -1);
1358 mnStackIdx -= 11;
1360 break;
1361 default:
1362 fprintf( stderr,"unhandled type2esc %d\n", nType2Esc);
1363 assert( false);
1364 break;
1368 // --------------------------------------------------------------------
1370 void CffSubsetterContext::callType2Subr( bool bGlobal, int nSubrNumber)
1372 const U8* const pOldReadPtr = mpReadPtr;
1373 const U8* const pOldReadEnd = mpReadEnd;
1375 int nLen = 0;
1376 if( bGlobal ) {
1377 nSubrNumber += mnGlobalSubrBias;
1378 nLen = seekIndexData( mnGlobalSubrBase, nSubrNumber);
1379 } else {
1380 nSubrNumber += mpCffLocal->mnLocalSubrBias;
1381 nLen = seekIndexData( mpCffLocal->mnLocalSubrBase, nSubrNumber);
1384 while( mpReadPtr < mpReadEnd)
1385 convertOneTypeOp();
1387 mpReadPtr = pOldReadPtr;
1388 mpReadEnd = pOldReadEnd;
1391 // --------------------------------------------------------------------
1393 static const int MAX_T1OPS_SIZE = 81920; // TODO: use dynamic value
1395 int CffSubsetterContext::convert2Type1Ops( CffLocal* pCffLocal, const U8* const pT2Ops, int nT2Len, U8* const pT1Ops)
1397 mpCffLocal = pCffLocal;
1399 // prepare the charstring conversion
1400 mpWritePtr = pT1Ops;
1401 #if 1 // TODO: update caller
1402 U8 aType1Ops[ MAX_T1OPS_SIZE];
1403 if( !pT1Ops)
1404 mpWritePtr = aType1Ops;
1405 *const_cast<U8**>(&pT1Ops) = mpWritePtr;
1406 #else
1407 assert( pT1Ops);
1408 #endif
1410 // prepend random seed for T1crypt
1411 *(mpWritePtr++) = 0x48;
1412 *(mpWritePtr++) = 0x44;
1413 *(mpWritePtr++) = 0x55;
1414 *(mpWritePtr++) = ' ';
1415 #if 1 // convert the Type2 charstring to Type1
1416 mpReadPtr = pT2Ops;
1417 mpReadEnd = pT2Ops + nT2Len;
1418 // prepend "hsbw" or "sbw"
1419 // TODO: only emit hsbw when charwidth is known
1420 // TODO: remove charwidth from T2 stack
1421 writeType1Val( 0); // TODO: aSubsetterContext.getLeftSideBearing();
1422 writeType1Val( 1000/*###getCharWidth()###*/);
1423 writeTypeOp( TYPE1OP::HSBW);
1424 mbSawError = false;
1425 mbNeedClose = false;
1426 mbIgnoreHints = false;
1427 mnHintSize=mnHorzHintSize=mnStackIdx=0; mnCharWidth=-1;//#######
1428 mnCntrMask = 0;
1429 while( mpReadPtr < mpReadEnd)
1430 convertOneTypeOp();
1431 // if( bActivePath)
1432 // writeTypeOp( TYPE1OP::CLOSEPATH);
1433 // if( bSubRoutine)
1434 // writeTypeOp( TYPE1OP::RETURN);
1435 if( mbSawError) {
1436 mpWritePtr = pT1Ops+4;
1437 // create an "idiotproof" charstring
1438 writeType1Val( 0);
1439 writeType1Val( 800);
1440 writeTypeOp( TYPE1OP::HSBW);
1441 writeType1Val( 50);
1442 writeTypeOp( TYPE1OP::HMOVETO);
1443 writeType1Val( 650);
1444 writeType1Val( 100);
1445 writeTypeOp( TYPE1OP::RLINETO);
1446 writeType1Val( -350);
1447 writeType1Val( 700);
1448 writeTypeOp( TYPE1OP::RLINETO);
1449 #if 0
1450 writeType1Val( -300);
1451 writeType1Val( -800);
1452 writeTypeOp( TYPE1OP::RLINETO);
1453 #else
1454 writeTypeOp( TYPE1OP::CLOSEPATH);
1455 #endif
1456 writeTypeOp( TYPE1OP::ENDCHAR);
1458 #else // useful for manually encoding charstrings
1459 mpWritePtr = pT1Ops;
1460 mpWritePtr += sprintf( (char*)mpWritePtr, "OOo_\x8b\x8c\x0c\x10\x0b");
1461 #endif
1462 const int nType1Len = mpWritePtr - pT1Ops;
1464 // encrypt the Type1 charstring
1465 int nRDCryptR = 4330; // TODO: mnRDCryptSeed;
1466 for( U8* p = pT1Ops; p < mpWritePtr; ++p) {
1467 *p ^= (nRDCryptR >> 8);
1468 nRDCryptR = (*(U8*)p + nRDCryptR) * 52845 + 22719;
1471 return nType1Len;
1474 // --------------------------------------------------------------------
1476 double CffSubsetterContext::readRealVal()
1478 // TODO: more thorough number validity test
1479 bool bComma = false;
1480 int nExpVal = 0;
1481 int nExpSign = 0;
1482 S64 nNumber = 0;
1483 double fReal = +1.0;
1484 for(;;){
1485 const U8 c = *(mpReadPtr++); // read nibbles
1486 // parse high nibble
1487 const U8 nH = c >> 4U;
1488 if( nH <= 9) {
1489 nNumber = nNumber * 10 + nH;
1490 --nExpVal;
1491 } else if( nH == 10) { // comma
1492 nExpVal = 0;
1493 bComma = true;
1494 } else if( nH == 11) { // +exp
1495 fReal *= nNumber;
1496 nExpSign = +1;
1497 nNumber = 0;
1498 } else if( nH == 12) { // -exp
1499 fReal *= nNumber;
1500 nExpSign = -1;
1501 nNumber = 0;
1502 } else if( nH == 13) { // reserved
1503 // TODO: ignore or error?
1504 } else if( nH == 14) // minus
1505 fReal = -fReal;
1506 else if( nH == 15) // end
1507 break;
1508 // parse low nibble
1509 const U8 nL = c & 0x0F;
1510 if( nL <= 9) {
1511 nNumber = nNumber * 10 + nL;
1512 --nExpVal;
1513 } else if( nL == 10) { // comma
1514 nExpVal = 0;
1515 bComma = true;
1516 } else if( nL == 11) { // +exp
1517 fReal *= nNumber;
1518 nNumber = 0;
1519 nExpSign = +1;
1520 } else if( nL == 12) { // -exp
1521 fReal *= nNumber;
1522 nNumber = 0;
1523 nExpSign = -1;
1524 } else if( nL == 13) { // reserved
1525 // TODO: ignore or error?
1526 } else if( nL == 14) // minus
1527 fReal = -fReal;
1528 else if( nL == 15) // end
1529 break;
1532 // merge exponents
1533 if( !bComma)
1534 nExpVal = 0;
1535 if( !nExpSign) { fReal *= nNumber;}
1536 else if( nExpSign > 0) { nExpVal += static_cast<int>(nNumber);}
1537 else if( nExpSign < 0) { nExpVal -= static_cast<int>(nNumber);}
1539 // apply exponents
1540 if( !nExpVal) { /*nothing to apply*/}
1541 else if( nExpVal > 0) { while( --nExpVal >= 0) fReal *= 10.0;}
1542 else if( nExpVal < 0) { while( ++nExpVal <= 0) fReal /= 10.0;}
1543 return fReal;
1546 // --------------------------------------------------------------------
1548 // prepare to access an element inside a CFF/CID index table
1549 int CffSubsetterContext::seekIndexData( int nIndexBase, int nDataIndex)
1551 if( nDataIndex < 0)
1552 return -1;
1553 mpReadPtr = mpBasePtr + nIndexBase;
1554 const int nDataCount = (mpReadPtr[0]<<8) + mpReadPtr[1];
1555 if( nDataIndex >= nDataCount)
1556 return -1;
1557 const int nDataOfsSz = mpReadPtr[2];
1558 mpReadPtr += 3 + (nDataOfsSz * nDataIndex);
1559 int nOfs1 = 0;
1560 switch( nDataOfsSz) {
1561 default: fprintf( stderr, "\tINVALID nDataOfsSz=%d\n\n", nDataOfsSz); return -1;
1562 case 1: nOfs1 = mpReadPtr[0]; break;
1563 case 2: nOfs1 = (mpReadPtr[0]<<8) + mpReadPtr[1]; break;
1564 case 3: nOfs1 = (mpReadPtr[0]<<16) + (mpReadPtr[1]<<8) + mpReadPtr[2]; break;
1565 case 4: nOfs1 = (mpReadPtr[0]<<24) + (mpReadPtr[1]<<16) + (mpReadPtr[2]<<8) + mpReadPtr[3]; break;
1567 mpReadPtr += nDataOfsSz;
1569 int nOfs2 = 0;
1570 switch( nDataOfsSz) {
1571 case 1: nOfs2 = mpReadPtr[0]; break;
1572 case 2: nOfs2 = (mpReadPtr[0]<<8) + mpReadPtr[1]; break;
1573 case 3: nOfs2 = (mpReadPtr[0]<<16) + (mpReadPtr[1]<<8) + mpReadPtr[2]; break;
1574 case 4: nOfs2 = (mpReadPtr[0]<<24) + (mpReadPtr[1]<<16) + (mpReadPtr[2]<<8) + mpReadPtr[3]; break;
1577 mpReadPtr = mpBasePtr + (nIndexBase + 2) + nDataOfsSz * (nDataCount + 1) + nOfs1;
1578 mpReadEnd = mpReadPtr + (nOfs2 - nOfs1);
1579 assert( nOfs1 >= 0);
1580 assert( nOfs2 >= nOfs1);
1581 assert( mpReadEnd <= mpBaseEnd);
1582 return (nOfs2 - nOfs1);
1585 // --------------------------------------------------------------------
1587 // skip over a CFF/CID index table
1588 void CffSubsetterContext::seekIndexEnd( int nIndexBase)
1590 mpReadPtr = mpBasePtr + nIndexBase;
1591 const int nDataCount = (mpReadPtr[0]<<8) + mpReadPtr[1];
1592 const int nDataOfsSz = mpReadPtr[2];
1593 mpReadPtr += 3 + nDataOfsSz * nDataCount;
1594 int nEndOfs = 0;
1595 switch( nDataOfsSz) {
1596 default: fprintf( stderr, "\tINVALID nDataOfsSz=%d\n\n", nDataOfsSz); return;
1597 case 1: nEndOfs = mpReadPtr[0]; break;
1598 case 2: nEndOfs = (mpReadPtr[0]<<8) + mpReadPtr[1]; break;
1599 case 3: nEndOfs = (mpReadPtr[0]<<16) + (mpReadPtr[1]<<8) + mpReadPtr[2];break;
1600 case 4: nEndOfs = (mpReadPtr[0]<<24) + (mpReadPtr[1]<<16) + (mpReadPtr[2]<<8) + mpReadPtr[3]; break;
1602 mpReadPtr += nDataOfsSz;
1603 mpReadPtr += nEndOfs - 1;
1604 mpReadEnd = mpBaseEnd;
1607 // ====================================================================
1609 // initialize FONTDICT specific values
1610 CffLocal::CffLocal( void)
1611 : mnPrivDictBase( 0)
1612 , mnPrivDictSize( 0)
1613 , mnLocalSubrOffs( 0)
1614 , mnLocalSubrBase( 0)
1615 , mnLocalSubrCount( 0)
1616 , mnLocalSubrBias( 0)
1617 , mnNominalWidth( 0)
1618 , mnDefaultWidth( 0)
1619 , mnStemStdHW( 0)
1620 , mnStemStdVW( 0)
1621 , mfBlueScale( 0.0)
1622 , mfBlueShift( 0.0)
1623 , mfBlueFuzz( 0.0)
1624 , mfExpFactor( 0.0)
1625 , mnLangGroup( 0)
1626 , mbForceBold( false)
1628 maStemSnapH.clear();
1629 maStemSnapV.clear();
1630 maBlueValues.clear();
1631 maOtherBlues.clear();
1632 maFamilyBlues.clear();
1633 maFamilyOtherBlues.clear();
1636 // --------------------------------------------------------------------
1638 CffGlobal::CffGlobal( void)
1639 : mnNameIdxBase( 0)
1640 , mnNameIdxCount( 0)
1641 , mnStringIdxBase( 0)
1642 , mnStringIdxCount( 0)
1643 , mbCIDFont( false)
1644 , mnCharStrBase( 0)
1645 , mnCharStrCount( 0)
1646 , mnEncodingBase( 0)
1647 , mnCharsetBase( 0)
1648 , mnGlobalSubrBase( 0)
1649 , mnGlobalSubrCount( 0)
1650 , mnGlobalSubrBias( 0)
1651 , mnFDSelectBase( 0)
1652 , mnFontDictBase( 0)
1653 , mnFDAryCount( 1)
1654 , mnFontNameSID( 0)
1655 , mnFullNameSID( 0)
1656 , mnFamilyNameSID( 0)
1658 maFontBBox.clear();
1659 // TODO; maFontMatrix.clear();
1662 // --------------------------------------------------------------------
1664 void CffSubsetterContext::initialCffRead( void)
1666 // get the CFFHeader
1667 mpReadPtr = mpBasePtr;
1668 const U8 nVerMajor = *(mpReadPtr++);
1669 const U8 nVerMinor = *(mpReadPtr++);
1670 const U8 nHeaderSize = *(mpReadPtr++);
1671 const U8 nOffsetSize = *(mpReadPtr++);
1672 // TODO: is the version number useful for anything else?
1673 assert( (nVerMajor == 1) && (nVerMinor == 0));
1674 (void)(nVerMajor + nVerMinor + nOffsetSize); // avoid compiler warnings
1676 // prepare access to the NameIndex
1677 mnNameIdxBase = nHeaderSize;
1678 mpReadPtr = mpBasePtr + nHeaderSize;
1679 mnNameIdxCount = (mpReadPtr[0]<<8) + mpReadPtr[1];
1680 seekIndexEnd( mnNameIdxBase);
1682 // get the TopDict index
1683 const long nTopDictBase = getReadOfs();
1684 const int nTopDictCount = (mpReadPtr[0]<<8) + mpReadPtr[1];
1685 if( nTopDictCount) {
1686 for( int i = 0; i < nTopDictCount; ++i) {
1687 seekIndexData( nTopDictBase, i);
1688 while( mpReadPtr < mpReadEnd)
1689 readDictOp();
1690 assert( mpReadPtr == mpReadEnd);
1694 // prepare access to the String index
1695 mnStringIdxBase = getReadOfs();
1696 mnStringIdxCount = (mpReadPtr[0]<<8) + mpReadPtr[1];
1697 seekIndexEnd( mnStringIdxBase);
1699 // prepare access to the GlobalSubr index
1700 mnGlobalSubrBase = getReadOfs();
1701 mnGlobalSubrCount = (mpReadPtr[0]<<8) + mpReadPtr[1];
1702 mnGlobalSubrBias = (mnGlobalSubrCount<1240)?107:(mnGlobalSubrCount<33900)?1131:32768;
1703 // skip past the last GlobalSubr entry
1704 // seekIndexEnd( mnGlobalSubrBase);
1706 // get/skip the Encodings (we got mnEncodingBase from TOPDICT)
1707 // seekEncodingsEnd( mnEncodingBase);
1708 // get/skip the Charsets (we got mnCharsetBase from TOPDICT)
1709 // seekCharsetsEnd( mnCharStrBase);
1710 // get/skip FDSelect (CID only) data
1712 // prepare access to the CharStrings index (we got the base from TOPDICT)
1713 mpReadPtr = mpBasePtr + mnCharStrBase;
1714 mnCharStrCount = (mpReadPtr[0]<<8) + mpReadPtr[1];
1715 // seekIndexEnd( mnCharStrBase);
1717 // read the FDArray index (CID only)
1718 if( mbCIDFont) {
1719 // assert( mnFontDictBase == tellRel());
1720 mpReadPtr = mpBasePtr + mnFontDictBase;
1721 mnFDAryCount = (mpReadPtr[0]<<8) + mpReadPtr[1];
1722 assert( mnFDAryCount < (int)(sizeof(maCffLocal)/sizeof(*maCffLocal)));
1724 // read FDArray details to get access to the PRIVDICTs
1725 for( int i = 0; i < mnFDAryCount; ++i) {
1726 mpCffLocal = &maCffLocal[i];
1727 seekIndexData( mnFontDictBase, i);
1728 while( mpReadPtr < mpReadEnd)
1729 readDictOp();
1730 assert( mpReadPtr == mpReadEnd);
1734 for( int i = 0; i < mnFDAryCount; ++i) {
1735 mpCffLocal = &maCffLocal[i];
1737 // get the PrivateDict index
1738 // (we got mnPrivDictSize and mnPrivDictBase from TOPDICT or FDArray)
1739 if( mpCffLocal->mnPrivDictSize != 0) {
1740 assert( mpCffLocal->mnPrivDictSize > 0);
1741 // get the PrivDict data
1742 mpReadPtr = mpBasePtr + mpCffLocal->mnPrivDictBase;
1743 mpReadEnd = mpReadPtr + mpCffLocal->mnPrivDictSize;
1744 assert( mpReadEnd <= mpBaseEnd);
1745 // read PrivDict details
1746 while( mpReadPtr < mpReadEnd)
1747 readDictOp();
1750 // prepare access to the LocalSubrs (we got mnLocalSubrOffs from PRIVDICT)
1751 if( mpCffLocal->mnLocalSubrOffs) {
1752 // read LocalSubrs summary
1753 mpCffLocal->mnLocalSubrBase = mpCffLocal->mnPrivDictBase + mpCffLocal->mnLocalSubrOffs;
1754 mpReadPtr = mpBasePtr + mpCffLocal->mnLocalSubrBase;
1755 const int nSubrCount = (mpReadPtr[0] << 8) + mpReadPtr[1];
1756 mpCffLocal->mnLocalSubrCount = nSubrCount;
1757 mpCffLocal->mnLocalSubrBias = (nSubrCount<1240)?107:(nSubrCount<33900)?1131:32768;
1758 // seekIndexEnd( mpCffLocal->mnLocalSubrBase);
1762 // ignore the Notices info
1765 // --------------------------------------------------------------------
1767 // get a cstring from a StringID
1768 const char* CffSubsetterContext::getString( int nStringID)
1770 // get a standard string if possible
1771 const static int nStdStrings = sizeof(pStringIds)/sizeof(*pStringIds);
1772 if( (nStringID >= 0) && (nStringID < nStdStrings))
1773 return pStringIds[ nStringID];
1775 // else get the string from the StringIndex table
1776 const U8* pReadPtr = mpReadPtr;
1777 const U8* pReadEnd = mpReadEnd;
1778 nStringID -= nStdStrings;
1779 int nLen = seekIndexData( mnStringIdxBase, nStringID);
1780 // assert( nLen >= 0);
1781 // TODO: just return the undecorated name
1782 // TODO: get rid of static char buffer
1783 static char aNameBuf[ 2560];
1784 if( nLen < 0) {
1785 sprintf( aNameBuf, "name[%d].notfound!", nStringID);
1786 } else {
1787 const int nMaxLen = sizeof(aNameBuf) - 1;
1788 if( nLen >= nMaxLen)
1789 nLen = nMaxLen;
1790 for( int i = 0; i < nLen; ++i)
1791 aNameBuf[i] = *(mpReadPtr++);
1792 aNameBuf[ nLen] = '\0';
1794 mpReadPtr = pReadPtr;
1795 mpReadEnd = pReadEnd;
1796 return aNameBuf;
1799 // --------------------------------------------------------------------
1801 // access a CID's FDSelect table
1802 int CffSubsetterContext::getFDSelect( int nGlyphIndex) const
1804 assert( nGlyphIndex >= 0);
1805 assert( nGlyphIndex < mnCharStrCount);
1806 if( !mbCIDFont)
1807 return 0;
1809 const U8* pReadPtr = mpBasePtr + mnFDSelectBase;
1810 const U8 nFDSelFormat = *(pReadPtr++);
1811 switch( nFDSelFormat) {
1812 case 0: { // FDSELECT format 0
1813 pReadPtr += nGlyphIndex;
1814 const U8 nFDIdx = *(pReadPtr++);
1815 return nFDIdx;
1816 } //break;
1817 case 3: { // FDSELECT format 3
1818 const U16 nRangeCount = (pReadPtr[0]<<8) + pReadPtr[1];
1819 assert( nRangeCount > 0);
1820 assert( nRangeCount <= mnCharStrCount);
1821 U16 nPrev = (pReadPtr[2]<<8) + pReadPtr[3];
1822 assert( nPrev == 0);
1823 pReadPtr += 4;
1824 // TODO? binary search
1825 for( int i = 0; i < nRangeCount; ++i) {
1826 const U8 nFDIdx = pReadPtr[0];
1827 const U16 nNext = (pReadPtr[1]<<8) + pReadPtr[2];
1828 assert( nPrev < nNext);
1829 if( nGlyphIndex < nNext)
1830 return nFDIdx;
1831 pReadPtr += 3;
1832 nPrev = nNext;
1834 } break;
1835 default: // invalid FDselect format
1836 fprintf( stderr, "invalid CFF.FdselType=%d\n", nFDSelFormat);
1837 break;
1840 assert( false);
1841 return -1;
1844 // --------------------------------------------------------------------
1846 int CffSubsetterContext::getGlyphSID( int nGlyphIndex) const
1848 if( nGlyphIndex == 0)
1849 return 0; // ".notdef"
1850 assert( nGlyphIndex >= 0);
1851 assert( nGlyphIndex < mnCharStrCount);
1852 if( (nGlyphIndex < 0) || (nGlyphIndex >= mnCharStrCount))
1853 return -1;
1855 // get the SID/CID from the Charset table
1856 const U8* pReadPtr = mpBasePtr + mnCharsetBase;
1857 const U8 nCSetFormat = *(pReadPtr++);
1858 int nGlyphsToSkip = nGlyphIndex - 1;
1859 switch( nCSetFormat) {
1860 case 0: // charset format 0
1861 pReadPtr += 2 * nGlyphsToSkip;
1862 nGlyphsToSkip = 0;
1863 break;
1864 case 1: // charset format 1
1865 while( nGlyphsToSkip >= 0) {
1866 const int nLeft = pReadPtr[2];
1867 if( nGlyphsToSkip <= nLeft)
1868 break;
1869 nGlyphsToSkip -= nLeft + 1;
1870 pReadPtr += 3;
1872 break;
1873 case 2: // charset format 2
1874 while( nGlyphsToSkip >= 0) {
1875 const int nLeft = (pReadPtr[2]<<8) + pReadPtr[3];
1876 if( nGlyphsToSkip <= nLeft)
1877 break;
1878 nGlyphsToSkip -= nLeft + 1;
1879 pReadPtr += 4;
1881 break;
1882 default:
1883 fprintf( stderr, "ILLEGAL CFF-Charset format %d\n", nCSetFormat);
1884 return -2;
1887 int nSID = (pReadPtr[0]<<8) + pReadPtr[1];
1888 nSID += nGlyphsToSkip;
1889 // NOTE: for CID-fonts the resulting SID is interpreted as CID
1890 return nSID;
1893 // --------------------------------------------------------------------
1895 // NOTE: the result becomes invalid with the next call to this method
1896 const char* CffSubsetterContext::getGlyphName( int nGlyphIndex)
1898 // the first glyph is always the .notdef glyph
1899 const char* pGlyphName = ".notdef";
1900 if( nGlyphIndex == 0)
1901 return pGlyphName;
1903 // prepare a result buffer
1904 // TODO: get rid of static buffer
1905 static char aDefaultGlyphName[64];
1906 pGlyphName = aDefaultGlyphName;
1908 // get the glyph specific name
1909 const int nSID = getGlyphSID( nGlyphIndex);
1910 if( nSID < 0) // default glyph name
1911 sprintf( aDefaultGlyphName, "gly%03d", nGlyphIndex);
1912 else if( mbCIDFont) // default glyph name in CIDs
1913 sprintf( aDefaultGlyphName, "cid%03d", nSID);
1914 else { // glyph name from string table
1915 const char* pSidName = getString( nSID);
1916 // check validity of glyph name
1917 if( pSidName) {
1918 const char* p = pSidName;
1919 while( (*p >= '0') && (*p <= 'z')) ++p;
1920 if( (p >= pSidName+1) && (*p == '\0'))
1921 pGlyphName = pSidName;
1923 // if needed invent a fallback name
1924 if( pGlyphName != pSidName)
1925 sprintf( aDefaultGlyphName, "bad%03d", nSID);
1928 return pGlyphName;
1931 // --------------------------------------------------------------------
1933 class Type1Emitter
1935 public:
1936 explicit Type1Emitter( const char* pOutFileName, bool bPfbSubset = true);
1937 explicit Type1Emitter( FILE* pOutFile, bool bPfbSubset = true);
1938 /*virtual*/ ~Type1Emitter( void);
1939 void setSubsetName( const char* );
1941 void emitRawData( const char* pData, int nLength) const;
1942 void emitAllRaw( void);
1943 void emitAllHex( void);
1944 void emitAllCrypted( void);
1945 int tellPos( void) const;
1946 void updateLen( int nTellPos, int nLength);
1947 void emitIntVector( const char* pLineHead, const char* pLineTail, const IntVector&);
1948 private:
1949 FILE* mpFileOut;
1950 bool mbCloseOutfile;
1951 char maBuffer[MAX_T1OPS_SIZE]; // TODO: dynamic allocation
1952 int mnEECryptR;
1953 public:
1954 char* mpPtr;
1956 char maSubsetName[256];
1957 bool mbPfbSubset;
1958 int mnHexLineCol;
1961 // --------------------------------------------------------------------
1963 Type1Emitter::Type1Emitter( const char* pPfbFileName, bool bPfbSubset)
1964 : mpFileOut( NULL)
1965 , mbCloseOutfile( true)
1966 , mnEECryptR( 55665) // default eexec seed, TODO: mnEECryptSeed
1967 , mpPtr( maBuffer)
1968 , mbPfbSubset( bPfbSubset)
1969 , mnHexLineCol( 0)
1971 mpFileOut = fopen( pPfbFileName, "wb");
1972 maSubsetName[0] = '\0';
1975 // --------------------------------------------------------------------
1977 Type1Emitter::Type1Emitter( FILE* pOutFile, bool bPfbSubset)
1978 : mpFileOut( pOutFile)
1979 , mbCloseOutfile( false)
1980 , mnEECryptR( 55665) // default eexec seed, TODO: mnEECryptSeed
1981 , mpPtr( maBuffer)
1982 , mbPfbSubset( bPfbSubset)
1983 , mnHexLineCol( 0)
1985 maSubsetName[0] = '\0';
1988 // --------------------------------------------------------------------
1990 Type1Emitter::~Type1Emitter( void)
1992 if( !mpFileOut)
1993 return;
1994 if( mbCloseOutfile )
1995 fclose( mpFileOut);
1996 mpFileOut = NULL;
1999 // --------------------------------------------------------------------
2001 void Type1Emitter::setSubsetName( const char* pSubsetName)
2003 maSubsetName[0] = '\0';
2004 if( pSubsetName)
2005 strncpy( maSubsetName, pSubsetName, sizeof(maSubsetName));
2006 maSubsetName[sizeof(maSubsetName)-1] = '\0';
2009 // --------------------------------------------------------------------
2011 int Type1Emitter::tellPos( void) const
2013 int nTellPos = ftell( mpFileOut);
2014 return nTellPos;
2017 // --------------------------------------------------------------------
2019 void Type1Emitter::updateLen( int nTellPos, int nLength)
2021 // update PFB segment header length
2022 U8 cData[4];
2023 cData[0] = static_cast<U8>(nLength >> 0);
2024 cData[1] = static_cast<U8>(nLength >> 8);
2025 cData[2] = static_cast<U8>(nLength >> 16);
2026 cData[3] = static_cast<U8>(nLength >> 24);
2027 const int nCurrPos = ftell( mpFileOut);
2028 fseek( mpFileOut, nTellPos, SEEK_SET);
2029 fwrite( cData, 1, sizeof(cData), mpFileOut);
2030 fseek( mpFileOut, nCurrPos, SEEK_SET);
2033 // --------------------------------------------------------------------
2035 inline void Type1Emitter::emitRawData( const char* pData, int nLength) const
2037 fwrite( pData, 1, nLength, mpFileOut);
2040 // --------------------------------------------------------------------
2042 inline void Type1Emitter::emitAllRaw( void)
2044 // writeout raw data
2045 assert( (mpPtr - maBuffer) < (int)sizeof(maBuffer));
2046 emitRawData( maBuffer, mpPtr - maBuffer);
2047 // reset the raw buffer
2048 mpPtr = maBuffer;
2051 // --------------------------------------------------------------------
2053 inline void Type1Emitter::emitAllHex( void)
2055 assert( (mpPtr - maBuffer) < (int)sizeof(maBuffer));
2056 for( const char* p = maBuffer; p < mpPtr;) {
2057 // convert binary chunk to hex
2058 char aHexBuf[0x4000];
2059 char* pOut = aHexBuf;
2060 while( (p < mpPtr) && (pOut < aHexBuf+sizeof(aHexBuf)-4)) {
2061 // convert each byte to hex
2062 char cNibble = (*p >> 4) & 0x0F;
2063 cNibble += (cNibble < 10) ? '0' : 'A'-10;
2064 *(pOut++) = cNibble;
2065 cNibble = *(p++) & 0x0F;
2066 cNibble += (cNibble < 10) ? '0' : 'A'-10;
2067 *(pOut++) = cNibble;
2068 // limit the line length
2069 if( (++mnHexLineCol & 0x3F) == 0)
2070 *(pOut++) = '\n';
2072 // writeout hex-converted chunk
2073 emitRawData( aHexBuf, pOut-aHexBuf);
2075 // reset the raw buffer
2076 mpPtr = maBuffer;
2079 // --------------------------------------------------------------------
2081 void Type1Emitter::emitAllCrypted( void)
2083 // apply t1crypt
2084 for( char* p = maBuffer; p < mpPtr; ++p) {
2085 *p ^= (mnEECryptR >> 8);
2086 mnEECryptR = (*(U8*)p + mnEECryptR) * 52845 + 22719;
2089 // emit the t1crypt result
2090 if( mbPfbSubset)
2091 emitAllRaw();
2092 else
2093 emitAllHex();
2096 // --------------------------------------------------------------------
2098 void Type1Emitter::emitIntVector( const char* pLineHead, const char* pLineTail,
2099 const IntVector& rVector)
2101 // ignore empty vectors
2102 if( rVector.empty())
2103 return;
2105 // emit the line head
2106 mpPtr += sprintf( mpPtr, pLineHead);
2107 // emit the vector values
2108 IntVector::value_type nVal = 0;
2109 for( IntVector::const_iterator it = rVector.begin();;) {
2110 nVal = *it;
2111 if( ++it == rVector.end() )
2112 break;
2113 mpPtr += sprintf( mpPtr, "%d ", nVal);
2115 // emit the last value
2116 mpPtr += sprintf( mpPtr, "%d", nVal);
2117 // emit the line tail
2118 mpPtr += sprintf( mpPtr, pLineTail);
2121 // --------------------------------------------------------------------
2123 bool CffSubsetterContext::emitAsType1( Type1Emitter& rEmitter,
2124 const long* pReqGlyphIDs, const U8* pReqEncoding,
2125 GlyphWidth* pGlyphWidths, int nGlyphCount, FontSubsetInfo& rFSInfo)
2127 // prepare some fontdirectory details
2128 static const int nUniqueIdBase = 4100000; // using private-interchange UniqueIds
2129 static int nUniqueId = nUniqueIdBase;
2130 ++nUniqueId;
2132 char* pFontName = rEmitter.maSubsetName;
2133 if( !*pFontName ) {
2134 if( mnFontNameSID) {
2135 // get the fontname directly if available
2136 strncpy( pFontName, getString( mnFontNameSID), sizeof(rEmitter.maSubsetName));
2137 } else if( mnFullNameSID) {
2138 // approximate fontname as fullname-whitespace
2139 const char* pI = getString( mnFullNameSID);
2140 char* pO = pFontName;
2141 const char* pLimit = pFontName + sizeof(rEmitter.maSubsetName) - 1;
2142 while( pO < pLimit) {
2143 const char c = *(pI++);
2144 if( c != ' ')
2145 *(pO++) = c;
2146 if( !c)
2147 break;
2149 *pO = '\0';
2150 } else {
2151 // fallback name of last resort
2152 strncpy( pFontName, "DummyName", sizeof(rEmitter.maSubsetName));
2155 const char* pFullName = pFontName;
2156 const char* pFamilyName = pFontName;
2158 char*& pOut = rEmitter.mpPtr; // convenience reference, TODO: cleanup
2160 // create a PFB+Type1 header
2161 if( rEmitter.mbPfbSubset ) {
2162 static const char aPfbHeader[] = "\x80\x01\x00\x00\x00\x00";
2163 rEmitter.emitRawData( aPfbHeader, sizeof(aPfbHeader)-1);
2166 pOut += sprintf( pOut, "%%!FontType1-1.0: %s 001.003\n", rEmitter.maSubsetName);
2167 // emit TOPDICT
2168 #if 0 // improve PS Type1 caching?
2169 nOfs += sprintf( &aT1Str[nOfs],
2170 "FontDirectory/%s known{/%s findfont dup/UniqueID known{dup\n"
2171 "/UniqueID get %d eq exch/FontType get 1 eq and}{pop false}ifelse\n"
2172 "{save true}{false}ifelse}\n{false}ifelse\n",
2173 pFamilyName, pFamilyName, nUniqueId);
2174 #endif
2175 pOut += sprintf( pOut,
2176 "11 dict begin\n" // TODO: dynamic entry count for TOPDICT
2177 "/FontType 1 def\n"
2178 "/PaintType 0 def\n");
2179 pOut += sprintf( pOut, "/FontName /%s def\n", rEmitter.maSubsetName);
2180 pOut += sprintf( pOut, "/UniqueID %d def\n", nUniqueId);
2181 pOut += sprintf( pOut, "/FontMatrix [0.001 0 0 0.001 0 0 ]readonly def\n");
2182 if( maFontBBox.size() == 4)
2183 pOut += sprintf( pOut, "/FontBBox [%d %d %d %d ]readonly def\n",
2184 maFontBBox[0], maFontBBox[1], maFontBBox[2], maFontBBox[3]);
2185 else
2186 pOut += sprintf( pOut, "/FontBBox [0 0 999 999]readonly def\n");
2187 // emit FONTINFO into TOPDICT
2188 pOut += sprintf( pOut,
2189 "/FontInfo 2 dict dup begin\n" // TODO: check fontinfo entry count
2190 " /FullName (%s) readonly def\n"
2191 " /FamilyName (%s) readonly def\n"
2192 "end readonly def\n",
2193 pFullName, pFamilyName);
2194 #if 0 // TODO: use an standard Type1 encoding if possible
2195 pOut += sprintf( pOut,
2196 "/Encoding StandardEncoding def\n");
2197 #else
2198 pOut += sprintf( pOut,
2199 "/Encoding 256 array\n"
2200 "0 1 255 {1 index exch /.notdef put} for\n");
2201 for( int i = 1; (i < nGlyphCount) && (i < 256); ++i) {
2202 const char* pGlyphName = getGlyphName( pReqGlyphIDs[i]);
2203 pOut += sprintf( pOut, "dup %d /%s put\n", pReqEncoding[i], pGlyphName);
2205 pOut += sprintf( pOut, "readonly def\n");
2206 #endif
2207 pOut += sprintf( pOut,
2208 // TODO: more topdict entries
2209 "currentdict end\n"
2210 "currentfile eexec\n");
2212 // emit PFB header
2213 rEmitter.emitAllRaw();
2214 if( rEmitter.mbPfbSubset) {
2215 // update PFB header segment
2216 const int nPfbHeaderLen = rEmitter.tellPos() - 6;
2217 rEmitter.updateLen( 2, nPfbHeaderLen);
2219 // prepare start of eexec segment
2220 rEmitter.emitRawData( "\x80\x02\x00\x00\x00\x00", 6); // segment start
2222 const int nEExecSegTell = rEmitter.tellPos();
2224 // which always starts with a privdict
2225 // count the privdict entries
2226 int nPrivEntryCount = 9;
2227 #if !defined(IGNORE_HINTS)
2228 // emit blue hints only if non-default values
2229 nPrivEntryCount += !mpCffLocal->maOtherBlues.empty();
2230 nPrivEntryCount += !mpCffLocal->maFamilyBlues.empty();
2231 nPrivEntryCount += !mpCffLocal->maFamilyOtherBlues.empty();
2232 nPrivEntryCount += (mpCffLocal->mfBlueScale != 0.0);
2233 nPrivEntryCount += (mpCffLocal->mfBlueShift != 0.0);
2234 nPrivEntryCount += (mpCffLocal->mfBlueFuzz != 0.0);
2235 // emit stem hints only if non-default values
2236 nPrivEntryCount += (mpCffLocal->mnStemStdHW != 0);
2237 nPrivEntryCount += (mpCffLocal->mnStemStdVW != 0);
2238 nPrivEntryCount += !mpCffLocal->maStemSnapH.empty();
2239 nPrivEntryCount += !mpCffLocal->maStemSnapV.empty();
2240 // emit other hints only if non-default values
2241 nPrivEntryCount += (mpCffLocal->mfExpFactor != 0.0);
2242 nPrivEntryCount += (mpCffLocal->mnLangGroup != 0);
2243 nPrivEntryCount += (mpCffLocal->mnLangGroup == 1);
2244 nPrivEntryCount += (mpCffLocal->mbForceBold != false);
2245 #endif // IGNORE_HINTS
2246 // emit the privdict header
2247 pOut += sprintf( pOut,
2248 "\110\104\125 "
2249 "dup\n/Private %d dict dup begin\n"
2250 "/RD{string currentfile exch readstring pop}executeonly def\n"
2251 "/ND{noaccess def}executeonly def\n"
2252 "/NP{noaccess put}executeonly def\n"
2253 "/MinFeature{16 16}ND\n"
2254 "/password 5839 def\n", // TODO: mnRDCryptSeed?
2255 nPrivEntryCount);
2257 #if defined(IGNORE_HINTS)
2258 pOut += sprintf( pOut, "/BlueValues []ND\n"); // BlueValues are mandatory
2259 #else
2260 // emit blue hint related privdict entries
2261 if( !mpCffLocal->maBlueValues.empty())
2262 rEmitter.emitIntVector( "/BlueValues [", "]ND\n", mpCffLocal->maBlueValues);
2263 else
2264 pOut += sprintf( pOut, "/BlueValues []ND\n"); // default to empty BlueValues
2265 rEmitter.emitIntVector( "/OtherBlues [", "]ND\n", mpCffLocal->maOtherBlues);
2266 rEmitter.emitIntVector( "/FamilyBlues [", "]ND\n", mpCffLocal->maFamilyBlues);
2267 rEmitter.emitIntVector( "/FamilyOtherBlues [", "]ND\n", mpCffLocal->maFamilyOtherBlues);
2269 if( mpCffLocal->mfBlueScale)
2270 pOut += sprintf( pOut, "/BlueScale %.6f def\n", mpCffLocal->mfBlueScale);
2271 if( mpCffLocal->mfBlueShift) // default BlueShift==7
2272 pOut += sprintf( pOut, "/BlueShift %.1f def\n", mpCffLocal->mfBlueShift);
2273 if( mpCffLocal->mfBlueFuzz) // default BlueFuzz==1
2274 pOut += sprintf( pOut, "/BlueFuzz %.1f def\n", mpCffLocal->mfBlueFuzz);
2276 // emit stem hint related privdict entries
2277 if( mpCffLocal->mnStemStdHW)
2278 pOut += sprintf( pOut, "/StdHW [%d] def\n", mpCffLocal->mnStemStdHW);
2279 if( mpCffLocal->mnStemStdVW)
2280 pOut += sprintf( pOut, "/StdVW [%d] def\n", mpCffLocal->mnStemStdVW);
2281 rEmitter.emitIntVector( "/StemSnapH [", "]ND\n", mpCffLocal->maStemSnapH);
2282 rEmitter.emitIntVector( "/StemSnapV [", "]ND\n", mpCffLocal->maStemSnapV);
2284 // emit other hints
2285 if( mpCffLocal->mbForceBold)
2286 pOut += sprintf( pOut, "/ForceBold true def\n");
2287 if( mpCffLocal->mnLangGroup != 0)
2288 pOut += sprintf( pOut, "/LanguageGroup %d def\n", mpCffLocal->mnLangGroup);
2289 if( mpCffLocal->mnLangGroup == 1) // compatibility with ancient printers
2290 pOut += sprintf( pOut, "/RndStemUp false def\n");
2291 if( mpCffLocal->mfExpFactor)
2292 pOut += sprintf( pOut, "/ExpansionFactor %.2f def\n", mpCffLocal->mfExpFactor);
2293 #endif // IGNORE_HINTS
2295 // emit remaining privdict entries
2296 pOut += sprintf( pOut, "/UniqueID %d def\n", nUniqueId);
2297 // TODO?: more privdict entries?
2299 static const char aOtherSubrs[] =
2300 "/OtherSubrs\n"
2301 "% Dummy code for faking flex hints\n"
2302 "[ {} {} {} {systemdict /internaldict known not {pop 3}\n"
2303 "{1183615869 systemdict /internaldict get exec\n"
2304 "dup /startlock known\n"
2305 "{/startlock get exec}\n"
2306 "{dup /strtlck known\n"
2307 "{/strtlck get exec}\n"
2308 "{pop 3}\nifelse}\nifelse}\nifelse\n} executeonly\n"
2309 "] ND\n";
2310 memcpy( pOut, aOtherSubrs, sizeof(aOtherSubrs)-1);
2311 pOut += sizeof(aOtherSubrs)-1;
2313 // emit used GlobalSubr charstrings
2314 // these are the just the default subrs
2315 static const char aSubrs[] =
2316 "/Subrs 5 array\n"
2317 "dup 0 15 RD \x5F\x3D\x6B\xAC\x3C\xBD\x74\x3D\x3E\x17\xA0\x86\x58\x08\x85 NP\n"
2318 "dup 1 9 RD \x5F\x3D\x6B\xD8\xA6\xB5\x68\xB6\xA2 NP\n"
2319 "dup 2 9 RD \x5F\x3D\x6B\xAC\x39\x46\xB9\x43\xF9 NP\n"
2320 "dup 3 5 RD \x5F\x3D\x6B\xAC\xB9 NP\n"
2321 "dup 4 12 RD \x5F\x3D\x6B\xAC\x3E\x5D\x48\x54\x62\x76\x39\x03 NP\n"
2322 "ND\n";
2323 memcpy( pOut, aSubrs, sizeof(aSubrs)-1);
2324 pOut += sizeof(aSubrs)-1;
2326 // TODO: emit more GlobalSubr charstrings?
2327 // TODO: emit used LocalSubr charstrings?
2329 // emit the CharStrings for the requested glyphs
2330 pOut += sprintf( pOut,
2331 "2 index /CharStrings %d dict dup begin\n", nGlyphCount);
2332 rEmitter.emitAllCrypted();
2333 for( int i = 0; i < nGlyphCount; ++i) {
2334 const int nGlyphId = pReqGlyphIDs[i];
2335 assert( (nGlyphId >= 0) && (nGlyphId < mnCharStrCount));
2336 // get privdict context matching to the glyph
2337 const int nFDSelect = getFDSelect( nGlyphId);
2338 mpCffLocal = &maCffLocal[ nFDSelect];
2339 // convert the Type2op charstring to its Type1op counterpart
2340 const int nT2Len = seekIndexData( mnCharStrBase, nGlyphId);
2341 assert( nT2Len > 0);
2342 U8 aType1Ops[ MAX_T1OPS_SIZE]; // TODO: dynamic allocation
2343 const int nT1Len = convert2Type1Ops( mpCffLocal, mpReadPtr, nT2Len, aType1Ops);
2344 // get the glyph name
2345 const char* pGlyphName = getGlyphName( nGlyphId);
2346 // emit the encrypted Type1op charstring
2347 pOut += sprintf( pOut, "/%s %d RD ", pGlyphName, nT1Len);
2348 memcpy( pOut, aType1Ops, nT1Len);
2349 pOut += nT1Len;
2350 pOut += sprintf( pOut, " ND\n");
2351 rEmitter.emitAllCrypted();
2352 // provide individual glyphwidths if requested
2353 if( pGlyphWidths )
2354 pGlyphWidths[i] = getCharWidth();
2356 pOut += sprintf( pOut, "end end\nreadonly put\nput\n");
2357 pOut += sprintf( pOut, "dup/FontName get exch definefont pop\n");
2358 pOut += sprintf( pOut, "mark currentfile closefile\n");
2359 rEmitter.emitAllCrypted();
2361 // mark stop of eexec encryption
2362 if( rEmitter.mbPfbSubset) {
2363 const int nEExecLen = rEmitter.tellPos() - nEExecSegTell;
2364 rEmitter.updateLen( nEExecSegTell-4, nEExecLen);
2367 // create PFB footer
2368 static const char aPfxFooter[] = "\x80\x01\x14\x02\x00\x00\n" // TODO: check segment len
2369 "0000000000000000000000000000000000000000000000000000000000000000\n"
2370 "0000000000000000000000000000000000000000000000000000000000000000\n"
2371 "0000000000000000000000000000000000000000000000000000000000000000\n"
2372 "0000000000000000000000000000000000000000000000000000000000000000\n"
2373 "0000000000000000000000000000000000000000000000000000000000000000\n"
2374 "0000000000000000000000000000000000000000000000000000000000000000\n"
2375 "0000000000000000000000000000000000000000000000000000000000000000\n"
2376 "0000000000000000000000000000000000000000000000000000000000000000\n"
2377 "cleartomark\n"
2378 "\x80\x03";
2379 if( rEmitter.mbPfbSubset)
2380 rEmitter.emitRawData( aPfxFooter, sizeof(aPfxFooter)-1);
2381 else
2382 rEmitter.emitRawData( aPfxFooter+6, sizeof(aPfxFooter)-9);
2384 // provide details to the subset requesters, TODO: move into own method?
2385 // note: Top and Bottom are flipped between Type1 and VCL
2386 rFSInfo.m_aFontBBox = Rectangle( Point( maFontBBox[0], maFontBBox[1] ), Point( maFontBBox[2], maFontBBox[3] ) );
2387 // PDF-Spec says the values below mean the ink bounds!
2388 // TODO: use better approximations for these ink bounds
2389 rFSInfo.m_nAscent = +rFSInfo.m_aFontBBox.Bottom(); // for capital letters
2390 rFSInfo.m_nDescent = -rFSInfo.m_aFontBBox.Top(); // for all letters
2391 rFSInfo.m_nCapHeight = rFSInfo.m_nAscent; // for top-flat capital letters
2393 rFSInfo.m_nFontType = rEmitter.mbPfbSubset ? FontSubsetInfo::TYPE1_PFB : FontSubsetInfo::TYPE1_PFA;
2394 rFSInfo.m_aPSName = String( rEmitter.maSubsetName, RTL_TEXTENCODING_UTF8 );
2396 return true;
2399 // ====================================================================
2401 bool FontSubsetInfo::CreateFontSubsetFromCff( GlyphWidth* pOutGlyphWidths )
2403 CffSubsetterContext aCff( mpInFontBytes, mnInByteLength);
2404 aCff.initialCffRead();
2406 // emit Type1 subset from the CFF input
2407 // TODO: also support CFF->CFF subsetting (when PDF-export and PS-printing need it)
2408 const bool bPfbSubset = (0 != (mnReqFontTypeMask & FontSubsetInfo::TYPE1_PFB));
2409 Type1Emitter aType1Emitter( mpOutFile, bPfbSubset);
2410 aType1Emitter.setSubsetName( mpReqFontName);
2411 bool bRC = aCff.emitAsType1( aType1Emitter,
2412 mpReqGlyphIds, mpReqEncodedIds,
2413 pOutGlyphWidths, mnReqGlyphCount, *this);
2414 return bRC;
2417 // ====================================================================