1 /* Copyright (C) 2000-2012 by George Williams */
2 /*
3 * Redistribution and use in source and binary forms, with or without
4 * modification, are permitted provided that the following conditions are met:
5
6 * Redistributions of source code must retain the above copyright notice, this
7 * list of conditions and the following disclaimer.
8
9 * Redistributions in binary form must reproduce the above copyright notice,
10 * this list of conditions and the following disclaimer in the documentation
11 * and/or other materials provided with the distribution.
12
13 * The name of the author may not be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
19 * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28 #include <fontforge-config.h>
29
30 #include "encoding.h"
31
32 #include "bitmapchar.h"
33 #include "bvedit.h"
34 #include "dumppfa.h"
35 #include "encoding.h"
36 #include "ffglib.h"
37 #include "fontforgevw.h"
38 #include "fvfonts.h"
39 #include "gfile.h"
40 #include "namelist.h"
41 #include "psfont.h"
42 #include "psread.h"
43 #include "pua.h"
44 #include "splinefill.h"
45 #include "splinefont.h"
46 #include "splinesaveafm.h"
47 #include "splineutil.h"
48 #include "splineutil2.h"
49 #include "ustring.h"
50 #include "utype.h"
51
52 #include <dirent.h>
53 #include <math.h>
54 #include <sys/types.h>
55 #include <unistd.h>
56
57 Encoding *default_encoding = NULL;
58
59 static int32 tex_base_encoding[] = {
60 0x0000, 0x02d9, 0xfb01, 0xfb02, 0x2044, 0x02dd, 0x0141, 0x0142,
61 0x02db, 0x02da, 0x000a, 0x02d8, 0x2212, 0x000d, 0x017d, 0x017e,
62 0x02c7, 0x0131, 0xf6be, 0xfb00, 0xfb03, 0xfb04, 0x2260, 0x221e,
63 0x2264, 0x2265, 0x2202, 0x2211, 0x220f, 0x03c0, 0x0060, 0x0027,
64 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x2019,
65 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f,
66 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
67 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f,
68 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
69 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f,
70 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057,
71 0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f,
72 0x2018, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067,
73 0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f,
74 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077,
75 0x0078, 0x0079, 0x007a, 0x007b, 0x007c, 0x007d, 0x007e, 0x007f,
76 0x20ac, 0x222b, 0x201a, 0x0192, 0x201e, 0x2026, 0x2020, 0x2021,
77 0x02c6, 0x2030, 0x0160, 0x2039, 0x0152, 0x2126, 0x221a, 0x2248,
78 0x0090, 0x0091, 0x0092, 0x201c, 0x201d, 0x2022, 0x2013, 0x2014,
79 0x02dc, 0x2122, 0x0161, 0x203a, 0x0153, 0x2206, 0x25ca, 0x0178,
80 0x0000, 0x00a1, 0x00a2, 0x00a3, 0x00a4, 0x00a5, 0x00a6, 0x00a7,
81 0x00a8, 0x00a9, 0x00aa, 0x00ab, 0x00ac, 0x002d, 0x00ae, 0x00af,
82 0x00b0, 0x00b1, 0x00b2, 0x00b3, 0x00b4, 0x00b5, 0x00b6, 0x00b7,
83 0x00b8, 0x00b9, 0x00ba, 0x00bb, 0x00bc, 0x00bd, 0x00be, 0x00bf,
84 0x00c0, 0x00c1, 0x00c2, 0x00c3, 0x00c4, 0x00c5, 0x00c6, 0x00c7,
85 0x00c8, 0x00c9, 0x00ca, 0x00cb, 0x00cc, 0x00cd, 0x00ce, 0x00cf,
86 0x00d0, 0x00d1, 0x00d2, 0x00d3, 0x00d4, 0x00d5, 0x00d6, 0x00d7,
87 0x00d8, 0x00d9, 0x00da, 0x00db, 0x00dc, 0x00dd, 0x00de, 0x00df,
88 0x00e0, 0x00e1, 0x00e2, 0x00e3, 0x00e4, 0x00e5, 0x00e6, 0x00e7,
89 0x00e8, 0x00e9, 0x00ea, 0x00eb, 0x00ec, 0x00ed, 0x00ee, 0x00ef,
90 0x00f0, 0x00f1, 0x00f2, 0x00f3, 0x00f4, 0x00f5, 0x00f6, 0x00f7,
91 0x00f8, 0x00f9, 0x00fa, 0x00fb, 0x00fc, 0x00fd, 0x00fe, 0x00ff
92 };
93
94 static int32 unicode_from_MacSymbol[] = {
95 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007,
96 0x0008, 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f,
97 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017,
98 0x0018, 0x0019, 0x001a, 0x001b, 0x001c, 0x001d, 0x001e, 0x001f,
99 0x0020, 0x0021, 0x2200, 0x0023, 0x2203, 0x0025, 0x0026, 0x220d,
100 0x0028, 0x0029, 0x2217, 0x002b, 0x002c, 0x2212, 0x002e, 0x002f,
101 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
102 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f,
103 0x2245, 0x0391, 0x0392, 0x03a7, 0x0394, 0x0395, 0x03a6, 0x0393,
104 0x0397, 0x0399, 0x03d1, 0x039a, 0x039b, 0x039c, 0x039d, 0x039f,
105 0x03a0, 0x0398, 0x03a1, 0x03a3, 0x03a4, 0x03a5, 0x03c2, 0x03a9,
106 0x039e, 0x03a8, 0x0396, 0x005b, 0x2234, 0x005d, 0x22a5, 0x005f,
107 0xf8e5, 0x03b1, 0x03b2, 0x03c7, 0x03b4, 0x03b5, 0x03c6, 0x03b3,
108 0x03b7, 0x03b9, 0x03d5, 0x03ba, 0x03bb, 0x03bc, 0x03bd, 0x03bf,
109 0x03c0, 0x03b8, 0x03c1, 0x03c3, 0x03c4, 0x03c5, 0x03d6, 0x03c9,
110 0x03be, 0x03c8, 0x03b6, 0x007b, 0x007c, 0x007d, 0x223c, 0x007f,
111 0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087,
112 0x0088, 0x0089, 0x008a, 0x008b, 0x008c, 0x008d, 0x008e, 0x008f,
113 0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097,
114 0x0098, 0x0099, 0x009a, 0x009b, 0x009c, 0x009d, 0x009e, 0x009f,
115 0x0000, 0x03d2, 0x2032, 0x2264, 0x2044, 0x221e, 0x0192, 0x2663,
116 0x2666, 0x2665, 0x2660, 0x2194, 0x2190, 0x2191, 0x2192, 0x2193,
117 0x00b0, 0x00b1, 0x2033, 0x2265, 0x00d7, 0x221d, 0x2202, 0x2022,
118 0x00f7, 0x2260, 0x2261, 0x2248, 0x2026, 0xf8e6, 0xf8e7, 0x21b5,
119 0x2135, 0x2111, 0x211c, 0x2118, 0x2297, 0x2295, 0x2205, 0x2229,
120 0x222a, 0x2283, 0x2287, 0x2284, 0x2282, 0x2286, 0x2208, 0x2209,
121 0x2220, 0x2207, 0x00ae, 0x00a9, 0x2122, 0x220f, 0x221a, 0x22c5,
122 0x00ac, 0x2227, 0x2228, 0x21d4, 0x21d0, 0x21d1, 0x21d2, 0x21d3,
123 0x22c4, 0x2329, 0xf8e8, 0xf8e9, 0xf8ea, 0x2211, 0xf8eb, 0xf8ec,
124 0xf8ed, 0xf8ee, 0xf8ef, 0xf8f0, 0xf8f1, 0xf8f2, 0xf8f3, 0xf8f4,
125 0xf8ff, 0x232a, 0x222b, 0x2320, 0xf8f5, 0x2321, 0xf8f6, 0xf8f7,
126 0xf8f8, 0xf8f9, 0xf8fa, 0xf8fb, 0xf8fc, 0xf8fd, 0xf8fe, 0x02c7
127 };
128
129 /* I don't think iconv provides encodings for zapfdingbats nor jis201 */
130 /* Perhaps I should list them here for compatability, but I think I'll just */
131 /* leave them out. I doubt they get used. */
132 static Encoding texbase = { "TeX-Base-Encoding", 256, tex_base_encoding, NULL, NULL, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "", 0, 0, 0, NULL, NULL, NULL, NULL, NULL, 0, 0 };
133 Encoding custom = { "Custom", 0, NULL, NULL, &texbase, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, "", 0, 0, 0, NULL, NULL, NULL, NULL, NULL, 0, 0 };
134 static Encoding original = { "Original", 0, NULL, NULL, &custom, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, "", 0, 0, 0, NULL, NULL, NULL, NULL, NULL, 0, 0 };
135 static Encoding unicodebmp = { "UnicodeBmp", 65536, NULL, NULL, &original, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, "", 0, 0, 0, NULL, NULL, NULL, NULL, NULL, 0, 0 };
136 static Encoding unicodefull = { "UnicodeFull", 17*65536, NULL, NULL, &unicodebmp, 1, 1, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, "", 0, 0, 0, NULL, NULL, NULL, NULL, NULL, 0, 0 };
137 static Encoding adobestd = { "AdobeStandard", 256, unicode_from_adobestd, (char**)AdobeStandardEncoding, &unicodefull,
138 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "", 0, 0, 0, NULL, NULL, NULL, NULL, NULL, 0, 0 };
139 static Encoding symbol = { "Symbol", 256, unicode_from_MacSymbol, NULL, &adobestd, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "", 0, 0, 0, NULL, NULL, NULL, NULL, NULL, 0, 0 };
140
141 Encoding *enclist = &symbol;
142
FindUnicharName(void)143 const char *FindUnicharName(void) {
144 /* Iconv and libiconv use different names for UCS2. Just great. Perhaps */
145 /* different versions of each use still different names? */
146 /* Even worse, both accept UCS-2, but under iconv it means native byte */
147 /* ordering and under libiconv it means big-endian */
148 iconv_t test;
149 static const char *goodname = NULL;
150 static const char *names[] = { "UCS-4-INTERNAL", "UCS-4", "UCS4", "ISO-10646-UCS-4", "UTF-32", NULL };
151 static const char *namesle[] = { "UCS-4LE", "UTF-32LE", NULL };
152 static const char *namesbe[] = { "UCS-4BE", "UTF-32BE", NULL };
153 const char **testnames;
154 int i;
155 union {
156 short s;
157 char c[2];
158 } u;
159
160 if ( goodname!=NULL )
161 return( goodname );
162
163 u.c[0] = 0x1; u.c[1] = 0x2;
164 if ( u.s==0x201 ) { /* Little endian */
165 testnames = namesle;
166 } else {
167 testnames = namesbe;
168 }
169 for ( i=0; testnames[i]!=NULL; ++i ) {
170 test = iconv_open(testnames[i],"ISO-8859-1");
171 if ( test!=(iconv_t) -1 && test!=NULL ) {
172 iconv_close(test);
173 goodname = testnames[i];
174 break;
175 }
176 }
177
178 if ( goodname==NULL ) {
179 for ( i=0; names[i]!=NULL; ++i ) {
180 test = iconv_open(names[i],"ISO-8859-1");
181 if ( test!=(iconv_t) -1 && test!=NULL ) {
182 iconv_close(test);
183 goodname = names[i];
184 break;
185 }
186 }
187 }
188
189 if ( goodname==NULL ) {
190 IError( "I can't figure out your version of iconv(). I need a name for the UCS-4 encoding and I can't find one. Reconfigure --without-iconv. Bye.");
191 exit( 1 );
192 }
193
194 test = iconv_open(goodname,"Mac");
195 if ( test==(iconv_t) -1 || test==NULL ) {
196 IError( "Your version of iconv does not support the \"Mac Roman\" encoding.\nIf this causes problems, reconfigure --without-iconv." );
197 } else
198 iconv_close(test);
199
200 /* I really should check for ISO-2022-JP, KR, CN, and all the other encodings */
201 /* I might find in a ttf 'name' table. But those tables take too long to build */
202 return( goodname );
203 }
204
TryEscape(Encoding * enc,const char * escape_sequence)205 static int TryEscape( Encoding *enc, const char *escape_sequence ) {
206 char from[20], ucs[20];
207 size_t fromlen, tolen;
208 ICONV_CONST char *fpt;
209 char *upt;
210 int i, j, low;
211 int esc_len = strlen(escape_sequence);
212
213 strcpy(from,escape_sequence);
214
215 enc->has_2byte = false;
216 low = -1;
217 for ( i=0; i<256; ++i ) if ( i!=escape_sequence[0] ) {
218 for ( j=0; j<256; ++j ) {
219 from[esc_len] = i; from[esc_len+1] = j; from[esc_len+2] = 0;
220 fromlen = esc_len+2;
221 fpt = from;
222 upt = ucs;
223 tolen = sizeof(ucs);
224 if ( iconv( enc->tounicode , &fpt, &fromlen, &upt, &tolen )!= (size_t) (-1) &&
225 upt-ucs==sizeof(unichar_t) /* Exactly one character */ ) {
226 if ( low==-1 ) {
227 enc->low_page = low = i;
228 enc->has_2byte = true;
229 }
230 enc->high_page = i;
231 break;
232 }
233 }
234 }
235 if ( enc->low_page==enc->high_page )
236 enc->has_2byte = false;
237 if ( enc->has_2byte ) {
238 strcpy(enc->iso_2022_escape, escape_sequence);
239 enc->iso_2022_escape_len = esc_len;
240 }
241 return( enc->has_2byte );
242 }
243
_FindOrMakeEncoding(const char * name,int make_it)244 Encoding *_FindOrMakeEncoding(const char *name,int make_it) {
245 Encoding *enc;
246 char buffer[20];
247 const char *iconv_name;
248 Encoding temp;
249 uint8 good[256];
250 int i, j, any, all;
251 char from[8], ucs[20];
252 size_t fromlen, tolen;
253 ICONV_CONST char *fpt;
254 char *upt;
255 /* iconv is not case sensitive */
256
257 if ( strncasecmp(name,"iso8859_",8)==0 || strncasecmp(name,"koi8_",5)==0 ) {
258 /* Fixup for old naming conventions */
259 strncpy(buffer,name,sizeof(buffer));
260 buffer[sizeof(buffer)-1] = '\0';
261 *strchr(buffer,'_') = '-';
262 name = buffer;
263 } else if ( strcasecmp(name,"iso-8859")==0 ) {
264 /* Fixup for old naming conventions */
265 strncpy(buffer,name,3);
266 strncpy(buffer+3,name+4,sizeof(buffer)-3);
267 buffer[sizeof(buffer)-1] = '\0';
268 name = buffer;
269 } else if ( strcasecmp(name,"isolatin10")==0 || strcasecmp(name,"latin10")==0 ) {
270 name = "iso8859-16"; /* try 10 before trying 1 */
271 } else if ( strcasecmp(name,"isolatin1")==0 ) {
272 name = "iso8859-1";
273 } else if ( strcasecmp(name,"isocyrillic")==0 ) {
274 name = "iso8859-5";
275 } else if ( strcasecmp(name,"isoarabic")==0 ) {
276 name = "iso8859-6";
277 } else if ( strcasecmp(name,"isogreek")==0 ) {
278 name = "iso8859-7";
279 } else if ( strcasecmp(name,"isohebrew")==0 ) {
280 name = "iso8859-8";
281 } else if ( strcasecmp(name,"isothai")==0 ) {
282 name = "tis-620"; /* TIS doesn't define non-breaking space in 0xA0 */
283 } else if ( strcasecmp(name,"latin0")==0 || strcasecmp(name,"latin9")==0 ) {
284 name = "iso8859-15"; /* "latin-9" is supported (libiconv bug?) */
285 } else if ( strcasecmp(name,"koi8r")==0 ) {
286 name = "koi8-r";
287 } else if ( strncasecmp(name,"jis201",6)==0 || strncasecmp(name,"jisx0201",8)==0 ) {
288 name = "jis_x0201";
289 } else if ( strcasecmp(name,"AdobeStandardEncoding")==0 || strcasecmp(name,"Adobe")==0 )
290 name = "AdobeStandard";
291 for ( enc=enclist; enc!=NULL; enc=enc->next )
292 if ( strmatch(name,enc->enc_name)==0 ||
293 (enc->iconv_name!=NULL && strmatch(name,enc->iconv_name)==0))
294 return( enc );
295 if ( strmatch(name,"unicode")==0 || strmatch(name,"iso10646")==0 || strmatch(name,"iso10646-1")==0 )
296 return( &unicodebmp );
297 if ( strmatch(name,"unicode4")==0 || strmatch(name,"ucs4")==0 )
298 return( &unicodefull );
299
300 iconv_name = name;
301 /* Mac seems to work ok */
302 if ( strcasecmp(name,"win")==0 || strcasecmp(name,"ansi")==0 )
303 iconv_name = "MS-ANSI"; /* "WINDOWS-1252";*/
304 else if ( strncasecmp(name,"jis208",6)==0 || strncasecmp(name,"jisx0208",8)==0 )
305 iconv_name = "ISO-2022-JP";
306 else if ( strncasecmp(name,"jis212",6)==0 || strncasecmp(name,"jisx0212",8)==0 )
307 iconv_name = "ISO-2022-JP-2";
308 else if ( strncasecmp(name,"ksc5601",7)==0 )
309 iconv_name = "ISO-2022-KR";
310 else if ( strcasecmp(name,"gb2312pk")==0 || strcasecmp(name,"gb2312packed")==0 )
311 iconv_name = "EUC-CN";
312 else if ( strncasecmp(name,"gb2312",6)==0 )
313 iconv_name = "ISO-2022-CN";
314 else if ( strcasecmp(name,"wansung")==0 )
315 iconv_name = "EUC-KR";
316 else if ( strcasecmp(name,"EUC-CN")==0 ) {
317 iconv_name = name;
318 name = "gb2312pk";
319 } else if ( strcasecmp(name,"EUC-KR")==0 ) {
320 iconv_name = name;
321 name = "wansung";
322 }
323
324 /* Escape sequences: */
325 /* ISO-2022-CN: \e $ ) A ^N */
326 /* ISO-2022-KR: \e $ ) C ^N */
327 /* ISO-2022-JP: \e $ B */
328 /* ISO-2022-JP-2: \e $ ( D */
329 /* ISO-2022-JP-3: \e $ ( O */ /* Capital "O", not zero */
330 /* ISO-2022-CN-EXT: \e $ ) E ^N */ /* Not sure about this, also uses CN escape */
331
332 memset(&temp,0,sizeof(temp));
333 temp.builtin = true;
334 temp.tounicode = iconv_open(FindUnicharName(),iconv_name);
335 if ( temp.tounicode==(iconv_t) -1 || temp.tounicode==NULL )
336 return( NULL ); /* Iconv doesn't recognize this name */
337 temp.fromunicode = iconv_open(iconv_name,FindUnicharName());
338 if ( temp.fromunicode==(iconv_t) -1 || temp.fromunicode==NULL ) {
339 /* This should never happen, but if it does... */
340 iconv_close(temp.tounicode);
341 return( NULL );
342 }
343
344 memset(good,0,sizeof(good));
345 any = false; all = true;
346 for ( i=1; i<256; ++i ) {
347 from[0] = i; from[1] = 0;
348 fromlen = 1;
349 fpt = from;
350 upt = ucs;
351 tolen = sizeof(ucs);
352 if ( iconv( temp.tounicode , &fpt, &fromlen, &upt, &tolen )!= (size_t) (-1)) {
353 good[i] = true;
354 any = true;
355 } else
356 all = false;
357 }
358 if ( any )
359 temp.has_1byte = true;
360 if ( all )
361 temp.only_1byte = true;
362
363 if ( !all ) {
364 if ( strstr(iconv_name,"2022")==NULL ) {
365 for ( i=temp.has_1byte; i<256; ++i ) if ( !good[i] ) {
366 for ( j=0; j<256; ++j ) {
367 from[0] = i; from[1] = j; from[2] = 0;
368 fromlen = 2;
369 fpt = from;
370 upt = ucs;
371 tolen = sizeof(ucs);
372 if ( iconv( temp.tounicode , &fpt, &fromlen, &upt, &tolen )!= (size_t) (-1) &&
373 upt-ucs==sizeof(unichar_t) /* Exactly one character */ ) {
374 if ( temp.low_page==-1 )
375 temp.low_page = i;
376 temp.high_page = i;
377 temp.has_2byte = true;
378 break;
379 }
380 }
381 }
382 if ( temp.low_page==temp.high_page ) {
383 temp.has_2byte = false;
384 temp.low_page = temp.high_page = -1;
385 }
386 }
387 if ( !temp.has_2byte && !good[033]/* escape */ ) {
388 if ( strstr(iconv_name,"2022")!=NULL &&
389 strstr(iconv_name,"JP3")!=NULL &&
390 TryEscape( &temp,"\33$(O" )) {
391 ;
392 } else if ( strstr(iconv_name,"2022")!=NULL &&
393 strstr(iconv_name,"JP2")!=NULL &&
394 TryEscape( &temp,"\33$(D" )) {
395 ;
396 } else if ( strstr(iconv_name,"2022")!=NULL &&
397 strstr(iconv_name,"JP")!=NULL &&
398 TryEscape( &temp,"\33$B" )) {
399 ;
400 } else if ( strstr(iconv_name,"2022")!=NULL &&
401 strstr(iconv_name,"KR")!=NULL &&
402 TryEscape( &temp,"\33$)C\16" )) {
403 ;
404 } else if ( strstr(iconv_name,"2022")!=NULL &&
405 strstr(iconv_name,"CN")!=NULL &&
406 TryEscape( &temp,"\33$)A\16" )) {
407 ;
408 }
409 }
410 }
411 if ( !temp.has_1byte && !temp.has_2byte )
412 return( NULL );
413 if ( !make_it )
414 return( NULL );
415
416 enc = chunkalloc(sizeof(Encoding));
417 *enc = temp;
418 enc->enc_name = copy(name);
419 if ( iconv_name!=name )
420 enc->iconv_name = copy(iconv_name);
421 enc->next = enclist;
422 enc->builtin = true;
423 enclist = enc;
424 if ( enc->has_2byte )
425 enc->char_cnt = (enc->high_page<<8) + 256;
426 else {
427 enc->char_cnt = 256;
428 enc->only_1byte = true;
429 }
430 if ( strstrmatch(iconv_name,"JP")!=NULL ||
431 strstrmatch(iconv_name,"sjis")!=NULL ||
432 strstrmatch(iconv_name,"cp932")!=NULL )
433 enc->is_japanese = true;
434 else if ( strstrmatch(iconv_name,"KR")!=NULL )
435 enc->is_korean = true;
436 else if ( strstrmatch(iconv_name,"CN")!=NULL )
437 enc->is_simplechinese = true;
438 else if ( strstrmatch(iconv_name,"BIG")!=NULL && strstrmatch(iconv_name,"5")!=NULL )
439 enc->is_tradchinese = true;
440
441 if ( strstrmatch(name,"ISO8859")!=NULL &&
442 strtol(name+strlen(name)-2,NULL,10)>=16 )
443 /* Not in our menu, don't hide */;
444 else if ( iconv_name!=name || strmatch(name,"mac")==0 || strstrmatch(name,"ISO8859")!=NULL ||
445 strmatch(name,"koi8-r")==0 || strmatch(name,"sjis")==0 ||
446 strmatch(name,"big5")==0 || strmatch(name,"big5hkscs")==0 )
447 enc->hidden = true;
448
449 return( enc );
450 }
451
FindOrMakeEncoding(const char * name)452 Encoding *FindOrMakeEncoding(const char *name) {
453 return( _FindOrMakeEncoding(name,true));
454 }
455
456 /* Plugin API */
AddEncoding(char * name,EncFunc enc_to_uni,EncFunc uni_to_enc,int max)457 int AddEncoding(char *name,EncFunc enc_to_uni,EncFunc uni_to_enc,int max) {
458 Encoding *enc;
459 int i;
460
461 for ( enc=enclist; enc!=NULL; enc=enc->next ) {
462 if ( strmatch(name,enc->enc_name)==0 ||
463 (enc->iconv_name!=NULL && strmatch(name,enc->iconv_name)==0)) {
464 if ( enc->tounicode_func==NULL )
465 return( 0 ); /* Failure */
466 else {
467 enc->tounicode_func = enc_to_uni;
468 enc->fromunicode_func = uni_to_enc;
469 enc->char_cnt = max;
470 return( 2 );
471 }
472 }
473 }
474
475 if ( strmatch(name,"unicode")==0 || strmatch(name,"iso10646")==0 || strmatch(name,"iso10646-1")==0 )
476 return( 0 ); /* Failure */
477 if ( strmatch(name,"unicode4")==0 || strmatch(name,"ucs4")==0 )
478 return( 0 ); /* Failure */
479
480 enc = chunkalloc(sizeof(Encoding));
481 enc->enc_name = copy(name);
482 enc->next = enclist;
483 enclist = enc;
484 enc->tounicode_func = enc_to_uni;
485 enc->fromunicode_func = uni_to_enc;
486 enc->char_cnt = max;
487 for ( i=0; i<256 && i<max; ++i )
488 if ( enc_to_uni(i)!=-1 )
489 break;
490
491 if ( i<256 && i<max )
492 enc->has_1byte = true;
493 if ( max<256 )
494 enc->only_1byte = true;
495 else
496 enc->has_2byte = true;
497 return( 1 );
498 }
499
getPfaEditEncodings(void)500 static char *getPfaEditEncodings(void) {
501 static char *encfile=NULL;
502 char buffer[1025];
503 char *ffdir;
504
505 if ( encfile!=NULL )
506 return encfile;
507 ffdir = getFontForgeUserDir(Config);
508 if ( ffdir==NULL )
509 return NULL;
510 sprintf(buffer,"%s/Encodings.ps", ffdir);
511 free(ffdir);
512 encfile = copy(buffer);
513 return encfile;
514 }
515
EncodingFree(Encoding * item)516 void EncodingFree(Encoding *item) {
517 int i;
518
519 if ( item==NULL )
520 return;
521
522 free(item->enc_name);
523 if ( item->psnames!=NULL ) {
524 for ( i=0; i<item->char_cnt; ++i )
525 free(item->psnames[i]);
526 free(item->psnames);
527 }
528 free(item->unicode);
529 free(item);
530 }
531
DeleteEncoding(Encoding * me)532 void DeleteEncoding(Encoding *me) {
533 FontViewBase *fv;
534 Encoding *prev;
535
536 if ( me->builtin )
537 return;
538
539 for ( fv = FontViewFirst(); fv!=NULL; fv = fv->next ) {
540 if ( fv->map->enc==me )
541 fv->map->enc = &custom;
542 }
543 if ( me==enclist )
544 enclist = me->next;
545 else {
546 for ( prev = enclist; prev!=NULL && prev->next!=me; prev=prev->next );
547 if ( prev!=NULL ) prev->next = me->next;
548 }
549 EncodingFree(me);
550 if ( default_encoding == me )
551 default_encoding = FindOrMakeEncoding("ISO8859-1");
552 if ( default_encoding == NULL )
553 default_encoding = &custom;
554 DumpPfaEditEncodings();
555 }
556
557 /* Parse a TXT file from the unicode consortium */
558 /* Unicode Consortium Format A */
559 /* List of lines with several fields, */
560 /* first is the encoding value (in hex), second the Unicode value (in hex) */
561 /* # is a comment character (to eol) */
ParseConsortiumEncodingFile(FILE * file)562 static Encoding *ParseConsortiumEncodingFile(FILE *file) {
563 char buffer[200];
564 int32 encs[0x10000];
565 int enc, unienc, max;
566 Encoding *item;
567
568 memset(encs, 0, sizeof(encs));
569 max = -1;
570
571 while ( fgets(buffer,sizeof(buffer),file)!=NULL ) {
572 if ( ishexdigit(buffer[0]) ) {
573 if ( sscanf(buffer, "%x %x", (unsigned *) &enc, (unsigned *) &unienc)==2 &&
574 enc<0x10000 && enc>=0 ) {
575 encs[enc] = unienc;
576 if ( enc>max ) max = enc;
577 }
578 }
579 }
580
581 if ( max==-1 )
582 return( NULL );
583
584 ++max;
585 if ( max<256 ) max = 256;
586 item = calloc(1,sizeof(Encoding));
587 item->only_1byte = item->has_1byte = true;
588 item->char_cnt = max;
589 item->unicode = malloc(max*sizeof(int32));
590 memcpy(item->unicode,encs,max*sizeof(int32));
591 return( item );
592 }
593
594 /**
595 * \brief Parses a GlyphOrderAndAliasDB encoding file
596 *
597 * \param [in] file The file handle to the encoding file
598 * \return The encoding, or NULL if none could be made
599 *
600 * \details Each line in the file contains one glyph name (equating to one slot).
601 * It is assumed that values are tab separated. There
602 * are at least two columns, with a third column being optional.
603 * The first column is the glyph name to be used on output. This
604 * is what will normally be used to determine the unicode value for
605 * this slot.
606 * The second column is the 'friendly' name - this is what will
607 * be used for the slot's name.
608 * The third, optional column specifies the unicode value that the
609 * slot should map to. When available, this will be used in preference
610 * to the first column.
611 */
ParseGlyphOrderAndAliasDB(FILE * file)612 static Encoding *ParseGlyphOrderAndAliasDB(FILE *file) {
613 GArray *enc_arr = g_array_sized_new(FALSE, TRUE, sizeof(int32), 256);
614 GArray *names_arr = g_array_sized_new(FALSE, TRUE, sizeof(char *), 256);
615 Encoding *item = NULL;
616 char buffer[BUFSIZ];
617 int enc, any = FALSE, has_1byte = FALSE;
618
619 while (fgets(buffer, sizeof(buffer), file)) {
620 char *split = strchr(buffer, '\t'), *split2, *enc_name = NULL;
621 if (split == NULL) {
622 // Skip entries that do not contain at least two (tab separated) values
623 LogError(_("ParseGlyphOrderAndAliasDB: Invalid (non-tab separated entry) at index %d: %s\n"), enc_arr->len, g_strstrip(buffer));
624 //enc = -1;
625 //g_array_append_val(enc_arr, enc);
626 //g_array_append_val(names_arr, enc_name);
627 continue;
628 }
629 *split++ = '\0';
630 // Buffer now contains the first column
631 g_strstrip(buffer);
632 // split contains the second, and possibly the third column
633 g_strstrip(split);
634
635 // Optional third column
636 split2 = strchr(split, '\t');
637 if (split2 != NULL) {
638 *split2++ = '\0';
639 g_strstrip(split2);
640 }
641
642 // Use the third column in preference to the first
643 enc = UniFromName((split2 != NULL) ? split2 : buffer, ui_none, &custom);
644 if (split[0] != '\0') {
645 /* Used not to do this, but there are several legal names */
646 /* for some slots and people get unhappy (rightly) if we */
647 /* use the wrong one */
648 enc_name = copy(split);
649 any = TRUE;
650 }
651
652 if (enc != -1 && enc_arr->len < 256) {
653 // We have a valid encoding within the first 256 entries
654 has_1byte = TRUE;
655 }
656
657 // Append entry to our arrays
658 g_array_append_val(enc_arr, enc);
659 g_array_append_val(names_arr, enc_name);
660 }
661
662 if (enc_arr->len > 0) {
663 // If we have mappings, we make an encoding.
664 char *tmp_name = ff_ask_string(_("Encoding name"), "GlyphOrderAndAliasDB", _("Please name this encoding"));
665 if (tmp_name != NULL) {
666 if (tmp_name[0] == '\0') {
667 // Encodings must be named.
668 free(tmp_name);
669 tmp_name = NULL;
670 } else {
671 item = calloc(1, sizeof(Encoding));
672 item->enc_name = tmp_name;
673 // We pad the map in accordance with existing code in FindOrMakeEncoding and elsewhere.
674 // Nobody knows why.
675 item->char_cnt = (enc_arr->len < 256) ? 256 : enc_arr->len;
676 item->unicode = malloc(item->char_cnt * sizeof(int32));
677 memcpy(item->unicode, enc_arr->data, enc_arr->len * sizeof(int32));
678 if (item->char_cnt > enc_arr->len) {
679 // Pad the unfilled entries with -1
680 memset(item->unicode + enc_arr->len, -1, sizeof(int32) * (enc_arr->len - item->char_cnt));
681 }
682 if (any) {
683 item->psnames = calloc(item->char_cnt, sizeof(char *));
684 memcpy(item->psnames, names_arr->data, names_arr->len * sizeof(char *));
685 }
686
687 item->is_custom = TRUE;
688 item->has_1byte = has_1byte;
689 if (enc_arr->len < 256) {
690 item->only_1byte = TRUE;
691 } else {
692 item->has_2byte = TRUE;
693 }
694 }
695 }
696 }
697
698 g_array_free(enc_arr, TRUE);
699 g_array_free(names_arr, TRUE);
700 return item;
701 }
702
RemoveMultiples(Encoding * item)703 void RemoveMultiples(Encoding *item) {
704 Encoding *test;
705
706 for ( test=enclist; test!=NULL; test = test->next ) {
707 if ( strcmp(test->enc_name,item->enc_name)==0 )
708 break;
709 }
710 if ( test!=NULL )
711 DeleteEncoding(test);
712 }
713
ParseEncodingFile(char * filename,char * encodingname)714 char *ParseEncodingFile(char *filename, char *encodingname) {
715 FILE *file;
716 char *orig = filename;
717 Encoding *head, *item, *prev, *next;
718 char *buf, *name;
719 int i,ch;
720
721 if ( filename==NULL ) filename = getPfaEditEncodings();
722 file = fopen(filename,"r");
723 if ( file==NULL ) {
724 if ( orig!=NULL )
725 ff_post_error(_("Couldn't open file"), _("Couldn't open file %.200s"), orig);
726 return( NULL );
727 }
728 ch = getc(file);
729 if ( ch==EOF ) {
730 fclose(file);
731 return( NULL );
732 }
733
734 /* Here we detect file format and decide which format
735 parsing routine to actually use.
736 */
737 ungetc(ch, file);
738
739
740 if(strlen(filename) >= 20
741 && !strcmp(filename + strlen(filename) - 20, "GlyphOrderAndAliasDB")){
742 head = ParseGlyphOrderAndAliasDB(file);
743 } else if (ch=='#' || ch=='0') {
744 head = ParseConsortiumEncodingFile(file);
745 if(encodingname)
746 head->enc_name = copy(encodingname);
747 } else {
748 head = PSSlurpEncodings(file);
749 }
750 fclose(file);
751 if ( head==NULL ) {
752 ff_post_error(_("Bad encoding file format"),_("Bad encoding file format") );
753 return( NULL );
754 }
755
756 for ( i=0, prev=NULL, item=head; item!=NULL; prev = item, item=next, ++i ) {
757 next = item->next;
758 if ( item->enc_name==NULL ) {
759 if ( no_windowing_ui ) {
760 ff_post_error(_("Bad encoding file format"),_("This file contains an unnamed encoding, which cannot be named in a script"));
761 EncodingFree(head);
762 return( NULL );
763 }
764 if ( item==head && item->next==NULL )
765 buf = strdup(_( "Please name this encoding" ));
766 else
767 buf = smprintf(_( "Please name encoding %d in this file" ), i );
768
769 name = ff_ask_string( buf, NULL, buf );
770
771 if ( name!=NULL ) {
772 item->enc_name = copy(name);
773 free(name);
774 } else {
775 if ( prev==NULL )
776 head = item->next;
777 else
778 prev->next = item->next;
779 EncodingFree(item);
780 }
781 }
782 }
783 for ( item=head; item!=NULL; item=item->next )
784 RemoveMultiples(item);
785
786 if ( enclist == NULL )
787 enclist = head;
788 else {
789 for ( item=enclist; item->next!=NULL; item=item->next );
790 item->next = head;
791 }
792 return( copy( head->enc_name ) );
793 }
794
LoadPfaEditEncodings(void)795 void LoadPfaEditEncodings(void) {
796 free(ParseEncodingFile(NULL, NULL));
797 }
798
DumpPfaEditEncodings(void)799 void DumpPfaEditEncodings(void) {
800 FILE *file;
801 Encoding *item;
802 int i;
803 char buffer[80];
804
805 for ( item=enclist; item!=NULL && item->builtin; item=item->next );
806 if ( item==NULL ) {
807 unlink(getPfaEditEncodings());
808 return;
809 }
810
811 file = fopen( getPfaEditEncodings(), "w");
812 if ( file==NULL ) {
813 LogError( _("couldn't write encodings file\n") );
814 return;
815 }
816
817 for ( item=enclist; item!=NULL; item = item->next ) if ( !item->builtin && item->tounicode_func==NULL ) {
818 fprintf( file, "/%s [\n", item->enc_name );
819 if ( item->psnames==NULL )
820 fprintf( file, "%% Use codepoints.\n" );
821 for ( i=0; i<item->char_cnt; ++i ) {
822 if ( item->psnames!=NULL && item->psnames[i]!=NULL )
823 fprintf( file, " /%s", item->psnames[i]);
824 else if ( item->unicode[i]<' ' || (item->unicode[i]>=0x7f && item->unicode[i]<0xa0))
825 fprintf( file, " /.notdef" );
826 else
827 fprintf( file, " /%s", StdGlyphName(buffer,item->unicode[i],ui_none,(NameList *) -1));
828 if ( (i&0xf)==0 )
829 fprintf( file, "\t\t%% 0x%02x\n", i );
830 else
831 putc('\n',file);
832 }
833 fprintf( file, "] def\n\n" );
834 }
835 fclose(file);
836 }
837
838 /* ************************************************************************** */
839 /* ****************************** CID Encodings ***************************** */
840 /* ************************************************************************** */
841 struct cidmap *cidmaps = NULL;
842
CIDFromName(char * name,SplineFont * cidmaster)843 int CIDFromName(char *name,SplineFont *cidmaster) {
844 /* We've had various conventions for encoding a cid inside a name */
845 /* I'm primarily interested in this when the name is something like */
846 /* Japan1.504.vert */
847 /* which tells me that the current glyph is the rotated version of */
848 /* cid 504 */
849 /* Other convention "cid-504.vert" */
850 int len = strlen( cidmaster->ordering );
851 int cid;
852 char *end;
853
854 if ( strncmp(name,cidmaster->ordering,len)==0 ) {
855 if ( name[len]=='.' ) ++len;
856 } else if ( strncmp(name,"cid-",4)==0 ) {
857 len = 4;
858 } else
859 len = 0;
860 cid = strtol(name+len,&end,10);
861 if ( end==name+len )
862 return( -1 );
863 if ( *end!='.' && *end!='\0' )
864 return( -1 );
865
866 return ( cid );
867 }
868
CID2Uni(struct cidmap * map,int cid)869 int CID2Uni(struct cidmap *map,int cid) {
870 unsigned int uni;
871
872 if ( map==NULL )
873 return( -1 );
874 else if ( cid==0 )
875 return( 0 );
876 else if ( cid<map->namemax && map->unicode[cid]!=0 )
877 return( map->unicode[cid] );
878 else if ( cid<map->namemax && map->name[cid]!=NULL ) {
879 if ( sscanf(map->name[cid],"uni%x", &uni )==1 )
880 return( uni );
881 }
882
883 return( -1 );
884 }
885
CID2NameUni(struct cidmap * map,int cid,char * buffer,int len)886 int CID2NameUni(struct cidmap *map,int cid, char *buffer, int len) {
887 int enc = -1;
888 const char *temp;
889
890 if ( map==NULL )
891 snprintf(buffer,len,"cid-%d", cid);
892 else if ( cid<map->namemax && map->name[cid]!=NULL ) {
893 strncpy(buffer,map->name[cid],len);
894 buffer[len-1] = '\0';
895 } else if ( cid==0 )
896 strcpy(buffer,".notdef");
897 else if ( cid<map->namemax && map->unicode[cid]!=0 ) {
898 if ( map->unicode==NULL || map->namemax==0 )
899 enc = 0;
900 else
901 enc = map->unicode[cid];
902 temp = StdGlyphName(buffer,enc,ui_none,(NameList *) -1);
903 if ( temp!=buffer )
904 strcpy(buffer,temp);
905 } else
906 snprintf(buffer,len,"%s.%d", map->ordering, cid);
907 return( enc );
908 }
909
NameUni2CID(struct cidmap * map,int uni,const char * name)910 int NameUni2CID(struct cidmap *map, int uni, const char *name) {
911 int i;
912 struct cidaltuni *alts;
913
914 if ( map==NULL )
915 return( -1 );
916 if ( uni!=-1 ) {
917 // Search for a matching code.
918 for ( i=0; i<map->namemax; ++i )
919 if ( map->unicode[i]==(uint32)uni )
920 return( i );
921 for ( alts=map->alts; alts!=NULL; alts=alts->next )
922 if ( alts->uni==uni )
923 return( alts->cid );
924 } else {
925 // Search for a matching name.
926 if ( name!=NULL )
927 for ( i=0; i<map->namemax; ++i )
928 if ( map->name[i]!=NULL && strcmp(map->name[i],name)==0 )
929 return( i );
930 }
931 return( -1 );
932 }
933
CIDSetAltUnis(struct cidmap * map,int cid)934 struct altuni *CIDSetAltUnis(struct cidmap *map,int cid) {
935 /* Some CIDs are mapped to several unicode code points, damn it */
936 struct altuni *sofar = NULL, *alt;
937 struct cidaltuni *alts;
938
939 for ( alts=map->alts; alts!=NULL; alts=alts->next ) {
940 if ( alts->cid==cid ) {
941 alt = chunkalloc(sizeof(struct altuni));
942 alt->next = sofar;
943 sofar = alt;
944 alt->unienc = alts->uni;
945 alt->vs = -1;
946 }
947 }
948 return( sofar );
949 }
950
MaxCID(struct cidmap * map)951 int MaxCID(struct cidmap *map) {
952 return( map->cidmax );
953 }
954
SearchDirForCidMap(const char * dir,char * registry,char * ordering,int supplement,char ** maybefile)955 static char *SearchDirForCidMap(const char *dir,char *registry,char *ordering,
956 int supplement,char **maybefile) {
957 char maybe[FILENAME_MAX+1];
958 struct dirent *ent;
959 DIR *d;
960 int len, rlen = strlen(registry), olen=strlen(ordering);
961 char *pt, *end, *ret;
962 int test, best = -1;
963
964 if ( dir==NULL )
965 return( NULL );
966
967 if ( *maybefile!=NULL ) {
968 char *pt = strrchr(*maybefile,'.');
969 while ( pt>*maybefile && isdigit(pt[-1]))
970 --pt;
971 best = strtol(pt,NULL,10);
972 }
973
974 d = opendir(dir);
975 if ( d==NULL )
976 return( NULL );
977 while ( (ent = readdir(d))!=NULL ) {
978 if ( (len = strlen(ent->d_name))<8 )
979 continue;
980 if ( strcmp(ent->d_name+len-7,".cidmap")!=0 )
981 continue;
982 if ( strncmp(ent->d_name,registry,rlen)!=0 || ent->d_name[rlen]!='-' )
983 continue;
984 pt = ent->d_name+rlen+1;
985 if ( strncmp(pt,ordering,olen)!=0 || pt[olen]!='-' )
986 continue;
987 pt += olen+1;
988 if ( !isdigit(*pt))
989 continue;
990 test = strtol(pt,&end,10);
991 if ( *end!='.' )
992 continue;
993 if ( test>=supplement ) {
994 ret = malloc(strlen(dir)+1+len+1);
995 strcpy(ret,dir);
996 strcat(ret,"/");
997 strcat(ret,ent->d_name);
998 closedir(d);
999 return( ret );
1000 } else if ( test>best ) {
1001 best = test;
1002 strcpy(maybe,ent->d_name);
1003 }
1004 }
1005 closedir(d);
1006 if ( best>-1 ) {
1007 ret = malloc(strlen(dir)+1+strlen(maybe)+1);
1008 strcpy(ret,dir);
1009 strcat(ret,"/");
1010 strcat(ret,maybe);
1011 *maybefile = ret;
1012 }
1013 return( NULL );
1014 }
1015
MakeDummyMap(char * registry,char * ordering,int supplement)1016 static struct cidmap *MakeDummyMap(char *registry,char *ordering,int supplement) {
1017 struct cidmap *ret = malloc(sizeof(struct cidmap));
1018
1019 ret->registry = copy(registry);
1020 ret->ordering = copy(ordering);
1021 ret->supplement = ret->maxsupple = supplement;
1022 ret->cidmax = ret->namemax = 0;
1023 ret->unicode = NULL; ret->name = NULL;
1024 ret->alts = NULL;
1025 ret->next = cidmaps;
1026 cidmaps = ret;
1027 return( ret );
1028 }
1029
LoadMapFromFile(char * file,char * registry,char * ordering,int supplement)1030 struct cidmap *LoadMapFromFile(char *file,char *registry,char *ordering,
1031 int supplement) {
1032 struct cidmap *ret = malloc(sizeof(struct cidmap));
1033 char *pt = strrchr(file,'.');
1034 FILE *f;
1035 int cid1, cid2, uni, cnt, i, ch;
1036 char name[100];
1037
1038 while ( pt>file && isdigit(pt[-1]))
1039 --pt;
1040 ret->supplement = ret->maxsupple = strtol(pt,NULL,10);
1041 if ( supplement>ret->maxsupple )
1042 ret->maxsupple = supplement;
1043 ret->registry = copy(registry);
1044 ret->ordering = copy(ordering);
1045 ret->alts = NULL;
1046 ret->cidmax = ret->namemax = 0;
1047 ret->unicode = NULL; ret->name = NULL;
1048 ret->next = cidmaps;
1049 cidmaps = ret;
1050
1051 f = fopen( file,"r" );
1052 if ( f==NULL ) {
1053 ff_post_error(_("Missing cidmap file"),_("Couldn't open cidmap file: %s"), file );
1054 } else if ( fscanf( f, "%d %d", &ret->cidmax, &ret->namemax )!=2 ) {
1055 ff_post_error(_("Bad cidmap file"),_("%s is not a cidmap file, please download\nhttp://fontforge.sourceforge.net/cidmaps.tgz"), file );
1056 fprintf( stderr, _("%s is not a cidmap file, please download\nhttp://fontforge.sourceforge.net/cidmaps.tgz"), file );
1057 fclose(f);
1058 } else {
1059 ret->unicode = calloc(ret->namemax+1,sizeof(uint32));
1060 ret->name = calloc(ret->namemax+1,sizeof(char *));
1061 while ( 1 ) {
1062 cnt=fscanf( f, "%d..%d %x", &cid1, &cid2, (unsigned *) &uni );
1063 if ( cnt<=0 )
1064 break;
1065 if ( cid1>ret->namemax )
1066 continue;
1067 if ( cnt==3 ) {
1068 if ( cid2>ret->namemax ) cid2 = ret->namemax;
1069 for ( i=cid1; i<=cid2; ++i )
1070 ret->unicode[i] = uni++;
1071 } else if ( cnt==1 ) {
1072 if ( fscanf(f,"%x", (unsigned *) &uni )==1 ) {
1073 ret->unicode[cid1] = uni;
1074 ch = getc(f);
1075 while ( ch==',' ) {
1076 if ( fscanf(f,"%x", (unsigned *) &uni )==1 ) {
1077 struct cidaltuni *alt = chunkalloc(sizeof(struct cidaltuni));
1078 alt->next = ret->alts;
1079 ret->alts = alt;
1080 alt->uni = uni;
1081 alt->cid = cid1;
1082 }
1083 ch = getc(f);
1084 }
1085 ungetc(ch,f);
1086 } else if ( fscanf(f," /%s", name )==1 )
1087 ret->name[cid1] = copy(name);
1088 }
1089 }
1090 fclose(f);
1091 }
1092 return( ret );
1093 }
1094
FindCidMap(char * registry,char * ordering,int supplement,SplineFont * sf)1095 struct cidmap *FindCidMap(char *registry,char *ordering,int supplement,SplineFont *sf) {
1096 struct cidmap *map, *maybe=NULL;
1097 char *file;
1098 char *maybefile=NULL;
1099 int maybe_sup = -1;
1100 const char *buts[3], *buts2[3], *buts3[3];
1101 char *buf = NULL;
1102 int ret;
1103
1104 if ( sf!=NULL && sf->cidmaster ) sf = sf->cidmaster;
1105 if ( sf!=NULL && sf->loading_cid_map )
1106 return( NULL );
1107
1108 for ( map = cidmaps; map!=NULL; map = map->next ) {
1109 if ( strcmp(map->registry,registry)==0 && strcmp(map->ordering,ordering)==0 ) {
1110 if ( supplement<=map->supplement )
1111 return( map );
1112 else if ( maybe==NULL || maybe->supplement<map->supplement )
1113 maybe = map;
1114 }
1115 }
1116 if ( maybe!=NULL && supplement<=maybe->maxsupple )
1117 return( maybe ); /* User has said it's ok to use maybe at this supplement level */
1118
1119 file = SearchDirForCidMap(".",registry,ordering,supplement,&maybefile);
1120 if ( file==NULL )
1121 file = SearchDirForCidMap(getFontForgeShareDir(),registry,ordering,supplement,&maybefile);
1122
1123 if ( file==NULL && (maybe!=NULL || maybefile!=NULL)) {
1124 if ( maybefile!=NULL ) {
1125 char *pt = strrchr(maybefile,'.');
1126 while ( pt>maybefile && isdigit(pt[-1]))
1127 --pt;
1128 maybe_sup = strtol(pt,NULL,10);
1129 if ( maybe!=NULL && maybe->supplement >= maybe_sup ) {
1130 free(maybefile); maybefile = NULL;
1131 maybe_sup = maybe->supplement;
1132 } else
1133 maybe = NULL;
1134 }
1135 if ( maybe!=NULL )
1136 maybe_sup = maybe->supplement;
1137 if ( sf!=NULL ) sf->loading_cid_map = true;
1138 buts[0] = _("_Use It"); buts[1] = _("_Search"); buts[2] = NULL;
1139 ret = ff_ask(_("Use CID Map"),(const char **) buts,0,1,_("This font is based on the charset %1$.20s-%2$.20s-%3$d, but the best I've been able to find is %1$.20s-%2$.20s-%4$d.\nShall I use that or let you search?"),
1140 registry,ordering,supplement,maybe_sup);
1141 if ( sf!=NULL ) sf->loading_cid_map = false;
1142 if ( ret==0 ) {
1143 if ( maybe!=NULL ) {
1144 maybe->maxsupple = supplement;
1145 return( maybe );
1146 } else {
1147 file = maybefile;
1148 maybefile = NULL;
1149 }
1150 }
1151 }
1152
1153 if ( file==NULL ) {
1154 char *uret;
1155 buf = smprintf( "%s-%s-*.cidmap", registry, ordering );
1156 if ( maybe==NULL && maybefile==NULL ) {
1157 buts3[0] = _("_Browse"); buts3[1] = _("_Give Up"); buts3[2] = NULL;
1158 ret = ff_ask(_("No cidmap file..."),(const char **)buts3,0,1,_("FontForge was unable to find a cidmap file for this font. It is not essential to have one, but some things will work better if you do. If you have not done so you might want to download the cidmaps from:\n http://FontForge.sourceforge.net/cidmaps.tgz\nand then gunzip and untar them and move them to:\n %.80s\n\nWould you like to search your local disk for an appropriate file?"),
1159 getFontForgeShareDir()==NULL?"/usr/share/fontforge":getFontForgeShareDir()
1160 );
1161 if ( ret==1 || no_windowing_ui )
1162 buf = NULL;
1163 }
1164 uret = NULL;
1165 if ( ( buf != NULL ) && !no_windowing_ui ) {
1166 if ( sf!=NULL ) sf->loading_cid_map = true;
1167 uret = ff_open_filename(_("Find a cidmap file..."), NULL, (char *) buf );
1168 if ( sf!=NULL ) sf->loading_cid_map = false;
1169 }
1170 if ( uret==NULL ) {
1171 buts2[0] = "_Use It"; buts2[1] = "_Search"; buts2[2] = NULL;
1172 if ( maybe==NULL && maybefile==NULL )
1173 /* No luck */;
1174 else if ( no_windowing_ui && maybe!=NULL ) {
1175 maybe->maxsupple = supplement;
1176 return( maybe );
1177 } else if ( no_windowing_ui ) {
1178 file = maybefile;
1179 maybefile = NULL;
1180 } else if ( ff_ask(_("Use CID Map"),(const char **)buts2,0,1,_("Are you sure you don't want to use the cidmap I found?"))==0 ) {
1181 if ( maybe!=NULL ) {
1182 maybe->maxsupple = supplement;
1183 return( maybe );
1184 } else {
1185 file = maybefile;
1186 maybefile = NULL;
1187 }
1188 }
1189 } else {
1190 file = utf82def_copy(uret);
1191 free(uret);
1192 }
1193 }
1194
1195 free(maybefile);
1196 if ( file!=NULL ) {
1197 map = LoadMapFromFile(file,registry,ordering,supplement);
1198 free(file);
1199 return( map );
1200 }
1201
1202 return( MakeDummyMap(registry,ordering,supplement));
1203 }
1204
SFApplyOrdering(SplineFont * sf,int glyphcnt)1205 static void SFApplyOrdering(SplineFont *sf, int glyphcnt) {
1206 SplineChar **glyphs, *sc;
1207 int i;
1208 RefChar *refs, *rnext, *rprev;
1209 SplineSet *new, *spl;
1210
1211 /* Remove references to characters which aren't in the new map (if any) */
1212 /* Don't need to fix up dependencies, because we throw the char away */
1213 for ( i=0; i<sf->glyphcnt; ++i ) if ( (sc = sf->glyphs[i])!=NULL ) {
1214 for ( rprev = NULL, refs=sc->layers[ly_fore].refs; refs!=NULL; refs=rnext ) {
1215 rnext = refs->next;
1216 if ( refs->sc->orig_pos==-1 ) {
1217 new = refs->layers[0].splines;
1218 if ( new!=NULL ) {
1219 for ( spl = new; spl->next!=NULL; spl = spl->next );
1220 spl->next = sc->layers[ly_fore].splines;
1221 sc->layers[ly_fore].splines = new;
1222 }
1223 refs->layers[0].splines=NULL;
1224 RefCharFree(refs);
1225 if ( rprev==NULL )
1226 sc->layers[ly_fore].refs = rnext;
1227 else
1228 rprev->next = rnext;
1229 } else
1230 rprev = refs;
1231 }
1232 }
1233
1234 glyphs = calloc(glyphcnt+1,sizeof(SplineChar *));
1235 for ( i=0; i<sf->glyphcnt; ++i ) if ( (sc = sf->glyphs[i])!=NULL ) {
1236 if ( sc->orig_pos==-1 )
1237 SplineCharFree(sc);
1238 else
1239 glyphs[sc->orig_pos] = sc;
1240 }
1241
1242 free(sf->glyphs);
1243 sf->glyphcnt = sf->glyphmax = glyphcnt;
1244 sf->glyphs = glyphs;
1245 }
1246
1247 /* Convert a normal font to a cid font, rearranging glyphs into cid order */
SFEncodeToMap(SplineFont * sf,struct cidmap * map)1248 void SFEncodeToMap(SplineFont *sf,struct cidmap *map) {
1249 SplineChar *sc;
1250 int i,max=0, anyextras=0;
1251
1252 for ( i=0; i<sf->glyphcnt; ++i ) if ( SCWorthOutputting(sc = sf->glyphs[i]) ) {
1253 sc->orig_pos = NameUni2CID(map,sc->unicodeenc,sc->name);
1254 if ( sc->orig_pos>max ) max = sc->orig_pos;
1255 else if ( sc->orig_pos==-1 ) ++anyextras;
1256 } else if ( sc!=NULL )
1257 sc->orig_pos = -1;
1258
1259 if ( anyextras ) {
1260 char *buttons[3];
1261 buttons[0] = _("_Delete"); buttons[1] = _("_Add"); buttons[2] = NULL;
1262 if ( ff_ask(_("Extraneous glyphs"),(const char **) buttons,0,1,_("The current encoding contains glyphs which I cannot map to CIDs.\nShould I delete them or add them to the end (where they may conflict with future ros definitions)?"))==1 ) {
1263 if ( map!=NULL && max<map->cidmax ) max = map->cidmax;
1264 anyextras = 0;
1265 for ( i=0; i<sf->glyphcnt; ++i ) if ( SCWorthOutputting(sc = sf->glyphs[i]) ) {
1266 if ( sc->orig_pos == -1 ) sc->orig_pos = max + anyextras++;
1267 }
1268 max += anyextras;
1269 }
1270 }
1271 SFApplyOrdering(sf, max+1);
1272 }
1273
1274 enum cmaptype { cmt_out=-1, cmt_coderange, cmt_notdefs, cmt_cid, cmt_max };
1275 struct coderange { uint32 first, last, cid; };
1276 struct cmap {
1277 struct {
1278 int n;
1279 struct coderange *ranges;
1280 } groups[cmt_max];
1281 char *registry;
1282 char *ordering;
1283 int supplement;
1284 struct remap *remap;
1285 int total;
1286 };
1287
cmapfree(struct cmap * cmap)1288 static void cmapfree(struct cmap *cmap) {
1289 free(cmap->registry);
1290 free(cmap->ordering);
1291 free(cmap->groups[cmt_coderange].ranges);
1292 free(cmap->groups[cmt_notdefs].ranges);
1293 free(cmap->groups[cmt_cid].ranges);
1294 free(cmap->remap);
1295 free(cmap);
1296 }
1297
ExtendArray(struct coderange * ranges,int * n,int val)1298 static struct coderange *ExtendArray(struct coderange *ranges,int *n, int val) {
1299 if ( *n == 0 )
1300 ranges = calloc(val,sizeof(struct coderange));
1301 else {
1302 ranges = realloc(ranges,(*n+val)*sizeof(struct coderange));
1303 memset(ranges+*n,0,val*sizeof(struct coderange));
1304 }
1305 *n += val;
1306 return( ranges );
1307 }
1308
readpsstr(char * str)1309 static char *readpsstr(char *str) {
1310 char *eos;
1311
1312 while ( isspace(*str)) ++str;
1313 if ( *str=='(' ) ++str;
1314 /* PostScript strings can be more complicated than this (hex, nested parens, Enc85...) */
1315 /* but none of those should show up here */
1316 for ( eos = str; *eos!=')' && *eos!='\0'; ++eos );
1317 return( copyn(str,eos-str));
1318 }
1319
ParseCMap(char * filename)1320 static struct cmap *ParseCMap(char *filename) {
1321 char buf2[200];
1322 FILE *file;
1323 struct cmap *cmap;
1324 char *end, *pt;
1325 int val, pos;
1326 enum cmaptype in;
1327 int in_is_single; // We set this if we are to parse cidchars into cidranges.
1328 static const char *bcsr = "begincodespacerange", *bndr = "beginnotdefrange", *bcr = "begincidrange", *bcc = "begincidchar";
1329 static const char *reg = "/Registry", *ord = "/Ordering", *sup="/Supplement";
1330
1331 file = fopen(filename,"r");
1332 if ( file==NULL )
1333 return( NULL );
1334
1335 cmap = calloc(1,sizeof(struct cmap));
1336 in = cmt_out;
1337 while ( fgets(buf2,sizeof(buf2),file)!=NULL ) {
1338 for ( pt=buf2; isspace(*pt); ++pt);
1339 if ( in==cmt_out ) {
1340 if ( *pt=='/' ) {
1341 if ( strncmp(pt,reg,strlen(reg))==0 )
1342 cmap->registry = readpsstr(pt+strlen(reg));
1343 else if ( strncmp(pt,ord,strlen(ord))==0 )
1344 cmap->ordering = readpsstr(pt+strlen(ord));
1345 else if ( strncmp(pt,sup,strlen(sup))==0 ) {
1346 for ( pt += strlen(sup); isspace(*pt); ++pt );
1347 cmap->supplement = strtol(pt,NULL,10);
1348 }
1349 continue;
1350 } else if ( !isdigit(*pt) )
1351 continue;
1352 val = strtol(pt,&end,10);
1353 while ( isspace(*end)) ++end;
1354 in_is_single = 0;
1355 if ( strncmp(end,bcsr,strlen(bcsr))==0 ) {
1356 in = cmt_coderange;
1357 } else if ( strncmp(end,bndr,strlen(bndr))==0 ) {
1358 in = cmt_notdefs;
1359 } else if ( strncmp(end,bcr,strlen(bcr))==0 ) {
1360 in = cmt_cid;
1361 } else if ( strncmp(end,bcc,strlen(bcc))==0 ) {
1362 in = cmt_cid;
1363 in_is_single = 1;
1364 }
1365 if ( in!=cmt_out ) {
1366 pos = cmap->groups[in].n;
1367 cmap->groups[in].ranges = ExtendArray(cmap->groups[in].ranges,&cmap->groups[in].n,val);
1368 }
1369 } else if ( strncmp(pt,"end",3)== 0 )
1370 in = cmt_out;
1371 else if (pos >= cmap->groups[in].n) {
1372 LogError(_("cidmap entry out of bounds: %s"), buf2);
1373 }
1374 else {
1375 // Read the first bracketed code.
1376 if ( *pt!='<' )
1377 continue;
1378 cmap->groups[in].ranges[pos].first = strtoul(pt+1,&end,16);
1379 if ( *end=='>' ) ++end;
1380 while ( isspace(*end)) ++end;
1381 if (in_is_single) {
1382 cmap->groups[in].ranges[pos].last = cmap->groups[in].ranges[pos].first;
1383 } else {
1384 // Read the second bracketed code.
1385 if ( *end=='<' ) ++end;
1386 cmap->groups[in].ranges[pos].last = strtoul(end,&end,16);
1387 if ( *end=='>' ) ++end;
1388 }
1389 if ( in!=cmt_coderange ) {
1390 while ( isspace(*end)) ++end;
1391 // Read the unbracketed argument.
1392 cmap->groups[in].ranges[pos].cid = strtol(end,&end,10);
1393 }
1394 ++pos;
1395 }
1396 }
1397 fclose(file);
1398 return( cmap );
1399 }
1400
CompressCMap(struct cmap * cmap)1401 static void CompressCMap(struct cmap *cmap) {
1402 int32 i,j,k, pos, base;
1403 uint32 min, oldmax;
1404 /* we can't really deal with three and four byte encodings */
1405 /* so if we get one arrange for the sf itself to do a remap */
1406
1407 cmap->total = 0x10000;
1408 for ( i=0; i<cmap->groups[cmt_coderange].n; ++i )
1409 if ( cmap->groups[cmt_coderange].ranges[i].last>0xfffff )
1410 break;
1411 if ( i==cmap->groups[cmt_coderange].n ) /* No need to remap */
1412 return;
1413
1414 cmap->remap = calloc(cmap->groups[cmt_coderange].n+1,sizeof(struct remap));
1415 base = 0;
1416 for ( i=0; i<cmap->groups[cmt_coderange].n; ++i )
1417 if ( cmap->groups[cmt_coderange].ranges[i].last<0xffff ) {
1418 base = 0x10000;
1419 break;
1420 }
1421
1422 pos=0;
1423 oldmax = base==0?0:0xffff;
1424 for ( i=0; i<cmap->groups[cmt_coderange].n; ++i ) {
1425 min = 0xffffffff; k=-1;
1426 for ( j=0; j<cmap->groups[cmt_coderange].n; ++j )
1427 if ( cmap->groups[cmt_coderange].ranges[j].first>oldmax &&
1428 cmap->groups[cmt_coderange].ranges[j].first<min ) {
1429 min = cmap->groups[cmt_coderange].ranges[j].first;
1430 k = j;
1431 }
1432 if ( k==-1 )
1433 break;
1434 cmap->remap[pos].firstenc = cmap->groups[cmt_coderange].ranges[k].first&~0xff;
1435 cmap->remap[pos].lastenc = cmap->groups[cmt_coderange].ranges[k].last|0xff;
1436 cmap->remap[pos].infont = base;
1437 base += cmap->remap[pos].lastenc-cmap->remap[pos].firstenc+1;
1438 oldmax = cmap->remap[pos].lastenc;
1439 ++pos;
1440 }
1441 cmap->remap[pos].infont = -1; /* Marks end */
1442 cmap->total = base;
1443 /* so cmap->remap will map sf indeces into the encoding in the cmap */
1444
1445 /* And now we want to change the groups[cmt_cid].ranges so that they will */
1446 /* map into sf indeces rather than into the encoding of the cmap */
1447 for ( i=0; i<cmap->groups[cmt_cid].n; ++i ) {
1448 for ( k=0; cmap->remap[k].infont!=-1; ++k )
1449 if ( cmap->groups[cmt_cid].ranges[i].first>=cmap->remap[k].firstenc &&
1450 cmap->groups[cmt_cid].ranges[i].first<=cmap->remap[k].lastenc )
1451 break;
1452 if ( cmap->remap[k].infont==-1 )
1453 continue;
1454 cmap->groups[cmt_cid].ranges[i].first += cmap->remap[k].infont-cmap->remap[k].firstenc;
1455 cmap->groups[cmt_cid].ranges[i].last += cmap->remap[k].infont-cmap->remap[k].firstenc;
1456 }
1457 }
1458
CIDFlatten(SplineFont * cidmaster,SplineChar ** glyphs,int charcnt)1459 SplineFont *CIDFlatten(SplineFont *cidmaster,SplineChar **glyphs,int charcnt) {
1460 FontViewBase *fvs;
1461 SplineFont *new;
1462 char buffer[20];
1463 BDFFont *bdf;
1464 int j;
1465
1466 if ( cidmaster==NULL )
1467 return(NULL);
1468 new = SplineFontEmpty();
1469 new->fontname = copy(cidmaster->fontname);
1470 new->fullname = copy(cidmaster->fullname);
1471 new->familyname = copy(cidmaster->familyname);
1472 new->weight = copy(cidmaster->weight);
1473 new->copyright = copy(cidmaster->copyright);
1474 sprintf(buffer,"%g", (double)cidmaster->cidversion);
1475 new->version = copy(buffer);
1476 new->italicangle = cidmaster->italicangle;
1477 new->upos = cidmaster->upos;
1478 new->uwidth = cidmaster->uwidth;
1479 new->ascent = cidmaster->ascent;
1480 new->descent = cidmaster->descent;
1481 new->changed = new->changed_since_autosave = true;
1482 new->display_antialias = cidmaster->display_antialias;
1483 new->hasvmetrics = cidmaster->hasvmetrics;
1484 new->fv = cidmaster->fv;
1485 /* Don't copy the grid splines, there won't be anything meaningfull at top level */
1486 /* and won't know which font to copy from below */
1487 new->bitmaps = cidmaster->bitmaps; /* should already be flattened */
1488 cidmaster->bitmaps = NULL; /* don't free 'em */
1489 for ( bdf=new->bitmaps; bdf!=NULL; bdf=bdf->next )
1490 bdf->sf = new;
1491 new->gpos_lookups = cidmaster->gpos_lookups;
1492 cidmaster->gpos_lookups = NULL;
1493 new->gsub_lookups = cidmaster->gsub_lookups;
1494 cidmaster->gsub_lookups = NULL;
1495 new->kerns = cidmaster->kerns; new->vkerns = cidmaster->vkerns;
1496 cidmaster->kerns = cidmaster->vkerns = NULL;
1497 new->names = cidmaster->names; cidmaster->names = NULL;
1498 new->horiz_base = cidmaster->horiz_base; cidmaster->horiz_base = NULL;
1499 new->vert_base = cidmaster->vert_base; cidmaster->vert_base = NULL;
1500 new->pfminfo = cidmaster->pfminfo;
1501 new->texdata = cidmaster->texdata;
1502 new->possub = cidmaster->possub; cidmaster->possub = NULL;
1503 new->sm = cidmaster->sm; cidmaster->sm = NULL;
1504 new->features = cidmaster->features; cidmaster->features = NULL;
1505 new->macstyle = cidmaster->macstyle;
1506 new->origname = copy( cidmaster->origname );
1507 new->display_size = cidmaster->display_size;
1508 /* Don't copy private */
1509 new->xuid = copy(cidmaster->xuid);
1510 new->glyphs = glyphs;
1511 new->glyphcnt = new->glyphmax = charcnt;
1512 for ( j=0; j<charcnt; ++j ) if ( glyphs[j]!=NULL ) {
1513 glyphs[j]->parent = new;
1514 glyphs[j]->orig_pos = j;
1515 }
1516 for ( fvs=new->fv; fvs!=NULL; fvs=fvs->nextsame ) {
1517 fvs->cidmaster = NULL;
1518 if ( fvs->sf->glyphcnt!=new->glyphcnt ) {
1519 free(fvs->selected);
1520 fvs->selected = calloc(new->glyphcnt,sizeof(uint8));
1521 if ( fvs->map->encmax < new->glyphcnt )
1522 fvs->map->map = realloc(fvs->map->map,(fvs->map->encmax = new->glyphcnt)*sizeof(int32));
1523 fvs->map->enccount = new->glyphcnt;
1524 if ( fvs->map->backmax < new->glyphcnt )
1525 fvs->map->backmap = realloc(fvs->map->backmap,(fvs->map->backmax = new->glyphcnt)*sizeof(int32));
1526 for ( j=0; j<new->glyphcnt; ++j )
1527 fvs->map->map[j] = fvs->map->backmap[j] = j;
1528 }
1529 fvs->sf = new;
1530 FVSetTitle(fvs);
1531 }
1532 FontViewReformatAll(new);
1533 SplineFontFree(cidmaster);
1534 return( new );
1535 }
1536
SFFlatten(SplineFont ** cidmasterpp)1537 void SFFlatten(SplineFont **cidmasterpp) {
1538 SplineChar **glyphs;
1539 SplineFont *cidmaster = *cidmasterpp;
1540 int i,j,max;
1541
1542 if ( cidmaster==NULL )
1543 return;
1544
1545 if ( cidmaster->cidmaster!=NULL ) {
1546 cidmaster = cidmaster->cidmaster;
1547 cidmasterpp = &cidmaster;
1548 }
1549 /* This doesn't change the ordering, so no need for special tricks to */
1550 /* preserve scrolling location. */
1551 for ( i=max=0; i<cidmaster->subfontcnt; ++i ) {
1552 if ( max<cidmaster->subfonts[i]->glyphcnt )
1553 max = cidmaster->subfonts[i]->glyphcnt;
1554 }
1555 glyphs = calloc(max,sizeof(SplineChar *));
1556 for ( j=0; j<max; ++j ) {
1557 for ( i=0; i<cidmaster->subfontcnt; ++i ) {
1558 if ( j<cidmaster->subfonts[i]->glyphcnt && cidmaster->subfonts[i]->glyphs[j]!=NULL ) {
1559 glyphs[j] = cidmaster->subfonts[i]->glyphs[j];
1560 cidmaster->subfonts[i]->glyphs[j] = NULL;
1561 break;
1562 }
1563 }
1564 }
1565 *cidmasterpp = CIDFlatten(cidmaster,glyphs,max);
1566 }
1567
SFFlattenByCMap(SplineFont ** sfpp,char * cmapname)1568 int SFFlattenByCMap(SplineFont **sfpp,char *cmapname) {
1569 struct cmap *cmap;
1570 int i,j,k,l,m, extras, max, curmax, warned;
1571 int found[4];
1572 SplineChar **glyphs = NULL, *sc;
1573 SplineFont *sf = *sfpp;
1574 FontViewBase *fvs;
1575
1576 if ( sf->cidmaster!=NULL ) {
1577 sf = sf->cidmaster;
1578 sfpp = &sf;
1579 }
1580 if ( sf->subfontcnt==0 ) {
1581 ff_post_error(_("Not a CID-keyed font"),_("Not a CID-keyed font"));
1582 return( false );
1583 }
1584 if ( cmapname==NULL )
1585 return( false );
1586 cmap = ParseCMap(cmapname);
1587 if ( cmap==NULL )
1588 return( false );
1589 CompressCMap(cmap);
1590 max = 0;
1591 for ( i=0; i<cmap->groups[cmt_cid].n; ++i ) {
1592 if ( max<cmap->groups[cmt_cid].ranges[i].last )
1593 max = cmap->groups[cmt_cid].ranges[i].last;
1594 if ( cmap->groups[cmt_cid].ranges[i].last>0x100000 ) {
1595 ff_post_error(_("Encoding Too Large"),_("Encoding Too Large"));
1596 cmapfree(cmap);
1597 return( false );
1598 }
1599 }
1600
1601 curmax = 0;
1602 for ( k=0; k<sf->subfontcnt; ++k ) {
1603 if ( curmax < sf->subfonts[k]->glyphcnt )
1604 curmax = sf->subfonts[k]->glyphcnt;
1605 }
1606
1607 glyphs = calloc(curmax,sizeof(SplineChar *));
1608 for ( i=0; i<curmax; ++i ) {
1609 for ( k=0; k<sf->subfontcnt; ++k )
1610 if ( i<sf->subfonts[k]->glyphcnt && sf->subfonts[k]->glyphs[i]!=NULL ) {
1611 glyphs[i] = sf->subfonts[k]->glyphs[i];
1612 sf->subfonts[k]->glyphs[i] = NULL;
1613 break;
1614 }
1615 }
1616 *sfpp = sf = CIDFlatten(sf,glyphs,curmax);
1617
1618 warned = false;
1619 for ( fvs=sf->fv; fvs!=NULL; fvs=fvs->nextsame ) {
1620 EncMap *map = fvs->map;
1621 for ( j=0; j<2; ++j ) {
1622 extras = 0;
1623 for ( i=0; i<curmax; ++i ) {
1624 sc = glyphs[i];
1625 if ( sc!=NULL ) {
1626 m = 0;
1627 for ( l=0; l<cmap->groups[cmt_cid].n; ++l ) {
1628 if ( i>=cmap->groups[cmt_cid].ranges[l].cid &&
1629 i<=cmap->groups[cmt_cid].ranges[l].cid +
1630 cmap->groups[cmt_cid].ranges[l].last -
1631 cmap->groups[cmt_cid].ranges[l].first ) {
1632 if ( m<sizeof(found)/sizeof(found[0]) )
1633 found[m++] = l;
1634 else if ( !warned ) {
1635 ff_post_notice(_("MultipleEncodingIgnored"),
1636 _("The glyph at CID %d is mapped to more than %d encodings. Only the first %d are handled."), i,
1637 sizeof(found)/sizeof(found[0]),
1638 sizeof(found)/sizeof(found[0]));
1639 warned = true;
1640 }
1641 }
1642 }
1643 if ( m==0 ) {
1644 if ( j ) {
1645 map->map[max+extras] = sc->orig_pos;
1646 map->backmap[sc->orig_pos] = max+extras;
1647 }
1648 ++extras;
1649 } else {
1650 if ( j ) {
1651 int p = cmap->groups[cmt_cid].ranges[found[0]].first +
1652 i-cmap->groups[cmt_cid].ranges[found[0]].cid;
1653 map->map[p] = sc->orig_pos;
1654 map->backmap[sc->orig_pos] = p;
1655 for ( l=1; l<m; ++l ) {
1656 int pos = cmap->groups[cmt_cid].ranges[found[l]].first +
1657 i-cmap->groups[cmt_cid].ranges[found[l]].cid;
1658 map->map[pos] = sc->orig_pos;
1659 }
1660 }
1661 }
1662 }
1663 }
1664 if ( !j ) {
1665 map->map = realloc(map->map,(map->encmax = map->enccount = max+extras)*sizeof(int32));
1666 memset(map->map,-1,map->enccount*sizeof(int32));
1667 memset(map->backmap,-1,sf->glyphcnt*sizeof(int32));
1668 fvs->selected = realloc(fvs->selected, map->enccount*sizeof(uint8));
1669 if (map->enccount > sf->glyphcnt) {
1670 memset(fvs->selected+sf->glyphcnt, 0, map->enccount-sf->glyphcnt);
1671 }
1672 map->remap = cmap->remap; cmap->remap = NULL;
1673 }
1674 warned = true;
1675 }
1676 }
1677 cmapfree(cmap);
1678 FontViewReformatAll(sf);
1679 return( true );
1680 }
1681
Enc2CMap(struct cmap * cmap,int enc)1682 static int Enc2CMap(struct cmap *cmap,int enc) {
1683 int i;
1684
1685 for ( i=0; i<cmap->groups[cmt_cid].n; ++i )
1686 if ( enc>=cmap->groups[cmt_cid].ranges[i].first &&
1687 enc<=cmap->groups[cmt_cid].ranges[i].last )
1688 return( enc-cmap->groups[cmt_cid].ranges[i].first+
1689 cmap->groups[cmt_cid].ranges[i].cid );
1690
1691 return( -1 );
1692 }
1693
SFEncodeToCMap(SplineFont * cidmaster,SplineFont * sf,EncMap * oldmap,struct cmap * cmap)1694 static void SFEncodeToCMap(SplineFont *cidmaster,SplineFont *sf,EncMap *oldmap, struct cmap *cmap) {
1695 SplineChar *sc, *GID0=NULL;
1696 int i,max=0, anyextras=0;
1697
1698 cidmaster->cidregistry = cmap->registry; cmap->registry = NULL;
1699 cidmaster->ordering = cmap->ordering; cmap->ordering = NULL;
1700 cidmaster->supplement = cmap->supplement;
1701
1702 for ( i=0; i<sf->glyphcnt; ++i ) if ( (sc = sf->glyphs[i])!=NULL ) {
1703 if ( strcmp(sc->name,".notdef")==0 )
1704 sc->orig_pos = 0;
1705 else if ( oldmap->backmap[i]==-1 )
1706 sc->orig_pos = -1;
1707 else {
1708 sc->orig_pos = Enc2CMap(cmap,oldmap->backmap[i]);
1709 if ( sc->orig_pos==0 ) {
1710 if ( GID0==NULL )
1711 GID0 = sc;
1712 else
1713 sc->orig_pos = -1;
1714 }
1715 }
1716 if ( sc->orig_pos>max ) max = sc->orig_pos;
1717 else if ( sc->orig_pos==-1 ) ++anyextras;
1718 }
1719 if ( GID0!=NULL )
1720 GID0->orig_pos = ++max;
1721
1722 if ( anyextras ) {
1723 char *buttons[3];
1724 buttons[0] = _("_Delete");
1725 buttons[1] = _("_Add");
1726 buttons[2] = NULL;
1727 if ( ff_ask(_("Extraneous glyphs"),(const char **) buttons,0,1,_("The current encoding contains glyphs which I cannot map to CIDs.\nShould I delete them or add them to the end (where they may conflict with future ros definitions)?"))==1 ) {
1728 if ( cmap!=NULL && max<cmap->total ) max = cmap->total;
1729 anyextras = 0;
1730 for ( i=0; i<sf->glyphcnt; ++i ) if ( (sc = sf->glyphs[i])!=NULL ) {
1731 if ( sc->orig_pos == -1 ) sc->orig_pos = max + anyextras++;
1732 }
1733 max += anyextras;
1734 }
1735 }
1736 SFApplyOrdering(sf, max+1);
1737 }
1738
1739 /* If we change the ascent/descent of a sub font then consider changing the */
1740 /* as/ds of the master font. I used to think this irrelevant, but as the */
1741 /* typoAscent/Descent is based on the master's ascent/descent it actually */
1742 /* is meaningful. Set the master to the subfont with the most glyphs */
CIDMasterAsDes(SplineFont * sf)1743 void CIDMasterAsDes(SplineFont *sf) {
1744 SplineFont *cidmaster = sf->cidmaster;
1745 SplineFont *best;
1746 int i, cid, cnt, bcnt;
1747
1748 if ( cidmaster==NULL )
1749 return;
1750 best = NULL; bcnt = 0;
1751 for ( i=0; i<cidmaster->subfontcnt; ++i ) {
1752 sf = cidmaster->subfonts[i];
1753 for ( cid=cnt=0; cid<sf->glyphcnt; ++cid )
1754 if ( sf->glyphs[cid]!=NULL )
1755 ++cnt;
1756 if ( cnt>bcnt ) {
1757 best = sf;
1758 bcnt = cnt;
1759 }
1760 }
1761 if ( best==NULL && cidmaster->subfontcnt>0 )
1762 best = cidmaster->subfonts[0];
1763 if ( best!=NULL ) {
1764 double ratio = 1000.0/(best->ascent+best->descent);
1765 int ascent = rint(best->ascent*ratio);
1766 if ( cidmaster->ascent!=ascent || cidmaster->descent!=1000-ascent ) {
1767 cidmaster->ascent = ascent;
1768 cidmaster->descent = 1000-ascent;
1769 }
1770 }
1771 }
1772
MakeCIDMaster(SplineFont * sf,EncMap * oldmap,int bycmap,char * cmapfilename,struct cidmap * cidmap)1773 SplineFont *MakeCIDMaster(SplineFont *sf,EncMap *oldmap,int bycmap,char *cmapfilename, struct cidmap *cidmap) {
1774 SplineFont *cidmaster;
1775 struct cidmap *map;
1776 struct cmap *cmap;
1777 FontViewBase *fvs;
1778
1779 cidmaster = SplineFontEmpty();
1780 if ( bycmap ) {
1781 if ( cmapfilename==NULL ) {
1782 SplineFontFree(cidmaster);
1783 return(NULL);
1784 }
1785 cmap = ParseCMap(cmapfilename);
1786 if ( cmap==NULL ) {
1787 SplineFontFree(cidmaster);
1788 return(NULL);
1789 }
1790 CompressCMap(cmap);
1791 SFEncodeToCMap(cidmaster,sf,oldmap,cmap);
1792 cmapfree(cmap);
1793 } else {
1794 map = cidmap;
1795 if ( map==NULL ) {
1796 SplineFontFree(cidmaster);
1797 return(NULL);
1798 }
1799 cidmaster->cidregistry = copy(map->registry);
1800 cidmaster->ordering = copy(map->ordering);
1801 cidmaster->supplement = map->supplement;
1802 SFEncodeToMap(sf,map);
1803 }
1804 if ( sf->uni_interp!=ui_none && sf->uni_interp!=ui_unset )
1805 cidmaster->uni_interp = sf->uni_interp;
1806 else if ( strstrmatch(cidmaster->ordering,"japan")!=NULL )
1807 cidmaster->uni_interp = ui_japanese;
1808 else if ( strstrmatch(cidmaster->ordering,"CNS")!=NULL )
1809 cidmaster->uni_interp = ui_trad_chinese;
1810 else if ( strstrmatch(cidmaster->ordering,"GB")!=NULL )
1811 cidmaster->uni_interp = ui_simp_chinese;
1812 else if ( strstrmatch(cidmaster->ordering,"Korea")!=NULL )
1813 cidmaster->uni_interp = ui_korean;
1814 sf->uni_interp = cidmaster->uni_interp;
1815 cidmaster->fontname = copy(sf->fontname);
1816 cidmaster->fullname = copy(sf->fullname);
1817 cidmaster->familyname = copy(sf->familyname);
1818 cidmaster->weight = copy(sf->weight);
1819 cidmaster->copyright = copy(sf->copyright);
1820 cidmaster->cidversion = 1.0;
1821 cidmaster->display_antialias = sf->display_antialias;
1822 cidmaster->display_size = sf->display_size;
1823 cidmaster->ascent = sf->ascent /*880*/;
1824 cidmaster->descent = sf->descent /*120*/;
1825 cidmaster->changed = cidmaster->changed_since_autosave = true;
1826 for ( fvs=sf->fv; fvs!=NULL; fvs=fvs->nextsame )
1827 fvs->cidmaster = cidmaster;
1828 cidmaster->fv = sf->fv;
1829 sf->cidmaster = cidmaster;
1830 cidmaster->subfontcnt = 1;
1831 cidmaster->subfonts = calloc(2,sizeof(SplineFont *));
1832 cidmaster->subfonts[0] = sf;
1833 cidmaster->gpos_lookups = sf->gpos_lookups; sf->gpos_lookups = NULL;
1834 cidmaster->gsub_lookups = sf->gsub_lookups; sf->gsub_lookups = NULL;
1835 cidmaster->horiz_base = sf->horiz_base; sf->horiz_base = NULL;
1836 cidmaster->vert_base = sf->vert_base; sf->vert_base = NULL;
1837 cidmaster->possub = sf->possub; sf->possub = NULL;
1838 cidmaster->kerns = sf->kerns; sf->kerns = NULL;
1839 cidmaster->vkerns = sf->vkerns; sf->vkerns = NULL;
1840 if ( sf->private==NULL )
1841 sf->private = calloc(1,sizeof(struct psdict));
1842 if ( !PSDictHasEntry(sf->private,"lenIV"))
1843 PSDictChangeEntry(sf->private,"lenIV","1"); /* It's 4 by default, in CIDs the convention seems to be 1 */
1844 for ( fvs=sf->fv; fvs!=NULL; fvs=fvs->nextsame ) {
1845 free(fvs->selected);
1846 fvs->selected = calloc(fvs->sf->glyphcnt,sizeof(uint8));
1847 EncMapFree(fvs->map);
1848 fvs->map = EncMap1to1(fvs->sf->glyphcnt);
1849 FVSetTitle(fvs);
1850 }
1851 CIDMasterAsDes(sf);
1852 FontViewReformatAll(sf);
1853 return( cidmaster );
1854 }
1855
CountOfEncoding(Encoding * encoding_name)1856 int CountOfEncoding(Encoding *encoding_name) {
1857 return( encoding_name->char_cnt );
1858 }
1859
SFEncodingName(SplineFont * sf,EncMap * map)1860 char *SFEncodingName(SplineFont *sf,EncMap *map) {
1861 char buffer[130];
1862
1863 if ( sf->cidmaster!=NULL )
1864 sf = sf->cidmaster;
1865 if ( sf->subfontcnt!=0 ) {
1866 sprintf( buffer, "%.50s-%.50s-%d", sf->cidregistry, sf->ordering, sf->supplement );
1867 return( copy( buffer ));
1868 }
1869 return( copy( map->enc->enc_name ));
1870 }
1871
1872 /* ************************** Reencoding routines ************************** */
1873
BDFOrigFixup(BDFFont * bdf,int orig_cnt,SplineFont * sf)1874 void BDFOrigFixup(BDFFont *bdf,int orig_cnt,SplineFont *sf) {
1875 BDFChar **glyphs;
1876 int i;
1877
1878 if ( bdf->glyphmax>=orig_cnt ) {
1879 if ( bdf->glyphcnt<orig_cnt ) {
1880 for ( i=bdf->glyphcnt; i<orig_cnt; ++i )
1881 bdf->glyphs[i] = NULL;
1882 bdf->glyphcnt = orig_cnt;
1883 }
1884 return;
1885 }
1886
1887 glyphs = calloc(orig_cnt,sizeof(BDFChar *));
1888 for ( i=0; i<bdf->glyphcnt; ++i ) if ( sf->glyphs[i]!=NULL ) {
1889 glyphs[sf->glyphs[i]->orig_pos] = bdf->glyphs[i];
1890 if ( bdf->glyphs[i]!=NULL ) /* Not all glyphs exist in a piecemeal font */
1891 bdf->glyphs[i]->orig_pos = sf->glyphs[i]->orig_pos;
1892 }
1893 free(bdf->glyphs);
1894 bdf->glyphs = glyphs;
1895 bdf->glyphcnt = bdf->glyphmax = orig_cnt;
1896 bdf->ticked = true;
1897 }
1898
_SFForceEncoding(SplineFont * sf,EncMap * old,Encoding * new_enc)1899 static int _SFForceEncoding(SplineFont *sf,EncMap *old, Encoding *new_enc) {
1900 int enc_cnt,i;
1901 BDFFont *bdf;
1902 FontViewBase *fvs;
1903
1904 /* Normally we base our encoding process on unicode code points. */
1905 /* but encodings like AdobeStandard are more interested in names than */
1906 /* code points. It is perfectly possible to have a font properly */
1907 /* encoded by code point which is not properly encoded by name */
1908 /* (might have f_i where it should have fi). So even if it's got */
1909 /* the right encoding, we still may want to force the names */
1910 if ( new_enc->is_custom )
1911 return(false); /* Custom, it's whatever's there */
1912
1913 if ( new_enc->is_original ) {
1914 SplineChar **glyphs;
1915 for ( i=0; i<sf->glyphcnt; ++i ) if ( sf->glyphs[i]!=NULL )
1916 sf->glyphs[i]->orig_pos = -1;
1917 for ( i=enc_cnt=0; i<old->enccount; ++i )
1918 if ( old->map[i]!=-1 && sf->glyphs[old->map[i]]!=NULL &&
1919 sf->glyphs[old->map[i]]->orig_pos == -1 )
1920 sf->glyphs[old->map[i]]->orig_pos = enc_cnt++;
1921 for ( i=0; i<sf->glyphcnt; ++i ) if ( sf->glyphs[i]!=NULL )
1922 if ( sf->glyphs[i]->orig_pos==-1 )
1923 sf->glyphs[i]->orig_pos = enc_cnt++;
1924 for ( i=0; i<sf->glyphcnt; ++i ) if ( sf->glyphs[i]!=NULL ) {
1925 struct splinecharlist *scl;
1926 int layer;
1927 RefChar *ref;
1928
1929 for ( scl=sf->glyphs[i]->dependents; scl!=NULL; scl=scl->next ) {
1930 for ( layer=0; layer<scl->sc->layer_cnt; ++layer )
1931 for ( ref = scl->sc->layers[layer].refs; ref!=NULL; ref=ref->next )
1932 ref->orig_pos = ref->sc->orig_pos;
1933 }
1934 }
1935 for ( fvs=sf->fv; fvs!=NULL; fvs=fvs->nextsame ) {
1936 fvs->map->ticked = false;
1937 /*if ( fvs->filled!=NULL ) fvs->filled->ticked = false;*/
1938 }
1939 for ( fvs=sf->fv; fvs!=NULL; fvs=fvs->nextsame ) if ( !fvs->map->ticked ) {
1940 EncMap *map = fvs->map;
1941 for ( i=0; i<map->enccount; ++i ) if ( map->map[i]!=-1 )
1942 map->map[i] = sf->glyphs[map->map[i]]->orig_pos;
1943 if ( enc_cnt>map->backmax ) {
1944 free(map->backmap);
1945 map->backmax = enc_cnt;
1946 map->backmap = malloc(enc_cnt*sizeof(int32));
1947 }
1948 memset(map->backmap,-1,enc_cnt*sizeof(int32));
1949 for ( i=0; i<map->enccount; ++i ) if ( map->map[i]!=-1 )
1950 if ( map->backmap[map->map[i]]==-1 )
1951 map->backmap[map->map[i]] = i;
1952 map->ticked = true;
1953 }
1954 if ( !old->ticked )
1955 IError( "Unticked encmap" );
1956 for ( bdf=sf->bitmaps; bdf!=NULL; bdf=bdf->next )
1957 BDFOrigFixup(bdf,enc_cnt,sf);
1958 for ( fvs=sf->fv; fvs!=NULL ; fvs=fvs->nextsame )
1959 FVBiggerGlyphCache(fvs,enc_cnt);
1960 glyphs = calloc(enc_cnt,sizeof(SplineChar *));
1961 for ( i=0; i<sf->glyphcnt; ++i ) if ( sf->glyphs[i]!=NULL )
1962 glyphs[sf->glyphs[i]->orig_pos] = sf->glyphs[i];
1963 free(sf->glyphs);
1964 sf->glyphs = glyphs;
1965 sf->glyphcnt = sf->glyphmax = enc_cnt;
1966 return( true );
1967 }
1968
1969 enc_cnt = new_enc->char_cnt;
1970
1971 if ( old->enccount<enc_cnt ) {
1972 if ( old->encmax<enc_cnt ) {
1973 old->map = realloc(old->map,enc_cnt*sizeof(int32));
1974 old->encmax = enc_cnt;
1975 }
1976 memset(old->map+old->enccount,-1,(enc_cnt-old->enccount)*sizeof(int32));
1977 old->enccount = enc_cnt;
1978 }
1979 old->enc = new_enc;
1980 for ( i=0; i<old->enccount && i<enc_cnt; ++i ) if ( old->map[i]!=-1 && sf->glyphs[old->map[i]]!=NULL ) {
1981 SplineChar dummy;
1982 int j = old->map[i];
1983 SCBuildDummy(&dummy,sf,old,i);
1984 sf->glyphs[j]->unicodeenc = dummy.unicodeenc;
1985 free(sf->glyphs[j]->name);
1986 sf->glyphs[j]->name = copy(dummy.name);
1987 }
1988 /* We just changed the unicode values for most glyphs */
1989 /* but any references to them will have the old values, and that's bad, so fix 'em up */
1990 for ( i=0; i<sf->glyphcnt; ++i ) if ( sf->glyphs[i]!=NULL ) {
1991 struct splinecharlist *scl;
1992 int layer;
1993 RefChar *ref;
1994
1995 for ( scl=sf->glyphs[i]->dependents; scl!=NULL; scl=scl->next ) {
1996 for ( layer=0; layer<scl->sc->layer_cnt; ++layer )
1997 for ( ref = scl->sc->layers[layer].refs; ref!=NULL; ref=ref->next )
1998 ref->unicode_enc = ref->sc->unicodeenc;
1999 }
2000 }
2001 return( true );
2002 }
2003
SFForceEncoding(SplineFont * sf,EncMap * old,Encoding * new_enc)2004 int SFForceEncoding(SplineFont *sf,EncMap *old, Encoding *new_enc) {
2005 if ( sf->mm!=NULL ) {
2006 MMSet *mm = sf->mm;
2007 int i;
2008 for ( i=0; i<mm->instance_count; ++i )
2009 _SFForceEncoding(mm->instances[i],old,new_enc);
2010 _SFForceEncoding(mm->normal,old,new_enc);
2011 } else
2012 return( _SFForceEncoding(sf,old,new_enc));
2013
2014 return( true );
2015 }
2016
EncMapFromEncoding(SplineFont * sf,Encoding * enc)2017 EncMap *EncMapFromEncoding(SplineFont *sf,Encoding *enc) {
2018 int i,j, extras, found, base, unmax;
2019 int32 *encoded=NULL, *unencoded=NULL;
2020 EncMap *map;
2021 struct altuni *altuni;
2022 SplineChar *sc;
2023
2024 if ( enc==NULL )
2025 return( NULL );
2026
2027 base = enc->char_cnt;
2028 if ( enc->is_original )
2029 base = 0;
2030 else if ( enc->char_cnt<=256 )
2031 base = 256;
2032 else if ( enc->char_cnt<=0x10000 )
2033 base = 0x10000;
2034 if ( base>0 ) {
2035 encoded = malloc(base*sizeof(int32));
2036 memset(encoded,-1,base*sizeof(int32));
2037 }
2038 if ( sf->glyphcnt>0 ) {
2039 unencoded = malloc(sf->glyphcnt*sizeof(int32));
2040 unmax = sf->glyphcnt;
2041 }
2042
2043 for ( i=extras=0; i<sf->glyphcnt; ++i ) if ( (sc=sf->glyphs[i])!=NULL ) {
2044 found = false;
2045 if ( enc->psnames!=NULL ) {
2046 for ( j=enc->char_cnt-1; j>=0; --j ) {
2047 if ( enc->psnames[j]!=NULL &&
2048 strcmp(enc->psnames[j],sc->name)==0 ) {
2049 found = true;
2050 encoded[j] = i;
2051 }
2052 }
2053 }
2054 if ( !found ) {
2055 if ( sc->unicodeenc!=-1 &&
2056 sc->unicodeenc < (int)unicode4_size &&
2057 (j = EncFromUni(sc->unicodeenc,enc))!= -1 )
2058 encoded[j] = i;
2059 else {
2060 /* I don't think extras can surpass unmax now, but it doesn't */
2061 /* hurt to leave the code (it's from when we encoded duplicates see below) */
2062 if ( extras>=unmax ) unencoded = realloc(unencoded,(unmax+=300)*sizeof(int32));
2063 unencoded[extras++] = i;
2064 }
2065 for ( altuni=sc->altuni; altuni!=NULL; altuni=altuni->next ) {
2066 if ( altuni->unienc!=-1 &&
2067 (uint32)altuni->unienc<unicode4_size &&
2068 altuni->vs==-1 &&
2069 altuni->fid==0 &&
2070 (j = EncFromUni(altuni->unienc,enc))!= -1 )
2071 encoded[j] = i;
2072 /* I used to have code here to add these unencoded duplicates */
2073 /* but I don't really see any reason to do so. The main unicode */
2074 /* will occur, and any encoded duplicates so the glyph won't */
2075 /* vanish */
2076 }
2077 }
2078 }
2079
2080 /* Some glyphs have both a pua encoding and an encoding in a non-bmp */
2081 /* plane. Big5HK does and the AMS glyphs do */
2082 if ( enc->is_unicodefull && (sf->uni_interp == ui_trad_chinese ||
2083 sf->uni_interp == ui_ams )) {
2084 const int *pua = sf->uni_interp == ui_ams? amspua : cns14pua;
2085 for ( i=0xe000; i<0xf8ff; ++i ) {
2086 if ( pua[i-0xe000]!=0 )
2087 encoded[pua[i-0xe000]] = encoded[i];
2088 }
2089 }
2090
2091 if ( enc->psnames != NULL ) {
2092 /* Names are more important than unicode code points for some encodings */
2093 /* AdobeStandard for instance which won't work if you have a glyph */
2094 /* named "f_i" (must be "fi") even though the code point is correct */
2095 /* The code above would match f_i where AS requires fi, so force the */
2096 /* names to be correct. */
2097 for ( j=0; j<enc->char_cnt; ++j ) {
2098 if ( encoded[j]!=-1 && enc->psnames[j]!=NULL &&
2099 strcmp(sf->glyphs[encoded[j]]->name,enc->psnames[j])!=0 ) {
2100 free(sf->glyphs[encoded[j]]->name);
2101 sf->glyphs[encoded[j]]->name = copy(enc->psnames[j]);
2102 }
2103 }
2104 }
2105
2106 map = chunkalloc(sizeof(EncMap));
2107 map->enccount = map->encmax = base + extras;
2108 if ( map->enccount>0 ) {
2109 map->map = malloc(map->enccount*sizeof(int32));
2110 if ( base>0 )
2111 memcpy(map->map,encoded,base*sizeof(int32));
2112 if ( extras>0 )
2113 memcpy(map->map+base,unencoded,extras*sizeof(int32));
2114 }
2115 map->backmax = sf->glyphcnt;
2116 if ( sf->glyphcnt>0 ) {
2117 map->backmap = malloc(sf->glyphcnt*sizeof(int32));
2118 memset(map->backmap,-1,sf->glyphcnt*sizeof(int32)); /* Just in case there are some unencoded glyphs (duplicates perhaps) */
2119 for ( i = map->enccount-1; i>=0; --i ) if ( map->map[i]!=-1 )
2120 map->backmap[map->map[i]] = i;
2121 }
2122 map->enc = enc;
2123
2124 free(encoded);
2125 free(unencoded);
2126
2127 return( map );
2128 }
2129
CompactEncMap(EncMap * map,SplineFont * sf)2130 EncMap *CompactEncMap(EncMap *map, SplineFont *sf) {
2131 int i, inuse, gid;
2132 int32 *newmap;
2133
2134 for ( i=inuse=0; i<map->enccount ; ++i )
2135 if ( (gid = map->map[i])!=-1 && SCWorthOutputting(sf->glyphs[gid]))
2136 ++inuse;
2137 newmap = malloc(inuse*sizeof(int32));
2138 for ( i=inuse=0; i<map->enccount ; ++i )
2139 if ( (gid = map->map[i])!=-1 && SCWorthOutputting(sf->glyphs[gid]))
2140 newmap[inuse++] = gid;
2141 free(map->map);
2142 map->map = newmap;
2143 map->enccount = inuse;
2144 map->encmax = inuse;
2145 map->enc = &custom;
2146 memset(map->backmap,-1,sf->glyphcnt*sizeof(int32));
2147 for ( i=inuse-1; i>=0; --i )
2148 if ( (gid=map->map[i])!=-1 )
2149 map->backmap[gid] = i;
2150 return( map );
2151 }
2152
BCProtectUndoes(Undoes * undo,BDFChar * bc)2153 static void BCProtectUndoes( Undoes *undo,BDFChar *bc ) {
2154 BDFRefChar *brhead, *brprev=NULL, *brnext;
2155
2156 for ( ; undo!=NULL; undo=undo->next ) {
2157 switch ( undo->undotype ) {
2158 case ut_bitmap:
2159 for ( brhead=undo->u.bmpstate.refs; brhead != NULL; brhead=brnext ) {
2160 brnext = brhead->next;
2161 if ( brhead->bdfc == bc ) {
2162 BCPasteInto( &undo->u.bmpstate,bc,brhead->xoff,brhead->yoff,false,false );
2163 if ( brprev == NULL )
2164 undo->u.bmpstate.refs = brnext;
2165 else
2166 brprev->next = brnext;
2167 free( brhead );
2168 } else
2169 brprev = brhead;
2170 }
2171 break;
2172 case ut_multiple:
2173 BCProtectUndoes( undo->u.multiple.mult,bc );
2174 break;
2175 case ut_composit:
2176 BCProtectUndoes( undo->u.composit.bitmaps,bc );
2177 break;
2178 }
2179 }
2180 }
2181
SFReencode(SplineFont * sf,const char * encname,int force)2182 int SFReencode(SplineFont *sf, const char *encname, int force) {
2183 Encoding *new_enc;
2184 FontViewBase *fv = sf->fv;
2185
2186 if ( strmatch(encname,"compacted")==0 ) {
2187 fv->normal = EncMapCopy(fv->map);
2188 CompactEncMap(fv->map,sf);
2189 } else {
2190 new_enc = FindOrMakeEncoding(encname);
2191 if ( new_enc==NULL )
2192 return -1;
2193 if ( force )
2194 SFForceEncoding(sf,fv->map,new_enc);
2195 else if ( new_enc==&custom )
2196 fv->map->enc = &custom;
2197 else {
2198 EncMap *map = EncMapFromEncoding(sf,new_enc);
2199 EncMapFree(fv->map);
2200 if (fv->sf != NULL && fv->map == fv->sf->map) { fv->sf->map = map; }
2201 fv->map = map;
2202 if ( !no_windowing_ui )
2203 FVSetTitle(fv);
2204 }
2205 if ( fv->normal!=NULL ) {
2206 EncMapFree(fv->normal);
2207 if (fv->sf != NULL && fv->map == fv->sf->map) { fv->sf->map = NULL; }
2208 fv->normal = NULL;
2209 }
2210 SFReplaceEncodingBDFProps(sf,fv->map);
2211 }
2212 free(fv->selected);
2213 fv->selected = calloc(fv->map->enccount,sizeof(uint8));
2214 if ( !no_windowing_ui )
2215 FontViewReformatAll(sf);
2216
2217 return 0;
2218 }
2219
SFRemoveGlyph(SplineFont * sf,SplineChar * sc)2220 void SFRemoveGlyph( SplineFont *sf,SplineChar *sc ) {
2221 struct splinecharlist *dep, *dnext;
2222 struct bdfcharlist *bdep, *bdnext;
2223 RefChar *rf, *refs, *rnext;
2224 BDFRefChar *bref, *brnext, *brprev;
2225 KernPair *kp, *kprev;
2226 int i;
2227 BDFFont *bdf;
2228 BDFChar *bfc, *dbc;
2229 int layer;
2230
2231 if ( sc==NULL )
2232 return;
2233
2234 /* Close any open windows */
2235 SCCloseAllViews(sc);
2236
2237 /* Turn any references to this glyph into inline copies of it */
2238 for ( dep=sc->dependents; dep!=NULL; dep=dnext ) {
2239 SplineChar *dsc = dep->sc;
2240 dnext = dep->next;
2241 /* May be more than one reference to us, colon has two refs to period */
2242 /* but only one dlist entry */
2243 for ( layer=0; layer<dsc->layer_cnt; ++layer ) {
2244 for ( rf = dsc->layers[layer].refs; rf!=NULL; rf=rnext ) {
2245 rnext = rf->next;
2246 if ( rf->sc==sc )
2247 SCRefToSplines(dsc,rf,layer);
2248 }
2249 }
2250 }
2251
2252 for ( layer=0; layer<sc->layer_cnt; ++layer ) {
2253 for ( refs=sc->layers[layer].refs; refs!=NULL; refs = rnext ) {
2254 rnext = refs->next;
2255 SCRemoveDependent(sc,refs,layer);
2256 }
2257 }
2258
2259 /* Remove any kerning pairs that look at this character */
2260 for ( i=0; i<sf->glyphcnt; ++i ) if ( sf->glyphs[i]!=NULL ) {
2261 for ( kprev=NULL, kp=sf->glyphs[i]->kerns; kp!=NULL; kprev = kp, kp=kp->next ) {
2262 if ( kp->sc==sc ) {
2263 if ( kprev==NULL )
2264 sf->glyphs[i]->kerns = kp->next;
2265 else
2266 kprev->next = kp->next;
2267 kp->next = NULL;
2268 KernPairsFree(kp);
2269 break;
2270 }
2271 }
2272 }
2273
2274 sf->glyphs[sc->orig_pos] = NULL;
2275
2276 for ( bdf=sf->bitmaps; bdf!=NULL; bdf = bdf->next ) {
2277 if ( sc->orig_pos<bdf->glyphcnt && (bfc = bdf->glyphs[sc->orig_pos])!= NULL ) {
2278 /* Turn any references to this glyph into inline copies of it */
2279 for ( bdep=bfc->dependents; bdep!=NULL; bdep=bdnext ) {
2280 dbc = bdep->bc;
2281 bdnext = bdep->next;
2282 brprev = NULL;
2283 /* May be more than one reference to us, colon has two refs to period */
2284 /* but only one dlist entry */
2285 for ( bref = dbc->refs; bref!=NULL; bref=brnext ) {
2286 brnext = bref->next;
2287 if ( bref->bdfc==bfc ) {
2288 BCPasteInto( dbc,bref->bdfc,bref->xoff,bref->yoff,false,false );
2289 if ( brprev == NULL ) dbc->refs = brnext;
2290 else brprev->next = brnext;
2291 free( bref );
2292 } else
2293 brprev = bref;
2294 }
2295 }
2296 /* Suppose we have deleted a reference from a composite glyph and than
2297 * going to remove the previously referenced glyph from the font. The
2298 * void reference still remains in the undoes stack, so that executing Undo/Redo
2299 * on the first glyph may lead to unpredictable effects. It is also
2300 * impossible to detect such problematic undoes checking just our
2301 * going-to-be-deleted glyph's dependents, because the composite character
2302 * no longer contains the problematic reference and so is not listed
2303 * in the dependents. Thus the only solution seems to be checking
2304 * every single glyph in the font.
2305 */
2306 for ( i=0; i<bdf->glyphcnt; i++ ) if (( dbc = bdf->glyphs[i] ) != NULL ) {
2307 BCProtectUndoes( dbc->undoes,bfc );
2308 BCProtectUndoes( dbc->redoes,bfc );
2309 }
2310 for ( bref=bfc->refs; refs!=NULL; bref = brnext ) {
2311 brnext = bref->next;
2312 BCRemoveDependent( bfc,bref );
2313 }
2314 bdf->glyphs[sc->orig_pos] = NULL;
2315 BDFCharFree(bfc);
2316 }
2317 }
2318
2319 SplineCharFree(sc);
2320 GlyphHashFree(sf);
2321 }
2322
MapAddEncodingSlot(EncMap * map,int gid)2323 static int MapAddEncodingSlot(EncMap *map,int gid) {
2324 int enc;
2325
2326 if ( map->enccount>=map->encmax )
2327 map->map = realloc(map->map,(map->encmax+=10)*sizeof(int32));
2328 enc = map->enccount++;
2329 map->map[enc] = gid;
2330 map->backmap[gid] = enc;
2331 return( enc );
2332 }
2333
FVAddEncodingSlot(FontViewBase * fv,int gid)2334 void FVAddEncodingSlot(FontViewBase *fv,int gid) {
2335 EncMap *map = fv->map;
2336 int enc;
2337
2338 enc = MapAddEncodingSlot(map,gid);
2339
2340 fv->selected = realloc(fv->selected,map->enccount);
2341 fv->selected[enc] = 0;
2342 FVAdjustScrollBarRows(fv,enc);
2343 }
2344
SFAddEncodingSlot(SplineFont * sf,int gid)2345 void SFAddEncodingSlot(SplineFont *sf,int gid) {
2346 FontViewBase *fv;
2347 for ( fv=sf->fv; fv!=NULL; fv = fv->nextsame )
2348 FVAddEncodingSlot(fv,gid);
2349 }
2350
MapAddEnc(SplineFont * sf,SplineChar * sc,EncMap * basemap,EncMap * map,int baseenc,int gid,FontViewBase * fv)2351 static int MapAddEnc(SplineFont *sf,SplineChar *sc,EncMap *basemap, EncMap *map,int baseenc, int gid, FontViewBase *fv) {
2352 int any = false, enc;
2353
2354 if ( gid>=map->backmax ) {
2355 map->backmap = realloc(map->backmap,(map->backmax+=10)*sizeof(int32));
2356 memset(map->backmap+map->backmax-10,-1,10*sizeof(int32));
2357 }
2358 if ( map->enc->psnames!=NULL ) {
2359 /* Check for multiple encodings */
2360 for ( enc = map->enc->char_cnt-1; enc>=0; --enc ) {
2361 if ( map->enc->psnames[enc]!=NULL && strcmp(sc->name,map->enc->psnames[enc])==0 ) {
2362 if ( !any ) {
2363 map->backmap[gid] = enc;
2364 any = true;
2365 }
2366 map->map[enc] = gid;
2367 }
2368 }
2369 } else {
2370 enc = SFFindSlot(sf,map,sc->unicodeenc,sc->name);
2371 if ( enc!=-1 ) {
2372 map->map[enc] = gid;
2373 map->backmap[gid] = enc;
2374 any = true;
2375 }
2376 }
2377 if ( basemap!=NULL && map->enc==basemap->enc && baseenc!=-1 ) {
2378 if ( baseenc>=map->enccount ) {
2379 if ( fv && map==fv->map )
2380 FVAddEncodingSlot(fv,gid);
2381 else
2382 MapAddEncodingSlot(map,gid);
2383 } else {
2384 map->map[baseenc] = gid;
2385 if ( map->backmap[gid]==-1 )
2386 map->backmap[gid] = baseenc;
2387 }
2388 any = true;
2389 }
2390 return( any );
2391 }
2392
SFAddGlyphAndEncode(SplineFont * sf,SplineChar * sc,EncMap * basemap,int baseenc)2393 void SFAddGlyphAndEncode(SplineFont *sf,SplineChar *sc,EncMap *basemap, int baseenc) {
2394 int gid, mapfound = false;
2395 FontViewBase *fv;
2396 BDFFont *bdf;
2397
2398 if ( sf->cidmaster==NULL ) {
2399 if ( sf->glyphcnt+1>=sf->glyphmax )
2400 sf->glyphs = realloc(sf->glyphs,(sf->glyphmax+=10)*sizeof(SplineChar *));
2401 gid = sf->glyphcnt++;
2402 for ( bdf = sf->bitmaps; bdf!=NULL; bdf=bdf->next ) {
2403 if ( sf->glyphcnt+1>=bdf->glyphmax )
2404 bdf->glyphs = realloc(bdf->glyphs,(bdf->glyphmax=sf->glyphmax)*sizeof(BDFChar *));
2405 if ( sf->glyphcnt>bdf->glyphcnt ) {
2406 memset(bdf->glyphs+bdf->glyphcnt,0,(sf->glyphcnt-bdf->glyphcnt)*sizeof(BDFChar *));
2407 bdf->glyphcnt = sf->glyphcnt;
2408 }
2409 }
2410 for ( fv=sf->fv; fv!=NULL; fv = fv->nextsame ) {
2411 EncMap *map = fv->map;
2412 if ( gid>=map->backmax )
2413 map->backmap = realloc(map->backmap,(map->backmax=gid+10)*sizeof(int32));
2414 map->backmap[gid] = -1;
2415 }
2416 } else {
2417 gid = baseenc < 0 ? sf->glyphcnt : baseenc;
2418 if ( gid+1>=sf->glyphmax )
2419 sf->glyphs = realloc(sf->glyphs,(sf->glyphmax = gid+10)*sizeof(SplineChar *));
2420 if ( gid>=sf->glyphcnt ) {
2421 memset(sf->glyphs+sf->glyphcnt,0,(gid+1-sf->glyphcnt)*sizeof(SplineChar *));
2422 sf->glyphcnt = gid+1;
2423 for ( bdf = sf->cidmaster->bitmaps; bdf!=NULL; bdf=bdf->next ) {
2424 if ( gid+1>=bdf->glyphmax )
2425 bdf->glyphs = realloc(bdf->glyphs,(bdf->glyphmax=gid+10)*sizeof(BDFChar *));
2426 if ( gid+1>bdf->glyphcnt ) {
2427 memset(bdf->glyphs+bdf->glyphcnt,0,(gid+1-bdf->glyphcnt)*sizeof(BDFChar *));
2428 bdf->glyphcnt = gid+1;
2429 }
2430 }
2431 for ( fv=sf->fv; fv!=NULL; fv = fv->nextsame ) if ( fv->sf==sf ) {
2432 EncMap *map = fv->map;
2433 if ( gid>=map->backmax )
2434 map->backmap = realloc(map->backmap,(map->backmax=gid+10)*sizeof(int32));
2435 map->backmap[gid] = -1;
2436 }
2437 }
2438 }
2439 sf->glyphs[gid] = NULL;
2440 for ( fv=sf->fv; fv!=NULL; fv = fv->nextsame ) {
2441 EncMap *map = fv->map;
2442
2443 FVBiggerGlyphCache(fv,gid);
2444
2445 if ( !MapAddEnc(sf,sc,basemap,map,baseenc,gid,fv) )
2446 FVAddEncodingSlot(fv,gid);
2447 if ( map==basemap ) mapfound = true;
2448 if ( fv->normal!=NULL ) {
2449 if ( !MapAddEnc(sf,sc,basemap,fv->normal,baseenc,gid,fv))
2450 MapAddEncodingSlot(fv->normal,gid);
2451 }
2452 }
2453 if ( !mapfound && basemap!=NULL )
2454 MapAddEnc(sf,sc,basemap,basemap,baseenc,gid,fv);
2455 sf->glyphs[gid] = sc;
2456 sc->orig_pos = gid;
2457 sc->parent = sf;
2458 SFHashGlyph(sf,sc);
2459 }
2460
SplineCharMatch(SplineFont * parent,SplineChar * sc)2461 static SplineChar *SplineCharMatch(SplineFont *parent,SplineChar *sc) {
2462 SplineChar *scnew = SFSplineCharCreate(parent);
2463
2464 scnew->parent = parent;
2465 scnew->orig_pos = sc->orig_pos;
2466 scnew->name = copy(sc->name);
2467 scnew->unicodeenc = sc->unicodeenc;
2468 scnew->width = sc->width;
2469 scnew->vwidth = sc->vwidth;
2470 scnew->widthset = true;
2471 return( scnew );
2472 }
2473
SFMatchGlyphs(SplineFont * sf,SplineFont * target,int addempties)2474 void SFMatchGlyphs(SplineFont *sf,SplineFont *target,int addempties) {
2475 /* reorder sf so that its glyphs array is the same as that in target */
2476 int i, j, cnt, cnt2;
2477 SplineChar **glyphs;
2478 BDFFont *bdf;
2479
2480 for ( i=0; i<sf->glyphcnt; ++i ) if ( sf->glyphs[i]!=NULL )
2481 sf->glyphs[i]->ticked = false;
2482 if (( cnt = target->glyphcnt )<sf->glyphcnt ) cnt = sf->glyphcnt;
2483 glyphs = calloc(cnt,sizeof(SplineChar *));
2484 for ( i=0; i<target->glyphcnt; ++i ) if ( target->glyphs[i]!=NULL ) {
2485 SplineChar *sc = SFGetChar(sf,target->glyphs[i]->unicodeenc,target->glyphs[i]->name );
2486 if ( sc==NULL && addempties )
2487 sc = SplineCharMatch(sf,target->glyphs[i]);
2488 if ( sc!=NULL ) {
2489 glyphs[i] = sc;
2490 sc->ticked = true;
2491 }
2492 }
2493 for ( i=cnt2=0; i<sf->glyphcnt; ++i )
2494 if ( sf->glyphs[i]!=NULL && !sf->glyphs[i]->ticked )
2495 ++cnt2;
2496 if ( target->glyphcnt+cnt2>cnt ) {
2497 glyphs = realloc(glyphs,(target->glyphcnt+cnt2)*sizeof(SplineChar *));
2498 memset(glyphs+cnt,0,(target->glyphcnt+cnt2-cnt)*sizeof(SplineChar *));
2499 cnt = target->glyphcnt+cnt2;
2500 }
2501 j = target->glyphcnt;
2502 for ( i=0; i<sf->glyphcnt; ++i )
2503 if ( sf->glyphs[i]!=NULL && !sf->glyphs[i]->ticked )
2504 glyphs[j++] = sf->glyphs[i];
2505 free(sf->glyphs);
2506 sf->glyphs = glyphs;
2507 sf->glyphcnt = sf->glyphmax = cnt;
2508 for ( i=0; i<sf->glyphcnt; ++i ) if ( sf->glyphs[i]!=NULL )
2509 sf->glyphs[i]->orig_pos = i;
2510 for ( bdf = sf->bitmaps; bdf!=NULL; bdf = bdf->next ) {
2511 BDFChar **glyphs;
2512 glyphs = calloc(sf->glyphcnt,sizeof(BDFChar *));
2513 for ( i=0; i<bdf->glyphcnt; ++i ) if ( bdf->glyphs[i]!=NULL )
2514 glyphs[bdf->glyphs[i]->sc->orig_pos] = bdf->glyphs[i];
2515 free(bdf->glyphs);
2516 bdf->glyphs = glyphs;
2517 bdf->glyphcnt = bdf->glyphmax = sf->glyphcnt;
2518 }
2519 }
2520
MMMatchGlyphs(MMSet * mm)2521 void MMMatchGlyphs(MMSet *mm) {
2522 /* reorder all instances so that they have the same orig_pos */
2523 int i, j, index, lasthole;
2524 SplineFont *sf, *base = NULL;
2525 SplineChar *sc, *scnew, *sc2;
2526
2527 for ( i = 0; i<mm->instance_count; ++i ) if ( mm->instances[i]!=NULL ) {
2528 base = mm->instances[i];
2529 break;
2530 }
2531 if ( base==NULL )
2532 return;
2533
2534 /* First build up an ordering that uses all glyphs found in any of the */
2535 /* sub-fonts, "base" will be the start of it. We will add glyphs to */
2536 /* "base" as needed */
2537 lasthole = -1;
2538 for ( i = 0; i<mm->instance_count; ++i ) if ( (sf=mm->instances[i])!=NULL && sf!=NULL ) {
2539 for ( j=0; j<sf->glyphcnt; ++j ) if ( (sc=sf->glyphs[j])!=NULL ) {
2540 if ( j<base->glyphcnt && base->glyphs[j]!=NULL &&
2541 base->glyphs[j]->unicodeenc==sc->unicodeenc &&
2542 strcmp(base->glyphs[j]->name,sc->name)==0 )
2543 continue; /* It's good, and in the same place */
2544 else if ( (sc2=SFGetChar(base,sc->unicodeenc,sc->name))!=NULL &&
2545 sc2->unicodeenc==sc->unicodeenc &&
2546 strcmp(sc2->name,sc->name)==0 )
2547 continue; /* Well, it's in there somewhere */
2548 else {
2549 /* We need to add it */
2550 if ( j<base->glyphcnt && base->glyphs[j]==NULL )
2551 index = j;
2552 else {
2553 for ( ++lasthole ; lasthole<base->glyphcnt && base->glyphs[lasthole]!=NULL; ++lasthole );
2554 index = lasthole;
2555 if ( lasthole>=base->glyphmax )
2556 base->glyphs = realloc(base->glyphs,(base->glyphmax+=20)*sizeof(SplineChar *));
2557 if ( lasthole>=base->glyphcnt )
2558 base->glyphcnt = lasthole+1;
2559 }
2560 base->glyphs[index] = scnew = SplineCharMatch(base,sc);
2561 scnew->orig_pos = index;
2562 }
2563 }
2564 }
2565
2566 /* Now force all other instances to match */
2567 for ( i = 0; i<mm->instance_count; ++i ) if ( (sf=mm->instances[i])!=NULL && sf!=base )
2568 SFMatchGlyphs(sf,base,true);
2569 if ( mm->normal!=NULL )
2570 SFMatchGlyphs(mm->normal,base,true);
2571 }
2572
UniFromEnc(int enc,Encoding * encname)2573 int32 UniFromEnc(int enc, Encoding *encname) {
2574 char from[20];
2575 unichar_t to[20];
2576 ICONV_CONST char *fpt;
2577 char *tpt;
2578 size_t fromlen, tolen;
2579
2580 if ( encname->is_custom || encname->is_original )
2581 return( -1 );
2582 if ( enc>=encname->char_cnt )
2583 return( -1 );
2584 if ( encname->is_unicodebmp || encname->is_unicodefull )
2585 return( enc );
2586 if ( encname->unicode!=NULL )
2587 return( encname->unicode[enc] );
2588 else if ( encname->tounicode ) {
2589 /* To my surprise, on RH9, doing a reset on conversion of CP1258->UCS2 */
2590 /* causes subsequent calls to return garbage */
2591 if ( encname->iso_2022_escape_len ) {
2592 tolen = sizeof(to); fromlen = 0;
2593 iconv(encname->tounicode,NULL,&fromlen,NULL,&tolen); /* Reset state */
2594 }
2595 fpt = from; tpt = (char *) to; tolen = sizeof(to);
2596 if ( encname->has_1byte && enc<256 ) {
2597 *(char *) fpt = enc;
2598 fromlen = 1;
2599 } else if ( encname->has_2byte ) {
2600 if ( encname->iso_2022_escape_len )
2601 strncpy(from,encname->iso_2022_escape,encname->iso_2022_escape_len );
2602 fromlen = encname->iso_2022_escape_len;
2603 from[fromlen++] = enc>>8;
2604 from[fromlen++] = enc&0xff;
2605 }
2606 if ( iconv(encname->tounicode,&fpt,&fromlen,&tpt,&tolen)==(size_t) -1 )
2607 return( -1 );
2608 if ( tpt-(char *) to == 0 ) {
2609 /* This strange call appears to be what we need to make CP1258->UCS2 */
2610 /* work. It's supposed to reset the state and give us the shift */
2611 /* out. As there is no state, and no shift out I have no idea why*/
2612 /* this works, but it does. */
2613 if ( iconv(encname->tounicode,NULL,&fromlen,&tpt,&tolen)==(size_t) -1 )
2614 return( -1 );
2615 }
2616 if ( tpt-(char *) to == sizeof(unichar_t) )
2617 {
2618 return( to[0] );
2619 }
2620 } else if ( encname->tounicode_func!=NULL ) {
2621 return( (encname->tounicode_func)(enc) );
2622 }
2623 return( -1 );
2624 }
2625
EncFromUni(int32 uni,Encoding * enc)2626 int32 EncFromUni(int32 uni, Encoding *enc) {
2627 unichar_t from[20];
2628 unsigned char to[20];
2629 ICONV_CONST char *fpt;
2630 char *tpt;
2631 size_t fromlen, tolen;
2632 int i;
2633
2634 if ( enc->is_custom || enc->is_original || enc->is_compact || uni==-1 )
2635 return( -1 );
2636 if ( enc->is_unicodebmp || enc->is_unicodefull )
2637 return( uni<enc->char_cnt ? uni : -1 );
2638
2639 if ( enc->unicode!=NULL ) {
2640 for ( i=0; i<enc->char_cnt; ++i ) {
2641 if ( enc->unicode[i]==uni )
2642 return( i );
2643 }
2644 return( -1 );
2645 } else if ( enc->fromunicode!=NULL ) {
2646 /* I don't see how there can be any state to reset in this direction */
2647 /* So I don't reset it */
2648 from[0] = uni;
2649 fromlen = sizeof(unichar_t);
2650 fpt = (char *) from; tpt = (char *) to; tolen = sizeof(to);
2651 iconv(enc->fromunicode,NULL,NULL,NULL,NULL); /* reset shift in/out, etc. */
2652 if ( iconv(enc->fromunicode,&fpt,&fromlen,&tpt,&tolen)==(size_t) -1 )
2653 return( -1 );
2654 if ( tpt-(char *) to == 1 )
2655 return( to[0] );
2656 if ( enc->iso_2022_escape_len!=0 ) {
2657 if ( tpt-(char *) to == enc->iso_2022_escape_len+2 &&
2658 strncmp((char *) to,enc->iso_2022_escape,enc->iso_2022_escape_len)==0 )
2659 return( (to[enc->iso_2022_escape_len]<<8) | to[enc->iso_2022_escape_len+1] );
2660 } else {
2661 if ( tpt-(char *) to == sizeof(unichar_t) )
2662 return( (to[0]<<8) | to[1] );
2663 }
2664 } else if ( enc->fromunicode_func!=NULL ) {
2665 return( (enc->fromunicode_func)(uni) );
2666 }
2667 return( -1 );
2668 }
2669
EncFromName(const char * name,enum uni_interp interp,Encoding * encname)2670 int32 EncFromName(const char *name,enum uni_interp interp,Encoding *encname) {
2671 int i;
2672 if ( encname->psnames!=NULL ) {
2673 for ( i=0; i<encname->char_cnt; ++i )
2674 if ( encname->psnames[i]!=NULL && strcmp(name,encname->psnames[i])==0 )
2675 return( i );
2676 }
2677 i = UniFromName(name,interp,encname);
2678 if ( i==-1 && strlen(name)==4 ) {
2679 /* MS says use this kind of name, Adobe says use the one above */
2680 char *end;
2681 i = strtol(name,&end,16);
2682 if ( i<0 || i>0xffff || *end!='\0' )
2683 return( -1 );
2684 }
2685 return( EncFromUni(i,encname));
2686 }
2687
SFExpandGlyphCount(SplineFont * sf,int newcnt)2688 void SFExpandGlyphCount(SplineFont *sf, int newcnt) {
2689 int old = sf->glyphcnt;
2690 FontViewBase *fv;
2691
2692 if ( old>=newcnt )
2693 return;
2694 if ( sf->glyphmax<newcnt ) {
2695 sf->glyphs = realloc(sf->glyphs,newcnt*sizeof(SplineChar *));
2696 sf->glyphmax = newcnt;
2697 }
2698 memset(sf->glyphs+sf->glyphcnt,0,(newcnt-sf->glyphcnt)*sizeof(SplineChar *));
2699 sf->glyphcnt = newcnt;
2700
2701 for ( fv=sf->fv; fv!=NULL; fv=fv->nextsame ) {
2702 if ( fv->sf==sf ) { /* Beware of cid keyed fonts which might look at a different subfont */
2703 if ( fv->normal!=NULL )
2704 continue; /* If compacted then we haven't added any glyphs so haven't changed anything */
2705 /* Don't display any of these guys, so not mapped. */
2706 /* No change to selection, or to map->map, but change to backmap */
2707 if ( newcnt>fv->map->backmax )
2708 fv->map->backmap = realloc(fv->map->backmap,(fv->map->backmax = newcnt+5)*sizeof(int32));
2709 memset(fv->map->backmap+old,-1,(newcnt-old)*sizeof(int32));
2710 }
2711 }
2712 }
2713