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