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