bump product version to 4.1.6.2
[LibreOffice.git] / vcl / source / fontsubset / cff.cxx
blob43e397ca89d4c458c46f7ef39f1d9468282dd7d6
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
21 #include <cstdio>
22 #include <cstring>
23 #include <assert.h>
25 #include <fontsubset.hxx>
27 #include <vcl/strhelper.hxx>
29 //#define IGNORE_HINTS
31 typedef unsigned char U8;
32 typedef unsigned short U16;
33 typedef long long S64;
35 typedef sal_Int32 GlyphWidth;
37 typedef float RealType;
38 typedef RealType ValType;
39 #include <vector>
40 typedef std::vector<ValType> ValVector;
42 // ====================================================================
44 static const char* pStringIds[] = {
45 /*0*/ ".notdef", "space", "exclam", "quotedbl",
46 "numbersign", "dollar", "percent", "ampersand",
47 "quoteright", "parenleft", "parenright", "asterisk",
48 "plus", "comma", "hyphen", "period",
49 /*16*/ "slash", "zero", "one", "two",
50 "three", "four", "five", "six",
51 "seven", "eight", "nine", "colon",
52 "semicolon", "less", "equal", "greater",
53 /*32*/ "question", "at", "A", "B",
54 "C", "D", "E", "F",
55 "G", "H", "I", "J",
56 "K", "L", "M", "N",
57 /*48*/ "O", "P", "Q", "R",
58 "S", "T", "U", "V",
59 "W", "X", "Y", "Z",
60 "bracketleft", "backslash", "bracketright", "asciicircum",
61 /*64*/ "underscore", "quoteleft", "a", "b",
62 "c", "d", "e", "f",
63 "g", "h", "i", "j",
64 "k", "l", "m", "n",
65 /*80*/ "o", "p", "q", "r",
66 "s", "t", "u", "v",
67 "w", "x", "y", "z",
68 "braceleft", "bar", "braceright", "asciitilde",
69 /*96*/ "exclamdown", "cent", "sterlin", "fraction",
70 "yen", "florin", "section", "currency",
71 "quotesingle", "quotedblleft", "guillemotleft", "guilsinglleft",
72 "guilsinglright", "fi", "fl", "endash",
73 /*112*/ "dagger", "daggerdbl", "periodcentered", "paragraph",
74 "bullet", "quotesinglbase", "quotedblbase", "quotedblright",
75 "guillemotright", "ellipsis", "perthousand", "questiondown",
76 "grave", "acute", "circumflex", "tilde",
77 /*128*/ "macron", "breve", "dotaccent", "dieresis",
78 "ring", "cedilla", "hungarumlaut", "ogonek",
79 "caron", "emdash", "AE", "ordfeminine",
80 "Lslash", "Oslash", "OE", "ordmasculine",
81 /*144*/ "ae", "dotlessi", "lslash", "oslash",
82 "oe", "germandbls", "onesuperior", "logicalnot",
83 "mu", "trademark", "Eth", "onehalf",
84 "plusminus", "Thorn", "onequarter", "divide",
85 /*160*/ "brokenbar", "degree", "thorn", "threequarters",
86 "twosuperior", "registered", "minus", "eth",
87 "multiply", "threesuperior", "copyright", "Aacute",
88 "Acircumflex", "Adieresis", "Agrave", "Aring",
89 /*176*/ "Atilde", "Ccedilla", "Eacute", "Ecircumflex",
90 "Edieresis", "Egrave", "Iacute", "Icircumflex",
91 "Idieresis", "Igrave", "Ntilde", "Oacute",
92 "Ocircumflex", "Odieresis", "Ograve", "Otilde",
93 /*192*/ "Scaron", "Uacute", "Ucircumflex", "Udieresis",
94 "Ugrave", "Yacute", "Ydieresis", "Zcaron",
95 "aacute", "acircumflex", "adieresis", "agrave",
96 "aring", "atilde", "ccedilla", "eacute",
97 /*208*/ "ecircumflex", "edieresis", "egrave", "iacute",
98 "icircumflex", "idieresis", "igrave", "ntilde",
99 "oacute", "ocircumflex", "odieresis", "ograve",
100 "otilde", "scaron", "uacute", "ucircumflex",
101 /*224*/ "udieresis", "ugrave", "yacute", "ydieresis",
102 "zcaron", "exclamsmall", "Hungarumlautsmall","dollaroldstyle",
103 "dollarsuperior", "ampersandsmall", "Acutesmall", "parenleftsuperior",
104 "parenrightsuperior","twodotenleader", "onedotenleader", "zerooldstyle",
105 /*240*/ "oneoldstyle", "twooldstyle", "threeoldstyle", "fouroldstyle",
106 "fiveoldstyle", "sixoldstyle", "sevenoldstyle", "eightoldstyle",
107 "nineoldstile", "commasuperior", "threequartersemdash","periodsuperior",
108 "questionsmall", "asuperior", "bsuperior", "centsuperior",
109 /*256*/ "dsuperior", "esuperior", "isuperior", "lsuperior",
110 "msuperior", "nsuperior", "osuperior", "rsuperior",
111 "ssuperior", "tsuperior", "ff", "ffi",
112 "ffl", "parenleftinferior","parenrightinferior","Circumflexsmall",
113 /*272*/ "hyphensuperior","Gravesmall", "Asmall", "Bsmall",
114 "Csmall", "Dsmall", "Esmall", "Fsmall",
115 "Gsmall", "Hsmall", "Ismall", "Jsmall",
116 "Ksmall", "Lsmall", "Msmall", "Nsmall",
117 /*288*/ "Osmall", "Psmall", "Qsmall", "Rsmall",
118 "Ssmall", "Tsmall", "Usmall", "Vsmall",
119 "Wsmall", "Xsmall", "Ysmall", "Zsmall",
120 "colonmonetary", "onefitted", "rupia", "Tildesmall",
121 /*304*/ "exclamdownsmall","centoldstyle", "Lslashsmall", "Scaronsmall",
122 "Zcaronsmall", "Dieresissmall", "Brevesmall", "Caronsmall",
123 "Dotaccentsmall", "Macronsmall", "figuredash", "hypheninferior",
124 "Ogoneksmall", "Ringsmall", "Cedillasmall", "questiondownsmall",
125 /*320*/ "oneeight", "threeeights", "fiveeights", "seveneights",
126 "onethird", "twothirds", "zerosuperior", "foursuperior",
127 "fivesuperior", "sixsuperior", "sevensuperior", "eightsuperior",
128 "ninesuperior", "zeroinferior", "oneinferior", "twoinferior",
129 /*336*/ "threeinferior","fourinferior", "fiveinferior", "sixinferior",
130 "seveninferior", "eightinferior", "nineinferior", "centinferior",
131 "dollarinferior", "periodinferior", "commainferior", "Agravesmall",
132 "Aacutesmall", "Acircumflexsmall", "Atildesmall", "Adieresissmall",
133 /*352*/ "Aringsmall", "AEsmall", "Ccedillasmall", "Egravesmall",
134 "Eacutesmall", "Ecircumflexsmall", "Edieresissmall", "Igravesmall",
135 "Iacutesmall", "Icircumflexsmall", "Idieresissmall", "Ethsmall",
136 "Ntildesmall", "Ogravesmall", "Oacutesmall", "Ocircumflexsmall",
137 /*368*/ "Otildesmall", "Odieressissmall", "OEsmall", "Oslashsmall",
138 "Ugravesmall", "Uacutesmall", "Ucircumflexsmall", "Udieresissmall",
139 "Yacutesmall", "Thornsmall", "Ydieresissmall", "001.000",
140 "001.001", "001.002", "001.003", "Black",
141 /*384*/ "Bold", "Book", "Light", "Medium",
142 "Regular", "Roman", "Semibold"
145 // --------------------------------------------------------------------
147 // --------------------------------------------------------------------
149 // TOP DICT keywords (also covers PRIV DICT keywords)
150 static const char* pDictOps[] = {
151 "sVersion", "sNotice", "sFullName", "sFamilyName",
152 "sWeight", "aFontBBox", "dBlueValues", "dOtherBlues",
153 "dFamilyBlues", "dFamilyOtherBlues", "nStdHW", "nStdVW",
154 "xESC", "nUniqueID", "aXUID", "nCharset",
155 "nEncoding", "nCharStrings", "PPrivate", "nSubrs",
156 "nDefaultWidthX", "nNominalWidthX", NULL, NULL,
157 NULL, NULL, NULL, NULL,
158 "shortint", "longint", "BCD", NULL
161 // --------------------------------------------------------------------
163 // TOP DICT escapes (also covers PRIV DICT escapes)
164 static const char* pDictEscs[] = {
165 "sCopyright", "bIsFixedPitch", "nItalicAngle", "nUnderlinePosition",
166 "nUnderlineThickness", "nPaintType", "tCharstringType", "aFontMatrix",
167 "nStrokeWidth", "nBlueScale", "nBlueShift", "nBlueFuzz",
168 "dStemSnapH", "dStemSnapV", "bForceBold", NULL,
169 NULL, "nLanguageGroup", "nExpansionFactor", "nInitialRandomSeed",
170 "nSyntheticBase", "sPostScript", "sBaseFontName", "dBaseFontBlend",
171 NULL, NULL, NULL, NULL,
172 NULL, NULL, "rROS", "nCIDFontVersion",
173 "nCIDFontRevision", "nCIDFontType", "nCIDCount", "nUIDBase",
174 "nFDArray", "nFDSelect", "sFontName"
177 // --------------------------------------------------------------------
179 static const char* pType1Ops[] = {
180 NULL, "2hstem", NULL, "2vstem",
181 "1vmoveto", "Arlineto", "1hlineto", "1vlineto",
182 "Crrcurveto", "0closepath", "Lcallsubr", "0return",
183 "xT1ESC", "2hsbw", "0endchar", NULL,
184 NULL, NULL, NULL, NULL,
185 NULL, "2rmoveto", "1hmoveto", NULL,
186 NULL, NULL, NULL, NULL,
187 NULL, NULL, "4vhcurveto", "4hvcurveto"
190 // --------------------------------------------------------------------
192 static const char* pT1EscOps[] = {
193 "0dotsection", "6vstem3", "6hstem3", NULL,
194 NULL, NULL, "5seac", "4sbw",
195 NULL, "1abs", "2add", "2sub",
196 "2div", NULL, NULL, NULL,
197 "Gcallothersubr", "1pop", NULL, NULL,
198 NULL, NULL, NULL, NULL,
199 NULL, NULL, NULL, NULL,
200 NULL, NULL, NULL, NULL,
201 NULL, "2setcurrentpoint"
204 // --------------------------------------------------------------------
206 struct TYPE1OP
208 enum OPS
210 HSTEM=1, VSTEM=3, VMOVETO=4, RLINETO=5,
211 HLINETO=6, VLINETO=7, RCURVETO=8, CLOSEPATH=9,
212 CALLSUBR=10, RETURN=11, T1ESC=12, HSBW=13,
213 ENDCHAR=14, RMOVETO=21, HMOVETO=22, VHCURVETO=30,
214 HVCURVETO=31
217 enum ESCS
219 DOTSECTION=0, VSTEM3=1, HSTEM3=2, SEAC=6,
220 SBW=7, ABS=9, ADD=10, SUB=11,
221 DIV=12, CALLOTHERSUBR=16, POP=17, SETCURRENTPOINT=33
225 // --------------------------------------------------------------------
227 static const char* pType2Ops[] = {
228 NULL, "hhstem", NULL, "vvstem",
229 "mvmoveto", "Arlineto", "Ehlineto", "Evlineto",
230 "Crrcurveto", NULL, "Lcallsubr", "Xreturn",
231 "xT2ESC", NULL, "eendchar", NULL,
232 NULL, NULL, "Hhstemhm", "Khintmask",
233 "Kcntrmask", "Mrmoveto", "mhmoveto", "Vvstemhm",
234 ".rcurveline", ".rlinecurve", ".vvcurveto", ".hhcurveto",
235 ".shortint", "Gcallgsubr", ".vhcurveto", ".hvcurveto"
238 // --------------------------------------------------------------------
240 static const char* pT2EscOps[] = {
241 NULL, NULL, NULL, "2and",
242 "2or", "1not", NULL, NULL,
243 NULL, "1abs", "2add", "2sub",
244 "2div", NULL, "1neg", "2eq",
245 NULL, NULL, "1drop", NULL,
246 "1put", "1get", "4ifelse", "0random",
247 "2mul", NULL, "1sqrt", "1dup",
248 "2exch", "Iindex", "Rroll", NULL,
249 NULL, NULL, "7hflex", "Fflex",
250 "9hflex1", "fflex1"
253 // --------------------------------------------------------------------
255 struct TYPE2OP
257 enum OPS
259 HSTEM=1, VSTEM=3, VMOVETO=4, RLINETO=5,
260 HLINETO=6, VLINETO=7, RCURVETO=8, CALLSUBR=10,
261 RETURN=11, T2ESC=12, ENDCHAR=14, HSTEMHM=18,
262 HINTMASK=19, CNTRMASK=20, RMOVETO=21, HMOVETO=22,
263 VSTEMHM=23, RCURVELINE=24, RLINECURVE=25, VVCURVETO=26,
264 HHCURVETO=27, SHORTINT=28, CALLGSUBR=29, VHCURVETO=30,
265 HVCURVETO=31
268 enum ESCS
270 AND=3, OR=4, NOT=5, ABS=9,
271 ADD=10, SUB=11, DIV=12, NEG=14,
272 EQ=15, DROP=18, PUT=20, GET=21,
273 IFELSE=22, RANDOM=23, MUL=24, SQRT=26,
274 DUP=27, EXCH=28, INDEX=29, ROLL=30,
275 HFLEX=34, FLEX=35, HFLEX1=36, FLEX1=37
279 // ====================================================================
281 struct CffGlobal
283 explicit CffGlobal();
285 int mnNameIdxBase;
286 int mnNameIdxCount;
287 int mnStringIdxBase;
288 int mnStringIdxCount;
289 bool mbCIDFont;
290 int mnCharStrBase;
291 int mnCharStrCount;
292 int mnEncodingBase;
293 int mnCharsetBase;
294 int mnGlobalSubrBase;
295 int mnGlobalSubrCount;
296 int mnGlobalSubrBias;
297 int mnFDSelectBase;
298 int mnFontDictBase;
299 int mnFDAryCount;
301 ValVector maFontBBox;
302 ValVector maFontMatrix;
304 int mnFontNameSID;
305 int mnFullNameSID;
306 int mnFamilyNameSID;
309 // ====================================================================
311 struct CffLocal
313 explicit CffLocal();
315 int mnPrivDictBase;
316 int mnPrivDictSize;
317 int mnLocalSubrOffs;
318 int mnLocalSubrBase;
319 int mnLocalSubrCount;
320 int mnLocalSubrBias;
322 ValType maNominalWidth;
323 ValType maDefaultWidth;
325 // ATM hinting related values
326 ValType maStemStdHW;
327 ValType maStemStdVW;
328 ValVector maStemSnapH;
329 ValVector maStemSnapV;
330 ValVector maBlueValues;
331 ValVector maOtherBlues;
332 ValVector maFamilyBlues;
333 ValVector maFamilyOtherBlues;
334 RealType mfBlueScale;
335 RealType mfBlueShift;
336 RealType mfBlueFuzz;
337 RealType mfExpFactor;
338 int mnLangGroup;
339 bool mbForceBold;
342 // ====================================================================
344 class SubsetterContext
346 public:
347 virtual ~SubsetterContext( void);
348 virtual bool emitAsType1( class Type1Emitter&,
349 const long* pGlyphIDs, const U8* pEncoding,
350 GlyphWidth* pGlyphWidths, int nGlyphCount, FontSubsetInfo& ) = 0;
353 // --------------------------------------------------------------------
355 SubsetterContext::~SubsetterContext( void)
358 // ====================================================================
360 class CffSubsetterContext
361 : public SubsetterContext
362 , private CffGlobal
364 public:
365 static const int NMAXSTACK = 48; // see CFF.appendixB
366 static const int NMAXHINTS = 2*96; // see CFF.appendixB
367 static const int NMAXTRANS = 32; // see CFF.appendixB
368 public:
369 explicit CffSubsetterContext( const U8* pBasePtr, int nBaseLen);
370 virtual ~CffSubsetterContext( void);
372 void initialCffRead( void);
373 bool emitAsType1( class Type1Emitter&,
374 const long* pGlyphIDs, const U8* pEncoding,
375 GlyphWidth* pGlyphWidths, int nGlyphCount, FontSubsetInfo& );
377 // used by charstring converter
378 void setCharStringType( int);
379 void fakeLocalSubrCount( int nLocalSubrs ) { maCffLocal[0].mnLocalSubrCount=nLocalSubrs;}
380 protected:
381 int convert2Type1Ops( CffLocal*, const U8* pType2Ops, int nType2Len, U8* pType1Ops);
382 private:
383 void convertOneTypeOp( void);
384 void convertOneTypeEsc( void);
385 void callType2Subr( bool bGlobal, int nSubrNumber);
386 long getReadOfs( void) const { return (long)(mpReadPtr - mpBasePtr);}
388 const U8* mpBasePtr;
389 const U8* mpBaseEnd;
391 const U8* mpReadPtr;
392 const U8* mpReadEnd;
394 U8* mpWritePtr;
395 bool mbSawError;
396 bool mbNeedClose;
397 bool mbIgnoreHints;
398 long mnCntrMask;
400 private:
401 int seekIndexData( int nIndexBase, int nDataIndex);
402 void seekIndexEnd( int nIndexBase);
404 private:
405 const char** mpCharStringOps;
406 const char** mpCharStringEscs;
408 CffLocal maCffLocal[16];
409 CffLocal* mpCffLocal;
411 void readDictOp( void);
412 RealType readRealVal( void);
413 const char* getString( int nStringID);
414 int getFDSelect( int nGlyphIndex) const;
415 int getGlyphSID( int nGlyphIndex) const;
416 const char* getGlyphName( int nGlyphIndex);
418 void read2push( void);
419 void pop2write( void);
420 void writeType1Val( ValType);
421 void writeTypeOp( int nTypeOp);
422 void writeTypeEsc( int nTypeOp);
423 void writeCurveTo( int nStackPos, int nIX1, int nIY1, int nIX2, int nIY2, int nIX3, int nIY3);
424 void pop2MultiWrite( int nArgsPerTypo, int nTypeOp, int nTypeXor=0);
425 void popAll2Write( int nTypeOp);
427 public: // TODO: is public really needed?
428 // accessing the value stack
429 // TODO: add more checks
430 void push( ValType nVal) { mnValStack[ mnStackIdx++] = nVal;}
431 ValType popVal( void) { return ((mnStackIdx>0) ? mnValStack[ --mnStackIdx] : 0);}
432 ValType peekVal( void) const { return ((mnStackIdx>0) ? mnValStack[ mnStackIdx-1] : 0);}
433 ValType getVal( int nIndex) const { return mnValStack[ nIndex];}
434 int popInt( void);
435 int peekInt( void) const;
436 int getInt( int nIndex) const;
437 int size( void) const { return mnStackIdx;}
438 bool empty( void) const { return !mnStackIdx;}
439 void clear( void) { mnStackIdx = 0;}
441 // accessing the charstring hints
442 void addHints( bool bVerticalHints);
443 int getHorzHintCount( void) const { return (mnHorzHintSize/2);}
444 int getVertHintCount( void) const { return (mnHintSize-mnHorzHintSize)/2;}
446 // accessing other charstring specifics
447 bool hasCharWidth( void) const { return (maCharWidth > 0);}
448 ValType getCharWidth( void) const { return maCharWidth;}
449 void setNominalWidth( ValType aWidth) { mpCffLocal->maNominalWidth = aWidth;}
450 void setDefaultWidth( ValType aWidth) { mpCffLocal->maDefaultWidth = aWidth;}
451 void updateWidth( bool bUseFirstVal);
453 private:
454 // typeop exceution context
455 int mnStackIdx;
456 ValType mnValStack[ NMAXSTACK+4];
457 ValType mnTransVals[ NMAXTRANS];
459 int mnHintSize;
460 int mnHorzHintSize;
461 ValType mnHintStack[ NMAXHINTS];
463 ValType maCharWidth;
466 // --------------------------------------------------------------------
468 CffSubsetterContext::CffSubsetterContext( const U8* pBasePtr, int nBaseLen)
469 : mpBasePtr( pBasePtr)
470 , mpBaseEnd( pBasePtr+nBaseLen)
471 , mnStackIdx(0)
472 , mnHintSize(0)
473 , mnHorzHintSize(0)
474 , maCharWidth(-1)
476 // setCharStringType( 1);
477 // TODO: new CffLocal[ mnFDAryCount];
478 mpCffLocal = &maCffLocal[0];
481 // --------------------------------------------------------------------
483 CffSubsetterContext::~CffSubsetterContext( void)
485 // TODO: delete[] maCffLocal;
488 // --------------------------------------------------------------------
490 inline int CffSubsetterContext::popInt( void)
492 const ValType aVal = popVal();
493 const int nInt = static_cast<int>(aVal);
494 assert( nInt == aVal);
495 return nInt;
498 // --------------------------------------------------------------------
500 inline int CffSubsetterContext::peekInt( void) const
502 const ValType aVal = peekVal();
503 const int nInt = static_cast<int>(aVal);
504 assert( nInt == aVal);
505 return nInt;
508 // --------------------------------------------------------------------
510 inline int CffSubsetterContext::getInt( int nIndex) const
512 const ValType aVal = getVal( nIndex);
513 const int nInt = static_cast<int>(aVal);
514 assert( nInt == aVal);
515 return nInt;
518 // --------------------------------------------------------------------
520 inline void CffSubsetterContext::updateWidth( bool bUseFirstVal)
522 #if 1 // TODO: is this still needed?
523 // the first value is not a hint but the charwidth
524 if( hasCharWidth())
525 return;
526 #endif
527 if( bUseFirstVal) {
528 maCharWidth = mpCffLocal->maNominalWidth + mnValStack[0];
529 // remove bottom stack entry
530 --mnStackIdx;
531 for( int i = 0; i < mnStackIdx; ++i)
532 mnValStack[ i] = mnValStack[ i+1];
533 } else {
534 maCharWidth = mpCffLocal->maDefaultWidth;
538 // --------------------------------------------------------------------
540 void CffSubsetterContext::addHints( bool bVerticalHints)
542 // the first charstring value may a charwidth instead of a charwidth
543 updateWidth( (mnStackIdx & 1) != 0);
544 // return early (e.g. no implicit hints for hintmask)
545 if( !mnStackIdx)
546 return;
548 // copy the remaining values to the hint arrays
549 // assert( (mnStackIdx & 1) == 0); // depends on called subrs
550 if( mnStackIdx & 1) --mnStackIdx;//#######
551 // TODO: if( !bSubr) assert( mnStackIdx >= 2);
553 assert( (mnHintSize + mnStackIdx) <= 2*NMAXHINTS);
555 #ifdef IGNORE_HINTS
556 mnHintSize += mnStackIdx;
557 #else
558 ValType nHintOfs = 0;
559 for( int i = 0; i < mnStackIdx; ++i) {
560 nHintOfs += mnValStack[ i ];
561 mnHintStack[ mnHintSize++] = nHintOfs;
563 #endif // IGNORE_HINTS
564 if( !bVerticalHints)
565 mnHorzHintSize = mnHintSize;
567 // clear all values from the stack
568 mnStackIdx = 0;
571 // --------------------------------------------------------------------
573 void CffSubsetterContext::setCharStringType( int nVal)
575 switch( nVal) {
576 case 1: mpCharStringOps=pType1Ops; mpCharStringEscs=pT1EscOps; break;
577 case 2: mpCharStringOps=pType2Ops; mpCharStringEscs=pT2EscOps; break;
578 default: fprintf( stderr, "Unknown CharstringType=%d\n",nVal); break;
582 // --------------------------------------------------------------------
584 void CffSubsetterContext::readDictOp( void)
586 ValType nVal = 0;
587 const U8 c = *mpReadPtr;
588 if( c <= 21 ) {
589 int nOpId = *(mpReadPtr++);
590 const char* pCmdName = 0;
591 if( nOpId != 12)
592 pCmdName = pDictOps[nOpId];
593 else {
594 const U8 nExtId = *(mpReadPtr++);
595 if (nExtId < 39)
596 pCmdName = pDictEscs[nExtId];
597 nOpId = 900 + nExtId;
600 if (!pCmdName) // skip reserved operators
601 return;
603 //TODO: if( nStackIdx > 0)
604 int nInt = 0;
605 switch( *pCmdName) {
606 default: fprintf( stderr, "unsupported DictOp.type=\'%c\'\n", *pCmdName); break;
607 case 'b': // bool
608 nInt = popInt();
609 switch( nOpId) {
610 case 915: mpCffLocal->mbForceBold = nInt; break; // "ForceBold"
611 default: break; // TODO: handle more boolean dictops?
613 break;
614 case 'n': // dict-op number
615 nVal = popVal();
616 nInt = static_cast<int>(nVal);
617 switch( nOpId) {
618 case 10: mpCffLocal->maStemStdHW = nVal; break; // "StdHW"
619 case 11: mpCffLocal->maStemStdVW = nVal; break; // "StdVW"
620 case 15: mnCharsetBase = nInt; break; // "charset"
621 case 16: mnEncodingBase = nInt; break; // "nEncoding"
622 case 17: mnCharStrBase = nInt; break; // "nCharStrings"
623 case 19: mpCffLocal->mnLocalSubrOffs = nInt; break;// "nSubrs"
624 case 20: setDefaultWidth( nVal ); break; // "defaultWidthX"
625 case 21: setNominalWidth( nVal ); break; // "nominalWidthX"
626 case 909: mpCffLocal->mfBlueScale = nVal; break; // "BlueScale"
627 case 910: mpCffLocal->mfBlueShift = nVal; break; // "BlueShift"
628 case 911: mpCffLocal->mfBlueFuzz = nVal; break; // "BlueFuzz"
629 case 912: mpCffLocal->mfExpFactor = nVal; break; // "ExpansionFactor"
630 case 917: mpCffLocal->mnLangGroup = nInt; break; // "LanguageGroup"
631 case 936: mnFontDictBase = nInt; break; // "nFDArray"
632 case 937: mnFDSelectBase = nInt; break; // "nFDSelect"
633 default: break; // TODO: handle more numeric dictops?
635 break;
636 case 'a': { // array
637 switch( nOpId) {
638 case 5: maFontBBox.clear(); break; // "FontBBox"
639 case 907: maFontMatrix.clear(); break; // "FontMatrix"
640 default: break; // TODO: reset other arrays?
642 for( int i = 0; i < size(); ++i ) {
643 nVal = getVal(i);
644 switch( nOpId) {
645 case 5: maFontBBox.push_back( nVal); break; // "FontBBox"
646 case 907: maFontMatrix.push_back( nVal); break; // "FontMatrix"
647 default: break; // TODO: handle more array dictops?
650 clear();
651 } break;
652 case 'd': { // delta array
653 nVal = 0;
654 for( int i = 0; i < size(); ++i ) {
655 nVal += getVal(i);
656 switch( nOpId) {
657 case 6: mpCffLocal->maBlueValues.push_back( nVal); break; // "BlueValues"
658 case 7: mpCffLocal->maOtherBlues.push_back( nVal); break; // "OtherBlues"
659 case 8: mpCffLocal->maFamilyBlues.push_back( nVal); break; // "FamilyBlues"
660 case 9: mpCffLocal->maFamilyOtherBlues.push_back( nVal); break;// "FamilyOtherBlues"
661 case 912: mpCffLocal->maStemSnapH.push_back( nVal); break; // "StemSnapH"
662 case 913: mpCffLocal->maStemSnapV.push_back( nVal); break; // "StemSnapV"
663 default: break; // TODO: handle more delta-array dictops?
666 clear();
667 } break;
668 case 's': // stringid (SID)
669 nInt = popInt();
670 switch( nOpId ) {
671 case 2: mnFullNameSID = nInt; break; // "FullName"
672 case 3: mnFamilyNameSID = nInt; break; // "FamilyName"
673 case 938: mnFontNameSID = nInt; break; // "FontName"
674 default: break; // TODO: handle more string dictops?
676 break;
677 case 'P': // private dict
678 mpCffLocal->mnPrivDictBase = popInt();
679 mpCffLocal->mnPrivDictSize = popInt();
680 break;
681 case 'r': { // ROS operands
682 int nSid1 = popInt();
683 int nSid2 = popInt();
684 (void)nSid1; // TODO: use
685 (void)nSid2; // TODO: use
686 nVal = popVal();
687 mbCIDFont = true;
688 } break;
689 case 't': // CharstringType
690 nInt = popInt();
691 setCharStringType( nInt );
692 break;
695 return;
698 if( (c >= 32) || (c == 28) ) {
699 // --mpReadPtr;
700 read2push();
701 } else if( c == 29 ) { // longint
702 ++mpReadPtr; // skip 29
703 int nS32 = mpReadPtr[0] << 24;
704 nS32 += mpReadPtr[1] << 16;
705 nS32 += mpReadPtr[2] << 8;
706 nS32 += mpReadPtr[3] << 0;
707 if( (sizeof(nS32) != 4) && (nS32 & (1<<31)))
708 nS32 |= (~0U) << 31; // assuming 2s complement
709 mpReadPtr += 4;
710 nVal = static_cast<ValType>(nS32);
711 push( nVal );
712 } else if( c == 30) { // real number
713 ++mpReadPtr; // skip 30
714 const RealType fReal = readRealVal();
715 // push value onto stack
716 nVal = fReal;
717 push( nVal);
721 // --------------------------------------------------------------------
723 void CffSubsetterContext::read2push()
725 ValType aVal = 0;
727 const U8*& p = mpReadPtr;
728 const U8 c = *p;
729 if( c == 28 ) {
730 short nS16 = (p[1] << 8) + p[2];
731 if( (sizeof(nS16) != 2) && (nS16 & (1<<15)))
732 nS16 |= (~0U) << 15; // assuming 2s complement
733 aVal = nS16;
734 p += 3;
735 } else if( c <= 246 ) { // -107..+107
736 aVal = static_cast<ValType>(p[0] - 139);
737 p += 1;
738 } else if( c <= 250 ) { // +108..+1131
739 aVal = static_cast<ValType>(((p[0] << 8) + p[1]) - 63124);
740 p += 2;
741 } else if( c <= 254 ) { // -108..-1131
742 aVal = static_cast<ValType>(64148 - ((p[0] << 8) + p[1]));
743 p += 2;
744 } else /*if( c == 255)*/ { // Fixed16.16
745 int nS32 = (p[1] << 24) + (p[2] << 16) + (p[3] << 8) + p[4];
746 if( (sizeof(nS32) != 2) && (nS32 & (1<<31)))
747 nS32 |= (~0U) << 31; // assuming 2s complement
748 aVal = static_cast<ValType>(nS32 * (1.0 / 0x10000));
749 p += 5;
752 push( aVal);
755 // --------------------------------------------------------------------
757 void CffSubsetterContext::writeType1Val( ValType aVal)
759 U8* pOut = mpWritePtr;
761 int nInt = static_cast<int>(aVal);
762 static const int nOutCharstrType = 1;
763 if( (nInt != aVal) && (nOutCharstrType == 2)) {
764 // numtype==255 means int32 for Type1, but 16.16 for Type2 charstrings!!!
765 *(pOut++) = 255; // Fixed 16.16
766 *(pOut++) = static_cast<U8>(nInt >> 8);
767 *(pOut++) = static_cast<U8>(nInt);
768 nInt = static_cast<int>(aVal * 0x10000) & 0xFFFF;
769 *(pOut++) = static_cast<U8>(nInt >> 8);
770 *(pOut++) = static_cast<U8>(nInt);
771 } else if( (nInt >= -107) && (nInt <= +107)) {
772 *(pOut++) = static_cast<U8>(nInt + 139); // -107..+107
773 } else if( (nInt >= -1131) && (nInt <= +1131)) {
774 if( nInt >= 0)
775 nInt += 63124; // +108..+1131
776 else
777 nInt = 64148 - nInt; // -108..-1131
778 *(pOut++) = static_cast<U8>(nInt >> 8);
779 *(pOut++) = static_cast<U8>(nInt);
780 } else if( nOutCharstrType == 1) {
781 // numtype==255 means int32 for Type1, but 16.16 for Type2 charstrings!!!
782 *(pOut++) = 255;
783 *(pOut++) = static_cast<U8>(nInt >> 24);
784 *(pOut++) = static_cast<U8>(nInt >> 16);
785 *(pOut++) = static_cast<U8>(nInt >> 8);
786 *(pOut++) = static_cast<U8>(nInt);
789 mpWritePtr = pOut;
792 // --------------------------------------------------------------------
794 inline void CffSubsetterContext::pop2write( void)
796 const ValType aVal = popVal();
797 writeType1Val( aVal);
800 // --------------------------------------------------------------------
802 inline void CffSubsetterContext::writeTypeOp( int nTypeOp)
804 *(mpWritePtr++) = static_cast<U8>(nTypeOp);
807 // --------------------------------------------------------------------
809 inline void CffSubsetterContext::writeTypeEsc( int nTypeEsc)
811 *(mpWritePtr++) = TYPE1OP::T1ESC;
812 *(mpWritePtr++) = static_cast<U8>(nTypeEsc);
815 // --------------------------------------------------------------------
817 void CffSubsetterContext::pop2MultiWrite( int nArgsPerTypo, int nTypeOp, int nTypeXor)
819 for( int i = 0; i < mnStackIdx;) {
820 for( int j = 0; j < nArgsPerTypo; ++j) {
821 const ValType aVal = mnValStack[i+j];
822 writeType1Val( aVal);
824 i += nArgsPerTypo;
825 writeTypeOp( nTypeOp);
826 nTypeOp ^= nTypeXor; // for toggling vlineto/hlineto
828 clear();
831 // --------------------------------------------------------------------
833 void CffSubsetterContext::popAll2Write( int nTypeOp)
835 // pop in reverse order, then write
836 for( int i = 0; i < mnStackIdx; ++i) {
837 const ValType aVal = mnValStack[i];
838 writeType1Val( aVal);
840 clear();
841 writeTypeOp( nTypeOp);
844 // --------------------------------------------------------------------
846 void CffSubsetterContext::writeCurveTo( int nStackPos,
847 int nIX1, int nIY1, int nIX2, int nIY2, int nIX3, int nIY3)
849 // get the values from the stack
850 const ValType nDX1 = nIX1 ? mnValStack[ nStackPos+nIX1 ] : 0;
851 const ValType nDY1 = nIY1 ? mnValStack[ nStackPos+nIY1 ] : 0;
852 const ValType nDX2 = nIX2 ? mnValStack[ nStackPos+nIX2 ] : 0;
853 const ValType nDY2 = nIY2 ? mnValStack[ nStackPos+nIY2 ] : 0;
854 const ValType nDX3 = nIX3 ? mnValStack[ nStackPos+nIX3 ] : 0;
855 const ValType nDY3 = nIY3 ? mnValStack[ nStackPos+nIY3 ] : 0;
857 // emit the curveto operator and operands
858 // TODO: determine the most efficient curveto operator
859 // TODO: depending on type1op or type2op target
860 writeType1Val( nDX1 );
861 writeType1Val( nDY1 );
862 writeType1Val( nDX2 );
863 writeType1Val( nDY2 );
864 writeType1Val( nDX3 );
865 writeType1Val( nDY3 );
866 writeTypeOp( TYPE1OP::RCURVETO );
869 // --------------------------------------------------------------------
871 void CffSubsetterContext::convertOneTypeOp( void)
873 const int nType2Op = *(mpReadPtr++);
875 int i, nInt; // prevent WAE for declarations inside switch cases
876 // convert each T2op
877 switch( nType2Op) {
878 case TYPE2OP::T2ESC:
879 convertOneTypeEsc();
880 break;
881 case TYPE2OP::HSTEM:
882 case TYPE2OP::VSTEM:
883 addHints( nType2Op == TYPE2OP::VSTEM );
884 #ifndef IGNORE_HINTS
885 for( i = 0; i < mnHintSize; i+=2 ) {
886 writeType1Val( mnHintStack[i]);
887 writeType1Val( mnHintStack[i+1] - mnHintStack[i]);
888 writeTypeOp( nType2Op );
890 #endif // IGNORE_HINTS
891 break;
892 case TYPE2OP::HSTEMHM:
893 case TYPE2OP::VSTEMHM:
894 addHints( nType2Op == TYPE2OP::VSTEMHM);
895 break;
896 case TYPE2OP::CNTRMASK:
897 // TODO: replace cntrmask with vstem3/hstem3
898 addHints( true);
899 #ifdef IGNORE_HINTS
900 mpReadPtr += (mnHintSize + 15) / 16;
901 mbIgnoreHints = true;
902 #else
904 U8 nMaskBit = 0;
905 U8 nMaskByte = 0;
906 for( i = 0; i < mnHintSize; i+=2, nMaskBit>>=1) {
907 if( !nMaskBit) {
908 nMaskByte = *(mpReadPtr++);
909 nMaskBit = 0x80;
911 if( !(nMaskByte & nMaskBit))
912 continue;
913 if( i >= 8*(int)sizeof(mnCntrMask))
914 mbIgnoreHints = true;
915 if( mbIgnoreHints)
916 continue;
917 mnCntrMask |= (1U << i);
920 #endif
921 break;
922 case TYPE2OP::HINTMASK:
923 addHints( true);
924 #ifdef IGNORE_HINTS
925 mpReadPtr += (mnHintSize + 15) / 16;
926 #else
928 long nHintMask = 0;
929 int nCntrBits[2] = {0,0};
930 U8 nMaskBit = 0;
931 U8 nMaskByte = 0;
932 for( i = 0; i < mnHintSize; i+=2, nMaskBit>>=1) {
933 if( !nMaskBit) {
934 nMaskByte = *(mpReadPtr++);
935 nMaskBit = 0x80;
937 if( !(nMaskByte & nMaskBit))
938 continue;
939 if( i >= 8*(int)sizeof(nHintMask))
940 mbIgnoreHints = true;
941 if( mbIgnoreHints)
942 continue;
943 nHintMask |= (1U << i);
944 nCntrBits[ i < mnHorzHintSize] += (mnCntrMask >> i) & 1;
947 mbIgnoreHints |= (nCntrBits[0] && (nCntrBits[0] != 3));
948 mbIgnoreHints |= (nCntrBits[1] && (nCntrBits[1] != 3));
949 if( mbIgnoreHints)
950 break;
952 for( i = 0; i < mnHintSize; i+=2) {
953 if( !(nHintMask & (1U << i)))
954 continue;
955 writeType1Val( mnHintStack[i]);
956 writeType1Val( mnHintStack[i+1] - mnHintStack[i]);
957 const bool bHorz = (i < mnHorzHintSize);
958 if( !nCntrBits[ bHorz])
959 writeTypeOp( bHorz ? TYPE1OP::HSTEM : TYPE1OP::VSTEM);
960 else if( !--nCntrBits[ bHorz])
961 writeTypeEsc( bHorz ? TYPE1OP::HSTEM3 : TYPE1OP::VSTEM3);
964 #endif
965 break;
966 case TYPE2OP::CALLSUBR:
967 case TYPE2OP::CALLGSUBR:
969 nInt = popInt();
970 const bool bGlobal = (nType2Op == TYPE2OP::CALLGSUBR);
971 callType2Subr( bGlobal, nInt);
973 break;
974 case TYPE2OP::RETURN:
975 // TODO: check that we are in a subroutine
976 return;
977 case TYPE2OP::VMOVETO:
978 case TYPE2OP::HMOVETO:
979 if( mbNeedClose)
980 writeTypeOp( TYPE1OP::CLOSEPATH);
981 else
982 updateWidth( size() > 1);
983 mbNeedClose = true;
984 pop2MultiWrite( 1, nType2Op);
985 break;
986 case TYPE2OP::VLINETO:
987 case TYPE2OP::HLINETO:
988 pop2MultiWrite( 1, nType2Op,
989 TYPE1OP::VLINETO ^ TYPE1OP::HLINETO);
990 break;
991 case TYPE2OP::RMOVETO:
992 // TODO: convert rmoveto to vlineto/hlineto if possible
993 if( mbNeedClose)
994 writeTypeOp( TYPE1OP::CLOSEPATH);
995 else
996 updateWidth( size() > 2);
997 mbNeedClose = true;
998 pop2MultiWrite( 2, nType2Op);
999 break;
1000 case TYPE2OP::RLINETO:
1001 // TODO: convert rlineto to vlineto/hlineto if possible
1002 pop2MultiWrite( 2, nType2Op);
1003 break;
1004 case TYPE2OP::RCURVETO:
1005 // TODO: convert rcurveto to vh/hv/hh/vv-curveto if possible
1006 pop2MultiWrite( 6, nType2Op);
1007 break;
1008 case TYPE2OP::RCURVELINE:
1009 i = 0;
1010 while( (i += 6) <= mnStackIdx)
1011 writeCurveTo( i, -6, -5, -4, -3, -2, -1 );
1012 i -= 6;
1013 while( (i += 2) <= mnStackIdx) {
1014 writeType1Val( mnValStack[i-2]);
1015 writeType1Val( mnValStack[i-1]);
1016 writeTypeOp( TYPE2OP::RLINETO);
1018 clear();
1019 break;
1020 case TYPE2OP::RLINECURVE:
1021 i = 0;
1022 while( (i += 2) <= mnStackIdx-6) {
1023 writeType1Val( mnValStack[i-2]);
1024 writeType1Val( mnValStack[i-1]);
1025 writeTypeOp( TYPE2OP::RLINETO);
1027 i -= 2;
1028 while( (i += 6) <= mnStackIdx)
1029 writeCurveTo( i, -6, -5, -4, -3, -2, -1 );
1030 clear();
1031 break;
1032 case TYPE2OP::VHCURVETO:
1033 case TYPE2OP::HVCURVETO:
1035 bool bVert = (nType2Op == TYPE2OP::VHCURVETO);
1036 i = 0;
1037 nInt = 0;
1038 if( mnStackIdx & 1 )
1039 nInt = static_cast<int>(mnValStack[ --mnStackIdx ]);
1040 while( (i += 4) <= mnStackIdx) {
1041 // TODO: use writeCurveTo()
1042 if( bVert ) writeType1Val( 0 );
1043 writeType1Val( mnValStack[i-4] );
1044 if( !bVert ) writeType1Val( 0);
1045 writeType1Val( mnValStack[i-3] );
1046 writeType1Val( mnValStack[i-2] );
1047 if( !bVert ) writeType1Val( static_cast<ValType>((i==mnStackIdx) ? nInt : 0) );
1048 writeType1Val( mnValStack[i-1] );
1049 if( bVert ) writeType1Val( static_cast<ValType>((i==mnStackIdx) ? nInt : 0) );
1050 bVert = !bVert;
1051 writeTypeOp( TYPE2OP::RCURVETO);
1054 clear();
1055 break;
1056 case TYPE2OP::HHCURVETO:
1057 i = (mnStackIdx & 1);
1058 while( (i += 4) <= mnStackIdx) {
1059 if( i != 5)
1060 writeCurveTo( i, -4, 0, -3, -2, -1, 0);
1061 else
1062 writeCurveTo( i, -4, -5, -3, -2, -1, 0);
1064 clear();
1065 break;
1066 case TYPE2OP::VVCURVETO:
1067 i = (mnStackIdx & 1);
1068 while( (i += 4) <= mnStackIdx) {
1069 if( i != 5)
1070 writeCurveTo( i, 0, -4, -3, -2, 0, -1);
1071 else
1072 writeCurveTo( i, -5, -4, -3, -2, 0, -1);
1074 clear();
1075 break;
1076 case TYPE2OP::ENDCHAR:
1077 if( mbNeedClose)
1078 writeTypeOp( TYPE1OP::CLOSEPATH);
1079 else
1080 updateWidth( size() >= 1);
1081 // mbNeedClose = true;
1082 writeTypeOp( TYPE1OP::ENDCHAR);
1083 break;
1084 default:
1085 if( ((nType2Op >= 32) && (nType2Op <= 255)) || (nType2Op == 28)) {
1086 --mpReadPtr;
1087 read2push();
1088 } else {
1089 popAll2Write( nType2Op);
1090 assert( false); // TODO?
1092 break;
1096 // --------------------------------------------------------------------
1098 void CffSubsetterContext::convertOneTypeEsc( void)
1100 const int nType2Esc = *(mpReadPtr++);
1101 ValType* pTop = &mnValStack[ mnStackIdx-1];
1102 // convert each T2op
1103 switch( nType2Esc) {
1104 case TYPE2OP::AND:
1105 assert( mnStackIdx >= 2 );
1106 pTop[0] = static_cast<ValType>(static_cast<int>(pTop[0]) & static_cast<int>(pTop[-1]));
1107 --mnStackIdx;
1108 break;
1109 case TYPE2OP::OR:
1110 assert( mnStackIdx >= 2 );
1111 pTop[0] = static_cast<ValType>(static_cast<int>(pTop[0]) | static_cast<int>(pTop[-1]));
1112 --mnStackIdx;
1113 break;
1114 case TYPE2OP::NOT:
1115 assert( mnStackIdx >= 1 );
1116 pTop[0] = (pTop[0] == 0);
1117 break;
1118 case TYPE2OP::ABS:
1119 assert( mnStackIdx >= 1 );
1120 if( pTop[0] >= 0)
1121 break;
1122 // fall through
1123 case TYPE2OP::NEG:
1124 assert( mnStackIdx >= 1 );
1125 pTop[0] = -pTop[0];
1126 break;
1127 case TYPE2OP::ADD:
1128 assert( mnStackIdx >= 2 );
1129 pTop[0] += pTop[-1];
1130 --mnStackIdx;
1131 break;
1132 case TYPE2OP::SUB:
1133 assert( mnStackIdx >= 2 );
1134 pTop[0] -= pTop[-1];
1135 --mnStackIdx;
1136 break;
1137 case TYPE2OP::MUL:
1138 assert( mnStackIdx >= 2 );
1139 if( pTop[-1])
1140 pTop[0] *= pTop[-1];
1141 --mnStackIdx;
1142 break;
1143 case TYPE2OP::DIV:
1144 assert( mnStackIdx >= 2 );
1145 if( pTop[-1])
1146 pTop[0] /= pTop[-1];
1147 --mnStackIdx;
1148 break;
1149 case TYPE2OP::EQ:
1150 assert( mnStackIdx >= 2 );
1151 pTop[0] = (pTop[0] == pTop[-1]);
1152 --mnStackIdx;
1153 break;
1154 case TYPE2OP::DROP:
1155 assert( mnStackIdx >= 1 );
1156 --mnStackIdx;
1157 break;
1158 case TYPE2OP::PUT: {
1159 assert( mnStackIdx >= 2 );
1160 const int nIdx = static_cast<int>(pTop[0]);
1161 assert( nIdx >= 0 );
1162 assert( nIdx < NMAXTRANS );
1163 mnTransVals[ nIdx] = pTop[-1];
1164 mnStackIdx -= 2;
1165 break;
1167 case TYPE2OP::GET: {
1168 assert( mnStackIdx >= 1 );
1169 const int nIdx = static_cast<int>(pTop[0]);
1170 assert( nIdx >= 0 );
1171 assert( nIdx < NMAXTRANS );
1172 pTop[0] = mnTransVals[ nIdx ];
1173 break;
1175 case TYPE2OP::IFELSE: {
1176 assert( mnStackIdx >= 4 );
1177 if( pTop[-1] > pTop[0] )
1178 pTop[-3] = pTop[-2];
1179 mnStackIdx -= 3;
1180 break;
1182 case TYPE2OP::RANDOM:
1183 pTop[+1] = 1234; // TODO
1184 ++mnStackIdx;
1185 break;
1186 case TYPE2OP::SQRT:
1187 // TODO: implement
1188 break;
1189 case TYPE2OP::DUP:
1190 assert( mnStackIdx >= 1 );
1191 pTop[+1] = pTop[0];
1192 ++mnStackIdx;
1193 break;
1194 case TYPE2OP::EXCH: {
1195 assert( mnStackIdx >= 2 );
1196 const ValType nVal = pTop[0];
1197 pTop[0] = pTop[-1];
1198 pTop[-1] = nVal;
1199 break;
1201 case TYPE2OP::INDEX: {
1202 assert( mnStackIdx >= 1 );
1203 const int nVal = static_cast<int>(pTop[0]);
1204 assert( nVal >= 0 );
1205 assert( nVal < mnStackIdx-1 );
1206 pTop[0] = pTop[-1-nVal];
1207 break;
1209 case TYPE2OP::ROLL: {
1210 assert( mnStackIdx >= 1 );
1211 const int nNum = static_cast<int>(pTop[0]);
1212 assert( nNum >= 0);
1213 assert( nNum < mnStackIdx-2 );
1214 (void)nNum; // TODO: implement
1215 const int nOfs = static_cast<int>(pTop[-1]);
1216 mnStackIdx -= 2;
1217 (void)nOfs;// TODO: implement
1218 break;
1220 case TYPE2OP::HFLEX1: {
1221 assert( mnStackIdx == 9);
1223 writeCurveTo( mnStackIdx, -9, -8, -7, -6, -5, 0);
1224 writeCurveTo( mnStackIdx, -4, 0, -3, -2, -1, 0);
1225 // TODO: emulate hflex1 using othersubr call
1227 mnStackIdx -= 9;
1229 break;
1230 case TYPE2OP::HFLEX: {
1231 assert( mnStackIdx == 7);
1232 ValType* pX = &mnValStack[ mnStackIdx];
1234 pX[+1] = -pX[-5]; // temp: +dy5==-dy2
1235 writeCurveTo( mnStackIdx, -7, 0, -6, -5, -4, 0);
1236 writeCurveTo( mnStackIdx, -3, 0, -2, +1, -1, 0);
1237 // TODO: emulate hflex using othersubr call
1239 mnStackIdx -= 7;
1241 break;
1242 case TYPE2OP::FLEX: {
1243 assert( mnStackIdx == 13 );
1244 writeCurveTo( mnStackIdx, -13, -12, -11, -10, -9, -8 );
1245 writeCurveTo( mnStackIdx, -7, -6, -5, -4, -3, -2 );
1246 const ValType nFlexDepth = mnValStack[ mnStackIdx-1 ];
1247 (void)nFlexDepth; // ignoring nFlexDepth
1248 mnStackIdx -= 13;
1250 break;
1251 case TYPE2OP::FLEX1: {
1252 assert( mnStackIdx == 11 );
1253 // write the first part of the flex1-hinted curve
1254 writeCurveTo( mnStackIdx, -11, -10, -9, -8, -7, -6 );
1256 // determine if nD6 is horizontal or vertical
1257 const int i = mnStackIdx;
1258 ValType nDeltaX = mnValStack[i-11] + mnValStack[i-9] + mnValStack[i-7] + mnValStack[i-5] + mnValStack[i-3];
1259 if( nDeltaX < 0 ) nDeltaX = -nDeltaX;
1260 ValType nDeltaY = mnValStack[i-10] + mnValStack[i-8] + mnValStack[i-6] + mnValStack[i-4] + mnValStack[i-2];
1261 if( nDeltaY < 0 ) nDeltaY = -nDeltaY;
1262 const bool bVertD6 = (nDeltaY > nDeltaX);
1264 // write the second part of the flex1-hinted curve
1265 if( !bVertD6 )
1266 writeCurveTo( mnStackIdx, -5, -4, -3, -2, -1, 0);
1267 else
1268 writeCurveTo( mnStackIdx, -5, -4, -3, -2, 0, -1);
1269 mnStackIdx -= 11;
1271 break;
1272 default:
1273 fprintf( stderr,"unhandled type2esc %d\n", nType2Esc);
1274 assert( false);
1275 break;
1279 // --------------------------------------------------------------------
1281 void CffSubsetterContext::callType2Subr( bool bGlobal, int nSubrNumber)
1283 const U8* const pOldReadPtr = mpReadPtr;
1284 const U8* const pOldReadEnd = mpReadEnd;
1286 if( bGlobal ) {
1287 nSubrNumber += mnGlobalSubrBias;
1288 seekIndexData( mnGlobalSubrBase, nSubrNumber);
1289 } else {
1290 nSubrNumber += mpCffLocal->mnLocalSubrBias;
1291 seekIndexData( mpCffLocal->mnLocalSubrBase, nSubrNumber);
1294 while( mpReadPtr < mpReadEnd)
1295 convertOneTypeOp();
1297 mpReadPtr = pOldReadPtr;
1298 mpReadEnd = pOldReadEnd;
1301 // --------------------------------------------------------------------
1303 static const int MAX_T1OPS_SIZE = 81920; // TODO: use dynamic value
1305 int CffSubsetterContext::convert2Type1Ops( CffLocal* pCffLocal, const U8* const pT2Ops, int nT2Len, U8* const pT1Ops)
1307 mpCffLocal = pCffLocal;
1309 // prepare the charstring conversion
1310 mpWritePtr = pT1Ops;
1311 #if 1 // TODO: update caller
1312 U8 aType1Ops[ MAX_T1OPS_SIZE];
1313 if( !pT1Ops)
1314 mpWritePtr = aType1Ops;
1315 *const_cast<U8**>(&pT1Ops) = mpWritePtr;
1316 #else
1317 assert( pT1Ops);
1318 #endif
1320 // prepend random seed for T1crypt
1321 *(mpWritePtr++) = 0x48;
1322 *(mpWritePtr++) = 0x44;
1323 *(mpWritePtr++) = 0x55;
1324 *(mpWritePtr++) = ' ';
1325 #if 1 // convert the Type2 charstring to Type1
1326 mpReadPtr = pT2Ops;
1327 mpReadEnd = pT2Ops + nT2Len;
1328 // prepend "hsbw" or "sbw"
1329 // TODO: only emit hsbw when charwidth is known
1330 // TODO: remove charwidth from T2 stack
1331 writeType1Val( 0); // TODO: aSubsetterContext.getLeftSideBearing();
1332 writeType1Val( 1000/*###getCharWidth()###*/);
1333 writeTypeOp( TYPE1OP::HSBW);
1334 mbSawError = false;
1335 mbNeedClose = false;
1336 mbIgnoreHints = false;
1337 mnHintSize=mnHorzHintSize=mnStackIdx=0; maCharWidth=-1;//#######
1338 mnCntrMask = 0;
1339 while( mpReadPtr < mpReadEnd)
1340 convertOneTypeOp();
1341 // if( bActivePath)
1342 // writeTypeOp( TYPE1OP::CLOSEPATH);
1343 // if( bSubRoutine)
1344 // writeTypeOp( TYPE1OP::RETURN);
1345 if( mbSawError) {
1346 mpWritePtr = pT1Ops+4;
1347 // create an "idiotproof" charstring
1348 writeType1Val( 0);
1349 writeType1Val( 800);
1350 writeTypeOp( TYPE1OP::HSBW);
1351 writeType1Val( 50);
1352 writeTypeOp( TYPE1OP::HMOVETO);
1353 writeType1Val( 650);
1354 writeType1Val( 100);
1355 writeTypeOp( TYPE1OP::RLINETO);
1356 writeType1Val( -350);
1357 writeType1Val( 700);
1358 writeTypeOp( TYPE1OP::RLINETO);
1359 writeTypeOp( TYPE1OP::CLOSEPATH);
1360 writeTypeOp( TYPE1OP::ENDCHAR);
1362 #else // useful for manually encoding charstrings
1363 mpWritePtr = pT1Ops;
1364 mpWritePtr += sprintf( (char*)mpWritePtr, "OOo_\x8b\x8c\x0c\x10\x0b");
1365 #endif
1366 const int nType1Len = mpWritePtr - pT1Ops;
1368 // encrypt the Type1 charstring
1369 int nRDCryptR = 4330; // TODO: mnRDCryptSeed;
1370 for( U8* p = pT1Ops; p < mpWritePtr; ++p) {
1371 *p ^= (nRDCryptR >> 8);
1372 nRDCryptR = (*(U8*)p + nRDCryptR) * 52845 + 22719;
1375 return nType1Len;
1378 // --------------------------------------------------------------------
1380 RealType CffSubsetterContext::readRealVal()
1382 // TODO: more thorough number validity test
1383 bool bComma = false;
1384 int nExpVal = 0;
1385 int nExpSign = 0;
1386 S64 nNumber = 0;
1387 RealType fReal = +1.0;
1388 for(;;){
1389 const U8 c = *(mpReadPtr++); // read nibbles
1390 // parse high nibble
1391 const U8 nH = c >> 4U;
1392 if( nH <= 9) {
1393 nNumber = nNumber * 10 + nH;
1394 --nExpVal;
1395 } else if( nH == 10) { // comma
1396 nExpVal = 0;
1397 bComma = true;
1398 } else if( nH == 11) { // +exp
1399 fReal *= nNumber;
1400 nExpSign = +1;
1401 nNumber = 0;
1402 } else if( nH == 12) { // -exp
1403 fReal *= nNumber;
1404 nExpSign = -1;
1405 nNumber = 0;
1406 } else if( nH == 13) { // reserved
1407 // TODO: ignore or error?
1408 } else if( nH == 14) // minus
1409 fReal = -fReal;
1410 else if( nH == 15) // end
1411 break;
1412 // parse low nibble
1413 const U8 nL = c & 0x0F;
1414 if( nL <= 9) {
1415 nNumber = nNumber * 10 + nL;
1416 --nExpVal;
1417 } else if( nL == 10) { // comma
1418 nExpVal = 0;
1419 bComma = true;
1420 } else if( nL == 11) { // +exp
1421 fReal *= nNumber;
1422 nNumber = 0;
1423 nExpSign = +1;
1424 } else if( nL == 12) { // -exp
1425 fReal *= nNumber;
1426 nNumber = 0;
1427 nExpSign = -1;
1428 } else if( nL == 13) { // reserved
1429 // TODO: ignore or error?
1430 } else if( nL == 14) // minus
1431 fReal = -fReal;
1432 else if( nL == 15) // end
1433 break;
1436 // merge exponents
1437 if( !bComma)
1438 nExpVal = 0;
1439 if( !nExpSign) { fReal *= nNumber;}
1440 else if( nExpSign > 0) { nExpVal += static_cast<int>(nNumber);}
1441 else if( nExpSign < 0) { nExpVal -= static_cast<int>(nNumber);}
1443 // apply exponents
1444 if( !nExpVal) { /*nothing to apply*/}
1445 else if( nExpVal > 0) { while( --nExpVal >= 0) fReal *= 10.0;}
1446 else if( nExpVal < 0) { while( ++nExpVal <= 0) fReal /= 10.0;}
1447 return fReal;
1450 // --------------------------------------------------------------------
1452 // prepare to access an element inside a CFF/CID index table
1453 int CffSubsetterContext::seekIndexData( int nIndexBase, int nDataIndex)
1455 assert( (nIndexBase > 0) && (mpBasePtr + nIndexBase + 3 <= mpBaseEnd));
1456 if( nDataIndex < 0)
1457 return -1;
1458 mpReadPtr = mpBasePtr + nIndexBase;
1459 const int nDataCount = (mpReadPtr[0]<<8) + mpReadPtr[1];
1460 if( nDataIndex >= nDataCount)
1461 return -1;
1462 const int nDataOfsSz = mpReadPtr[2];
1463 mpReadPtr += 3 + (nDataOfsSz * nDataIndex);
1464 int nOfs1 = 0;
1465 switch( nDataOfsSz) {
1466 default: fprintf( stderr, "\tINVALID nDataOfsSz=%d\n\n", nDataOfsSz); return -1;
1467 case 1: nOfs1 = mpReadPtr[0]; break;
1468 case 2: nOfs1 = (mpReadPtr[0]<<8) + mpReadPtr[1]; break;
1469 case 3: nOfs1 = (mpReadPtr[0]<<16) + (mpReadPtr[1]<<8) + mpReadPtr[2]; break;
1470 case 4: nOfs1 = (mpReadPtr[0]<<24) + (mpReadPtr[1]<<16) + (mpReadPtr[2]<<8) + mpReadPtr[3]; break;
1472 mpReadPtr += nDataOfsSz;
1474 int nOfs2 = 0;
1475 switch( nDataOfsSz) {
1476 case 1: nOfs2 = mpReadPtr[0]; break;
1477 case 2: nOfs2 = (mpReadPtr[0]<<8) + mpReadPtr[1]; break;
1478 case 3: nOfs2 = (mpReadPtr[0]<<16) + (mpReadPtr[1]<<8) + mpReadPtr[2]; break;
1479 case 4: nOfs2 = (mpReadPtr[0]<<24) + (mpReadPtr[1]<<16) + (mpReadPtr[2]<<8) + mpReadPtr[3]; break;
1482 mpReadPtr = mpBasePtr + (nIndexBase + 2) + nDataOfsSz * (nDataCount + 1) + nOfs1;
1483 mpReadEnd = mpReadPtr + (nOfs2 - nOfs1);
1484 assert( nOfs1 >= 0);
1485 assert( nOfs2 >= nOfs1);
1486 assert( mpReadPtr <= mpBaseEnd);
1487 assert( mpReadEnd <= mpBaseEnd);
1488 return (nOfs2 - nOfs1);
1491 // --------------------------------------------------------------------
1493 // skip over a CFF/CID index table
1494 void CffSubsetterContext::seekIndexEnd( int nIndexBase)
1496 assert( (nIndexBase > 0) && (mpBasePtr + nIndexBase + 3 <= mpBaseEnd));
1497 mpReadPtr = mpBasePtr + nIndexBase;
1498 const int nDataCount = (mpReadPtr[0]<<8) + mpReadPtr[1];
1499 const int nDataOfsSz = mpReadPtr[2];
1500 mpReadPtr += 3 + nDataOfsSz * nDataCount;
1501 assert( mpReadPtr <= mpBaseEnd);
1502 int nEndOfs = 0;
1503 switch( nDataOfsSz) {
1504 default: fprintf( stderr, "\tINVALID nDataOfsSz=%d\n\n", nDataOfsSz); return;
1505 case 1: nEndOfs = mpReadPtr[0]; break;
1506 case 2: nEndOfs = (mpReadPtr[0]<<8) + mpReadPtr[1]; break;
1507 case 3: nEndOfs = (mpReadPtr[0]<<16) + (mpReadPtr[1]<<8) + mpReadPtr[2];break;
1508 case 4: nEndOfs = (mpReadPtr[0]<<24) + (mpReadPtr[1]<<16) + (mpReadPtr[2]<<8) + mpReadPtr[3]; break;
1510 mpReadPtr += nDataOfsSz;
1511 mpReadPtr += nEndOfs - 1;
1512 mpReadEnd = mpBaseEnd;
1513 assert( nEndOfs >= 0);
1514 assert( mpReadEnd <= mpBaseEnd);
1517 // ====================================================================
1519 // initialize FONTDICT specific values
1520 CffLocal::CffLocal( void)
1521 : mnPrivDictBase( 0)
1522 , mnPrivDictSize( 0)
1523 , mnLocalSubrOffs( 0)
1524 , mnLocalSubrBase( 0)
1525 , mnLocalSubrCount( 0)
1526 , mnLocalSubrBias( 0)
1527 , maNominalWidth( 0)
1528 , maDefaultWidth( 0)
1529 , maStemStdHW( 0)
1530 , maStemStdVW( 0)
1531 , mfBlueScale( 0.0)
1532 , mfBlueShift( 0.0)
1533 , mfBlueFuzz( 0.0)
1534 , mfExpFactor( 0.0)
1535 , mnLangGroup( 0)
1536 , mbForceBold( false)
1538 maStemSnapH.clear();
1539 maStemSnapV.clear();
1540 maBlueValues.clear();
1541 maOtherBlues.clear();
1542 maFamilyBlues.clear();
1543 maFamilyOtherBlues.clear();
1546 // --------------------------------------------------------------------
1548 CffGlobal::CffGlobal( void)
1549 : mnNameIdxBase( 0)
1550 , mnNameIdxCount( 0)
1551 , mnStringIdxBase( 0)
1552 , mnStringIdxCount( 0)
1553 , mbCIDFont( false)
1554 , mnCharStrBase( 0)
1555 , mnCharStrCount( 0)
1556 , mnEncodingBase( 0)
1557 , mnCharsetBase( 0)
1558 , mnGlobalSubrBase( 0)
1559 , mnGlobalSubrCount( 0)
1560 , mnGlobalSubrBias( 0)
1561 , mnFDSelectBase( 0)
1562 , mnFontDictBase( 0)
1563 , mnFDAryCount( 1)
1564 , mnFontNameSID( 0)
1565 , mnFullNameSID( 0)
1566 , mnFamilyNameSID( 0)
1568 maFontBBox.clear();
1569 // TODO; maFontMatrix.clear();
1572 // --------------------------------------------------------------------
1574 void CffSubsetterContext::initialCffRead( void)
1576 // get the CFFHeader
1577 mpReadPtr = mpBasePtr;
1578 const U8 nVerMajor = *(mpReadPtr++);
1579 const U8 nVerMinor = *(mpReadPtr++);
1580 const U8 nHeaderSize = *(mpReadPtr++);
1581 const U8 nOffsetSize = *(mpReadPtr++);
1582 // TODO: is the version number useful for anything else?
1583 assert( (nVerMajor == 1) && (nVerMinor == 0));
1584 (void)(nVerMajor + nVerMinor + nOffsetSize); // avoid compiler warnings
1586 // prepare access to the NameIndex
1587 mnNameIdxBase = nHeaderSize;
1588 mpReadPtr = mpBasePtr + nHeaderSize;
1589 mnNameIdxCount = (mpReadPtr[0]<<8) + mpReadPtr[1];
1590 seekIndexEnd( mnNameIdxBase);
1592 // get the TopDict index
1593 const long nTopDictBase = getReadOfs();
1594 const int nTopDictCount = (mpReadPtr[0]<<8) + mpReadPtr[1];
1595 if( nTopDictCount) {
1596 for( int i = 0; i < nTopDictCount; ++i) {
1597 seekIndexData( nTopDictBase, i);
1598 while( mpReadPtr < mpReadEnd)
1599 readDictOp();
1600 assert( mpReadPtr == mpReadEnd);
1604 // prepare access to the String index
1605 mnStringIdxBase = getReadOfs();
1606 mnStringIdxCount = (mpReadPtr[0]<<8) + mpReadPtr[1];
1607 seekIndexEnd( mnStringIdxBase);
1609 // prepare access to the GlobalSubr index
1610 mnGlobalSubrBase = getReadOfs();
1611 mnGlobalSubrCount = (mpReadPtr[0]<<8) + mpReadPtr[1];
1612 mnGlobalSubrBias = (mnGlobalSubrCount<1240)?107:(mnGlobalSubrCount<33900)?1131:32768;
1613 // skip past the last GlobalSubr entry
1614 // seekIndexEnd( mnGlobalSubrBase);
1616 // get/skip the Encodings (we got mnEncodingBase from TOPDICT)
1617 // seekEncodingsEnd( mnEncodingBase);
1618 // get/skip the Charsets (we got mnCharsetBase from TOPDICT)
1619 // seekCharsetsEnd( mnCharStrBase);
1620 // get/skip FDSelect (CID only) data
1622 // prepare access to the CharStrings index (we got the base from TOPDICT)
1623 mpReadPtr = mpBasePtr + mnCharStrBase;
1624 mnCharStrCount = (mpReadPtr[0]<<8) + mpReadPtr[1];
1625 // seekIndexEnd( mnCharStrBase);
1627 // read the FDArray index (CID only)
1628 if( mbCIDFont) {
1629 // assert( mnFontDictBase == tellRel());
1630 mpReadPtr = mpBasePtr + mnFontDictBase;
1631 mnFDAryCount = (mpReadPtr[0]<<8) + mpReadPtr[1];
1632 assert( mnFDAryCount < (int)(sizeof(maCffLocal)/sizeof(*maCffLocal)));
1634 // read FDArray details to get access to the PRIVDICTs
1635 for( int i = 0; i < mnFDAryCount; ++i) {
1636 mpCffLocal = &maCffLocal[i];
1637 seekIndexData( mnFontDictBase, i);
1638 while( mpReadPtr < mpReadEnd)
1639 readDictOp();
1640 assert( mpReadPtr == mpReadEnd);
1644 for( int i = 0; i < mnFDAryCount; ++i) {
1645 mpCffLocal = &maCffLocal[i];
1647 // get the PrivateDict index
1648 // (we got mnPrivDictSize and mnPrivDictBase from TOPDICT or FDArray)
1649 if( mpCffLocal->mnPrivDictSize != 0) {
1650 assert( mpCffLocal->mnPrivDictSize > 0);
1651 // get the PrivDict data
1652 mpReadPtr = mpBasePtr + mpCffLocal->mnPrivDictBase;
1653 mpReadEnd = mpReadPtr + mpCffLocal->mnPrivDictSize;
1654 assert( mpReadEnd <= mpBaseEnd);
1655 // read PrivDict details
1656 while( mpReadPtr < mpReadEnd)
1657 readDictOp();
1660 // prepare access to the LocalSubrs (we got mnLocalSubrOffs from PRIVDICT)
1661 if( mpCffLocal->mnLocalSubrOffs) {
1662 // read LocalSubrs summary
1663 mpCffLocal->mnLocalSubrBase = mpCffLocal->mnPrivDictBase + mpCffLocal->mnLocalSubrOffs;
1664 mpReadPtr = mpBasePtr + mpCffLocal->mnLocalSubrBase;
1665 const int nSubrCount = (mpReadPtr[0] << 8) + mpReadPtr[1];
1666 mpCffLocal->mnLocalSubrCount = nSubrCount;
1667 mpCffLocal->mnLocalSubrBias = (nSubrCount<1240)?107:(nSubrCount<33900)?1131:32768;
1668 // seekIndexEnd( mpCffLocal->mnLocalSubrBase);
1672 // ignore the Notices info
1675 // --------------------------------------------------------------------
1677 // get a cstring from a StringID
1678 const char* CffSubsetterContext::getString( int nStringID)
1680 // get a standard string if possible
1681 const static int nStdStrings = sizeof(pStringIds)/sizeof(*pStringIds);
1682 if( (nStringID >= 0) && (nStringID < nStdStrings))
1683 return pStringIds[ nStringID];
1685 // else get the string from the StringIndex table
1686 const U8* pReadPtr = mpReadPtr;
1687 const U8* pReadEnd = mpReadEnd;
1688 nStringID -= nStdStrings;
1689 int nLen = seekIndexData( mnStringIdxBase, nStringID);
1690 // assert( nLen >= 0);
1691 // TODO: just return the undecorated name
1692 // TODO: get rid of static char buffer
1693 static char aNameBuf[ 2560];
1694 if( nLen < 0) {
1695 sprintf( aNameBuf, "name[%d].notfound!", nStringID);
1696 } else {
1697 const int nMaxLen = sizeof(aNameBuf) - 1;
1698 if( nLen >= nMaxLen)
1699 nLen = nMaxLen;
1700 for( int i = 0; i < nLen; ++i)
1701 aNameBuf[i] = *(mpReadPtr++);
1702 aNameBuf[ nLen] = '\0';
1704 mpReadPtr = pReadPtr;
1705 mpReadEnd = pReadEnd;
1706 return aNameBuf;
1709 // --------------------------------------------------------------------
1711 // access a CID's FDSelect table
1712 int CffSubsetterContext::getFDSelect( int nGlyphIndex) const
1714 assert( nGlyphIndex >= 0);
1715 assert( nGlyphIndex < mnCharStrCount);
1716 if( !mbCIDFont)
1717 return 0;
1719 const U8* pReadPtr = mpBasePtr + mnFDSelectBase;
1720 const U8 nFDSelFormat = *(pReadPtr++);
1721 switch( nFDSelFormat) {
1722 case 0: { // FDSELECT format 0
1723 pReadPtr += nGlyphIndex;
1724 const U8 nFDIdx = *(pReadPtr++);
1725 return nFDIdx;
1726 } //break;
1727 case 3: { // FDSELECT format 3
1728 const U16 nRangeCount = (pReadPtr[0]<<8) + pReadPtr[1];
1729 assert( nRangeCount > 0);
1730 assert( nRangeCount <= mnCharStrCount);
1731 U16 nPrev = (pReadPtr[2]<<8) + pReadPtr[3];
1732 assert( nPrev == 0);
1733 (void)nPrev;
1734 pReadPtr += 4;
1735 // TODO? binary search
1736 for( int i = 0; i < nRangeCount; ++i) {
1737 const U8 nFDIdx = pReadPtr[0];
1738 const U16 nNext = (pReadPtr[1]<<8) + pReadPtr[2];
1739 assert( nPrev < nNext);
1740 if( nGlyphIndex < nNext)
1741 return nFDIdx;
1742 pReadPtr += 3;
1743 nPrev = nNext;
1745 } break;
1746 default: // invalid FDselect format
1747 fprintf( stderr, "invalid CFF.FdselType=%d\n", nFDSelFormat);
1748 break;
1751 assert( false);
1752 return -1;
1755 // --------------------------------------------------------------------
1757 int CffSubsetterContext::getGlyphSID( int nGlyphIndex) const
1759 if( nGlyphIndex == 0)
1760 return 0; // ".notdef"
1761 assert( nGlyphIndex >= 0);
1762 assert( nGlyphIndex < mnCharStrCount);
1763 if( (nGlyphIndex < 0) || (nGlyphIndex >= mnCharStrCount))
1764 return -1;
1766 // get the SID/CID from the Charset table
1767 const U8* pReadPtr = mpBasePtr + mnCharsetBase;
1768 const U8 nCSetFormat = *(pReadPtr++);
1769 int nGlyphsToSkip = nGlyphIndex - 1;
1770 switch( nCSetFormat) {
1771 case 0: // charset format 0
1772 pReadPtr += 2 * nGlyphsToSkip;
1773 nGlyphsToSkip = 0;
1774 break;
1775 case 1: // charset format 1
1776 while( nGlyphsToSkip >= 0) {
1777 const int nLeft = pReadPtr[2];
1778 if( nGlyphsToSkip <= nLeft)
1779 break;
1780 nGlyphsToSkip -= nLeft + 1;
1781 pReadPtr += 3;
1783 break;
1784 case 2: // charset format 2
1785 while( nGlyphsToSkip >= 0) {
1786 const int nLeft = (pReadPtr[2]<<8) + pReadPtr[3];
1787 if( nGlyphsToSkip <= nLeft)
1788 break;
1789 nGlyphsToSkip -= nLeft + 1;
1790 pReadPtr += 4;
1792 break;
1793 default:
1794 fprintf( stderr, "ILLEGAL CFF-Charset format %d\n", nCSetFormat);
1795 return -2;
1798 int nSID = (pReadPtr[0]<<8) + pReadPtr[1];
1799 nSID += nGlyphsToSkip;
1800 // NOTE: for CID-fonts the resulting SID is interpreted as CID
1801 return nSID;
1804 // --------------------------------------------------------------------
1806 // NOTE: the result becomes invalid with the next call to this method
1807 const char* CffSubsetterContext::getGlyphName( int nGlyphIndex)
1809 // the first glyph is always the .notdef glyph
1810 const char* pGlyphName = ".notdef";
1811 if( nGlyphIndex == 0)
1812 return pGlyphName;
1814 // prepare a result buffer
1815 // TODO: get rid of static buffer
1816 static char aDefaultGlyphName[64];
1817 pGlyphName = aDefaultGlyphName;
1819 // get the glyph specific name
1820 const int nSID = getGlyphSID( nGlyphIndex);
1821 if( nSID < 0) // default glyph name
1822 sprintf( aDefaultGlyphName, "gly%03d", nGlyphIndex);
1823 else if( mbCIDFont) // default glyph name in CIDs
1824 sprintf( aDefaultGlyphName, "cid%03d", nSID);
1825 else { // glyph name from string table
1826 const char* pSidName = getString( nSID);
1827 // check validity of glyph name
1828 if( pSidName) {
1829 const char* p = pSidName;
1830 while( (*p >= '0') && (*p <= 'z')) ++p;
1831 if( (p >= pSidName+1) && (*p == '\0'))
1832 pGlyphName = pSidName;
1834 // if needed invent a fallback name
1835 if( pGlyphName != pSidName)
1836 sprintf( aDefaultGlyphName, "bad%03d", nSID);
1839 return pGlyphName;
1842 // --------------------------------------------------------------------
1844 class Type1Emitter
1846 public:
1847 explicit Type1Emitter( FILE* pOutFile, bool bPfbSubset = true);
1848 /*virtual*/ ~Type1Emitter( void);
1849 void setSubsetName( const char* );
1851 size_t emitRawData( const char* pData, size_t nLength) const;
1852 void emitAllRaw( void);
1853 void emitAllHex( void);
1854 void emitAllCrypted( void);
1855 int tellPos( void) const;
1856 size_t updateLen( int nTellPos, size_t nLength);
1857 void emitValVector( const char* pLineHead, const char* pLineTail, const ValVector&);
1858 private:
1859 FILE* mpFileOut;
1860 bool mbCloseOutfile;
1861 char maBuffer[MAX_T1OPS_SIZE]; // TODO: dynamic allocation
1862 int mnEECryptR;
1863 public:
1864 char* mpPtr;
1866 char maSubsetName[256];
1867 bool mbPfbSubset;
1868 int mnHexLineCol;
1871 // --------------------------------------------------------------------
1873 Type1Emitter::Type1Emitter( FILE* pOutFile, bool bPfbSubset)
1874 : mpFileOut( pOutFile)
1875 , mbCloseOutfile( false)
1876 , mnEECryptR( 55665) // default eexec seed, TODO: mnEECryptSeed
1877 , mpPtr( maBuffer)
1878 , mbPfbSubset( bPfbSubset)
1879 , mnHexLineCol( 0)
1881 maSubsetName[0] = '\0';
1884 // --------------------------------------------------------------------
1886 Type1Emitter::~Type1Emitter( void)
1888 if( !mpFileOut)
1889 return;
1890 if( mbCloseOutfile )
1891 fclose( mpFileOut);
1892 mpFileOut = NULL;
1895 // --------------------------------------------------------------------
1897 void Type1Emitter::setSubsetName( const char* pSubsetName)
1899 maSubsetName[0] = '\0';
1900 if( pSubsetName)
1901 strncpy( maSubsetName, pSubsetName, sizeof(maSubsetName));
1902 maSubsetName[sizeof(maSubsetName)-1] = '\0';
1905 // --------------------------------------------------------------------
1907 int Type1Emitter::tellPos( void) const
1909 int nTellPos = ftell( mpFileOut);
1910 return nTellPos;
1913 // --------------------------------------------------------------------
1915 size_t Type1Emitter::updateLen( int nTellPos, size_t nLength)
1917 // update PFB segment header length
1918 U8 cData[4];
1919 cData[0] = static_cast<U8>(nLength >> 0);
1920 cData[1] = static_cast<U8>(nLength >> 8);
1921 cData[2] = static_cast<U8>(nLength >> 16);
1922 cData[3] = static_cast<U8>(nLength >> 24);
1923 const long nCurrPos = ftell( mpFileOut);
1924 fseek( mpFileOut, nTellPos, SEEK_SET);
1925 size_t nWrote = fwrite( cData, 1, sizeof(cData), mpFileOut);
1926 if( nCurrPos >= 0)
1927 fseek( mpFileOut, nCurrPos, SEEK_SET);
1928 return nWrote;
1931 // --------------------------------------------------------------------
1933 inline size_t Type1Emitter::emitRawData(const char* pData, size_t nLength) const
1935 return fwrite( pData, 1, nLength, mpFileOut);
1938 // --------------------------------------------------------------------
1940 inline void Type1Emitter::emitAllRaw( void)
1942 // writeout raw data
1943 assert( (mpPtr - maBuffer) < (int)sizeof(maBuffer));
1944 emitRawData( maBuffer, mpPtr - maBuffer);
1945 // reset the raw buffer
1946 mpPtr = maBuffer;
1949 // --------------------------------------------------------------------
1951 inline void Type1Emitter::emitAllHex( void)
1953 assert( (mpPtr - maBuffer) < (int)sizeof(maBuffer));
1954 for( const char* p = maBuffer; p < mpPtr;) {
1955 // convert binary chunk to hex
1956 char aHexBuf[0x4000];
1957 char* pOut = aHexBuf;
1958 while( (p < mpPtr) && (pOut < aHexBuf+sizeof(aHexBuf)-4)) {
1959 // convert each byte to hex
1960 char cNibble = (*p >> 4) & 0x0F;
1961 cNibble += (cNibble < 10) ? '0' : 'A'-10;
1962 *(pOut++) = cNibble;
1963 cNibble = *(p++) & 0x0F;
1964 cNibble += (cNibble < 10) ? '0' : 'A'-10;
1965 *(pOut++) = cNibble;
1966 // limit the line length
1967 if( (++mnHexLineCol & 0x3F) == 0)
1968 *(pOut++) = '\n';
1970 // writeout hex-converted chunk
1971 emitRawData( aHexBuf, pOut-aHexBuf);
1973 // reset the raw buffer
1974 mpPtr = maBuffer;
1977 // --------------------------------------------------------------------
1979 void Type1Emitter::emitAllCrypted( void)
1981 // apply t1crypt
1982 for( char* p = maBuffer; p < mpPtr; ++p) {
1983 *p ^= (mnEECryptR >> 8);
1984 mnEECryptR = (*(U8*)p + mnEECryptR) * 52845 + 22719;
1987 // emit the t1crypt result
1988 if( mbPfbSubset)
1989 emitAllRaw();
1990 else
1991 emitAllHex();
1994 // --------------------------------------------------------------------
1996 // #i110387# quick-and-dirty double->ascii conversion
1997 // needed because sprintf/ecvt/etc. alone are too localized (LC_NUMERIC)
1998 // also strip off trailing zeros in fraction while we are at it
1999 inline int dbl2str( char* pOut, double fVal, int nPrecision=6)
2001 const int nLen = psp::getValueOfDouble( pOut, fVal, nPrecision);
2002 return nLen;
2005 // --------------------------------------------------------------------
2007 void Type1Emitter::emitValVector( const char* pLineHead, const char* pLineTail,
2008 const ValVector& rVector)
2010 // ignore empty vectors
2011 if( rVector.empty())
2012 return;
2014 // emit the line head
2015 mpPtr += sprintf( mpPtr, "%s", pLineHead);
2016 // emit the vector values
2017 ValVector::value_type aVal = 0;
2018 for( ValVector::const_iterator it = rVector.begin();;) {
2019 aVal = *it;
2020 if( ++it == rVector.end() )
2021 break;
2022 mpPtr += dbl2str( mpPtr, aVal);
2023 *(mpPtr++) = ' ';
2025 // emit the last value
2026 mpPtr += dbl2str( mpPtr, aVal);
2027 // emit the line tail
2028 mpPtr += sprintf( mpPtr, "%s", pLineTail);
2031 // --------------------------------------------------------------------
2033 bool CffSubsetterContext::emitAsType1( Type1Emitter& rEmitter,
2034 const long* pReqGlyphIDs, const U8* pReqEncoding,
2035 GlyphWidth* pGlyphWidths, int nGlyphCount, FontSubsetInfo& rFSInfo)
2037 // prepare some fontdirectory details
2038 static const int nUniqueIdBase = 4100000; // using private-interchange UniqueIds
2039 static int nUniqueId = nUniqueIdBase;
2040 ++nUniqueId;
2042 char* pFontName = rEmitter.maSubsetName;
2043 if( !*pFontName ) {
2044 if( mnFontNameSID) {
2045 // get the fontname directly if available
2046 strncpy( pFontName, getString( mnFontNameSID), sizeof(rEmitter.maSubsetName) - 1);
2047 pFontName[sizeof(rEmitter.maSubsetName) - 1] = 0;
2048 } else if( mnFullNameSID) {
2049 // approximate fontname as fullname-whitespace
2050 const char* pI = getString( mnFullNameSID);
2051 char* pO = pFontName;
2052 const char* pLimit = pFontName + sizeof(rEmitter.maSubsetName) - 1;
2053 while( pO < pLimit) {
2054 const char c = *(pI++);
2055 if( c != ' ')
2056 *(pO++) = c;
2057 if( !c)
2058 break;
2060 *pO = '\0';
2061 } else {
2062 // fallback name of last resort
2063 strncpy( pFontName, "DummyName", sizeof(rEmitter.maSubsetName));
2066 const char* pFullName = pFontName;
2067 const char* pFamilyName = pFontName;
2069 char*& pOut = rEmitter.mpPtr; // convenience reference, TODO: cleanup
2071 // create a PFB+Type1 header
2072 if( rEmitter.mbPfbSubset ) {
2073 static const char aPfbHeader[] = "\x80\x01\x00\x00\x00\x00";
2074 rEmitter.emitRawData( aPfbHeader, sizeof(aPfbHeader)-1);
2077 pOut += sprintf( pOut, "%%!FontType1-1.0: %s 001.003\n", rEmitter.maSubsetName);
2078 // emit TOPDICT
2079 pOut += sprintf( pOut,
2080 "11 dict begin\n" // TODO: dynamic entry count for TOPDICT
2081 "/FontType 1 def\n"
2082 "/PaintType 0 def\n");
2083 pOut += sprintf( pOut, "/FontName /%s def\n", rEmitter.maSubsetName);
2084 pOut += sprintf( pOut, "/UniqueID %d def\n", nUniqueId);
2085 // emit FontMatrix
2086 if( maFontMatrix.size() == 6)
2087 rEmitter.emitValVector( "/FontMatrix [", "]readonly def\n", maFontMatrix);
2088 else // emit default FontMatrix if needed
2089 pOut += sprintf( pOut, "/FontMatrix [0.001 0 0 0.001 0 0]readonly def\n");
2090 // emit FontBBox
2091 if( maFontBBox.size() == 4)
2092 rEmitter.emitValVector( "/FontBBox {", "}readonly def\n", maFontBBox);
2093 else // emit default FontBBox if needed
2094 pOut += sprintf( pOut, "/FontBBox {0 0 999 999}readonly def\n");
2095 // emit FONTINFO into TOPDICT
2096 pOut += sprintf( pOut,
2097 "/FontInfo 2 dict dup begin\n" // TODO: check fontinfo entry count
2098 " /FullName (%s) readonly def\n"
2099 " /FamilyName (%s) readonly def\n"
2100 "end readonly def\n",
2101 pFullName, pFamilyName);
2103 pOut += sprintf( pOut,
2104 "/Encoding 256 array\n"
2105 "0 1 255 {1 index exch /.notdef put} for\n");
2106 for( int i = 1; (i < nGlyphCount) && (i < 256); ++i) {
2107 const char* pGlyphName = getGlyphName( pReqGlyphIDs[i]);
2108 pOut += sprintf( pOut, "dup %d /%s put\n", pReqEncoding[i], pGlyphName);
2110 pOut += sprintf( pOut, "readonly def\n");
2111 pOut += sprintf( pOut,
2112 // TODO: more topdict entries
2113 "currentdict end\n"
2114 "currentfile eexec\n");
2116 // emit PFB header
2117 rEmitter.emitAllRaw();
2118 if( rEmitter.mbPfbSubset) {
2119 // update PFB header segment
2120 const int nPfbHeaderLen = rEmitter.tellPos() - 6;
2121 rEmitter.updateLen( 2, nPfbHeaderLen);
2123 // prepare start of eexec segment
2124 rEmitter.emitRawData( "\x80\x02\x00\x00\x00\x00", 6); // segment start
2126 const int nEExecSegTell = rEmitter.tellPos();
2128 // which always starts with a privdict
2129 // count the privdict entries
2130 int nPrivEntryCount = 9;
2131 #if !defined(IGNORE_HINTS)
2132 // emit blue hints only if non-default values
2133 nPrivEntryCount += !mpCffLocal->maOtherBlues.empty();
2134 nPrivEntryCount += !mpCffLocal->maFamilyBlues.empty();
2135 nPrivEntryCount += !mpCffLocal->maFamilyOtherBlues.empty();
2136 nPrivEntryCount += (mpCffLocal->mfBlueScale != 0.0);
2137 nPrivEntryCount += (mpCffLocal->mfBlueShift != 0.0);
2138 nPrivEntryCount += (mpCffLocal->mfBlueFuzz != 0.0);
2139 // emit stem hints only if non-default values
2140 nPrivEntryCount += (mpCffLocal->maStemStdHW != 0);
2141 nPrivEntryCount += (mpCffLocal->maStemStdVW != 0);
2142 nPrivEntryCount += !mpCffLocal->maStemSnapH.empty();
2143 nPrivEntryCount += !mpCffLocal->maStemSnapV.empty();
2144 // emit other hints only if non-default values
2145 nPrivEntryCount += (mpCffLocal->mfExpFactor != 0.0);
2146 nPrivEntryCount += (mpCffLocal->mnLangGroup != 0);
2147 nPrivEntryCount += (mpCffLocal->mnLangGroup == 1);
2148 nPrivEntryCount += (mpCffLocal->mbForceBold != false);
2149 #endif // IGNORE_HINTS
2150 // emit the privdict header
2151 pOut += sprintf( pOut,
2152 "\110\104\125 "
2153 "dup\n/Private %d dict dup begin\n"
2154 "/RD{string currentfile exch readstring pop}executeonly def\n"
2155 "/ND{noaccess def}executeonly def\n"
2156 "/NP{noaccess put}executeonly def\n"
2157 "/MinFeature{16 16}ND\n"
2158 "/password 5839 def\n", // TODO: mnRDCryptSeed?
2159 nPrivEntryCount);
2161 #if defined(IGNORE_HINTS)
2162 pOut += sprintf( pOut, "/BlueValues []ND\n"); // BlueValues are mandatory
2163 #else
2164 // emit blue hint related privdict entries
2165 if( !mpCffLocal->maBlueValues.empty())
2166 rEmitter.emitValVector( "/BlueValues [", "]ND\n", mpCffLocal->maBlueValues);
2167 else
2168 pOut += sprintf( pOut, "/BlueValues []ND\n"); // default to empty BlueValues
2169 rEmitter.emitValVector( "/OtherBlues [", "]ND\n", mpCffLocal->maOtherBlues);
2170 rEmitter.emitValVector( "/FamilyBlues [", "]ND\n", mpCffLocal->maFamilyBlues);
2171 rEmitter.emitValVector( "/FamilyOtherBlues [", "]ND\n", mpCffLocal->maFamilyOtherBlues);
2173 if( mpCffLocal->mfBlueScale) {
2174 pOut += sprintf( pOut, "/BlueScale ");
2175 pOut += dbl2str( pOut, mpCffLocal->mfBlueScale, 6);
2176 pOut += sprintf( pOut, " def\n");
2178 if( mpCffLocal->mfBlueShift) { // default BlueShift==7
2179 pOut += sprintf( pOut, "/BlueShift ");
2180 pOut += dbl2str( pOut, mpCffLocal->mfBlueShift);
2181 pOut += sprintf( pOut, " def\n");
2183 if( mpCffLocal->mfBlueFuzz) { // default BlueFuzz==1
2184 pOut += sprintf( pOut, "/BlueFuzz ");
2185 pOut += dbl2str( pOut, mpCffLocal->mfBlueFuzz);
2186 pOut += sprintf( pOut, " def\n");
2189 // emit stem hint related privdict entries
2190 if( mpCffLocal->maStemStdHW) {
2191 pOut += sprintf( pOut, "/StdHW [");
2192 pOut += dbl2str( pOut, mpCffLocal->maStemStdHW);
2193 pOut += sprintf( pOut, "] def\n");
2195 if( mpCffLocal->maStemStdVW) {
2196 pOut += sprintf( pOut, "/StdVW [");
2197 pOut += dbl2str( pOut, mpCffLocal->maStemStdVW);
2198 pOut += sprintf( pOut, "] def\n");
2200 rEmitter.emitValVector( "/StemSnapH [", "]ND\n", mpCffLocal->maStemSnapH);
2201 rEmitter.emitValVector( "/StemSnapV [", "]ND\n", mpCffLocal->maStemSnapV);
2203 // emit other hints
2204 if( mpCffLocal->mbForceBold)
2205 pOut += sprintf( pOut, "/ForceBold true def\n");
2206 if( mpCffLocal->mnLangGroup != 0)
2207 pOut += sprintf( pOut, "/LanguageGroup %d def\n", mpCffLocal->mnLangGroup);
2208 if( mpCffLocal->mnLangGroup == 1) // compatibility with ancient printers
2209 pOut += sprintf( pOut, "/RndStemUp false def\n");
2210 if( mpCffLocal->mfExpFactor) {
2211 pOut += sprintf( pOut, "/ExpansionFactor ");
2212 pOut += dbl2str( pOut, mpCffLocal->mfExpFactor);
2213 pOut += sprintf( pOut, " def\n");
2215 #endif // IGNORE_HINTS
2217 // emit remaining privdict entries
2218 pOut += sprintf( pOut, "/UniqueID %d def\n", nUniqueId);
2219 // TODO?: more privdict entries?
2221 static const char aOtherSubrs[] =
2222 "/OtherSubrs\n"
2223 "% Dummy code for faking flex hints\n"
2224 "[ {} {} {} {systemdict /internaldict known not {pop 3}\n"
2225 "{1183615869 systemdict /internaldict get exec\n"
2226 "dup /startlock known\n"
2227 "{/startlock get exec}\n"
2228 "{dup /strtlck known\n"
2229 "{/strtlck get exec}\n"
2230 "{pop 3}\nifelse}\nifelse}\nifelse\n} executeonly\n"
2231 "] ND\n";
2232 memcpy( pOut, aOtherSubrs, sizeof(aOtherSubrs)-1);
2233 pOut += sizeof(aOtherSubrs)-1;
2235 // emit used GlobalSubr charstrings
2236 // these are the just the default subrs
2237 // TODO: do we need them as the flex hints are resolved differently?
2238 static const char aSubrs[] =
2239 "/Subrs 5 array\n"
2240 "dup 0 15 RD \x5F\x3D\x6B\xAC\x3C\xBD\x74\x3D\x3E\x17\xA0\x86\x58\x08\x85 NP\n"
2241 "dup 1 9 RD \x5F\x3D\x6B\xD8\xA6\xB5\x68\xB6\xA2 NP\n"
2242 "dup 2 9 RD \x5F\x3D\x6B\xAC\x39\x46\xB9\x43\xF9 NP\n"
2243 "dup 3 5 RD \x5F\x3D\x6B\xAC\xB9 NP\n"
2244 "dup 4 12 RD \x5F\x3D\x6B\xAC\x3E\x5D\x48\x54\x62\x76\x39\x03 NP\n"
2245 "ND\n";
2246 memcpy( pOut, aSubrs, sizeof(aSubrs)-1);
2247 pOut += sizeof(aSubrs)-1;
2249 // TODO: emit more GlobalSubr charstrings?
2250 // TODO: emit used LocalSubr charstrings?
2252 // emit the CharStrings for the requested glyphs
2253 pOut += sprintf( pOut,
2254 "2 index /CharStrings %d dict dup begin\n", nGlyphCount);
2255 rEmitter.emitAllCrypted();
2256 for( int i = 0; i < nGlyphCount; ++i) {
2257 const int nGlyphId = pReqGlyphIDs[i];
2258 assert( (nGlyphId >= 0) && (nGlyphId < mnCharStrCount));
2259 // get privdict context matching to the glyph
2260 const int nFDSelect = getFDSelect( nGlyphId);
2261 if( nFDSelect < 0)
2262 continue;
2263 mpCffLocal = &maCffLocal[ nFDSelect];
2264 // convert the Type2op charstring to its Type1op counterpart
2265 const int nT2Len = seekIndexData( mnCharStrBase, nGlyphId);
2266 assert( nT2Len > 0);
2267 U8 aType1Ops[ MAX_T1OPS_SIZE]; // TODO: dynamic allocation
2268 const int nT1Len = convert2Type1Ops( mpCffLocal, mpReadPtr, nT2Len, aType1Ops);
2269 // get the glyph name
2270 const char* pGlyphName = getGlyphName( nGlyphId);
2271 // emit the encrypted Type1op charstring
2272 pOut += sprintf( pOut, "/%s %d RD ", pGlyphName, nT1Len);
2273 memcpy( pOut, aType1Ops, nT1Len);
2274 pOut += nT1Len;
2275 pOut += sprintf( pOut, " ND\n");
2276 rEmitter.emitAllCrypted();
2277 // provide individual glyphwidths if requested
2278 if( pGlyphWidths ) {
2279 ValType aCharWidth = getCharWidth();
2280 if( maFontMatrix.size() >= 4)
2281 aCharWidth *= 1000.0F * maFontMatrix[0];
2282 pGlyphWidths[i] = static_cast<GlyphWidth>(aCharWidth);
2285 pOut += sprintf( pOut, "end end\nreadonly put\nput\n");
2286 pOut += sprintf( pOut, "dup/FontName get exch definefont pop\n");
2287 pOut += sprintf( pOut, "mark currentfile closefile\n");
2288 rEmitter.emitAllCrypted();
2290 // mark stop of eexec encryption
2291 if( rEmitter.mbPfbSubset) {
2292 const int nEExecLen = rEmitter.tellPos() - nEExecSegTell;
2293 rEmitter.updateLen( nEExecSegTell-4, nEExecLen);
2296 // create PFB footer
2297 static const char aPfxFooter[] = "\x80\x01\x14\x02\x00\x00\n" // TODO: check segment len
2298 "0000000000000000000000000000000000000000000000000000000000000000\n"
2299 "0000000000000000000000000000000000000000000000000000000000000000\n"
2300 "0000000000000000000000000000000000000000000000000000000000000000\n"
2301 "0000000000000000000000000000000000000000000000000000000000000000\n"
2302 "0000000000000000000000000000000000000000000000000000000000000000\n"
2303 "0000000000000000000000000000000000000000000000000000000000000000\n"
2304 "0000000000000000000000000000000000000000000000000000000000000000\n"
2305 "0000000000000000000000000000000000000000000000000000000000000000\n"
2306 "cleartomark\n"
2307 "\x80\x03";
2308 if( rEmitter.mbPfbSubset)
2309 rEmitter.emitRawData( aPfxFooter, sizeof(aPfxFooter)-1);
2310 else
2311 rEmitter.emitRawData( aPfxFooter+6, sizeof(aPfxFooter)-9);
2313 // provide details to the subset requesters, TODO: move into own method?
2314 // note: Top and Bottom are flipped between Type1 and VCL
2315 // note: the rest of VCL expects the details below to be scaled like for an emUnits==1000 font
2316 ValType fXFactor = 1.0;
2317 ValType fYFactor = 1.0;
2318 if( maFontMatrix.size() >= 4) {
2319 fXFactor = 1000.0F * maFontMatrix[0];
2320 fYFactor = 1000.0F * maFontMatrix[3];
2322 rFSInfo.m_aFontBBox = Rectangle( Point( static_cast<long>(maFontBBox[0] * fXFactor),
2323 static_cast<long>(maFontBBox[1] * fYFactor) ),
2324 Point( static_cast<long>(maFontBBox[2] * fXFactor),
2325 static_cast<long>(maFontBBox[3] * fYFactor) ) );
2326 // PDF-Spec says the values below mean the ink bounds!
2327 // TODO: use better approximations for these ink bounds
2328 rFSInfo.m_nAscent = +rFSInfo.m_aFontBBox.Bottom(); // for capital letters
2329 rFSInfo.m_nDescent = -rFSInfo.m_aFontBBox.Top(); // for all letters
2330 rFSInfo.m_nCapHeight = rFSInfo.m_nAscent; // for top-flat capital letters
2332 rFSInfo.m_nFontType = rEmitter.mbPfbSubset ? FontSubsetInfo::TYPE1_PFB : FontSubsetInfo::TYPE1_PFA;
2333 rFSInfo.m_aPSName = String( rEmitter.maSubsetName, RTL_TEXTENCODING_UTF8 );
2335 return true;
2338 // ====================================================================
2340 bool FontSubsetInfo::CreateFontSubsetFromCff( GlyphWidth* pOutGlyphWidths )
2342 CffSubsetterContext aCff( mpInFontBytes, mnInByteLength);
2343 aCff.initialCffRead();
2345 // emit Type1 subset from the CFF input
2346 // TODO: also support CFF->CFF subsetting (when PDF-export and PS-printing need it)
2347 const bool bPfbSubset = (0 != (mnReqFontTypeMask & FontSubsetInfo::TYPE1_PFB));
2348 Type1Emitter aType1Emitter( mpOutFile, bPfbSubset);
2349 aType1Emitter.setSubsetName( mpReqFontName);
2350 bool bRC = aCff.emitAsType1( aType1Emitter,
2351 mpReqGlyphIds, mpReqEncodedIds,
2352 pOutGlyphWidths, mnReqGlyphCount, *this);
2353 return bRC;
2356 // ====================================================================
2358 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */