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