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