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