nss: upgrade to release 3.73
[LibreOffice.git] / vcl / source / fontsubset / cff.cxx
blob7d418ef2694cd96934f29171731e91cb252a6f42
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 <vector>
23 #include <assert.h>
25 #include <fontsubset.hxx>
27 #include <o3tl/safeint.hxx>
28 #include <strhelper.hxx>
29 #include <sal/log.hxx>
31 typedef sal_uInt8 U8;
32 typedef sal_uInt16 U16;
33 typedef sal_Int64 S64;
35 typedef double RealType;
36 typedef RealType ValType;
38 static const char* pStringIds[] = {
39 /*0*/ ".notdef", "space", "exclam", "quotedbl",
40 "numbersign", "dollar", "percent", "ampersand",
41 "quoteright", "parenleft", "parenright", "asterisk",
42 "plus", "comma", "hyphen", "period",
43 /*16*/ "slash", "zero", "one", "two",
44 "three", "four", "five", "six",
45 "seven", "eight", "nine", "colon",
46 "semicolon", "less", "equal", "greater",
47 /*32*/ "question", "at", "A", "B",
48 "C", "D", "E", "F",
49 "G", "H", "I", "J",
50 "K", "L", "M", "N",
51 /*48*/ "O", "P", "Q", "R",
52 "S", "T", "U", "V",
53 "W", "X", "Y", "Z",
54 "bracketleft", "backslash", "bracketright", "asciicircum",
55 /*64*/ "underscore", "quoteleft", "a", "b",
56 "c", "d", "e", "f",
57 "g", "h", "i", "j",
58 "k", "l", "m", "n",
59 /*80*/ "o", "p", "q", "r",
60 "s", "t", "u", "v",
61 "w", "x", "y", "z",
62 "braceleft", "bar", "braceright", "asciitilde",
63 /*96*/ "exclamdown", "cent", "sterlin", "fraction",
64 "yen", "florin", "section", "currency",
65 "quotesingle", "quotedblleft", "guillemotleft", "guilsinglleft",
66 "guilsinglright", "fi", "fl", "endash",
67 /*112*/ "dagger", "daggerdbl", "periodcentered", "paragraph",
68 "bullet", "quotesinglbase", "quotedblbase", "quotedblright",
69 "guillemotright", "ellipsis", "perthousand", "questiondown",
70 "grave", "acute", "circumflex", "tilde",
71 /*128*/ "macron", "breve", "dotaccent", "dieresis",
72 "ring", "cedilla", "hungarumlaut", "ogonek",
73 "caron", "emdash", "AE", "ordfeminine",
74 "Lslash", "Oslash", "OE", "ordmasculine",
75 /*144*/ "ae", "dotlessi", "lslash", "oslash",
76 "oe", "germandbls", "onesuperior", "logicalnot",
77 "mu", "trademark", "Eth", "onehalf",
78 "plusminus", "Thorn", "onequarter", "divide",
79 /*160*/ "brokenbar", "degree", "thorn", "threequarters",
80 "twosuperior", "registered", "minus", "eth",
81 "multiply", "threesuperior", "copyright", "Aacute",
82 "Acircumflex", "Adieresis", "Agrave", "Aring",
83 /*176*/ "Atilde", "Ccedilla", "Eacute", "Ecircumflex",
84 "Edieresis", "Egrave", "Iacute", "Icircumflex",
85 "Idieresis", "Igrave", "Ntilde", "Oacute",
86 "Ocircumflex", "Odieresis", "Ograve", "Otilde",
87 /*192*/ "Scaron", "Uacute", "Ucircumflex", "Udieresis",
88 "Ugrave", "Yacute", "Ydieresis", "Zcaron",
89 "aacute", "acircumflex", "adieresis", "agrave",
90 "aring", "atilde", "ccedilla", "eacute",
91 /*208*/ "ecircumflex", "edieresis", "egrave", "iacute",
92 "icircumflex", "idieresis", "igrave", "ntilde",
93 "oacute", "ocircumflex", "odieresis", "ograve",
94 "otilde", "scaron", "uacute", "ucircumflex",
95 /*224*/ "udieresis", "ugrave", "yacute", "ydieresis",
96 "zcaron", "exclamsmall", "Hungarumlautsmall","dollaroldstyle",
97 "dollarsuperior", "ampersandsmall", "Acutesmall", "parenleftsuperior",
98 "parenrightsuperior","twodotenleader", "onedotenleader", "zerooldstyle",
99 /*240*/ "oneoldstyle", "twooldstyle", "threeoldstyle", "fouroldstyle",
100 "fiveoldstyle", "sixoldstyle", "sevenoldstyle", "eightoldstyle",
101 "nineoldstile", "commasuperior", "threequartersemdash","periodsuperior",
102 "questionsmall", "asuperior", "bsuperior", "centsuperior",
103 /*256*/ "dsuperior", "esuperior", "isuperior", "lsuperior",
104 "msuperior", "nsuperior", "osuperior", "rsuperior",
105 "ssuperior", "tsuperior", "ff", "ffi",
106 "ffl", "parenleftinferior","parenrightinferior","Circumflexsmall",
107 /*272*/ "hyphensuperior","Gravesmall", "Asmall", "Bsmall",
108 "Csmall", "Dsmall", "Esmall", "Fsmall",
109 "Gsmall", "Hsmall", "Ismall", "Jsmall",
110 "Ksmall", "Lsmall", "Msmall", "Nsmall",
111 /*288*/ "Osmall", "Psmall", "Qsmall", "Rsmall",
112 "Ssmall", "Tsmall", "Usmall", "Vsmall",
113 "Wsmall", "Xsmall", "Ysmall", "Zsmall",
114 "colonmonetary", "onefitted", "rupia", "Tildesmall",
115 /*304*/ "exclamdownsmall","centoldstyle", "Lslashsmall", "Scaronsmall",
116 "Zcaronsmall", "Dieresissmall", "Brevesmall", "Caronsmall",
117 "Dotaccentsmall", "Macronsmall", "figuredash", "hypheninferior",
118 "Ogoneksmall", "Ringsmall", "Cedillasmall", "questiondownsmall",
119 /*320*/ "oneeight", "threeeights", "fiveeights", "seveneights",
120 "onethird", "twothirds", "zerosuperior", "foursuperior",
121 "fivesuperior", "sixsuperior", "sevensuperior", "eightsuperior",
122 "ninesuperior", "zeroinferior", "oneinferior", "twoinferior",
123 /*336*/ "threeinferior","fourinferior", "fiveinferior", "sixinferior",
124 "seveninferior", "eightinferior", "nineinferior", "centinferior",
125 "dollarinferior", "periodinferior", "commainferior", "Agravesmall",
126 "Aacutesmall", "Acircumflexsmall", "Atildesmall", "Adieresissmall",
127 /*352*/ "Aringsmall", "AEsmall", "Ccedillasmall", "Egravesmall",
128 "Eacutesmall", "Ecircumflexsmall", "Edieresissmall", "Igravesmall",
129 "Iacutesmall", "Icircumflexsmall", "Idieresissmall", "Ethsmall",
130 "Ntildesmall", "Ogravesmall", "Oacutesmall", "Ocircumflexsmall",
131 /*368*/ "Otildesmall", "Odieressissmall", "OEsmall", "Oslashsmall",
132 "Ugravesmall", "Uacutesmall", "Ucircumflexsmall", "Udieresissmall",
133 "Yacutesmall", "Thornsmall", "Ydieresissmall", "001.000",
134 "001.001", "001.002", "001.003", "Black",
135 /*384*/ "Bold", "Book", "Light", "Medium",
136 "Regular", "Roman", "Semibold"
139 // TOP DICT keywords (also covers PRIV DICT keywords)
140 static const char* pDictOps[] = {
141 "sVersion", "sNotice", "sFullName", "sFamilyName",
142 "sWeight", "aFontBBox", "dBlueValues", "dOtherBlues",
143 "dFamilyBlues", "dFamilyOtherBlues", "nStdHW", "nStdVW",
144 "xESC", "nUniqueID", "aXUID", "nCharset",
145 "nEncoding", "nCharStrings", "PPrivate", "nSubrs",
146 "nDefaultWidthX", "nNominalWidthX", nullptr, nullptr,
147 nullptr, nullptr, nullptr, nullptr,
148 "shortint", "longint", "BCD", nullptr
151 // TOP DICT escapes (also covers PRIV DICT escapes)
152 static const char* pDictEscs[] = {
153 "sCopyright", "bIsFixedPitch", "nItalicAngle", "nUnderlinePosition",
154 "nUnderlineThickness", "nPaintType", "tCharstringType", "aFontMatrix",
155 "nStrokeWidth", "nBlueScale", "nBlueShift", "nBlueFuzz",
156 "dStemSnapH", "dStemSnapV", "bForceBold", nullptr,
157 nullptr, "nLanguageGroup", "nExpansionFactor", "nInitialRandomSeed",
158 "nSyntheticBase", "sPostScript", "sBaseFontName", "dBaseFontBlend",
159 nullptr, nullptr, nullptr, nullptr,
160 nullptr, nullptr, "rROS", "nCIDFontVersion",
161 "nCIDFontRevision", "nCIDFontType", "nCIDCount", "nUIDBase",
162 "nFDArray", "nFDSelect", "sFontName"
165 namespace {
167 namespace TYPE1OP
169 enum OPS
171 HSTEM=1, VSTEM=3, VMOVETO=4, RLINETO=5,
172 HLINETO=6, VLINETO=7, RCURVETO=8, CLOSEPATH=9,
173 CALLSUBR=10, RETURN=11, T1ESC=12, HSBW=13,
174 ENDCHAR=14, RMOVETO=21, HMOVETO=22, VHCURVETO=30,
175 HVCURVETO=31
178 enum ESCS
180 DOTSECTION=0, VSTEM3=1, HSTEM3=2, SEAC=6,
181 SBW=7, ABS=9, ADD=10, SUB=11,
182 DIV=12, CALLOTHERSUBR=16, POP=17, SETCURRENTPOINT=33
186 namespace TYPE2OP
188 enum OPS
190 HSTEM=1, VSTEM=3, VMOVETO=4, RLINETO=5,
191 HLINETO=6, VLINETO=7, RCURVETO=8, CALLSUBR=10,
192 RETURN=11, T2ESC=12, ENDCHAR=14, HSTEMHM=18,
193 HINTMASK=19, CNTRMASK=20, RMOVETO=21, HMOVETO=22,
194 VSTEMHM=23, RCURVELINE=24, RLINECURVE=25, VVCURVETO=26,
195 HHCURVETO=27, SHORTINT=28, CALLGSUBR=29, VHCURVETO=30,
196 HVCURVETO=31
199 enum ESCS
201 AND=3, OR=4, NOT=5, ABS=9,
202 ADD=10, SUB=11, DIV=12, NEG=14,
203 EQ=15, DROP=18, PUT=20, GET=21,
204 IFELSE=22, RANDOM=23, MUL=24, SQRT=26,
205 DUP=27, EXCH=28, INDEX=29, ROLL=30,
206 HFLEX=34, FLEX=35, HFLEX1=36, FLEX1=37
210 struct CffGlobal
212 explicit CffGlobal();
214 int mnNameIdxBase;
215 int mnStringIdxBase;
216 bool mbCIDFont;
217 int mnCharStrBase;
218 int mnCharStrCount;
219 int mnCharsetBase;
220 int mnGlobalSubrBase;
221 int mnGlobalSubrCount;
222 int mnGlobalSubrBias;
223 int mnFDSelectBase;
224 int mnFontDictBase;
225 int mnFDAryCount;
227 std::vector<ValType> maFontBBox;
228 std::vector<ValType> maFontMatrix;
230 int mnFontNameSID;
231 int mnFullNameSID;
234 struct CffLocal
236 explicit CffLocal();
238 int mnPrivDictBase;
239 int mnPrivDictSize;
240 int mnLocalSubrOffs;
241 int mnLocalSubrBase;
242 int mnLocalSubrBias;
244 ValType maNominalWidth;
245 ValType maDefaultWidth;
247 // ATM hinting related values
248 ValType maStemStdHW;
249 ValType maStemStdVW;
250 std::vector<ValType> maStemSnapH;
251 std::vector<ValType> maStemSnapV;
252 std::vector<ValType> maBlueValues;
253 std::vector<ValType> maOtherBlues;
254 std::vector<ValType> maFamilyBlues;
255 std::vector<ValType> maFamilyOtherBlues;
256 RealType mfBlueScale;
257 RealType mfBlueShift;
258 RealType mfBlueFuzz;
259 RealType mfExpFactor;
260 int mnLangGroup;
261 bool mbForceBold;
264 class CffSubsetterContext
265 : private CffGlobal
267 public:
268 static const int NMAXSTACK = 48; // see CFF.appendixB
269 static const int NMAXHINTS = 2*96; // see CFF.appendixB
270 static const int NMAXTRANS = 32; // see CFF.appendixB
272 explicit CffSubsetterContext( const U8* pBasePtr, int nBaseLen);
274 bool initialCffRead();
275 void emitAsType1( class Type1Emitter&,
276 const sal_GlyphId* pGlyphIds, const U8* pEncoding,
277 sal_Int32* pGlyphWidths, int nGlyphCount, FontSubsetInfo& );
279 private:
280 int convert2Type1Ops( CffLocal*, const U8* pType2Ops, int nType2Len, U8* pType1Ops);
281 void convertOneTypeOp();
282 void convertOneTypeEsc();
283 void callType2Subr( bool bGlobal, int nSubrNumber);
284 sal_Int32 getReadOfs() const { return static_cast<sal_Int32>(mpReadPtr - mpBasePtr);}
286 const U8* mpBasePtr;
287 const U8* mpBaseEnd;
289 const U8* mpReadPtr;
290 const U8* mpReadEnd;
292 U8* mpWritePtr;
293 bool mbNeedClose;
294 bool mbIgnoreHints;
295 sal_Int32 mnCntrMask;
297 int seekIndexData( int nIndexBase, int nDataIndex);
298 void seekIndexEnd( int nIndexBase);
300 CffLocal maCffLocal[256];
301 CffLocal* mpCffLocal;
303 void readDictOp();
304 RealType readRealVal();
305 const char* getString( int nStringID);
306 int getFDSelect( int nGlyphIndex) const;
307 int getGlyphSID( int nGlyphIndex) const;
308 const char* getGlyphName( int nGlyphIndex);
310 void read2push();
311 void writeType1Val( ValType);
312 void writeTypeOp( int nTypeOp);
313 void writeTypeEsc( int nTypeOp);
314 void writeCurveTo( int nStackPos, int nIX1, int nIY1, int nIX2, int nIY2, int nIX3, int nIY3);
315 void pop2MultiWrite( int nArgsPerTypo, int nTypeOp, int nTypeXor=0);
316 void popAll2Write( int nTypeOp);
318 public: // TODO: is public really needed?
319 // accessing the value stack
320 // TODO: add more checks
321 void push( ValType nVal) { mnValStack[ mnStackIdx++] = nVal;}
322 ValType popVal() { return ((mnStackIdx>0) ? mnValStack[ --mnStackIdx] : 0);}
323 ValType getVal( int nIndex) const { return mnValStack[ nIndex];}
324 int popInt();
325 int size() const { return mnStackIdx;}
326 void clear() { mnStackIdx = 0;}
328 // accessing the charstring hints
329 void addHints( bool bVerticalHints);
331 // accessing other charstring specifics
332 void updateWidth( bool bUseFirstVal);
334 private:
335 // typeop execution context
336 int mnStackIdx;
337 ValType mnValStack[ NMAXSTACK+4];
338 ValType mnTransVals[ NMAXTRANS];
340 int mnHintSize;
341 int mnHorzHintSize;
342 ValType mnHintStack[ NMAXHINTS];
344 ValType maCharWidth;
349 CffSubsetterContext::CffSubsetterContext( const U8* pBasePtr, int nBaseLen)
350 : mpBasePtr( pBasePtr)
351 , mpBaseEnd( pBasePtr+nBaseLen)
352 , mpReadPtr(nullptr)
353 , mpReadEnd(nullptr)
354 , mpWritePtr(nullptr)
355 , mbNeedClose(false)
356 , mbIgnoreHints(false)
357 , mnCntrMask(0)
358 , mnStackIdx(0)
359 , mnValStack{}
360 , mnTransVals{}
361 , mnHintSize(0)
362 , mnHorzHintSize(0)
363 , mnHintStack{}
364 , maCharWidth(-1)
366 // setCharStringType( 1);
367 // TODO: new CffLocal[ mnFDAryCount];
368 mpCffLocal = &maCffLocal[0];
371 inline int CffSubsetterContext::popInt()
373 const ValType aVal = popVal();
374 const int nInt = static_cast<int>(aVal);
375 assert( nInt == aVal);
376 return nInt;
379 inline void CffSubsetterContext::updateWidth( bool bUseFirstVal)
381 // the first value is not a hint but the charwidth
382 if( maCharWidth>0 )
383 return;
385 if( bUseFirstVal) {
386 maCharWidth = mpCffLocal->maNominalWidth + mnValStack[0];
387 // remove bottom stack entry
388 --mnStackIdx;
389 for( int i = 0; i < mnStackIdx; ++i)
390 mnValStack[ i] = mnValStack[ i+1];
391 } else {
392 maCharWidth = mpCffLocal->maDefaultWidth;
396 void CffSubsetterContext::addHints( bool bVerticalHints)
398 // the first charstring value may a charwidth instead of a charwidth
399 updateWidth( (mnStackIdx & 1) != 0);
400 // return early (e.g. no implicit hints for hintmask)
401 if( !mnStackIdx)
402 return;
404 // copy the remaining values to the hint arrays
405 // assert( (mnStackIdx & 1) == 0); // depends on called subrs
406 if( mnStackIdx & 1) --mnStackIdx;//#######
407 // TODO: if( !bSubr) assert( mnStackIdx >= 2);
409 assert( (mnHintSize + mnStackIdx) <= 2*NMAXHINTS);
411 ValType nHintOfs = 0;
412 for( int i = 0; i < mnStackIdx; ++i) {
413 nHintOfs += mnValStack[ i ];
414 mnHintStack[ mnHintSize++] = nHintOfs;
417 if( !bVerticalHints)
418 mnHorzHintSize = mnHintSize;
420 // clear all values from the stack
421 mnStackIdx = 0;
424 void CffSubsetterContext::readDictOp()
426 const U8 c = *mpReadPtr;
427 if( c <= 21 ) {
428 int nOpId = *(mpReadPtr++);
429 const char* pCmdName = nullptr;
430 if( nOpId != 12)
431 pCmdName = pDictOps[nOpId];
432 else {
433 const U8 nExtId = *(mpReadPtr++);
434 if (nExtId < 39)
435 pCmdName = pDictEscs[nExtId];
436 nOpId = 900 + nExtId;
439 if (!pCmdName) // skip reserved operators
440 return;
442 //TODO: if( nStackIdx > 0)
443 int nInt = 0;
444 switch( *pCmdName) {
445 default: SAL_WARN("vcl.fonts", "unsupported DictOp.type='" << *pCmdName << "'."); break;
446 case 'b': // bool
447 nInt = popInt();
448 switch( nOpId) {
449 case 915: mpCffLocal->mbForceBold = nInt; break; // "ForceBold"
450 default: break; // TODO: handle more boolean dictops?
452 break;
453 case 'n': { // dict-op number
454 ValType nVal = popVal();
455 nInt = static_cast<int>(nVal);
456 switch( nOpId) {
457 case 10: mpCffLocal->maStemStdHW = nVal; break; // "StdHW"
458 case 11: mpCffLocal->maStemStdVW = nVal; break; // "StdVW"
459 case 15: mnCharsetBase = nInt; break; // "charset"
460 case 16: break; // "nEncoding"
461 case 17: mnCharStrBase = nInt; break; // "nCharStrings"
462 case 19: mpCffLocal->mnLocalSubrOffs = nInt; break;// "nSubrs"
463 case 20: mpCffLocal->maDefaultWidth = nVal; break; // "defaultWidthX"
464 case 21: mpCffLocal->maNominalWidth = nVal; break; // "nominalWidthX"
465 case 909: mpCffLocal->mfBlueScale = nVal; break; // "BlueScale"
466 case 910: mpCffLocal->mfBlueShift = nVal; break; // "BlueShift"
467 case 911: mpCffLocal->mfBlueFuzz = nVal; break; // "BlueFuzz"
468 case 912: mpCffLocal->mfExpFactor = nVal; break; // "ExpansionFactor"
469 case 917: mpCffLocal->mnLangGroup = nInt; break; // "LanguageGroup"
470 case 936: mnFontDictBase = nInt; break; // "nFDArray"
471 case 937: mnFDSelectBase = nInt; break; // "nFDSelect"
472 default: break; // TODO: handle more numeric dictops?
474 } break;
475 case 'a': { // array
476 switch( nOpId) {
477 case 5: maFontBBox.clear(); break; // "FontBBox"
478 case 907: maFontMatrix.clear(); break; // "FontMatrix"
479 default: break; // TODO: reset other arrays?
481 for( int i = 0; i < size(); ++i ) {
482 ValType nVal = getVal(i);
483 switch( nOpId) {
484 case 5: maFontBBox.push_back( nVal); break; // "FontBBox"
485 case 907: maFontMatrix.push_back( nVal); break; // "FontMatrix"
486 default: break; // TODO: handle more array dictops?
489 clear();
490 } break;
491 case 'd': { // delta array
492 ValType nVal = 0;
493 for( int i = 0; i < size(); ++i ) {
494 nVal += getVal(i);
495 switch( nOpId) {
496 case 6: mpCffLocal->maBlueValues.push_back( nVal); break; // "BlueValues"
497 case 7: mpCffLocal->maOtherBlues.push_back( nVal); break; // "OtherBlues"
498 case 8: mpCffLocal->maFamilyBlues.push_back( nVal); break; // "FamilyBlues"
499 case 9: mpCffLocal->maFamilyOtherBlues.push_back( nVal); break;// "FamilyOtherBlues"
500 case 912: mpCffLocal->maStemSnapH.push_back( nVal); break; // "StemSnapH"
501 case 913: mpCffLocal->maStemSnapV.push_back( nVal); break; // "StemSnapV"
502 default: break; // TODO: handle more delta-array dictops?
505 clear();
506 } break;
507 case 's': // stringid (SID)
508 nInt = popInt();
509 switch( nOpId ) {
510 case 2: mnFullNameSID = nInt; break; // "FullName"
511 case 3: break; // "FamilyName"
512 case 938: mnFontNameSID = nInt; break; // "FontName"
513 default: break; // TODO: handle more string dictops?
515 break;
516 case 'P': // private dict
517 mpCffLocal->mnPrivDictBase = popInt();
518 mpCffLocal->mnPrivDictSize = popInt();
519 break;
520 case 'r': { // ROS operands
521 popInt(); // TODO: use sid1
522 popInt(); // TODO: use sid2
523 popVal();
524 mbCIDFont = true;
525 } break;
526 case 't': // CharstringType
527 popInt();
528 break;
530 } else if( (c >= 32) || (c == 28) ) {
531 // --mpReadPtr;
532 read2push();
533 } else if( c == 29 ) { // longint
534 ++mpReadPtr; // skip 29
535 sal_Int32 nS32 = mpReadPtr[0] << 24;
536 nS32 += mpReadPtr[1] << 16;
537 nS32 += mpReadPtr[2] << 8;
538 nS32 += mpReadPtr[3] << 0;
539 mpReadPtr += 4;
540 ValType nVal = static_cast<ValType>(nS32);
541 push( nVal );
542 } else if( c == 30) { // real number
543 ++mpReadPtr; // skip 30
544 const RealType fReal = readRealVal();
545 // push value onto stack
546 ValType nVal = fReal;
547 push( nVal);
551 void CffSubsetterContext::read2push()
553 ValType aVal = 0;
555 const U8*& p = mpReadPtr;
556 const U8 c = *p;
557 if( c == 28 ) {
558 sal_Int16 nS16 = (p[1] << 8) + p[2];
559 aVal = nS16;
560 p += 3;
561 } else if( c <= 246 ) { // -107..+107
562 aVal = static_cast<ValType>(p[0] - 139);
563 p += 1;
564 } else if( c <= 250 ) { // +108..+1131
565 aVal = static_cast<ValType>(((p[0] << 8) + p[1]) - 63124);
566 p += 2;
567 } else if( c <= 254 ) { // -108..-1131
568 aVal = static_cast<ValType>(64148 - ((p[0] << 8) + p[1]));
569 p += 2;
570 } else /*if( c == 255)*/ { // Fixed16.16
571 int nS32 = (p[1] << 24) + (p[2] << 16) + (p[3] << 8) + p[4];
572 if( (sizeof(nS32) != 2) && (nS32 & (1U<<31)))
573 nS32 |= (~0U) << 31; // assuming 2s complement
574 aVal = static_cast<ValType>(nS32 * (1.0 / 0x10000));
575 p += 5;
578 push( aVal);
581 void CffSubsetterContext::writeType1Val( ValType aVal)
583 U8* pOut = mpWritePtr;
585 int nInt = static_cast<int>(aVal);
586 if( (nInt >= -107) && (nInt <= +107)) {
587 *(pOut++) = static_cast<U8>(nInt + 139); // -107..+107
588 } else if( (nInt >= -1131) && (nInt <= +1131)) {
589 if( nInt >= 0)
590 nInt += 63124; // +108..+1131
591 else
592 nInt = 64148 - nInt; // -108..-1131
593 *(pOut++) = static_cast<U8>(nInt >> 8);
594 *(pOut++) = static_cast<U8>(nInt);
595 } else {
596 // numtype==255 means int32 for Type1, but 16.16 for Type2 charstrings!!!
597 *(pOut++) = 255;
598 *(pOut++) = static_cast<U8>(nInt >> 24);
599 *(pOut++) = static_cast<U8>(nInt >> 16);
600 *(pOut++) = static_cast<U8>(nInt >> 8);
601 *(pOut++) = static_cast<U8>(nInt);
604 mpWritePtr = pOut;
607 inline void CffSubsetterContext::writeTypeOp( int nTypeOp)
609 *(mpWritePtr++) = static_cast<U8>(nTypeOp);
612 inline void CffSubsetterContext::writeTypeEsc( int nTypeEsc)
614 *(mpWritePtr++) = TYPE1OP::T1ESC;
615 *(mpWritePtr++) = static_cast<U8>(nTypeEsc);
618 void CffSubsetterContext::pop2MultiWrite( int nArgsPerTypo, int nTypeOp, int nTypeXor)
620 for( int i = 0; i < mnStackIdx;) {
621 for( int j = 0; j < nArgsPerTypo; ++j) {
622 const ValType aVal = mnValStack[i+j];
623 writeType1Val( aVal);
625 i += nArgsPerTypo;
626 writeTypeOp( nTypeOp);
627 nTypeOp ^= nTypeXor; // for toggling vlineto/hlineto
629 clear();
632 void CffSubsetterContext::popAll2Write( int nTypeOp)
634 // pop in reverse order, then write
635 for( int i = 0; i < mnStackIdx; ++i) {
636 const ValType aVal = mnValStack[i];
637 writeType1Val( aVal);
639 clear();
640 writeTypeOp( nTypeOp);
643 void CffSubsetterContext::writeCurveTo( int nStackPos,
644 int nIX1, int nIY1, int nIX2, int nIY2, int nIX3, int nIY3)
646 // get the values from the stack
647 const ValType nDX1 = nIX1 ? mnValStack[ nStackPos+nIX1 ] : 0;
648 const ValType nDY1 = nIY1 ? mnValStack[ nStackPos+nIY1 ] : 0;
649 const ValType nDX2 = nIX2 ? mnValStack[ nStackPos+nIX2 ] : 0;
650 const ValType nDY2 = nIY2 ? mnValStack[ nStackPos+nIY2 ] : 0;
651 const ValType nDX3 = nIX3 ? mnValStack[ nStackPos+nIX3 ] : 0;
652 const ValType nDY3 = nIY3 ? mnValStack[ nStackPos+nIY3 ] : 0;
654 // emit the curveto operator and operands
655 // TODO: determine the most efficient curveto operator
656 // TODO: depending on type1op or type2op target
657 writeType1Val( nDX1 );
658 writeType1Val( nDY1 );
659 writeType1Val( nDX2 );
660 writeType1Val( nDY2 );
661 writeType1Val( nDX3 );
662 writeType1Val( nDY3 );
663 writeTypeOp( TYPE1OP::RCURVETO );
666 void CffSubsetterContext::convertOneTypeOp()
668 const int nType2Op = *(mpReadPtr++);
670 int i, nInt; // prevent WAE for declarations inside switch cases
671 // convert each T2op
672 switch( nType2Op) {
673 case TYPE2OP::T2ESC:
674 convertOneTypeEsc();
675 break;
676 case TYPE2OP::HSTEM:
677 case TYPE2OP::VSTEM:
678 addHints( nType2Op == TYPE2OP::VSTEM );
679 for( i = 0; i < mnHintSize; i+=2 ) {
680 writeType1Val( mnHintStack[i]);
681 writeType1Val( mnHintStack[i+1] - mnHintStack[i]);
682 writeTypeOp( nType2Op );
684 break;
685 case TYPE2OP::HSTEMHM:
686 case TYPE2OP::VSTEMHM:
687 addHints( nType2Op == TYPE2OP::VSTEMHM);
688 break;
689 case TYPE2OP::CNTRMASK:
690 // TODO: replace cntrmask with vstem3/hstem3
691 addHints( true);
693 U8 nMaskBit = 0;
694 U8 nMaskByte = 0;
695 for( i = 0; i < mnHintSize; i+=2, nMaskBit>>=1) {
696 if( !nMaskBit) {
697 nMaskByte = *(mpReadPtr++);
698 nMaskBit = 0x80;
700 if( !(nMaskByte & nMaskBit))
701 continue;
702 if( i >= 8*int(sizeof(mnCntrMask)))
703 mbIgnoreHints = true;
704 if( mbIgnoreHints)
705 continue;
706 mnCntrMask |= (1U << i);
709 break;
710 case TYPE2OP::HINTMASK:
711 addHints( true);
713 sal_Int32 nHintMask = 0;
714 int nCntrBits[2] = {0,0};
715 U8 nMaskBit = 0;
716 U8 nMaskByte = 0;
717 int const MASK_BITS = 8*sizeof(nHintMask);
718 for( i = 0; i < mnHintSize; i+=2, nMaskBit>>=1) {
719 if( !nMaskBit) {
720 nMaskByte = *(mpReadPtr++);
721 nMaskBit = 0x80;
723 if( !(nMaskByte & nMaskBit))
724 continue;
725 if( i >= MASK_BITS)
726 mbIgnoreHints = true;
727 if( mbIgnoreHints)
728 continue;
729 nHintMask |= (1U << i);
730 nCntrBits[ i < mnHorzHintSize] += (mnCntrMask >> i) & 1;
733 mbIgnoreHints |= (nCntrBits[0] && (nCntrBits[0] != 3));
734 mbIgnoreHints |= (nCntrBits[1] && (nCntrBits[1] != 3));
735 if( mbIgnoreHints)
736 break;
738 for( i = 0; i < mnHintSize; i+=2) {
739 if(i >= MASK_BITS || !(nHintMask & (1U << i)))
740 continue;
741 writeType1Val( mnHintStack[i]);
742 writeType1Val( mnHintStack[i+1] - mnHintStack[i]);
743 const bool bHorz = (i < mnHorzHintSize);
744 if( !nCntrBits[ bHorz])
745 writeTypeOp( bHorz ? TYPE1OP::HSTEM : TYPE1OP::VSTEM);
746 else if( !--nCntrBits[ bHorz])
747 writeTypeEsc( bHorz ? TYPE1OP::HSTEM3 : TYPE1OP::VSTEM3);
750 break;
751 case TYPE2OP::CALLSUBR:
752 case TYPE2OP::CALLGSUBR:
754 nInt = popInt();
755 const bool bGlobal = (nType2Op == TYPE2OP::CALLGSUBR);
756 callType2Subr( bGlobal, nInt);
758 break;
759 case TYPE2OP::RETURN:
760 // TODO: check that we are in a subroutine
761 return;
762 case TYPE2OP::VMOVETO:
763 case TYPE2OP::HMOVETO:
764 if( mbNeedClose)
765 writeTypeOp( TYPE1OP::CLOSEPATH);
766 else
767 updateWidth( size() > 1);
768 mbNeedClose = true;
769 pop2MultiWrite( 1, nType2Op);
770 break;
771 case TYPE2OP::VLINETO:
772 case TYPE2OP::HLINETO:
773 pop2MultiWrite( 1, nType2Op,
774 TYPE1OP::VLINETO ^ TYPE1OP::HLINETO);
775 break;
776 case TYPE2OP::RMOVETO:
777 // TODO: convert rmoveto to vlineto/hlineto if possible
778 if( mbNeedClose)
779 writeTypeOp( TYPE1OP::CLOSEPATH);
780 else
781 updateWidth( size() > 2);
782 mbNeedClose = true;
783 pop2MultiWrite( 2, nType2Op);
784 break;
785 case TYPE2OP::RLINETO:
786 // TODO: convert rlineto to vlineto/hlineto if possible
787 pop2MultiWrite( 2, nType2Op);
788 break;
789 case TYPE2OP::RCURVETO:
790 // TODO: convert rcurveto to vh/hv/hh/vv-curveto if possible
791 pop2MultiWrite( 6, nType2Op);
792 break;
793 case TYPE2OP::RCURVELINE:
794 i = 0;
795 while( (i += 6) <= mnStackIdx)
796 writeCurveTo( i, -6, -5, -4, -3, -2, -1 );
797 i -= 6;
798 while( (i += 2) <= mnStackIdx) {
799 writeType1Val( mnValStack[i-2]);
800 writeType1Val( mnValStack[i-1]);
801 writeTypeOp( TYPE2OP::RLINETO);
803 clear();
804 break;
805 case TYPE2OP::RLINECURVE:
806 i = 0;
807 while( (i += 2) <= mnStackIdx-6) {
808 writeType1Val( mnValStack[i-2]);
809 writeType1Val( mnValStack[i-1]);
810 writeTypeOp( TYPE2OP::RLINETO);
812 i -= 2;
813 while( (i += 6) <= mnStackIdx)
814 writeCurveTo( i, -6, -5, -4, -3, -2, -1 );
815 clear();
816 break;
817 case TYPE2OP::VHCURVETO:
818 case TYPE2OP::HVCURVETO:
820 bool bVert = (nType2Op == TYPE2OP::VHCURVETO);
821 i = 0;
822 nInt = 0;
823 if( mnStackIdx & 1 )
824 nInt = static_cast<int>(mnValStack[ --mnStackIdx ]);
825 while( (i += 4) <= mnStackIdx) {
826 // TODO: use writeCurveTo()
827 if( bVert ) writeType1Val( 0 );
828 writeType1Val( mnValStack[i-4] );
829 if( !bVert ) writeType1Val( 0);
830 writeType1Val( mnValStack[i-3] );
831 writeType1Val( mnValStack[i-2] );
832 if( !bVert ) writeType1Val( static_cast<ValType>((i==mnStackIdx) ? nInt : 0) );
833 writeType1Val( mnValStack[i-1] );
834 if( bVert ) writeType1Val( static_cast<ValType>((i==mnStackIdx) ? nInt : 0) );
835 bVert = !bVert;
836 writeTypeOp( TYPE2OP::RCURVETO);
839 clear();
840 break;
841 case TYPE2OP::HHCURVETO:
842 i = (mnStackIdx & 1);
843 while( (i += 4) <= mnStackIdx) {
844 if( i != 5)
845 writeCurveTo( i, -4, 0, -3, -2, -1, 0);
846 else
847 writeCurveTo( i, -4, -5, -3, -2, -1, 0);
849 clear();
850 break;
851 case TYPE2OP::VVCURVETO:
852 i = (mnStackIdx & 1);
853 while( (i += 4) <= mnStackIdx) {
854 if( i != 5)
855 writeCurveTo( i, 0, -4, -3, -2, 0, -1);
856 else
857 writeCurveTo( i, -5, -4, -3, -2, 0, -1);
859 clear();
860 break;
861 case TYPE2OP::ENDCHAR:
862 if( mbNeedClose)
863 writeTypeOp( TYPE1OP::CLOSEPATH);
864 else
865 updateWidth( size() >= 1);
866 // mbNeedClose = true;
867 writeTypeOp( TYPE1OP::ENDCHAR);
868 break;
869 default:
870 if( ((nType2Op >= 32) && (nType2Op <= 255)) || (nType2Op == 28)) {
871 --mpReadPtr;
872 read2push();
873 } else {
874 popAll2Write( nType2Op);
875 assert(false && "TODO?");
877 break;
881 void CffSubsetterContext::convertOneTypeEsc()
883 const int nType2Esc = *(mpReadPtr++);
884 ValType* pTop = &mnValStack[ mnStackIdx-1];
885 // convert each T2op
886 switch( nType2Esc) {
887 case TYPE2OP::AND:
888 assert( mnStackIdx >= 2 );
889 pTop[0] = static_cast<ValType>(static_cast<int>(pTop[0]) & static_cast<int>(pTop[-1]));
890 --mnStackIdx;
891 break;
892 case TYPE2OP::OR:
893 assert( mnStackIdx >= 2 );
894 pTop[0] = static_cast<ValType>(static_cast<int>(pTop[0]) | static_cast<int>(pTop[-1]));
895 --mnStackIdx;
896 break;
897 case TYPE2OP::NOT:
898 assert( mnStackIdx >= 1 );
899 pTop[0] = ValType(pTop[0] == 0);
900 break;
901 case TYPE2OP::ABS:
902 assert( mnStackIdx >= 1 );
903 if( pTop[0] >= 0)
904 break;
905 [[fallthrough]];
906 case TYPE2OP::NEG:
907 assert( mnStackIdx >= 1 );
908 pTop[0] = -pTop[0];
909 break;
910 case TYPE2OP::ADD:
911 assert( mnStackIdx >= 2 );
912 pTop[0] += pTop[-1];
913 --mnStackIdx;
914 break;
915 case TYPE2OP::SUB:
916 assert( mnStackIdx >= 2 );
917 pTop[0] -= pTop[-1];
918 --mnStackIdx;
919 break;
920 case TYPE2OP::MUL:
921 assert( mnStackIdx >= 2 );
922 if( pTop[-1])
923 pTop[0] *= pTop[-1];
924 --mnStackIdx;
925 break;
926 case TYPE2OP::DIV:
927 assert( mnStackIdx >= 2 );
928 if( pTop[-1])
929 pTop[0] /= pTop[-1];
930 --mnStackIdx;
931 break;
932 case TYPE2OP::EQ:
933 assert( mnStackIdx >= 2 );
934 pTop[0] = ValType(pTop[0] == pTop[-1]);
935 --mnStackIdx;
936 break;
937 case TYPE2OP::DROP:
938 assert( mnStackIdx >= 1 );
939 --mnStackIdx;
940 break;
941 case TYPE2OP::PUT: {
942 assert( mnStackIdx >= 2 );
943 const int nIdx = static_cast<int>(pTop[0]);
944 assert( nIdx >= 0 );
945 assert( nIdx < NMAXTRANS );
946 mnTransVals[ nIdx] = pTop[-1];
947 mnStackIdx -= 2;
948 break;
950 case TYPE2OP::GET: {
951 assert( mnStackIdx >= 1 );
952 const int nIdx = static_cast<int>(pTop[0]);
953 assert( nIdx >= 0 );
954 assert( nIdx < NMAXTRANS );
955 pTop[0] = mnTransVals[ nIdx ];
956 break;
958 case TYPE2OP::IFELSE: {
959 assert( mnStackIdx >= 4 );
960 if( pTop[-1] > pTop[0] )
961 pTop[-3] = pTop[-2];
962 mnStackIdx -= 3;
963 break;
965 case TYPE2OP::RANDOM:
966 pTop[+1] = 1234; // TODO
967 ++mnStackIdx;
968 break;
969 case TYPE2OP::SQRT:
970 // TODO: implement
971 break;
972 case TYPE2OP::DUP:
973 assert( mnStackIdx >= 1 );
974 pTop[+1] = pTop[0];
975 ++mnStackIdx;
976 break;
977 case TYPE2OP::EXCH: {
978 assert( mnStackIdx >= 2 );
979 const ValType nVal = pTop[0];
980 pTop[0] = pTop[-1];
981 pTop[-1] = nVal;
982 break;
984 case TYPE2OP::INDEX: {
985 assert( mnStackIdx >= 1 );
986 const int nVal = static_cast<int>(pTop[0]);
987 assert( nVal >= 0 );
988 assert( nVal < mnStackIdx-1 );
989 pTop[0] = pTop[-1-nVal];
990 break;
992 case TYPE2OP::ROLL: {
993 assert( mnStackIdx >= 1 );
994 const int nNum = static_cast<int>(pTop[0]);
995 assert( nNum >= 0);
996 assert( nNum < mnStackIdx-2 );
997 (void)nNum; // TODO: implement
998 // TODO: implement: const int nOfs = static_cast<int>(pTop[-1]);
999 mnStackIdx -= 2;
1000 break;
1002 case TYPE2OP::HFLEX1: {
1003 assert( mnStackIdx == 9);
1005 writeCurveTo( mnStackIdx, -9, -8, -7, -6, -5, 0);
1006 writeCurveTo( mnStackIdx, -4, 0, -3, -2, -1, 0);
1007 // TODO: emulate hflex1 using othersubr call
1009 mnStackIdx -= 9;
1011 break;
1012 case TYPE2OP::HFLEX: {
1013 assert( mnStackIdx == 7);
1014 ValType* pX = &mnValStack[ mnStackIdx];
1016 pX[+1] = -pX[-5]; // temp: +dy5==-dy2
1017 writeCurveTo( mnStackIdx, -7, 0, -6, -5, -4, 0);
1018 writeCurveTo( mnStackIdx, -3, 0, -2, +1, -1, 0);
1019 // TODO: emulate hflex using othersubr call
1021 mnStackIdx -= 7;
1023 break;
1024 case TYPE2OP::FLEX: {
1025 assert( mnStackIdx == 13 );
1026 writeCurveTo( mnStackIdx, -13, -12, -11, -10, -9, -8 );
1027 writeCurveTo( mnStackIdx, -7, -6, -5, -4, -3, -2 );
1028 // ignoring ValType nFlexDepth = mnValStack[ mnStackIdx-1 ];
1029 mnStackIdx -= 13;
1031 break;
1032 case TYPE2OP::FLEX1: {
1033 assert( mnStackIdx == 11 );
1034 // write the first part of the flex1-hinted curve
1035 writeCurveTo( mnStackIdx, -11, -10, -9, -8, -7, -6 );
1037 // determine if nD6 is horizontal or vertical
1038 const int i = mnStackIdx;
1039 ValType nDeltaX = mnValStack[i-11] + mnValStack[i-9] + mnValStack[i-7] + mnValStack[i-5] + mnValStack[i-3];
1040 if( nDeltaX < 0 ) nDeltaX = -nDeltaX;
1041 ValType nDeltaY = mnValStack[i-10] + mnValStack[i-8] + mnValStack[i-6] + mnValStack[i-4] + mnValStack[i-2];
1042 if( nDeltaY < 0 ) nDeltaY = -nDeltaY;
1043 const bool bVertD6 = (nDeltaY > nDeltaX);
1045 // write the second part of the flex1-hinted curve
1046 if( !bVertD6 )
1047 writeCurveTo( mnStackIdx, -5, -4, -3, -2, -1, 0);
1048 else
1049 writeCurveTo( mnStackIdx, -5, -4, -3, -2, 0, -1);
1050 mnStackIdx -= 11;
1052 break;
1053 default:
1054 SAL_WARN("vcl.fonts", "unhandled type2esc " << nType2Esc);
1055 assert( false);
1056 break;
1060 void CffSubsetterContext::callType2Subr( bool bGlobal, int nSubrNumber)
1062 const U8* const pOldReadPtr = mpReadPtr;
1063 const U8* const pOldReadEnd = mpReadEnd;
1065 if( bGlobal ) {
1066 nSubrNumber += mnGlobalSubrBias;
1067 seekIndexData( mnGlobalSubrBase, nSubrNumber);
1068 } else {
1069 nSubrNumber += mpCffLocal->mnLocalSubrBias;
1070 seekIndexData( mpCffLocal->mnLocalSubrBase, nSubrNumber);
1073 while( mpReadPtr < mpReadEnd)
1074 convertOneTypeOp();
1076 mpReadPtr = pOldReadPtr;
1077 mpReadEnd = pOldReadEnd;
1080 const int MAX_T1OPS_SIZE = 81920; // TODO: use dynamic value
1082 int CffSubsetterContext::convert2Type1Ops( CffLocal* pCffLocal, const U8* const pT2Ops, int nT2Len, U8* const pT1Ops)
1084 mpCffLocal = pCffLocal;
1086 // prepare the charstring conversion
1087 mpWritePtr = pT1Ops;
1088 U8 aType1Ops[ MAX_T1OPS_SIZE];
1089 if( !pT1Ops)
1090 mpWritePtr = aType1Ops;
1091 *const_cast<U8**>(&pT1Ops) = mpWritePtr;
1093 // prepend random seed for T1crypt
1094 *(mpWritePtr++) = 0x48;
1095 *(mpWritePtr++) = 0x44;
1096 *(mpWritePtr++) = 0x55;
1097 *(mpWritePtr++) = ' ';
1099 // convert the Type2 charstring to Type1
1100 mpReadPtr = pT2Ops;
1101 mpReadEnd = pT2Ops + nT2Len;
1102 // prepend "hsbw" or "sbw"
1103 // TODO: only emit hsbw when charwidth is known
1104 writeType1Val(0); // TODO: aSubsetterContext.getLeftSideBearing();
1105 U8* pCharWidthPtr=mpWritePtr; // need to overwrite that later
1106 // pad out 5 bytes for the char width with default val 1000 (to be
1107 // filled with the actual value below)
1108 *(mpWritePtr++) = 255;
1109 *(mpWritePtr++) = static_cast<U8>(0);
1110 *(mpWritePtr++) = static_cast<U8>(0);
1111 *(mpWritePtr++) = static_cast<U8>(250);
1112 *(mpWritePtr++) = static_cast<U8>(124);
1113 writeTypeOp(TYPE1OP::HSBW);
1114 mbNeedClose = false;
1115 mbIgnoreHints = false;
1116 mnHintSize=mnHorzHintSize=mnStackIdx=0; maCharWidth=-1;//#######
1117 mnCntrMask = 0;
1118 while( mpReadPtr < mpReadEnd)
1119 convertOneTypeOp();
1120 if( maCharWidth != -1 )
1122 // overwrite earlier charWidth value, which we only now have
1123 // parsed out of mpReadPtr buffer (by way of
1124 // convertOneTypeOp()s above)
1125 const int nInt = static_cast<int>(maCharWidth);
1126 *(pCharWidthPtr++) = 255;
1127 *(pCharWidthPtr++) = static_cast<U8>(nInt >> 24);
1128 *(pCharWidthPtr++) = static_cast<U8>(nInt >> 16);
1129 *(pCharWidthPtr++) = static_cast<U8>(nInt >> 8);
1130 *(pCharWidthPtr++) = static_cast<U8>(nInt);
1133 const int nType1Len = mpWritePtr - pT1Ops;
1135 // encrypt the Type1 charstring
1136 unsigned nRDCryptR = 4330; // TODO: mnRDCryptSeed;
1137 for( U8* p = pT1Ops; p < mpWritePtr; ++p) {
1138 *p ^= (nRDCryptR >> 8);
1139 nRDCryptR = (*p + nRDCryptR) * 52845 + 22719;
1142 return nType1Len;
1145 RealType CffSubsetterContext::readRealVal()
1147 // TODO: more thorough number validity test
1148 bool bComma = false;
1149 int nExpVal = 0;
1150 int nExpSign = 0;
1151 S64 nNumber = 0;
1152 RealType fReal = +1.0;
1153 for(;;){
1154 const U8 c = *(mpReadPtr++); // read nibbles
1155 // parse high nibble
1156 const U8 nH = c >> 4U;
1157 if( nH <= 9) {
1158 nNumber = nNumber * 10 + nH;
1159 --nExpVal;
1160 } else if( nH == 10) { // comma
1161 nExpVal = 0;
1162 bComma = true;
1163 } else if( nH == 11) { // +exp
1164 fReal *= nNumber;
1165 nExpSign = +1;
1166 nNumber = 0;
1167 } else if( nH == 12) { // -exp
1168 fReal *= nNumber;
1169 nExpSign = -1;
1170 nNumber = 0;
1171 } else if( nH == 13) { // reserved
1172 // TODO: ignore or error?
1173 } else if( nH == 14) // minus
1174 fReal = -fReal;
1175 else if( nH == 15) // end
1176 break;
1177 // parse low nibble
1178 const U8 nL = c & 0x0F;
1179 if( nL <= 9) {
1180 nNumber = nNumber * 10 + nL;
1181 --nExpVal;
1182 } else if( nL == 10) { // comma
1183 nExpVal = 0;
1184 bComma = true;
1185 } else if( nL == 11) { // +exp
1186 fReal *= nNumber;
1187 nNumber = 0;
1188 nExpSign = +1;
1189 } else if( nL == 12) { // -exp
1190 fReal *= nNumber;
1191 nNumber = 0;
1192 nExpSign = -1;
1193 } else if( nL == 13) { // reserved
1194 // TODO: ignore or error?
1195 } else if( nL == 14) // minus
1196 fReal = -fReal;
1197 else if( nL == 15) // end
1198 break;
1201 // merge exponents
1202 if( !bComma)
1203 nExpVal = 0;
1204 if( !nExpSign) { fReal *= nNumber;}
1205 else if( nExpSign > 0) { nExpVal += static_cast<int>(nNumber);}
1206 else if( nExpSign < 0) { nExpVal -= static_cast<int>(nNumber);}
1208 // apply exponents
1209 if( !nExpVal) { /*nothing to apply*/}
1210 else if( nExpVal > 0) { while( --nExpVal >= 0) fReal *= 10.0;}
1211 else if( nExpVal < 0) { while( ++nExpVal <= 0) fReal /= 10.0;}
1212 return fReal;
1215 // prepare to access an element inside a CFF/CID index table
1216 int CffSubsetterContext::seekIndexData( int nIndexBase, int nDataIndex)
1218 assert( (nIndexBase > 0) && (mpBasePtr + nIndexBase + 3 <= mpBaseEnd));
1219 if( nDataIndex < 0)
1220 return -1;
1221 mpReadPtr = mpBasePtr + nIndexBase;
1222 const int nDataCount = (mpReadPtr[0]<<8) + mpReadPtr[1];
1223 if( nDataIndex >= nDataCount)
1224 return -1;
1225 const int nDataOfsSz = mpReadPtr[2];
1226 mpReadPtr += 3 + (nDataOfsSz * nDataIndex);
1227 int nOfs1 = 0;
1228 switch( nDataOfsSz) {
1229 default: SAL_WARN("vcl.fonts", "\tINVALID nDataOfsSz=" << nDataOfsSz); return -1;
1230 case 1: nOfs1 = mpReadPtr[0]; break;
1231 case 2: nOfs1 = (mpReadPtr[0]<<8) + mpReadPtr[1]; break;
1232 case 3: nOfs1 = (mpReadPtr[0]<<16) + (mpReadPtr[1]<<8) + mpReadPtr[2]; break;
1233 case 4: nOfs1 = (mpReadPtr[0]<<24) + (mpReadPtr[1]<<16) + (mpReadPtr[2]<<8) + mpReadPtr[3]; break;
1235 mpReadPtr += nDataOfsSz;
1237 int nOfs2 = 0;
1238 switch( nDataOfsSz) {
1239 case 1: nOfs2 = mpReadPtr[0]; break;
1240 case 2: nOfs2 = (mpReadPtr[0]<<8) + mpReadPtr[1]; break;
1241 case 3: nOfs2 = (mpReadPtr[0]<<16) + (mpReadPtr[1]<<8) + mpReadPtr[2]; break;
1242 case 4: nOfs2 = (mpReadPtr[0]<<24) + (mpReadPtr[1]<<16) + (mpReadPtr[2]<<8) + mpReadPtr[3]; break;
1245 mpReadPtr = mpBasePtr + (nIndexBase + 2) + nDataOfsSz * (nDataCount + 1) + nOfs1;
1246 mpReadEnd = mpReadPtr + (nOfs2 - nOfs1);
1247 assert( nOfs1 >= 0);
1248 assert( nOfs2 >= nOfs1);
1249 assert( mpReadPtr <= mpBaseEnd);
1250 assert( mpReadEnd <= mpBaseEnd);
1251 return (nOfs2 - nOfs1);
1254 // skip over a CFF/CID index table
1255 void CffSubsetterContext::seekIndexEnd( int nIndexBase)
1257 assert( (nIndexBase > 0) && (mpBasePtr + nIndexBase + 3 <= mpBaseEnd));
1258 mpReadPtr = mpBasePtr + nIndexBase;
1259 const int nDataCount = (mpReadPtr[0]<<8) + mpReadPtr[1];
1260 const int nDataOfsSz = mpReadPtr[2];
1261 mpReadPtr += 3 + nDataOfsSz * nDataCount;
1262 assert( mpReadPtr <= mpBaseEnd);
1263 int nEndOfs = 0;
1264 switch( nDataOfsSz) {
1265 default: SAL_WARN("vcl.fonts", "\tINVALID nDataOfsSz=" << nDataOfsSz); return;
1266 case 1: nEndOfs = mpReadPtr[0]; break;
1267 case 2: nEndOfs = (mpReadPtr[0]<<8) + mpReadPtr[1]; break;
1268 case 3: nEndOfs = (mpReadPtr[0]<<16) + (mpReadPtr[1]<<8) + mpReadPtr[2];break;
1269 case 4: nEndOfs = (mpReadPtr[0]<<24) + (mpReadPtr[1]<<16) + (mpReadPtr[2]<<8) + mpReadPtr[3]; break;
1271 mpReadPtr += nDataOfsSz;
1272 mpReadPtr += nEndOfs - 1;
1273 mpReadEnd = mpBaseEnd;
1274 assert( nEndOfs >= 0);
1275 assert( mpReadEnd <= mpBaseEnd);
1278 // initialize FONTDICT specific values
1279 CffLocal::CffLocal()
1280 : mnPrivDictBase( 0)
1281 , mnPrivDictSize( 0)
1282 , mnLocalSubrOffs( 0)
1283 , mnLocalSubrBase( 0)
1284 , mnLocalSubrBias( 0)
1285 , maNominalWidth( 0)
1286 , maDefaultWidth( 0)
1287 , maStemStdHW( 0)
1288 , maStemStdVW( 0)
1289 , mfBlueScale( 0.0)
1290 , mfBlueShift( 0.0)
1291 , mfBlueFuzz( 0.0)
1292 , mfExpFactor( 0.0)
1293 , mnLangGroup( 0)
1294 , mbForceBold( false)
1298 CffGlobal::CffGlobal()
1299 : mnNameIdxBase( 0)
1300 , mnStringIdxBase( 0)
1301 , mbCIDFont( false)
1302 , mnCharStrBase( 0)
1303 , mnCharStrCount( 0)
1304 , mnCharsetBase( 0)
1305 , mnGlobalSubrBase( 0)
1306 , mnGlobalSubrCount( 0)
1307 , mnGlobalSubrBias( 0)
1308 , mnFDSelectBase( 0)
1309 , mnFontDictBase( 0)
1310 , mnFDAryCount( 1)
1311 , mnFontNameSID( 0)
1312 , mnFullNameSID( 0)
1316 bool CffSubsetterContext::initialCffRead()
1318 // get the CFFHeader
1319 mpReadPtr = mpBasePtr;
1320 const U8 nVerMajor = *(mpReadPtr++);
1321 const U8 nVerMinor = *(mpReadPtr++);
1322 const U8 nHeaderSize = *(mpReadPtr++);
1323 const U8 nOffsetSize = *(mpReadPtr++);
1324 // TODO: is the version number useful for anything else?
1325 assert( (nVerMajor == 1) && (nVerMinor == 0));
1326 (void)(nVerMajor + nVerMinor + nOffsetSize); // avoid compiler warnings
1328 // prepare access to the NameIndex
1329 mnNameIdxBase = nHeaderSize;
1330 mpReadPtr = mpBasePtr + nHeaderSize;
1331 seekIndexEnd( mnNameIdxBase);
1333 // get the TopDict index
1334 const sal_Int32 nTopDictBase = getReadOfs();
1335 const int nTopDictCount = (mpReadPtr[0]<<8) + mpReadPtr[1];
1336 if( nTopDictCount) {
1337 for( int i = 0; i < nTopDictCount; ++i) {
1338 seekIndexData( nTopDictBase, i);
1339 while( mpReadPtr < mpReadEnd)
1340 readDictOp();
1341 assert( mpReadPtr == mpReadEnd);
1345 // prepare access to the String index
1346 mnStringIdxBase = getReadOfs();
1347 seekIndexEnd( mnStringIdxBase);
1349 // prepare access to the GlobalSubr index
1350 mnGlobalSubrBase = getReadOfs();
1351 mnGlobalSubrCount = (mpReadPtr[0]<<8) + mpReadPtr[1];
1352 mnGlobalSubrBias = (mnGlobalSubrCount<1240)?107:(mnGlobalSubrCount<33900)?1131:32768;
1353 // skip past the last GlobalSubr entry
1354 // seekIndexEnd( mnGlobalSubrBase);
1356 // get/skip the Encodings (we got mnEncodingBase from TOPDICT)
1357 // seekEncodingsEnd( mnEncodingBase);
1358 // get/skip the Charsets (we got mnCharsetBase from TOPDICT)
1359 // seekCharsetsEnd( mnCharStrBase);
1360 // get/skip FDSelect (CID only) data
1362 // prepare access to the CharStrings index (we got the base from TOPDICT)
1363 mpReadPtr = mpBasePtr + mnCharStrBase;
1364 mnCharStrCount = (mpReadPtr[0]<<8) + mpReadPtr[1];
1365 // seekIndexEnd( mnCharStrBase);
1367 // read the FDArray index (CID only)
1368 if( mbCIDFont) {
1369 // assert( mnFontDictBase == tellRel());
1370 mpReadPtr = mpBasePtr + mnFontDictBase;
1371 mnFDAryCount = (mpReadPtr[0]<<8) + mpReadPtr[1];
1372 if (o3tl::make_unsigned(mnFDAryCount) >= SAL_N_ELEMENTS(maCffLocal))
1374 SAL_INFO("vcl.fonts", "CffSubsetterContext: too many CFF in font");
1375 return false;
1378 // read FDArray details to get access to the PRIVDICTs
1379 for( int i = 0; i < mnFDAryCount; ++i) {
1380 mpCffLocal = &maCffLocal[i];
1381 seekIndexData( mnFontDictBase, i);
1382 while( mpReadPtr < mpReadEnd)
1383 readDictOp();
1384 assert( mpReadPtr == mpReadEnd);
1388 for( int i = 0; i < mnFDAryCount; ++i) {
1389 mpCffLocal = &maCffLocal[i];
1391 // get the PrivateDict index
1392 // (we got mnPrivDictSize and mnPrivDictBase from TOPDICT or FDArray)
1393 if( mpCffLocal->mnPrivDictSize != 0) {
1394 assert( mpCffLocal->mnPrivDictSize > 0);
1395 // get the PrivDict data
1396 mpReadPtr = mpBasePtr + mpCffLocal->mnPrivDictBase;
1397 mpReadEnd = mpReadPtr + mpCffLocal->mnPrivDictSize;
1398 assert( mpReadEnd <= mpBaseEnd);
1399 // read PrivDict details
1400 while( mpReadPtr < mpReadEnd)
1401 readDictOp();
1404 // prepare access to the LocalSubrs (we got mnLocalSubrOffs from PRIVDICT)
1405 if( mpCffLocal->mnLocalSubrOffs) {
1406 // read LocalSubrs summary
1407 mpCffLocal->mnLocalSubrBase = mpCffLocal->mnPrivDictBase + mpCffLocal->mnLocalSubrOffs;
1408 mpReadPtr = mpBasePtr + mpCffLocal->mnLocalSubrBase;
1409 const int nSubrCount = (mpReadPtr[0] << 8) + mpReadPtr[1];
1410 mpCffLocal->mnLocalSubrBias = (nSubrCount<1240)?107:(nSubrCount<33900)?1131:32768;
1411 // seekIndexEnd( mpCffLocal->mnLocalSubrBase);
1415 // ignore the Notices info
1417 return true;
1420 // get a cstring from a StringID
1421 const char* CffSubsetterContext::getString( int nStringID)
1423 // get a standard string if possible
1424 const static int nStdStrings = SAL_N_ELEMENTS(pStringIds);
1425 if( (nStringID >= 0) && (nStringID < nStdStrings))
1426 return pStringIds[ nStringID];
1428 // else get the string from the StringIndex table
1429 const U8* pReadPtr = mpReadPtr;
1430 const U8* pReadEnd = mpReadEnd;
1431 nStringID -= nStdStrings;
1432 int nLen = seekIndexData( mnStringIdxBase, nStringID);
1433 // assert( nLen >= 0);
1434 // TODO: just return the undecorated name
1435 // TODO: get rid of static char buffer
1436 static char aNameBuf[ 2560];
1437 if( nLen < 0) {
1438 sprintf( aNameBuf, "name[%d].notfound!", nStringID);
1439 } else {
1440 const int nMaxLen = sizeof(aNameBuf) - 1;
1441 if( nLen >= nMaxLen)
1442 nLen = nMaxLen;
1443 for( int i = 0; i < nLen; ++i)
1444 aNameBuf[i] = *(mpReadPtr++);
1445 aNameBuf[ nLen] = '\0';
1447 mpReadPtr = pReadPtr;
1448 mpReadEnd = pReadEnd;
1449 return aNameBuf;
1452 // access a CID's FDSelect table
1453 int CffSubsetterContext::getFDSelect( int nGlyphIndex) const
1455 assert( nGlyphIndex >= 0);
1456 assert( nGlyphIndex < mnCharStrCount);
1457 if( !mbCIDFont)
1458 return 0;
1460 const U8* pReadPtr = mpBasePtr + mnFDSelectBase;
1461 const U8 nFDSelFormat = *(pReadPtr++);
1462 switch( nFDSelFormat) {
1463 case 0: { // FDSELECT format 0
1464 pReadPtr += nGlyphIndex;
1465 const U8 nFDIdx = *(pReadPtr++);
1466 return nFDIdx;
1467 } //break;
1468 case 3: { // FDSELECT format 3
1469 const U16 nRangeCount = (pReadPtr[0]<<8) + pReadPtr[1];
1470 assert( nRangeCount > 0);
1471 assert( nRangeCount <= mnCharStrCount);
1472 U16 nPrev = (pReadPtr[2]<<8) + pReadPtr[3];
1473 assert( nPrev == 0);
1474 (void)nPrev;
1475 pReadPtr += 4;
1476 // TODO? binary search
1477 for( int i = 0; i < nRangeCount; ++i) {
1478 const U8 nFDIdx = pReadPtr[0];
1479 const U16 nNext = (pReadPtr[1]<<8) + pReadPtr[2];
1480 assert( nPrev < nNext);
1481 if( nGlyphIndex < nNext)
1482 return nFDIdx;
1483 pReadPtr += 3;
1484 nPrev = nNext;
1486 } break;
1487 default: // invalid FDselect format
1488 SAL_WARN("vcl.fonts", "invalid CFF.FdselType=" << nFDSelFormat);
1489 break;
1492 assert( false);
1493 return -1;
1496 int CffSubsetterContext::getGlyphSID( int nGlyphIndex) const
1498 if( nGlyphIndex == 0)
1499 return 0; // ".notdef"
1500 assert( nGlyphIndex >= 0);
1501 assert( nGlyphIndex < mnCharStrCount);
1502 if( (nGlyphIndex < 0) || (nGlyphIndex >= mnCharStrCount))
1503 return -1;
1505 // get the SID/CID from the Charset table
1506 const U8* pReadPtr = mpBasePtr + mnCharsetBase;
1507 const U8 nCSetFormat = *(pReadPtr++);
1508 int nGlyphsToSkip = nGlyphIndex - 1;
1509 switch( nCSetFormat) {
1510 case 0: // charset format 0
1511 pReadPtr += 2 * nGlyphsToSkip;
1512 nGlyphsToSkip = 0;
1513 break;
1514 case 1: // charset format 1
1515 while( nGlyphsToSkip >= 0) {
1516 const int nLeft = pReadPtr[2];
1517 if( nGlyphsToSkip <= nLeft)
1518 break;
1519 nGlyphsToSkip -= nLeft + 1;
1520 pReadPtr += 3;
1522 break;
1523 case 2: // charset format 2
1524 while( nGlyphsToSkip >= 0) {
1525 const int nLeft = (pReadPtr[2]<<8) + pReadPtr[3];
1526 if( nGlyphsToSkip <= nLeft)
1527 break;
1528 nGlyphsToSkip -= nLeft + 1;
1529 pReadPtr += 4;
1531 break;
1532 default:
1533 SAL_WARN("vcl.fonts", "ILLEGAL CFF-Charset format " << nCSetFormat);
1534 return -2;
1537 int nSID = (pReadPtr[0]<<8) + pReadPtr[1];
1538 nSID += nGlyphsToSkip;
1539 // NOTE: for CID-fonts the resulting SID is interpreted as CID
1540 return nSID;
1543 // NOTE: the result becomes invalid with the next call to this method
1544 const char* CffSubsetterContext::getGlyphName( int nGlyphIndex)
1546 // the first glyph is always the .notdef glyph
1547 const char* pGlyphName = ".notdef";
1548 if( nGlyphIndex == 0)
1549 return pGlyphName;
1551 // prepare a result buffer
1552 // TODO: get rid of static buffer
1553 static char aDefaultGlyphName[64];
1554 pGlyphName = aDefaultGlyphName;
1556 // get the glyph specific name
1557 const int nSID = getGlyphSID( nGlyphIndex);
1558 if( nSID < 0) // default glyph name
1559 sprintf( aDefaultGlyphName, "gly%03d", nGlyphIndex);
1560 else if( mbCIDFont) // default glyph name in CIDs
1561 sprintf( aDefaultGlyphName, "cid%03d", nSID);
1562 else { // glyph name from string table
1563 const char* pSidName = getString( nSID);
1564 // check validity of glyph name
1565 if( pSidName) {
1566 const char* p = pSidName;
1567 while( (*p >= '0') && (*p <= 'z')) ++p;
1568 if( (p >= pSidName+1) && (*p == '\0'))
1569 pGlyphName = pSidName;
1571 // if needed invent a fallback name
1572 if( pGlyphName != pSidName)
1573 sprintf( aDefaultGlyphName, "bad%03d", nSID);
1576 return pGlyphName;
1579 namespace {
1581 class Type1Emitter
1583 public:
1584 explicit Type1Emitter( FILE* pOutFile, bool bPfbSubset);
1585 ~Type1Emitter();
1586 void setSubsetName( const char* );
1588 size_t emitRawData( const char* pData, size_t nLength) const;
1589 void emitAllRaw();
1590 void emitAllHex();
1591 void emitAllCrypted();
1592 int tellPos() const;
1593 void updateLen( int nTellPos, size_t nLength);
1594 void emitValVector( const char* pLineHead, const char* pLineTail, const std::vector<ValType>&);
1595 private:
1596 FILE* mpFileOut;
1597 char maBuffer[MAX_T1OPS_SIZE]; // TODO: dynamic allocation
1598 unsigned mnEECryptR;
1599 public:
1600 char* mpPtr;
1602 char maSubsetName[256];
1603 bool mbPfbSubset;
1604 int mnHexLineCol;
1609 Type1Emitter::Type1Emitter( FILE* pOutFile, bool bPfbSubset)
1610 : mpFileOut( pOutFile)
1611 , maBuffer{}
1612 , mnEECryptR( 55665) // default eexec seed, TODO: mnEECryptSeed
1613 , mpPtr( maBuffer)
1614 , mbPfbSubset( bPfbSubset)
1615 , mnHexLineCol( 0)
1617 maSubsetName[0] = '\0';
1620 Type1Emitter::~Type1Emitter()
1622 if( !mpFileOut)
1623 return;
1624 mpFileOut = nullptr;
1627 void Type1Emitter::setSubsetName( const char* pSubsetName)
1629 maSubsetName[0] = '\0';
1630 if( pSubsetName)
1631 strncpy( maSubsetName, pSubsetName, sizeof(maSubsetName) - 1);
1632 maSubsetName[sizeof(maSubsetName)-1] = '\0';
1635 int Type1Emitter::tellPos() const
1637 int nTellPos = ftell( mpFileOut);
1638 return nTellPos;
1641 void Type1Emitter::updateLen( int nTellPos, size_t nLength)
1643 // update PFB segment header length
1644 U8 cData[4];
1645 cData[0] = static_cast<U8>(nLength >> 0);
1646 cData[1] = static_cast<U8>(nLength >> 8);
1647 cData[2] = static_cast<U8>(nLength >> 16);
1648 cData[3] = static_cast<U8>(nLength >> 24);
1649 const tools::Long nCurrPos = ftell(mpFileOut);
1650 if (nCurrPos < 0)
1651 return;
1652 if (fseek( mpFileOut, nTellPos, SEEK_SET) != 0)
1653 return;
1654 fwrite(cData, 1, sizeof(cData), mpFileOut);
1655 (void)fseek(mpFileOut, nCurrPos, SEEK_SET);
1658 inline size_t Type1Emitter::emitRawData(const char* pData, size_t nLength) const
1660 return fwrite( pData, 1, nLength, mpFileOut);
1663 inline void Type1Emitter::emitAllRaw()
1665 // writeout raw data
1666 assert( (mpPtr - maBuffer) < int(sizeof(maBuffer)));
1667 emitRawData( maBuffer, mpPtr - maBuffer);
1668 // reset the raw buffer
1669 mpPtr = maBuffer;
1672 inline void Type1Emitter::emitAllHex()
1674 assert( (mpPtr - maBuffer) < int(sizeof(maBuffer)));
1675 for( const char* p = maBuffer; p < mpPtr;) {
1676 // convert binary chunk to hex
1677 char aHexBuf[0x4000];
1678 char* pOut = aHexBuf;
1679 while( (p < mpPtr) && (pOut < aHexBuf+sizeof(aHexBuf)-4)) {
1680 // convert each byte to hex
1681 char cNibble = (static_cast<unsigned char>(*p) >> 4) & 0x0F;
1682 cNibble += (cNibble < 10) ? '0' : 'A'-10;
1683 *(pOut++) = cNibble;
1684 cNibble = *(p++) & 0x0F;
1685 cNibble += (cNibble < 10) ? '0' : 'A'-10;
1686 *(pOut++) = cNibble;
1687 // limit the line length
1688 if( (++mnHexLineCol & 0x3F) == 0)
1689 *(pOut++) = '\n';
1691 // writeout hex-converted chunk
1692 emitRawData( aHexBuf, pOut-aHexBuf);
1694 // reset the raw buffer
1695 mpPtr = maBuffer;
1698 void Type1Emitter::emitAllCrypted()
1700 // apply t1crypt
1701 for( char* p = maBuffer; p < mpPtr; ++p) {
1702 *p ^= (mnEECryptR >> 8);
1703 mnEECryptR = (*reinterpret_cast<U8*>(p) + mnEECryptR) * 52845 + 22719;
1706 // emit the t1crypt result
1707 if( mbPfbSubset)
1708 emitAllRaw();
1709 else
1710 emitAllHex();
1713 // #i110387# quick-and-dirty double->ascii conversion
1714 // needed because sprintf/ecvt/etc. alone are too localized (LC_NUMERIC)
1715 // also strip off trailing zeros in fraction while we are at it
1716 static int dbl2str( char* pOut, double fVal)
1718 const int nLen = psp::getValueOfDouble( pOut, fVal, 6);
1719 return nLen;
1722 void Type1Emitter::emitValVector( const char* pLineHead, const char* pLineTail,
1723 const std::vector<ValType>& rVector)
1725 // ignore empty vectors
1726 if( rVector.empty())
1727 return;
1729 // emit the line head
1730 mpPtr += sprintf( mpPtr, "%s", pLineHead);
1731 // emit the vector values
1732 std::vector<ValType>::value_type aVal = 0;
1733 for( std::vector<ValType>::const_iterator it = rVector.begin();;) {
1734 aVal = *it;
1735 if( ++it == rVector.end() )
1736 break;
1737 mpPtr += dbl2str( mpPtr, aVal);
1738 *(mpPtr++) = ' ';
1740 // emit the last value
1741 mpPtr += dbl2str( mpPtr, aVal);
1742 // emit the line tail
1743 mpPtr += sprintf( mpPtr, "%s", pLineTail);
1746 void CffSubsetterContext::emitAsType1( Type1Emitter& rEmitter,
1747 const sal_GlyphId* pReqGlyphIds, const U8* pReqEncoding,
1748 sal_Int32* pGlyphWidths, int nGlyphCount, FontSubsetInfo& rFSInfo)
1750 // prepare some fontdirectory details
1751 static const int nUniqueIdBase = 4100000; // using private-interchange UniqueIds
1752 static int nUniqueId = nUniqueIdBase;
1753 ++nUniqueId;
1755 char* pFontName = rEmitter.maSubsetName;
1756 if( !*pFontName ) {
1757 if( mnFontNameSID) {
1758 // get the fontname directly if available
1759 strncpy( pFontName, getString( mnFontNameSID), sizeof(rEmitter.maSubsetName) - 1);
1760 pFontName[sizeof(rEmitter.maSubsetName) - 1] = 0;
1761 } else if( mnFullNameSID) {
1762 // approximate fontname as fullname-whitespace
1763 const char* pI = getString( mnFullNameSID);
1764 char* pO = pFontName;
1765 const char* pLimit = pFontName + sizeof(rEmitter.maSubsetName) - 1;
1766 while( pO < pLimit) {
1767 const char c = *(pI++);
1768 if( c != ' ')
1769 *(pO++) = c;
1770 if( !c)
1771 break;
1773 *pO = '\0';
1774 } else {
1775 // fallback name of last resort
1776 strncpy( pFontName, "DummyName", sizeof(rEmitter.maSubsetName));
1779 const char* pFullName = pFontName;
1780 const char* pFamilyName = pFontName;
1782 char*& pOut = rEmitter.mpPtr; // convenience reference, TODO: cleanup
1784 // create a PFB+Type1 header
1785 if( rEmitter.mbPfbSubset ) {
1786 static const char aPfbHeader[] = "\x80\x01\x00\x00\x00\x00";
1787 rEmitter.emitRawData( aPfbHeader, sizeof(aPfbHeader)-1);
1790 pOut += sprintf( pOut, "%%!FontType1-1.0: %s 001.003\n", rEmitter.maSubsetName);
1791 // emit TOPDICT
1792 pOut += sprintf( pOut,
1793 "11 dict begin\n" // TODO: dynamic entry count for TOPDICT
1794 "/FontType 1 def\n"
1795 "/PaintType 0 def\n");
1796 pOut += sprintf( pOut, "/FontName /%s def\n", rEmitter.maSubsetName);
1797 pOut += sprintf( pOut, "/UniqueID %d def\n", nUniqueId);
1798 // emit FontMatrix
1799 if( maFontMatrix.size() == 6)
1800 rEmitter.emitValVector( "/FontMatrix [", "]readonly def\n", maFontMatrix);
1801 else // emit default FontMatrix if needed
1802 pOut += sprintf( pOut, "/FontMatrix [0.001 0 0 0.001 0 0]readonly def\n");
1803 // emit FontBBox
1804 if( maFontBBox.size() == 4)
1805 rEmitter.emitValVector( "/FontBBox {", "}readonly def\n", maFontBBox);
1806 else // emit default FontBBox if needed
1807 pOut += sprintf( pOut, "/FontBBox {0 0 999 999}readonly def\n");
1808 // emit FONTINFO into TOPDICT
1809 pOut += sprintf( pOut,
1810 "/FontInfo 2 dict dup begin\n" // TODO: check fontinfo entry count
1811 " /FullName (%s) readonly def\n"
1812 " /FamilyName (%s) readonly def\n"
1813 "end readonly def\n",
1814 pFullName, pFamilyName);
1816 pOut += sprintf( pOut,
1817 "/Encoding 256 array\n"
1818 "0 1 255 {1 index exch /.notdef put} for\n");
1819 for( int i = 1; (i < nGlyphCount) && (i < 256); ++i) {
1820 const char* pGlyphName = getGlyphName( pReqGlyphIds[i]);
1821 pOut += sprintf( pOut, "dup %d /%s put\n", pReqEncoding[i], pGlyphName);
1823 pOut += sprintf( pOut, "readonly def\n");
1824 pOut += sprintf( pOut,
1825 // TODO: more topdict entries
1826 "currentdict end\n"
1827 "currentfile eexec\n");
1829 // emit PFB header
1830 rEmitter.emitAllRaw();
1831 if( rEmitter.mbPfbSubset) {
1832 // update PFB header segment
1833 const int nPfbHeaderLen = rEmitter.tellPos() - 6;
1834 rEmitter.updateLen( 2, nPfbHeaderLen);
1836 // prepare start of eexec segment
1837 rEmitter.emitRawData( "\x80\x02\x00\x00\x00\x00", 6); // segment start
1839 const int nEExecSegTell = rEmitter.tellPos();
1841 // which always starts with a privdict
1842 // count the privdict entries
1843 int nPrivEntryCount = 9;
1844 // emit blue hints only if non-default values
1845 nPrivEntryCount += int(!mpCffLocal->maOtherBlues.empty());
1846 nPrivEntryCount += int(!mpCffLocal->maFamilyBlues.empty());
1847 nPrivEntryCount += int(!mpCffLocal->maFamilyOtherBlues.empty());
1848 nPrivEntryCount += int(mpCffLocal->mfBlueScale != 0.0);
1849 nPrivEntryCount += int(mpCffLocal->mfBlueShift != 0.0);
1850 nPrivEntryCount += int(mpCffLocal->mfBlueFuzz != 0.0);
1851 // emit stem hints only if non-default values
1852 nPrivEntryCount += int(mpCffLocal->maStemStdHW != 0);
1853 nPrivEntryCount += int(mpCffLocal->maStemStdVW != 0);
1854 nPrivEntryCount += int(!mpCffLocal->maStemSnapH.empty());
1855 nPrivEntryCount += int(!mpCffLocal->maStemSnapV.empty());
1856 // emit other hints only if non-default values
1857 nPrivEntryCount += int(mpCffLocal->mfExpFactor != 0.0);
1858 nPrivEntryCount += int(mpCffLocal->mnLangGroup != 0);
1859 nPrivEntryCount += int(mpCffLocal->mnLangGroup == 1);
1860 nPrivEntryCount += int(mpCffLocal->mbForceBold);
1861 // emit the privdict header
1862 pOut += sprintf( pOut,
1863 "\110\104\125 "
1864 "dup\n/Private %d dict dup begin\n"
1865 "/RD{string currentfile exch readstring pop}executeonly def\n"
1866 "/ND{noaccess def}executeonly def\n"
1867 "/NP{noaccess put}executeonly def\n"
1868 "/MinFeature{16 16}ND\n"
1869 "/password 5839 def\n", // TODO: mnRDCryptSeed?
1870 nPrivEntryCount);
1872 // emit blue hint related privdict entries
1873 if( !mpCffLocal->maBlueValues.empty())
1874 rEmitter.emitValVector( "/BlueValues [", "]ND\n", mpCffLocal->maBlueValues);
1875 else
1876 pOut += sprintf( pOut, "/BlueValues []ND\n"); // default to empty BlueValues
1877 rEmitter.emitValVector( "/OtherBlues [", "]ND\n", mpCffLocal->maOtherBlues);
1878 rEmitter.emitValVector( "/FamilyBlues [", "]ND\n", mpCffLocal->maFamilyBlues);
1879 rEmitter.emitValVector( "/FamilyOtherBlues [", "]ND\n", mpCffLocal->maFamilyOtherBlues);
1881 if( mpCffLocal->mfBlueScale) {
1882 pOut += sprintf( pOut, "/BlueScale ");
1883 pOut += dbl2str( pOut, mpCffLocal->mfBlueScale);
1884 pOut += sprintf( pOut, " def\n");
1886 if( mpCffLocal->mfBlueShift) { // default BlueShift==7
1887 pOut += sprintf( pOut, "/BlueShift ");
1888 pOut += dbl2str( pOut, mpCffLocal->mfBlueShift);
1889 pOut += sprintf( pOut, " def\n");
1891 if( mpCffLocal->mfBlueFuzz) { // default BlueFuzz==1
1892 pOut += sprintf( pOut, "/BlueFuzz ");
1893 pOut += dbl2str( pOut, mpCffLocal->mfBlueFuzz);
1894 pOut += sprintf( pOut, " def\n");
1897 // emit stem hint related privdict entries
1898 if( mpCffLocal->maStemStdHW) {
1899 pOut += sprintf( pOut, "/StdHW [");
1900 pOut += dbl2str( pOut, mpCffLocal->maStemStdHW);
1901 pOut += sprintf( pOut, "] def\n");
1903 if( mpCffLocal->maStemStdVW) {
1904 pOut += sprintf( pOut, "/StdVW [");
1905 pOut += dbl2str( pOut, mpCffLocal->maStemStdVW);
1906 pOut += sprintf( pOut, "] def\n");
1908 rEmitter.emitValVector( "/StemSnapH [", "]ND\n", mpCffLocal->maStemSnapH);
1909 rEmitter.emitValVector( "/StemSnapV [", "]ND\n", mpCffLocal->maStemSnapV);
1911 // emit other hints
1912 if( mpCffLocal->mbForceBold)
1913 pOut += sprintf( pOut, "/ForceBold true def\n");
1914 if( mpCffLocal->mnLangGroup != 0)
1915 pOut += sprintf( pOut, "/LanguageGroup %d def\n", mpCffLocal->mnLangGroup);
1916 if( mpCffLocal->mnLangGroup == 1) // compatibility with ancient printers
1917 pOut += sprintf( pOut, "/RndStemUp false def\n");
1918 if( mpCffLocal->mfExpFactor) {
1919 pOut += sprintf( pOut, "/ExpansionFactor ");
1920 pOut += dbl2str( pOut, mpCffLocal->mfExpFactor);
1921 pOut += sprintf( pOut, " def\n");
1924 // emit remaining privdict entries
1925 pOut += sprintf( pOut, "/UniqueID %d def\n", nUniqueId);
1926 // TODO?: more privdict entries?
1928 static const char aOtherSubrs[] =
1929 "/OtherSubrs\n"
1930 "% Dummy code for faking flex hints\n"
1931 "[ {} {} {} {systemdict /internaldict known not {pop 3}\n"
1932 "{1183615869 systemdict /internaldict get exec\n"
1933 "dup /startlock known\n"
1934 "{/startlock get exec}\n"
1935 "{dup /strtlck known\n"
1936 "{/strtlck get exec}\n"
1937 "{pop 3}\nifelse}\nifelse}\nifelse\n} executeonly\n"
1938 "] ND\n";
1939 memcpy( pOut, aOtherSubrs, sizeof(aOtherSubrs)-1);
1940 pOut += sizeof(aOtherSubrs)-1;
1942 // emit used GlobalSubr charstrings
1943 // these are the just the default subrs
1944 // TODO: do we need them as the flex hints are resolved differently?
1945 static const char aSubrs[] =
1946 "/Subrs 5 array\n"
1947 "dup 0 15 RD \x5F\x3D\x6B\xAC\x3C\xBD\x74\x3D\x3E\x17\xA0\x86\x58\x08\x85 NP\n"
1948 "dup 1 9 RD \x5F\x3D\x6B\xD8\xA6\xB5\x68\xB6\xA2 NP\n"
1949 "dup 2 9 RD \x5F\x3D\x6B\xAC\x39\x46\xB9\x43\xF9 NP\n"
1950 "dup 3 5 RD \x5F\x3D\x6B\xAC\xB9 NP\n"
1951 "dup 4 12 RD \x5F\x3D\x6B\xAC\x3E\x5D\x48\x54\x62\x76\x39\x03 NP\n"
1952 "ND\n";
1953 memcpy( pOut, aSubrs, sizeof(aSubrs)-1);
1954 pOut += sizeof(aSubrs)-1;
1956 // TODO: emit more GlobalSubr charstrings?
1957 // TODO: emit used LocalSubr charstrings?
1959 // emit the CharStrings for the requested glyphs
1960 pOut += sprintf( pOut,
1961 "2 index /CharStrings %d dict dup begin\n", nGlyphCount);
1962 rEmitter.emitAllCrypted();
1963 for( int i = 0; i < nGlyphCount; ++i) {
1964 const int nCffGlyphId = pReqGlyphIds[i];
1965 assert( (nCffGlyphId >= 0) && (nCffGlyphId < mnCharStrCount));
1966 // get privdict context matching to the glyph
1967 const int nFDSelect = getFDSelect( nCffGlyphId);
1968 if( nFDSelect < 0)
1969 continue;
1970 mpCffLocal = &maCffLocal[ nFDSelect];
1971 // convert the Type2op charstring to its Type1op counterpart
1972 const int nT2Len = seekIndexData( mnCharStrBase, nCffGlyphId);
1973 assert( nT2Len > 0);
1974 U8 aType1Ops[ MAX_T1OPS_SIZE]; // TODO: dynamic allocation
1975 const int nT1Len = convert2Type1Ops( mpCffLocal, mpReadPtr, nT2Len, aType1Ops);
1976 // get the glyph name
1977 const char* pGlyphName = getGlyphName( nCffGlyphId);
1978 // emit the encrypted Type1op charstring
1979 pOut += sprintf( pOut, "/%s %d RD ", pGlyphName, nT1Len);
1980 memcpy( pOut, aType1Ops, nT1Len);
1981 pOut += nT1Len;
1982 pOut += sprintf( pOut, " ND\n");
1983 rEmitter.emitAllCrypted();
1984 // provide individual glyphwidths if requested
1985 if( pGlyphWidths ) {
1986 ValType aCharWidth = maCharWidth;
1987 if( maFontMatrix.size() >= 4)
1988 aCharWidth *= 1000.0F * maFontMatrix[0];
1989 pGlyphWidths[i] = static_cast<sal_Int32>(aCharWidth);
1992 pOut += sprintf( pOut, "end end\nreadonly put\nput\n");
1993 pOut += sprintf( pOut, "dup/FontName get exch definefont pop\n");
1994 pOut += sprintf( pOut, "mark currentfile closefile\n");
1995 rEmitter.emitAllCrypted();
1997 // mark stop of eexec encryption
1998 if( rEmitter.mbPfbSubset) {
1999 const int nEExecLen = rEmitter.tellPos() - nEExecSegTell;
2000 rEmitter.updateLen( nEExecSegTell-4, nEExecLen);
2003 // create PFB footer
2004 static const char aPfxFooter[] = "\x80\x01\x14\x02\x00\x00\n" // TODO: check segment len
2005 "0000000000000000000000000000000000000000000000000000000000000000\n"
2006 "0000000000000000000000000000000000000000000000000000000000000000\n"
2007 "0000000000000000000000000000000000000000000000000000000000000000\n"
2008 "0000000000000000000000000000000000000000000000000000000000000000\n"
2009 "0000000000000000000000000000000000000000000000000000000000000000\n"
2010 "0000000000000000000000000000000000000000000000000000000000000000\n"
2011 "0000000000000000000000000000000000000000000000000000000000000000\n"
2012 "0000000000000000000000000000000000000000000000000000000000000000\n"
2013 "cleartomark\n"
2014 "\x80\x03";
2015 if( rEmitter.mbPfbSubset)
2016 rEmitter.emitRawData( aPfxFooter, sizeof(aPfxFooter)-1);
2017 else
2018 rEmitter.emitRawData( aPfxFooter+6, sizeof(aPfxFooter)-9);
2020 // provide details to the subset requesters, TODO: move into own method?
2021 // note: Top and Bottom are flipped between Type1 and VCL
2022 // note: the rest of VCL expects the details below to be scaled like for an emUnits==1000 font
2023 ValType fXFactor = 1.0;
2024 ValType fYFactor = 1.0;
2025 if( maFontMatrix.size() >= 4) {
2026 fXFactor = 1000.0F * maFontMatrix[0];
2027 fYFactor = 1000.0F * maFontMatrix[3];
2029 rFSInfo.m_aFontBBox = tools::Rectangle( Point( static_cast<sal_Int32>(maFontBBox[0] * fXFactor),
2030 static_cast<sal_Int32>(maFontBBox[1] * fYFactor) ),
2031 Point( static_cast<sal_Int32>(maFontBBox[2] * fXFactor),
2032 static_cast<sal_Int32>(maFontBBox[3] * fYFactor) ) );
2033 // PDF-Spec says the values below mean the ink bounds!
2034 // TODO: use better approximations for these ink bounds
2035 rFSInfo.m_nAscent = +rFSInfo.m_aFontBBox.Bottom(); // for capital letters
2036 rFSInfo.m_nDescent = -rFSInfo.m_aFontBBox.Top(); // for all letters
2037 rFSInfo.m_nCapHeight = rFSInfo.m_nAscent; // for top-flat capital letters
2039 rFSInfo.m_nFontType = rEmitter.mbPfbSubset ? FontType::TYPE1_PFB : FontType::TYPE1_PFA;
2040 rFSInfo.m_aPSName = OUString( rEmitter.maSubsetName, strlen(rEmitter.maSubsetName), RTL_TEXTENCODING_UTF8 );
2043 bool FontSubsetInfo::CreateFontSubsetFromCff( sal_Int32* pOutGlyphWidths )
2045 CffSubsetterContext aCff( mpInFontBytes, mnInByteLength);
2046 bool bRC = aCff.initialCffRead();
2047 if (!bRC)
2048 return bRC;
2050 // emit Type1 subset from the CFF input
2051 // TODO: also support CFF->CFF subsetting (when PDF-export and PS-printing need it)
2052 const bool bPfbSubset(mnReqFontTypeMask & FontType::TYPE1_PFB);
2053 Type1Emitter aType1Emitter( mpOutFile, bPfbSubset);
2054 aType1Emitter.setSubsetName( mpReqFontName);
2055 aCff.emitAsType1( aType1Emitter,
2056 mpReqGlyphIds, mpReqEncodedIds,
2057 pOutGlyphWidths, mnReqGlyphCount, *this);
2058 return true;
2061 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */