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