1 /* -*- coding: utf-8 -*- */
2 /* Copyright (C) 2000-2012 by George Williams */
3 /*
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are met:
6 
7  * Redistributions of source code must retain the above copyright notice, this
8  * list of conditions and the following disclaimer.
9 
10  * Redistributions in binary form must reproduce the above copyright notice,
11  * this list of conditions and the following disclaimer in the documentation
12  * and/or other materials provided with the distribution.
13 
14  * The name of the author may not be used to endorse or promote products
15  * derived from this software without specific prior written permission.
16 
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
18  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
19  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
20  * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
22  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
23  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
24  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
25  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
26  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  */
28 
29 #include <fontforge-config.h>
30 
31 #include "autohint.h"
32 #include "autowidth.h"
33 #include "bitmapchar.h"
34 #include "bvedit.h"
35 #include "chardata.h"
36 #include "cvundoes.h"
37 #include "encoding.h"
38 #include "fontforgevw.h"
39 #include "fvfonts.h"
40 #include "namelist.h"
41 #include "splinefill.h"
42 #include "splinesaveafm.h"
43 #include "splineutil.h"
44 #include "ustring.h"
45 #include "utype.h"
46 
47 #include <math.h>
48 
49 int accent_offset = 6;
50 int GraveAcuteCenterBottom = 1;
51 int PreferSpacingAccents = false;
52 int CharCenterHighest = 1;
53 
54 #define BottomAccent	0x300
55 #define TopAccent	0x345
56 
57 /* for accents between 0x300 and 345 these are some synonyms */
58 /* type1 wants accented chars built with accents in the 0x2c? range */
59 /*  except for grave and acute which live in iso8859-1 range */
60 /*  this table is ordered on a best try basis */
61 static const unichar_t accents[][4] = {
62     { 0x2cb, 0x300, 0x60 },	/* grave */
63     { 0x2ca, 0x301, 0xb4 },	/* acute */
64     { 0x2c6, 0x302, 0x5e },	/* circumflex */
65     { 0x2dc, 0x303, 0x7e },	/* tilde */
66     { 0x2c9, 0x304, 0xaf },	/* macron */
67     { 0x305, 0xaf },		/* overline, (macron is suggested as a syn, but it's not quite right) */
68     { 0x2d8, 0x306 },		/* breve */
69     { 0x2d9, 0x307, '.' },	/* dot above */
70     { 0xa8,  0x308 },		/* diaeresis */
71     { 0x2c0 },			/* hook above */
72     { 0x2da, 0xb0 },		/* ring above */
73     { 0x2dd },			/* real acute */
74     { 0x2c7 },			/* caron */
75     { 0x2c8, 0x384, 0x30d, '\''  },	/* vertical line, tonos */
76     { 0x30e, '"' },		/* real vertical line */
77     { 0 },			/* real grave */
78     { 0 },			/* cand... */		/* 310 */
79     { 0 },			/* inverted breve */
80     { 0x2bb },			/* turned comma */
81     { 0x2bc, 0x313, ',' },	/* comma above */
82     { 0x2bd },			/* reversed comma */
83     { 0x2bc, 0x315, ',' },	/* comma above right */
84     { 0x316, 0x60, 0x2cb },	/* grave below */
85     { 0x317, 0xb4, 0x2ca },	/* acute below */
86     { 0 },			/* left tack */
87     { 0 },			/* right tack */
88     { 0 },			/* left angle */
89     { 0 },			/* horn, sometimes comma but only if nothing better */
90     { 0 },			/* half ring */
91     { 0x2d4 },			/* up tack */
92     { 0x2d5 },			/* down tack */
93     { 0x2d6, 0x31f, '+' },	/* plus below */
94     { 0x2d7, 0x320, '-' },	/* minus below */	/* 320 */
95     { 0x2b2 },			/* hook */
96     { 0 },			/* back hook */
97     { 0x323, 0x2d9, '.' },	/* dot below */
98     { 0x324, 0xa8 },		/* diaeresis below */
99     { 0x325, 0x2da, 0xb0 },	/* ring below */
100     { 0x326, 0x2bc, ',' },	/* comma below */
101     { 0xb8 },			/* cedilla */
102     { 0x2db },			/* ogonek */		/* 0x328 */
103     { 0x329, 0x2c8, 0x384, '\''  },	/* vertical line below */
104     { 0 },			/* bridge below */
105     { 0 },			/* real arch below */
106     { 0x32c, 0x2c7 },		/* caron below */
107     { 0x32d, 0x2c6, 0x52 },	/* circumflex below */
108     { 0x32e, 0x2d8 },		/* breve below */
109     { 0 },			/* inverted breve below */
110     { 0x330, 0x2dc, 0x7e },	/* tilde below */	/* 0x330 */
111     { 0x331, 0xaf, 0x2c9 },	/* macron below */
112     { 0x332, '_' },		/* low line */
113     { 0 },			/* real low line */
114     { 0x334, 0x2dc, 0x7e },	/* tilde overstrike */
115     { 0x335, '-' },		/* line overstrike */
116     { 0x336, '_' },		/* long line overstrike */
117     { 0x337, '/' },		/* short solidus overstrike */
118     { 0x338, '/' },		/* long solidus overstrike */	/* 0x338 */
119     { 0 },
120     { 0 },
121     { 0 },
122     { 0 },
123     { 0 },
124     { 0 },
125     { 0 },
126     { 0x340, 0x60, 0x2cb },	/* tone mark, left of circumflex */ /* 0x340 */
127     { 0x341, 0xb4, 0x2ca },	/* tone mark, right of circumflex */
128     { 0x342, 0x2dc, 0x7e },	/* perispomeni (tilde) */
129     { 0x343, 0x2bc, ',' },	/* koronis */
130     { 0 },			/* dialytika tonos (two accents) */
131     { 0x37a },			/* ypogegrammeni */
132     { 0xffff }
133 };
134 
135 static int SCMakeDotless(SplineFont *sf, SplineChar *dotless, int layer, BDFFont *bdf, int disp_only, int doit);
136 
CanonicalCombiner(int uni)137 int CanonicalCombiner(int uni) {
138     /* Translate spacing accents to combiners */
139     int j,k;
140 
141     /* The above table will use these occasionally, but we don't want to */
142     /*  translate them. They aren't accents */
143     if ( uni==',' || uni=='\'' || uni=='"' || uni=='~' || uni=='^' || uni=='-' ||
144 	    uni=='+' || uni=='.' )
145 return( uni );
146 
147     for ( j=0; accents[j][0]!=0xffff; ++j ) {
148 	for ( k=0; k<4 && accents[j][k]!=0; ++k ) {
149 	    if ( uni==accents[j][k] ) {
150 		uni = 0x300+j;
151 	break;
152 	    }
153 	}
154 	if ( uni>=0x300 && uni<0x370 )
155     break;
156     }
157 return( uni );
158 }
159 
160 static const char *uc_accent_names[] = {
161     "Grave",
162     "Acute",
163     "Circumflex",
164     "Tilde",
165     "Macron",
166     "Overline",
167     "Breve",
168     "Dotaccent",
169     "Diaeresis",
170     NULL,
171     "Ring",
172     "Acute",
173     "Caron"
174 };
175 
176 /* greek accents */
177 /* because of accent unification I can't use the same glyphs for greek and */
178 /*  latin accents. Annoying. So when unicode decomposes a greek letter to */
179 /*  use 0x0301 we actually want 0x1ffd and so on */
180 static unichar_t unicode_greekalts[256][3] = {
181 /* 1F00 */ { 0x03B1, 0x1FBF, 0 },
182 /* 1F01 */ { 0x03B1, 0x1FFE, 0 },
183 /* 1F02 */ { 0x03B1, 0x1FCD, 0 },
184 /* 1F03 */ { 0x03B1, 0x1FDD, 0 },
185 /* 1F04 */ { 0x03B1, 0x1FCE, 0 },
186 /* 1F05 */ { 0x03B1, 0x1FDE, 0 },
187 /* 1F06 */ { 0x03B1, 0x1FCF, 0 },
188 /* 1F07 */ { 0x03B1, 0x1FDF, 0 },
189 /* 1F08 */ { 0x0391, 0x1FBF, 0 },
190 /* 1F09 */ { 0x0391, 0x1FFE, 0 },
191 /* 1F0A */ { 0x0391, 0x1FCD, 0 },
192 /* 1F0B */ { 0x0391, 0x1FDD, 0 },
193 /* 1F0C */ { 0x0391, 0x1FCE, 0 },
194 /* 1F0D */ { 0x0391, 0x1FDE, 0 },
195 /* 1F0E */ { 0x0391, 0x1FCF, 0 },
196 /* 1F0F */ { 0x0391, 0x1FDF, 0 },
197 /* 1F10 */ { 0x03B5, 0x1FBF, 0 },
198 /* 1F11 */ { 0x03B5, 0x1FFE, 0 },
199 /* 1F12 */ { 0x03B5, 0x1FCD, 0 },
200 /* 1F13 */ { 0x03B5, 0x1FDD, 0 },
201 /* 1F14 */ { 0x03B5, 0x1FCE, 0 },
202 /* 1F15 */ { 0x03B5, 0x1FDE, 0 },
203 /* 1F16 */ { 0 },
204 /* 1F17 */ { 0 },
205 /* 1F18 */ { 0x0395, 0x1FBF, 0 },
206 /* 1F19 */ { 0x0395, 0x1FFE, 0 },
207 /* 1F1A */ { 0x0395, 0x1FCD, 0 },
208 /* 1F1B */ { 0x0395, 0x1FDD, 0 },
209 /* 1F1C */ { 0x0395, 0x1FCE, 0 },
210 /* 1F1D */ { 0x0395, 0x1FDE, 0 },
211 /* 1F1E */ { 0 },
212 /* 1F1F */ { 0 },
213 /* 1F20 */ { 0x03B7, 0x1FBF, 0 },
214 /* 1F21 */ { 0x03B7, 0x1FFE, 0 },
215 /* 1F22 */ { 0x03B7, 0x1FCD, 0 },
216 /* 1F23 */ { 0x03B7, 0x1FDD, 0 },
217 /* 1F24 */ { 0x03B7, 0x1FCE, 0 },
218 /* 1F25 */ { 0x03B7, 0x1FDE, 0 },
219 /* 1F26 */ { 0x03B7, 0x1FCF, 0 },
220 /* 1F27 */ { 0x03B7, 0x1FDF, 0 },
221 /* 1F28 */ { 0x0397, 0x1FBF, 0 },
222 /* 1F29 */ { 0x0397, 0x1FFE, 0 },
223 /* 1F2A */ { 0x0397, 0x1FCD, 0 },
224 /* 1F2B */ { 0x0397, 0x1FDD, 0 },
225 /* 1F2C */ { 0x0397, 0x1FCE, 0 },
226 /* 1F2D */ { 0x0397, 0x1FDE, 0 },
227 /* 1F2E */ { 0x0397, 0x1FCF, 0 },
228 /* 1F2F */ { 0x0397, 0x1FDF, 0 },
229 /* 1F30 */ { 0x03B9, 0x1FBF, 0 },
230 /* 1F31 */ { 0x03B9, 0x1FFE, 0 },
231 /* 1F32 */ { 0x03B9, 0x1FCD, 0 },
232 /* 1F33 */ { 0x03B9, 0x1FDD, 0 },
233 /* 1F34 */ { 0x03B9, 0x1FCE, 0 },
234 /* 1F35 */ { 0x03B9, 0x1FDE, 0 },
235 /* 1F36 */ { 0x03B9, 0x1FCF, 0 },
236 /* 1F37 */ { 0x03B9, 0x1FDF, 0 },
237 /* 1F38 */ { 0x0399, 0x1FBF, 0 },
238 /* 1F39 */ { 0x0399, 0x1FFE, 0 },
239 /* 1F3A */ { 0x0399, 0x1FCD, 0 },
240 /* 1F3B */ { 0x0399, 0x1FDD, 0 },
241 /* 1F3C */ { 0x0399, 0x1FCE, 0 },
242 /* 1F3D */ { 0x0399, 0x1FDE, 0 },
243 /* 1F3E */ { 0x0399, 0x1FCF, 0 },
244 /* 1F3F */ { 0x0399, 0x1FDF, 0 },
245 /* 1F40 */ { 0x03BF, 0x1FBF, 0 },
246 /* 1F41 */ { 0x03BF, 0x1FFE, 0 },
247 /* 1F42 */ { 0x03BF, 0x1FCD, 0 },
248 /* 1F43 */ { 0x03BF, 0x1FDD, 0 },
249 /* 1F44 */ { 0x03BF, 0x1FCE, 0 },
250 /* 1F45 */ { 0x03BF, 0x1FDE, 0 },
251 /* 1F46 */ { 0 },
252 /* 1F47 */ { 0 },
253 /* 1F48 */ { 0x039F, 0x1FBF, 0 },
254 /* 1F49 */ { 0x039F, 0x1FFE, 0 },
255 /* 1F4A */ { 0x039F, 0x1FCD, 0 },
256 /* 1F4B */ { 0x039F, 0x1FDD, 0 },
257 /* 1F4C */ { 0x039F, 0x1FCE, 0 },
258 /* 1F4D */ { 0x039F, 0x1FDE, 0 },
259 /* 1F4E */ { 0 },
260 /* 1F4F */ { 0 },
261 /* 1F50 */ { 0x03C5, 0x1FBF, 0 },
262 /* 1F51 */ { 0x03C5, 0x1FFE, 0 },
263 /* 1F52 */ { 0x03C5, 0x1FCD, 0 },
264 /* 1F53 */ { 0x03C5, 0x1FDD, 0 },
265 /* 1F54 */ { 0x03C5, 0x1FCE, 0 },
266 /* 1F55 */ { 0x03C5, 0x1FDE, 0 },
267 /* 1F56 */ { 0x03C5, 0x1FCF, 0 },
268 /* 1F57 */ { 0x03C5, 0x1FDF, 0 },
269 /* 1F58 */ { 0 },
270 /* 1F59 */ { 0x03a5, 0x1FFE, 0 },
271 /* 1F5A */ { 0 },
272 /* 1F5B */ { 0x03a5, 0x1FDD, 0 },
273 /* 1F5C */ { 0 },
274 /* 1F5D */ { 0x03a5, 0x1FDE, 0 },
275 /* 1F5E */ { 0 },
276 /* 1F5F */ { 0x03a5, 0x1FDF, 0 },
277 /* 1F60 */ { 0x03C9, 0x1FBF, 0 },
278 /* 1F61 */ { 0x03C9, 0x1FFE, 0 },
279 /* 1F62 */ { 0x03C9, 0x1FCD, 0 },
280 /* 1F63 */ { 0x03C9, 0x1FDD, 0 },
281 /* 1F64 */ { 0x03C9, 0x1FCE, 0 },
282 /* 1F65 */ { 0x03C9, 0x1FDE, 0 },
283 /* 1F66 */ { 0x03C9, 0x1FCF, 0 },
284 /* 1F67 */ { 0x03C9, 0x1FDF, 0 },
285 /* 1F68 */ { 0x03A9, 0x1FBF, 0 },
286 /* 1F69 */ { 0x03A9, 0x1FFE, 0 },
287 /* 1F6A */ { 0x03A9, 0x1FCD, 0 },
288 /* 1F6B */ { 0x03A9, 0x1FDD, 0 },
289 /* 1F6C */ { 0x03A9, 0x1FCE, 0 },
290 /* 1F6D */ { 0x03A9, 0x1FDE, 0 },
291 /* 1F6E */ { 0x03A9, 0x1FCF, 0 },
292 /* 1F6F */ { 0x03A9, 0x1FDF, 0 },
293 /* 1F70 */ { 0x03B1, 0x1FEF, 0 },
294 /* 1F71 */ { 0x03B1, 0x1FFD, 0 },
295 /* 1F72 */ { 0x03B5, 0x1FEF, 0 },
296 /* 1F73 */ { 0x03B5, 0x1FFD, 0 },
297 /* 1F74 */ { 0x03B7, 0x1FEF, 0 },
298 /* 1F75 */ { 0x03B7, 0x1FFD, 0 },
299 /* 1F76 */ { 0x03B9, 0x1FEF, 0 },
300 /* 1F77 */ { 0x03B9, 0x1FFD, 0 },
301 /* 1F78 */ { 0x03BF, 0x1FEF, 0 },
302 /* 1F79 */ { 0x03BF, 0x1FFD, 0 },
303 /* 1F7A */ { 0x03C5, 0x1FEF, 0 },
304 /* 1F7B */ { 0x03C5, 0x1FFD, 0 },
305 /* 1F7C */ { 0x03C9, 0x1FEF, 0 },
306 /* 1F7D */ { 0x03C9, 0x1FFD, 0 },
307 /* 1F7E */ { 0 },
308 /* 1F7F */ { 0 },
309 /* 1F80 */ { 0x1F00, 0x0345, 0 },
310 /* 1F81 */ { 0x1F01, 0x0345, 0 },
311 /* 1F82 */ { 0x1F02, 0x0345, 0 },
312 /* 1F83 */ { 0x1F03, 0x0345, 0 },
313 /* 1F84 */ { 0x1F04, 0x0345, 0 },
314 /* 1F85 */ { 0x1F05, 0x0345, 0 },
315 /* 1F86 */ { 0x1F06, 0x0345, 0 },
316 /* 1F87 */ { 0x1F07, 0x0345, 0 },
317 /* 1F88 */ { 0x1F08, 0x1FBE, 0 },
318 /* 1F89 */ { 0x1F09, 0x1FBE, 0 },
319 /* 1F8A */ { 0x1F0A, 0x1FBE, 0 },
320 /* 1F8B */ { 0x1F0B, 0x1FBE, 0 },
321 /* 1F8C */ { 0x1F0C, 0x1FBE, 0 },
322 /* 1F8D */ { 0x1F0D, 0x1FBE, 0 },
323 /* 1F8E */ { 0x1F0E, 0x1FBE, 0 },
324 /* 1F8F */ { 0x1F0F, 0x1FBE, 0 },
325 /* 1F90 */ { 0x1F20, 0x0345, 0 },
326 /* 1F91 */ { 0x1F21, 0x0345, 0 },
327 /* 1F92 */ { 0x1F22, 0x0345, 0 },
328 /* 1F93 */ { 0x1F23, 0x0345, 0 },
329 /* 1F94 */ { 0x1F24, 0x0345, 0 },
330 /* 1F95 */ { 0x1F25, 0x0345, 0 },
331 /* 1F96 */ { 0x1F26, 0x0345, 0 },
332 /* 1F97 */ { 0x1F27, 0x0345, 0 },
333 /* 1F98 */ { 0x1F28, 0x1FBE, 0 },
334 /* 1F99 */ { 0x1F29, 0x1FBE, 0 },
335 /* 1F9A */ { 0x1F2A, 0x1FBE, 0 },
336 /* 1F9B */ { 0x1F2B, 0x1FBE, 0 },
337 /* 1F9C */ { 0x1F2C, 0x1FBE, 0 },
338 /* 1F9D */ { 0x1F2D, 0x1FBE, 0 },
339 /* 1F9E */ { 0x1F2E, 0x1FBE, 0 },
340 /* 1F9F */ { 0x1F2F, 0x1FBE, 0 },
341 /* 1FA0 */ { 0x1F60, 0x0345, 0 },
342 /* 1FA1 */ { 0x1F61, 0x0345, 0 },
343 /* 1FA2 */ { 0x1F62, 0x0345, 0 },
344 /* 1FA3 */ { 0x1F63, 0x0345, 0 },
345 /* 1FA4 */ { 0x1F64, 0x0345, 0 },
346 /* 1FA5 */ { 0x1F65, 0x0345, 0 },
347 /* 1FA6 */ { 0x1F66, 0x0345, 0 },
348 /* 1FA7 */ { 0x1F67, 0x0345, 0 },
349 /* 1FA8 */ { 0x1F68, 0x1FBE, 0 },
350 /* 1FA9 */ { 0x1F69, 0x1FBE, 0 },
351 /* 1FAA */ { 0x1F6A, 0x1FBE, 0 },
352 /* 1FAB */ { 0x1F6B, 0x1FBE, 0 },
353 /* 1FAC */ { 0x1F6C, 0x1FBE, 0 },
354 /* 1FAD */ { 0x1F6D, 0x1FBE, 0 },
355 /* 1FAE */ { 0x1F6E, 0x1FBE, 0 },
356 /* 1FAF */ { 0x1F6F, 0x1FBE, 0 },
357 /* 1FB0 */ { 0x03B1, 0x0306, 0 },
358 /* 1FB1 */ { 0x03B1, 0x0304, 0 },
359 /* 1FB2 */ { 0x1F70, 0x0345, 0 },
360 /* 1FB3 */ { 0x03B1, 0x0345, 0 },
361 /* 1FB4 */ { 0x1f71, 0x0345, 0 },
362 /* 1FB5 */ { 0 },
363 /* 1FB6 */ { 0x03B1, 0x1FC0, 0 },
364 /* 1FB7 */ { 0x1FB6, 0x0345, 0 },
365 /* 1FB8 */ { 0x0391, 0x0306, 0 },
366 /* 1FB9 */ { 0x0391, 0x0304, 0 },
367 /* 1FBA */ { 0x0391, 0x1FEF, 0 },
368 /* 1FBB */ { 0x0391, 0x1FFD, 0 },
369 /* 1FBC */ { 0x0391, 0x1FBE, 0 },
370 /* 1FBD */ { 0x0020, 0x0313, 0 },
371 /* 1FBE */ { 0x0020, 0x0345, 0 },
372 /* 1FBF */ { 0x0020, 0x0313, 0 },
373 /* 1FC0 */ { 0x0020, 0x0342, 0 },
374 /* 1FC1 */ { 0x00A8, 0x1FC0, 0 },
375 /* 1FC2 */ { 0x1F74, 0x0345, 0 },
376 /* 1FC3 */ { 0x03B7, 0x0345, 0 },
377 /* 1FC4 */ { 0x1f75, 0x0345, 0 },
378 /* 1FC5 */ { 0 },
379 /* 1FC6 */ { 0x03B7, 0x1FC0, 0 },
380 /* 1FC7 */ { 0x1FC6, 0x0345, 0 },
381 /* 1FC8 */ { 0x0395, 0x1FEF, 0 },
382 /* 1FC9 */ { 0x0395, 0x1FFD, 0 },
383 /* 1FCA */ { 0x0397, 0x1FEF, 0 },
384 /* 1FCB */ { 0x0397, 0x1FFD, 0 },
385 /* 1FCC */ { 0x0397, 0x1FBE, 0 },
386 /* 1FCD */ { 0x1FBF, 0x1FEF, 0 },
387 /* 1FCE */ { 0x1FBF, 0x1FFD, 0 },
388 /* 1FCF */ { 0x1FBF, 0x1FC0, 0 },
389 /* 1FD0 */ { 0x03B9, 0x0306, 0 },
390 /* 1FD1 */ { 0x03B9, 0x0304, 0 },
391 /* 1FD2 */ { 0x03B9, 0x1FED, 0 },
392 /* 1FD3 */ { 0x03B9, 0x1FEE, 0 },
393 /* 1FD4 */ { 0 },
394 /* 1FD5 */ { 0 },
395 /* 1FD6 */ { 0x03B9, 0x1FC0, 0 },
396 /* 1FD7 */ { 0x03B9, 0x1FC1, 0 },
397 /* 1FD8 */ { 0x0399, 0x0306, 0 },
398 /* 1FD9 */ { 0x0399, 0x0304, 0 },
399 /* 1FDA */ { 0x0399, 0x1FEF, 0 },
400 /* 1FDB */ { 0x0399, 0x1FFD, 0 },
401 /* 1FDC */ { 0 },
402 /* 1FDD */ { 0x1FFE, 0x1FEF, 0 },
403 /* 1FDE */ { 0x1FFE, 0x1FFD, 0 },
404 /* 1FDF */ { 0x1FFE, 0x1FC0, 0 },
405 /* 1FE0 */ { 0x03C5, 0x0306, 0 },
406 /* 1FE1 */ { 0x03C5, 0x0304, 0 },
407 /* 1FE2 */ { 0x03C5, 0x1FED, 0 },
408 /* 1FE3 */ { 0x03C5, 0x1FEE, 0 },
409 /* 1FE4 */ { 0x03C1, 0x1FBF, 0 },
410 /* 1FE5 */ { 0x03C1, 0x1FFE, 0 },
411 /* 1FE6 */ { 0x03C5, 0x1FC0, 0 },
412 /* 1FE7 */ { 0x03C5, 0x1FC1, 0 },
413 /* 1FE8 */ { 0x03A5, 0x0306, 0 },
414 /* 1FE9 */ { 0x03A5, 0x0304, 0 },
415 /* 1FEA */ { 0x03A5, 0x1FEF, 0 },
416 /* 1FEB */ { 0x03A5, 0x1FFD, 0 },
417 /* 1FEC */ { 0x03A1, 0x1FFE, 0 },
418 /* 1FED */ { 0x00A8, 0x1FEF, 0 },
419 /* 1FEE */ { 0x0385, 0 },
420 /* 1FEF */ { 0x0060, 0 },
421 /* 1FF0 */ { 0 },
422 /* 1FF1 */ { 0 },
423 /* 1FF2 */ { 0x1F7C, 0x0345, 0 },
424 /* 1FF3 */ { 0x03C9, 0x0345, 0 },
425 /* 1FF4 */ { 0x03CE, 0x0345, 0 },
426 /* 1FF5 */ { 0 },
427 /* 1FF6 */ { 0x03C9, 0x1FC0, 0 },
428 /* 1FF7 */ { 0x1FF6, 0x0345, 0 },
429 /* 1FF8 */ { 0x039F, 0x1FEF, 0 },
430 /* 1FF9 */ { 0x039F, 0x1FFD, 0 },
431 /* 1FFA */ { 0x03A9, 0x1FEF, 0 },
432 /* 1FFB */ { 0x03A9, 0x1FFD, 0 },
433 /* 1FFC */ { 0x03A9, 0x1FBE, 0 },
434 /* 1FFD */ { 0x00B4, 0 },
435 /* 1FFE */ { 0x0020, 0x0314, 0 },
436 /* 1FFF */ { 0 },
437 };
438 
439 unichar_t adobes_pua_alts[0x200][3] = {	/* Mapped from 0xf600-0xf7ff */
440 /* U+F600 */ { 0 },
441 /* U+F601 */ { 0 },
442 /* U+F602 */ { 0 },
443 /* U+F603 */ { 0 },
444 /* U+F604 */ { 0 },
445 /* U+F605 */ { 0 },
446 /* U+F606 */ { 0 },
447 /* U+F607 */ { 0 },
448 /* U+F608 */ { 0 },
449 /* U+F609 */ { 0 },
450 /* U+F60A */ { 0 },
451 /* U+F60B */ { 0 },
452 /* U+F60C */ { 0 },
453 /* U+F60D */ { 0 },
454 /* U+F60E */ { 0 },
455 /* U+F60F */ { 0 },
456 /* U+F610 */ { 0 },
457 /* U+F611 */ { 0 },
458 /* U+F612 */ { 0 },
459 /* U+F613 */ { 0 },
460 /* U+F614 */ { 0 },
461 /* U+F615 */ { 0 },
462 /* U+F616 */ { 0 },
463 /* U+F617 */ { 0 },
464 /* U+F618 */ { 0 },
465 /* U+F619 */ { 0 },
466 /* U+F61A */ { 0 },
467 /* U+F61B */ { 0 },
468 /* U+F61C */ { 0 },
469 /* U+F61D */ { 0 },
470 /* U+F61E */ { 0 },
471 /* U+F61F */ { 0 },
472 /* U+F620 */ { 0 },
473 /* U+F621 */ { 0 },
474 /* U+F622 */ { 0 },
475 /* U+F623 */ { 0 },
476 /* U+F624 */ { 0 },
477 /* U+F625 */ { 0 },
478 /* U+F626 */ { 0 },
479 /* U+F627 */ { 0 },
480 /* U+F628 */ { 0 },
481 /* U+F629 */ { 0 },
482 /* U+F62A */ { 0 },
483 /* U+F62B */ { 0 },
484 /* U+F62C */ { 0 },
485 /* U+F62D */ { 0 },
486 /* U+F62E */ { 0 },
487 /* U+F62F */ { 0 },
488 /* U+F630 */ { 0 },
489 /* U+F631 */ { 0 },
490 /* U+F632 */ { 0 },
491 /* U+F633 */ { 0 },
492 /* U+F634 */ { 0x0020, 0x0326, 0 },
493 /* U+F635 */ { 0x0020, 0x0326, 0 },
494 /* U+F636 */ { 0x03d6, 0x0000, 0 },
495 /* U+F637 */ { 0x0068, 0x0000, 0 },
496 /* U+F638 */ { 0x0030, 0x0000, 0 },
497 /* U+F639 */ { 0x0030, 0x0000, 0 },
498 /* U+F63A */ { 0x0032, 0x0000, 0 },
499 /* U+F63B */ { 0x0033, 0x0000, 0 },
500 /* U+F63C */ { 0x0034, 0x0000, 0 },
501 /* U+F63D */ { 0x0035, 0x0000, 0 },
502 /* U+F63E */ { 0x0036, 0x0000, 0 },
503 /* U+F63F */ { 0x0037, 0x0000, 0 },
504 /* U+F640 */ { 0x0038, 0x0000, 0 },
505 /* U+F641 */ { 0x0039, 0x0000, 0 },
506 /* U+F642 */ { 0x0025, 0x0000, 0 },
507 /* U+F643 */ { 0x0030, 0x0000, 0 },
508 /* U+F644 */ { 0x0031, 0x0000, 0 },
509 /* U+F645 */ { 0x0032, 0x0000, 0 },
510 /* U+F646 */ { 0x0033, 0x0000, 0 },
511 /* U+F647 */ { 0x0034, 0x0000, 0 },
512 /* U+F648 */ { 0x0035, 0x0000, 0 },
513 /* U+F649 */ { 0x0036, 0x0000, 0 },
514 /* U+F64A */ { 0x0037, 0x0000, 0 },
515 /* U+F64B */ { 0x0038, 0x0000, 0 },
516 /* U+F64C */ { 0x0039, 0x0000, 0 },
517 /* U+F64D */ { 0x20a1, 0x0000, 0 },
518 /* U+F64E */ { 0x20ac, 0x0000, 0 },
519 /* U+F64F */ { 0x0192, 0x0000, 0 },
520 /* U+F650 */ { 0x0023, 0x0000, 0 },
521 /* U+F651 */ { 0x00a3, 0x0000, 0 },
522 /* U+F652 */ { 0x00a5, 0x0000, 0 },
523 /* U+F653 */ { 0x0024, 0x0000, 0 },
524 /* U+F654 */ { 0x00a2, 0x0000, 0 },
525 /* U+F655 */ { 0x0030, 0x0000, 0 },
526 /* U+F656 */ { 0x0031, 0x0000, 0 },
527 /* U+F657 */ { 0x0032, 0x0000, 0 },
528 /* U+F658 */ { 0x0033, 0x0000, 0 },
529 /* U+F659 */ { 0x0034, 0x0000, 0 },
530 /* U+F65A */ { 0x0035, 0x0000, 0 },
531 /* U+F65B */ { 0x0036, 0x0000, 0 },
532 /* U+F65C */ { 0x0037, 0x0000, 0 },
533 /* U+F65D */ { 0x0038, 0x0000, 0 },
534 /* U+F65E */ { 0x0039, 0x0000, 0 },
535 /* U+F65F */ { 0x002c, 0x0000, 0 },
536 /* U+F660 */ { 0x002e, 0x0000, 0 },
537 /* U+F661 */ { 0x0030, 0x0000, 0 },
538 /* U+F662 */ { 0x0031, 0x0000, 0 },
539 /* U+F663 */ { 0x0032, 0x0000, 0 },
540 /* U+F664 */ { 0x0033, 0x0000, 0 },
541 /* U+F665 */ { 0x0034, 0x0000, 0 },
542 /* U+F666 */ { 0x0035, 0x0000, 0 },
543 /* U+F667 */ { 0x0036, 0x0000, 0 },
544 /* U+F668 */ { 0x0037, 0x0000, 0 },
545 /* U+F669 */ { 0x0038, 0x0000, 0 },
546 /* U+F66A */ { 0x0039, 0x0000, 0 },
547 /* U+F66B */ { 0x002c, 0x0000, 0 },
548 /* U+F66C */ { 0x002e, 0x0000, 0 },
549 /* U+F66D */ { 0xf761, 0x0306, 0 },
550 /* U+F66E */ { 0xf761, 0x0304, 0 },
551 /* U+F66F */ { 0xf761, 0x0328, 0 },
552 /* U+F670 */ { 0xf7e6, 0x0301, 0 },
553 /* U+F671 */ { 0xf763, 0x0301, 0 },
554 /* U+F672 */ { 0xf763, 0x030c, 0 },
555 /* U+F673 */ { 0xf763, 0x0302, 0 },
556 /* U+F674 */ { 0xf763, 0x0307, 0 },
557 /* U+F675 */ { 0xf764, 0x030c, 0 },
558 /* U+F676 */ { 0x0111, 0x0000, 0 },
559 /* U+F677 */ { 0xf765, 0x0306, 0 },
560 /* U+F678 */ { 0xf765, 0x030c, 0 },
561 /* U+F679 */ { 0xf765, 0x0307, 0 },
562 /* U+F67A */ { 0xf765, 0x0304, 0 },
563 /* U+F67B */ { 0x014b, 0x0000, 0 },
564 /* U+F67C */ { 0xf765, 0x0328, 0 },
565 /* U+F67D */ { 0xf767, 0x0306, 0 },
566 /* U+F67E */ { 0xf767, 0x0302, 0 },
567 /* U+F67F */ { 0xf767, 0x0326, 0 },
568 /* U+F680 */ { 0xf767, 0x0307, 0 },
569 /* U+F681 */ { 0x0127, 0x0000, 0 },
570 /* U+F682 */ { 0xf768, 0x0302, 0 },
571 /* U+F683 */ { 0xf769, 0x0306, 0 },
572 /* U+F684 */ { 0xf769, 0xf76a, 0 },
573 /* U+F685 */ { 0xf769, 0x0304, 0 },
574 /* U+F686 */ { 0xf769, 0x0328, 0 },
575 /* U+F687 */ { 0xf769, 0x0303, 0 },
576 /* U+F688 */ { 0xf76a, 0x0302, 0 },
577 /* U+F689 */ { 0xf76b, 0x0326, 0 },
578 /* U+F68A */ { 0xf76c, 0x0301, 0 },
579 /* U+F68B */ { 0xf76c, 0x030c, 0 },
580 /* U+F68C */ { 0xf76c, 0x0326, 0 },
581 /* U+F68D */ { 0xf76c, 0x00b7, 0 },
582 /* U+F68E */ { 0xf76e, 0x0301, 0 },
583 /* U+F68F */ { 0xf76e, 0x030c, 0 },
584 /* U+F690 */ { 0xf76e, 0x0326, 0 },
585 /* U+F691 */ { 0xf76f, 0x0306, 0 },
586 /* U+F692 */ { 0xf76f, 0x030b, 0 },
587 /* U+F693 */ { 0xf76f, 0x0304, 0 },
588 /* U+F694 */ { 0xf7f8, 0x0301, 0 },
589 /* U+F695 */ { 0xf772, 0x0301, 0 },
590 /* U+F696 */ { 0xf772, 0x030c, 0 },
591 /* U+F697 */ { 0xf772, 0x0326, 0 },
592 /* U+F698 */ { 0xf773, 0x0301, 0 },
593 /* U+F699 */ { 0xf773, 0x0327, 0 },
594 /* U+F69A */ { 0xf773, 0x0302, 0 },
595 /* U+F69B */ { 0xf773, 0x0326, 0 },
596 /* U+F69C */ { 0x0167, 0x0000, 0 },
597 /* U+F69D */ { 0xf774, 0x030c, 0 },
598 /* U+F69E */ { 0xf774, 0x0326, 0 },
599 /* U+F69F */ { 0xf775, 0x0306, 0 },
600 /* U+F6A0 */ { 0xf775, 0x030b, 0 },
601 /* U+F6A1 */ { 0xf775, 0x0304, 0 },
602 /* U+F6A2 */ { 0xf775, 0x0328, 0 },
603 /* U+F6A3 */ { 0xf775, 0x030a, 0 },
604 /* U+F6A4 */ { 0xf775, 0x0303, 0 },
605 /* U+F6A5 */ { 0xf777, 0x0301, 0 },
606 /* U+F6A6 */ { 0xf777, 0x0302, 0 },
607 /* U+F6A7 */ { 0xf777, 0x0308, 0 },
608 /* U+F6A8 */ { 0xf777, 0x0300, 0 },
609 /* U+F6A9 */ { 0xf779, 0x0302, 0 },
610 /* U+F6AA */ { 0xf779, 0x0300, 0 },
611 /* U+F6AB */ { 0xf77a, 0x0301, 0 },
612 /* U+F6AC */ { 0xf77a, 0x0307, 0 },
613 /* U+F6AD */ { 0xf769, 0x0307, 0 },
614 /* U+F6AE */ { 0x0028, 0x0000, 0 },
615 /* U+F6AF */ { 0x0029, 0x0000, 0 },
616 /* U+F6B0 */ { 0x005b, 0x0000, 0 },
617 /* U+F6B1 */ { 0x005d, 0x0000, 0 },
618 /* U+F6B2 */ { 0x007b, 0x0000, 0 },
619 /* U+F6B3 */ { 0x007d, 0x0000, 0 },
620 /* U+F6B4 */ { 0x00a1, 0x0000, 0 },
621 /* U+F6B5 */ { 0x00bf, 0x0000, 0 },
622 /* U+F6B6 */ { 0x00ab, 0x0000, 0 },
623 /* U+F6B7 */ { 0x00bb, 0x0000, 0 },
624 /* U+F6B8 */ { 0x2039, 0x0000, 0 },
625 /* U+F6B9 */ { 0x203a, 0x0000, 0 },
626 /* U+F6BA */ { 0x002d, 0x0000, 0 },
627 /* U+F6BB */ { 0x2013, 0x0000, 0 },
628 /* U+F6BC */ { 0x2014, 0x0000, 0 },
629 /* U+F6BD */ { 0x00b7, 0x0000, 0 },
630 /* U+F6BE */ { 0x006a, 0x0000, 0 },
631 /* U+F6BF */ { 0x004c, 0x004c, 0 },
632 /* U+F6C0 */ { 0x006c, 0x006c, 0 },
633 /* U+F6C1 */ { 0x0053, 0x0327, 0 },
634 /* U+F6C2 */ { 0x0073, 0x0327, 0 },
635 /* U+F6C3 */ { 0x0313, 0x0326, 0 },
636 /* U+F6C4 */ { 0x0433, 0x0000, 0 },
637 /* U+F6C5 */ { 0x0431, 0x0000, 0 },
638 /* U+F6C6 */ { 0x0434, 0x0000, 0 },
639 /* U+F6C7 */ { 0x043f, 0x0000, 0 },
640 /* U+F6C8 */ { 0x0442, 0x0000, 0 },
641 /* U+F6C9 */ { 0x02ca, 0x0000, 0 },
642 /* U+F6CA */ { 0x02c7, 0x0000, 0 },
643 /* U+F6CB */ { 0x00a8, 0x0000, 0 },
644 /* U+F6CC */ { 0x00a8, 0x02ca, 0 },
645 /* U+F6CD */ { 0x00a8, 0x02cb, 0 },
646 /* U+F6CE */ { 0x02cb, 0x0000, 0 },
647 /* U+F6CF */ { 0x02dd, 0x0000, 0 },
648 /* U+F6D0 */ { 0x02c9, 0x0000, 0 },
649 /* U+F6D1 */ { 0x02d8, 0x0000, 0 },
650 /* U+F6D2 */ { 0x02c6, 0x0000, 0 },
651 /* U+F6D3 */ { 0x030f, 0x030f, 0 },
652 /* U+F6D4 */ { 0x02d8, 0x0000, 0 },
653 /* U+F6D5 */ { 0x02c6, 0x0000, 0 },
654 /* U+F6D6 */ { 0x030f, 0x030f, 0 },
655 /* U+F6D7 */ { 0x00a8, 0x02ca, 0 },
656 /* U+F6D8 */ { 0x00a8, 0x02cb, 0 },
657 /* U+F6D9 */ { 0x00a9, 0x0000, 0 },
658 /* U+F6DA */ { 0x00ae, 0x0000, 0 },
659 /* U+F6DB */ { 0x2122, 0x0000, 0 },
660 /* U+F6DC */ { 0x0031, 0x0000, 0 },
661 /* U+F6DD */ { 0x0052, 0x0070, 0 },
662 /* U+F6DE */ { 0x002d, 0x0000, 0 },
663 /* U+F6DF */ { 0x00a2, 0x0000, 0 },
664 /* U+F6E0 */ { 0x00a2, 0x0000, 0 },
665 /* U+F6E1 */ { 0x002c, 0x0000, 0 },
666 /* U+F6E2 */ { 0x002c, 0x0000, 0 },
667 /* U+F6E3 */ { 0x0024, 0x0000, 0 },
668 /* U+F6E4 */ { 0x0024, 0x0000, 0 },
669 /* U+F6E5 */ { 0x002d, 0x0000, 0 },
670 /* U+F6E6 */ { 0x002d, 0x0000, 0 },
671 /* U+F6E7 */ { 0x002e, 0x0000, 0 },
672 /* U+F6E8 */ { 0x002e, 0x0000, 0 },
673 /* U+F6E9 */ { 0x0061, 0x0000, 0 },
674 /* U+F6EA */ { 0x0062, 0x0000, 0 },
675 /* U+F6EB */ { 0x0064, 0x0000, 0 },
676 /* U+F6EC */ { 0x0065, 0x0000, 0 },
677 /* U+F6ED */ { 0x0069, 0x0000, 0 },
678 /* U+F6EE */ { 0x006c, 0x0000, 0 },
679 /* U+F6EF */ { 0x006d, 0x0000, 0 },
680 /* U+F6F0 */ { 0x006f, 0x0000, 0 },
681 /* U+F6F1 */ { 0x0072, 0x0000, 0 },
682 /* U+F6F2 */ { 0x0073, 0x0000, 0 },
683 /* U+F6F3 */ { 0x0074, 0x0000, 0 },
684 /* U+F6F4 */ { 0x02d8, 0x0000, 0 },
685 /* U+F6F5 */ { 0x02c7, 0x0000, 0 },
686 /* U+F6F6 */ { 0x02c6, 0x0000, 0 },
687 /* U+F6F7 */ { 0x02d9, 0x0000, 0 },
688 /* U+F6F8 */ { 0x02dd, 0x0000, 0 },
689 /* U+F6F9 */ { 0x0142, 0x0000, 0 },
690 /* U+F6FA */ { 0xf76f, 0xf765, 0 },
691 /* U+F6FB */ { 0xf76f, 0x0328, 0 },
692 /* U+F6FC */ { 0xf772, 0x030a, 0 },
693 /* U+F6FD */ { 0xf773, 0x030c, 0 },
694 /* U+F6FE */ { 0xf774, 0x0303, 0 },
695 /* U+F6FF */ { 0xf77a, 0x030c, 0 },
696 /* U+F700 */ { 0 },
697 /* U+F701 */ { 0 },
698 /* U+F702 */ { 0 },
699 /* U+F703 */ { 0 },
700 /* U+F704 */ { 0 },
701 /* U+F705 */ { 0 },
702 /* U+F706 */ { 0 },
703 /* U+F707 */ { 0 },
704 /* U+F708 */ { 0 },
705 /* U+F709 */ { 0 },
706 /* U+F70A */ { 0 },
707 /* U+F70B */ { 0 },
708 /* U+F70C */ { 0 },
709 /* U+F70D */ { 0 },
710 /* U+F70E */ { 0 },
711 /* U+F70F */ { 0 },
712 /* U+F710 */ { 0 },
713 /* U+F711 */ { 0 },
714 /* U+F712 */ { 0 },
715 /* U+F713 */ { 0 },
716 /* U+F714 */ { 0 },
717 /* U+F715 */ { 0 },
718 /* U+F716 */ { 0 },
719 /* U+F717 */ { 0 },
720 /* U+F718 */ { 0 },
721 /* U+F719 */ { 0 },
722 /* U+F71A */ { 0 },
723 /* U+F71B */ { 0 },
724 /* U+F71C */ { 0 },
725 /* U+F71D */ { 0 },
726 /* U+F71E */ { 0 },
727 /* U+F71F */ { 0 },
728 /* U+F720 */ { 0 },
729 /* U+F721 */ { 0x0021, 0x0000, 0 },
730 /* U+F722 */ { 0 },
731 /* U+F723 */ { 0 },
732 /* U+F724 */ { 0x0024, 0x0000, 0 },
733 /* U+F725 */ { 0 },
734 /* U+F726 */ { 0x0026, 0x0000, 0 },
735 /* U+F727 */ { 0 },
736 /* U+F728 */ { 0 },
737 /* U+F729 */ { 0 },
738 /* U+F72A */ { 0 },
739 /* U+F72B */ { 0 },
740 /* U+F72C */ { 0 },
741 /* U+F72D */ { 0 },
742 /* U+F72E */ { 0 },
743 /* U+F72F */ { 0 },
744 /* U+F730 */ { 0x0030, 0x0000, 0 },
745 /* U+F731 */ { 0x0031, 0x0000, 0 },
746 /* U+F732 */ { 0x0032, 0x0000, 0 },
747 /* U+F733 */ { 0x0033, 0x0000, 0 },
748 /* U+F734 */ { 0x0034, 0x0000, 0 },
749 /* U+F735 */ { 0x0035, 0x0000, 0 },
750 /* U+F736 */ { 0x0036, 0x0000, 0 },
751 /* U+F737 */ { 0x0037, 0x0000, 0 },
752 /* U+F738 */ { 0x0038, 0x0000, 0 },
753 /* U+F739 */ { 0x0039, 0x0000, 0 },
754 /* U+F73A */ { 0 },
755 /* U+F73B */ { 0 },
756 /* U+F73C */ { 0 },
757 /* U+F73D */ { 0 },
758 /* U+F73E */ { 0 },
759 /* U+F73F */ { 0x003f, 0x0000, 0 },
760 /* U+F740 */ { 0 },
761 /* U+F741 */ { 0 },
762 /* U+F742 */ { 0 },
763 /* U+F743 */ { 0 },
764 /* U+F744 */ { 0 },
765 /* U+F745 */ { 0 },
766 /* U+F746 */ { 0 },
767 /* U+F747 */ { 0 },
768 /* U+F748 */ { 0 },
769 /* U+F749 */ { 0 },
770 /* U+F74A */ { 0 },
771 /* U+F74B */ { 0 },
772 /* U+F74C */ { 0 },
773 /* U+F74D */ { 0 },
774 /* U+F74E */ { 0 },
775 /* U+F74F */ { 0 },
776 /* U+F750 */ { 0 },
777 /* U+F751 */ { 0 },
778 /* U+F752 */ { 0 },
779 /* U+F753 */ { 0 },
780 /* U+F754 */ { 0 },
781 /* U+F755 */ { 0 },
782 /* U+F756 */ { 0 },
783 /* U+F757 */ { 0 },
784 /* U+F758 */ { 0 },
785 /* U+F759 */ { 0 },
786 /* U+F75A */ { 0 },
787 /* U+F75B */ { 0 },
788 /* U+F75C */ { 0 },
789 /* U+F75D */ { 0 },
790 /* U+F75E */ { 0 },
791 /* U+F75F */ { 0 },
792 /* U+F760 */ { 0x0060, 0x0000, 0 },
793 /* U+F761 */ { 0x0061, 0x0000, 0 },
794 /* U+F762 */ { 0x0062, 0x0000, 0 },
795 /* U+F763 */ { 0x0063, 0x0000, 0 },
796 /* U+F764 */ { 0x0064, 0x0000, 0 },
797 /* U+F765 */ { 0x0065, 0x0000, 0 },
798 /* U+F766 */ { 0x0066, 0x0000, 0 },
799 /* U+F767 */ { 0x0067, 0x0000, 0 },
800 /* U+F768 */ { 0x0068, 0x0000, 0 },
801 /* U+F769 */ { 0x0069, 0x0000, 0 },
802 /* U+F76A */ { 0x006a, 0x0000, 0 },
803 /* U+F76B */ { 0x006b, 0x0000, 0 },
804 /* U+F76C */ { 0x006c, 0x0000, 0 },
805 /* U+F76D */ { 0x006d, 0x0000, 0 },
806 /* U+F76E */ { 0x006e, 0x0000, 0 },
807 /* U+F76F */ { 0x006f, 0x0000, 0 },
808 /* U+F770 */ { 0x0070, 0x0000, 0 },
809 /* U+F771 */ { 0x0071, 0x0000, 0 },
810 /* U+F772 */ { 0x0072, 0x0000, 0 },
811 /* U+F773 */ { 0x0073, 0x0000, 0 },
812 /* U+F774 */ { 0x0074, 0x0000, 0 },
813 /* U+F775 */ { 0x0075, 0x0000, 0 },
814 /* U+F776 */ { 0x0076, 0x0000, 0 },
815 /* U+F777 */ { 0x0077, 0x0000, 0 },
816 /* U+F778 */ { 0x0078, 0x0000, 0 },
817 /* U+F779 */ { 0x0079, 0x0000, 0 },
818 /* U+F77A */ { 0x007a, 0x0000, 0 },
819 /* U+F77B */ { 0 },
820 /* U+F77C */ { 0 },
821 /* U+F77D */ { 0 },
822 /* U+F77E */ { 0 },
823 /* U+F77F */ { 0 },
824 /* U+F780 */ { 0 },
825 /* U+F781 */ { 0 },
826 /* U+F782 */ { 0 },
827 /* U+F783 */ { 0 },
828 /* U+F784 */ { 0 },
829 /* U+F785 */ { 0 },
830 /* U+F786 */ { 0 },
831 /* U+F787 */ { 0 },
832 /* U+F788 */ { 0 },
833 /* U+F789 */ { 0 },
834 /* U+F78A */ { 0 },
835 /* U+F78B */ { 0 },
836 /* U+F78C */ { 0 },
837 /* U+F78D */ { 0 },
838 /* U+F78E */ { 0 },
839 /* U+F78F */ { 0 },
840 /* U+F790 */ { 0 },
841 /* U+F791 */ { 0 },
842 /* U+F792 */ { 0 },
843 /* U+F793 */ { 0 },
844 /* U+F794 */ { 0 },
845 /* U+F795 */ { 0 },
846 /* U+F796 */ { 0 },
847 /* U+F797 */ { 0 },
848 /* U+F798 */ { 0 },
849 /* U+F799 */ { 0 },
850 /* U+F79A */ { 0 },
851 /* U+F79B */ { 0 },
852 /* U+F79C */ { 0 },
853 /* U+F79D */ { 0 },
854 /* U+F79E */ { 0 },
855 /* U+F79F */ { 0 },
856 /* U+F7A0 */ { 0 },
857 /* U+F7A1 */ { 0x00a1, 0x0000, 0 },
858 /* U+F7A2 */ { 0x00a2, 0x0000, 0 },
859 /* U+F7A3 */ { 0 },
860 /* U+F7A4 */ { 0 },
861 /* U+F7A5 */ { 0 },
862 /* U+F7A6 */ { 0 },
863 /* U+F7A7 */ { 0 },
864 /* U+F7A8 */ { 0x00a8, 0x0000, 0 },
865 /* U+F7A9 */ { 0 },
866 /* U+F7AA */ { 0 },
867 /* U+F7AB */ { 0 },
868 /* U+F7AC */ { 0 },
869 /* U+F7AD */ { 0 },
870 /* U+F7AE */ { 0 },
871 /* U+F7AF */ { 0x00af, 0x0000, 0 },
872 /* U+F7B0 */ { 0 },
873 /* U+F7B1 */ { 0 },
874 /* U+F7B2 */ { 0 },
875 /* U+F7B3 */ { 0 },
876 /* U+F7B4 */ { 0x00b4, 0x0000, 0 },
877 /* U+F7B5 */ { 0 },
878 /* U+F7B6 */ { 0 },
879 /* U+F7B7 */ { 0 },
880 /* U+F7B8 */ { 0x00b8, 0x0000, 0 },
881 /* U+F7B9 */ { 0 },
882 /* U+F7BA */ { 0 },
883 /* U+F7BB */ { 0 },
884 /* U+F7BC */ { 0 },
885 /* U+F7BD */ { 0 },
886 /* U+F7BE */ { 0 },
887 /* U+F7BF */ { 0x00bf, 0x0000, 0 },
888 /* U+F7C0 */ { 0 },
889 /* U+F7C1 */ { 0 },
890 /* U+F7C2 */ { 0 },
891 /* U+F7C3 */ { 0 },
892 /* U+F7C4 */ { 0 },
893 /* U+F7C5 */ { 0 },
894 /* U+F7C6 */ { 0 },
895 /* U+F7C7 */ { 0 },
896 /* U+F7C8 */ { 0 },
897 /* U+F7C9 */ { 0 },
898 /* U+F7CA */ { 0 },
899 /* U+F7CB */ { 0 },
900 /* U+F7CC */ { 0 },
901 /* U+F7CD */ { 0 },
902 /* U+F7CE */ { 0 },
903 /* U+F7CF */ { 0 },
904 /* U+F7D0 */ { 0 },
905 /* U+F7D1 */ { 0 },
906 /* U+F7D2 */ { 0 },
907 /* U+F7D3 */ { 0 },
908 /* U+F7D4 */ { 0 },
909 /* U+F7D5 */ { 0 },
910 /* U+F7D6 */ { 0 },
911 /* U+F7D7 */ { 0 },
912 /* U+F7D8 */ { 0 },
913 /* U+F7D9 */ { 0 },
914 /* U+F7DA */ { 0 },
915 /* U+F7DB */ { 0 },
916 /* U+F7DC */ { 0 },
917 /* U+F7DD */ { 0 },
918 /* U+F7DE */ { 0 },
919 /* U+F7DF */ { 0 },
920 /* U+F7E0 */ { 0xf761, 0x0300, 0 },
921 /* U+F7E1 */ { 0xf761, 0x0301, 0 },
922 /* U+F7E2 */ { 0xf761, 0x0302, 0 },
923 /* U+F7E3 */ { 0xf761, 0x0303, 0 },
924 /* U+F7E4 */ { 0xf761, 0x0308, 0 },
925 /* U+F7E5 */ { 0xf761, 0x030a, 0 },
926 /* U+F7E6 */ { 0xf761, 0xf765, 0 },
927 /* U+F7E7 */ { 0xf763, 0x0327, 0 },
928 /* U+F7E8 */ { 0xf765, 0x0300, 0 },
929 /* U+F7E9 */ { 0xf765, 0x0301, 0 },
930 /* U+F7EA */ { 0xf765, 0x0302, 0 },
931 /* U+F7EB */ { 0xf765, 0x0308, 0 },
932 /* U+F7EC */ { 0xf769, 0x0300, 0 },
933 /* U+F7ED */ { 0xf769, 0x0301, 0 },
934 /* U+F7EE */ { 0xf769, 0x0302, 0 },
935 /* U+F7EF */ { 0xf769, 0x0308, 0 },
936 /* U+F7F0 */ { 0x00f0, 0x0000, 0 },
937 /* U+F7F1 */ { 0xf76e, 0x0303, 0 },
938 /* U+F7F2 */ { 0xf76f, 0x0300, 0 },
939 /* U+F7F3 */ { 0xf76f, 0x0301, 0 },
940 /* U+F7F4 */ { 0xf76f, 0x0302, 0 },
941 /* U+F7F5 */ { 0xf76f, 0x0303, 0 },
942 /* U+F7F6 */ { 0xf76f, 0x0308, 0 },
943 /* U+F7F7 */ { 0 },
944 /* U+F7F8 */ { 0x00f8, 0x0000, 0 },
945 /* U+F7F9 */ { 0xf775, 0x0300, 0 },
946 /* U+F7FA */ { 0xf775, 0x0301, 0 },
947 /* U+F7FB */ { 0xf775, 0x0302, 0 },
948 /* U+F7FC */ { 0xf775, 0x0308, 0 },
949 /* U+F7FD */ { 0xf779, 0x0301, 0 },
950 /* U+F7FE */ { 0x00fe, 0x0000, 0 },
951 /* U+F7FF */ { 0xf779, 0x0308, 0 }
952 };
953 
SplineSetQuickTop(SplineSet * ss)954 static real SplineSetQuickTop(SplineSet *ss) {
955     real max = -1e10;
956     SplinePoint *sp;
957 
958     for ( ; ss!=NULL; ss=ss->next ) {
959 	for ( sp=ss->first; ; ) {
960 	    if ( sp->me.y > max ) max = sp->me.y;
961 	    if ( sp->next==NULL )
962 	break;
963 	    sp = sp->next->to;
964 	    if ( sp==ss->first )
965 	break;
966 	}
967     }
968     if ( max<-65536 ) max = 0;	/* return a reasonable value for an empty glyph */
969 return( max );
970 }
971 
SplineCharQuickTop(SplineChar * sc,int layer)972 static real SplineCharQuickTop(SplineChar *sc,int layer) {
973     RefChar *ref;
974     real max, temp;
975 
976     max = SplineSetQuickTop(sc->layers[layer].splines);
977     for ( ref = sc->layers[layer].refs; ref!=NULL; ref = ref->next )
978 	if ( (temp =SplineSetQuickTop(ref->layers[0].splines))>max )
979 	    max = temp;
980 return( max );
981 }
982 
isaccent(int uni)983 int isaccent(int uni) {
984 
985     if ( uni<0x10000 && iscombining(uni) )
986 return( true );
987     if ( uni>=0x2b0 && uni<0x2ff )
988 return( true );
989     if ( uni=='.' || uni==',' || uni==0x60 || uni==0x5e || uni==0x7e ||
990 	    uni==0xa8 || uni==0xaf || uni==0xb8 || uni==0x384 || uni==0x385 ||
991 	    (uni>=0x1fbd && uni<=0x1fc1) ||
992 	    (uni>=0x1fcd && uni<=0x1fcf) ||
993 	    (uni>=0x1fed && uni<=0x1fef) ||
994 	    (uni>=0x1ffd && uni<=0x1fff) )
995 return( true );
996 
997 return( false );
998 }
999 
haschar(SplineFont * sf,unichar_t ch,char * dot)1000 static int haschar(SplineFont *sf,unichar_t ch,char *dot) {
1001     char buffer[200], namebuf[200];
1002 
1003     if ( dot==NULL || ch==-1 )
1004 return( SCWorthOutputting(SFGetChar(sf,ch,NULL)) );
1005     snprintf(buffer,sizeof(buffer),"%s%s",
1006 	    (char *) StdGlyphName(namebuf,ch,sf->uni_interp,sf->for_new_glyphs),
1007 	    dot);
1008     if ( SCWorthOutputting(SFGetChar(sf,-1,buffer)) )
1009 return( true );
1010     else if ( isaccent(ch))
1011 return( SCWorthOutputting(SFGetChar(sf,ch,NULL)) );
1012     else
1013 return( false );
1014 }
1015 
GetChar(SplineFont * sf,unichar_t ch,char * dot)1016 static SplineChar *GetChar(SplineFont *sf,unichar_t ch,char *dot) {
1017     char buffer[200], namebuf[200];
1018     SplineChar *sc;
1019     /* Basically the same as above */
1020 
1021     if ( dot==NULL || ch==-1 )
1022 return( SFGetChar(sf,ch,NULL) );
1023     snprintf(buffer,sizeof(buffer),"%s%s",
1024 	    (char *) StdGlyphName(namebuf,ch,sf->uni_interp,sf->for_new_glyphs),
1025 	    dot);
1026     if ( (sc = SFGetChar(sf,-1,buffer)) )
1027 return( sc );
1028     else if ( isaccent(ch))
1029 return( SFGetChar(sf,ch,NULL) );
1030     else
1031 return( NULL );
1032 }
1033 
arabicfixup(SplineFont * sf,const unichar_t * upt,int ini,int final)1034 static const unichar_t *arabicfixup(SplineFont *sf, const unichar_t *upt, int ini, int final) {
1035     static unichar_t arabicalts[20];
1036     unichar_t *apt; const unichar_t *pt;
1037 
1038     for ( apt=arabicalts, pt = upt; *pt!='\0'; ++pt, ++apt ) {
1039 	if ( *pt==' ' ) {
1040 	    *apt = ' ';
1041 	    ini = true;
1042 	} else if ( *pt<0x600 || *pt>0x6ff )
1043 	    *apt = *pt;
1044 	else if ( ini ) {
1045 	    *apt = ArabicForms[*pt-0x600].initial;
1046 	    ini = false;
1047 	} else if ( pt[1]==' ' || (pt[1]=='\0' && final))
1048 	    *apt = ArabicForms[*pt-0x600].final;
1049 	else
1050 	    *apt = ArabicForms[*pt-0x600].medial;
1051 	if ( !haschar(sf,*apt,NULL))
1052     break;
1053     }
1054     if ( *pt=='\0' ) {
1055 	*apt = '\0';
1056 return(arabicalts);
1057     }
1058 return( upt );
1059 }
1060 
SFAlternateFromLigature(SplineFont * sf,int base,SplineChar * sc)1061 static const unichar_t *SFAlternateFromLigature(SplineFont *sf, int base,SplineChar *sc) {
1062     static unichar_t space[30];
1063     unichar_t *spt, *send = space+sizeof(space)/sizeof(space[0])-1;
1064     char *ligstart, *semi, *pt, sch, ch, *dpt;
1065     int j;
1066     PST *pst;
1067 
1068     if ( sc==NULL && base>=0 )
1069 	sc = SFGetChar(sf,base,NULL);
1070     pst = NULL;
1071     if ( sc!=NULL )
1072 	for ( pst=sc->possub; pst!=NULL && pst->type!=pst_ligature; pst = pst->next );
1073     if ( sc==NULL || pst==NULL )
1074 return( NULL );
1075 
1076     ligstart=pst->u.lig.components;
1077     semi = strchr(ligstart,';');
1078     if ( semi==NULL ) semi = ligstart+strlen(ligstart);
1079     sch = *semi; *semi = '\0';
1080     spt = space;
1081     dpt = NULL;
1082     for ( pt = ligstart; *pt!='\0'; ) {
1083 	char *start = pt; dpt=NULL;
1084 	for ( ; *pt!='\0' && *pt!=' '; ++pt );
1085 	ch = *pt; *pt = '\0';
1086 	for ( j=0; j<sf->glyphcnt; ++j )
1087 	    if ( sf->glyphs[j]!=NULL && strcmp(sf->glyphs[j]->name,start)==0 )
1088 	break;
1089 	*pt = ch;
1090 	if ( j==sf->glyphcnt && (dpt=strchr(start,'.'))!=NULL && dpt<pt ) {
1091 	    int dch = *dpt; *dpt='\0';
1092 	    for ( j=0; j<sf->glyphcnt; ++j )
1093 		if ( sf->glyphs[j]!=NULL && strcmp(sf->glyphs[j]->name,start)==0 )
1094 	    break;
1095 	    *dpt = dch;
1096 	}
1097 	if ( j>=sf->glyphcnt || sf->glyphs[j]->unicodeenc==-1 || spt>=send ) {
1098 	    *semi = sch;
1099 return( NULL );
1100 	}
1101 	*spt++ = sf->glyphs[j]->unicodeenc;
1102 	if ( ch!='\0' ) ++pt;
1103     }
1104     *spt ='\0';
1105     *semi = sch;
1106 
1107     if ( *space>=0x0600 && *space<=0x6ff ) {
1108 	int ini=0, final=0;
1109 	if ( dpt==NULL || strncmp(dpt,".isolated",strlen(".isolated"))==0 )
1110 	    ini=final = true;
1111 	else if ( strncmp(dpt,".initial",strlen(".initial"))==0 )
1112 	    ini=true;
1113 	else if ( strncmp(dpt,".final",strlen(".final"))==0 )
1114 	    final=true;
1115 return( arabicfixup(sf,space,ini,final));
1116     }
1117 
1118 return( space );
1119 }
1120 
SFGetAlternate(SplineFont * sf,int base,SplineChar * sc,int nocheck)1121 const unichar_t *SFGetAlternate(SplineFont *sf, int base,SplineChar *sc,int nocheck) {
1122     static unichar_t greekalts[5];
1123     const unichar_t *upt, *pt; unichar_t *gpt;
1124     char *dot = NULL;
1125 
1126     if ( sc!=NULL ) {
1127         if ( sc->user_decomp != NULL ) return sc->user_decomp;
1128         if ((dot = strchr(sc->name,'.'))!=NULL ) {
1129             /* agrave.sc should be built from a.sc and grave or grave.sc */
1130             char *temp = copyn(sc->name,dot-sc->name);
1131             base = UniFromName(temp,sf->uni_interp,NULL);
1132             free(temp);
1133         }
1134     }
1135 
1136     if ( base>=0xac00 && base<=0xd7a3 ) { /* Hangul syllables */
1137 	greekalts[0] = (base-0xac00)/(21*28) + 0x1100;
1138 	greekalts[1] = ((base-0xac00)/28)%21 + 0x1161;
1139 	if ( (base-0xac00)%28==0 )
1140 	    greekalts[2] = 0;
1141 	else
1142 	    greekalts[2] = (base-0xac00)%28 -1 + 0x11a8;
1143 	greekalts[3] = 0;
1144 return( greekalts );
1145     }
1146     if ( base=='i' || base=='j' ) {
1147 	if ( base=='i' )
1148 	    greekalts[0] = 0x131;
1149 	else if ( haschar(sf,0x237,NULL))
1150 	    greekalts[0] = 0x237;		/* proposed dotlessj */
1151 	else
1152 	    greekalts[0] = 0xf6be;		/* Dotlessj in Adobe's private use area */
1153 	greekalts[1] = 0x307;
1154 	greekalts[2] = 0;
1155 return( greekalts );
1156     }
1157 
1158     if ( sf->uni_interp==ui_adobe && base>=0xf600 && base<=0xf7ff &&
1159 	    adobes_pua_alts[base-0xf600]!=0 )
1160 return( adobes_pua_alts[base-0xf600]);
1161 
1162     if ( base==-1 || base>=65536 || unicode_alternates[base>>8]==NULL ||
1163 	    (upt = unicode_alternates[base>>8][base&0xff])==NULL )
1164 return( SFAlternateFromLigature(sf,base,sc));
1165 
1166 	    /* The definitions of some of the greek letters may make some */
1167 	    /*  linguistic sense, but I can't use it to place the accents */
1168 	    /*  properly. So I redefine them here */
1169     if ( base>=0x1f00 && base<0x2000 ) {
1170 	gpt = unicode_greekalts[base-0x1f00];
1171 	if ( *gpt && (nocheck ||
1172 		(haschar(sf,*gpt,dot) && (gpt[1]=='\0' || haschar(sf,gpt[1],dot))) ))
1173 return( gpt );
1174 	    /* Similarly for these (korean) jamo */
1175     } else if (( base>=0x1176 && base<=0x117e ) || (base>=0x119a && base<=0x119c)) {
1176 	greekalts[0] = upt[1]; greekalts[1] = upt[0]; greekalts[2] = 0;
1177 return( greekalts );
1178     } else if ( base>=0x380 && base<=0x3ff && upt!=NULL ) {
1179 	/* Use precombined accents when possible */
1180 	if ( base==0x390 || base==0x3b0 ) {
1181 	    greekalts[0] = base==0x390?0x3b9:0x3c5;
1182 	    greekalts[1] = 0x385;
1183 	    greekalts[2] = '\0';
1184 	    if ( nocheck || haschar(sf,greekalts[1],dot))
1185 return( greekalts );
1186 	}
1187 	/* In version 3 of unicode tonos gets converted to acute, which it */
1188 	/*  doesn't look like. Convert it back */
1189 	for ( pt=upt ; *pt && *pt!=0x301; ++pt );
1190 	if ( *pt ) {
1191 	    for ( gpt=greekalts ; *upt ; ++upt ) {
1192 		if ( *upt==0x301 )
1193 		    *gpt++ = 0x384 /* I used to use 0x30d, thinking that it was a combining tonos, but greek users tell me it is not */;
1194 		else
1195 		    *gpt++ = *upt;
1196 	    }
1197 return( greekalts );
1198 	}
1199     } else if (( base>=0xfb50 && base<=0xfdff ) || ( base>=0xfe70 && base<0xfeff ))
1200 return( arabicfixup(sf,upt,isarabisolated(base)||isarabinitial(base),
1201 		isarabisolated(base)||isarabfinal(base)));
1202     else if ( base==0x0122 || base==0x0136 || base==0x137 ||
1203 	    base==0x013b || base==0x013c || base==0x0145 ||
1204 	    base==0x0146 || base==0x0156 || base==0x0157 ) {
1205 	/* Unicode says these use cedilla, but it looks like a comma below */
1206 	greekalts[0] = base==0x0122 ? 'G' :
1207 		       base==0x0136 ? 'K' :
1208 		       base==0x0137 ? 'k' :
1209 		       base==0x013b ? 'L' :
1210 		       base==0x013c ? 'l' :
1211 		       base==0x0145 ? 'N' :
1212 		       base==0x0146 ? 'n' :
1213 		       base==0x0156 ? 'R' :
1214 			   'r';
1215 	greekalts[1] = 0x326;
1216 	greekalts[2] = '\0';
1217 return( greekalts );
1218     } else if ( base==0x0123 ) {
1219 	/* Unicode says this uses cedilla, but it looks like a turned comma above */
1220 	greekalts[0] = 'g';
1221 	greekalts[1] = 0x312;
1222 	greekalts[2] = '\0';
1223 return( greekalts );
1224     } else if ( base==0x010f || base==0x013d || base==0x013e || base==0x0165 ) {
1225 	/* Unicode says these use caron, but it looks like comma above right */
1226 	greekalts[0] =  base==0x010f ? 'd' :
1227 			base==0x013d ? 'L' :
1228 			base==0x013e ? 'l' :
1229 			   't';
1230 	greekalts[1] = 0x315;
1231 	greekalts[2] = '\0';
1232 return( greekalts );
1233     }
1234 
1235 return( upt );
1236 }
1237 
1238 static SplineChar *GetGoodAccentGlyph(SplineFont *sf, int uni, int basech,
1239 	int *invert,double ia, char *dot, SplineChar *destination);
1240 
SFIsCompositBuildable(SplineFont * sf,int unicodeenc,SplineChar * sc,int layer)1241 int SFIsCompositBuildable(SplineFont *sf,int unicodeenc,SplineChar *sc,int layer) {
1242     const unichar_t *pt, *all; unichar_t ch, basech;
1243     SplineChar *one, *two;
1244     char *dot = NULL;
1245     int invert = false;
1246 
1247     if ( unicodeenc==0x131 || unicodeenc==0x0237 || unicodeenc==0xf6be )
1248 return( SCMakeDotless(sf,SFGetOrMakeChar(sf,unicodeenc,NULL),layer,NULL,false,false));
1249 
1250     if ( sc!=NULL && (dot = strchr(sc->name,'.'))!=NULL ) {
1251 	/* agrave.sc should be built from a.sc and grave or grave.sc */
1252 	char *temp = copyn(sc->name,dot-sc->name);
1253 	unicodeenc = UniFromName(temp,sf->uni_interp,NULL);
1254 	free(temp);
1255     }
1256 
1257     if (( all = pt = SFGetAlternate(sf,unicodeenc,sc,false))==NULL )
1258 return( false );
1259 
1260     if ( sc!=NULL )
1261 	one = sc;
1262     else
1263 	one=SFGetOrMakeChar(sf,unicodeenc,NULL);
1264 
1265     basech = *pt;
1266     for ( ; *pt; ++pt ) {
1267 	ch = *pt;
1268 	if ( all!=pt && isaccent(ch) ) {	/* first glyph is magic and doesn't go through accent processing */
1269 	    two = GetGoodAccentGlyph(sf,ch,basech,&invert,sf->italicangle,dot,one);
1270 	} else if ( !haschar(sf,ch,dot))
1271 return( false );
1272 	else
1273 	    two = GetChar(sf,ch,dot);
1274 	/* No recursive references */
1275 	/* Cyrillic gamma could refer to Greek gamma, which the entry gives as an alternate */
1276 	if ( one!=NULL && (two==NULL || SCDependsOnSC(two,one)) )
1277 return( false );
1278     }
1279 return( true );
1280 }
1281 
SFIsRotatable(SplineFont * sf,SplineChar * sc)1282 int SFIsRotatable(SplineFont *sf,SplineChar *sc) {
1283     char *end;
1284     int cid;
1285 
1286     if ( sf->cidmaster!=NULL && strncmp(sc->name,"vertcid_",8)==0 ) {
1287 	cid = strtol(sc->name+8,&end,10);
1288 	if ( *end=='\0' && SFHasCID(sf,cid)!=-1)
1289 return( true );
1290     } else if ( sf->cidmaster!=NULL && strstr(sc->name,".vert")!=NULL &&
1291 	    (cid = CIDFromName(sc->name,sf->cidmaster))!= -1 ) {
1292 	if ( SFHasCID(sf,cid)!=-1)
1293 return( true );
1294     } else if ( strncmp(sc->name,"vertuni",7)==0 && strlen(sc->name)==11 ) {
1295 	int uni = strtol(sc->name+7,&end,16);
1296 	if ( *end=='\0' && SFCIDFindExistingChar(sf,uni,NULL)!=-1 )
1297 return( true );
1298     } else if ( strncmp(sc->name,"uni",3)==0 && strstr(sc->name,".vert")!=NULL ) {
1299 	int uni = strtol(sc->name+3,&end,16);
1300 	if ( *end=='.' && SFCIDFindExistingChar(sf,uni,NULL)!=-1 )
1301 return( true );
1302     } else if ( sc->name[0]=='u' && strstr(sc->name,".vert")!=NULL ) {
1303 	int uni = strtol(sc->name+1,&end,16);
1304 	if ( *end=='.' && SFCIDFindExistingChar(sf,uni,NULL)!=-1 )
1305 return( true );
1306     } else if ( strstr(sc->name,".vert")!=NULL || strstr(sc->name,".vrt2")!=NULL) {
1307 	int ret;
1308 	char *temp;
1309 	end = strchr(sc->name,'.');
1310 	temp = copyn(sc->name,end-sc->name);
1311 	ret = SFFindExistingSlot(sf,-1,temp)!=-1;
1312 	free(temp);
1313 return( ret );
1314     }
1315 return( false );
1316 }
1317 
hascomposing(SplineFont * sf,int u,SplineChar * sc)1318 int hascomposing(SplineFont *sf,int u,SplineChar *sc) {
1319     const unichar_t *upt = SFGetAlternate(sf,u,sc,false);
1320 
1321     if ( upt!=NULL ) {
1322 	while ( *upt ) {
1323 	    if ( (u==0x13f || u==0x140 ) && *upt==0xb7 )
1324 return( true );	/* b7, centered dot is used as a combining accent for Ldot */
1325 		/* It's spacing for ldot (but we want to pretend it's an accent) */
1326 		/*  and 0x22EF is a ligature of ... */
1327 	    else if ( iscombining(*upt) ||
1328 		    *upt==0x0384 ||	/* tonos */
1329 		    *upt==0x0385 ||	/* dieresis/tonos */
1330 		    *upt==0x1ffe || *upt==0x1fbf || *upt==0x1fcf || *upt==0x1fdf ||
1331 		    *upt==0x1fbd || *upt==0x1fef || *upt==0x1fc0 || *upt==0x1fc1 ||
1332 		    *upt==0x1fee || *upt==0x1ffd || *upt==0x1fbe || *upt==0x1fed ||
1333 		    *upt==0x1fcd || *upt==0x1fdd || *upt==0x1fce || *upt==0x1fde )	/* Special greek accents */
1334 return( true );
1335 	    /* Only build Jongsung out of chosung when doing a build composit */
1336 	    /*  not when doing a build accented (that's what the upt[1]!='\0' */
1337 	    /*  means */
1338 	    if ( *upt>=0x1100 && *upt<0x11c7 && upt[1]!='\0' )
1339 return( true );
1340 	    ++upt;
1341 	}
1342 
1343 	if ( u>=0x1f70 && u<0x1f80 )
1344 return( true );			/* Yes. they do work, I don't care what it looks like */
1345 	if ( u==0x0149 )
1346 return( true );
1347     }
1348 return( false );
1349 }
1350 
SFIsSomethingBuildable(SplineFont * sf,SplineChar * sc,int layer,int onlyaccents)1351 int SFIsSomethingBuildable(SplineFont *sf,SplineChar *sc, int layer, int onlyaccents) {
1352     int unicodeenc = sc->unicodeenc;
1353 
1354     if (sc->user_decomp) return true;
1355 
1356     if ( onlyaccents &&		/* Don't build greek accents out of latin ones */
1357 	    (unicodeenc==0x1fbd || unicodeenc==0x1fbe || unicodeenc==0x1fbf ||
1358 	     unicodeenc==0x1fef || unicodeenc==0x1ffd || unicodeenc==0x1ffe))
1359 return( false );
1360 
1361     if ((unicodeenc <= 0xffff && iszerowidth(unicodeenc)) ||
1362 	    (unicodeenc>=0x2000 && unicodeenc<=0x2015 ))
1363 return( !onlyaccents );
1364 
1365     if ( SFIsCompositBuildable(sf,unicodeenc,sc,layer))
1366 return( !onlyaccents || hascomposing(sf,sc->unicodeenc,sc) );
1367 
1368     if ( !onlyaccents && SCMakeDotless(sf,sc,layer,NULL,false,false))
1369 return( true );
1370 
1371 return( SFIsRotatable(sf,sc));
1372 }
1373 
SPInRange(SplinePoint * sp,real ymin,real ymax)1374 static int SPInRange(SplinePoint *sp, real ymin, real ymax) {
1375 return ( sp->me.y>=ymin && sp->me.y<=ymax );
1376 }
1377 
_SplineSetFindXRange(SplinePointList * spl,DBounds * bounds,real ymin,real ymax,real ia)1378 static void _SplineSetFindXRange(SplinePointList *spl, DBounds *bounds,
1379 	real ymin, real ymax, real ia) {
1380     Spline *spline;
1381     real xadjust, tia = tan(ia);
1382 
1383     for ( ; spl!=NULL; spl = spl->next ) {
1384 	if ( SPInRange(spl->first,ymin,ymax) ) {
1385 	    xadjust = spl->first->me.x + tia*(spl->first->me.y-ymin);
1386 	    if ( bounds->minx==0 && bounds->maxx==0 ) {
1387 		bounds->minx = bounds->maxx = xadjust;
1388 	    } else {
1389 		if ( xadjust<bounds->minx ) bounds->minx = xadjust;
1390 		if ( xadjust>bounds->maxx ) bounds->maxx = xadjust;
1391 	    }
1392 	}
1393 	for ( spline = spl->first->next; spline!=NULL && spline->to!=spl->first; spline=spline->to->next ) {
1394 	    if ( SPInRange(spline->to,ymin,ymax) ) {
1395 	    xadjust = spline->to->me.x + tia*(spline->to->me.y-ymin);
1396 		if ( bounds->minx==0 && bounds->maxx==0 ) {
1397 		    bounds->minx = bounds->maxx = xadjust;
1398 		} else {
1399 		    if ( xadjust<bounds->minx ) bounds->minx = xadjust;
1400 		    if ( xadjust>bounds->maxx ) bounds->maxx = xadjust;
1401 		}
1402 	    }
1403 	}
1404     }
1405 }
1406 
_SplineSetFindXRangeAtYExtremum(SplinePointList * spl,DBounds * bounds,int findymax,real yextreme)1407 static real _SplineSetFindXRangeAtYExtremum(SplinePointList *spl, DBounds *bounds,
1408 	int findymax, real yextreme) {
1409     Spline *spline;
1410     extended t0, t1, t2, t3;
1411     bigreal y0, y1, y2, y3, x;
1412 
1413     for ( ; spl!=NULL; spl = spl->next ) {
1414 	for ( spline = spl->first->next; spline!=NULL; spline=spline->to->next ) {
1415 	    if (( findymax &&
1416 		    !(yextreme>spline->from->me.y && yextreme>spline->from->nextcp.y &&
1417 		      yextreme>spline->to->me.y && yextreme>spline->to->prevcp.y )) ||
1418 		(!findymax &&
1419 		    !(yextreme<spline->from->me.y && yextreme<spline->from->nextcp.y &&
1420 		      yextreme<spline->to->me.y && yextreme<spline->to->prevcp.y )) ) {
1421 		/* Ok this spline might be bigger(less) than our current */
1422 		/*  extreme value, so check it */
1423 		SplineFindExtrema(&spline->splines[1],&t1,&t2);
1424 		y0 = spline->from->me.y; t0 = 0;
1425 		y3 = spline->to->me.y; t3 = 1;
1426 		if ( t1!=-1 ) {
1427 		    y1 = ((spline->splines[1].a*t1+spline->splines[1].b)*t1+spline->splines[1].c)*t1+spline->splines[1].d;
1428 		    if ( y1>y0 ) { y0 = y1; t0 = t1; }
1429 		}
1430 		if ( t2!=-1 ) {
1431 		    y2 = ((spline->splines[1].a*t2+spline->splines[1].b)*t2+spline->splines[1].c)*t2+spline->splines[1].d;
1432 		    if ( y2>y3 ) { y3 = y2; t3 = t2; }
1433 		}
1434 		if ( (findymax && y0>yextreme+.1) || (!findymax && y0<yextreme-.1) ) {
1435 		    bounds->miny = bounds->maxy = yextreme = y0;
1436 		    bounds->minx = bounds->maxx =
1437 			    ((spline->splines[0].a*t0+spline->splines[0].b)*t0+spline->splines[0].c)*t0+spline->splines[0].d;
1438 		} else if ( (findymax && y0>=yextreme-.1) || (!findymax && y0<=yextreme+1) ) {
1439 		    x = ((spline->splines[0].a*t0+spline->splines[0].b)*t0+spline->splines[0].c)*t0+spline->splines[0].d;
1440 		    if ( x>bounds->maxx ) bounds->maxx = x;
1441 		    else if ( x<bounds->minx ) bounds->minx = x;
1442 		}
1443 		if ( (findymax && y3>yextreme+.1) || (!findymax && y3<yextreme-.1) ) {
1444 		    bounds->miny = bounds->maxy = yextreme = y3;
1445 		    bounds->minx = bounds->maxx =
1446 			    ((spline->splines[0].a*t3+spline->splines[0].b)*t3+spline->splines[0].c)*t3+spline->splines[0].d;
1447 		} else if ( (findymax && y3>=yextreme-.1) || (!findymax && y3<=yextreme+1) ) {
1448 		    x = ((spline->splines[0].a*t3+spline->splines[0].b)*t3+spline->splines[0].c)*t3+spline->splines[0].d;
1449 		    if ( x>bounds->maxx ) bounds->maxx = x;
1450 		    else if ( x<bounds->minx ) bounds->minx = x;
1451 		}
1452 	    }
1453 	    if ( spline->to == spl->first )
1454 	break;
1455 	}
1456     }
1457 return( yextreme );
1458 }
1459 
1460 /* this is called by the accented character routines with bounds set for the */
1461 /*  entire character. Our job is to make a guess at what the top of the */
1462 /*  character looks like so that we can do an optical accent placement */
1463 /* I currently think the best bet is to find the very highest point(s) and */
1464 /*  center on that. I used to find the bounds of the top quarter of the char */
SCFindTopXRange(SplineChar * sc,int layer,DBounds * bounds)1465 static real SCFindTopXRange(SplineChar *sc,int layer,DBounds *bounds) {
1466     RefChar *rf;
1467     real yextreme = -0x80000;
1468 
1469     /* a char with no splines (ie. a space) must have an lbearing of 0 */
1470     bounds->minx = bounds->maxx = 0;
1471 
1472     for ( rf=sc->layers[layer].refs; rf!=NULL; rf = rf->next )
1473 	yextreme = _SplineSetFindXRangeAtYExtremum(rf->layers[0].splines,bounds,true,yextreme);
1474 
1475     yextreme = _SplineSetFindXRangeAtYExtremum(sc->layers[layer].splines,bounds,true,yextreme);
1476     if ( yextreme == -0x80000 ) yextreme = 0;
1477 return( yextreme );
1478 }
1479 
SCFindBottomXRange(SplineChar * sc,int layer,DBounds * bounds,real ia)1480 static real SCFindBottomXRange(SplineChar *sc,int layer,DBounds *bounds, real ia) {
1481     RefChar *rf;
1482     real yextreme = 0x80000;
1483 
1484     /* a char with no splines (ie. a space) must have an lbearing of 0 */
1485     bounds->minx = bounds->maxx = 0;
1486 
1487     for ( rf=sc->layers[layer].refs; rf!=NULL; rf = rf->next )
1488 	yextreme = _SplineSetFindXRangeAtYExtremum(rf->layers[0].splines,bounds,false,yextreme);
1489 
1490     yextreme = _SplineSetFindXRangeAtYExtremum(sc->layers[layer].splines,bounds,false,yextreme);
1491     if ( yextreme == 0x80000 ) yextreme = 0;
1492 return( yextreme );
1493 }
1494 
1495 /* the cedilla and ogonec accents do not center on the accent itself but on */
1496 /*  the small part of it that joins at the top */
SCFindTopBounds(SplineChar * sc,int layer,DBounds * bounds,real ia)1497 static real SCFindTopBounds(SplineChar *sc,int layer,DBounds *bounds, real ia) {
1498     RefChar *rf;
1499     int ymax = bounds->maxy+1, ymin = ymax-(bounds->maxy-bounds->miny)/20;
1500 
1501     /* a char with no splines (ie. a space) must have an lbearing of 0 */
1502     bounds->minx = bounds->maxx = 0;
1503 
1504     for ( rf=sc->layers[layer].refs; rf!=NULL; rf = rf->next )
1505 	_SplineSetFindXRange(rf->layers[0].splines,bounds,ymin,ymax,ia);
1506 
1507     _SplineSetFindXRange(sc->layers[layer].splines,bounds,ymin,ymax,ia);
1508 return( ymin );
1509 }
1510 
1511 /* And similarly for the floating hook, and often for grave and acute */
SCFindBottomBounds(SplineChar * sc,int layer,DBounds * bounds,real ia)1512 static real SCFindBottomBounds(SplineChar *sc,int layer,DBounds *bounds, real ia) {
1513     RefChar *rf;
1514     int ymin = bounds->miny-1, ymax = ymin+(bounds->maxy-bounds->miny)/20;
1515 
1516     /* a char with no splines (ie. a space) must have an lbearing of 0 */
1517     bounds->minx = bounds->maxx = 0;
1518 
1519     for ( rf=sc->layers[layer].refs; rf!=NULL; rf = rf->next )
1520 	_SplineSetFindXRange(rf->layers[0].splines,bounds,ymin,ymax,ia);
1521 
1522     _SplineSetFindXRange(sc->layers[layer].splines,bounds,ymin,ymax,ia);
1523 return( ymin );
1524 }
1525 
SplineCharFindSlantedBounds(SplineChar * sc,int layer,DBounds * bounds,real ia)1526 static real SplineCharFindSlantedBounds(SplineChar *sc,int layer,DBounds *bounds, real ia) {
1527     int ymin, ymax;
1528     RefChar *rf;
1529 
1530     SplineCharFindBounds(sc,bounds);
1531 
1532     ymin = bounds->miny-1, ymax = bounds->maxy+1;
1533 
1534     if ( ia!=0 ) {
1535 	bounds->minx = bounds->maxx = 0;
1536 
1537 	for ( rf=sc->layers[layer].refs; rf!=NULL; rf = rf->next )
1538 	    _SplineSetFindXRange(rf->layers[0].splines,bounds,ymin,ymax,ia);
1539 
1540 	_SplineSetFindXRange(sc->layers[layer].splines,bounds,ymin,ymax,ia);
1541     }
1542 return( ymin );
1543 }
1544 
SCStemCheck(SplineFont * sf,int layer,int basech,DBounds * bb,DBounds * rbb,int pos)1545 static int SCStemCheck(SplineFont *sf,int layer,int basech,DBounds *bb, DBounds *rbb,int pos) {
1546     /* cedilla (and ogonec on A) should be centered underneath the left */
1547     /*  (or right) vertical (or diagonal) stem. Here we try to find that */
1548     /*  stem */
1549     StemInfo *h, *best;
1550     SplineChar *sc;
1551     DStemInfo *d;
1552 
1553     sc = SFGetChar(sf,basech,NULL);
1554     if ( sc==NULL )
1555 return( 0x70000000 );
1556     if ( autohint_before_generate && sc->changedsincelasthinted && !sc->manualhints )
1557 	SplineCharAutoHint(sc,layer,NULL);
1558     if ( (best=sc->vstem)!=NULL ) {
1559 	if ( pos & FF_UNICODE_CENTERLEFT ) {
1560 	    for ( h=best->next; h!=NULL && h->start<best->start+best->width; h=h->next )
1561 		if ( h->start+h->width<best->start+best->width )
1562 		    best = h;
1563 	    if ( best->start+best->width/2>(bb->maxx+bb->minx)/2 )
1564 		best = NULL;
1565 	} else if ( pos & FF_UNICODE_CENTERRIGHT ) {
1566 	    while ( best->next!=NULL )
1567 		best = best->next;
1568 	    if ( best->start+best->width/2<(bb->maxx+bb->minx)/2 )
1569 		best = NULL;
1570 	} else {
1571 	    for ( h=best->next; h!=NULL ; h=h->next )
1572 		if ( HIlen(h)>HIlen(best))
1573 		    best = h;
1574 	}
1575 	if ( best!=NULL )
1576 return( best->start + best->width/2 - (rbb->maxx-rbb->minx)/2 - rbb->minx );
1577     }
1578     if ( sc->dstem != NULL ) {
1579         double himin, himax, hibase, roff, temp;
1580         double lbx = 0, rbx = 0, lbxtest, rbxtest;
1581         HintInstance *hi;
1582 	for ( d=sc->dstem; d!=NULL ; d=d->next ) {
1583             if ( d->where == NULL )
1584         continue;
1585             if ( d->where->begin < d->where->end ) {
1586                 himin = d->where->begin;
1587                 himax = d->where->end;
1588             } else {
1589                 himin = d->where->end;
1590                 himax = d->where->begin;
1591             }
1592             for ( hi=d->where->next; hi!=NULL; hi=hi->next ) {
1593                 if ( hi->begin < himin ) himin = hi->begin;
1594                 if ( hi->end < himin ) himin = hi->end;
1595                 if ( hi->end > himax ) himax = hi->end;
1596                 if ( hi->begin > himax ) himax = hi->begin;
1597             }
1598             hibase = ( d->unit.y > 0 ) ? himin : himax;
1599             roff =  ( d->right.x - d->left.x ) * d->unit.x +
1600                     ( d->right.y - d->left.y ) * d->unit.y;
1601             lbxtest = d->left.x + d->unit.x * hibase;
1602             rbxtest = d->right.x + d->unit.x * ( hibase - roff );
1603             if ( rbxtest < lbxtest ) {
1604                 temp = rbxtest; rbxtest = lbxtest; lbxtest = temp;
1605             }
1606             if ( d == sc->dstem ||
1607                 ( ( pos & FF_UNICODE_CENTERLEFT ) && rbxtest < rbx ) ||
1608                 ( ( pos & FF_UNICODE_CENTERRIGHT ) && lbxtest > lbx ) ) {
1609                 lbx = lbxtest; rbx = rbxtest;
1610             }
1611         }
1612         if ( lbx < rbx && (
1613             ( ( pos & FF_UNICODE_CENTERLEFT ) &&
1614             ( lbx + rbx )/2 <= ( bb->maxx + bb->minx )/2 ) ||
1615             ( ( pos & FF_UNICODE_CENTERRIGHT ) &&
1616             ( lbx + rbx )/2 >= ( bb->maxx + bb->minx )/2 )))
1617 return(( lbx + rbx )/2 - ( rbb->maxx - rbb->minx )/2 - rbb->minx );
1618     }
1619 return( 0x70000000 );
1620 }
1621 
_SCAddRef(SplineChar * sc,SplineChar * rsc,int layer,real transform[6])1622 void _SCAddRef(SplineChar *sc,SplineChar *rsc,int layer,real transform[6]) {
1623     RefChar *ref = RefCharCreate();
1624 
1625     ref->sc = rsc;
1626     ref->unicode_enc = rsc->unicodeenc;
1627     ref->orig_pos = rsc->orig_pos;
1628     ref->adobe_enc = getAdobeEnc(rsc->name);
1629     ref->next = sc->layers[layer].refs;
1630     sc->layers[layer].refs = ref;
1631     memcpy(ref->transform,transform,sizeof(real [6]));
1632     SCReinstanciateRefChar(sc,ref,layer);
1633     SCMakeDependent(sc,rsc);
1634 }
1635 
SCAddRef(SplineChar * sc,SplineChar * rsc,int layer,real xoff,real yoff)1636 void SCAddRef(SplineChar *sc,SplineChar *rsc,int layer, real xoff, real yoff) {
1637     real transform[6];
1638     transform[0] = transform[3] = 1;
1639     transform[1] = transform[2] = 0;
1640     transform[4] = xoff; transform[5] = yoff;
1641     _SCAddRef(sc,rsc,layer,transform);
1642 }
1643 
BCClearAndCopyBelow(BDFFont * bdf,int togid,int fromgid,int ymax)1644 static void BCClearAndCopyBelow(BDFFont *bdf,int togid,int fromgid, int ymax) {
1645     BDFChar *bc, *rbc;
1646 
1647     bc = BDFMakeGID(bdf,togid);
1648     BCPreserveState(bc);
1649     BCFlattenFloat(bc);
1650     BCCompressBitmap(bc);
1651     if ( bdf->glyphs[fromgid]!=NULL ) {
1652 	rbc = bdf->glyphs[fromgid];
1653 	free(bc->bitmap);
1654 	bc->xmin = rbc->xmin;
1655 	bc->xmax = rbc->xmax;
1656 	bc->ymin = rbc->ymin;
1657 	bc->ymax = ymax;
1658 	bc->bytes_per_line = rbc->bytes_per_line;
1659 	bc->width = rbc->width;
1660 	bc->bitmap = malloc(bc->bytes_per_line*(bc->ymax-bc->ymin+1));
1661 	memcpy(bc->bitmap,rbc->bitmap+(rbc->ymax-ymax)*rbc->bytes_per_line,
1662 		bc->bytes_per_line*(bc->ymax-bc->ymin+1));
1663     }
1664 }
1665 
BCAddReference(BDFChar * bc,BDFChar * rbc,int gid,int xoff,int yoff)1666 static void BCAddReference( BDFChar *bc,BDFChar *rbc,int gid,int xoff,int yoff ) {
1667     BDFRefChar *bcref;
1668 
1669     bcref = calloc( 1,sizeof( BDFRefChar ));
1670     bcref->bdfc = rbc; bcref->gid = gid;
1671     bcref->xoff = xoff; bcref->yoff = yoff;
1672     bcref->next = bc->refs; bc->refs = bcref;
1673     BCMakeDependent( bc,rbc );
1674 }
1675 
BCFindGap(BDFChar * bc)1676 static int BCFindGap(BDFChar *bc) {
1677     int i,y;
1678 
1679     BCFlattenFloat(bc);
1680     BCCompressBitmap(bc);
1681     for ( y=bc->ymax; y>=bc->ymin; --y ) {
1682 	for ( i=0; i<bc->bytes_per_line; ++i )
1683 	    if ( bc->bitmap[(bc->ymax-y)*bc->bytes_per_line+i]!=0 )
1684 	break;
1685 	if ( i==bc->bytes_per_line )
1686 return( y );
1687     }
1688 return( bc->ymax );
1689 }
1690 
SCMakeBaseReference(SplineChar * sc,SplineFont * sf,int layer,int ch,BDFFont * bdf,int disp_only)1691 static int SCMakeBaseReference(SplineChar *sc,SplineFont *sf,int layer,int ch, BDFFont *bdf,int disp_only) {
1692     SplineChar *rsc;
1693     BDFChar *bc;
1694     char *dot;
1695     char buffer[200], namebuf[200];
1696 
1697     if ( (dot = strchr(sc->name,'.'))!=NULL && sc->user_decomp==NULL ) {
1698 	snprintf(buffer,sizeof(buffer),"%s%s",
1699 		(char *) StdGlyphName(namebuf,ch,sf->uni_interp,sf->for_new_glyphs),
1700 		dot);
1701 	rsc = SFGetChar(sf,-1,buffer);
1702     } else
1703 	rsc = SFGetChar(sf,ch,NULL);
1704 
1705     if ( rsc==NULL && dot==NULL ) {
1706 	if ( ch==0x131 || ch==0xf6be || ch==0x237) {
1707 	    if ( ch==0x131 ) ch='i'; else ch = 'j';
1708 	    rsc = SFGetChar(sf,ch,NULL);
1709 	    if ( rsc!=NULL && !sf->dotlesswarn ) {
1710 /* GT: the string "dotlessi" is the official postscript name for the glyph */
1711 /* GT: containing an "i" without a dot on top of it. The name "dotlessi" */
1712 /* GT: should be left untranslated, though you may wish to explain what it */
1713 /* GT: means */
1714 		ff_post_error( _("Missing Glyph..."),ch=='i'?_("Your font is missing the dotlessi glyph,\nplease add it and remake your accented glyphs"):
1715 /* GT: Adobe decided that a dotless j glyph was needed, assigned a code */
1716 /* GT: point to it in the private use area, and named it "dotlessj". Then */
1717 /* GT: years later the Unicode people decided one was needed and assigned */
1718 /* GT: it U+0237, so that's now the official code point and it is named */
1719 /* GT: "uni0237". The name "dotlessj" is deprecated but still present in */
1720 /* GT: many fonts. Neither "dotlessj" nor "uni0237" should be translated */
1721 /* GT: because they are standard PostScript glyph names. */
1722 /* GT: Again you may wish to explain that these refer to a "j" without a dot */
1723 			_("Your font is missing the uni0237 glyph,\nand the deprecated dotlessj glyph,\nplease add the former and remake your accented glyphs"));
1724 		sf->dotlesswarn = true;
1725 	    }
1726 	}
1727     }
1728     if ( rsc==NULL )
1729 return( 0 );
1730     if ( bdf == NULL || !disp_only ) {
1731 	sc->width = rsc->width;
1732 	if ( ch!=' ' )			/* Some accents are built by combining with space. Don't. The reference won't be displayed or selectable but will be there and might cause confusion... */
1733 	    SCAddRef(sc,rsc,layer,0,0);	/* should be after the call to MakeChar */
1734     }
1735     if ( !disp_only ) {
1736 	for ( bdf=sf->cidmaster?sf->cidmaster->bitmaps:sf->bitmaps; bdf!=NULL; bdf=bdf->next ) {
1737 	    if ( bdf->glyphs[rsc->orig_pos] != NULL ) {
1738 		if (( bc = bdf->glyphs[sc->orig_pos] ) == NULL ) {
1739 		    bc = BDFMakeGID(bdf,sc->orig_pos);
1740 		    BCClearAll( bc );
1741 		}
1742 		if ( ch!=' ' )
1743 		    BCAddReference( bc,bdf->glyphs[rsc->orig_pos],rsc->orig_pos,0,0 );
1744 	    }
1745 	}
1746     } else if ( bdf != NULL ) {
1747 	if ( bdf->glyphs[rsc->orig_pos] != NULL ) {
1748 	    if (( bc = bdf->glyphs[sc->orig_pos] ) == NULL ) {
1749 		bc = BDFMakeGID(bdf,sc->orig_pos);
1750 		BCClearAll( bc );
1751 	    }
1752 	    if ( ch!=' ' )
1753 		BCAddReference( bc,bdf->glyphs[rsc->orig_pos],rsc->orig_pos,0,0 );
1754 	}
1755     }
1756 return( 1 );
1757 }
1758 
GetGoodAccentGlyph(SplineFont * sf,int uni,int basech,int * invert,double ia,char * dot,SplineChar * destination)1759 static SplineChar *GetGoodAccentGlyph(SplineFont *sf, int uni, int basech,
1760 	int *invert,double ia, char *dot, SplineChar *destination) {
1761     int ach= -1;
1762     const unichar_t *apt, *end;
1763     SplineChar *rsc;
1764     char buffer[200], namebuf[200];
1765 
1766     *invert = false;
1767 
1768     /* cedilla on lower "g" becomes a turned comma above it */
1769     if ( uni==0x327 && basech=='g' && haschar(sf,0x312, dot))
1770 	uni = 0x312;
1771     if ( !PreferSpacingAccents && ((haschar(sf,uni, dot) &&
1772 		!SCDependsOnSC(GetChar(sf,uni,dot),destination)) ||
1773 	    (dot!=NULL && haschar(sf,uni, NULL) &&
1774 		!SCDependsOnSC(GetChar(sf,uni,NULL),destination))) )
1775 	ach = uni;
1776     else if ( uni>=BottomAccent && uni<=TopAccent && (PreferSpacingAccents || !haschar(sf,uni,NULL)) ) {
1777 	apt = accents[uni-BottomAccent]; end = apt+sizeof(accents[0])/sizeof(accents[0][0]);
1778 	while ( *apt && apt<end &&
1779 		(             GetChar(sf,*apt,dot) ==NULL || SCDependsOnSC(GetChar(sf,*apt,dot),destination)) &&
1780 		(dot==NULL || GetChar(sf,*apt,NULL)==NULL || SCDependsOnSC(GetChar(sf,*apt,NULL),destination)) )
1781 	    ++apt;
1782 	if ( *apt!='\0' && apt<end && PreferSpacingAccents)
1783 	    ach = *apt;
1784 	else if ( haschar(sf,uni,dot) && !SCDependsOnSC(GetChar(sf,uni,dot),destination))
1785 	    ach = uni;
1786 	else if ( uni==0x31b && haschar(sf,',',NULL))
1787 	    ach = ',';
1788 	else if (( uni == 0x32f || uni == 0x311 ) && haschar(sf,0x2d8,NULL) && ia==0 && PreferSpacingAccents) {
1789 	    /* In italic fonts invert is not enough, you must do more */
1790 	    ach = 0x2d8;
1791 	    *invert = true;
1792 	} else if ( (uni == 0x30c || uni == 0x32c ) &&
1793 		(haschar(sf,0x302,dot) || haschar(sf,0x2c6,NULL) || haschar(sf,'^',NULL)) ) {
1794 	    *invert = true;
1795 	    if (PreferSpacingAccents && haschar(sf,0x2c6,NULL))
1796 		ach = 0x2c6;
1797 	    else if ( haschar(sf,'^',NULL) )
1798 		ach = '^';
1799 	    else
1800 		ach = 0x302;
1801 	}
1802     } else
1803 	ach = uni;
1804 
1805     rsc = NULL;
1806     if ( dot!=NULL ) {
1807 	snprintf(buffer,sizeof(buffer),"%s%s",
1808 		(char *) StdGlyphName(namebuf,ach,sf->uni_interp,sf->for_new_glyphs),
1809 		dot);
1810 	rsc = SFGetChar(sf,-1,buffer);
1811     }
1812     if ( rsc==NULL ) {
1813 	rsc = SFGetChar(sf,ach,NULL);
1814 	dot = NULL;
1815     }
1816 
1817     /* Look to see if there are upper case variants of the accents available */
1818     if ( dot==NULL && ( isupper(basech) || (basech>=0x400 && basech<=0x52f) )) {
1819 	char *uc_accent;
1820 	SplineChar *test = NULL;
1821 	char buffer[80];
1822 	char *suffixes[4];
1823 	int scnt=0, i;
1824 
1825 	if ( rsc!=NULL ) {
1826 	    uc_accent = malloc(strlen(rsc->name)+11);
1827 	    strcpy(uc_accent,rsc->name);
1828 	} else
1829 	    uc_accent = NULL;
1830 	memset(suffixes,0,sizeof(suffixes));
1831 	if ( basech>=0x400 && basech<=0x52f ) {
1832 	    if ( isupper(basech) )
1833 		suffixes[scnt++] = "cyrcap";
1834 	    suffixes[scnt++] = "cyr";
1835 	}
1836 	if ( isupper(basech))
1837 	    suffixes[scnt++] = "cap";
1838 
1839 	for ( i=0; test==NULL && i<scnt; ++i ) {
1840 	    if ( uni>=BottomAccent && uni<=TopAccent && (PreferSpacingAccents || !haschar(sf,uni,NULL)) ) {
1841 		apt = accents[uni-BottomAccent]; end = apt+sizeof(accents[0])/sizeof(accents[0][0]);
1842 		while ( test==NULL && apt<end ) {
1843 		    int acc = *apt ? *apt : uni;
1844 		    sprintf( buffer,"%.70s.%s", StdGlyphName(buffer,acc,ui_none,(NameList *) -1), suffixes[i]);
1845 		    if ( (test = SFGetChar(sf,-1,buffer))!=NULL )
1846 			rsc = test;
1847 		    if ( test==NULL ) {
1848 			sprintf( buffer,"uni%04X.%s", acc, suffixes[i]);
1849 			if ( (test = SFGetChar(sf,-1,buffer))!=NULL )
1850 			    rsc = test;
1851 		    }
1852 		    if ( *apt=='\0' )
1853 		break;
1854 		    ++apt;
1855 		}
1856 	    }
1857 	}
1858 	if ( test==NULL && uni>=BottomAccent && uni<=TopAccent && isupper(basech) &&
1859 		(PreferSpacingAccents || !haschar(sf,uni,NULL)) ) {
1860 	    apt = accents[uni-BottomAccent]; end = apt+sizeof(accents[0])/sizeof(accents[0][0]);
1861 	    while ( test==NULL && apt<end ) {
1862 		int acc = *apt ? *apt : uni;
1863 		sprintf( buffer,"%.70s.%s", StdGlyphName(buffer,acc,ui_none,(NameList *) -1), suffixes[i]);
1864 		if ( islower(buffer[0])) {
1865 		    buffer[0] = toupper(buffer[0]);
1866 		    if ( (test = SFGetChar(sf,-1,buffer))!=NULL )
1867 			rsc = test;
1868 		}
1869 		if ( *apt=='\0' )
1870 	    break;
1871 		++apt;
1872 	    }
1873 	}
1874 	if ( test==NULL && uni>=BottomAccent && uni<BottomAccent+sizeof(uc_accent_names)/sizeof(uc_accent_names[0]) &&
1875 		uc_accent_names[uni-BottomAccent]!=NULL && isupper(basech))
1876 	    if ( (test = SFGetChar(sf,-1,uc_accent_names[uni-BottomAccent]))!=NULL )
1877 		rsc = test;
1878 	if ( test==NULL && uc_accent!=NULL && islower(*uc_accent) && isupper(basech)) {
1879 	    *uc_accent = toupper(*uc_accent);
1880 	    if ( (test=SFGetChar(sf,-1,uc_accent))!=NULL )
1881 		rsc = test;
1882 	}
1883 	free(uc_accent);
1884     }
1885     if ( rsc!=NULL && SCDependsOnSC(rsc,destination))
1886 	rsc = NULL;
1887 return( rsc );
1888 }
1889 
TurnOffUseMyMetrics(SplineChar * sc)1890 static void TurnOffUseMyMetrics(SplineChar *sc) {
1891     /* When building greek polytonic glyphs, or any glyphs where the accents */
1892     /*  change the metrics, we should turn off "use my metrics" on the base */
1893     /*  reference */
1894     RefChar *refs;
1895     int ly;
1896 
1897     for ( ly=ly_fore; ly<sc->layer_cnt; ++ly )
1898 	for ( refs = sc->layers[ly].refs; refs!=NULL; refs = refs->next )
1899 	    refs->use_my_metrics = false;
1900 }
1901 
AnchorClassMatch(SplineChar * sc1,SplineChar * sc2,AnchorClass * restrict_,AnchorPoint ** _ap1,AnchorPoint ** _ap2)1902 AnchorClass *AnchorClassMatch(SplineChar *sc1,SplineChar *sc2,AnchorClass *restrict_,
1903 	AnchorPoint **_ap1,AnchorPoint **_ap2 ) {
1904     AnchorPoint *ap1, *ap2;
1905 
1906     for ( ap1=sc1->anchor; ap1!=NULL ; ap1=ap1->next ) if ( restrict_==(AnchorClass *) -1 || ap1->anchor==restrict_ ) {
1907 	for ( ap2=sc2->anchor; ap2!=NULL; ap2=ap2->next ) if ( restrict_==(AnchorClass *) -1 || ap2->anchor==restrict_ ) {
1908 	    if ( ap1->anchor==ap2->anchor &&
1909 		    ((ap1->type>=at_basechar && ap1->type<=at_basemark && ap2->type==at_mark) ||
1910 		     (ap1->type==at_cexit && ap2->type==at_centry) )) {
1911 		 *_ap1 = ap1;
1912 		 *_ap2 = ap2;
1913 return( ap1->anchor );
1914 	    }
1915 	}
1916     }
1917 return( NULL );
1918 }
1919 
AnchorClassMkMkMatch(SplineChar * sc1,SplineChar * sc2,AnchorPoint ** _ap1,AnchorPoint ** _ap2)1920 AnchorClass *AnchorClassMkMkMatch(SplineChar *sc1,SplineChar *sc2,
1921 	AnchorPoint **_ap1,AnchorPoint **_ap2 ) {
1922     AnchorPoint *ap1, *ap2;
1923 
1924     for ( ap1=sc1->anchor; ap1!=NULL ; ap1=ap1->next ) {
1925 	for ( ap2=sc2->anchor; ap2!=NULL; ap2=ap2->next ) {
1926 	    if ( ap1->anchor==ap2->anchor &&
1927 		    ap1->type==at_basemark && ap2->type==at_mark)  {
1928 		 *_ap1 = ap1;
1929 		 *_ap2 = ap2;
1930 return( ap1->anchor );
1931 	    }
1932 	}
1933     }
1934 return( NULL );
1935 }
1936 
AnchorClassCursMatch(SplineChar * sc1,SplineChar * sc2,AnchorPoint ** _ap1,AnchorPoint ** _ap2)1937 AnchorClass *AnchorClassCursMatch(SplineChar *sc1,SplineChar *sc2,
1938 	AnchorPoint **_ap1,AnchorPoint **_ap2 ) {
1939     AnchorPoint *ap1, *ap2;
1940 
1941     for ( ap1=sc1->anchor; ap1!=NULL ; ap1=ap1->next ) {
1942 	for ( ap2=sc2->anchor; ap2!=NULL; ap2=ap2->next ) {
1943 	    if ( ap1->anchor==ap2->anchor &&
1944 		    ap1->type==at_cexit && ap2->type==at_centry)  {
1945 		 *_ap1 = ap1;
1946 		 *_ap2 = ap2;
1947 return( ap1->anchor );
1948 	    }
1949 	}
1950     }
1951 return( NULL );
1952 }
1953 
_BCCenterAccent(BDFFont * bdf,int gid,int rgid,int ch,int basech,int italicoff,uint32 pos,real em)1954 static void _BCCenterAccent( BDFFont *bdf, int gid, int rgid, int ch, int basech, int italicoff,
1955 	uint32 pos,	/* unicode char position info, see #define for utype2[] in utype.h */
1956 	real em ) {
1957     BDFChar *bc, *rbc;
1958     int ixoff, iyoff, ispacing;
1959     IBounds ibb, irb;
1960 
1961     if (( rbc = bdf->glyphs[rgid] ) != NULL && ( bc = bdf->glyphs[gid] ) != NULL ) {
1962 	if ( (ispacing = (bdf->pixelsize*accent_offset+50)/100)<=1 ) ispacing = 2;
1963 	BCFlattenFloat(rbc);
1964 	BCCompressBitmap(rbc);
1965 	BDFCharQuickBounds( bc,&ibb,0,0,false,true );
1966 	BDFCharQuickBounds( rbc,&irb,0,0,false,true );
1967 
1968 	if ( (pos & FF_UNICODE_ABOVE) && (pos & (FF_UNICODE_LEFT|FF_UNICODE_RIGHT)) )
1969 	    iyoff = ibb.maxy - irb.maxy;
1970 	else if ( pos & FF_UNICODE_ABOVE )
1971 	    iyoff = ibb.maxy + ispacing - irb.miny;
1972 	else if ( pos & FF_UNICODE_BELOW ) {
1973 	    iyoff = ibb.miny - irb.maxy;
1974 	    if ( !( pos & FF_UNICODE_TOUCHING) )
1975 		iyoff -= ispacing;
1976 	} else if ( pos & FF_UNICODE_OVERSTRIKE )
1977 	    iyoff = ibb.miny - irb.miny + ((ibb.maxy-ibb.miny)-(irb.maxy-irb.miny))/2;
1978 	else
1979 	    iyoff = ibb.miny - irb.miny;
1980 	if ( isupper(basech) && ch==0x342)
1981 	    ixoff = ibb.minx - irb.minx;
1982 	else if ( pos & FF_UNICODE_LEFT )
1983 	    ixoff = ibb.minx - ispacing - irb.maxx;
1984 	else if ( pos & FF_UNICODE_RIGHT ) {
1985 	    ixoff = ibb.maxx - irb.minx + ispacing/2;
1986 	    if ( !( pos & FF_UNICODE_TOUCHING) )
1987 		ixoff += ispacing;
1988 	} else {
1989 	    if ( pos & FF_UNICODE_CENTERLEFT )
1990 		ixoff = ibb.minx + (ibb.maxx-ibb.minx)/2 - irb.maxx;
1991 	    else if ( pos & FF_UNICODE_LEFTEDGE )
1992 		ixoff = ibb.minx - irb.minx;
1993 	    else if ( pos & FF_UNICODE_CENTERRIGHT )
1994 		ixoff = ibb.minx + (ibb.maxx-ibb.minx)/2 - irb.minx;
1995 	    else if ( pos & FF_UNICODE_RIGHTEDGE )
1996 		ixoff = ibb.maxx - irb.maxx;
1997 	    else
1998 		ixoff = ibb.minx - irb.minx + ((ibb.maxx-ibb.minx)-(irb.maxx-irb.minx))/2;
1999 	}
2000 	ixoff += rint( italicoff*bdf->pixelsize/em );
2001 	BCAddReference( bc,rbc,rgid,ixoff,iyoff );
2002     }
2003 }
2004 
_SCCenterAccent(SplineChar * sc,SplineChar * basersc,SplineFont * sf,int layer,int ch,BDFFont * bdf,int disp_only,SplineChar * rsc,real ia,int basech,int invert,uint32 pos)2005 static void _SCCenterAccent(SplineChar *sc,SplineChar *basersc, SplineFont *sf,
2006 	int layer, int ch, BDFFont *bdf, int disp_only,
2007 	SplineChar *rsc, real ia, int basech,
2008 	int invert,	/* invert accent, false==0, true!=0 */
2009 	uint32 pos	/* unicode char position info, see #define for utype2[] in utype.h */ ) {
2010     real transform[6];
2011     DBounds bb, rbb, bbb;
2012     real xoff, yoff;
2013     real spacing = (sf->ascent+sf->descent)*accent_offset/100;
2014     real ybase, italicoff;
2015     const unichar_t *temp;
2016     int baserch = basech;
2017     int eta;
2018     AnchorPoint *ap1, *ap2;
2019 
2020     if ( rsc==NULL || sc==NULL )
2021 return;
2022 
2023     /* When we center an accent on Uhorn, we don't really want it centered */
2024     /*  on the combination, we want it centered on "U". So if basech is itself*/
2025     /*  a combo, find what it is based on */
2026     if ( (temp = SFGetAlternate(sf,basech,NULL,false))!=NULL && haschar(sf,*temp,NULL))
2027 	baserch = *temp;
2028     /* Similarly in Ø or ø, we really want to base the accents on O or o */
2029     if ( baserch==0xf8 ) baserch = 'o';
2030     else if ( baserch==0xd8 ) baserch = 'O';
2031 
2032     SplineCharFindSlantedBounds(rsc,layer,&rbb,ia);
2033     if ( ch==0x328 || ch==0x327 ) {	/* cedilla and ogonek */
2034 	SCFindTopBounds(rsc,layer,&rbb,ia);
2035 	/* should do more than touch, should overlap a tiny bit... */
2036 	rbb.maxy -= (rbb.maxy-rbb.miny)/30;
2037     } else if ( ch==0x345 ) {	/* ypogegrammeni */
2038 	SCFindTopBounds(rsc,layer,&rbb,ia);
2039     } else if ( (GraveAcuteCenterBottom && (ch==0x300 || ch==0x301 || ch==0x30b || ch==0x30f)) || ch==0x309 )	/* grave, acute, hungarian, Floating hook */
2040 	SCFindBottomBounds(rsc,layer,&rbb,ia);
2041     else if ( basech=='A' && ch==0x30a )
2042 	/* Again, a tiny bit of overlap is usual for Aring */
2043 	rbb.miny += (rbb.maxy-rbb.miny)/30;
2044     ybase = SplineCharFindSlantedBounds(sc,layer,&bb,ia);
2045     if ( basersc==NULL ) {
2046 	if ( baserch!=basech && ( basersc = SFGetChar(sf,baserch,NULL))!=NULL )
2047 	    /* Do Nothing */;
2048 	else if ( basersc == NULL || (basech!=-1 && (basech==sc->unicodeenc || ( basersc = SFGetChar(sf,basech,NULL))==NULL )))
2049 	    basersc = sc;
2050     }
2051     if ( ia==0 && baserch!=basech && basersc!=NULL ) {
2052 	ybase = SplineCharFindSlantedBounds(basersc,layer,&bbb,ia);
2053 	if ( (ffUnicodeUtype2(ch) & (FF_UNICODE_ABOVE|FF_UNICODE_BELOW)) ) {
2054 	    /* if unicode.org character definition matches ABOVE or BELOW, then... */
2055 	    bbb.maxy = bb.maxy;
2056 	    bbb.miny = bb.miny;
2057 	}
2058 	if ( (ffUnicodeUtype2(ch) & (FF_UNICODE_RIGHT|FF_UNICODE_LEFT)) ) {
2059 	    /* if unicode.org character definition matches RIGHT or LEFT, then... */
2060 	    bbb.maxx = bb.maxx;
2061 	    bbb.minx = bb.minx;
2062 	}
2063 	bb = bbb;
2064     }
2065 
2066     transform[0] = transform[3] = 1;
2067     transform[1] = transform[2] = transform[4] = transform[5] = 0;
2068 
2069     italicoff = 0;
2070     if ( sc->layers[layer].refs!=NULL && sc->layers[layer].refs->next!=NULL &&
2071 	    (AnchorClassMkMkMatch(sc->layers[layer].refs->sc,rsc,&ap1,&ap2)!=NULL ||
2072 	     AnchorClassCursMatch(sc->layers[layer].refs->sc,rsc,&ap1,&ap2)!=NULL) ) {
2073 	/* Do we have a mark to mark attachment to the last anchor we added? */
2074 	/*  (or a cursive exit to entry match?) */
2075 	/*  If so then figure offsets relative to it. */
2076 	xoff = ap1->me.x-ap2->me.x + sc->layers[layer].refs->transform[4];
2077 	yoff = ap1->me.y-ap2->me.y + sc->layers[layer].refs->transform[5];
2078 	pos = ffUnicodeUtype2(ch);	/* init with unicode.org position information */
2079     } else if ( AnchorClassMatch(basersc,rsc,(AnchorClass *) -1,&ap1,&ap2)!=NULL && ap2->type==at_mark ) {
2080 	xoff = ap1->me.x-ap2->me.x;
2081 	yoff = ap1->me.y-ap2->me.y;
2082 	pos = ffUnicodeUtype2(ch);	/* init with unicode.org position information */
2083     } else {
2084  /* try to establish a common line on which all accents lie. The problem being*/
2085  /*  that an accent above a,e,o will usually be slightly higher than an accent */
2086  /*  above i or u, similarly for upper case. Letters with ascenders shouldn't */
2087  /*  have much of a problem because ascenders are (usually) all the same shape*/
2088  /* Obviously this test is only meaningful for latin,greek,cyrillic alphas */
2089  /*  hence test for isupper,islower. And I'm assuming greek,cyrillic will */
2090  /*  be consistant with latin */
2091 	if ( islower(basech) || isupper(basech)) {
2092 	    SplineChar *common = SFGetChar(sf,islower(basech)?'o':'O',NULL);
2093 	    if ( common!=NULL ) {
2094 		real top = SplineCharQuickTop(common,layer);
2095 		if ( bb.maxy<top ) {
2096 		    bb.maxx += tan(ia)*(top-bb.maxy);
2097 		    bb.maxy = top;
2098 		}
2099 	    }
2100 	}
2101 	eta = false;
2102 	if ( ((basech>=0x1f20 && basech<=0x1f27) || basech==0x1f74 || basech==0x1f75 || basech==0x1fc6 || basech==0x3b7 || basech==0x3ae) &&
2103 		ch==0x345 ) {
2104 	    bb.miny = 0;		/* ypogegrammeni rides below baseline, not below bottom stem */
2105 	    eta = true;
2106 	    if ( basersc!=NULL && basersc->vstem!=NULL ) {
2107 		bb.minx = basersc->vstem->start;
2108 		bb.maxx = bb.minx + basersc->vstem->width;
2109 	    } else
2110 		bb.maxx -= (bb.maxx-bb.minx)/3;	/* Should also be centered on left stem of eta, but I don't know how to do that..., hence this hack */
2111 	}
2112 
2113 	if ( invert ) {
2114 	    /* yes, this transform does a vertical flip from the vertical midpoint of the breve */
2115 	    transform[3] = -1;
2116 	    transform[5] = rbb.maxy+rbb.miny;
2117 	}
2118 	if ( pos==FF_UNICODE_NOPOSDATAGIVEN ) {
2119 	    /* if here, then we need to initialize some type of position info for the accent */
2120 	    if ( ch<0 || ch>=0x10000 )	/* makeutype.c only built data in utype.c for {0...MAXC} */
2121 		pos = FF_UNICODE_ABOVE;
2122 	    else
2123 		pos = ffUnicodeUtype2(ch);	/* init with unicode.org position information */
2124 	    /* In greek, PSILI and friends are centered above lower case, and kern left*/
2125 	    /*  for upper case */
2126 	    if (( basech>=0x390 && basech<=0x3ff) || (basech>=0x1f00 && basech<=0x1fff)) {
2127 		if ( ( basech==0x1fbf || basech==0x1fef || basech==0x1ffe ) &&
2128 			(ch==0x1fbf || ch==0x1fef || ch==0x1ffe || ch==0x1fbd || ch==0x1ffd )) {
2129 		    pos = FF_UNICODE_ABOVE|FF_UNICODE_RIGHT;
2130 		} else if ( isupper(basech) &&
2131 			(ch==0x313 || ch==0x314 || ch==0x301 || ch==0x300 || ch==0x30d ||
2132 			 ch==0x1ffe || ch==0x1fbf || ch==0x1fcf || ch==0x1fdf ||
2133 			 ch==0x1fbd || ch==0x1fef || ch==0x1ffd ||
2134 			 ch==0x1fcd || ch==0x1fdd || ch==0x1fce || ch==0x1fde ) )
2135 		    pos = FF_UNICODE_ABOVE|FF_UNICODE_LEFT;
2136 		else if ( isupper(basech) && ch==0x1fbe )
2137 		    pos = FF_UNICODE_RIGHT;
2138 		else if ( ch==0x1fcd || ch==0x1fdd || ch==0x1fce || ch==0x1fde ||
2139 			 ch==0x1ffe || ch==0x1fbf || ch==0x1fcf || ch==0x1fdf ||
2140 			 ch==0x384 )
2141 		    pos = FF_UNICODE_ABOVE;
2142 	    } else if ( (basech==0x1ffe || basech==0x1fbf) && (ch==0x301 || ch==0x300))
2143 		pos = FF_UNICODE_RIGHT;
2144 	    else if ( sc->unicodeenc==0x1fbe && ch==0x345 )
2145 		pos = FF_UNICODE_RIGHT;
2146 	    else if ( basech=='l' && ch==0xb7 )
2147 		pos = FF_UNICODE_RIGHT|FF_UNICODE_OVERSTRIKE;
2148 	    else if ( basech=='L' && ch==0xb7 )
2149 		pos = FF_UNICODE_OVERSTRIKE;
2150 	    else if ( ch==0xb7 )
2151 		pos = FF_UNICODE_RIGHT;
2152 	    else if ( basech=='A' && ch==0x30a )	/* Aring usually touches */
2153 		pos = FF_UNICODE_ABOVE|FF_UNICODE_TOUCHING;
2154 	    else if (( basech=='A' || basech=='a' || basech=='E' || basech=='u' ) &&
2155 		    ch == 0x328 )
2156 		pos = FF_UNICODE_BELOW|FF_UNICODE_CENTERRIGHT|FF_UNICODE_TOUCHING;	/* ogonek off to the right for these in polish (but not lc e) */
2157 	    else if (( basech=='N' || basech=='n' || basech=='K' || basech=='k' || basech=='R' || basech=='r' || basech=='H' || basech=='h' ) &&
2158 		    ch == 0x327 )
2159 		pos = FF_UNICODE_BELOW|FF_UNICODE_CENTERLEFT|FF_UNICODE_TOUCHING;	/* cedilla off under left stem for these guys */
2160 	    if ( basech==0x391 && pos==(FF_UNICODE_ABOVE|FF_UNICODE_LEFT) ) {
2161 		bb.minx += (bb.maxx-bb.minx)/4;
2162 	    }
2163 	}
2164 	if ( sc->unicodeenc==0x0149 )
2165 	    pos = FF_UNICODE_ABOVE|FF_UNICODE_LEFT;
2166 	else if ( sc->unicodeenc==0x013d || sc->unicodeenc==0x013e )
2167 	    pos = FF_UNICODE_ABOVE|FF_UNICODE_RIGHT;
2168 	else if ( sc->unicodeenc==0x010f || sc->unicodeenc==0x013d ||
2169 		  sc->unicodeenc==0x013e || sc->unicodeenc==0x0165 )
2170 	    pos = FF_UNICODE_ABOVE|FF_UNICODE_RIGHT;
2171 	else if ( (sc->unicodeenc==0x1fbd || sc->unicodeenc==0x1fbf ||
2172 		sc->unicodeenc==0x1ffe || sc->unicodeenc==0x1fc0 ) &&
2173 		bb.maxy==0 && bb.miny==0 ) {
2174 	    /* Building accents on top of space */
2175 	    bb.maxy = 7*sf->ascent/10;
2176 	}
2177 
2178 	if ( (pos & FF_UNICODE_ABOVE) && (pos & (FF_UNICODE_LEFT|FF_UNICODE_RIGHT)) )
2179 	    yoff = bb.maxy - rbb.maxy;
2180 	else if ( pos & FF_UNICODE_ABOVE ) {
2181 	    yoff = bb.maxy - rbb.miny;
2182 	    if ( !( pos & FF_UNICODE_TOUCHING) )
2183 		yoff += spacing;
2184 	} else if ( pos & FF_UNICODE_BELOW ) {
2185 	    yoff = bb.miny - rbb.maxy;
2186 	    if ( !( pos & FF_UNICODE_TOUCHING) )
2187 		yoff -= spacing;
2188 	} else if ( pos & FF_UNICODE_OVERSTRIKE )
2189 	    yoff = bb.miny - rbb.miny + ((bb.maxy-bb.miny)-(rbb.maxy-rbb.miny))/2;
2190 	else /* If neither Above, Below, nor overstrike then should use the same baseline */
2191 	    yoff = bb.miny - rbb.miny;
2192 
2193 	if ( pos & (FF_UNICODE_ABOVE|FF_UNICODE_BELOW) ) {
2194 	    /* When we center an accent above an asymetric character like "C" we */
2195 	    /*  should not pick the mid point of the char. Rather we should pick */
2196 	    /*  the highest point (mostly anyway, there are exceptions) */
2197 	    if ( pos & FF_UNICODE_ABOVE ) {
2198 		static DBounds pointless;
2199 		if ( CharCenterHighest ) {
2200 		    if ( basech!='b' && basech!='d' && basech!='h' && basech!='n' && basech!='r' && basech!=0xf8 &&
2201 			    basech!='B' && basech!='D' && basech!='L' && basech!=0xd8 )
2202 			ybase = SCFindTopXRange(sc,layer,&bb);
2203 		    if ( ((basech=='h' && ch==0x307) ||	/* dot over the stem in hdot */
2204 			    basech=='i' || basech=='j' || basech==0x131 || basech==0xf6be || basech==0x237 ||
2205 			    (basech=='k' && ch==0x301) ||
2206 			    (baserch=='L' && (ch==0x301 || ch==0x304)) ||
2207 			    basech=='l' || basech=='t' ) &&
2208 			    (xoff=SCStemCheck(sf,layer,basech,&bb,&pointless,pos))!=0x70000000 )
2209 			bb.minx = bb.maxx = xoff;		/* While on "t" we should center over the stem */
2210 		}
2211 	    } else if ( ( pos & FF_UNICODE_BELOW ) && !eta )
2212 		if ( CharCenterHighest )
2213 		    ybase = SCFindBottomXRange(sc,layer,&bb,ia);
2214 	}
2215 
2216 	if ( isupper(basech) && ch==0x342)	/* While this guy rides above PSILI on left */
2217 	    xoff = bb.minx - rbb.minx;
2218 	else if ( pos & FF_UNICODE_LEFT )
2219 	    xoff = bb.minx - spacing - rbb.maxx;
2220 	else if ( pos & FF_UNICODE_RIGHT ) {
2221 	    xoff = bb.maxx - rbb.minx+spacing/2;
2222 	    if ( !( pos & FF_UNICODE_TOUCHING) )
2223 		xoff += spacing;
2224 	} else {
2225 	    if ( (pos & (FF_UNICODE_CENTERLEFT|FF_UNICODE_CENTERRIGHT)) &&
2226 		    (xoff=SCStemCheck(sf,layer,basech,&bb,&rbb,pos))!=0x70000000 )
2227 		/* Done */;
2228 	    else if ( pos & FF_UNICODE_CENTERLEFT )
2229 		xoff = bb.minx + (bb.maxx-bb.minx)/2 - rbb.maxx;
2230 	    else if ( pos & FF_UNICODE_LEFTEDGE )
2231 		xoff = bb.minx - rbb.minx;
2232 	    else if ( pos & FF_UNICODE_CENTERRIGHT )
2233 		xoff = bb.minx + (bb.maxx-bb.minx)/2 - rbb.minx;
2234 	    else if ( pos & FF_UNICODE_RIGHTEDGE )
2235 		xoff = bb.maxx - rbb.maxx;
2236 	    else
2237 		xoff = bb.minx - rbb.minx + ((bb.maxx-bb.minx)-(rbb.maxx-rbb.minx))/2;
2238 	}
2239 	if ( ia!=0 )
2240 	    xoff += (italicoff = tan(-ia)*(rbb.miny+yoff-ybase));
2241     }	/* Anchor points */
2242     transform[4] = xoff;
2243     /*if ( invert ) transform[5] -= yoff; else */transform[5] += yoff;
2244 
2245     if ( bdf == NULL || !disp_only ) {
2246 	_SCAddRef(sc,rsc,layer,transform);
2247 	if ( pos != FF_UNICODE_NOPOSDATAGIVEN && (pos & FF_UNICODE_RIGHT) )
2248 	    SCSynchronizeWidth(sc,sc->width + rbb.maxx-rbb.minx+spacing,sc->width,NULL);
2249 	if ( pos != FF_UNICODE_NOPOSDATAGIVEN && (pos & (FF_UNICODE_LEFT|FF_UNICODE_RIGHT|FF_UNICODE_CENTERLEFT|FF_UNICODE_LEFTEDGE|FF_UNICODE_CENTERRIGHT|FF_UNICODE_RIGHTEDGE)) )
2250 	    TurnOffUseMyMetrics(sc);
2251     }
2252     if ( !disp_only ) {
2253 	for ( bdf=sf->cidmaster?sf->cidmaster->bitmaps:sf->bitmaps; bdf!=NULL; bdf=bdf->next ) {
2254 	    if ( bdf->glyphs[rsc->orig_pos] != NULL )
2255 		_BCCenterAccent( bdf,sc->orig_pos,rsc->orig_pos,ch,basech,italicoff,pos,sf->ascent+sf->descent );
2256 	}
2257     } else if ( bdf != NULL && bdf->glyphs[rsc->orig_pos] != NULL )
2258 	_BCCenterAccent( bdf,sc->orig_pos,rsc->orig_pos,ch,basech,italicoff,pos,sf->ascent+sf->descent );
2259 }
2260 
SCCenterAccent(SplineChar * sc,SplineChar * basersc,SplineFont * sf,int layer,int ch,BDFFont * bdf,int disp_only,real ia,int basech,char * dot)2261 static void SCCenterAccent(SplineChar *sc,SplineChar *basersc, SplineFont *sf,
2262 	int layer, int ch, BDFFont *bdf,int disp_only,
2263 	real ia, int basech, char *dot ) {
2264     int invert = false;			/* invert accent, false==0, true!=0 */
2265     SplineChar *rsc = GetGoodAccentGlyph(sf,ch,basech,&invert,ia,dot,sc);
2266 
2267     /* find a location to put an accent on this character */
2268     _SCCenterAccent(sc,basersc,sf,layer,ch,bdf,disp_only,rsc,ia,basech,invert,FF_UNICODE_NOPOSDATAGIVEN);
2269 }
2270 
_BCPutRefAfter(BDFFont * bdf,int gid,int rgid,int normal,int under)2271 static void _BCPutRefAfter( BDFFont *bdf,int gid,int rgid,int normal,int under ) {
2272     BDFChar *bc, *rbc;
2273     int ispacing;
2274 
2275     if ( bdf->glyphs[rgid]!=NULL && bdf->glyphs[gid]!=NULL ) {
2276 	rbc = bdf->glyphs[rgid];
2277 	bc = bdf->glyphs[gid];
2278 	BCFlattenFloat(rbc);
2279 	BCCompressBitmap(rbc);
2280 	BCCompressBitmap(bc);
2281 	if ( (ispacing = (bdf->pixelsize*accent_offset+50)/100)<=1 ) ispacing = 2;
2282 	if ( normal ) {
2283 	    BCAddReference( bc,rbc,rgid,bc->width,0 );
2284 	    bc->width += rbc->width;
2285 	} else if ( under ) {
2286 	    BCAddReference( bc,rbc,rgid,
2287 		    (bc->xmax+rbc->xmin-rbc->xmax-rbc->xmin)/2,
2288 		    bc->ymin-ispacing-rbc->ymax );
2289 	} else {
2290 	    BCAddReference( bc,rbc,rgid,bc->xmax-ispacing-rbc->xmin,0 );
2291 	}
2292     }
2293 }
2294 
SCPutRefAfter(SplineChar * sc,SplineFont * sf,int layer,int ch,BDFFont * bdf,int disp_only,char * dot)2295 static void SCPutRefAfter(SplineChar *sc,SplineFont *sf,int layer, int ch,
2296 	BDFFont *bdf,int disp_only, char *dot) {
2297     SplineChar *rsc = SFGetChar(sf,ch,NULL);
2298     int full = sc->unicodeenc, normal = false, under = false/*, stationary=false*/;
2299     DBounds bb, rbb;
2300     real spacing = (sf->ascent+sf->descent)*accent_offset/100;
2301     char buffer[300], namebuf[300];
2302 
2303     if ( bdf == NULL || !disp_only ) {
2304 	if ( dot!=NULL && rsc!=NULL ) {
2305 	    snprintf(buffer,sizeof(buffer),"%s%s", rsc->name, dot );
2306 	    rsc = SFGetChar(sf,-1,buffer);
2307 	} else if ( dot!=NULL ) {
2308 	    snprintf(buffer,sizeof(buffer),"%s%s",
2309 		    (char *) StdGlyphName(namebuf,ch,sf->uni_interp,sf->for_new_glyphs),
2310 		    dot);
2311 	    rsc = SFGetChar(sf,-1,buffer);
2312 	}
2313 
2314 	if ( full<0x1100 || full>0x11ff ) {
2315 	    SCAddRef(sc,rsc,layer,sc->width,0);
2316 	    sc->width += rsc->width;
2317 	    normal = true;
2318     /* these two jamo (same consonant really) ride underneath (except sometimes) */
2319     /* So should the jungsong */
2320 	} else if (( ch==0x110b && (full!=0x1135 && full!=0x1147 && full!=0x114d)) ||
2321 		    (ch==0x11bc && full!=0x11ee) ||
2322 		    full==0x1182 || full==0x1183 || full==0x1187 || (full==0x118b && ch==0x1173) ||
2323 		    full==0x118d || full==0x1193 || (full>=0x1195 && full<=0x1197) ||
2324 		    full==0x119d || full==0x11a0 ) {
2325 	    SplineCharQuickBounds(sc,&bb);
2326 	    SplineCharQuickBounds(rsc,&rbb);
2327 	    SCAddRef(sc,rsc,layer,(bb.maxx+bb.minx)/2-(rbb.maxx+rbb.minx)/2,bb.miny-spacing-rbb.maxy);
2328 	    under = true;
2329 	} else {	/* Jamo should snuggle right up to one another, and ignore the width */
2330 	    SplineCharQuickBounds(sc,&bb);
2331 	    SplineCharQuickBounds(rsc,&rbb);
2332 	    SCAddRef(sc,rsc,layer,bb.maxx+spacing-rbb.minx,0);
2333 	}
2334     }
2335     if ( !disp_only ) {
2336 	for ( bdf=sf->cidmaster?sf->cidmaster->bitmaps:sf->bitmaps; bdf!=NULL; bdf=bdf->next ) {
2337 	    _BCPutRefAfter( bdf,sc->orig_pos,rsc->orig_pos,normal,under );
2338 	}
2339     } else if ( bdf != NULL )
2340 	_BCPutRefAfter( bdf,sc->orig_pos,rsc->orig_pos,normal,under );
2341 }
2342 
BCMakeSpace(BDFFont * bdf,int gid,int width,int em)2343 static void BCMakeSpace(BDFFont *bdf, int gid, int width, int em) {
2344     BDFChar *bc;
2345 
2346     if ( (bc = bdf->glyphs[gid])==NULL ) {
2347 	BDFMakeGID( bdf,gid );
2348     } else {
2349 	BCPreserveState(bc);
2350 	BCFlattenFloat(bc);
2351 	BCCompressBitmap(bc);
2352 	free(bc->bitmap);
2353 	bc->xmin = 0;
2354 	bc->xmax = 1;
2355 	bc->ymin = 0;
2356 	bc->ymax = 1;
2357 	bc->bytes_per_line = 1;
2358 	bc->width = rint(width*bdf->pixelsize/(real) em);
2359 	bc->bitmap = calloc(bc->bytes_per_line*(bc->ymax-bc->ymin+1),sizeof(uint8));
2360     }
2361 }
2362 
DoSpaces(SplineFont * sf,SplineChar * sc,int layer,BDFFont * bdf,int disp_only)2363 static void DoSpaces(SplineFont *sf,SplineChar *sc,int layer,BDFFont *bdf,int disp_only) {
2364     int width;
2365     int uni = sc->unicodeenc;
2366     int em = sf->ascent+sf->descent;
2367     SplineChar *tempsc;
2368 
2369     if ( iszerowidth(uni))
2370 	width = 0;
2371     else switch ( uni ) {
2372       case 0x2000: case 0x2002:
2373 	width = em/2;
2374       break;
2375       case 0x2001: case 0x2003:
2376 	width = em;
2377       break;
2378       case 0x2004:
2379 	width = em/3;
2380       break;
2381       case 0x2005:
2382 	width = em/4;
2383       break;
2384       case 0x2006:
2385 	width = em/6;
2386       break;
2387       case 0x2009:
2388 	width = em/10;
2389       break;
2390       case 0x200a:
2391 	width = em/100;
2392       break;
2393       case 0x2007:
2394 	tempsc = SFGetChar(sf,'0',NULL);
2395 	if ( tempsc!=NULL && tempsc->layers[layer].splines==NULL && tempsc->layers[layer].refs==NULL ) tempsc = NULL;
2396 	if ( tempsc==NULL ) width = em/2; else width = tempsc->width;
2397       break;
2398       case 0x2008:
2399 	tempsc = SFGetChar(sf,'.',NULL);
2400 	if ( tempsc!=NULL && tempsc->layers[layer].splines==NULL && tempsc->layers[layer].refs==NULL ) tempsc = NULL;
2401 	if ( tempsc==NULL ) width = em/4; else width = tempsc->width;
2402       break;
2403       case ' ':
2404 	tempsc = SFGetChar(sf,'I',NULL);
2405 	if ( tempsc!=NULL && tempsc->layers[layer].splines==NULL && tempsc->layers[layer].refs==NULL ) tempsc = NULL;
2406 	if ( tempsc==NULL ) width = em/4; else width = tempsc->width;
2407       break;
2408       default:
2409 	width = em/3;
2410       break;
2411     }
2412 
2413     if ( !disp_only || bdf == NULL ) {
2414 	sc->width = width;
2415 	sc->widthset = true;
2416 	SCCharChangedUpdate(sc,ly_none);
2417     }
2418 
2419     if ( !disp_only ) {
2420 	for ( bdf=sf->cidmaster?sf->cidmaster->bitmaps:sf->bitmaps; bdf!=NULL; bdf=bdf->next ) {
2421 	    BCMakeSpace( bdf,sc->orig_pos,width,em );
2422 	    BCCharChangedUpdate(bdf->glyphs[sc->orig_pos]);
2423 	}
2424     } else if ( bdf != NULL ) {
2425 	BCMakeSpace( bdf,sc->orig_pos,width,em );
2426 	BCCharChangedUpdate(bdf->glyphs[sc->orig_pos]);
2427     }
2428 }
2429 
MakeSP(real x,real y,SplinePoint * last,int order2)2430 static SplinePoint *MakeSP(real x, real y, SplinePoint *last,int order2) {
2431     SplinePoint *new = chunkalloc(sizeof(SplinePoint));
2432 
2433     new->me.x = x; new->me.y = y;
2434     new->prevcp = new->nextcp = new->me;
2435     new->noprevcp = new->nonextcp = true;
2436     new->pointtype = pt_corner;
2437     if ( last!=NULL )
2438 	SplineMake(last,new,order2);
2439 return( new );
2440 }
2441 
BCMakeRule(BDFFont * bdf,int gid,int layer)2442 static void BCMakeRule(BDFFont *bdf, int gid, int layer) {
2443     BDFChar *bc, *tempbc;
2444 
2445     if ( (bc = bdf->glyphs[gid])==NULL ) {
2446 	BDFMakeGID(bdf,gid);
2447     } else {
2448 	BCPreserveState(bc);
2449 	BCFlattenFloat(bc);
2450 	BCCompressBitmap(bc);
2451 	free(bc->bitmap);
2452 	tempbc = SplineCharRasterize(bc->sc,layer,bdf->pixelsize);
2453 	bc->xmin = tempbc->xmin;
2454 	bc->xmax = tempbc->xmax;
2455 	bc->ymin = tempbc->ymin;
2456 	bc->ymax = tempbc->ymax;
2457 	bc->bytes_per_line = tempbc->bytes_per_line;
2458 	bc->width = tempbc->width;
2459 	bc->bitmap = tempbc->bitmap;
2460 	free(tempbc);
2461     }
2462 }
2463 
DoRules(SplineFont * sf,SplineChar * sc,int layer,BDFFont * bdf,int disp_only)2464 static void DoRules(SplineFont *sf,SplineChar *sc,int layer,BDFFont *bdf,int disp_only) {
2465     int width;
2466     int uni = sc->unicodeenc;
2467     int em = sf->ascent+sf->descent;
2468     SplineChar *tempsc;
2469     DBounds b;
2470     real lbearing, rbearing, height, ypos;
2471     SplinePoint *first, *sp;
2472 
2473     switch ( uni ) {
2474       case '-':
2475 	width = em/3;
2476       break;
2477       case 0x2010: case 0x2011:
2478 	tempsc = SFGetChar(sf,'-',NULL);
2479 	if ( tempsc!=NULL && tempsc->layers[layer].splines==NULL && tempsc->layers[layer].refs==NULL ) tempsc = NULL;
2480 	if ( tempsc==NULL ) width = (4*em)/10; else width = tempsc->width;
2481       break;
2482       case 0x2012:
2483 	tempsc = SFGetChar(sf,'0',NULL);
2484 	if ( tempsc!=NULL && tempsc->layers[layer].splines==NULL && tempsc->layers[layer].refs==NULL ) tempsc = NULL;
2485 	if ( tempsc==NULL ) width = em/2; else width = tempsc->width;
2486       break;
2487       case 0x2013:
2488 	width = em/2;
2489       break;
2490       case 0x2014: case 0x30fc:
2491 	width = em;
2492       break;
2493       case 0x2015:		/* French quotation dash */
2494 	width = 2*em;
2495       break;
2496       default:
2497 	width = em/3;
2498       break;
2499     }
2500 
2501     tempsc = SFGetChar(sf,'-',NULL);
2502     if ( tempsc==NULL || (tempsc->layers[layer].splines==NULL && tempsc->layers[layer].refs==NULL )) {
2503 	height = em/10;
2504 	lbearing = rbearing = em/10;
2505 	if ( lbearing+rbearing>2*width/3 )
2506 	    lbearing = rbearing = width/4;
2507 	ypos = em/4;
2508     } else {
2509 	SplineCharFindBounds(tempsc,&b);
2510 	height = b.maxy-b.miny;
2511 	rbearing = tempsc->width - b.maxx;
2512 	lbearing = b.minx;
2513 	ypos = b.miny;
2514     }
2515     if ( bdf == NULL || !disp_only ) {
2516 	first = sp = MakeSP(lbearing,ypos,NULL,sc->layers[layer].order2);
2517 	sp = MakeSP(lbearing,ypos+height,sp,sc->layers[layer].order2);
2518 	sp = MakeSP(width-rbearing,ypos+height,sp,sc->layers[layer].order2);
2519 	sp = MakeSP(width-rbearing,ypos,sp,sc->layers[layer].order2);
2520 	SplineMake(sp,first,sc->layers[layer].order2);
2521 	sc->layers[layer].splines = chunkalloc(sizeof(SplinePointList));
2522 	sc->layers[layer].splines->first = sc->layers[layer].splines->last = first;
2523 	sc->layers[layer].splines->start_offset = 0;
2524 	sc->width = width;
2525 	sc->widthset = true;
2526 	SCCharChangedUpdate(sc,layer);
2527     }
2528 
2529     if ( !disp_only ) {
2530 	for ( bdf=sf->cidmaster?sf->cidmaster->bitmaps:sf->bitmaps; bdf!=NULL; bdf=bdf->next ) {
2531 	    BCMakeRule( bdf,sc->orig_pos,layer );
2532 	    BCCharChangedUpdate(bdf->glyphs[sc->orig_pos]);
2533 	}
2534     } else if ( bdf != NULL ) {
2535 	BCMakeRule( bdf,sc->orig_pos,layer );
2536 	BCCharChangedUpdate(bdf->glyphs[sc->orig_pos]);
2537     }
2538 }
2539 
BCDoRotation(BDFFont * bdf,int gid)2540 static void BCDoRotation(BDFFont *bdf, int gid) {
2541     BDFChar *from, *to;
2542 
2543     if ( gid>=bdf->glyphcnt || bdf->glyphs[gid]==NULL )
2544 return;
2545     from = bdf->glyphs[gid];
2546     to = BDFMakeGID(bdf,gid);
2547     BCRotateCharForVert(to,from,bdf);
2548     BCCharChangedUpdate(to);
2549 }
2550 
DoRotation(SplineFont * sf,SplineChar * sc,int layer,BDFFont * bdf,int disp_only)2551 static void DoRotation(SplineFont *sf,SplineChar *sc,int layer,BDFFont *bdf,int disp_only) {
2552     /* In when laying CJK characters vertically and intermixed latin (greek,etc) */
2553     /*  characters need to be rotated. Adobe's cid tables call for some */
2554     /*  pre-rotated characters, so we might as well be prepared to deal with */
2555     /*  them. Note the rotated and normal characters are often in different */
2556     /*  subfonts so we can't use references */
2557     SplineChar *scbase;
2558     real transform[6];
2559     SplineSet *last, *temp;
2560     RefChar *ref;
2561     char *end;
2562     int j,cid;
2563 
2564     if ( sf->cidmaster!=NULL && strncmp(sc->name,"vertcid_",8)==0 ) {
2565 	cid = strtol(sc->name+8,&end,10);
2566 	if ( *end!='\0' || (j=SFHasCID(sf,cid))==-1)
2567 return;		/* Can't happen */
2568 	scbase = sf->cidmaster->subfonts[j]->glyphs[cid];
2569     } else if ( sf->cidmaster!=NULL && strstr(sc->name,".vert")!=NULL &&
2570 	    (cid = CIDFromName(sc->name,sf->cidmaster))!= -1 ) {
2571 	if ( (j=SFHasCID(sf,cid))==-1)
2572 return;		/* Can't happen */
2573 	scbase = sf->cidmaster->subfonts[j]->glyphs[cid];
2574     } else {
2575 	if ( strncmp(sc->name,"vertuni",7)==0 && strlen(sc->name)==11 ) {
2576 	    char *end;
2577 	    int uni = strtol(sc->name+7,&end,16);
2578 	    if ( *end!='\0' || (cid = SFCIDFindExistingChar(sf,uni,NULL))==-1 )
2579 return;		/* Can't happen */
2580 	} else if ( strncmp(sc->name,"uni",3)==0 && strstr(sc->name,".vert")!=NULL ) {
2581 	    int uni = strtol(sc->name+3,&end,16);
2582 	    if ( *end!='.' || (cid = SFCIDFindExistingChar(sf,uni,NULL))==-1 )
2583 return;
2584 	} else if ( sc->name[0]=='u' && strstr(sc->name,".vert")!=NULL ) {
2585 	    int uni = strtol(sc->name+1,&end,16);
2586 	    if ( *end!='.' || (cid = SFCIDFindExistingChar(sf,uni,NULL))==-1 )
2587 return;
2588 	} else if ( strstr(sc->name,".vert")!=NULL || strstr(sc->name,".vrt2")!=NULL) {
2589 	    char *temp;
2590 	    end = strchr(sc->name,'.');
2591 	    temp = copyn(sc->name,end-sc->name);
2592 	    cid = SFFindExistingSlot(sf,-1,temp);
2593 	    free(temp);
2594 	    if ( cid==-1 )
2595 return;
2596 	}
2597 	if ( sf->cidmaster==NULL )
2598 	    scbase = sf->glyphs[cid];
2599 	else
2600 	    scbase = sf->cidmaster->subfonts[SFHasCID(sf,cid)]->glyphs[cid];
2601     }
2602 
2603     if ( bdf == NULL || !disp_only ) {
2604 	transform[0] = transform[3] = 0;
2605 	transform[1] = -1; transform[2] = 1;
2606 	transform[4] = scbase->parent->descent; transform[5] = /*scbase->parent->vertical_origin*/ scbase->parent->ascent;
2607 
2608 	sc->layers[layer].splines = SplinePointListTransform(SplinePointListCopy(scbase->layers[layer].splines),
2609 		transform, tpt_AllPoints );
2610 	if ( sc->layers[layer].splines==NULL ) last = NULL;
2611 	else for ( last = sc->layers[layer].splines; last->next!=NULL; last = last->next );
2612 
2613 	for ( ref = scbase->layers[layer].refs; ref!=NULL; ref=ref->next ) {
2614 	    temp = SplinePointListTransform(SplinePointListCopy(ref->layers[0].splines),
2615 		transform, tpt_AllPoints );
2616 	    if ( last==NULL )
2617 		sc->layers[layer].splines = temp;
2618 	    else
2619 		last->next = temp;
2620 	    if ( temp!=NULL )
2621 		for ( last=temp; last->next!=NULL; last=last->next );
2622 	}
2623 	sc->width = sc->parent->ascent+sc->parent->descent;
2624 	SCCharChangedUpdate(sc,layer);
2625     }
2626 
2627     if ( !disp_only ) {
2628 	for ( bdf=sf->cidmaster?sf->cidmaster->bitmaps:sf->bitmaps; bdf!=NULL; bdf=bdf->next ) {
2629 	    BCDoRotation( bdf,sc->orig_pos );
2630 	}
2631     } else if ( bdf != NULL ) {
2632 	BCDoRotation( bdf,sc->orig_pos );
2633     }
2634 }
2635 
SCMakeRightToLeftLig(SplineChar * sc,SplineFont * sf,int layer,const unichar_t * start,BDFFont * bdf,int disp_only)2636 static int SCMakeRightToLeftLig(SplineChar *sc,SplineFont *sf,
2637 	int layer, const unichar_t *start,BDFFont *bdf,int disp_only) {
2638     int cnt = u_strlen(start);
2639     int ret=false, ch, alt_ch;
2640     const unichar_t *pt;
2641 
2642     pt = start+cnt-1;
2643     ch = *pt;
2644     if ( ch>=0x621 && ch<=0x6ff ) {
2645 	alt_ch = ArabicForms[ch-0x600].final;
2646 	if ( alt_ch!=0 && haschar(sf,alt_ch,NULL))
2647 	    ch = alt_ch;
2648     }
2649     if ( SCMakeBaseReference(sc,sf,layer,ch,bdf,disp_only) ) {
2650 	for ( --pt; pt>=start; --pt ) {
2651 	    ch = *pt;
2652 	    if ( ch>=0x621 && ch<=0x6ff ) {
2653 		if ( pt==start )
2654 		    alt_ch = ArabicForms[ch-0x600].initial;
2655 		else
2656 		    alt_ch = ArabicForms[ch-0x600].medial;
2657 		if ( alt_ch!=0 && haschar(sf,alt_ch,NULL))
2658 		    ch = alt_ch;
2659 	    }
2660 	    SCPutRefAfter(sc,sf,layer,ch,bdf,disp_only,NULL);
2661 	}
2662 	ret = true;
2663     }
2664 return( ret );
2665 }
2666 
SCBuildHangul(SplineFont * sf,SplineChar * sc,int layer,const unichar_t * pt,BDFFont * bdf,int disp_only)2667 static void SCBuildHangul(SplineFont *sf,SplineChar *sc, int layer, const unichar_t *pt,
2668 	BDFFont *bdf, int disp_only) {
2669     SplineChar *rsc;
2670     int first = true;
2671 
2672     sc->width = 0;
2673     while ( *pt ) {
2674 	rsc = SFGetChar(sf,*pt++,NULL);
2675 	if ( rsc!=NULL ) {
2676 	    if ( bdf == NULL || !disp_only ) {
2677 		SCAddRef(sc,rsc,layer,0,0);
2678 		if ( rsc->width>sc->width ) sc->width = rsc->width;
2679 	    }
2680 	    if ( !disp_only ) {
2681 		for ( bdf=sf->cidmaster?sf->cidmaster->bitmaps:sf->bitmaps; bdf!=NULL; bdf=bdf->next ) {
2682 		    if ( first )
2683 			BCClearAll(bdf->glyphs[sc->orig_pos]);
2684 		    BCAddReference( BDFMakeGID(bdf,sc->orig_pos),bdf->glyphs[rsc->orig_pos],
2685 			rsc->orig_pos,0,0 );
2686 		}
2687 	    } else if ( bdf != NULL ) {
2688 		if ( first )
2689 		    BCClearAll(bdf->glyphs[sc->orig_pos]);
2690 		BCAddReference( BDFMakeGID(bdf,sc->orig_pos),bdf->glyphs[rsc->orig_pos],
2691 		    rsc->orig_pos,0,0 );
2692 	    }
2693 	    first = false;
2694 	}
2695     }
2696 }
2697 
_SCMakeDotless(SplineFont * sf,SplineChar * dotless,int layer,int doit)2698 static int _SCMakeDotless(SplineFont *sf, SplineChar *dotless, int layer, int doit) {
2699     SplineChar *sc, *xsc;
2700     BlueData bd;
2701     SplineSet *head=NULL, *last=NULL, *test, *cur, *next;
2702     DBounds b;
2703 
2704     sc = SFGetChar(sf,dotless->unicodeenc==0x131?'i':'j',NULL);
2705     xsc = SFGetChar(sf,'x',NULL);
2706     if ( sc==NULL || sc->layers[layer].splines==NULL || sc->layers[layer].refs!=NULL || xsc==NULL )
2707 return( false );
2708     QuickBlues(sf,layer,&bd);
2709     if ( bd.xheight==0 )
2710 return(false );
2711     for ( test=sc->layers[layer].splines; test!=NULL; test=test->next ) {
2712 	next = test->next; test->next = NULL;
2713 	SplineSetQuickBounds(test,&b);
2714 	test->next = next;
2715 	if ( b.miny < bd.xheight ) {
2716 	    if ( !doit )
2717 return( true );
2718 	    cur = SplinePointListCopy1(test);
2719 	    if ( last==NULL )
2720 		head = cur;
2721 	    else
2722 		last->next = cur;
2723 	    last = cur;
2724 	}
2725     }
2726     if ( head==NULL )
2727 return( false );
2728 
2729     SCPreserveLayer(dotless,layer,true);
2730     SplinePointListsFree(dotless->layers[layer].splines);
2731     dotless->layers[layer].splines = NULL;
2732     SCRemoveLayerDependents(dotless,layer);
2733     dotless->width = sc->width;
2734     dotless->layers[layer].splines = head;
2735     SCCharChangedUpdate(dotless,layer);
2736 return( true );
2737 }
2738 
SCMakeDotless(SplineFont * sf,SplineChar * dotless,int layer,BDFFont * bdf,int disp_only,int doit)2739 static int SCMakeDotless(SplineFont *sf, SplineChar *dotless, int layer, BDFFont *bdf, int disp_only, int doit) {
2740     SplineChar *sc;
2741     BDFChar *bc;
2742     int ret = 0;
2743 
2744     if ( dotless==NULL )
2745 return( ret );
2746 	if ( dotless->unicodeenc!=0x131 && dotless->unicodeenc!=0xf6be && dotless->unicodeenc!=0x237 )
2747 return( ret );
2748     sc = SFGetChar(sf,dotless->unicodeenc==0x131?'i':'j',NULL);
2749     if ( sc==NULL )
2750 return( ret );
2751     if ( bdf==NULL || !disp_only )
2752 	ret = _SCMakeDotless( sf,dotless,layer,doit );
2753 
2754     if ( !disp_only ) {
2755 	for ( bdf=sf->bitmaps; bdf!=NULL; bdf=bdf->next ) {
2756 	    if (( bc = bdf->glyphs[sc->orig_pos])!=NULL ) {
2757 		BCClearAndCopyBelow(bdf,dotless->orig_pos,sc->orig_pos,BCFindGap(bc));
2758 	    }
2759 	}
2760     } else if ( bdf != NULL ) {
2761 	if (( bc = bdf->glyphs[sc->orig_pos])!=NULL ) {
2762 	    BCClearAndCopyBelow(bdf,dotless->orig_pos,sc->orig_pos,BCFindGap(bc));
2763 	}
2764     }
2765 
2766 return( ret );
2767 }
2768 
SCSetReasonableLBearing(SplineChar * sc,SplineChar * base,int layer)2769 static void SCSetReasonableLBearing(SplineChar *sc,SplineChar *base,int layer) {
2770     DBounds full, b;
2771     SplineFont *sf;
2772     int emsize;
2773     double xoff;
2774     RefChar *ref;
2775     real transform[6];
2776 
2777     /* Hmm. Panov doesn't think this should happen */
2778 return;
2779 
2780     SplineCharLayerFindBounds(sc,layer,&full);
2781     SplineCharLayerFindBounds(base,layer,&b);
2782 
2783     sf = sc->parent;
2784     emsize = sf->ascent+sf->descent;
2785 
2786     /* Now don't get excited if we have a very thin glyph (I in a sans-serif) */
2787     /*  and a centered accent spills off to the left a little */
2788     if ( full.minx>=0 || full.minx>=b.minx || full.minx>=-(emsize/20) )
2789 return;
2790     /* ok. let's say we want an lbearing that's the same as that of the base */
2791     /*  glyph */
2792     xoff = b.minx-full.minx;
2793     memset(transform,0,sizeof(transform));
2794     transform[0] = transform[3] = 1.0;
2795     transform[4] = xoff;
2796     for ( ref=sc->layers[layer].refs; ref!=NULL; ref=ref->next ) {
2797 	ref->bb.minx += xoff; ref->bb.maxx += xoff;
2798 	ref->transform[4] += xoff;
2799 	SplinePointListTransform(ref->layers[0].splines,transform,tpt_AllPoints);
2800     }
2801     SCSynchronizeWidth(sc,sc->width + xoff,sc->width,NULL);
2802 }
2803 
SCUserDecompAccent(SplineChar * sc,unichar_t accent,int accent_hint)2804 int SCUserDecompAccent(SplineChar *sc, unichar_t accent, int accent_hint) {
2805     return (sc->user_decomp != NULL &&
2806             accent != '\0' &&
2807             accent_hint);
2808 }
2809 
SCBuildComposit(SplineFont * sf,SplineChar * sc,int layer,BDFFont * bdf,int disp_only,int accent_hint)2810 void SCBuildComposit(SplineFont *sf, SplineChar *sc, int layer, BDFFont *bdf, int disp_only, int accent_hint) {
2811     const unichar_t *pt, *apt; unichar_t ch;
2812     real ia;
2813     char *dot;
2814     /* This does not handle arabic ligatures at all. It would need to reverse */
2815     /*  the string and deal with <final>, <medial>, etc. info we don't have */
2816 
2817     if ( !SFIsSomethingBuildable(sf,sc,layer,false))
2818 return;
2819     if ( !disp_only || bdf == NULL ) {
2820 	SCPreserveLayer(sc,layer,true);
2821 	SplinePointListsFree(sc->layers[layer].splines);
2822 	sc->layers[layer].splines = NULL;
2823 	SCRemoveLayerDependents(sc,layer);
2824 	sc->width = 0;
2825     }
2826     if ( !disp_only ) {
2827 	for ( bdf=sf->cidmaster?sf->cidmaster->bitmaps:sf->bitmaps; bdf!=NULL; bdf=bdf->next )
2828 	    if ( bdf->glyphs[sc->orig_pos]!=NULL )
2829 		BCClearAll( bdf->glyphs[sc->orig_pos] );
2830     } else if ( bdf!=NULL) {
2831 	if ( bdf->glyphs[sc->orig_pos]!=NULL )
2832 	    BCClearAll( bdf->glyphs[sc->orig_pos] );
2833     }
2834 
2835     if ( iszerowidth(sc->unicodeenc) || (sc->unicodeenc>=0x2000 && sc->unicodeenc<=0x200f )) {
2836 	DoSpaces( sf,sc,layer,bdf,disp_only );
2837 return;
2838     } else if ( sc->unicodeenc>=0x2010 && sc->unicodeenc<=0x2015 ) {
2839 	DoRules( sf,sc,layer,bdf,disp_only );
2840 return;
2841     } else if ( SFIsRotatable(sf,sc) ) {
2842 	DoRotation( sf,sc,layer,bdf,disp_only );
2843 return;
2844     } else if ( sc->unicodeenc==0x131 || sc->unicodeenc==0x237 || sc->unicodeenc==0xf6be ) {
2845 	SCMakeDotless( sf,sc,layer,bdf,disp_only,true );
2846 return;
2847     }
2848 
2849     if (( ia = sf->italicangle )==0 )
2850 	ia = SFGuessItalicAngle(sf);
2851     ia *= FF_PI/180;	/* convert degrees to radians */
2852 
2853     dot = strchr(sc->name,'.');
2854 
2855     pt= SFGetAlternate(sf,sc->unicodeenc,sc,false);
2856     ch = *pt++;
2857     if ( dot==NULL && ( ch=='i' || ch=='j' || ch==0x456 )) {
2858 	/* if we're combining i (or j) with an accent that would interfere */
2859 	/*  with the dot, then get rid of the dot. (use dotlessi) */
2860 	for ( apt = pt; *apt && combiningposmask(*apt) != FF_UNICODE_ABOVE; ++apt);
2861 	if ( *apt!='\0' ) {
2862 	    if ( ch=='i' || ch==0x456 ) ch = 0x0131;
2863 	    else if ( ch=='j' ) {
2864 		if ( haschar(sf,0x237,NULL) ) ch = 0x237;		/* Proposed dotlessj */
2865 		else ch = 0xf6be;				/* Adobe's private use dotless j */
2866 	    }
2867 	}
2868     }
2869     if ( sc->unicodeenc>=0xac00 && sc->unicodeenc<=0xd7a3 )
2870 	SCBuildHangul(sf,sc,layer,pt-1,bdf,disp_only);
2871     else if ( isrighttoleft(ch) && !iscombining(*pt)) {
2872 	SCMakeRightToLeftLig(sc,sf,layer,pt-1,bdf,disp_only);
2873     } else {
2874 	RefChar *base;
2875 	if ( !SCMakeBaseReference(sc,sf,layer,ch,bdf,disp_only) )
2876 return;
2877 	base = sc->layers[layer].refs;
2878 	if ( base==NULL )
2879 	    /* Happens when building glyphs which are themselves marks, like */
2880 	    /* perispomeni which is a tilde over a space, only we don't make */
2881 	    /* a reference to space */;
2882 	else if ( sc->width == base->sc->width )
2883 	    base->use_my_metrics = true;
2884 	while ( iscombining(*pt) || SCUserDecompAccent(sc, *pt, accent_hint) || (ch=='L' && *pt==0xb7) ||	/* b7, centered dot is used as a combining accent for Ldot but as a lig for ldot */
2885 		*pt==0x384 || *pt==0x385 || (*pt>=0x1fbd && *pt<=0x1fff) )	/* Special greek accents */
2886 	    SCCenterAccent(sc,base!=NULL?base->sc:NULL,sf,layer,*pt++,bdf,disp_only,ia,ch,dot);
2887 	while ( *pt ) {
2888 	    if ( base!=NULL ) base->use_my_metrics = false;
2889 	    SCPutRefAfter(sc,sf,layer,*pt++,bdf,disp_only,dot);
2890 	}
2891 	/* All along we assumed the base glyph didn't move. This makes       */
2892 	/* positioning easier. But if we add accents to the left we now want */
2893 	/* to move the glyph so we don't have a negative lbearing */
2894 	if ( base!=NULL )
2895 	    SCSetReasonableLBearing(sc,base->sc,layer);
2896     }
2897     if ( !disp_only || bdf == NULL )
2898 	SCCharChangedUpdate(sc,layer);
2899     if ( !disp_only ) {
2900 	for ( bdf=sf->cidmaster?sf->cidmaster->bitmaps:sf->bitmaps; bdf!=NULL; bdf=bdf->next )
2901 	    if ( bdf->glyphs[sc->orig_pos]!=NULL )
2902 		BCCharChangedUpdate(bdf->glyphs[sc->orig_pos]);
2903     } else if ( bdf != NULL && bdf->glyphs[sc->orig_pos]!=NULL )
2904 	BCCharChangedUpdate(bdf->glyphs[sc->orig_pos]);
2905 return;
2906 }
2907 
SCAppendAccent(SplineChar * sc,int layer,char * glyph_name,int uni,uint32 pos)2908 int SCAppendAccent(SplineChar *sc,int layer,
2909 	char *glyph_name,	/* unicode char name */
2910 	int uni,		/* unicode char value */
2911 	uint32 pos		/* unicode char position info, see #define for (uint32)(utype2[]) */ ) {
2912     SplineFont *sf = sc->parent;
2913     double ia;
2914     int basech;
2915     RefChar *ref, *last=NULL;
2916     int invert = false;		/* invert accent, false==0, true!=0 */
2917     SplineChar *asc;
2918     int i;
2919     const unichar_t *apt, *end;
2920     char *pt;
2921 
2922     for ( ref=sc->layers[layer].refs; ref!=NULL; ref=ref->next )
2923 	last = ref;
2924     if ( last==NULL )
2925 return( 1 );				/* No base character reference found */
2926     basech = last->sc->unicodeenc;
2927 
2928     if (( ia = sf->italicangle )==0 )
2929 	ia = SFGuessItalicAngle(sf);
2930     ia *= FF_PI/180;	/* convert degrees to radians */
2931 
2932     SCPreserveLayer(sc,layer,true);
2933 
2934     asc = SFGetChar(sf,uni,glyph_name);
2935     if ( asc!=NULL && uni==-1 )
2936 	uni = asc->unicodeenc;
2937     else if ( asc==NULL && uni!=-1 )
2938 	asc = GetGoodAccentGlyph(sf,uni,basech,&invert,ia,NULL,sc);
2939     if ( asc==NULL )
2940 return( 2 );				/* Could not find that accent */
2941     if ( uni==-1 && (pt=strchr(asc->name,'.'))!=NULL && pt-asc->name<100 ) {
2942 	char buffer[101];
2943 	strncpy(buffer,asc->name,pt-asc->name);
2944 	buffer[(pt-asc->name)] = '\0';
2945 	uni = UniFromName(buffer,ui_none,NULL);
2946     }
2947 
2948     if ( uni<=BottomAccent || uni>=TopAccent ) {
2949 	/* Find the real combining character that maps to this glyph */
2950 	/* that's where we store positioning info */
2951 	for ( i=BottomAccent; i<=TopAccent; ++i ) {
2952 	    apt = accents[i-BottomAccent]; end = apt+sizeof(accents[0])/sizeof(accents[0][0]);
2953 	    while ( apt<end && *apt!=uni )
2954 		++apt;
2955 	    if ( apt<end ) {
2956 		uni = i;
2957 	break;
2958 	    }
2959 	}
2960     }
2961 
2962     _SCCenterAccent(sc,last->sc,sf,layer,uni,NULL,false,asc,ia,basech,invert,pos);
2963 return( 0 );
2964 }
2965