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 
31 typedef sal_uInt8 U8;
32 typedef sal_uInt16 U16;
33 typedef sal_Int64 S64;
34 
35 typedef double RealType;
36 typedef RealType ValType;
37 
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"
137 };
138 
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
149 };
150 
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"
163 };
164 
165 namespace {
166 
167 namespace 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 
186 namespace 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 
210 struct 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 
234 struct 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 
264 class CffSubsetterContext
265 : private CffGlobal
266 {
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
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 
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);}
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 
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;}
327 
328  // accessing the charstring hints
329  void addHints( bool bVerticalHints);
330 
331  // accessing other charstring specifics
332  void updateWidth( bool bUseFirstVal);
333 
334 private:
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 
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)
365 {
366 // setCharStringType( 1);
367  // TODO: new CffLocal[ mnFDAryCount];
368  mpCffLocal = &maCffLocal[0];
369 }
370 
371 inline 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 
379 inline 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 
396 void 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 
424 void 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 
551 void 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 
581 void 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 
607 inline void CffSubsetterContext::writeTypeOp( int nTypeOp)
608 {
609  *(mpWritePtr++) = static_cast<U8>(nTypeOp);
610 }
611 
612 inline void CffSubsetterContext::writeTypeEsc( int nTypeEsc)
613 {
614  *(mpWritePtr++) = TYPE1OP::T1ESC;
615  *(mpWritePtr++) = static_cast<U8>(nTypeEsc);
616 }
617 
618 void 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 
632 void 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 
643 void 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 
666 void 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 
881 void 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 
1060 void 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 
1080 const int MAX_T1OPS_SIZE = 81920; // TODO: use dynamic value
1081 
1082 int 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 
1145 RealType 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
1216 int 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
1255 void 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
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)
1295 {
1296 }
1297 
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)
1313 {
1314 }
1315 
1316 bool 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
1421 const 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
1453 int 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 
1496 int 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
1544 const 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 
1579 namespace {
1580 
1581 class Type1Emitter
1582 {
1583 public:
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>&);
1595 private:
1596  FILE* mpFileOut;
1597  char maBuffer[MAX_T1OPS_SIZE]; // TODO: dynamic allocation
1598  unsigned mnEECryptR;
1599 public:
1600  char* mpPtr;
1601 
1602  char maSubsetName[256];
1603  bool mbPfbSubset;
1604  int mnHexLineCol;
1605 };
1606 
1607 }
1608 
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)
1616 {
1617  maSubsetName[0] = '\0';
1618 }
1619 
1620 Type1Emitter::~Type1Emitter()
1621 {
1622  if( !mpFileOut)
1623  return;
1624  mpFileOut = nullptr;
1625 }
1626 
1627 void 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 
1635 int Type1Emitter::tellPos() const
1636 {
1637  int nTellPos = ftell( mpFileOut);
1638  return nTellPos;
1639 }
1640 
1641 void 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 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 
1658 inline size_t Type1Emitter::emitRawData(const char* pData, size_t nLength) const
1659 {
1660  return fwrite( pData, 1, nLength, mpFileOut);
1661 }
1662 
1663 inline 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 
1672 inline 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 
1698 void 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
1716 static int dbl2str( char* pOut, double fVal)
1717 {
1718  const int nLen = psp::getValueOfDouble( pOut, fVal, 6);
1719  return nLen;
1720 }
1721 
1722 void 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 
1746 void 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 
2043 bool 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: */
FontType m_nFontType
font-type of subset result
Definition: fontsubset.hxx:70
MUL
RANDOM
const sal_GlyphId * mpReqGlyphIds
Definition: fontsubset.hxx:83
OPS
Definition: cff.cxx:169
double RealType
Definition: cff.cxx:35
const wchar_t *typedef int(__stdcall *DllNativeUnregProc)(int
bool CreateFontSubsetFromCff(sal_Int32 *pOutGlyphWidths)
Definition: cff.cxx:2043
const int MAX_T1OPS_SIZE
Definition: cff.cxx:1080
sal_uInt16 sal_GlyphId
Definition: glyphitem.hxx:26
OUString m_aPSName
Definition: fontsubset.hxx:65
const BorderLinePrimitive2D *pCandidateB assert(pCandidateA)
oslFileHandle & pOut
long Top() const
const char * mpReqFontName
Definition: fontsubset.hxx:82
#define SAL_N_ELEMENTS(arr)
DIV
unsigned const char * mpInFontBytes
Definition: fontsubset.hxx:74
int i
NOT
constexpr std::enable_if_t< std::is_signed_v< T >, std::make_unsigned_t< T > > make_unsigned(T value)
#define PUT(p, e, t, m)
PSType1 Postscript Font Ascii.
long Bottom() const
ESCS
Definition: cff.cxx:178
size
sal_Int64 S64
Definition: cff.cxx:33
Definition: cff.cxx:167
Definition: cff.cxx:186
FILE * mpOutFile
Definition: fontsubset.hxx:81
NEG
static const char * pDictOps[]
Definition: cff.cxx:140
static int dbl2str(char *pOut, double fVal)
Definition: cff.cxx:1716
FontType mnReqFontTypeMask
allowed subset-target font types
Definition: fontsubset.hxx:80
SUB
const sal_uInt8 * mpReqEncodedIds
Definition: fontsubset.hxx:84
unsigned char sal_uInt8
#define SAL_INFO(area, stream)
OR
GET
EQ
void * p
int getValueOfDouble(char *pBuffer, double f, int nPrecision=0)
Definition: strhelper.hxx:60
sal_uInt16 U16
Definition: cff.cxx:32
RealType ValType
Definition: cff.cxx:36
int m_nAscent
all metrics in PS font units
Definition: fontsubset.hxx:66
static const char * pDictEscs[]
Definition: cff.cxx:152
PSType1 Postscript Font Binary.
#define SAL_WARN(area, stream)
OUString getString(const Any &_rAny)
RETURN
tools::Rectangle m_aFontBBox
Definition: fontsubset.hxx:69
sal_uInt8 U8
Definition: cff.cxx:31
static const char * pStringIds[]
Definition: cff.cxx:38
AND
typedef void(CALLTYPE *GetFuncDataPtr)(sal_uInt16 &nNo