LibreOffice Module vcl (master) 1
cff.cxx
Go to the documentation of this file.
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
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/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
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 .
18 */
19
20#include <cstdio>
21#include <cstring>
22#include <vector>
23#include <assert.h>
24
25#include <fontsubset.hxx>
26
27#include <o3tl/safeint.hxx>
28#include <strhelper.hxx>
29#include <sal/log.hxx>
30
31typedef sal_uInt8 U8;
32typedef sal_uInt16 U16;
33typedef sal_Int64 S64;
34
35typedef double RealType;
37
38static 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"
137};
138
139// TOP DICT keywords (also covers PRIV DICT keywords)
140static 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
149};
150
151// TOP DICT escapes (also covers PRIV DICT escapes)
152static 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"
163};
164
165namespace {
166
167namespace TYPE1OP
168{
169 enum OPS
170 {
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
176 };
177
178 enum ESCS
179 {
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
183 };
184}
185
186namespace TYPE2OP
187{
188 enum OPS
189 {
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
197 };
198
199 enum ESCS
200 {
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
207 };
208}
209
210struct CffGlobal
211{
212 explicit CffGlobal();
213
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;
226
227 std::vector<ValType> maFontBBox;
228 std::vector<ValType> maFontMatrix;
229
230 int mnFontNameSID;
231 int mnFullNameSID;
232};
233
234struct CffLocal
235{
236 explicit CffLocal();
237
238 int mnPrivDictBase;
239 int mnPrivDictSize;
240 int mnLocalSubrOffs;
241 int mnLocalSubrBase;
242 int mnLocalSubrBias;
243
244 ValType maNominalWidth;
245 ValType maDefaultWidth;
246
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;
262};
263
264class CffSubsetterContext
265: private CffGlobal
266{
267public:
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
271
272 explicit CffSubsetterContext( const U8* pBasePtr, int nBaseLen);
273
274 bool initialCffRead();
275 void emitAsType1( class Type1Emitter&,
276 const sal_GlyphId* pGlyphIds, const U8* pEncoding,
277 sal_Int32* pGlyphWidths, int nGlyphCount, FontSubsetInfo& );
278
279private:
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);}
285
286 const U8* mpBasePtr;
287 const U8* mpBaseEnd;
288
289 const U8* mpReadPtr;
290 const U8* mpReadEnd;
291
292 U8* mpWritePtr;
293 bool mbNeedClose;
294 bool mbIgnoreHints;
295 sal_Int32 mnCntrMask;
296
297 int seekIndexData( int nIndexBase, int nDataIndex);
298 void seekIndexEnd( int nIndexBase);
299
300 CffLocal maCffLocal[256];
301 CffLocal* mpCffLocal;
302
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);
309
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);
317
318public: // 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;}
327
328 // accessing the charstring hints
329 void addHints( bool bVerticalHints);
330
331 // accessing other charstring specifics
332 void updateWidth( bool bUseFirstVal);
333
334private:
335 // typeop execution context
336 int mnStackIdx;
337 ValType mnValStack[ NMAXSTACK+4];
338 ValType mnTransVals[ NMAXTRANS];
339
340 int mnHintSize;
341 int mnHorzHintSize;
342 ValType mnHintStack[ NMAXHINTS];
343
344 ValType maCharWidth;
345};
346
347}
348
349CffSubsetterContext::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)
365{
366// setCharStringType( 1);
367 // TODO: new CffLocal[ mnFDAryCount];
368 mpCffLocal = &maCffLocal[0];
369}
370
371inline int CffSubsetterContext::popInt()
372{
373 const ValType aVal = popVal();
374 const int nInt = static_cast<int>(aVal);
375 assert( nInt == aVal);
376 return nInt;
377}
378
379inline void CffSubsetterContext::updateWidth( bool bUseFirstVal)
380{
381 // the first value is not a hint but the charwidth
382 if( maCharWidth>0 )
383 return;
384
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;
393 }
394}
395
396void CffSubsetterContext::addHints( bool bVerticalHints)
397{
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;
403
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);
408
409 assert( (mnHintSize + mnStackIdx) <= 2*NMAXHINTS);
410
411 ValType nHintOfs = 0;
412 for( int i = 0; i < mnStackIdx; ++i) {
413 nHintOfs += mnValStack[ i ];
414 mnHintStack[ mnHintSize++] = nHintOfs;
415 }
416
417 if( !bVerticalHints)
418 mnHorzHintSize = mnHintSize;
419
420 // clear all values from the stack
421 mnStackIdx = 0;
422}
423
424void CffSubsetterContext::readDictOp()
425{
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;
437 }
438
439 if (!pCmdName) // skip reserved operators
440 return;
441
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?
451 }
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?
473 }
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?
480 }
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?
487 }
488 }
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?
503 }
504 }
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?
514 }
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;
529 }
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);
548 }
549}
550
551void CffSubsetterContext::read2push()
552{
553 ValType aVal = 0;
554
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;
576 }
577
578 push( aVal);
579}
580
581void CffSubsetterContext::writeType1Val( ValType aVal)
582{
583 U8* pOut = mpWritePtr;
584
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);
602 }
603
604 mpWritePtr = pOut;
605}
606
607inline void CffSubsetterContext::writeTypeOp( int nTypeOp)
608{
609 *(mpWritePtr++) = static_cast<U8>(nTypeOp);
610}
611
612inline void CffSubsetterContext::writeTypeEsc( int nTypeEsc)
613{
614 *(mpWritePtr++) = TYPE1OP::T1ESC;
615 *(mpWritePtr++) = static_cast<U8>(nTypeEsc);
616}
617
618void CffSubsetterContext::pop2MultiWrite( int nArgsPerTypo, int nTypeOp, int nTypeXor)
619{
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);
624 }
625 i += nArgsPerTypo;
626 writeTypeOp( nTypeOp);
627 nTypeOp ^= nTypeXor; // for toggling vlineto/hlineto
628 }
629 clear();
630}
631
632void CffSubsetterContext::popAll2Write( int nTypeOp)
633{
634 // pop in reverse order, then write
635 for( int i = 0; i < mnStackIdx; ++i) {
636 const ValType aVal = mnValStack[i];
637 writeType1Val( aVal);
638 }
639 clear();
640 writeTypeOp( nTypeOp);
641}
642
643void CffSubsetterContext::writeCurveTo( int nStackPos,
644 int nIX1, int nIY1, int nIX2, int nIY2, int nIX3, int nIY3)
645{
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;
653
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 );
664}
665
666void CffSubsetterContext::convertOneTypeOp()
667{
668 const int nType2Op = *(mpReadPtr++);
669
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 );
683 }
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);
692 {
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;
699 }
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);
707 }
708 }
709 break;
710 case TYPE2OP::HINTMASK:
711 addHints( true);
712 {
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;
722 }
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;
731 }
732
733 mbIgnoreHints |= (nCntrBits[0] && (nCntrBits[0] != 3));
734 mbIgnoreHints |= (nCntrBits[1] && (nCntrBits[1] != 3));
735 if( mbIgnoreHints)
736 break;
737
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);
748 }
749 }
750 break;
751 case TYPE2OP::CALLSUBR:
752 case TYPE2OP::CALLGSUBR:
753 {
754 nInt = popInt();
755 const bool bGlobal = (nType2Op == TYPE2OP::CALLGSUBR);
756 callType2Subr( bGlobal, nInt);
757 }
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);
802 }
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);
811 }
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:
819 {
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);
837 }
838 }
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);
848 }
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);
858 }
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?");
876 }
877 break;
878 }
879}
880
881void CffSubsetterContext::convertOneTypeEsc()
882{
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;
949 }
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;
957 }
958 case TYPE2OP::IFELSE: {
959 assert( mnStackIdx >= 4 );
960 if( pTop[-1] > pTop[0] )
961 pTop[-3] = pTop[-2];
962 mnStackIdx -= 3;
963 break;
964 }
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;
983 }
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;
991 }
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;
1001 }
1002 case TYPE2OP::HFLEX1: {
1003 assert( mnStackIdx == 9);
1004
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
1008
1009 mnStackIdx -= 9;
1010 }
1011 break;
1012 case TYPE2OP::HFLEX: {
1013 assert( mnStackIdx == 7);
1014 ValType* pX = &mnValStack[ mnStackIdx];
1015
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
1020
1021 mnStackIdx -= 7;
1022 }
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;
1030 }
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 );
1036
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);
1044
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;
1051 }
1052 break;
1053 default:
1054 SAL_WARN("vcl.fonts", "unhandled type2esc " << nType2Esc);
1055 assert( false);
1056 break;
1057 }
1058}
1059
1060void CffSubsetterContext::callType2Subr( bool bGlobal, int nSubrNumber)
1061{
1062 const U8* const pOldReadPtr = mpReadPtr;
1063 const U8* const pOldReadEnd = mpReadEnd;
1064
1065 if( bGlobal ) {
1066 nSubrNumber += mnGlobalSubrBias;
1067 seekIndexData( mnGlobalSubrBase, nSubrNumber);
1068 } else {
1069 nSubrNumber += mpCffLocal->mnLocalSubrBias;
1070 seekIndexData( mpCffLocal->mnLocalSubrBase, nSubrNumber);
1071 }
1072
1073 while( mpReadPtr < mpReadEnd)
1074 convertOneTypeOp();
1075
1076 mpReadPtr = pOldReadPtr;
1077 mpReadEnd = pOldReadEnd;
1078}
1079
1080const int MAX_T1OPS_SIZE = 81920; // TODO: use dynamic value
1081
1082int CffSubsetterContext::convert2Type1Ops( CffLocal* pCffLocal, const U8* const pT2Ops, int nT2Len, U8* const pT1Ops)
1083{
1084 mpCffLocal = pCffLocal;
1085
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;
1092
1093 // prepend random seed for T1crypt
1094 *(mpWritePtr++) = 0x48;
1095 *(mpWritePtr++) = 0x44;
1096 *(mpWritePtr++) = 0x55;
1097 *(mpWritePtr++) = ' ';
1098
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 )
1121 {
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);
1131 }
1132
1133 const int nType1Len = mpWritePtr - pT1Ops;
1134
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;
1140 }
1141
1142 return nType1Len;
1143}
1144
1145RealType CffSubsetterContext::readRealVal()
1146{
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;
1199 }
1200
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);}
1207
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;
1213}
1214
1215// prepare to access an element inside a CFF/CID index table
1216int CffSubsetterContext::seekIndexData( int nIndexBase, int nDataIndex)
1217{
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;
1234 }
1235 mpReadPtr += nDataOfsSz;
1236
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;
1243 }
1244
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);
1252}
1253
1254// skip over a CFF/CID index table
1255void CffSubsetterContext::seekIndexEnd( int nIndexBase)
1256{
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;
1270 }
1271 mpReadPtr += nDataOfsSz;
1272 mpReadPtr += nEndOfs - 1;
1273 mpReadEnd = mpBaseEnd;
1274 assert( nEndOfs >= 0);
1275 assert( mpReadEnd <= mpBaseEnd);
1276}
1277
1278// initialize FONTDICT specific values
1279CffLocal::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)
1295{
1296}
1297
1298CffGlobal::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)
1313{
1314}
1315
1316bool CffSubsetterContext::initialCffRead()
1317{
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
1327
1328 // prepare access to the NameIndex
1329 mnNameIdxBase = nHeaderSize;
1330 mpReadPtr = mpBasePtr + nHeaderSize;
1331 seekIndexEnd( mnNameIdxBase);
1332
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);
1342 }
1343 }
1344
1345 // prepare access to the String index
1346 mnStringIdxBase = getReadOfs();
1347 seekIndexEnd( mnStringIdxBase);
1348
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);
1355
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
1361
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);
1366
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))
1373 {
1374 SAL_INFO("vcl.fonts", "CffSubsetterContext: too many CFF in font");
1375 return false;
1376 }
1377
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);
1385 }
1386 }
1387
1388 for( int i = 0; i < mnFDAryCount; ++i) {
1389 mpCffLocal = &maCffLocal[i];
1390
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();
1402 }
1403
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);
1412 }
1413 }
1414
1415 // ignore the Notices info
1416
1417 return true;
1418}
1419
1420// get a cstring from a StringID
1421const char* CffSubsetterContext::getString( int nStringID)
1422{
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];
1427
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';
1446 }
1447 mpReadPtr = pReadPtr;
1448 mpReadEnd = pReadEnd;
1449 return aNameBuf;
1450}
1451
1452// access a CID's FDSelect table
1453int CffSubsetterContext::getFDSelect( int nGlyphIndex) const
1454{
1455 assert( nGlyphIndex >= 0);
1456 assert( nGlyphIndex < mnCharStrCount);
1457 if( !mbCIDFont)
1458 return 0;
1459
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;
1485 }
1486 } break;
1487 default: // invalid FDselect format
1488 SAL_WARN("vcl.fonts", "invalid CFF.FdselType=" << nFDSelFormat);
1489 break;
1490 }
1491
1492 assert( false);
1493 return -1;
1494}
1495
1496int CffSubsetterContext::getGlyphSID( int nGlyphIndex) const
1497{
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;
1504
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;
1521 }
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;
1530 }
1531 break;
1532 default:
1533 SAL_WARN("vcl.fonts", "ILLEGAL CFF-Charset format " << nCSetFormat);
1534 return -2;
1535 }
1536
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;
1541}
1542
1543// NOTE: the result becomes invalid with the next call to this method
1544const char* CffSubsetterContext::getGlyphName( int nGlyphIndex)
1545{
1546 // the first glyph is always the .notdef glyph
1547 const char* pGlyphName = ".notdef";
1548 if( nGlyphIndex == 0)
1549 return pGlyphName;
1550
1551 // prepare a result buffer
1552 // TODO: get rid of static buffer
1553 static char aDefaultGlyphName[64];
1554 pGlyphName = aDefaultGlyphName;
1555
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;
1570 }
1571 // if needed invent a fallback name
1572 if( pGlyphName != pSidName)
1573 sprintf( aDefaultGlyphName, "bad%03d", nSID);
1574 }
1575
1576 return pGlyphName;
1577}
1578
1579namespace {
1580
1581class Type1Emitter
1582{
1583public:
1584 explicit Type1Emitter( FILE* pOutFile, bool bPfbSubset);
1585 ~Type1Emitter();
1586 void setSubsetName( const char* );
1587
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>&);
1595private:
1596 FILE* mpFileOut;
1597 char maBuffer[MAX_T1OPS_SIZE]; // TODO: dynamic allocation
1598 unsigned mnEECryptR;
1599public:
1600 char* mpPtr;
1601
1602 char maSubsetName[256];
1603 bool mbPfbSubset;
1604 int mnHexLineCol;
1605};
1606
1607}
1608
1609Type1Emitter::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)
1616{
1617 maSubsetName[0] = '\0';
1618}
1619
1620Type1Emitter::~Type1Emitter()
1621{
1622 if( !mpFileOut)
1623 return;
1624 mpFileOut = nullptr;
1625}
1626
1627void Type1Emitter::setSubsetName( const char* pSubsetName)
1628{
1629 maSubsetName[0] = '\0';
1630 if( pSubsetName)
1631 strncpy( maSubsetName, pSubsetName, sizeof(maSubsetName) - 1);
1632 maSubsetName[sizeof(maSubsetName)-1] = '\0';
1633}
1634
1635int Type1Emitter::tellPos() const
1636{
1637 int nTellPos = ftell( mpFileOut);
1638 return nTellPos;
1639}
1640
1641void Type1Emitter::updateLen( int nTellPos, size_t nLength)
1642{
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);
1656}
1657
1658inline size_t Type1Emitter::emitRawData(const char* pData, size_t nLength) const
1659{
1660 return fwrite( pData, 1, nLength, mpFileOut);
1661}
1662
1663inline void Type1Emitter::emitAllRaw()
1664{
1665 // writeout raw data
1666 assert( (mpPtr - maBuffer) < int(sizeof(maBuffer)));
1667 emitRawData( maBuffer, mpPtr - maBuffer);
1668 // reset the raw buffer
1669 mpPtr = maBuffer;
1670}
1671
1672inline void Type1Emitter::emitAllHex()
1673{
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';
1690 }
1691 // writeout hex-converted chunk
1692 emitRawData( aHexBuf, pOut-aHexBuf);
1693 }
1694 // reset the raw buffer
1695 mpPtr = maBuffer;
1696}
1697
1698void Type1Emitter::emitAllCrypted()
1699{
1700 // apply t1crypt
1701 for( char* p = maBuffer; p < mpPtr; ++p) {
1702 *p ^= (mnEECryptR >> 8);
1703 mnEECryptR = (*reinterpret_cast<U8*>(p) + mnEECryptR) * 52845 + 22719;
1704 }
1705
1706 // emit the t1crypt result
1707 if( mbPfbSubset)
1708 emitAllRaw();
1709 else
1710 emitAllHex();
1711}
1712
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
1716static int dbl2str( char* pOut, double fVal)
1717{
1718 const int nLen = psp::getValueOfDouble( pOut, fVal, 6);
1719 return nLen;
1720}
1721
1722void Type1Emitter::emitValVector( const char* pLineHead, const char* pLineTail,
1723 const std::vector<ValType>& rVector)
1724{
1725 // ignore empty vectors
1726 if( rVector.empty())
1727 return;
1728
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++) = ' ';
1739 }
1740 // emit the last value
1741 mpPtr += dbl2str( mpPtr, aVal);
1742 // emit the line tail
1743 mpPtr += sprintf( mpPtr, "%s", pLineTail);
1744}
1745
1746void CffSubsetterContext::emitAsType1( Type1Emitter& rEmitter,
1747 const sal_GlyphId* pReqGlyphIds, const U8* pReqEncoding,
1748 sal_Int32* pGlyphWidths, int nGlyphCount, FontSubsetInfo& rFSInfo)
1749{
1750 // prepare some fontdirectory details
1751 static const int nUniqueIdBase = 4100000; // using private-interchange UniqueIds
1752 static int nUniqueId = nUniqueIdBase;
1753 ++nUniqueId;
1754
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;
1772 }
1773 *pO = '\0';
1774 } else {
1775 // fallback name of last resort
1776 strncpy( pFontName, "DummyName", sizeof(rEmitter.maSubsetName));
1777 }
1778 }
1779 const char* pFullName = pFontName;
1780 const char* pFamilyName = pFontName;
1781
1782 char*& pOut = rEmitter.mpPtr; // convenience reference, TODO: cleanup
1783
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);
1788 }
1789
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);
1815
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);
1822 }
1823 pOut += sprintf( pOut, "readonly def\n");
1824 pOut += sprintf( pOut,
1825 // TODO: more topdict entries
1826 "currentdict end\n"
1827 "currentfile eexec\n");
1828
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);
1835
1836 // prepare start of eexec segment
1837 rEmitter.emitRawData( "\x80\x02\x00\x00\x00\x00", 6); // segment start
1838 }
1839 const int nEExecSegTell = rEmitter.tellPos();
1840
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);
1871
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);
1880
1881 if( mpCffLocal->mfBlueScale) {
1882 pOut += sprintf( pOut, "/BlueScale ");
1883 pOut += dbl2str( pOut, mpCffLocal->mfBlueScale);
1884 pOut += sprintf( pOut, " def\n");
1885 }
1886 if( mpCffLocal->mfBlueShift) { // default BlueShift==7
1887 pOut += sprintf( pOut, "/BlueShift ");
1888 pOut += dbl2str( pOut, mpCffLocal->mfBlueShift);
1889 pOut += sprintf( pOut, " def\n");
1890 }
1891 if( mpCffLocal->mfBlueFuzz) { // default BlueFuzz==1
1892 pOut += sprintf( pOut, "/BlueFuzz ");
1893 pOut += dbl2str( pOut, mpCffLocal->mfBlueFuzz);
1894 pOut += sprintf( pOut, " def\n");
1895 }
1896
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");
1902 }
1903 if( mpCffLocal->maStemStdVW) {
1904 pOut += sprintf( pOut, "/StdVW [");
1905 pOut += dbl2str( pOut, mpCffLocal->maStemStdVW);
1906 pOut += sprintf( pOut, "] def\n");
1907 }
1908 rEmitter.emitValVector( "/StemSnapH [", "]ND\n", mpCffLocal->maStemSnapH);
1909 rEmitter.emitValVector( "/StemSnapV [", "]ND\n", mpCffLocal->maStemSnapV);
1910
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");
1922 }
1923
1924 // emit remaining privdict entries
1925 pOut += sprintf( pOut, "/UniqueID %d def\n", nUniqueId);
1926 // TODO?: more privdict entries?
1927
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;
1941
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;
1955
1956 // TODO: emit more GlobalSubr charstrings?
1957 // TODO: emit used LocalSubr charstrings?
1958
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);
1990 }
1991 }
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();
1996
1997 // mark stop of eexec encryption
1998 if( rEmitter.mbPfbSubset) {
1999 const int nEExecLen = rEmitter.tellPos() - nEExecSegTell;
2000 rEmitter.updateLen( nEExecSegTell-4, nEExecLen);
2001 }
2002
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);
2019
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];
2028 }
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
2038
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 );
2041}
2042
2043bool FontSubsetInfo::CreateFontSubsetFromCff( sal_Int32* pOutGlyphWidths )
2044{
2045 CffSubsetterContext aCff( mpInFontBytes, mnInByteLength);
2046 bool bRC = aCff.initialCffRead();
2047 if (!bRC)
2048 return bRC;
2049
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,
2057 pOutGlyphWidths, mnReqGlyphCount, *this);
2058 return true;
2059}
2060
2061/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
static const char * pDictOps[]
Definition: cff.cxx:140
sal_uInt8 U8
Definition: cff.cxx:31
double RealType
Definition: cff.cxx:35
sal_Int64 S64
Definition: cff.cxx:33
const int MAX_T1OPS_SIZE
Definition: cff.cxx:1080
static const char * pStringIds[]
Definition: cff.cxx:38
sal_uInt16 U16
Definition: cff.cxx:32
ESCS
Definition: cff.cxx:179
static int dbl2str(char *pOut, double fVal)
Definition: cff.cxx:1716
static const char * pDictEscs[]
Definition: cff.cxx:152
OPS
Definition: cff.cxx:170
RealType ValType
Definition: cff.cxx:36
tools::Rectangle m_aFontBBox
Definition: fontsubset.hxx:70
OUString m_aPSName
Definition: fontsubset.hxx:66
const char * mpReqFontName
Definition: fontsubset.hxx:83
FontType m_nFontType
font-type of subset result
Definition: fontsubset.hxx:71
unsigned const char * mpInFontBytes
Definition: fontsubset.hxx:75
FILE * mpOutFile
Definition: fontsubset.hxx:82
const sal_GlyphId * mpReqGlyphIds
Definition: fontsubset.hxx:84
const sal_uInt8 * mpReqEncodedIds
Definition: fontsubset.hxx:85
FontType mnReqFontTypeMask
allowed subset-target font types
Definition: fontsubset.hxx:81
bool CreateFontSubsetFromCff(sal_Int32 *pOutGlyphWidths)
Definition: cff.cxx:2043
int m_nAscent
all metrics in PS font units
Definition: fontsubset.hxx:67
constexpr tools::Long Top() const
constexpr tools::Long Bottom() const
@ TYPE1_PFB
PSType1 Postscript Font Binary.
@ TYPE1_PFA
PSType1 Postscript Font Ascii.
sal_uInt16 sal_GlyphId
Definition: glyphid.hxx:24
sal_Int32 nIndex
void * p
#define SAL_WARN(area, stream)
#define SAL_INFO(area, stream)
#define SAL_N_ELEMENTS(arr)
Definition: cff.cxx:168
Definition: cff.cxx:187
size
OUString getString(const Any &_rAny)
int i
constexpr std::enable_if_t< std::is_signed_v< T >, std::make_unsigned_t< T > > make_unsigned(T value)
int getValueOfDouble(char *pBuffer, double f, int nPrecision=0)
Definition: strhelper.hxx:60
long Long
const wchar_t *typedef int(__stdcall *DllNativeUnregProc)(int
#define PUT(p, e, t, m)
NOT
MUL
GET
SUB
RETURN
DIV
AND
OR
EQ
RANDOM
NEG
unsigned char sal_uInt8
oslFileHandle & pOut
sal_Int32 nLength