update credits
[LibreOffice.git] / vcl / source / fontsubset / cff.cxx
blob9e2d1d3e44d06821ae95f0ac6c973516a38b57e6
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 .
20 #include <cstdio>
21 #include <cstring>
22 #include <assert.h>
24 #include "fontsubset.hxx"
26 #include <vcl/strhelper.hxx>
28 //#define IGNORE_HINTS
30 typedef unsigned char U8;
31 typedef unsigned short U16;
32 typedef long long S64;
34 typedef sal_Int32 GlyphWidth;
36 typedef float RealType;
37 typedef RealType ValType;
38 #include <vector>
39 typedef std::vector<ValType> ValVector;
41 static const char* pStringIds[] = {
42 /*0*/ ".notdef", "space", "exclam", "quotedbl",
43 "numbersign", "dollar", "percent", "ampersand",
44 "quoteright", "parenleft", "parenright", "asterisk",
45 "plus", "comma", "hyphen", "period",
46 /*16*/ "slash", "zero", "one", "two",
47 "three", "four", "five", "six",
48 "seven", "eight", "nine", "colon",
49 "semicolon", "less", "equal", "greater",
50 /*32*/ "question", "at", "A", "B",
51 "C", "D", "E", "F",
52 "G", "H", "I", "J",
53 "K", "L", "M", "N",
54 /*48*/ "O", "P", "Q", "R",
55 "S", "T", "U", "V",
56 "W", "X", "Y", "Z",
57 "bracketleft", "backslash", "bracketright", "asciicircum",
58 /*64*/ "underscore", "quoteleft", "a", "b",
59 "c", "d", "e", "f",
60 "g", "h", "i", "j",
61 "k", "l", "m", "n",
62 /*80*/ "o", "p", "q", "r",
63 "s", "t", "u", "v",
64 "w", "x", "y", "z",
65 "braceleft", "bar", "braceright", "asciitilde",
66 /*96*/ "exclamdown", "cent", "sterlin", "fraction",
67 "yen", "florin", "section", "currency",
68 "quotesingle", "quotedblleft", "guillemotleft", "guilsinglleft",
69 "guilsinglright", "fi", "fl", "endash",
70 /*112*/ "dagger", "daggerdbl", "periodcentered", "paragraph",
71 "bullet", "quotesinglbase", "quotedblbase", "quotedblright",
72 "guillemotright", "ellipsis", "perthousand", "questiondown",
73 "grave", "acute", "circumflex", "tilde",
74 /*128*/ "macron", "breve", "dotaccent", "dieresis",
75 "ring", "cedilla", "hungarumlaut", "ogonek",
76 "caron", "emdash", "AE", "ordfeminine",
77 "Lslash", "Oslash", "OE", "ordmasculine",
78 /*144*/ "ae", "dotlessi", "lslash", "oslash",
79 "oe", "germandbls", "onesuperior", "logicalnot",
80 "mu", "trademark", "Eth", "onehalf",
81 "plusminus", "Thorn", "onequarter", "divide",
82 /*160*/ "brokenbar", "degree", "thorn", "threequarters",
83 "twosuperior", "registered", "minus", "eth",
84 "multiply", "threesuperior", "copyright", "Aacute",
85 "Acircumflex", "Adieresis", "Agrave", "Aring",
86 /*176*/ "Atilde", "Ccedilla", "Eacute", "Ecircumflex",
87 "Edieresis", "Egrave", "Iacute", "Icircumflex",
88 "Idieresis", "Igrave", "Ntilde", "Oacute",
89 "Ocircumflex", "Odieresis", "Ograve", "Otilde",
90 /*192*/ "Scaron", "Uacute", "Ucircumflex", "Udieresis",
91 "Ugrave", "Yacute", "Ydieresis", "Zcaron",
92 "aacute", "acircumflex", "adieresis", "agrave",
93 "aring", "atilde", "ccedilla", "eacute",
94 /*208*/ "ecircumflex", "edieresis", "egrave", "iacute",
95 "icircumflex", "idieresis", "igrave", "ntilde",
96 "oacute", "ocircumflex", "odieresis", "ograve",
97 "otilde", "scaron", "uacute", "ucircumflex",
98 /*224*/ "udieresis", "ugrave", "yacute", "ydieresis",
99 "zcaron", "exclamsmall", "Hungarumlautsmall","dollaroldstyle",
100 "dollarsuperior", "ampersandsmall", "Acutesmall", "parenleftsuperior",
101 "parenrightsuperior","twodotenleader", "onedotenleader", "zerooldstyle",
102 /*240*/ "oneoldstyle", "twooldstyle", "threeoldstyle", "fouroldstyle",
103 "fiveoldstyle", "sixoldstyle", "sevenoldstyle", "eightoldstyle",
104 "nineoldstile", "commasuperior", "threequartersemdash","periodsuperior",
105 "questionsmall", "asuperior", "bsuperior", "centsuperior",
106 /*256*/ "dsuperior", "esuperior", "isuperior", "lsuperior",
107 "msuperior", "nsuperior", "osuperior", "rsuperior",
108 "ssuperior", "tsuperior", "ff", "ffi",
109 "ffl", "parenleftinferior","parenrightinferior","Circumflexsmall",
110 /*272*/ "hyphensuperior","Gravesmall", "Asmall", "Bsmall",
111 "Csmall", "Dsmall", "Esmall", "Fsmall",
112 "Gsmall", "Hsmall", "Ismall", "Jsmall",
113 "Ksmall", "Lsmall", "Msmall", "Nsmall",
114 /*288*/ "Osmall", "Psmall", "Qsmall", "Rsmall",
115 "Ssmall", "Tsmall", "Usmall", "Vsmall",
116 "Wsmall", "Xsmall", "Ysmall", "Zsmall",
117 "colonmonetary", "onefitted", "rupia", "Tildesmall",
118 /*304*/ "exclamdownsmall","centoldstyle", "Lslashsmall", "Scaronsmall",
119 "Zcaronsmall", "Dieresissmall", "Brevesmall", "Caronsmall",
120 "Dotaccentsmall", "Macronsmall", "figuredash", "hypheninferior",
121 "Ogoneksmall", "Ringsmall", "Cedillasmall", "questiondownsmall",
122 /*320*/ "oneeight", "threeeights", "fiveeights", "seveneights",
123 "onethird", "twothirds", "zerosuperior", "foursuperior",
124 "fivesuperior", "sixsuperior", "sevensuperior", "eightsuperior",
125 "ninesuperior", "zeroinferior", "oneinferior", "twoinferior",
126 /*336*/ "threeinferior","fourinferior", "fiveinferior", "sixinferior",
127 "seveninferior", "eightinferior", "nineinferior", "centinferior",
128 "dollarinferior", "periodinferior", "commainferior", "Agravesmall",
129 "Aacutesmall", "Acircumflexsmall", "Atildesmall", "Adieresissmall",
130 /*352*/ "Aringsmall", "AEsmall", "Ccedillasmall", "Egravesmall",
131 "Eacutesmall", "Ecircumflexsmall", "Edieresissmall", "Igravesmall",
132 "Iacutesmall", "Icircumflexsmall", "Idieresissmall", "Ethsmall",
133 "Ntildesmall", "Ogravesmall", "Oacutesmall", "Ocircumflexsmall",
134 /*368*/ "Otildesmall", "Odieressissmall", "OEsmall", "Oslashsmall",
135 "Ugravesmall", "Uacutesmall", "Ucircumflexsmall", "Udieresissmall",
136 "Yacutesmall", "Thornsmall", "Ydieresissmall", "001.000",
137 "001.001", "001.002", "001.003", "Black",
138 /*384*/ "Bold", "Book", "Light", "Medium",
139 "Regular", "Roman", "Semibold"
142 // TOP DICT keywords (also covers PRIV DICT keywords)
143 static const char* pDictOps[] = {
144 "sVersion", "sNotice", "sFullName", "sFamilyName",
145 "sWeight", "aFontBBox", "dBlueValues", "dOtherBlues",
146 "dFamilyBlues", "dFamilyOtherBlues", "nStdHW", "nStdVW",
147 "xESC", "nUniqueID", "aXUID", "nCharset",
148 "nEncoding", "nCharStrings", "PPrivate", "nSubrs",
149 "nDefaultWidthX", "nNominalWidthX", NULL, NULL,
150 NULL, NULL, NULL, NULL,
151 "shortint", "longint", "BCD", NULL
154 // TOP DICT escapes (also covers PRIV DICT escapes)
155 static const char* pDictEscs[] = {
156 "sCopyright", "bIsFixedPitch", "nItalicAngle", "nUnderlinePosition",
157 "nUnderlineThickness", "nPaintType", "tCharstringType", "aFontMatrix",
158 "nStrokeWidth", "nBlueScale", "nBlueShift", "nBlueFuzz",
159 "dStemSnapH", "dStemSnapV", "bForceBold", NULL,
160 NULL, "nLanguageGroup", "nExpansionFactor", "nInitialRandomSeed",
161 "nSyntheticBase", "sPostScript", "sBaseFontName", "dBaseFontBlend",
162 NULL, NULL, NULL, NULL,
163 NULL, NULL, "rROS", "nCIDFontVersion",
164 "nCIDFontRevision", "nCIDFontType", "nCIDCount", "nUIDBase",
165 "nFDArray", "nFDSelect", "sFontName"
168 static const char* pType1Ops[] = {
169 NULL, "2hstem", NULL, "2vstem",
170 "1vmoveto", "Arlineto", "1hlineto", "1vlineto",
171 "Crrcurveto", "0closepath", "Lcallsubr", "0return",
172 "xT1ESC", "2hsbw", "0endchar", NULL,
173 NULL, NULL, NULL, NULL,
174 NULL, "2rmoveto", "1hmoveto", NULL,
175 NULL, NULL, NULL, NULL,
176 NULL, NULL, "4vhcurveto", "4hvcurveto"
179 static const char* pT1EscOps[] = {
180 "0dotsection", "6vstem3", "6hstem3", NULL,
181 NULL, NULL, "5seac", "4sbw",
182 NULL, "1abs", "2add", "2sub",
183 "2div", NULL, NULL, NULL,
184 "Gcallothersubr", "1pop", NULL, NULL,
185 NULL, NULL, NULL, NULL,
186 NULL, NULL, NULL, NULL,
187 NULL, NULL, NULL, NULL,
188 NULL, "2setcurrentpoint"
191 struct TYPE1OP
193 enum OPS
195 HSTEM=1, VSTEM=3, VMOVETO=4, RLINETO=5,
196 HLINETO=6, VLINETO=7, RCURVETO=8, CLOSEPATH=9,
197 CALLSUBR=10, RETURN=11, T1ESC=12, HSBW=13,
198 ENDCHAR=14, RMOVETO=21, HMOVETO=22, VHCURVETO=30,
199 HVCURVETO=31
202 enum ESCS
204 DOTSECTION=0, VSTEM3=1, HSTEM3=2, SEAC=6,
205 SBW=7, ABS=9, ADD=10, SUB=11,
206 DIV=12, CALLOTHERSUBR=16, POP=17, SETCURRENTPOINT=33
210 static const char* pType2Ops[] = {
211 NULL, "hhstem", NULL, "vvstem",
212 "mvmoveto", "Arlineto", "Ehlineto", "Evlineto",
213 "Crrcurveto", NULL, "Lcallsubr", "Xreturn",
214 "xT2ESC", NULL, "eendchar", NULL,
215 NULL, NULL, "Hhstemhm", "Khintmask",
216 "Kcntrmask", "Mrmoveto", "mhmoveto", "Vvstemhm",
217 ".rcurveline", ".rlinecurve", ".vvcurveto", ".hhcurveto",
218 ".shortint", "Gcallgsubr", ".vhcurveto", ".hvcurveto"
221 static const char* pT2EscOps[] = {
222 NULL, NULL, NULL, "2and",
223 "2or", "1not", NULL, NULL,
224 NULL, "1abs", "2add", "2sub",
225 "2div", NULL, "1neg", "2eq",
226 NULL, NULL, "1drop", NULL,
227 "1put", "1get", "4ifelse", "0random",
228 "2mul", NULL, "1sqrt", "1dup",
229 "2exch", "Iindex", "Rroll", NULL,
230 NULL, NULL, "7hflex", "Fflex",
231 "9hflex1", "fflex1"
234 struct TYPE2OP
236 enum OPS
238 HSTEM=1, VSTEM=3, VMOVETO=4, RLINETO=5,
239 HLINETO=6, VLINETO=7, RCURVETO=8, CALLSUBR=10,
240 RETURN=11, T2ESC=12, ENDCHAR=14, HSTEMHM=18,
241 HINTMASK=19, CNTRMASK=20, RMOVETO=21, HMOVETO=22,
242 VSTEMHM=23, RCURVELINE=24, RLINECURVE=25, VVCURVETO=26,
243 HHCURVETO=27, SHORTINT=28, CALLGSUBR=29, VHCURVETO=30,
244 HVCURVETO=31
247 enum ESCS
249 AND=3, OR=4, NOT=5, ABS=9,
250 ADD=10, SUB=11, DIV=12, NEG=14,
251 EQ=15, DROP=18, PUT=20, GET=21,
252 IFELSE=22, RANDOM=23, MUL=24, SQRT=26,
253 DUP=27, EXCH=28, INDEX=29, ROLL=30,
254 HFLEX=34, FLEX=35, HFLEX1=36, FLEX1=37
258 struct CffGlobal
260 explicit CffGlobal();
262 int mnNameIdxBase;
263 int mnNameIdxCount;
264 int mnStringIdxBase;
265 int mnStringIdxCount;
266 bool mbCIDFont;
267 int mnCharStrBase;
268 int mnCharStrCount;
269 int mnEncodingBase;
270 int mnCharsetBase;
271 int mnGlobalSubrBase;
272 int mnGlobalSubrCount;
273 int mnGlobalSubrBias;
274 int mnFDSelectBase;
275 int mnFontDictBase;
276 int mnFDAryCount;
278 ValVector maFontBBox;
279 ValVector maFontMatrix;
281 int mnFontNameSID;
282 int mnFullNameSID;
283 int mnFamilyNameSID;
286 struct CffLocal
288 explicit CffLocal();
290 int mnPrivDictBase;
291 int mnPrivDictSize;
292 int mnLocalSubrOffs;
293 int mnLocalSubrBase;
294 int mnLocalSubrCount;
295 int mnLocalSubrBias;
297 ValType maNominalWidth;
298 ValType maDefaultWidth;
300 // ATM hinting related values
301 ValType maStemStdHW;
302 ValType maStemStdVW;
303 ValVector maStemSnapH;
304 ValVector maStemSnapV;
305 ValVector maBlueValues;
306 ValVector maOtherBlues;
307 ValVector maFamilyBlues;
308 ValVector maFamilyOtherBlues;
309 RealType mfBlueScale;
310 RealType mfBlueShift;
311 RealType mfBlueFuzz;
312 RealType mfExpFactor;
313 int mnLangGroup;
314 bool mbForceBold;
317 class CffSubsetterContext
318 : private CffGlobal
320 public:
321 static const int NMAXSTACK = 48; // see CFF.appendixB
322 static const int NMAXHINTS = 2*96; // see CFF.appendixB
323 static const int NMAXTRANS = 32; // see CFF.appendixB
324 public:
325 explicit CffSubsetterContext( const U8* pBasePtr, int nBaseLen);
326 ~CffSubsetterContext();
328 bool initialCffRead();
329 bool emitAsType1( class Type1Emitter&,
330 const sal_GlyphId* pGlyphIds, const U8* pEncoding,
331 GlyphWidth* pGlyphWidths, int nGlyphCount, FontSubsetInfo& );
333 // used by charstring converter
334 void setCharStringType( int);
335 protected:
336 int convert2Type1Ops( CffLocal*, const U8* pType2Ops, int nType2Len, U8* pType1Ops);
337 private:
338 void convertOneTypeOp();
339 void convertOneTypeEsc();
340 void callType2Subr( bool bGlobal, int nSubrNumber);
341 sal_Int32 getReadOfs() const { return (sal_Int32)(mpReadPtr - mpBasePtr);}
343 const U8* mpBasePtr;
344 const U8* mpBaseEnd;
346 const U8* mpReadPtr;
347 const U8* mpReadEnd;
349 U8* mpWritePtr;
350 bool mbSawError;
351 bool mbNeedClose;
352 bool mbIgnoreHints;
353 sal_Int32 mnCntrMask;
355 private:
356 int seekIndexData( int nIndexBase, int nDataIndex);
357 void seekIndexEnd( int nIndexBase);
359 private:
360 const char** mpCharStringOps;
361 const char** mpCharStringEscs;
363 CffLocal maCffLocal[256];
364 CffLocal* mpCffLocal;
366 void readDictOp();
367 RealType readRealVal();
368 const char* getString( int nStringID);
369 int getFDSelect( int nGlyphIndex) const;
370 int getGlyphSID( int nGlyphIndex) const;
371 const char* getGlyphName( int nGlyphIndex);
373 void read2push();
374 void writeType1Val( ValType);
375 void writeTypeOp( int nTypeOp);
376 void writeTypeEsc( int nTypeOp);
377 void writeCurveTo( int nStackPos, int nIX1, int nIY1, int nIX2, int nIY2, int nIX3, int nIY3);
378 void pop2MultiWrite( int nArgsPerTypo, int nTypeOp, int nTypeXor=0);
379 void popAll2Write( int nTypeOp);
381 public: // TODO: is public really needed?
382 // accessing the value stack
383 // TODO: add more checks
384 void push( ValType nVal) { mnValStack[ mnStackIdx++] = nVal;}
385 ValType popVal() { return ((mnStackIdx>0) ? mnValStack[ --mnStackIdx] : 0);}
386 ValType getVal( int nIndex) const { return mnValStack[ nIndex];}
387 int popInt();
388 int size() const { return mnStackIdx;}
389 void clear() { mnStackIdx = 0;}
391 // accessing the charstring hints
392 void addHints( bool bVerticalHints);
394 // accessing other charstring specifics
395 bool hasCharWidth() const { return (maCharWidth > 0);}
396 ValType getCharWidth() const { return maCharWidth;}
397 void setNominalWidth( ValType aWidth) { mpCffLocal->maNominalWidth = aWidth;}
398 void setDefaultWidth( ValType aWidth) { mpCffLocal->maDefaultWidth = aWidth;}
399 void updateWidth( bool bUseFirstVal);
401 private:
402 // typeop exceution context
403 int mnStackIdx;
404 ValType mnValStack[ NMAXSTACK+4];
405 ValType mnTransVals[ NMAXTRANS];
407 int mnHintSize;
408 int mnHorzHintSize;
409 ValType mnHintStack[ NMAXHINTS];
411 ValType maCharWidth;
414 CffSubsetterContext::CffSubsetterContext( const U8* pBasePtr, int nBaseLen)
415 : mpBasePtr( pBasePtr)
416 , mpBaseEnd( pBasePtr+nBaseLen)
417 , mpReadPtr(NULL)
418 , mpReadEnd(NULL)
419 , mpWritePtr(NULL)
420 , mbSawError(false)
421 , mbNeedClose(false)
422 , mbIgnoreHints(false)
423 , mnCntrMask(0)
424 , mpCharStringOps(NULL)
425 , mpCharStringEscs(NULL)
426 , mnStackIdx(0)
427 , mnHintSize(0)
428 , mnHorzHintSize(0)
429 , maCharWidth(-1)
431 // setCharStringType( 1);
432 // TODO: new CffLocal[ mnFDAryCount];
433 mpCffLocal = &maCffLocal[0];
436 CffSubsetterContext::~CffSubsetterContext()
438 // TODO: delete[] maCffLocal;
441 inline int CffSubsetterContext::popInt()
443 const ValType aVal = popVal();
444 const int nInt = static_cast<int>(aVal);
445 assert( nInt == aVal);
446 return nInt;
449 inline void CffSubsetterContext::updateWidth( bool bUseFirstVal)
451 #if 1 // TODO: is this still needed?
452 // the first value is not a hint but the charwidth
453 if( hasCharWidth())
454 return;
455 #endif
456 if( bUseFirstVal) {
457 maCharWidth = mpCffLocal->maNominalWidth + mnValStack[0];
458 // remove bottom stack entry
459 --mnStackIdx;
460 for( int i = 0; i < mnStackIdx; ++i)
461 mnValStack[ i] = mnValStack[ i+1];
462 } else {
463 maCharWidth = mpCffLocal->maDefaultWidth;
467 void CffSubsetterContext::addHints( bool bVerticalHints)
469 // the first charstring value may a charwidth instead of a charwidth
470 updateWidth( (mnStackIdx & 1) != 0);
471 // return early (e.g. no implicit hints for hintmask)
472 if( !mnStackIdx)
473 return;
475 // copy the remaining values to the hint arrays
476 // assert( (mnStackIdx & 1) == 0); // depends on called subrs
477 if( mnStackIdx & 1) --mnStackIdx;//#######
478 // TODO: if( !bSubr) assert( mnStackIdx >= 2);
480 assert( (mnHintSize + mnStackIdx) <= 2*NMAXHINTS);
482 #ifdef IGNORE_HINTS
483 mnHintSize += mnStackIdx;
484 #else
485 ValType nHintOfs = 0;
486 for( int i = 0; i < mnStackIdx; ++i) {
487 nHintOfs += mnValStack[ i ];
488 mnHintStack[ mnHintSize++] = nHintOfs;
490 #endif // IGNORE_HINTS
491 if( !bVerticalHints)
492 mnHorzHintSize = mnHintSize;
494 // clear all values from the stack
495 mnStackIdx = 0;
498 void CffSubsetterContext::setCharStringType( int nVal)
500 switch( nVal) {
501 case 1: mpCharStringOps=pType1Ops; mpCharStringEscs=pT1EscOps; break;
502 case 2: mpCharStringOps=pType2Ops; mpCharStringEscs=pT2EscOps; break;
503 default: fprintf( stderr, "Unknown CharstringType=%d\n",nVal); break;
507 void CffSubsetterContext::readDictOp()
509 ValType nVal = 0;
510 const U8 c = *mpReadPtr;
511 if( c <= 21 ) {
512 int nOpId = *(mpReadPtr++);
513 const char* pCmdName = 0;
514 if( nOpId != 12)
515 pCmdName = pDictOps[nOpId];
516 else {
517 const U8 nExtId = *(mpReadPtr++);
518 if (nExtId < 39)
519 pCmdName = pDictEscs[nExtId];
520 nOpId = 900 + nExtId;
523 if (!pCmdName) // skip reserved operators
524 return;
526 //TODO: if( nStackIdx > 0)
527 int nInt = 0;
528 switch( *pCmdName) {
529 default: fprintf( stderr, "unsupported DictOp.type=\'%c\'\n", *pCmdName); break;
530 case 'b': // bool
531 nInt = popInt();
532 switch( nOpId) {
533 case 915: mpCffLocal->mbForceBold = nInt; break; // "ForceBold"
534 default: break; // TODO: handle more boolean dictops?
536 break;
537 case 'n': // dict-op number
538 nVal = popVal();
539 nInt = static_cast<int>(nVal);
540 switch( nOpId) {
541 case 10: mpCffLocal->maStemStdHW = nVal; break; // "StdHW"
542 case 11: mpCffLocal->maStemStdVW = nVal; break; // "StdVW"
543 case 15: mnCharsetBase = nInt; break; // "charset"
544 case 16: mnEncodingBase = nInt; break; // "nEncoding"
545 case 17: mnCharStrBase = nInt; break; // "nCharStrings"
546 case 19: mpCffLocal->mnLocalSubrOffs = nInt; break;// "nSubrs"
547 case 20: setDefaultWidth( nVal ); break; // "defaultWidthX"
548 case 21: setNominalWidth( nVal ); break; // "nominalWidthX"
549 case 909: mpCffLocal->mfBlueScale = nVal; break; // "BlueScale"
550 case 910: mpCffLocal->mfBlueShift = nVal; break; // "BlueShift"
551 case 911: mpCffLocal->mfBlueFuzz = nVal; break; // "BlueFuzz"
552 case 912: mpCffLocal->mfExpFactor = nVal; break; // "ExpansionFactor"
553 case 917: mpCffLocal->mnLangGroup = nInt; break; // "LanguageGroup"
554 case 936: mnFontDictBase = nInt; break; // "nFDArray"
555 case 937: mnFDSelectBase = nInt; break; // "nFDSelect"
556 default: break; // TODO: handle more numeric dictops?
558 break;
559 case 'a': { // array
560 switch( nOpId) {
561 case 5: maFontBBox.clear(); break; // "FontBBox"
562 case 907: maFontMatrix.clear(); break; // "FontMatrix"
563 default: break; // TODO: reset other arrays?
565 for( int i = 0; i < size(); ++i ) {
566 nVal = getVal(i);
567 switch( nOpId) {
568 case 5: maFontBBox.push_back( nVal); break; // "FontBBox"
569 case 907: maFontMatrix.push_back( nVal); break; // "FontMatrix"
570 default: break; // TODO: handle more array dictops?
573 clear();
574 } break;
575 case 'd': { // delta array
576 nVal = 0;
577 for( int i = 0; i < size(); ++i ) {
578 nVal += getVal(i);
579 switch( nOpId) {
580 case 6: mpCffLocal->maBlueValues.push_back( nVal); break; // "BlueValues"
581 case 7: mpCffLocal->maOtherBlues.push_back( nVal); break; // "OtherBlues"
582 case 8: mpCffLocal->maFamilyBlues.push_back( nVal); break; // "FamilyBlues"
583 case 9: mpCffLocal->maFamilyOtherBlues.push_back( nVal); break;// "FamilyOtherBlues"
584 case 912: mpCffLocal->maStemSnapH.push_back( nVal); break; // "StemSnapH"
585 case 913: mpCffLocal->maStemSnapV.push_back( nVal); break; // "StemSnapV"
586 default: break; // TODO: handle more delta-array dictops?
589 clear();
590 } break;
591 case 's': // stringid (SID)
592 nInt = popInt();
593 switch( nOpId ) {
594 case 2: mnFullNameSID = nInt; break; // "FullName"
595 case 3: mnFamilyNameSID = nInt; break; // "FamilyName"
596 case 938: mnFontNameSID = nInt; break; // "FontName"
597 default: break; // TODO: handle more string dictops?
599 break;
600 case 'P': // private dict
601 mpCffLocal->mnPrivDictBase = popInt();
602 mpCffLocal->mnPrivDictSize = popInt();
603 break;
604 case 'r': { // ROS operands
605 int nSid1 = popInt();
606 int nSid2 = popInt();
607 (void)nSid1; // TODO: use
608 (void)nSid2; // TODO: use
609 nVal = popVal();
610 mbCIDFont = true;
611 } break;
612 case 't': // CharstringType
613 nInt = popInt();
614 setCharStringType( nInt );
615 break;
618 return;
621 if( (c >= 32) || (c == 28) ) {
622 // --mpReadPtr;
623 read2push();
624 } else if( c == 29 ) { // longint
625 ++mpReadPtr; // skip 29
626 int nS32 = mpReadPtr[0] << 24;
627 nS32 += mpReadPtr[1] << 16;
628 nS32 += mpReadPtr[2] << 8;
629 nS32 += mpReadPtr[3] << 0;
630 if( (sizeof(nS32) != 4) && (nS32 & (1U<<31)))
631 nS32 |= (~0U) << 31; // assuming 2s complement
632 mpReadPtr += 4;
633 nVal = static_cast<ValType>(nS32);
634 push( nVal );
635 } else if( c == 30) { // real number
636 ++mpReadPtr; // skip 30
637 const RealType fReal = readRealVal();
638 // push value onto stack
639 nVal = fReal;
640 push( nVal);
644 void CffSubsetterContext::read2push()
646 ValType aVal = 0;
648 const U8*& p = mpReadPtr;
649 const U8 c = *p;
650 if( c == 28 ) {
651 short nS16 = (p[1] << 8) + p[2];
652 if( (sizeof(nS16) != 2) && (nS16 & (1<<15)))
653 nS16 |= (~0U) << 15; // assuming 2s complement
654 aVal = nS16;
655 p += 3;
656 } else if( c <= 246 ) { // -107..+107
657 aVal = static_cast<ValType>(p[0] - 139);
658 p += 1;
659 } else if( c <= 250 ) { // +108..+1131
660 aVal = static_cast<ValType>(((p[0] << 8) + p[1]) - 63124);
661 p += 2;
662 } else if( c <= 254 ) { // -108..-1131
663 aVal = static_cast<ValType>(64148 - ((p[0] << 8) + p[1]));
664 p += 2;
665 } else /*if( c == 255)*/ { // Fixed16.16
666 int nS32 = (p[1] << 24) + (p[2] << 16) + (p[3] << 8) + p[4];
667 if( (sizeof(nS32) != 2) && (nS32 & (1U<<31)))
668 nS32 |= (~0U) << 31; // assuming 2s complement
669 aVal = static_cast<ValType>(nS32 * (1.0 / 0x10000));
670 p += 5;
673 push( aVal);
676 void CffSubsetterContext::writeType1Val( ValType aVal)
678 U8* pOut = mpWritePtr;
680 int nInt = static_cast<int>(aVal);
681 if( (nInt >= -107) && (nInt <= +107)) {
682 *(pOut++) = static_cast<U8>(nInt + 139); // -107..+107
683 } else if( (nInt >= -1131) && (nInt <= +1131)) {
684 if( nInt >= 0)
685 nInt += 63124; // +108..+1131
686 else
687 nInt = 64148 - nInt; // -108..-1131
688 *(pOut++) = static_cast<U8>(nInt >> 8);
689 *(pOut++) = static_cast<U8>(nInt);
690 } else {
691 // numtype==255 means int32 for Type1, but 16.16 for Type2 charstrings!!!
692 *(pOut++) = 255;
693 *(pOut++) = static_cast<U8>(nInt >> 24);
694 *(pOut++) = static_cast<U8>(nInt >> 16);
695 *(pOut++) = static_cast<U8>(nInt >> 8);
696 *(pOut++) = static_cast<U8>(nInt);
699 mpWritePtr = pOut;
702 inline void CffSubsetterContext::writeTypeOp( int nTypeOp)
704 *(mpWritePtr++) = static_cast<U8>(nTypeOp);
707 inline void CffSubsetterContext::writeTypeEsc( int nTypeEsc)
709 *(mpWritePtr++) = TYPE1OP::T1ESC;
710 *(mpWritePtr++) = static_cast<U8>(nTypeEsc);
713 void CffSubsetterContext::pop2MultiWrite( int nArgsPerTypo, int nTypeOp, int nTypeXor)
715 for( int i = 0; i < mnStackIdx;) {
716 for( int j = 0; j < nArgsPerTypo; ++j) {
717 const ValType aVal = mnValStack[i+j];
718 writeType1Val( aVal);
720 i += nArgsPerTypo;
721 writeTypeOp( nTypeOp);
722 nTypeOp ^= nTypeXor; // for toggling vlineto/hlineto
724 clear();
727 void CffSubsetterContext::popAll2Write( int nTypeOp)
729 // pop in reverse order, then write
730 for( int i = 0; i < mnStackIdx; ++i) {
731 const ValType aVal = mnValStack[i];
732 writeType1Val( aVal);
734 clear();
735 writeTypeOp( nTypeOp);
738 void CffSubsetterContext::writeCurveTo( int nStackPos,
739 int nIX1, int nIY1, int nIX2, int nIY2, int nIX3, int nIY3)
741 // get the values from the stack
742 const ValType nDX1 = nIX1 ? mnValStack[ nStackPos+nIX1 ] : 0;
743 const ValType nDY1 = nIY1 ? mnValStack[ nStackPos+nIY1 ] : 0;
744 const ValType nDX2 = nIX2 ? mnValStack[ nStackPos+nIX2 ] : 0;
745 const ValType nDY2 = nIY2 ? mnValStack[ nStackPos+nIY2 ] : 0;
746 const ValType nDX3 = nIX3 ? mnValStack[ nStackPos+nIX3 ] : 0;
747 const ValType nDY3 = nIY3 ? mnValStack[ nStackPos+nIY3 ] : 0;
749 // emit the curveto operator and operands
750 // TODO: determine the most efficient curveto operator
751 // TODO: depending on type1op or type2op target
752 writeType1Val( nDX1 );
753 writeType1Val( nDY1 );
754 writeType1Val( nDX2 );
755 writeType1Val( nDY2 );
756 writeType1Val( nDX3 );
757 writeType1Val( nDY3 );
758 writeTypeOp( TYPE1OP::RCURVETO );
761 void CffSubsetterContext::convertOneTypeOp()
763 const int nType2Op = *(mpReadPtr++);
765 int i, nInt; // prevent WAE for declarations inside switch cases
766 // convert each T2op
767 switch( nType2Op) {
768 case TYPE2OP::T2ESC:
769 convertOneTypeEsc();
770 break;
771 case TYPE2OP::HSTEM:
772 case TYPE2OP::VSTEM:
773 addHints( nType2Op == TYPE2OP::VSTEM );
774 #ifndef IGNORE_HINTS
775 for( i = 0; i < mnHintSize; i+=2 ) {
776 writeType1Val( mnHintStack[i]);
777 writeType1Val( mnHintStack[i+1] - mnHintStack[i]);
778 writeTypeOp( nType2Op );
780 #endif // IGNORE_HINTS
781 break;
782 case TYPE2OP::HSTEMHM:
783 case TYPE2OP::VSTEMHM:
784 addHints( nType2Op == TYPE2OP::VSTEMHM);
785 break;
786 case TYPE2OP::CNTRMASK:
787 // TODO: replace cntrmask with vstem3/hstem3
788 addHints( true);
789 #ifdef IGNORE_HINTS
790 mpReadPtr += (mnHintSize + 15) / 16;
791 mbIgnoreHints = true;
792 #else
794 U8 nMaskBit = 0;
795 U8 nMaskByte = 0;
796 for( i = 0; i < mnHintSize; i+=2, nMaskBit>>=1) {
797 if( !nMaskBit) {
798 nMaskByte = *(mpReadPtr++);
799 nMaskBit = 0x80;
801 if( !(nMaskByte & nMaskBit))
802 continue;
803 if( i >= 8*(int)sizeof(mnCntrMask))
804 mbIgnoreHints = true;
805 if( mbIgnoreHints)
806 continue;
807 mnCntrMask |= (1U << i);
810 #endif
811 break;
812 case TYPE2OP::HINTMASK:
813 addHints( true);
814 #ifdef IGNORE_HINTS
815 mpReadPtr += (mnHintSize + 15) / 16;
816 #else
818 sal_Int32 nHintMask = 0;
819 int nCntrBits[2] = {0,0};
820 U8 nMaskBit = 0;
821 U8 nMaskByte = 0;
822 for( i = 0; i < mnHintSize; i+=2, nMaskBit>>=1) {
823 if( !nMaskBit) {
824 nMaskByte = *(mpReadPtr++);
825 nMaskBit = 0x80;
827 if( !(nMaskByte & nMaskBit))
828 continue;
829 if( i >= 8*(int)sizeof(nHintMask))
830 mbIgnoreHints = true;
831 if( mbIgnoreHints)
832 continue;
833 nHintMask |= (1U << i);
834 nCntrBits[ i < mnHorzHintSize] += (mnCntrMask >> i) & 1;
837 mbIgnoreHints |= (nCntrBits[0] && (nCntrBits[0] != 3));
838 mbIgnoreHints |= (nCntrBits[1] && (nCntrBits[1] != 3));
839 if( mbIgnoreHints)
840 break;
842 for( i = 0; i < mnHintSize; i+=2) {
843 if( !(nHintMask & (1U << i)))
844 continue;
845 writeType1Val( mnHintStack[i]);
846 writeType1Val( mnHintStack[i+1] - mnHintStack[i]);
847 const bool bHorz = (i < mnHorzHintSize);
848 if( !nCntrBits[ bHorz])
849 writeTypeOp( bHorz ? TYPE1OP::HSTEM : TYPE1OP::VSTEM);
850 else if( !--nCntrBits[ bHorz])
851 writeTypeEsc( bHorz ? TYPE1OP::HSTEM3 : TYPE1OP::VSTEM3);
854 #endif
855 break;
856 case TYPE2OP::CALLSUBR:
857 case TYPE2OP::CALLGSUBR:
859 nInt = popInt();
860 const bool bGlobal = (nType2Op == TYPE2OP::CALLGSUBR);
861 callType2Subr( bGlobal, nInt);
863 break;
864 case TYPE2OP::RETURN:
865 // TODO: check that we are in a subroutine
866 return;
867 case TYPE2OP::VMOVETO:
868 case TYPE2OP::HMOVETO:
869 if( mbNeedClose)
870 writeTypeOp( TYPE1OP::CLOSEPATH);
871 else
872 updateWidth( size() > 1);
873 mbNeedClose = true;
874 pop2MultiWrite( 1, nType2Op);
875 break;
876 case TYPE2OP::VLINETO:
877 case TYPE2OP::HLINETO:
878 pop2MultiWrite( 1, nType2Op,
879 TYPE1OP::VLINETO ^ TYPE1OP::HLINETO);
880 break;
881 case TYPE2OP::RMOVETO:
882 // TODO: convert rmoveto to vlineto/hlineto if possible
883 if( mbNeedClose)
884 writeTypeOp( TYPE1OP::CLOSEPATH);
885 else
886 updateWidth( size() > 2);
887 mbNeedClose = true;
888 pop2MultiWrite( 2, nType2Op);
889 break;
890 case TYPE2OP::RLINETO:
891 // TODO: convert rlineto to vlineto/hlineto if possible
892 pop2MultiWrite( 2, nType2Op);
893 break;
894 case TYPE2OP::RCURVETO:
895 // TODO: convert rcurveto to vh/hv/hh/vv-curveto if possible
896 pop2MultiWrite( 6, nType2Op);
897 break;
898 case TYPE2OP::RCURVELINE:
899 i = 0;
900 while( (i += 6) <= mnStackIdx)
901 writeCurveTo( i, -6, -5, -4, -3, -2, -1 );
902 i -= 6;
903 while( (i += 2) <= mnStackIdx) {
904 writeType1Val( mnValStack[i-2]);
905 writeType1Val( mnValStack[i-1]);
906 writeTypeOp( TYPE2OP::RLINETO);
908 clear();
909 break;
910 case TYPE2OP::RLINECURVE:
911 i = 0;
912 while( (i += 2) <= mnStackIdx-6) {
913 writeType1Val( mnValStack[i-2]);
914 writeType1Val( mnValStack[i-1]);
915 writeTypeOp( TYPE2OP::RLINETO);
917 i -= 2;
918 while( (i += 6) <= mnStackIdx)
919 writeCurveTo( i, -6, -5, -4, -3, -2, -1 );
920 clear();
921 break;
922 case TYPE2OP::VHCURVETO:
923 case TYPE2OP::HVCURVETO:
925 bool bVert = (nType2Op == TYPE2OP::VHCURVETO);
926 i = 0;
927 nInt = 0;
928 if( mnStackIdx & 1 )
929 nInt = static_cast<int>(mnValStack[ --mnStackIdx ]);
930 while( (i += 4) <= mnStackIdx) {
931 // TODO: use writeCurveTo()
932 if( bVert ) writeType1Val( 0 );
933 writeType1Val( mnValStack[i-4] );
934 if( !bVert ) writeType1Val( 0);
935 writeType1Val( mnValStack[i-3] );
936 writeType1Val( mnValStack[i-2] );
937 if( !bVert ) writeType1Val( static_cast<ValType>((i==mnStackIdx) ? nInt : 0) );
938 writeType1Val( mnValStack[i-1] );
939 if( bVert ) writeType1Val( static_cast<ValType>((i==mnStackIdx) ? nInt : 0) );
940 bVert = !bVert;
941 writeTypeOp( TYPE2OP::RCURVETO);
944 clear();
945 break;
946 case TYPE2OP::HHCURVETO:
947 i = (mnStackIdx & 1);
948 while( (i += 4) <= mnStackIdx) {
949 if( i != 5)
950 writeCurveTo( i, -4, 0, -3, -2, -1, 0);
951 else
952 writeCurveTo( i, -4, -5, -3, -2, -1, 0);
954 clear();
955 break;
956 case TYPE2OP::VVCURVETO:
957 i = (mnStackIdx & 1);
958 while( (i += 4) <= mnStackIdx) {
959 if( i != 5)
960 writeCurveTo( i, 0, -4, -3, -2, 0, -1);
961 else
962 writeCurveTo( i, -5, -4, -3, -2, 0, -1);
964 clear();
965 break;
966 case TYPE2OP::ENDCHAR:
967 if( mbNeedClose)
968 writeTypeOp( TYPE1OP::CLOSEPATH);
969 else
970 updateWidth( size() >= 1);
971 // mbNeedClose = true;
972 writeTypeOp( TYPE1OP::ENDCHAR);
973 break;
974 default:
975 if( ((nType2Op >= 32) && (nType2Op <= 255)) || (nType2Op == 28)) {
976 --mpReadPtr;
977 read2push();
978 } else {
979 popAll2Write( nType2Op);
980 assert(false && "TODO?");
982 break;
986 void CffSubsetterContext::convertOneTypeEsc()
988 const int nType2Esc = *(mpReadPtr++);
989 ValType* pTop = &mnValStack[ mnStackIdx-1];
990 // convert each T2op
991 switch( nType2Esc) {
992 case TYPE2OP::AND:
993 assert( mnStackIdx >= 2 );
994 pTop[0] = static_cast<ValType>(static_cast<int>(pTop[0]) & static_cast<int>(pTop[-1]));
995 --mnStackIdx;
996 break;
997 case TYPE2OP::OR:
998 assert( mnStackIdx >= 2 );
999 pTop[0] = static_cast<ValType>(static_cast<int>(pTop[0]) | static_cast<int>(pTop[-1]));
1000 --mnStackIdx;
1001 break;
1002 case TYPE2OP::NOT:
1003 assert( mnStackIdx >= 1 );
1004 pTop[0] = ValType(pTop[0] == 0);
1005 break;
1006 case TYPE2OP::ABS:
1007 assert( mnStackIdx >= 1 );
1008 if( pTop[0] >= 0)
1009 break;
1010 // fall through
1011 case TYPE2OP::NEG:
1012 assert( mnStackIdx >= 1 );
1013 pTop[0] = -pTop[0];
1014 break;
1015 case TYPE2OP::ADD:
1016 assert( mnStackIdx >= 2 );
1017 pTop[0] += pTop[-1];
1018 --mnStackIdx;
1019 break;
1020 case TYPE2OP::SUB:
1021 assert( mnStackIdx >= 2 );
1022 pTop[0] -= pTop[-1];
1023 --mnStackIdx;
1024 break;
1025 case TYPE2OP::MUL:
1026 assert( mnStackIdx >= 2 );
1027 if( pTop[-1])
1028 pTop[0] *= pTop[-1];
1029 --mnStackIdx;
1030 break;
1031 case TYPE2OP::DIV:
1032 assert( mnStackIdx >= 2 );
1033 if( pTop[-1])
1034 pTop[0] /= pTop[-1];
1035 --mnStackIdx;
1036 break;
1037 case TYPE2OP::EQ:
1038 assert( mnStackIdx >= 2 );
1039 pTop[0] = ValType(pTop[0] == pTop[-1]);
1040 --mnStackIdx;
1041 break;
1042 case TYPE2OP::DROP:
1043 assert( mnStackIdx >= 1 );
1044 --mnStackIdx;
1045 break;
1046 case TYPE2OP::PUT: {
1047 assert( mnStackIdx >= 2 );
1048 const int nIdx = static_cast<int>(pTop[0]);
1049 assert( nIdx >= 0 );
1050 assert( nIdx < NMAXTRANS );
1051 mnTransVals[ nIdx] = pTop[-1];
1052 mnStackIdx -= 2;
1053 break;
1055 case TYPE2OP::GET: {
1056 assert( mnStackIdx >= 1 );
1057 const int nIdx = static_cast<int>(pTop[0]);
1058 assert( nIdx >= 0 );
1059 assert( nIdx < NMAXTRANS );
1060 pTop[0] = mnTransVals[ nIdx ];
1061 break;
1063 case TYPE2OP::IFELSE: {
1064 assert( mnStackIdx >= 4 );
1065 if( pTop[-1] > pTop[0] )
1066 pTop[-3] = pTop[-2];
1067 mnStackIdx -= 3;
1068 break;
1070 case TYPE2OP::RANDOM:
1071 pTop[+1] = 1234; // TODO
1072 ++mnStackIdx;
1073 break;
1074 case TYPE2OP::SQRT:
1075 // TODO: implement
1076 break;
1077 case TYPE2OP::DUP:
1078 assert( mnStackIdx >= 1 );
1079 pTop[+1] = pTop[0];
1080 ++mnStackIdx;
1081 break;
1082 case TYPE2OP::EXCH: {
1083 assert( mnStackIdx >= 2 );
1084 const ValType nVal = pTop[0];
1085 pTop[0] = pTop[-1];
1086 pTop[-1] = nVal;
1087 break;
1089 case TYPE2OP::INDEX: {
1090 assert( mnStackIdx >= 1 );
1091 const int nVal = static_cast<int>(pTop[0]);
1092 assert( nVal >= 0 );
1093 assert( nVal < mnStackIdx-1 );
1094 pTop[0] = pTop[-1-nVal];
1095 break;
1097 case TYPE2OP::ROLL: {
1098 assert( mnStackIdx >= 1 );
1099 const int nNum = static_cast<int>(pTop[0]);
1100 assert( nNum >= 0);
1101 assert( nNum < mnStackIdx-2 );
1102 (void)nNum; // TODO: implement
1103 const int nOfs = static_cast<int>(pTop[-1]);
1104 mnStackIdx -= 2;
1105 (void)nOfs;// TODO: implement
1106 break;
1108 case TYPE2OP::HFLEX1: {
1109 assert( mnStackIdx == 9);
1111 writeCurveTo( mnStackIdx, -9, -8, -7, -6, -5, 0);
1112 writeCurveTo( mnStackIdx, -4, 0, -3, -2, -1, 0);
1113 // TODO: emulate hflex1 using othersubr call
1115 mnStackIdx -= 9;
1117 break;
1118 case TYPE2OP::HFLEX: {
1119 assert( mnStackIdx == 7);
1120 ValType* pX = &mnValStack[ mnStackIdx];
1122 pX[+1] = -pX[-5]; // temp: +dy5==-dy2
1123 writeCurveTo( mnStackIdx, -7, 0, -6, -5, -4, 0);
1124 writeCurveTo( mnStackIdx, -3, 0, -2, +1, -1, 0);
1125 // TODO: emulate hflex using othersubr call
1127 mnStackIdx -= 7;
1129 break;
1130 case TYPE2OP::FLEX: {
1131 assert( mnStackIdx == 13 );
1132 writeCurveTo( mnStackIdx, -13, -12, -11, -10, -9, -8 );
1133 writeCurveTo( mnStackIdx, -7, -6, -5, -4, -3, -2 );
1134 const ValType nFlexDepth = mnValStack[ mnStackIdx-1 ];
1135 (void)nFlexDepth; // ignoring nFlexDepth
1136 mnStackIdx -= 13;
1138 break;
1139 case TYPE2OP::FLEX1: {
1140 assert( mnStackIdx == 11 );
1141 // write the first part of the flex1-hinted curve
1142 writeCurveTo( mnStackIdx, -11, -10, -9, -8, -7, -6 );
1144 // determine if nD6 is horizontal or vertical
1145 const int i = mnStackIdx;
1146 ValType nDeltaX = mnValStack[i-11] + mnValStack[i-9] + mnValStack[i-7] + mnValStack[i-5] + mnValStack[i-3];
1147 if( nDeltaX < 0 ) nDeltaX = -nDeltaX;
1148 ValType nDeltaY = mnValStack[i-10] + mnValStack[i-8] + mnValStack[i-6] + mnValStack[i-4] + mnValStack[i-2];
1149 if( nDeltaY < 0 ) nDeltaY = -nDeltaY;
1150 const bool bVertD6 = (nDeltaY > nDeltaX);
1152 // write the second part of the flex1-hinted curve
1153 if( !bVertD6 )
1154 writeCurveTo( mnStackIdx, -5, -4, -3, -2, -1, 0);
1155 else
1156 writeCurveTo( mnStackIdx, -5, -4, -3, -2, 0, -1);
1157 mnStackIdx -= 11;
1159 break;
1160 default:
1161 fprintf( stderr,"unhandled type2esc %d\n", nType2Esc);
1162 assert( false);
1163 break;
1167 void CffSubsetterContext::callType2Subr( bool bGlobal, int nSubrNumber)
1169 const U8* const pOldReadPtr = mpReadPtr;
1170 const U8* const pOldReadEnd = mpReadEnd;
1172 if( bGlobal ) {
1173 nSubrNumber += mnGlobalSubrBias;
1174 seekIndexData( mnGlobalSubrBase, nSubrNumber);
1175 } else {
1176 nSubrNumber += mpCffLocal->mnLocalSubrBias;
1177 seekIndexData( mpCffLocal->mnLocalSubrBase, nSubrNumber);
1180 while( mpReadPtr < mpReadEnd)
1181 convertOneTypeOp();
1183 mpReadPtr = pOldReadPtr;
1184 mpReadEnd = pOldReadEnd;
1187 static const int MAX_T1OPS_SIZE = 81920; // TODO: use dynamic value
1189 int CffSubsetterContext::convert2Type1Ops( CffLocal* pCffLocal, const U8* const pT2Ops, int nT2Len, U8* const pT1Ops)
1191 mpCffLocal = pCffLocal;
1193 // prepare the charstring conversion
1194 mpWritePtr = pT1Ops;
1195 #if 1 // TODO: update caller
1196 U8 aType1Ops[ MAX_T1OPS_SIZE];
1197 if( !pT1Ops)
1198 mpWritePtr = aType1Ops;
1199 *const_cast<U8**>(&pT1Ops) = mpWritePtr;
1200 #else
1201 assert( pT1Ops);
1202 #endif
1204 // prepend random seed for T1crypt
1205 *(mpWritePtr++) = 0x48;
1206 *(mpWritePtr++) = 0x44;
1207 *(mpWritePtr++) = 0x55;
1208 *(mpWritePtr++) = ' ';
1209 #if 1 // convert the Type2 charstring to Type1
1210 mpReadPtr = pT2Ops;
1211 mpReadEnd = pT2Ops + nT2Len;
1212 // prepend "hsbw" or "sbw"
1213 // TODO: only emit hsbw when charwidth is known
1214 // TODO: remove charwidth from T2 stack
1215 writeType1Val( 0); // TODO: aSubsetterContext.getLeftSideBearing();
1216 writeType1Val( 1000/*###getCharWidth()###*/);
1217 writeTypeOp( TYPE1OP::HSBW);
1218 mbSawError = false;
1219 mbNeedClose = false;
1220 mbIgnoreHints = false;
1221 mnHintSize=mnHorzHintSize=mnStackIdx=0; maCharWidth=-1;//#######
1222 mnCntrMask = 0;
1223 while( mpReadPtr < mpReadEnd)
1224 convertOneTypeOp();
1225 // if( bActivePath)
1226 // writeTypeOp( TYPE1OP::CLOSEPATH);
1227 // if( bSubRoutine)
1228 // writeTypeOp( TYPE1OP::RETURN);
1229 if( mbSawError) {
1230 mpWritePtr = pT1Ops+4;
1231 // create an "idiotproof" charstring
1232 writeType1Val( 0);
1233 writeType1Val( 800);
1234 writeTypeOp( TYPE1OP::HSBW);
1235 writeType1Val( 50);
1236 writeTypeOp( TYPE1OP::HMOVETO);
1237 writeType1Val( 650);
1238 writeType1Val( 100);
1239 writeTypeOp( TYPE1OP::RLINETO);
1240 writeType1Val( -350);
1241 writeType1Val( 700);
1242 writeTypeOp( TYPE1OP::RLINETO);
1243 writeTypeOp( TYPE1OP::CLOSEPATH);
1244 writeTypeOp( TYPE1OP::ENDCHAR);
1246 #else // useful for manually encoding charstrings
1247 mpWritePtr = pT1Ops;
1248 mpWritePtr += sprintf( (char*)mpWritePtr, "OOo_\x8b\x8c\x0c\x10\x0b");
1249 #endif
1250 const int nType1Len = mpWritePtr - pT1Ops;
1252 // encrypt the Type1 charstring
1253 int nRDCryptR = 4330; // TODO: mnRDCryptSeed;
1254 for( U8* p = pT1Ops; p < mpWritePtr; ++p) {
1255 *p ^= (nRDCryptR >> 8);
1256 nRDCryptR = (*p + nRDCryptR) * 52845 + 22719;
1259 return nType1Len;
1262 RealType CffSubsetterContext::readRealVal()
1264 // TODO: more thorough number validity test
1265 bool bComma = false;
1266 int nExpVal = 0;
1267 int nExpSign = 0;
1268 S64 nNumber = 0;
1269 RealType fReal = +1.0;
1270 for(;;){
1271 const U8 c = *(mpReadPtr++); // read nibbles
1272 // parse high nibble
1273 const U8 nH = c >> 4U;
1274 if( nH <= 9) {
1275 nNumber = nNumber * 10 + nH;
1276 --nExpVal;
1277 } else if( nH == 10) { // comma
1278 nExpVal = 0;
1279 bComma = true;
1280 } else if( nH == 11) { // +exp
1281 fReal *= nNumber;
1282 nExpSign = +1;
1283 nNumber = 0;
1284 } else if( nH == 12) { // -exp
1285 fReal *= nNumber;
1286 nExpSign = -1;
1287 nNumber = 0;
1288 } else if( nH == 13) { // reserved
1289 // TODO: ignore or error?
1290 } else if( nH == 14) // minus
1291 fReal = -fReal;
1292 else if( nH == 15) // end
1293 break;
1294 // parse low nibble
1295 const U8 nL = c & 0x0F;
1296 if( nL <= 9) {
1297 nNumber = nNumber * 10 + nL;
1298 --nExpVal;
1299 } else if( nL == 10) { // comma
1300 nExpVal = 0;
1301 bComma = true;
1302 } else if( nL == 11) { // +exp
1303 fReal *= nNumber;
1304 nNumber = 0;
1305 nExpSign = +1;
1306 } else if( nL == 12) { // -exp
1307 fReal *= nNumber;
1308 nNumber = 0;
1309 nExpSign = -1;
1310 } else if( nL == 13) { // reserved
1311 // TODO: ignore or error?
1312 } else if( nL == 14) // minus
1313 fReal = -fReal;
1314 else if( nL == 15) // end
1315 break;
1318 // merge exponents
1319 if( !bComma)
1320 nExpVal = 0;
1321 if( !nExpSign) { fReal *= nNumber;}
1322 else if( nExpSign > 0) { nExpVal += static_cast<int>(nNumber);}
1323 else if( nExpSign < 0) { nExpVal -= static_cast<int>(nNumber);}
1325 // apply exponents
1326 if( !nExpVal) { /*nothing to apply*/}
1327 else if( nExpVal > 0) { while( --nExpVal >= 0) fReal *= 10.0;}
1328 else if( nExpVal < 0) { while( ++nExpVal <= 0) fReal /= 10.0;}
1329 return fReal;
1332 // prepare to access an element inside a CFF/CID index table
1333 int CffSubsetterContext::seekIndexData( int nIndexBase, int nDataIndex)
1335 assert( (nIndexBase > 0) && (mpBasePtr + nIndexBase + 3 <= mpBaseEnd));
1336 if( nDataIndex < 0)
1337 return -1;
1338 mpReadPtr = mpBasePtr + nIndexBase;
1339 const int nDataCount = (mpReadPtr[0]<<8) + mpReadPtr[1];
1340 if( nDataIndex >= nDataCount)
1341 return -1;
1342 const int nDataOfsSz = mpReadPtr[2];
1343 mpReadPtr += 3 + (nDataOfsSz * nDataIndex);
1344 int nOfs1 = 0;
1345 switch( nDataOfsSz) {
1346 default: fprintf( stderr, "\tINVALID nDataOfsSz=%d\n\n", nDataOfsSz); return -1;
1347 case 1: nOfs1 = mpReadPtr[0]; break;
1348 case 2: nOfs1 = (mpReadPtr[0]<<8) + mpReadPtr[1]; break;
1349 case 3: nOfs1 = (mpReadPtr[0]<<16) + (mpReadPtr[1]<<8) + mpReadPtr[2]; break;
1350 case 4: nOfs1 = (mpReadPtr[0]<<24) + (mpReadPtr[1]<<16) + (mpReadPtr[2]<<8) + mpReadPtr[3]; break;
1352 mpReadPtr += nDataOfsSz;
1354 int nOfs2 = 0;
1355 switch( nDataOfsSz) {
1356 case 1: nOfs2 = mpReadPtr[0]; break;
1357 case 2: nOfs2 = (mpReadPtr[0]<<8) + mpReadPtr[1]; break;
1358 case 3: nOfs2 = (mpReadPtr[0]<<16) + (mpReadPtr[1]<<8) + mpReadPtr[2]; break;
1359 case 4: nOfs2 = (mpReadPtr[0]<<24) + (mpReadPtr[1]<<16) + (mpReadPtr[2]<<8) + mpReadPtr[3]; break;
1362 mpReadPtr = mpBasePtr + (nIndexBase + 2) + nDataOfsSz * (nDataCount + 1) + nOfs1;
1363 mpReadEnd = mpReadPtr + (nOfs2 - nOfs1);
1364 assert( nOfs1 >= 0);
1365 assert( nOfs2 >= nOfs1);
1366 assert( mpReadPtr <= mpBaseEnd);
1367 assert( mpReadEnd <= mpBaseEnd);
1368 return (nOfs2 - nOfs1);
1371 // skip over a CFF/CID index table
1372 void CffSubsetterContext::seekIndexEnd( int nIndexBase)
1374 assert( (nIndexBase > 0) && (mpBasePtr + nIndexBase + 3 <= mpBaseEnd));
1375 mpReadPtr = mpBasePtr + nIndexBase;
1376 const int nDataCount = (mpReadPtr[0]<<8) + mpReadPtr[1];
1377 const int nDataOfsSz = mpReadPtr[2];
1378 mpReadPtr += 3 + nDataOfsSz * nDataCount;
1379 assert( mpReadPtr <= mpBaseEnd);
1380 int nEndOfs = 0;
1381 switch( nDataOfsSz) {
1382 default: fprintf( stderr, "\tINVALID nDataOfsSz=%d\n\n", nDataOfsSz); return;
1383 case 1: nEndOfs = mpReadPtr[0]; break;
1384 case 2: nEndOfs = (mpReadPtr[0]<<8) + mpReadPtr[1]; break;
1385 case 3: nEndOfs = (mpReadPtr[0]<<16) + (mpReadPtr[1]<<8) + mpReadPtr[2];break;
1386 case 4: nEndOfs = (mpReadPtr[0]<<24) + (mpReadPtr[1]<<16) + (mpReadPtr[2]<<8) + mpReadPtr[3]; break;
1388 mpReadPtr += nDataOfsSz;
1389 mpReadPtr += nEndOfs - 1;
1390 mpReadEnd = mpBaseEnd;
1391 assert( nEndOfs >= 0);
1392 assert( mpReadEnd <= mpBaseEnd);
1395 // initialize FONTDICT specific values
1396 CffLocal::CffLocal()
1397 : mnPrivDictBase( 0)
1398 , mnPrivDictSize( 0)
1399 , mnLocalSubrOffs( 0)
1400 , mnLocalSubrBase( 0)
1401 , mnLocalSubrCount( 0)
1402 , mnLocalSubrBias( 0)
1403 , maNominalWidth( 0)
1404 , maDefaultWidth( 0)
1405 , maStemStdHW( 0)
1406 , maStemStdVW( 0)
1407 , mfBlueScale( 0.0)
1408 , mfBlueShift( 0.0)
1409 , mfBlueFuzz( 0.0)
1410 , mfExpFactor( 0.0)
1411 , mnLangGroup( 0)
1412 , mbForceBold( false)
1414 maStemSnapH.clear();
1415 maStemSnapV.clear();
1416 maBlueValues.clear();
1417 maOtherBlues.clear();
1418 maFamilyBlues.clear();
1419 maFamilyOtherBlues.clear();
1422 CffGlobal::CffGlobal()
1423 : mnNameIdxBase( 0)
1424 , mnNameIdxCount( 0)
1425 , mnStringIdxBase( 0)
1426 , mnStringIdxCount( 0)
1427 , mbCIDFont( false)
1428 , mnCharStrBase( 0)
1429 , mnCharStrCount( 0)
1430 , mnEncodingBase( 0)
1431 , mnCharsetBase( 0)
1432 , mnGlobalSubrBase( 0)
1433 , mnGlobalSubrCount( 0)
1434 , mnGlobalSubrBias( 0)
1435 , mnFDSelectBase( 0)
1436 , mnFontDictBase( 0)
1437 , mnFDAryCount( 1)
1438 , mnFontNameSID( 0)
1439 , mnFullNameSID( 0)
1440 , mnFamilyNameSID( 0)
1442 maFontBBox.clear();
1443 // TODO; maFontMatrix.clear();
1446 bool CffSubsetterContext::initialCffRead()
1448 // get the CFFHeader
1449 mpReadPtr = mpBasePtr;
1450 const U8 nVerMajor = *(mpReadPtr++);
1451 const U8 nVerMinor = *(mpReadPtr++);
1452 const U8 nHeaderSize = *(mpReadPtr++);
1453 const U8 nOffsetSize = *(mpReadPtr++);
1454 // TODO: is the version number useful for anything else?
1455 assert( (nVerMajor == 1) && (nVerMinor == 0));
1456 (void)(nVerMajor + nVerMinor + nOffsetSize); // avoid compiler warnings
1458 // prepare access to the NameIndex
1459 mnNameIdxBase = nHeaderSize;
1460 mpReadPtr = mpBasePtr + nHeaderSize;
1461 mnNameIdxCount = (mpReadPtr[0]<<8) + mpReadPtr[1];
1462 seekIndexEnd( mnNameIdxBase);
1464 // get the TopDict index
1465 const sal_Int32 nTopDictBase = getReadOfs();
1466 const int nTopDictCount = (mpReadPtr[0]<<8) + mpReadPtr[1];
1467 if( nTopDictCount) {
1468 for( int i = 0; i < nTopDictCount; ++i) {
1469 seekIndexData( nTopDictBase, i);
1470 while( mpReadPtr < mpReadEnd)
1471 readDictOp();
1472 assert( mpReadPtr == mpReadEnd);
1476 // prepare access to the String index
1477 mnStringIdxBase = getReadOfs();
1478 mnStringIdxCount = (mpReadPtr[0]<<8) + mpReadPtr[1];
1479 seekIndexEnd( mnStringIdxBase);
1481 // prepare access to the GlobalSubr index
1482 mnGlobalSubrBase = getReadOfs();
1483 mnGlobalSubrCount = (mpReadPtr[0]<<8) + mpReadPtr[1];
1484 mnGlobalSubrBias = (mnGlobalSubrCount<1240)?107:(mnGlobalSubrCount<33900)?1131:32768;
1485 // skip past the last GlobalSubr entry
1486 // seekIndexEnd( mnGlobalSubrBase);
1488 // get/skip the Encodings (we got mnEncodingBase from TOPDICT)
1489 // seekEncodingsEnd( mnEncodingBase);
1490 // get/skip the Charsets (we got mnCharsetBase from TOPDICT)
1491 // seekCharsetsEnd( mnCharStrBase);
1492 // get/skip FDSelect (CID only) data
1494 // prepare access to the CharStrings index (we got the base from TOPDICT)
1495 mpReadPtr = mpBasePtr + mnCharStrBase;
1496 mnCharStrCount = (mpReadPtr[0]<<8) + mpReadPtr[1];
1497 // seekIndexEnd( mnCharStrBase);
1499 // read the FDArray index (CID only)
1500 if( mbCIDFont) {
1501 // assert( mnFontDictBase == tellRel());
1502 mpReadPtr = mpBasePtr + mnFontDictBase;
1503 mnFDAryCount = (mpReadPtr[0]<<8) + mpReadPtr[1];
1504 if (static_cast<size_t>(mnFDAryCount) >= SAL_N_ELEMENTS(maCffLocal))
1506 SAL_INFO("vcl.fonts", "CffSubsetterContext: too many CFF in font");
1507 return false;
1510 // read FDArray details to get access to the PRIVDICTs
1511 for( int i = 0; i < mnFDAryCount; ++i) {
1512 mpCffLocal = &maCffLocal[i];
1513 seekIndexData( mnFontDictBase, i);
1514 while( mpReadPtr < mpReadEnd)
1515 readDictOp();
1516 assert( mpReadPtr == mpReadEnd);
1520 for( int i = 0; i < mnFDAryCount; ++i) {
1521 mpCffLocal = &maCffLocal[i];
1523 // get the PrivateDict index
1524 // (we got mnPrivDictSize and mnPrivDictBase from TOPDICT or FDArray)
1525 if( mpCffLocal->mnPrivDictSize != 0) {
1526 assert( mpCffLocal->mnPrivDictSize > 0);
1527 // get the PrivDict data
1528 mpReadPtr = mpBasePtr + mpCffLocal->mnPrivDictBase;
1529 mpReadEnd = mpReadPtr + mpCffLocal->mnPrivDictSize;
1530 assert( mpReadEnd <= mpBaseEnd);
1531 // read PrivDict details
1532 while( mpReadPtr < mpReadEnd)
1533 readDictOp();
1536 // prepare access to the LocalSubrs (we got mnLocalSubrOffs from PRIVDICT)
1537 if( mpCffLocal->mnLocalSubrOffs) {
1538 // read LocalSubrs summary
1539 mpCffLocal->mnLocalSubrBase = mpCffLocal->mnPrivDictBase + mpCffLocal->mnLocalSubrOffs;
1540 mpReadPtr = mpBasePtr + mpCffLocal->mnLocalSubrBase;
1541 const int nSubrCount = (mpReadPtr[0] << 8) + mpReadPtr[1];
1542 mpCffLocal->mnLocalSubrCount = nSubrCount;
1543 mpCffLocal->mnLocalSubrBias = (nSubrCount<1240)?107:(nSubrCount<33900)?1131:32768;
1544 // seekIndexEnd( mpCffLocal->mnLocalSubrBase);
1548 // ignore the Notices info
1550 return true;
1553 // get a cstring from a StringID
1554 const char* CffSubsetterContext::getString( int nStringID)
1556 // get a standard string if possible
1557 const static int nStdStrings = sizeof(pStringIds)/sizeof(*pStringIds);
1558 if( (nStringID >= 0) && (nStringID < nStdStrings))
1559 return pStringIds[ nStringID];
1561 // else get the string from the StringIndex table
1562 const U8* pReadPtr = mpReadPtr;
1563 const U8* pReadEnd = mpReadEnd;
1564 nStringID -= nStdStrings;
1565 int nLen = seekIndexData( mnStringIdxBase, nStringID);
1566 // assert( nLen >= 0);
1567 // TODO: just return the undecorated name
1568 // TODO: get rid of static char buffer
1569 static char aNameBuf[ 2560];
1570 if( nLen < 0) {
1571 sprintf( aNameBuf, "name[%d].notfound!", nStringID);
1572 } else {
1573 const int nMaxLen = sizeof(aNameBuf) - 1;
1574 if( nLen >= nMaxLen)
1575 nLen = nMaxLen;
1576 for( int i = 0; i < nLen; ++i)
1577 aNameBuf[i] = *(mpReadPtr++);
1578 aNameBuf[ nLen] = '\0';
1580 mpReadPtr = pReadPtr;
1581 mpReadEnd = pReadEnd;
1582 return aNameBuf;
1585 // access a CID's FDSelect table
1586 int CffSubsetterContext::getFDSelect( int nGlyphIndex) const
1588 assert( nGlyphIndex >= 0);
1589 assert( nGlyphIndex < mnCharStrCount);
1590 if( !mbCIDFont)
1591 return 0;
1593 const U8* pReadPtr = mpBasePtr + mnFDSelectBase;
1594 const U8 nFDSelFormat = *(pReadPtr++);
1595 switch( nFDSelFormat) {
1596 case 0: { // FDSELECT format 0
1597 pReadPtr += nGlyphIndex;
1598 const U8 nFDIdx = *(pReadPtr++);
1599 return nFDIdx;
1600 } //break;
1601 case 3: { // FDSELECT format 3
1602 const U16 nRangeCount = (pReadPtr[0]<<8) + pReadPtr[1];
1603 assert( nRangeCount > 0);
1604 assert( nRangeCount <= mnCharStrCount);
1605 U16 nPrev = (pReadPtr[2]<<8) + pReadPtr[3];
1606 assert( nPrev == 0);
1607 (void)nPrev;
1608 pReadPtr += 4;
1609 // TODO? binary search
1610 for( int i = 0; i < nRangeCount; ++i) {
1611 const U8 nFDIdx = pReadPtr[0];
1612 const U16 nNext = (pReadPtr[1]<<8) + pReadPtr[2];
1613 assert( nPrev < nNext);
1614 if( nGlyphIndex < nNext)
1615 return nFDIdx;
1616 pReadPtr += 3;
1617 nPrev = nNext;
1619 } break;
1620 default: // invalid FDselect format
1621 fprintf( stderr, "invalid CFF.FdselType=%d\n", nFDSelFormat);
1622 break;
1625 assert( false);
1626 return -1;
1629 int CffSubsetterContext::getGlyphSID( int nGlyphIndex) const
1631 if( nGlyphIndex == 0)
1632 return 0; // ".notdef"
1633 assert( nGlyphIndex >= 0);
1634 assert( nGlyphIndex < mnCharStrCount);
1635 if( (nGlyphIndex < 0) || (nGlyphIndex >= mnCharStrCount))
1636 return -1;
1638 // get the SID/CID from the Charset table
1639 const U8* pReadPtr = mpBasePtr + mnCharsetBase;
1640 const U8 nCSetFormat = *(pReadPtr++);
1641 int nGlyphsToSkip = nGlyphIndex - 1;
1642 switch( nCSetFormat) {
1643 case 0: // charset format 0
1644 pReadPtr += 2 * nGlyphsToSkip;
1645 nGlyphsToSkip = 0;
1646 break;
1647 case 1: // charset format 1
1648 while( nGlyphsToSkip >= 0) {
1649 const int nLeft = pReadPtr[2];
1650 if( nGlyphsToSkip <= nLeft)
1651 break;
1652 nGlyphsToSkip -= nLeft + 1;
1653 pReadPtr += 3;
1655 break;
1656 case 2: // charset format 2
1657 while( nGlyphsToSkip >= 0) {
1658 const int nLeft = (pReadPtr[2]<<8) + pReadPtr[3];
1659 if( nGlyphsToSkip <= nLeft)
1660 break;
1661 nGlyphsToSkip -= nLeft + 1;
1662 pReadPtr += 4;
1664 break;
1665 default:
1666 fprintf( stderr, "ILLEGAL CFF-Charset format %d\n", nCSetFormat);
1667 return -2;
1670 int nSID = (pReadPtr[0]<<8) + pReadPtr[1];
1671 nSID += nGlyphsToSkip;
1672 // NOTE: for CID-fonts the resulting SID is interpreted as CID
1673 return nSID;
1676 // NOTE: the result becomes invalid with the next call to this method
1677 const char* CffSubsetterContext::getGlyphName( int nGlyphIndex)
1679 // the first glyph is always the .notdef glyph
1680 const char* pGlyphName = ".notdef";
1681 if( nGlyphIndex == 0)
1682 return pGlyphName;
1684 // prepare a result buffer
1685 // TODO: get rid of static buffer
1686 static char aDefaultGlyphName[64];
1687 pGlyphName = aDefaultGlyphName;
1689 // get the glyph specific name
1690 const int nSID = getGlyphSID( nGlyphIndex);
1691 if( nSID < 0) // default glyph name
1692 sprintf( aDefaultGlyphName, "gly%03d", nGlyphIndex);
1693 else if( mbCIDFont) // default glyph name in CIDs
1694 sprintf( aDefaultGlyphName, "cid%03d", nSID);
1695 else { // glyph name from string table
1696 const char* pSidName = getString( nSID);
1697 // check validity of glyph name
1698 if( pSidName) {
1699 const char* p = pSidName;
1700 while( (*p >= '0') && (*p <= 'z')) ++p;
1701 if( (p >= pSidName+1) && (*p == '\0'))
1702 pGlyphName = pSidName;
1704 // if needed invent a fallback name
1705 if( pGlyphName != pSidName)
1706 sprintf( aDefaultGlyphName, "bad%03d", nSID);
1709 return pGlyphName;
1712 class Type1Emitter
1714 public:
1715 explicit Type1Emitter( FILE* pOutFile, bool bPfbSubset = true);
1716 ~Type1Emitter();
1717 void setSubsetName( const char* );
1719 size_t emitRawData( const char* pData, size_t nLength) const;
1720 void emitAllRaw();
1721 void emitAllHex();
1722 void emitAllCrypted();
1723 int tellPos() const;
1724 size_t updateLen( int nTellPos, size_t nLength);
1725 void emitValVector( const char* pLineHead, const char* pLineTail, const ValVector&);
1726 private:
1727 FILE* mpFileOut;
1728 bool mbCloseOutfile;
1729 char maBuffer[MAX_T1OPS_SIZE]; // TODO: dynamic allocation
1730 int mnEECryptR;
1731 public:
1732 char* mpPtr;
1734 char maSubsetName[256];
1735 bool mbPfbSubset;
1736 int mnHexLineCol;
1739 Type1Emitter::Type1Emitter( FILE* pOutFile, bool bPfbSubset)
1740 : mpFileOut( pOutFile)
1741 , mbCloseOutfile( false)
1742 , mnEECryptR( 55665) // default eexec seed, TODO: mnEECryptSeed
1743 , mpPtr( maBuffer)
1744 , mbPfbSubset( bPfbSubset)
1745 , mnHexLineCol( 0)
1747 maSubsetName[0] = '\0';
1750 Type1Emitter::~Type1Emitter()
1752 if( !mpFileOut)
1753 return;
1754 if( mbCloseOutfile )
1755 fclose( mpFileOut);
1756 mpFileOut = NULL;
1759 void Type1Emitter::setSubsetName( const char* pSubsetName)
1761 maSubsetName[0] = '\0';
1762 if( pSubsetName)
1763 strncpy( maSubsetName, pSubsetName, sizeof(maSubsetName));
1764 maSubsetName[sizeof(maSubsetName)-1] = '\0';
1767 int Type1Emitter::tellPos() const
1769 int nTellPos = ftell( mpFileOut);
1770 return nTellPos;
1773 size_t Type1Emitter::updateLen( int nTellPos, size_t nLength)
1775 // update PFB segment header length
1776 U8 cData[4];
1777 cData[0] = static_cast<U8>(nLength >> 0);
1778 cData[1] = static_cast<U8>(nLength >> 8);
1779 cData[2] = static_cast<U8>(nLength >> 16);
1780 cData[3] = static_cast<U8>(nLength >> 24);
1781 const long nCurrPos = ftell(mpFileOut);
1782 if (nCurrPos < 0)
1783 return 0;
1784 if (fseek( mpFileOut, nTellPos, SEEK_SET) != 0)
1785 return 0;
1786 size_t nWrote = fwrite(cData, 1, sizeof(cData), mpFileOut);
1787 if( nCurrPos >= 0)
1788 (void)fseek(mpFileOut, nCurrPos, SEEK_SET);
1789 return nWrote;
1792 inline size_t Type1Emitter::emitRawData(const char* pData, size_t nLength) const
1794 return fwrite( pData, 1, nLength, mpFileOut);
1797 inline void Type1Emitter::emitAllRaw()
1799 // writeout raw data
1800 assert( (mpPtr - maBuffer) < (int)sizeof(maBuffer));
1801 emitRawData( maBuffer, mpPtr - maBuffer);
1802 // reset the raw buffer
1803 mpPtr = maBuffer;
1806 inline void Type1Emitter::emitAllHex()
1808 assert( (mpPtr - maBuffer) < (int)sizeof(maBuffer));
1809 for( const char* p = maBuffer; p < mpPtr;) {
1810 // convert binary chunk to hex
1811 char aHexBuf[0x4000];
1812 char* pOut = aHexBuf;
1813 while( (p < mpPtr) && (pOut < aHexBuf+sizeof(aHexBuf)-4)) {
1814 // convert each byte to hex
1815 char cNibble = (*p >> 4) & 0x0F;
1816 cNibble += (cNibble < 10) ? '0' : 'A'-10;
1817 *(pOut++) = cNibble;
1818 cNibble = *(p++) & 0x0F;
1819 cNibble += (cNibble < 10) ? '0' : 'A'-10;
1820 *(pOut++) = cNibble;
1821 // limit the line length
1822 if( (++mnHexLineCol & 0x3F) == 0)
1823 *(pOut++) = '\n';
1825 // writeout hex-converted chunk
1826 emitRawData( aHexBuf, pOut-aHexBuf);
1828 // reset the raw buffer
1829 mpPtr = maBuffer;
1832 void Type1Emitter::emitAllCrypted()
1834 // apply t1crypt
1835 for( char* p = maBuffer; p < mpPtr; ++p) {
1836 *p ^= (mnEECryptR >> 8);
1837 mnEECryptR = (*reinterpret_cast<U8*>(p) + mnEECryptR) * 52845 + 22719;
1840 // emit the t1crypt result
1841 if( mbPfbSubset)
1842 emitAllRaw();
1843 else
1844 emitAllHex();
1847 // #i110387# quick-and-dirty double->ascii conversion
1848 // needed because sprintf/ecvt/etc. alone are too localized (LC_NUMERIC)
1849 // also strip off trailing zeros in fraction while we are at it
1850 inline int dbl2str( char* pOut, double fVal, int nPrecision=6)
1852 const int nLen = psp::getValueOfDouble( pOut, fVal, nPrecision);
1853 return nLen;
1856 void Type1Emitter::emitValVector( const char* pLineHead, const char* pLineTail,
1857 const ValVector& rVector)
1859 // ignore empty vectors
1860 if( rVector.empty())
1861 return;
1863 // emit the line head
1864 mpPtr += sprintf( mpPtr, "%s", pLineHead);
1865 // emit the vector values
1866 ValVector::value_type aVal = 0;
1867 for( ValVector::const_iterator it = rVector.begin();;) {
1868 aVal = *it;
1869 if( ++it == rVector.end() )
1870 break;
1871 mpPtr += dbl2str( mpPtr, aVal);
1872 *(mpPtr++) = ' ';
1874 // emit the last value
1875 mpPtr += dbl2str( mpPtr, aVal);
1876 // emit the line tail
1877 mpPtr += sprintf( mpPtr, "%s", pLineTail);
1880 bool CffSubsetterContext::emitAsType1( Type1Emitter& rEmitter,
1881 const sal_GlyphId* pReqGlyphIds, const U8* pReqEncoding,
1882 GlyphWidth* pGlyphWidths, int nGlyphCount, FontSubsetInfo& rFSInfo)
1884 // prepare some fontdirectory details
1885 static const int nUniqueIdBase = 4100000; // using private-interchange UniqueIds
1886 static int nUniqueId = nUniqueIdBase;
1887 ++nUniqueId;
1889 char* pFontName = rEmitter.maSubsetName;
1890 if( !*pFontName ) {
1891 if( mnFontNameSID) {
1892 // get the fontname directly if available
1893 strncpy( pFontName, getString( mnFontNameSID), sizeof(rEmitter.maSubsetName) - 1);
1894 pFontName[sizeof(rEmitter.maSubsetName) - 1] = 0;
1895 } else if( mnFullNameSID) {
1896 // approximate fontname as fullname-whitespace
1897 const char* pI = getString( mnFullNameSID);
1898 char* pO = pFontName;
1899 const char* pLimit = pFontName + sizeof(rEmitter.maSubsetName) - 1;
1900 while( pO < pLimit) {
1901 const char c = *(pI++);
1902 if( c != ' ')
1903 *(pO++) = c;
1904 if( !c)
1905 break;
1907 *pO = '\0';
1908 } else {
1909 // fallback name of last resort
1910 strncpy( pFontName, "DummyName", sizeof(rEmitter.maSubsetName));
1913 const char* pFullName = pFontName;
1914 const char* pFamilyName = pFontName;
1916 char*& pOut = rEmitter.mpPtr; // convenience reference, TODO: cleanup
1918 // create a PFB+Type1 header
1919 if( rEmitter.mbPfbSubset ) {
1920 static const char aPfbHeader[] = "\x80\x01\x00\x00\x00\x00";
1921 rEmitter.emitRawData( aPfbHeader, sizeof(aPfbHeader)-1);
1924 pOut += sprintf( pOut, "%%!FontType1-1.0: %s 001.003\n", rEmitter.maSubsetName);
1925 // emit TOPDICT
1926 pOut += sprintf( pOut,
1927 "11 dict begin\n" // TODO: dynamic entry count for TOPDICT
1928 "/FontType 1 def\n"
1929 "/PaintType 0 def\n");
1930 pOut += sprintf( pOut, "/FontName /%s def\n", rEmitter.maSubsetName);
1931 pOut += sprintf( pOut, "/UniqueID %d def\n", nUniqueId);
1932 // emit FontMatrix
1933 if( maFontMatrix.size() == 6)
1934 rEmitter.emitValVector( "/FontMatrix [", "]readonly def\n", maFontMatrix);
1935 else // emit default FontMatrix if needed
1936 pOut += sprintf( pOut, "/FontMatrix [0.001 0 0 0.001 0 0]readonly def\n");
1937 // emit FontBBox
1938 if( maFontBBox.size() == 4)
1939 rEmitter.emitValVector( "/FontBBox {", "}readonly def\n", maFontBBox);
1940 else // emit default FontBBox if needed
1941 pOut += sprintf( pOut, "/FontBBox {0 0 999 999}readonly def\n");
1942 // emit FONTINFO into TOPDICT
1943 pOut += sprintf( pOut,
1944 "/FontInfo 2 dict dup begin\n" // TODO: check fontinfo entry count
1945 " /FullName (%s) readonly def\n"
1946 " /FamilyName (%s) readonly def\n"
1947 "end readonly def\n",
1948 pFullName, pFamilyName);
1950 pOut += sprintf( pOut,
1951 "/Encoding 256 array\n"
1952 "0 1 255 {1 index exch /.notdef put} for\n");
1953 for( int i = 1; (i < nGlyphCount) && (i < 256); ++i) {
1954 const char* pGlyphName = getGlyphName( pReqGlyphIds[i]);
1955 pOut += sprintf( pOut, "dup %d /%s put\n", pReqEncoding[i], pGlyphName);
1957 pOut += sprintf( pOut, "readonly def\n");
1958 pOut += sprintf( pOut,
1959 // TODO: more topdict entries
1960 "currentdict end\n"
1961 "currentfile eexec\n");
1963 // emit PFB header
1964 rEmitter.emitAllRaw();
1965 if( rEmitter.mbPfbSubset) {
1966 // update PFB header segment
1967 const int nPfbHeaderLen = rEmitter.tellPos() - 6;
1968 rEmitter.updateLen( 2, nPfbHeaderLen);
1970 // prepare start of eexec segment
1971 rEmitter.emitRawData( "\x80\x02\x00\x00\x00\x00", 6); // segment start
1973 const int nEExecSegTell = rEmitter.tellPos();
1975 // which always starts with a privdict
1976 // count the privdict entries
1977 int nPrivEntryCount = 9;
1978 #if !defined(IGNORE_HINTS)
1979 // emit blue hints only if non-default values
1980 nPrivEntryCount += int(!mpCffLocal->maOtherBlues.empty());
1981 nPrivEntryCount += int(!mpCffLocal->maFamilyBlues.empty());
1982 nPrivEntryCount += int(!mpCffLocal->maFamilyOtherBlues.empty());
1983 nPrivEntryCount += int(mpCffLocal->mfBlueScale != 0.0);
1984 nPrivEntryCount += int(mpCffLocal->mfBlueShift != 0.0);
1985 nPrivEntryCount += int(mpCffLocal->mfBlueFuzz != 0.0);
1986 // emit stem hints only if non-default values
1987 nPrivEntryCount += int(mpCffLocal->maStemStdHW != 0);
1988 nPrivEntryCount += int(mpCffLocal->maStemStdVW != 0);
1989 nPrivEntryCount += int(!mpCffLocal->maStemSnapH.empty());
1990 nPrivEntryCount += int(!mpCffLocal->maStemSnapV.empty());
1991 // emit other hints only if non-default values
1992 nPrivEntryCount += int(mpCffLocal->mfExpFactor != 0.0);
1993 nPrivEntryCount += int(mpCffLocal->mnLangGroup != 0);
1994 nPrivEntryCount += int(mpCffLocal->mnLangGroup == 1);
1995 nPrivEntryCount += int(mpCffLocal->mbForceBold);
1996 #endif // IGNORE_HINTS
1997 // emit the privdict header
1998 pOut += sprintf( pOut,
1999 "\110\104\125 "
2000 "dup\n/Private %d dict dup begin\n"
2001 "/RD{string currentfile exch readstring pop}executeonly def\n"
2002 "/ND{noaccess def}executeonly def\n"
2003 "/NP{noaccess put}executeonly def\n"
2004 "/MinFeature{16 16}ND\n"
2005 "/password 5839 def\n", // TODO: mnRDCryptSeed?
2006 nPrivEntryCount);
2008 #if defined(IGNORE_HINTS)
2009 pOut += sprintf( pOut, "/BlueValues []ND\n"); // BlueValues are mandatory
2010 #else
2011 // emit blue hint related privdict entries
2012 if( !mpCffLocal->maBlueValues.empty())
2013 rEmitter.emitValVector( "/BlueValues [", "]ND\n", mpCffLocal->maBlueValues);
2014 else
2015 pOut += sprintf( pOut, "/BlueValues []ND\n"); // default to empty BlueValues
2016 rEmitter.emitValVector( "/OtherBlues [", "]ND\n", mpCffLocal->maOtherBlues);
2017 rEmitter.emitValVector( "/FamilyBlues [", "]ND\n", mpCffLocal->maFamilyBlues);
2018 rEmitter.emitValVector( "/FamilyOtherBlues [", "]ND\n", mpCffLocal->maFamilyOtherBlues);
2020 if( mpCffLocal->mfBlueScale) {
2021 pOut += sprintf( pOut, "/BlueScale ");
2022 pOut += dbl2str( pOut, mpCffLocal->mfBlueScale, 6);
2023 pOut += sprintf( pOut, " def\n");
2025 if( mpCffLocal->mfBlueShift) { // default BlueShift==7
2026 pOut += sprintf( pOut, "/BlueShift ");
2027 pOut += dbl2str( pOut, mpCffLocal->mfBlueShift);
2028 pOut += sprintf( pOut, " def\n");
2030 if( mpCffLocal->mfBlueFuzz) { // default BlueFuzz==1
2031 pOut += sprintf( pOut, "/BlueFuzz ");
2032 pOut += dbl2str( pOut, mpCffLocal->mfBlueFuzz);
2033 pOut += sprintf( pOut, " def\n");
2036 // emit stem hint related privdict entries
2037 if( mpCffLocal->maStemStdHW) {
2038 pOut += sprintf( pOut, "/StdHW [");
2039 pOut += dbl2str( pOut, mpCffLocal->maStemStdHW);
2040 pOut += sprintf( pOut, "] def\n");
2042 if( mpCffLocal->maStemStdVW) {
2043 pOut += sprintf( pOut, "/StdVW [");
2044 pOut += dbl2str( pOut, mpCffLocal->maStemStdVW);
2045 pOut += sprintf( pOut, "] def\n");
2047 rEmitter.emitValVector( "/StemSnapH [", "]ND\n", mpCffLocal->maStemSnapH);
2048 rEmitter.emitValVector( "/StemSnapV [", "]ND\n", mpCffLocal->maStemSnapV);
2050 // emit other hints
2051 if( mpCffLocal->mbForceBold)
2052 pOut += sprintf( pOut, "/ForceBold true def\n");
2053 if( mpCffLocal->mnLangGroup != 0)
2054 pOut += sprintf( pOut, "/LanguageGroup %d def\n", mpCffLocal->mnLangGroup);
2055 if( mpCffLocal->mnLangGroup == 1) // compatibility with ancient printers
2056 pOut += sprintf( pOut, "/RndStemUp false def\n");
2057 if( mpCffLocal->mfExpFactor) {
2058 pOut += sprintf( pOut, "/ExpansionFactor ");
2059 pOut += dbl2str( pOut, mpCffLocal->mfExpFactor);
2060 pOut += sprintf( pOut, " def\n");
2062 #endif // IGNORE_HINTS
2064 // emit remaining privdict entries
2065 pOut += sprintf( pOut, "/UniqueID %d def\n", nUniqueId);
2066 // TODO?: more privdict entries?
2068 static const char aOtherSubrs[] =
2069 "/OtherSubrs\n"
2070 "% Dummy code for faking flex hints\n"
2071 "[ {} {} {} {systemdict /internaldict known not {pop 3}\n"
2072 "{1183615869 systemdict /internaldict get exec\n"
2073 "dup /startlock known\n"
2074 "{/startlock get exec}\n"
2075 "{dup /strtlck known\n"
2076 "{/strtlck get exec}\n"
2077 "{pop 3}\nifelse}\nifelse}\nifelse\n} executeonly\n"
2078 "] ND\n";
2079 memcpy( pOut, aOtherSubrs, sizeof(aOtherSubrs)-1);
2080 pOut += sizeof(aOtherSubrs)-1;
2082 // emit used GlobalSubr charstrings
2083 // these are the just the default subrs
2084 // TODO: do we need them as the flex hints are resolved differently?
2085 static const char aSubrs[] =
2086 "/Subrs 5 array\n"
2087 "dup 0 15 RD \x5F\x3D\x6B\xAC\x3C\xBD\x74\x3D\x3E\x17\xA0\x86\x58\x08\x85 NP\n"
2088 "dup 1 9 RD \x5F\x3D\x6B\xD8\xA6\xB5\x68\xB6\xA2 NP\n"
2089 "dup 2 9 RD \x5F\x3D\x6B\xAC\x39\x46\xB9\x43\xF9 NP\n"
2090 "dup 3 5 RD \x5F\x3D\x6B\xAC\xB9 NP\n"
2091 "dup 4 12 RD \x5F\x3D\x6B\xAC\x3E\x5D\x48\x54\x62\x76\x39\x03 NP\n"
2092 "ND\n";
2093 memcpy( pOut, aSubrs, sizeof(aSubrs)-1);
2094 pOut += sizeof(aSubrs)-1;
2096 // TODO: emit more GlobalSubr charstrings?
2097 // TODO: emit used LocalSubr charstrings?
2099 // emit the CharStrings for the requested glyphs
2100 pOut += sprintf( pOut,
2101 "2 index /CharStrings %d dict dup begin\n", nGlyphCount);
2102 rEmitter.emitAllCrypted();
2103 for( int i = 0; i < nGlyphCount; ++i) {
2104 const int nCffGlyphId = pReqGlyphIds[i];
2105 assert( (nCffGlyphId >= 0) && (nCffGlyphId < mnCharStrCount));
2106 // get privdict context matching to the glyph
2107 const int nFDSelect = getFDSelect( nCffGlyphId);
2108 if( nFDSelect < 0)
2109 continue;
2110 mpCffLocal = &maCffLocal[ nFDSelect];
2111 // convert the Type2op charstring to its Type1op counterpart
2112 const int nT2Len = seekIndexData( mnCharStrBase, nCffGlyphId);
2113 assert( nT2Len > 0);
2114 U8 aType1Ops[ MAX_T1OPS_SIZE]; // TODO: dynamic allocation
2115 const int nT1Len = convert2Type1Ops( mpCffLocal, mpReadPtr, nT2Len, aType1Ops);
2116 // get the glyph name
2117 const char* pGlyphName = getGlyphName( nCffGlyphId);
2118 // emit the encrypted Type1op charstring
2119 pOut += sprintf( pOut, "/%s %d RD ", pGlyphName, nT1Len);
2120 memcpy( pOut, aType1Ops, nT1Len);
2121 pOut += nT1Len;
2122 pOut += sprintf( pOut, " ND\n");
2123 rEmitter.emitAllCrypted();
2124 // provide individual glyphwidths if requested
2125 if( pGlyphWidths ) {
2126 ValType aCharWidth = getCharWidth();
2127 if( maFontMatrix.size() >= 4)
2128 aCharWidth *= 1000.0F * maFontMatrix[0];
2129 pGlyphWidths[i] = static_cast<GlyphWidth>(aCharWidth);
2132 pOut += sprintf( pOut, "end end\nreadonly put\nput\n");
2133 pOut += sprintf( pOut, "dup/FontName get exch definefont pop\n");
2134 pOut += sprintf( pOut, "mark currentfile closefile\n");
2135 rEmitter.emitAllCrypted();
2137 // mark stop of eexec encryption
2138 if( rEmitter.mbPfbSubset) {
2139 const int nEExecLen = rEmitter.tellPos() - nEExecSegTell;
2140 rEmitter.updateLen( nEExecSegTell-4, nEExecLen);
2143 // create PFB footer
2144 static const char aPfxFooter[] = "\x80\x01\x14\x02\x00\x00\n" // TODO: check segment len
2145 "0000000000000000000000000000000000000000000000000000000000000000\n"
2146 "0000000000000000000000000000000000000000000000000000000000000000\n"
2147 "0000000000000000000000000000000000000000000000000000000000000000\n"
2148 "0000000000000000000000000000000000000000000000000000000000000000\n"
2149 "0000000000000000000000000000000000000000000000000000000000000000\n"
2150 "0000000000000000000000000000000000000000000000000000000000000000\n"
2151 "0000000000000000000000000000000000000000000000000000000000000000\n"
2152 "0000000000000000000000000000000000000000000000000000000000000000\n"
2153 "cleartomark\n"
2154 "\x80\x03";
2155 if( rEmitter.mbPfbSubset)
2156 rEmitter.emitRawData( aPfxFooter, sizeof(aPfxFooter)-1);
2157 else
2158 rEmitter.emitRawData( aPfxFooter+6, sizeof(aPfxFooter)-9);
2160 // provide details to the subset requesters, TODO: move into own method?
2161 // note: Top and Bottom are flipped between Type1 and VCL
2162 // note: the rest of VCL expects the details below to be scaled like for an emUnits==1000 font
2163 ValType fXFactor = 1.0;
2164 ValType fYFactor = 1.0;
2165 if( maFontMatrix.size() >= 4) {
2166 fXFactor = 1000.0F * maFontMatrix[0];
2167 fYFactor = 1000.0F * maFontMatrix[3];
2169 rFSInfo.m_aFontBBox = Rectangle( Point( static_cast<sal_Int32>(maFontBBox[0] * fXFactor),
2170 static_cast<sal_Int32>(maFontBBox[1] * fYFactor) ),
2171 Point( static_cast<sal_Int32>(maFontBBox[2] * fXFactor),
2172 static_cast<sal_Int32>(maFontBBox[3] * fYFactor) ) );
2173 // PDF-Spec says the values below mean the ink bounds!
2174 // TODO: use better approximations for these ink bounds
2175 rFSInfo.m_nAscent = +rFSInfo.m_aFontBBox.Bottom(); // for capital letters
2176 rFSInfo.m_nDescent = -rFSInfo.m_aFontBBox.Top(); // for all letters
2177 rFSInfo.m_nCapHeight = rFSInfo.m_nAscent; // for top-flat capital letters
2179 rFSInfo.m_nFontType = rEmitter.mbPfbSubset ? FontSubsetInfo::TYPE1_PFB : FontSubsetInfo::TYPE1_PFA;
2180 rFSInfo.m_aPSName = OUString( rEmitter.maSubsetName, strlen(rEmitter.maSubsetName), RTL_TEXTENCODING_UTF8 );
2182 return true;
2185 bool FontSubsetInfo::CreateFontSubsetFromCff( GlyphWidth* pOutGlyphWidths )
2187 CffSubsetterContext aCff( mpInFontBytes, mnInByteLength);
2188 bool bRC = aCff.initialCffRead();
2189 if (!bRC)
2190 return bRC;
2192 // emit Type1 subset from the CFF input
2193 // TODO: also support CFF->CFF subsetting (when PDF-export and PS-printing need it)
2194 const bool bPfbSubset = (0 != (mnReqFontTypeMask & FontSubsetInfo::TYPE1_PFB));
2195 Type1Emitter aType1Emitter( mpOutFile, bPfbSubset);
2196 aType1Emitter.setSubsetName( mpReqFontName);
2197 bRC = aCff.emitAsType1( aType1Emitter,
2198 mpReqGlyphIds, mpReqEncodedIds,
2199 pOutGlyphWidths, mnReqGlyphCount, *this);
2200 return bRC;
2203 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */