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