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