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