w32tex
About: TeX Live provides a comprehensive TeX system including all the major TeX-related programs, macro packages, and fonts that are free software. Windows sources.
  Fossies Dox: w32tex-src.tar.xz  ("unofficial" and yet experimental doxygen-generated source code documentation)  

lookups.c
Go to the documentation of this file.
1 /* Copyright (C) 2007,2008 by George Williams */
2 /*
3  * Redistribution and use in source and binary forms, with or without
4  * modification, are permitted provided that the following conditions are met:
5 
6  * Redistributions of source code must retain the above copyright notice, this
7  * list of conditions and the following disclaimer.
8 
9  * Redistributions in binary form must reproduce the above copyright notice,
10  * this list of conditions and the following disclaimer in the documentation
11  * and/or other materials provided with the distribution.
12 
13  * The name of the author may not be used to endorse or promote products
14  * derived from this software without specific prior written permission.
15 
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
17  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
19  * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  */
27 #include "fontforgevw.h"
28 #include <chardata.h>
29 #include <utype.h>
30 #include <ustring.h>
31 #include <math.h>
32 #include <locale.h>
33 #include <stdlib.h>
34 #include "ttf.h"
35 #include "lookups.h"
36 
38 #if 0 /* They get stuffed into the 'MATH' table now */
39 /* I added these first three features to allow round-trip conversion of tfm files */
40  { CHR('I','T','L','C'), "ITLC", N_("Italic Correction"), gpos_single_mask },
41  { CHR('T','C','H','L'), "TCHL", N_("TeX Glyphlist"), gsub_alternate_mask },
42  { CHR('T','E','X','L'), "TEXL", N_("TeX Extension List"), gsub_multiple_mask },
43 #endif
44 /* Normal OpenType features follow */
45  { CHR('a','a','l','t'), "aalt", N_("Access All Alternates"), gsub_single_mask|gsub_alternate_mask },
46  { CHR('a','b','v','f'), "abvf", N_("Above Base Forms"), gsub_single_mask },
47  { CHR('a','b','v','m'), "abvm", N_("Above Base Mark"), gpos_mark2base_mask|gpos_mark2ligature_mask },
48  { CHR('a','b','v','s'), "abvs", N_("Above Base Substitutions"), gsub_ligature_mask },
49  { CHR('a','f','r','c'), "afrc", N_("Vertical Fractions"), gsub_ligature_mask },
50  { CHR('a','k','h','n'), "akhn", N_("Akhand"), gsub_ligature_mask },
51  { CHR('a','l','i','g'), "alig", N_("Ancient Ligatures"), gsub_ligature_mask },
52  { CHR('b','l','w','f'), "blwf", N_("Below Base Forms"), gsub_ligature_mask },
53  { CHR('b','l','w','m'), "blwm", N_("Below Base Mark"), gpos_mark2base_mask|gpos_mark2ligature_mask },
54  { CHR('b','l','w','s'), "blws", N_("Below Base Substitutions"), gsub_ligature_mask },
55  { CHR('c','2','p','c'), "c2pc", N_("Capitals to Petite Capitals"), gsub_single_mask },
56  { CHR('c','2','s','c'), "c2sc", N_("Capitals to Small Capitals"), gsub_single_mask },
57  { CHR('c','a','l','t'), "calt", N_("Contextual Alternates"), gsub_context_mask|gsub_contextchain_mask },
58  { CHR('c','a','s','e'), "case", N_("Case-Sensitive Forms"), gsub_single_mask|gpos_single_mask },
59  { CHR('c','c','m','p'), "ccmp", N_("Glyph Composition/Decomposition"), gsub_multiple_mask|gsub_ligature_mask },
60  { CHR('c','l','i','g'), "clig", N_("Contextual Ligatures"), gsub_reversecchain_mask },
61  { CHR('c','p','c','t'), "cpct", N_("Centered CJK Punctuation"), gpos_single_mask },
62  { CHR('c','p','s','p'), "cpsp", N_("Capital Spacing"), gpos_single_mask },
63  { CHR('c','s','w','h'), "cswh", N_("Contextual Swash"), gsub_reversecchain_mask },
64  { CHR('c','u','r','s'), "curs", N_("Cursive Attachment"), gpos_cursive_mask },
65  { CHR('c','v','0','0'), "cv00", N_("Character Variants 00"), gsub_single_mask },
66  { CHR('c','v','0','1'), "cv01", N_("Character Variants 01"), gsub_single_mask },
67  { CHR('c','v','0','2'), "cv02", N_("Character Variants 02"), gsub_single_mask },
68  { CHR('c','v','0','3'), "cv03", N_("Character Variants 03"), gsub_single_mask },
69  { CHR('c','v','0','4'), "cv04", N_("Character Variants 04"), gsub_single_mask },
70  { CHR('c','v','0','5'), "cv05", N_("Character Variants 05"), gsub_single_mask },
71  { CHR('c','v','0','6'), "cv06", N_("Character Variants 06"), gsub_single_mask },
72  { CHR('c','v','0','7'), "cv07", N_("Character Variants 07"), gsub_single_mask },
73  { CHR('c','v','0','8'), "cv08", N_("Character Variants 08"), gsub_single_mask },
74  { CHR('c','v','0','9'), "cv09", N_("Character Variants 09"), gsub_single_mask },
75  { CHR('c','v','1','0'), "cv10", N_("Character Variants 10"), gsub_single_mask },
76  { CHR('c','v','9','9'), "cv99", N_("Character Variants 99"), gsub_single_mask },
77  { CHR('d','c','a','p'), "dcap", N_("Drop Caps"), gsub_single_mask },
78  { CHR('d','i','s','t'), "dist", N_("Distance"), gpos_pair_mask },
79  { CHR('d','l','i','g'), "dlig", N_("Discretionary Ligatures"), gsub_ligature_mask },
80  { CHR('d','n','o','m'), "dnom", N_("Denominators"), gsub_single_mask },
81  { CHR('d','p','n','g'), "dpng", N_("Dipthongs (Obsolete)"), gsub_ligature_mask },
82  { CHR('e','x','p','t'), "expt", N_("Expert Forms"), gsub_single_mask },
83  { CHR('f','a','l','t'), "falt", N_("Final Glyph On Line"), gsub_alternate_mask },
84  { CHR('f','i','n','2'), "fin2", N_("Terminal Forms #2"), gsub_context_mask|gsub_contextchain_mask },
85  { CHR('f','i','n','3'), "fin3", N_("Terminal Forms #3"), gsub_context_mask|gsub_contextchain_mask },
86  { CHR('f','i','n','a'), "fina", N_("Terminal Forms"), gsub_single_mask },
87  { CHR('f','l','a','c'), "flac", N_("Flattened Accents over Capitals"), gsub_single_mask|gsub_ligature_mask },
88  { CHR('f','r','a','c'), "frac", N_("Diagonal Fractions"), gsub_single_mask|gsub_ligature_mask },
89  { CHR('f','w','i','d'), "fwid", N_("Full Widths"), gsub_single_mask|gpos_single_mask },
90  { CHR('h','a','l','f'), "half", N_("Half Forms"), gsub_ligature_mask },
91  { CHR('h','a','l','n'), "haln", N_("Halant Forms"), gsub_ligature_mask },
92  { CHR('h','a','l','t'), "halt", N_("Alternative Half Widths"), gpos_single_mask },
93  { CHR('h','i','s','t'), "hist", N_("Historical Forms"), gsub_single_mask },
94  { CHR('h','k','n','a'), "hkna", N_("Horizontal Kana Alternatives"), gsub_single_mask },
95  { CHR('h','l','i','g'), "hlig", N_("Historic Ligatures"), gsub_ligature_mask },
96  { CHR('h','n','g','l'), "hngl", N_("Hanja to Hangul"), gsub_single_mask|gsub_alternate_mask },
97  { CHR('h','o','j','o'), "hojo", N_("Hojo (JIS X 0212-1990) Kanji Forms"), gsub_single_mask },
98  { CHR('h','w','i','d'), "hwid", N_("Half Widths"), gsub_single_mask|gpos_single_mask },
99  { CHR('i','n','i','t'), "init", N_("Initial Forms"), gsub_single_mask },
100  { CHR('i','s','o','l'), "isol", N_("Isolated Forms"), gsub_single_mask },
101  { CHR('i','t','a','l'), "ital", N_("Italics"), gsub_single_mask },
102  { CHR('j','a','l','t'), "jalt", N_("Justification Alternatives"), gsub_alternate_mask },
103  { CHR('j','a','j','p'), "jajp", N_("Japanese Forms (Obsolete"), gsub_single_mask|gsub_alternate_mask },
104  { CHR('j','p','7','8'), "jp78", N_("JIS78 Forms"), gsub_single_mask|gsub_alternate_mask },
105  { CHR('j','p','8','3'), "jp83", N_("JIS83 Forms"), gsub_single_mask },
106  { CHR('j','p','9','0'), "jp90", N_("JIS90 Forms"), gsub_single_mask },
107  { CHR('k','e','r','n'), "kern", N_("Horizontal Kerning"), gpos_pair_mask|gpos_context_mask|gpos_contextchain_mask },
108  { CHR('l','f','b','d'), "lfbd", N_("Left Bounds"), gpos_single_mask },
109  { CHR('l','i','g','a'), "liga", N_("Standard Ligatures"), gsub_ligature_mask },
110  { CHR('l','j','m','o'), "ljmo", N_("Leading Jamo Forms"), gsub_ligature_mask },
111  { CHR('l','n','u','m'), "lnum", N_("Lining Figures"), gsub_single_mask },
112  { CHR('l','o','c','l'), "locl", N_("Localized Forms"), gsub_single_mask },
113  { CHR('m','a','r','k'), "mark", N_("Mark Positioning"), gpos_mark2base_mask|gpos_mark2ligature_mask },
114  { CHR('m','e','d','2'), "med2", N_("Medial Forms 2"), gsub_context_mask|gsub_contextchain_mask },
115  { CHR('m','e','d','i'), "medi", N_("Medial Forms"), gsub_single_mask },
116  { CHR('m','g','r','k'), "mgrk", N_("Mathematical Greek"), gsub_single_mask },
117  { CHR('m','k','m','k'), "mkmk", N_("Mark to Mark"), gpos_mark2mark_mask },
118  { CHR('m','s','e','t'), "mset", N_("Mark Positioning via Substitution"), gsub_context_mask|gsub_contextchain_mask },
119  { CHR('n','a','l','t'), "nalt", N_("Alternate Annotation Forms"), gsub_single_mask|gsub_alternate_mask },
120  { CHR('n','u','k','t'), "nukt", N_("Nukta Forms"), gsub_ligature_mask },
121  { CHR('n','u','m','r'), "numr", N_("Numerators"), gsub_single_mask },
122  { CHR('o','n','u','m'), "onum", N_("Oldstyle Figures"), gsub_single_mask },
123  { CHR('o','p','b','d'), "opbd", N_("Optical Bounds"), gpos_single_mask },
124  { CHR('o','r','d','n'), "ordn", N_("Ordinals"), gsub_ligature_mask|gsub_context_mask|gsub_contextchain_mask },
125  { CHR('o','r','n','m'), "ornm", N_("Ornaments"), gsub_single_mask|gsub_alternate_mask },
126  { CHR('p','a','l','t'), "palt", N_("Proportional Alternate Metrics"), gpos_single_mask },
127  { CHR('p','c','a','p'), "pcap", N_("Lowercase to Petite Capitals"), gsub_single_mask },
128  { CHR('p','k','n','a'), "pkna", N_("Proportional Kana"), gpos_single_mask },
129  { CHR('p','n','u','m'), "pnum", N_("Proportional Numbers"), gsub_single_mask },
130  { CHR('p','r','e','f'), "pref", N_("Pre Base Forms"), gsub_ligature_mask },
131  { CHR('p','r','e','s'), "pres", N_("Pre Base Substitutions"), gsub_ligature_mask|gsub_context_mask|gsub_contextchain_mask },
132  { CHR('p','s','t','f'), "pstf", N_("Post Base Forms"), gsub_ligature_mask },
133  { CHR('p','s','t','s'), "psts", N_("Post Base Substitutions"), gsub_ligature_mask },
134  { CHR('p','w','i','d'), "pwid", N_("Proportional Width"), gsub_single_mask },
135  { CHR('q','w','i','d'), "qwid", N_("Quarter Widths"), gsub_single_mask|gpos_single_mask },
136  { CHR('r','a','n','d'), "rand", N_("Randomize"), gsub_alternate_mask },
137  { CHR('r','k','r','f'), "rkrf", N_("Rakar Forms"), gsub_ligature_mask },
138  { CHR('r','l','i','g'), "rlig", N_("Required Ligatures"), gsub_ligature_mask },
139  { CHR('r','p','h','f'), "rphf", N_("Reph Form"), gsub_ligature_mask },
140  { CHR('r','t','b','d'), "rtbd", N_("Right Bounds"), gpos_single_mask },
141  { CHR('r','t','l','a'), "rtla", N_("Right to Left Alternates"), gsub_single_mask },
142  { CHR('r','u','b','y'), "ruby", N_("Ruby Notational Forms"), gsub_single_mask },
143  { CHR('s','a','l','t'), "salt", N_("Stylistic Alternatives"), gsub_single_mask|gsub_alternate_mask },
144  { CHR('s','i','n','f'), "sinf", N_("Scientific Inferiors"), gsub_single_mask },
145  { CHR('s','m','c','p'), "smcp", N_("Lowercase to Small Capitals"), gsub_single_mask },
146  { CHR('s','m','p','l'), "smpl", N_("Simplified Forms"), gsub_single_mask },
147  { CHR('s','s','0','1'), "ss01", N_("Style Set 1"), gsub_single_mask },
148  { CHR('s','s','0','2'), "ss02", N_("Style Set 2"), gsub_single_mask },
149  { CHR('s','s','0','3'), "ss03", N_("Style Set 3"), gsub_single_mask },
150  { CHR('s','s','0','4'), "ss04", N_("Style Set 4"), gsub_single_mask },
151  { CHR('s','s','0','5'), "ss05", N_("Style Set 5"), gsub_single_mask },
152  { CHR('s','s','0','6'), "ss06", N_("Style Set 6"), gsub_single_mask },
153  { CHR('s','s','0','7'), "ss07", N_("Style Set 7"), gsub_single_mask },
154  { CHR('s','s','0','8'), "ss08", N_("Style Set 8"), gsub_single_mask },
155  { CHR('s','s','0','9'), "ss09", N_("Style Set 9"), gsub_single_mask },
156  { CHR('s','s','1','0'), "ss10", N_("Style Set 10"), gsub_single_mask },
157  { CHR('s','s','1','1'), "ss11", N_("Style Set 11"), gsub_single_mask },
158  { CHR('s','s','1','2'), "ss12", N_("Style Set 12"), gsub_single_mask },
159  { CHR('s','s','1','3'), "ss13", N_("Style Set 13"), gsub_single_mask },
160  { CHR('s','s','1','4'), "ss14", N_("Style Set 14"), gsub_single_mask },
161  { CHR('s','s','1','5'), "ss15", N_("Style Set 15"), gsub_single_mask },
162  { CHR('s','s','1','6'), "ss16", N_("Style Set 16"), gsub_single_mask },
163  { CHR('s','s','1','7'), "ss17", N_("Style Set 17"), gsub_single_mask },
164  { CHR('s','s','1','8'), "ss18", N_("Style Set 18"), gsub_single_mask },
165  { CHR('s','s','1','9'), "ss19", N_("Style Set 19"), gsub_single_mask },
166  { CHR('s','s','2','0'), "ss20", N_("Style Set 20"), gsub_single_mask },
167  { CHR('s','s','t','y'), "ssty", N_("Script Style"), gsub_single_mask },
168  { CHR('s','u','b','s'), "subs", N_("Subscript"), gsub_single_mask },
169  { CHR('s','u','p','s'), "sups", N_("Superscript"), gsub_single_mask },
170  { CHR('s','w','s','h'), "swsh", N_("Swash"), gsub_single_mask|gsub_alternate_mask },
171  { CHR('t','i','t','l'), "titl", N_("Titling"), gsub_single_mask },
172  { CHR('t','j','m','o'), "tjmo", N_("Trailing Jamo Forms"), gsub_ligature_mask },
173  { CHR('t','n','a','m'), "tnam", N_("Traditional Name Forms"), gsub_single_mask },
174  { CHR('t','n','u','m'), "tnum", N_("Tabular Numbers"), gsub_single_mask },
175  { CHR('t','r','a','d'), "trad", N_("Traditional Forms"), gsub_single_mask|gsub_alternate_mask },
176  { CHR('t','w','i','d'), "twid", N_("Third Widths"), gsub_single_mask|gpos_single_mask },
177  { CHR('u','n','i','c'), "unic", N_("Unicase"), gsub_single_mask },
178  { CHR('v','a','l','t'), "valt", N_("Alternate Vertical Metrics"), gpos_single_mask },
179  { CHR('v','a','t','u'), "vatu", N_("Vattu Variants"), gsub_ligature_mask },
180  { CHR('v','e','r','t'), "vert", N_("Vertical Alternates (obs)"), gsub_single_mask },
181  { CHR('v','h','a','l'), "vhal", N_("Alternate Vertical Half Metrics"), gpos_single_mask },
182  { CHR('v','j','m','o'), "vjmo", N_("Vowel Jamo Forms"), gsub_ligature_mask },
183  { CHR('v','k','n','a'), "vkna", N_("Vertical Kana Alternates"), gsub_single_mask },
184  { CHR('v','k','r','n'), "vkrn", N_("Vertical Kerning"), gpos_pair_mask|gpos_context_mask|gpos_contextchain_mask },
185  { CHR('v','p','a','l'), "vpal", N_("Proportional Alternate Vertical Metrics"), gpos_single_mask },
186  { CHR('v','r','t','2'), "vrt2", N_("Vertical Rotation & Alternates"), gsub_single_mask },
187  { CHR('z','e','r','o'), "zero", N_("Slashed Zero"), gsub_single_mask },
188 /* This is my hack for setting the "Required feature" field of a script */
190  { 0, NULL, 0, 0 }
191 };
192 
193 static int uint32_cmp(const void *_ui1, const void *_ui2) {
194  if ( *(uint32 *) _ui1 > *(uint32 *)_ui2 )
195 return( 1 );
196  if ( *(uint32 *) _ui1 < *(uint32 *)_ui2 )
197 return( -1 );
198 
199 return( 0 );
200 }
201 
202 static int lang_cmp(const void *_ui1, const void *_ui2) {
203  /* The default language is magic, and should come first in the list even */
204  /* if that is not true alphabetical order */
205  if ( *(uint32 *) _ui1 == DEFAULT_LANG )
206 return( -1 );
207  if ( *(uint32 *) _ui2 == DEFAULT_LANG )
208 return( 1 );
209 
210  if ( *(uint32 *) _ui1 > *(uint32 *)_ui2 )
211 return( 1 );
212  if ( *(uint32 *) _ui1 < *(uint32 *)_ui2 )
213 return( -1 );
214 
215 return( 0 );
216 }
217 
219 
220  while ( fl!=NULL ) {
221  if ( fl->featuretag==tag )
222 return( fl );
223  fl = fl->next;
224  }
225 return( NULL );
226 }
227 
229 
230  while ( fl!=NULL ) {
231  if ( fl->featuretag==tag )
232 return( true );
233  fl = fl->next;
234  }
235 return( false );
236 }
237 
239  struct scriptlanglist *sl;
240 
241  if ( fl==NULL ) /* No features bound to lookup? (nested?) don't restrict by script */
242 return( true );
243 
244  while ( fl!=NULL ) {
245  for ( sl=fl->scripts; sl!=NULL; sl=sl->next ) {
246  if ( sl->script == script )
247 return( true );
248  }
249  fl = fl->next;
250  }
251 return( false );
252 }
253 
255  struct scriptlanglist *sl;
256 
257  while ( fl!=NULL ) {
258  if ( fl->featuretag == feature ) {
259  for ( sl=fl->scripts; sl!=NULL; sl=sl->next ) {
260  if ( sl->script == script )
261 return( true );
262  }
263  }
264  fl = fl->next;
265  }
266 return( false );
267 }
268 
270  int l;
271 
272  for ( l=0; l<sl->lang_cnt; ++l ) {
273  uint32 lang = l<MAX_LANG ? sl->langs[l] : sl->morelangs[l-MAX_LANG];
274  if ( lang==DEFAULT_LANG )
275 return( true );
276  }
277 return( false );
278 }
279 
280 struct scriptlanglist *DefaultLangTagInScriptList(struct scriptlanglist *sl, int DFLT_ok) {
281 
282  while ( sl!=NULL ) {
283  if ( DFLT_ok || sl->script!=DEFAULT_SCRIPT ) {
285 return( sl );
286  }
287  sl = sl->next;
288  }
289 return( NULL );
290 }
291 
293  /* Presumes that either SFFindUnusedLookups or SFFindClearUnusedLookupBits */
294  /* has been called first */
295  /* Since MS will sometimes ignore a script if it isn't found in both */
296  /* GPOS and GSUB we want to return the same script list no matter */
297  /* what the setting of gpos ... so we totally ignore that argument */
298  /* and always look at both sets of lookups */
299 
300 /* Sergey Malkin from MicroSoft tells me:
301  Each shaping engine in Uniscribe can decide on its requirements for
302  layout tables - some of them require both GSUB and GPOS, in some cases
303  any table present is enough, or it can work without any table.
304 
305  Sometimes, purpose of the check is to determine if font is supporting
306  particular script - if required tables are not there font is just
307  rejected by this shaping engine. Sometimes, shaping engine can not just
308  reject the font because there are fonts using older shaping technologies
309  we still have to support, so it uses some logic when to fallback to
310  legacy layout code.
311 
312  In your case this is Hebrew, where both tables are required to use
313  OpenType processing. Arabic requires both tables too, Latin requires
314  GSUB to execute GPOS. But in general, if you have both tables you should
315  be safe with any script to get fully featured OpenType shaping.
316 
317 In other words, if we have a Hebrew font with just GPOS features they won't work,
318 and MS will not use the font at all. We must add a GSUB table. In the unlikely
319 event that we had a hebrew font with only GSUB it would not work either.
320 
321 So if we want our lookups to have a chance of executing under Uniscribe we
322 better make sure that both tables have the same script set.
323 
324 (Sergey says we could optimize a little: A Latin GSUB table will run without
325 a GPOS, but he says the GPOS won't work without a GSUB.)
326 */
327  int cnt=0, tot=0, i;
328  uint32 *scripts = NULL;
329  OTLookup *test;
331  struct scriptlanglist *sl;
332 
333  /* So here always give scripts for both (see comment above) no */
334  /* matter what they asked for */
335  for ( gpos=0; gpos<2; ++gpos ) {
336  for ( test = gpos ? sf->gpos_lookups : sf->gsub_lookups; test!=NULL; test = test->next ) {
337  if ( test->unused )
338  continue;
339  for ( fl=test->features; fl!=NULL; fl=fl->next ) {
340  for ( sl=fl->scripts ; sl!=NULL; sl=sl->next ) {
341  for ( i=0; i<cnt; ++i ) {
342  if ( sl->script==scripts[i] )
343  break;
344  }
345  if ( i==cnt ) {
346  if ( cnt>=tot )
347  scripts = grealloc(scripts,(tot+=10)*sizeof(uint32));
348  scripts[cnt++] = sl->script;
349  }
350  }
351  }
352  }
353  }
354 
355  if ( cnt==0 )
356 return( NULL );
357 
358  /* We want our scripts in alphabetic order */
359  qsort(scripts,cnt,sizeof(uint32),uint32_cmp);
360  /* add a 0 entry to mark the end of the list */
361  if ( cnt>=tot )
362  scripts = grealloc(scripts,(tot+1)*sizeof(uint32));
363  scripts[cnt] = 0;
364 return( scripts );
365 }
366 
368  /* However, the language lists (I think) are distinct */
369  /* But giving a value of -1 for gpos will give us the set of languages in */
370  /* both tables (for this script) */
371  int cnt=0, tot=0, i, g, l;
372  uint32 *langs = NULL;
373  OTLookup *test;
375  struct scriptlanglist *sl;
376 
377  for ( g=0; g<2; ++g ) {
378  if (( gpos==0 && g==1 ) || ( gpos==1 && g==0 ))
379  continue;
380  for ( test = gpos ? sf->gpos_lookups : sf->gsub_lookups; test!=NULL; test = test->next ) {
381  if ( test->unused )
382  continue;
383  for ( fl=test->features; fl!=NULL; fl=fl->next ) {
384  for ( sl=fl->scripts ; sl!=NULL; sl=sl->next ) {
385  if ( sl->script==script ) {
386  for ( l=0; l<sl->lang_cnt; ++l ) {
387  unsigned lang;
388  if ( l<MAX_LANG )
389  lang = sl->langs[l];
390  else
391  lang = sl->morelangs[l-MAX_LANG];
392  for ( i=0; i<cnt; ++i ) {
393  if ( lang==langs[i] )
394  break;
395  }
396  if ( i==cnt ) {
397  if ( cnt>=tot )
398  langs = grealloc(langs,(tot+=10)*sizeof(uint32));
399  langs[cnt++] = lang;
400  }
401  }
402  }
403  }
404  }
405  }
406  }
407 
408  if ( cnt==0 ) {
409  /* We add dummy script entries. Because Uniscribe will refuse to */
410  /* process some scripts if they don't have an entry in both GPOS */
411  /* an GSUB. So if a script appears in either table, force it to */
412  /* appear in both. That means we can get scripts with no lookups */
413  /* and hence no languages. It seems that Uniscribe doesn't like */
414  /* that either. So give each such script a dummy default language */
415  /* entry. This is what VOLT does */
416  langs = gcalloc(2,sizeof(uint32));
417  langs[0] = DEFAULT_LANG;
418 return( langs );
419  }
420 
421  /* We want our languages in alphabetic order */
422  qsort(langs,cnt,sizeof(uint32),lang_cmp);
423  /* add a 0 entry to mark the end of the list */
424  if ( cnt>=tot )
425  langs = grealloc(langs,(tot+1)*sizeof(uint32));
426  langs[cnt] = 0;
427 return( langs );
428 }
429 
431  int cnt=0, tot=0, i, l, isg;
432  uint32 *features = NULL;
433  OTLookup *test;
435  struct scriptlanglist *sl;
436  /* gpos==0 => GSUB, gpos==1 => GPOS, gpos==-1 => both, gpos==-2 => Both & kern */
437 
438  if ( sf->cidmaster ) sf=sf->cidmaster;
439  for ( isg = 0; isg<2; ++isg ) {
440  if ( gpos>=0 && isg!=gpos )
441  continue;
442  for ( test = isg ? sf->gpos_lookups : sf->gsub_lookups; test!=NULL; test = test->next ) {
443  if ( test->unused )
444  continue;
445  for ( fl=test->features; fl!=NULL; fl=fl->next ) {
446  if ( script==0xffffffff ) {
447  for ( i=0; i<cnt; ++i ) {
448  if ( fl->featuretag==features[i] )
449  break;
450  }
451  if ( i==cnt ) {
452  if ( cnt>=tot )
453  features = grealloc(features,(tot+=10)*sizeof(uint32));
454  features[cnt++] = fl->featuretag;
455  }
456  } else for ( sl=fl->scripts ; sl!=NULL; sl=sl->next ) {
457  if ( sl->script==script ) {
458  int matched = false;
459  for ( l=0; l<sl->lang_cnt; ++l ) {
460  unsigned testlang;
461  if ( l<MAX_LANG )
462  testlang = sl->langs[l];
463  else
464  testlang = sl->morelangs[l-MAX_LANG];
465  if ( testlang==lang ) {
466  matched = true;
467  break;
468  }
469  }
470  if ( matched ) {
471  for ( i=0; i<cnt; ++i ) {
472  if ( fl->featuretag==features[i] )
473  break;
474  }
475  if ( i==cnt ) {
476  if ( cnt>=tot )
477  features = grealloc(features,(tot+=10)*sizeof(uint32));
478  features[cnt++] = fl->featuretag;
479  }
480  }
481  }
482  }
483  }
484  }
485  }
486 
487  if ( sf->design_size!=0 && gpos ) {
488  /* The 'size' feature is like no other. It has no lookups and so */
489  /* we will never find it in the normal course of events. If the */
490  /* user has specified a design size, then every script/lang combo */
491  /* gets a 'size' feature which contains no lookups but feature */
492  /* params */
493  if ( cnt>=tot )
494  features = grealloc(features,(tot+=2)*sizeof(uint32));
495  features[cnt++] = CHR('s','i','z','e');
496  }
497 
498  if ( cnt==0 )
499 return( gcalloc(1,sizeof(uint32)) );
500 
501  /* We don't care if our features are in alphabetical order here */
502  /* all that matters is whether the complete list of features is */
503  /* ordering here would be irrelevant */
504  /* qsort(features,cnt,sizeof(uint32),uint32_cmp); */
505 
506  /* add a 0 entry to mark the end of the list */
507  if ( cnt>=tot )
508  features = grealloc(features,(tot+1)*sizeof(uint32));
509  features[cnt] = 0;
510 return( features );
511 }
512 
514  int cnt=0, tot=0, l;
515  OTLookup **lookups = NULL;
516  OTLookup *test;
518  struct scriptlanglist *sl;
519 
520  for ( test = gpos ? sf->gpos_lookups : sf->gsub_lookups; test!=NULL; test = test->next ) {
521  if ( test->unused )
522  continue;
523  for ( fl=test->features; fl!=NULL; fl=fl->next ) {
524  if ( fl->featuretag==feature ) {
525  for ( sl=fl->scripts ; sl!=NULL; sl=sl->next ) {
526  if ( sl->script==script ) {
527  for ( l=0; l<sl->lang_cnt; ++l ) {
528  unsigned testlang;
529  if ( l<MAX_LANG )
530  testlang = sl->langs[l];
531  else
532  testlang = sl->morelangs[l-MAX_LANG];
533  if ( testlang==lang ) {
534  if ( cnt>=tot )
535  lookups = grealloc(lookups,(tot+=10)*sizeof(OTLookup *));
536  lookups[cnt++] = test;
537  goto found;
538  }
539  }
540  }
541  }
542  }
543  }
544  found:;
545  }
546 
547  if ( cnt==0 )
548 return( NULL );
549 
550  /* lookup order is irrelevant here. might as well leave it in invocation order */
551  /* add a 0 entry to mark the end of the list */
552  if ( cnt>=tot )
553  lookups = grealloc(lookups,(tot+1)*sizeof(OTLookup *));
554  lookups[cnt] = 0;
555 return( lookups );
556 }
557 
558 static int LigaturesFirstComponentGID(SplineFont *sf,char *components) {
559  int gid, ch;
560  char *pt;
561 
562  for ( pt = components; *pt!='\0' && *pt!=' '; ++pt );
563  ch = *pt; *pt = '\0';
564  gid = SFFindExistingSlot(sf,-1,components);
565  *pt = ch;
566 return( gid );
567 }
568 
569 static int PSTValid(SplineFont *sf,PST *pst) {
570  char *start, *pt, ch;
571  int ret;
572  (void)sf;
573  switch ( pst->type ) {
574  case pst_position:
575 return( true );
576  case pst_pair:
577 return( SCWorthOutputting(SFGetChar(sf,-1,pst->u.pair.paired)) );
579  case pst_ligature:
580  for ( start = pst->u.mult.components; *start ; ) {
581  for ( pt=start; *pt && *pt!=' '; ++pt );
582  ch = *pt; *pt = '\0';
584  *pt = ch;
585  if ( !ret )
586 return( false );
587  if ( ch==0 )
588  start = pt;
589  else
590  start = pt+1;
591  }
592  }
593 return( true );
594 }
595 
597  uint8 *used = gcalloc(sf->glyphcnt,sizeof(uint8));
598  SplineChar **glyphs, *sc;
599  int i, k, gid, cnt;
600  KernPair *kp;
601  PST *pst;
602  int ispair = subtable->lookup->lookup_type == gpos_pair;
603  int isliga = subtable->lookup->lookup_type == gsub_ligature;
604  sc = NULL;
605  for ( i=0; i<sf->glyphcnt; ++i ) if ( SCWorthOutputting(sc = sf->glyphs[i]) ) {
606  if ( ispair ) {
607  for ( k=0; k<2; ++k ) {
608  for ( kp= k ? sc->kerns : sc->vkerns; kp!=NULL ; kp=kp->next ) {
609  if ( !SCWorthOutputting(kp->sc))
610  continue;
611  if ( kp->subtable == subtable ) {
612  used[i] = true;
613  goto continue_;
614  }
615  }
616  }
617  }
618  for ( pst=sc->possub; pst!=NULL; pst=pst->next ) {
619  if ( pst->subtable == subtable && PSTValid(sf,pst)) {
620  if ( !isliga ) {
621  used[i] = true;
622  goto continue_;
623  } else {
624  gid = LigaturesFirstComponentGID(sf,pst->u.lig.components);
625  pst->u.lig.lig = sc;
626  if ( gid!=-1 )
627  used[gid] = true;
628  /* can't continue here. ffi might be "f+f+i" and "ff+i" */
629  /* and we need to mark both "f" and "ff" as used */
630  }
631  }
632  }
633  continue_: ;
634  }
635 
636  for ( i=cnt=0 ; i<sf->glyphcnt; ++i )
637  if ( used[i] )
638  ++cnt;
639 
640  if ( cnt==0 ) {
641  free(used);
642 return( NULL );
643  }
644  glyphs = galloc((cnt+1)*sizeof(SplineChar *));
645  for ( i=cnt=0 ; i<sf->glyphcnt; ++i ) {
646  if ( used[i] )
647  glyphs[cnt++] = sf->glyphs[i];
648  }
649  glyphs[cnt] = NULL;
650  free(used);
651 return( glyphs );
652 }
653 
655  uint8 *used = gcalloc(sf->glyphcnt,sizeof(uint8));
656  SplineChar **glyphs, *sc;
657  int i, cnt;
658  PST *pst;
659  sc=NULL;
660  /* for ( i=0; i<sf->glyphcnt; ++i ) if ( SCWorthOutputting(sc = sf->glyphs[i]) ) { */
661  /* for ( pst=sc->possub; pst!=NULL; pst=pst->next ) { */
662  /* if ( pst->subtable == subtable ) { */
663  /* used[i] = true; */
664  /* goto continue_; */
665  /* } */
666  /* } */
667  /* continue_: ; */
668  /* } */
669  /* Issue 866 : currently #define SCWorthOutputting(a) 1 so we drop it */
670  for ( i=0; i<sf->glyphcnt; ++i ) {
671  sc = sf->glyphs[i];
672  if ( sc ) {
673  for ( pst=sc->possub; pst!=NULL; pst=pst->next ) {
674  if ( pst->subtable == subtable ) {
675  used[i] = true;
676  goto continue_;
677  }
678  }
679  continue_: ;
680  }/* end if ( sc ) */
681  }/*end for */
682 
683  for ( i=cnt=0 ; i<sf->glyphcnt; ++i )
684  if ( used[i] )
685  ++cnt;
686 
687  if ( cnt==0 ) {
688  free(used);
689 return( NULL );
690  }
691 
692  glyphs = galloc((cnt+1)*sizeof(SplineChar *));
693  for ( i=cnt=0 ; i<sf->glyphcnt; ++i ) {
694  if ( used[i] )
695  glyphs[cnt++] = sf->glyphs[i];
696  }
697  glyphs[cnt] = NULL;
698  free(used);
699 return( glyphs );
700 }
701 
703  OTLookup *test;
704  struct lookup_subtable *sub;
705  int gpos;
706  AnchorClass *ac;
707  AnchorPoint *ap;
708  SplineChar *sc;
709  KernPair *kp;
710  PST *pst;
711  int k,gid,isv;
712  SplineFont *_sf = sf;
713  sc=NULL;
714  if ( _sf->cidmaster ) _sf = _sf->cidmaster;
715 
716  /* Some things are obvious. If a subtable consists of a kernclass or some */
717  /* such, then obviously it is used. But more distributed info takes more */
718  /* work. So mark anything easy as used, and anything difficult as unused */
719  /* We'll work on the difficult things later */
720  for ( gpos=0; gpos<2; ++gpos ) {
721  for ( test = gpos ? _sf->gpos_lookups : _sf->gsub_lookups; test!=NULL; test = test->next ) {
722  for ( sub = test->subtables; sub!=NULL; sub=sub->next ) {
723  if ( sub->kc!=NULL || sub->fpst!=NULL ) {
724  sub->unused = false;
725  continue;
726  }
727  sub->unused = true;
728  /* We'll turn the following bit back on if there turns out */
729  /* to be an anchor class attached to it -- that is subtly */
730  /* different than being unused -- unused will be set if all */
731  /* acs are unused, this bit will be on if there are unused */
732  /* classes that still refer to us. */
733  sub->anchor_classes = false;
734  }
735  }
736  }
737 
738  /* To be useful an anchor class must have both at least one base and one mark */
739  /* (for cursive anchors that means at least one entry and at least one exit) */
740  /* Start by assuming the worst */
741  for ( ac = _sf->anchor; ac!=NULL; ac=ac->next )
742  ac->has_mark = ac->has_base = false;
743 
744  /* Ok, for each glyph, look at all lookups (or anchor classes) it affects */
745  /* and mark the appropriate parts of them as used */
746  k = 0;
747  do {
748  sf = _sf->subfontcnt==0 ? _sf : _sf->subfonts[k];
749  for ( gid=0; gid<sf->glyphcnt; ++gid ) if ( SCWorthOutputting(sc = sf->glyphs[gid]) ) {
750  for ( ap=sc->anchor; ap!=NULL; ap=ap->next ) {
751  switch ( ap->type ) {
752  case at_mark: case at_centry:
753  ap->anchor->has_mark = true;
754  break;
755  case at_basechar: case at_baselig: case at_basemark:
756  case at_cexit:
757  ap->anchor->has_base = true;
758  break;
759  }
760  }
761  for ( isv=0; isv<2; ++isv ) {
762  for ( kp= isv ? sc->kerns : sc->vkerns ; kp!=NULL; kp=kp->next ) {
763  if ( SCWorthOutputting(kp->sc))
764  kp->subtable->unused = false;
765  }
766  }
767  for ( pst=sc->possub; pst!=NULL; pst=pst->next ) {
768  if ( pst->subtable==NULL )
769  continue;
770  if ( !PSTValid(sf,pst))
771  continue;
772  pst->subtable->unused = false;
773  }
774  }
775  ++k;
776  } while ( k<_sf->subfontcnt );
777 
778  /* Finally for any anchor class that has both a mark and a base then it is */
779  /* used, and its lookup is also used */
780  /* Also, even if unused, as long as the anchor class exists we must keep */
781  /* the subtable around */
782  for ( ac = _sf->anchor; ac!=NULL; ac=ac->next ) {
783  ac->subtable->anchor_classes = true;
784  if ( ac->has_mark && ac->has_base )
785  ac->subtable->unused = false;
786  }
787 
788  /* Now for each lookup, a lookup is unused if ALL subtables are unused */
789  for ( gpos=0; gpos<2; ++gpos ) {
790  for ( test = gpos ? _sf->gpos_lookups : _sf->gsub_lookups; test!=NULL; test = test->next ) {
791  test->unused = test->empty = true;
792  for ( sub=test->subtables; sub!=NULL; sub=sub->next ) {
793  if ( !sub->unused )
794  test->unused = false;
795  if ( !sub->unused && !sub->anchor_classes ) {
796  test->empty = false;
797  break;
798  }
799  }
800  }
801  }
802 }
803 
805  OTLookup *test;
806  int gpos;
807 
808  for ( gpos=0; gpos<2; ++gpos ) {
809  for ( test = gpos ? sf->gpos_lookups : sf->gsub_lookups; test!=NULL; test = test->next ) {
810  test->unused = false;
811  test->empty = false;
812  test->def_lang_checked = false;
813  }
814  }
815 }
816 
818  int gid;
819  SplineChar *sc;
820  AnchorPoint *ap, *prev, *next;
821 
822  for ( gid=0; gid<sf->glyphcnt; ++gid ) if ( (sc = sf->glyphs[gid])!=NULL ) {
823  for ( prev=NULL, ap=sc->anchor; ap!=NULL; ap=next ) {
824  next = ap->next;
825  if ( ap->anchor!=ac )
826  prev = ap;
827  else {
828  if ( prev==NULL )
829  sc->anchor = next;
830  else
831  prev->next = next;
832  ap->next = NULL;
834  }
835  }
836  }
837 }
838 
839 static void RemoveNestedReferences(SplineFont *sf,int isgpos,OTLookup *dying) {
840  OTLookup *otl;
841  struct lookup_subtable *sub;
842  int i,j,k;
843  (void)dying;
844  for ( otl = isgpos ? sf->gpos_lookups : sf->gsub_lookups; otl!=NULL; otl = otl->next ) {
845  /* Reverse chaining tables do not reference lookups. The match pattern*/
846  /* is a (exactly one) coverage table, and each glyph in that table */
847  /* as an inline replacement. There is no lookup to do the replacement*/
848  /* (so we ignore it here) */
851  for ( sub=otl->subtables; sub!=NULL; sub=sub->next ) {
852  FPST *fpst = sub->fpst;
853  for ( i=0; i<fpst->rule_cnt; ++i ) {
854  for ( j=0; j<fpst->rules[i].lookup_cnt; ++j ) {
855  if ( fpst->rules[i].lookups[j].lookup == otl ) {
856  for ( k=j+1; k<fpst->rules[i].lookup_cnt; ++k )
857  fpst->rules[i].lookups[k-1] = fpst->rules[i].lookups[k];
858  --fpst->rules[i].lookup_cnt;
859  --j;
860  }
861  }
862  }
863  }
864  }
865  }
866 }
867 
869  int remove_incomplete_anchorclasses,
870  int remove_unused_lookups) {
871  int gpos;
872  struct lookup_subtable *sub, *subnext, *prev;
873  AnchorClass *ac, *acprev, *acnext;
874  OTLookup *otl, *otlprev, *otlnext;
875  otlprev=NULL;
876  /* Presumes someone has called SFFindUnusedLookups first */
877 
878  if ( remove_incomplete_anchorclasses ) {
879  for ( acprev=NULL, ac=sf->anchor; ac!=NULL; ac=acnext ) {
880  acnext = ac->next;
881  if ( ac->has_mark && ac->has_base )
882  acprev = ac;
883  else {
885  ac->next = NULL;
886  AnchorClassesFree(ac);
887  if ( acprev==NULL )
888  sf->anchor = acnext;
889  else
890  acprev = acnext;
891  }
892  }
893  }
894 
895  for ( gpos=0; gpos<2; ++gpos ) {
896  for ( otl = gpos ? sf->gpos_lookups : sf->gsub_lookups; otl!=NULL; otl = otlnext ) {
897  otlnext = otl->next;
898  if ( remove_unused_lookups && (otl->empty ||
899  (otl->unused && remove_incomplete_anchorclasses)) ) {
900  if ( otlprev!=NULL )
901  otlprev->next = otlnext;
902  else if ( gpos )
903  sf->gpos_lookups = otlnext;
904  else
905  sf->gsub_lookups = otlnext;
906  RemoveNestedReferences(sf,gpos,otl);
907  OTLookupFree(otl);
908  } else {
909  for ( prev=NULL, sub=otl->subtables; sub!=NULL; sub=subnext ) {
910  subnext = sub->next;
911  if ( sub->unused &&
912  (!sub->anchor_classes ||
913  remove_incomplete_anchorclasses )) {
914  if ( prev==NULL )
915  otl->subtables = subnext;
916  else
917  prev->next = subnext;
918  free(sub->subtable_name);
919  chunkfree(sub,sizeof(*sub));
920  } else
921  prev = sub;
922  }
923  }
924  }
925  }
926 }
927 
929  OTLookup *otl = sub->lookup;
930  struct lookup_subtable *subprev, *subtest;
931 
932  if ( sf->cidmaster!=NULL ) sf = sf->cidmaster;
933 
934  if ( sub->fpst!=NULL ) {
935  FPST *prev = NULL, *test;
936  for ( test=sf->possub; test!=NULL && test!=sub->fpst; prev=test, test=test->next );
937  if ( prev==NULL )
938  sf->possub = sub->fpst->next;
939  else
940  prev->next = sub->fpst->next;
941  sub->fpst->next = NULL;
942  FPSTFree(sub->fpst);
943  sub->fpst = NULL;
944  } else if ( sub->kc!=NULL ) {
945  KernClass *prev = NULL, *test;
946  for ( test=sf->kerns; test!=NULL && test!=sub->kc; prev=test, test=test->next );
947  if ( test!=NULL ) {
948  if ( prev==NULL )
949  sf->kerns = sub->kc->next;
950  else
951  prev->next = sub->kc->next;
952  } else {
953  for ( prev=NULL,test=sf->vkerns; test!=NULL && test!=sub->kc; prev=test, test=test->next );
954  if ( prev==NULL )
955  sf->vkerns = sub->kc->next;
956  else
957  prev->next = sub->kc->next;
958  }
959  sub->kc->next = NULL;
960  KernClassListFree(sub->kc);
961  sub->kc = NULL;
962  } else if ( otl->lookup_type==gpos_cursive || otl->lookup_type==gpos_mark2base ||
964  AnchorClass *ac, *acnext;
965  for ( ac=sf->anchor; ac!=NULL; ac=acnext ) {
966  acnext = ac->next;
967  if ( ac->subtable==sub )
969  }
970  } else {
971  int i,k,v;
972  SplineChar *sc;
973  SplineFont *_sf;
974  PST *pst, *prev, *next;
975  KernPair *kp, *kpprev, *kpnext;
976  k=0; i=0;
977  do {
978  _sf = sf->subfontcnt==0 ? sf : sf->subfonts[i];
979  for ( i=0; i<_sf->glyphcnt; ++i ) if ( (sc=_sf->glyphs[i])!=NULL ) {
980  for ( pst=sc->possub, prev=NULL ; pst!=NULL; pst=next ) {
981  next = pst->next;
982  if ( pst->subtable==sub ) {
983  if ( prev==NULL )
984  sc->possub = next;
985  else
986  prev->next = next;
987  pst->next = NULL;
988  PSTFree(pst);
989  } else
990  prev = pst;
991  }
992  for ( v=0; v<2; ++v ) {
993  for ( kp=v ? sc->vkerns : sc->kerns, kpprev=NULL ; kp!=NULL; kp=kpnext ) {
994  kpnext = kp->next;
995  if ( kp->subtable==sub ) {
996  if ( kpprev!=NULL )
997  kpprev->next = kpnext;
998  else if ( v )
999  sc->vkerns = kpnext;
1000  else
1001  sc->kerns = kpnext;
1002  kp->next = NULL;
1003  KernPairsFree(kp);
1004  } else
1005  kpprev = kp;
1006  }
1007  }
1008  }
1009  ++k;
1010  } while ( k<sf->subfontcnt );
1011  }
1012 
1013  subprev = NULL;
1014  for ( subtest = otl->subtables; subtest!=NULL && subtest!=sub; subprev = subtest, subtest=subtest->next );
1015  if ( subprev==NULL )
1016  otl->subtables = sub->next;
1017  else
1018  subprev->next = sub->next;
1019  free(sub->subtable_name);
1020  free(sub->suffix);
1021  chunkfree(sub,sizeof(struct lookup_subtable));
1022 }
1023 
1025  OTLookup *test, *prev;
1026  int isgpos;
1027  struct lookup_subtable *sub, *subnext;
1028 
1029  if ( sf->cidmaster ) sf = sf->cidmaster;
1030 
1031  for ( sub = otl->subtables; sub!=NULL; sub=subnext ) {
1032  subnext = sub->next;
1034  }
1035 
1036  for ( prev=NULL, test=sf->gpos_lookups; test!=NULL && test!=otl; prev=test, test=test->next );
1037  if ( test==NULL ) {
1038  isgpos = false;
1039  for ( prev=NULL, test=sf->gsub_lookups; test!=NULL && test!=otl; prev=test, test=test->next );
1040  } else
1041  isgpos = true;
1042  if ( prev!=NULL )
1043  prev->next = otl->next;
1044  else if ( isgpos )
1045  sf->gpos_lookups = otl->next;
1046  else
1047  sf->gsub_lookups = otl->next;
1048 
1049  RemoveNestedReferences(sf,isgpos,otl);
1050 
1051  otl->next = NULL;
1052  OTLookupFree(otl);
1053 }
1054 
1056  int isgpos;
1057  OTLookup *otl;
1058  struct lookup_subtable *sub;
1059 
1060  if ( sf->cidmaster ) sf = sf->cidmaster;
1061 
1062  if ( name==NULL )
1063 return( NULL );
1064 
1065  for ( isgpos=0; isgpos<2; ++isgpos ) {
1066  for ( otl = isgpos ? sf->gpos_lookups : sf->gsub_lookups ; otl!=NULL; otl=otl->next ) {
1067  for ( sub = otl->subtables; sub!=NULL; sub=sub->next ) {
1068  if ( strcmp(name,sub->subtable_name)==0 )
1069 return( sub );
1070  }
1071  }
1072  }
1073 return( NULL );
1074 }
1075 
1078  free(name);
1079 return( sub );
1080 }
1081 
1083  int isgpos;
1084  OTLookup *otl;
1085 
1086  if ( sf->cidmaster ) sf = sf->cidmaster;
1087 
1088  if ( name==NULL )
1089 return( NULL );
1090 
1091  for ( isgpos=0; isgpos<2; ++isgpos ) {
1092  for ( otl = isgpos ? sf->gpos_lookups : sf->gsub_lookups ; otl!=NULL; otl=otl->next ) {
1093  if ( strcmp(name,otl->lookup_name)==0 )
1094 return( otl );
1095  }
1096  }
1097 return( NULL );
1098 }
1099 
1101  struct scriptlanglist *sl;
1102  int l;
1103 
1104  for ( sl = fl->scripts; sl!=NULL && sl->script!=script_tag; sl=sl->next );
1105  if ( sl==NULL ) {
1106  sl = chunkalloc(sizeof(struct scriptlanglist));
1107  sl->script = script_tag;
1108  sl->next = fl->scripts;
1109  fl->scripts = sl;
1110  }
1111  for ( l=0; l<MAX_LANG && l<sl->lang_cnt && sl->langs[l]!=lang_tag; ++l );
1112  if ( l>=MAX_LANG && l<sl->lang_cnt ) {
1113  while ( l<sl->lang_cnt && sl->morelangs[l-MAX_LANG]!=lang_tag )
1114  ++l;
1115  }
1116  if ( l>=sl->lang_cnt ) {
1117  if ( l<MAX_LANG )
1118  sl->langs[l] = lang_tag;
1119  else {
1120  if ( l%MAX_LANG == 0 )
1121  sl->morelangs = grealloc(sl->morelangs,l*sizeof(uint32));
1122  /* We've just allocated MAX_LANG-1 more than we need */
1123  /* so we don't do quite some many allocations */
1124  sl->morelangs[l-MAX_LANG] = lang_tag;
1125  }
1126  ++sl->lang_cnt;
1127  }
1128 }
1129 
1131  while ( fl!=NULL ) {
1132  FListAppendScriptLang(fl,script_tag,lang_tag);
1133  fl=fl->next;
1134  }
1135 }
1136 
1138  static struct { uint32 tag; char *suffix; } tags2suffix[] = {
1139  { CHR('v','r','t','2'), "vert" }, /* Will check for vrt2 later */
1140  { CHR('o','n','u','m'), "oldstyle" },
1141  { CHR('s','u','p','s'), "superior" },
1142  { CHR('s','u','b','s'), "inferior" },
1143  { CHR('s','w','s','h'), "swash" },
1144  { CHR('f','w','i','d'), "full" },
1145  { CHR('h','w','i','d'), "hw" },
1146  { 0 , NULL }
1147  };
1148  int i;
1149 
1150  while ( fl!=NULL ) {
1151  for ( i=0; tags2suffix[i].tag!=0; ++i )
1152  if ( tags2suffix[i].tag==fl->featuretag )
1153 return( copy( tags2suffix[i].suffix ));
1154  fl = fl->next;
1155  }
1156 return( NULL );
1157 }
1158 #ifdef LUA_FF_LIB
1159 /* ma = State Machine, un = Unknown */
1160 char *lookup_type_names[2][10] =
1161  { { "us", "ss", "ms", "as", "ls", "cs", "ks", "es", "rk" },
1162  { "up", "sp", "pp", "ca", "mb", "ml", "mm", "cp", "kp","ep" }};
1163 #else
1164 char *lookup_type_names[2][10] =
1165  { { N_("Undefined substitution"), N_("Single Substitution"), N_("Multiple Substitution"),
1166  N_("Alternate Substitution"), N_("Ligature Substitution"), N_("Contextual Substitution"),
1167  N_("Contextual Chaining Substitution"), N_("Extension"),
1168  N_("Reverse Contextual Chaining Substitution") },
1169  { N_("Undefined positioning"), N_("Single Positioning"), N_("Pairwise Positioning (kerning)"),
1170  N_("Cursive attachment"), N_("Mark to base attachment"),
1171  N_("Mark to Ligature attachment"), N_("Mark to Mark attachment"),
1172  N_("Contextual Positioning"), N_("Contextual Chaining Positioning"),
1173  N_("Extension") }};
1174 #endif
1175 
1176 /* This is a non-ui based copy of a similar list in lookupui.c */
1177 static struct {
1178  char *text;
1180 } localscripts[] = {
1181  { N_("Arabic"), CHR('a','r','a','b') },
1182  { N_("Aramaic"), CHR('a','r','a','m') }, /* Only in ff */
1183  { N_("Armenian"), CHR('a','r','m','n') },
1184  { N_("Avestan"), CHR('a','v','e','s') }, /* Only in ff */
1185  { N_("Balinese"), CHR('b','a','l','i') },
1186  { N_("Batak"), CHR('b','a','t','k') },
1187  { N_("Bengali"), CHR('b','e','n','g') },
1188  { N_("Bengali2"), CHR('b','n','g','2') },
1189  { N_("Bliss Symbolics"), CHR('b','l','i','s') }, /* Only in ff */
1190  { N_("Bopomofo"), CHR('b','o','p','o') },
1191  { N_("Brāhmī"), CHR('b','r','a','h') },
1192  { N_("Braille"), CHR('b','r','a','i') },
1193  { N_("Buginese"), CHR('b','u','g','i') },
1194  { N_("Buhid"), CHR('b','u','h','d') },
1195  { N_("Byzantine Music"), CHR('b','y','z','m') },
1196  { N_("Canadian Syllabics"), CHR('c','a','n','s') },
1197  { N_("Carian"), CHR('c','a','r','i') },
1198  { N_("Cherokee"), CHR('c','h','a','m') },
1199  { N_("Cham"), CHR('c','h','a','m') },
1200  { N_("Cherokee"), CHR('c','h','e','r') },
1201  { N_("Cirth"), CHR('c','i','r','t') }, /* Only in ff */
1202  { N_("CJK Ideographic"), CHR('h','a','n','i') },
1203  { N_("Coptic"), CHR('c','o','p','t') },
1204  { N_("Cypro-Minoan"), CHR('c','p','r','t') },
1205  { N_("Cypriot syllabary"), CHR('c','p','m','n') }, /* Only in ff */
1206  { N_("Cyrillic"), CHR('c','y','r','l') },
1207  { N_("Default"), CHR('D','F','L','T') },
1208  { N_("Deseret (Mormon)"), CHR('d','s','r','t') },
1209  { N_("Devanagari"), CHR('d','e','v','a') },
1210  { N_("Devanagari2"), CHR('d','e','v','2') },
1211 /* { N_("Egyptian demotic"), CHR('e','g','y','d') }, */
1212 /* { N_("Egyptian hieratic"), CHR('e','g','y','h') }, */
1213 /* GT: Someone asked if FontForge actually was prepared generate hieroglyph output */
1214 /* GT: because of this string. No. But OpenType and Unicode have placeholders for */
1215 /* GT: dealing with these scripts against the day someone wants to use them. So */
1216 /* GT: FontForge must be prepared to deal with those placeholders if nothing else. */
1217 /* { N_("Egyptian hieroglyphs"), CHR('e','g','y','p') }, */
1218  { N_("Ethiopic"), CHR('e','t','h','i') },
1219  { N_("Georgian"), CHR('g','e','o','r') },
1220  { N_("Glagolitic"), CHR('g','l','a','g') },
1221  { N_("Gothic"), CHR('g','o','t','h') },
1222  { N_("Greek"), CHR('g','r','e','k') },
1223  { N_("Gujarati"), CHR('g','u','j','r') },
1224  { N_("Gujarati2"), CHR('g','j','r','2') },
1225  { N_("Gurmukhi"), CHR('g','u','r','u') },
1226  { N_("Gurmukhi2"), CHR('g','u','r','2') },
1227  { N_("Hangul Jamo"), CHR('j','a','m','o') },
1228  { N_("Hangul"), CHR('h','a','n','g') },
1229  { N_("Hanunóo"), CHR('h','a','n','o') },
1230  { N_("Hebrew"), CHR('h','e','b','r') },
1231 /* { N_("Pahawh Hmong"), CHR('h','m','n','g') },*/
1232 /* { N_("Indus (Harappan)"), CHR('i','n','d','s') },*/
1233  { N_("Javanese"), CHR('j','a','v','a') },
1234  { N_("Kayah Li"), CHR('k','a','l','i') },
1235  { N_("Hiragana & Katakana"), CHR('k','a','n','a') },
1236  { N_("Kharoṣṭhī"), CHR('k','h','a','r') },
1237  { N_("Kannada"), CHR('k','n','d','a') },
1238  { N_("Kannada2"), CHR('k','n','d','2') },
1239  { N_("Khmer"), CHR('k','h','m','r') },
1240  { N_("Kharosthi"), CHR('k','h','a','r') },
1241  { N_("Lao") , CHR('l','a','o',' ') },
1242  { N_("Latin"), CHR('l','a','t','n') },
1243  { N_("Lepcha (Róng)"), CHR('l','e','p','c') },
1244  { N_("Limbu"), CHR('l','i','m','b') }, /* Not in ISO 15924 !!!!!, just guessing */
1245  { N_("Linear A"), CHR('l','i','n','a') }, /* Only in ff */
1246  { N_("Linear B"), CHR('l','i','n','b') },
1247  { N_("Lycian"), CHR('l','y','c','i') },
1248  { N_("Lydian"), CHR('l','y','d','i') },
1249  { N_("Mandaean"), CHR('m','a','n','d') },
1250 /* { N_("Mayan hieroglyphs"), CHR('m','a','y','a') },*/
1251  { N_("Malayālam"), CHR('m','l','y','m') },
1252  { N_("Malayālam2"), CHR('m','l','y','2') }, /* Only in ff, should be mlm2 */
1253  { N_("Mathematical Alphanumeric Symbols"), CHR('m','a','t','h') },
1254  { N_("Mongolian"), CHR('m','o','n','g') },
1255  { N_("Musical"), CHR('m','u','s','i') }, /* Only in ff, should be musc */
1256  { N_("Myanmar"), CHR('m','y','m','r') },
1257  { N_("New Tai Lue"), CHR('t','a','l','u') },
1258  { N_("N'Ko"), CHR('n','k','o',' ') },
1259  { N_("Ogham"), CHR('o','g','a','m') },
1260  { N_("Ol Chiki"), CHR('o','l','c','k') },
1261  { N_("Old Italic (Etruscan, Oscan, etc.)"), CHR('i','t','a','l') },
1262  { N_("Old Permic"), CHR('p','e','r','m') }, /* Only in ff */
1263  { N_("Old Persian cuneiform"), CHR('x','p','e','o') },
1264  { N_("Oriya"), CHR('o','r','y','a') },
1265  { N_("Oriya2"), CHR('o','r','y','2') },
1266  { N_("Osmanya"), CHR('o','s','m','a') },
1267  { N_("Pahlavi"), CHR('p','a','l','v') }, /* Only in ff */
1268  { N_("Phags-pa"), CHR('p','h','a','g') },
1269  { N_("Phoenician"), CHR('p','h','n','x') },
1270  { N_("Phaistos"), CHR('p','h','s','t') }, /* Only in ff */
1271  { N_("Pollard Phonetic"), CHR('p','l','r','d') }, /* Only in ff */
1272  { N_("Rejang"), CHR('r','j','n','g') },
1273  { N_("Rongorongo"), CHR('r','o','r','o') }, /* Only in ff */
1274  { N_("Runic"), CHR('r','u','n','r') },
1275  { N_("Saurashtra"), CHR('s','a','u','r') },
1276  { N_("Shavian"), CHR('s','h','a','w') },
1277  { N_("Sinhala"), CHR('s','i','n','h') },
1278  { N_("Sumero-Akkadian Cuneiform"), CHR('x','s','u','x') },
1279  { N_("Sundanese"), CHR('s','u','n','d') },
1280  { N_("Syloti Nagri"), CHR('s','y','l','o') },
1281  { N_("Syriac"), CHR('s','y','r','c') },
1282  { N_("Tagalog"), CHR('t','g','l','g') },
1283  { N_("Tagbanwa"), CHR('t','a','g','b') },
1284  { N_("Tai Le"), CHR('t','a','l','e') }, /* Not in ISO 15924 !!!!!, just guessing */
1285  { N_("Tai Lu"), CHR('t','a','l','a') }, /* Not in ISO 15924 !!!!!, just guessing */
1286  { N_("Tamil"), CHR('t','a','m','l') },
1287  { N_("Tamil2"), CHR('t','m','l','2') },
1288  { N_("Telugu"), CHR('t','e','l','u') },
1289  { N_("Telugu2"), CHR('t','e','l','2') },
1290  { N_("Tengwar"), CHR('t','e','n','g') }, /* Only in ff */
1291  { N_("Thaana"), CHR('t','h','a','a') },
1292  { N_("Thai"), CHR('t','h','a','i') },
1293  { N_("Tibetan"), CHR('t','i','b','t') },
1294  { N_("Tifinagh (Berber)"), CHR('t','f','n','g') },
1295  { N_("Ugaritic"), CHR('u','g','r','t') }, /* Only in ff, should be ugar */
1296  { N_("Vai"), CHR('v','a','i',' ') },
1297 /* { N_("Visible Speech"), CHR('v','i','s','p') },*/
1298  { N_("Cuneiform, Ugaritic"), CHR('x','u','g','a') }, /* Only in ff */
1299  { N_("Yi") , CHR('y','i',' ',' ') },
1300 /* { N_("Private Use Script 1"), CHR('q','a','a','a') },*/
1301 /* { N_("Private Use Script 2"), CHR('q','a','a','b') },*/
1302 /* { N_("Undetermined Script"), CHR('z','y','y','y') },*/
1303 /* { N_("Uncoded Script"), CHR('z','z','z','z') },*/
1304  { NULL, 0 }
1305 };
1306 
1307 void LookupInit(void) {
1308  static int done = false;
1309  int i, j;
1310 
1311  if ( done )
1312 return;
1313  done = true;
1314  for ( j=0; j<2; ++j ) {
1315  for ( i=0; i<10; ++i )
1316  if ( lookup_type_names[j][i]!=NULL )
1317  lookup_type_names[j][i] = _((char *) lookup_type_names[j][i]);
1318  }
1319  for ( i=0; localscripts[i].text!=NULL; ++i )
1321  for ( i=0; friendlies[i].friendlyname!=NULL; ++i )
1322  friendlies[i].friendlyname = _(friendlies[i].friendlyname);
1323 }
1324 
1325 char *TagFullName(SplineFont *sf,uint32 tag, int onlyifknown) {
1326  char ubuf[200], *end = ubuf+sizeof(ubuf);
1327  int k;
1328 
1329  unsigned stag = tag;
1330  if ( tag==CHR('n','u','t','f') ) /* early name that was standardize later as... */
1331  stag = CHR('a','f','r','c'); /* Stood for nut fractions. "nut" meaning "fits in an en" in old typography-speak => vertical fractions rather than diagonal ones */
1332  if ( tag==REQUIRED_FEATURE ) {
1333  strcpy(ubuf,_("Required Feature"));
1334  } else {
1335  LookupInit();
1336  for ( k=0; friendlies[k].tag!=0; ++k ) {
1337  if ( friendlies[k].tag == stag )
1338  break;
1339  }
1340  ubuf[0] = '\'';
1341  ubuf[1] = tag>>24;
1342  ubuf[2] = (tag>>16)&0xff;
1343  ubuf[3] = (tag>>8)&0xff;
1344  ubuf[4] = tag&0xff;
1345  ubuf[5] = '\'';
1346  ubuf[6] = ' ';
1347  if ( friendlies[k].tag!=0 )
1348  strncpy(ubuf+7, (char *) friendlies[k].friendlyname,end-ubuf-7);
1349  else if ( onlyifknown )
1350 return( NULL );
1351  else
1352  ubuf[7]='\0';
1353  }
1354 return( copy( ubuf ));
1355 }
1356 
1357 
1359  char *userfriendly = NULL, *script;
1361  char *lookuptype;
1362  char *format;
1363  struct lookup_subtable *subtable;
1364  int k;
1365  (void)sf;
1366 
1367  LookupInit();
1368 
1369  if ( otl->lookup_name==NULL ) {
1370  for ( k=0; k<2; ++k ) {
1371 #ifndef LUA_FF_LIB
1372  for ( fl=otl->features; fl!=NULL ; fl=fl->next ) {
1373  /* look first for a feature attached to a default language */
1374  if ( k==1 || DefaultLangTagInScriptList(fl->scripts,false)!=NULL ) {
1375  userfriendly = TagFullName(sf,fl->featuretag, true);
1376  if ( userfriendly!=NULL )
1377  break;
1378  }
1379  }
1380  if ( userfriendly!=NULL )
1381  break;
1382 #endif
1383  }
1384  if ( userfriendly==NULL ) {
1385  if ( (otl->lookup_type>>8)<2 && (otl->lookup_type&0xff)<10 )
1386  lookuptype = _(lookup_type_names[otl->lookup_type>>8][otl->lookup_type&0xff]);
1387  else
1388 #ifdef LUA_FF_LIB
1389  lookuptype = "un";
1390 #else
1391  lookuptype = _("Unknown");
1392 #endif
1393  for ( fl=otl->features; fl!=NULL; fl=fl->next );
1394  if ( fl==NULL )
1395  userfriendly = copy(lookuptype);
1396  else {
1397  userfriendly = galloc( strlen(lookuptype) + 40);
1398 #ifdef LUA_FF_LIB
1399  if ( (otl->lookup_type&0xff)>= 0xf0 ) {
1400  sprintf( userfriendly, "%s_<%d,%d>", lookuptype,
1401  (fl->featuretag>>16), (fl->featuretag&0xffff));
1402  } else {
1403  sprintf( userfriendly, "%s_%c%c%c%c", lookuptype,
1404  fl->featuretag>>24,
1405  fl->featuretag>>16,
1406  fl->featuretag>>8 ,
1407  fl->featuretag );
1408  }
1409 #else
1410  sprintf( userfriendly, "%s '%c%c%c%c'", lookuptype,
1411  fl->featuretag>>24,
1412  fl->featuretag>>16,
1413  fl->featuretag>>8 ,
1414  fl->featuretag );
1415 #endif
1416  }
1417  }
1418  script = NULL;
1419  if ( fl==NULL ) fl = otl->features;
1420  if ( fl!=NULL && fl->scripts!=NULL ) {
1421  char buf[8];
1422  int j;
1423  struct scriptlanglist *sl, *found, *found2;
1424  uint32 script_tag = fl->scripts->script;
1425  found = found2 = NULL;
1426  for ( sl = fl->scripts; sl!=NULL; sl=sl->next ) {
1427  if ( sl->script == DEFAULT_SCRIPT )
1428  /* Ignore it */;
1429  else if ( DefaultLangTagInOneScriptList(sl)) {
1430  if ( found==NULL )
1431  found = sl;
1432  else {
1433  found = found2 = NULL;
1434  break;
1435  }
1436  } else if ( found2 == NULL )
1437  found2 = sl;
1438  else
1439  found2 = (struct scriptlanglist *) -1;
1440  }
1441  if ( found==NULL && found2!=NULL && found2 != (struct scriptlanglist *) -1 )
1442  found = found2;
1443  if ( found!=NULL ) {
1444  script_tag = found->script;
1445  for ( j=0; localscripts[j].text!=NULL && script_tag!=localscripts[j].tag; ++j ) {;}
1446 #ifdef LUA_FF_LIB
1447  buf[0] = fl->scripts->script>>24;
1448  buf[1] = (fl->scripts->script>>16)&0xff;
1449  buf[2] = (fl->scripts->script>>8)&0xff;
1450  buf[3] = fl->scripts->script&0xff;
1451  buf[4] = 0;
1452  script = copy(buf);
1453 #else
1454  if ( localscripts[j].text!=NULL )
1455  script = copy( _((char *) localscripts[j].text) );
1456  else {
1457  buf[0] = '\'';
1458  buf[1] = fl->scripts->script>>24;
1459  buf[2] = (fl->scripts->script>>16)&0xff;
1460  buf[3] = (fl->scripts->script>>8)&0xff;
1461  buf[4] = fl->scripts->script&0xff;
1462  buf[5] = '\'';
1463  buf[6] = 0;
1464  script = copy(buf);
1465  }
1466 #endif
1467  }
1468  }
1469  if ( script!=NULL ) {
1470 /* GT: This string is used to generate a name for each OpenType lookup. */
1471 /* GT: The %s will be filled with the user friendly name of the feature used to invoke the lookup */
1472 /* GT: The second %s (if present) is the script */
1473 /* GT: While the %d is the index into the lookup list and is used to disambiguate it */
1474 /* GT: In case that is needed */
1475 #ifdef LUA_FF_LIB
1476  format = "%s_%s_l_%d";
1477 #else
1478  format = _("%s in %s lookup %d");
1479 #endif
1480  otl->lookup_name = galloc( strlen(userfriendly)+strlen(format)+strlen(script)+10 );
1481  sprintf( otl->lookup_name, format, userfriendly, script, otl->lookup_index );
1482  } else {
1483 #ifdef LUA_FF_LIB
1484  format = "%s_l_%d";
1485 #else
1486  format = _("%s lookup %d");
1487 #endif
1488  otl->lookup_name = galloc( strlen(userfriendly)+strlen(format)+10 );
1489  sprintf( otl->lookup_name, format, userfriendly, otl->lookup_index );
1490  }
1491  free(script);
1492  free(userfriendly);
1493  }
1494 
1495  if ( otl->subtables==NULL )
1496  /* IError( _("Lookup with no subtables"))*/;
1497  else {
1498  int cnt = 0;
1499  for ( subtable = otl->subtables; subtable!=NULL; subtable=subtable->next, ++cnt )
1500  if ( subtable->subtable_name==NULL ) {
1501  if ( subtable==otl->subtables && subtable->next==NULL )
1502 /* GT: This string is used to generate a name for an OpenType lookup subtable. */
1503 /* GT: %s is the lookup name */
1504 #ifdef LUA_FF_LIB
1505  format = "%s_s";
1506 #else
1507  format = _("%s subtable");
1508 #endif
1509  else if ( subtable->per_glyph_pst_or_kern )
1510 /* GT: This string is used to generate a name for an OpenType lookup subtable. */
1511 /* GT: %s is the lookup name, %d is the index of the subtable in the lookup */
1512 #ifdef LUA_FF_LIB
1513  format = "%s_g_%d";
1514 #else
1515  format = _("%s per glyph data %d");
1516 #endif
1517  else if ( subtable->kc!=NULL )
1518 #ifdef LUA_FF_LIB
1519  format = "%s_k_%d";
1520 #else
1521  format = _("%s kerning class %d");
1522 #endif
1523  else if ( subtable->fpst!=NULL )
1524 #ifdef LUA_FF_LIB
1525  format = "%s_c_%d";
1526 #else
1527  format = _("%s contextual %d");
1528 #endif
1529  else if ( subtable->anchor_classes )
1530 #ifdef LUA_FF_LIB
1531  format = "%s_a_%d";
1532 #else
1533  format = _("%s anchor %d");
1534 #endif
1535  else {
1536  IError("Subtable status not filled in for %dth subtable of %s", cnt, otl->lookup_name );
1537  format = "%s !!!!!!!! %d";
1538  }
1539  subtable->subtable_name = galloc( strlen(otl->lookup_name)+strlen(format)+10 );
1540  sprintf( subtable->subtable_name, format, otl->lookup_name, cnt );
1541  }
1542  }
1543  if ( otl->lookup_type==gsub_ligature ) {
1544  for ( fl=otl->features; fl!=NULL; fl=fl->next )
1545  if ( fl->featuretag==CHR('l','i','g','a') || fl->featuretag==CHR('r','l','i','g'))
1546  otl->store_in_afm = true;
1547  }
1548 
1549  if ( otl->lookup_type==gsub_single )
1550  for ( subtable = otl->subtables; subtable!=NULL; subtable=subtable->next )
1551  subtable->suffix = SuffixFromTags(otl->features);
1552 }
1553 
1554 static void LangOrder(struct scriptlanglist *sl) {
1555  int i,j;
1556  uint32 lang, lang2;
1557 
1558  for ( i=0; i<sl->lang_cnt; ++i ) {
1559  lang = i<MAX_LANG ? sl->langs[i] : sl->morelangs[i-MAX_LANG];
1560  for ( j=i+1; j<sl->lang_cnt; ++j ) {
1561  lang2 = j<MAX_LANG ? sl->langs[j] : sl->morelangs[j-MAX_LANG];
1562  if ( lang>lang2 ) {
1563  if ( i<MAX_LANG )
1564  sl->langs[i] = lang2;
1565  else
1566  sl->morelangs[i-MAX_LANG] = lang2;
1567  if ( j<MAX_LANG )
1568  sl->langs[j] = lang;
1569  else
1570  sl->morelangs[j-MAX_LANG] = lang;
1571  lang = lang2;
1572  }
1573  }
1574  }
1575 }
1576 
1577 static struct scriptlanglist *SLOrder(struct scriptlanglist *sl) {
1578  int i,j, cnt;
1579  struct scriptlanglist *sl2, *space[30], **allocked=NULL, **test = space;
1580 
1581  for ( sl2=sl, cnt=0; sl2!=NULL; sl2=sl2->next, ++cnt )
1582  LangOrder(sl2);
1583  if ( cnt<=1 )
1584 return( sl );
1585  if ( cnt>30 )
1586  test = allocked = galloc(cnt*sizeof(struct scriptlanglist *));
1587  for ( sl2=sl, cnt=0; sl2!=NULL; sl2=sl2->next, ++cnt )
1588  test[cnt] = sl2;
1589  for ( i=0; i<cnt; ++i ) for ( j=i+1; j<cnt; ++j ) {
1590  if ( test[i]->script > test[j]->script ) {
1591  struct scriptlanglist *temp;
1592  temp = test[i];
1593  test[i] = test[j];
1594  test[j] = temp;
1595  }
1596  }
1597  sl = test[0];
1598  for ( i=1; i<cnt; ++i )
1599  test[i-1]->next = test[i];
1600  test[i-1]->next = NULL;
1601  free( allocked );
1602 return( sl );
1603 }
1604 
1606  int i,j, cnt;
1607  FeatureScriptLangList *fl2, *space[30], **allocked=NULL, **test = space;
1608 
1609  for ( fl2=fl, cnt=0; fl2!=NULL; fl2=fl2->next, ++cnt )
1610  fl2->scripts = SLOrder(fl2->scripts);
1611  if ( cnt<=1 )
1612 return( fl );
1613  if ( cnt>30 )
1614  test = allocked = galloc(cnt*sizeof(FeatureScriptLangList *));
1615  for ( fl2=fl, cnt=0; fl2!=NULL; fl2=fl2->next, ++cnt )
1616  test[cnt] = fl2;
1617  for ( i=0; i<cnt; ++i ) for ( j=i+1; j<cnt; ++j ) {
1618  if ( test[i]->featuretag > test[j]->featuretag ) {
1620  temp = test[i];
1621  test[i] = test[j];
1622  test[j] = temp;
1623  }
1624  }
1625  fl = test[0];
1626  for ( i=1; i<cnt; ++i )
1627  test[i-1]->next = test[i];
1628  test[i-1]->next = NULL;
1629  free( allocked );
1630 return( fl );
1631 }
1632 
1633 struct scriptlanglist *SLCopy(struct scriptlanglist *sl) {
1634  struct scriptlanglist *newsl;
1635 
1636  newsl = chunkalloc(sizeof(struct scriptlanglist));
1637  *newsl = *sl;
1638  newsl->next = NULL;
1639 
1640  if ( sl->lang_cnt>MAX_LANG ) {
1641  newsl->morelangs = galloc((newsl->lang_cnt-MAX_LANG)*sizeof(uint32));
1642  memcpy(newsl->morelangs,sl->morelangs,(newsl->lang_cnt-MAX_LANG)*sizeof(uint32));
1643  }
1644 return( newsl );
1645 }
1646 
1648  struct scriptlanglist *head=NULL, *last=NULL, *cur;
1649 
1650  for ( ; sl!=NULL; sl=sl->next ) {
1651  cur = SLCopy(sl);
1652  if ( head==NULL )
1653  head = cur;
1654  else
1655  last->next = cur;
1656  last = cur;
1657  }
1658 return( head );
1659 }
1660 
1662  FeatureScriptLangList *newfl;
1663 
1664  if ( fl==NULL )
1665 return( NULL );
1666 
1667  newfl = chunkalloc(sizeof(FeatureScriptLangList));
1668  *newfl = *fl;
1669  newfl->next = NULL;
1670 
1671  newfl->scripts = SListCopy(fl->scripts);
1672 return( newfl );
1673 }
1674 
1675 static void LangMerge(struct scriptlanglist *into, struct scriptlanglist *from) {
1676  int i,j;
1677  uint32 flang, tlang;
1678 
1679  for ( i=0 ; i<from->lang_cnt; ++i ) {
1680  flang = i<MAX_LANG ? from->langs[i] : from->morelangs[i-MAX_LANG];
1681  for ( j=0; j<into->lang_cnt; ++j ) {
1682  tlang = j<MAX_LANG ? into->langs[j] : into->morelangs[j-MAX_LANG];
1683  if ( tlang==flang )
1684  break;
1685  }
1686  if ( j==into->lang_cnt ) {
1687  if ( into->lang_cnt<MAX_LANG )
1688  into->langs[into->lang_cnt++] = flang;
1689  else {
1690  into->morelangs = grealloc(into->morelangs,(into->lang_cnt+1-MAX_LANG)*sizeof(uint32));
1691  into->morelangs[into->lang_cnt++-MAX_LANG] = flang;
1692  }
1693  }
1694  }
1695 }
1696 
1698  struct scriptlanglist *isl;
1699 
1700  for ( ; fsl!=NULL; fsl = fsl->next ) {
1701  for ( isl=into->scripts; isl!=NULL; isl=isl->next ) {
1702  if ( fsl->script==isl->script )
1703  break;
1704  }
1705  if ( isl!=NULL )
1706  LangMerge(isl,fsl);
1707  else {
1708  isl = SLCopy(fsl);
1709  isl->next = into->scripts;
1710  into->scripts = isl;
1711  }
1712  }
1713 }
1714 
1715 void FLMerge(OTLookup *into, OTLookup *from) {
1716  /* Merge the feature list from "from" into "into" */
1717  FeatureScriptLangList *ifl, *ffl;
1718 
1719  /* first check for common featuretags and merge the scripts of each */
1720  for ( ffl = from->features; ffl!=NULL; ffl = ffl->next ) {
1721  for ( ifl=into->features; ifl!=NULL; ifl=ifl->next ) {
1722  if ( ffl->featuretag==ifl->featuretag )
1723  break;
1724  }
1725  if ( ifl!=NULL )
1726  SLMerge(ffl,ifl->scripts);
1727  else {
1728  ifl = FeatureListCopy(ffl);
1729  ifl->next = into->features;
1730  into->features = ifl;
1731  }
1732  }
1733  into->features = FLOrder(into->features);
1734 }
1735 
1736 void SFSubTablesMerge(SplineFont *_sf,struct lookup_subtable *subfirst,
1737  struct lookup_subtable *subsecond) {
1738  unsigned lookup_type = subfirst->lookup->lookup_type;
1739  int gid,k,isv;
1740  SplineChar *sc;
1741  SplineFont *sf = _sf;
1742  PST *pst, *fpst, *spst, *pstprev, *pstnext;
1743  KernPair *fkp, *skp, *kpprev, *kpnext;
1744  AnchorClass *ac;
1745 
1746  if ( lookup_type != subsecond->lookup->lookup_type ) {
1747  IError("Attempt to merge lookup subtables with mismatch types");
1748 return;
1749  }
1750  if ( lookup_type != gsub_single &&
1751  lookup_type != gsub_multiple &&
1752  lookup_type != gsub_alternate &&
1753  lookup_type != gsub_ligature &&
1754  lookup_type != gpos_single &&
1755  lookup_type != gpos_pair &&
1756  lookup_type != gpos_cursive &&
1757  lookup_type != gpos_mark2base &&
1758  lookup_type != gpos_mark2ligature &&
1759  lookup_type != gpos_mark2mark ) {
1760  IError("Attempt to merge lookup subtables with bad types");
1761 return;
1762  } else if ( subfirst->kc!=NULL || subsecond->kc != NULL ) {
1763  IError("Attempt to merge lookup subtables with kerning classes");
1764 return;
1765  }
1766 
1767  if ( lookup_type==gpos_cursive || lookup_type==gpos_mark2base ||
1768  lookup_type==gpos_mark2ligature || lookup_type==gpos_mark2mark ) {
1769  for ( ac = sf->anchor; ac!=NULL ; ac=ac->next )
1770  if ( ac->subtable == subsecond )
1771  ac->subtable = subfirst;
1772  } else {
1773  k=0;
1774  do {
1775  sf = _sf->subfontcnt==0 ? _sf : _sf->subfonts[k];
1776  for ( gid=0; gid<sf->glyphcnt; ++gid ) if ( (sc=sf->glyphs[gid])!=NULL ) {
1777  if ( lookup_type==gsub_single || lookup_type==gsub_multiple ||
1778  lookup_type==gsub_alternate || lookup_type==gpos_single ) {
1779  fpst = spst = NULL;
1780  for ( pst=sc->possub; pst!=NULL; pst=pst->next ) {
1781  if ( pst->subtable == subfirst ) {
1782  fpst = pst;
1783  if ( spst!=NULL )
1784  break;
1785  } else if ( pst->subtable == subsecond ) {
1786  spst = pst;
1787  if ( fpst!=NULL )
1788  break;
1789  }
1790  }
1791  if ( fpst==NULL && spst!=NULL )
1792  spst->subtable = subfirst;
1793  else if ( spst!=NULL ) {
1794  LogError(_("The glyph, %s, contains a %s from %s and one from %s.\nThe one from %s will be removed.\n"),
1795  sc->name,
1796  lookup_type==gpos_single ? _("positioning") : _("substitution"),
1797  subfirst->subtable_name, subsecond->subtable_name,
1798  subsecond->subtable_name );
1799  pstprev = NULL;
1800  for ( pst=sc->possub; pst!=NULL && pst!=spst; pstprev=pst, pst=pst->next );
1801  if ( pstprev==NULL )
1802  sc->possub = spst->next;
1803  else
1804  pstprev = spst->next;
1805  spst->next = NULL;
1806  PSTFree(spst);
1807  }
1808  } else if ( lookup_type==gsub_ligature || lookup_type==gpos_pair ) {
1809  pstprev = NULL;
1810  for ( spst=sc->possub; spst!=NULL ; spst = pstnext ) {
1811  pstnext = spst->next;
1812  if ( spst->subtable == subsecond ) {
1813  for ( fpst=sc->possub; fpst!=NULL; fpst=fpst->next ) {
1814  if ( fpst->subtable == subfirst &&
1815  strcmp(fpst->u.lig.components,spst->u.lig.components)==0 )
1816  break;
1817  }
1818  if ( fpst==NULL )
1819  spst->subtable = subfirst;
1820  else {
1821  LogError(_("The glyph, %s, contains the same %s from %s and from %s.\nThe one from %s will be removed.\n"),
1822  sc->name,
1823  lookup_type==gsub_ligature ? _("ligature") : _("kern pair"),
1824  subfirst->subtable_name, subsecond->subtable_name,
1825  subsecond->subtable_name );
1826  if ( pstprev==NULL )
1827  sc->possub = pstnext;
1828  else
1829  pstprev->next = pstnext;
1830  spst->next = NULL;
1831  PSTFree(spst);
1832  spst = pstprev;
1833  }
1834  }
1835  pstprev = spst;
1836  }
1837  for ( isv=0; isv<2; ++isv ) {
1838  kpprev = NULL;
1839  for ( skp=isv ? sc->vkerns : sc->kerns; skp!=NULL ; skp = kpnext ) {
1840  kpnext = skp->next;
1841  if ( skp->subtable == subsecond ) {
1842  for ( fkp=isv ? sc->vkerns : sc->kerns; fkp!=NULL; fkp=fkp->next ) {
1843  if ( fkp->subtable == subfirst && fkp->sc==skp->sc )
1844  break;
1845  }
1846  if ( fkp==NULL )
1847  skp->subtable = subfirst;
1848  else {
1849  LogError(_("The glyph, %s, contains the same kern pair from %s and from %s.\nThe one from %s will be removed.\n"),
1850  sc->name,
1851  subfirst->subtable_name, subsecond->subtable_name,
1852  subsecond->subtable_name );
1853  if ( kpprev!=NULL )
1854  kpprev->next = kpnext;
1855  else if ( isv )
1856  sc->vkerns = kpnext;
1857  else
1858  sc->kerns = kpnext;
1859  skp->next = NULL;
1860  KernPairsFree(skp);
1861  skp = kpprev;
1862  }
1863  }
1864  kpprev = skp;
1865  }
1866  }
1867  }
1868  }
1869  ++k;
1870  } while ( k<_sf->subfontcnt );
1871  }
1872 }
1873 
1874 /* ************************************************************************** */
1875 /* ******************************* copy lookup ****************************** */
1876 /* ************************************************************************** */
1877 
1878 static char **ClassCopy(int class_cnt,char **classes) {
1879  char **newclasses;
1880  int i;
1881 
1882  if ( classes==NULL || class_cnt==0 )
1883 return( NULL );
1884  newclasses = galloc(class_cnt*sizeof(char *));
1885  for ( i=0; i<class_cnt; ++i )
1886  newclasses[i] = copy(classes[i]);
1887 return( newclasses );
1888 }
1889 
1890 static OTLookup *_OTLookupCopyInto(struct sfmergecontext *mc,
1891  OTLookup *from_otl, OTLookup *before, int do_contents);
1893  OTLookup *from_otl) {
1894  char *newname;
1895  OTLookup *to_nested_otl;
1896  int l;
1897 
1898  if ( from_otl==NULL )
1899 return( NULL );
1900 
1901  for ( l=0; l<mc->lcnt; ++l ) {
1902  if ( mc->lks[l].from == from_otl )
1903 return( mc->lks[l].to );
1904  }
1905 
1906  newname = strconcat(mc->prefix,from_otl->lookup_name);
1907  to_nested_otl = SFFindLookup(mc->sf_to,newname);
1908  free(newname);
1909  if ( to_nested_otl==NULL )
1910  to_nested_otl = _OTLookupCopyInto(mc, from_otl, (OTLookup *) -1, true );
1911 return( to_nested_otl );
1912 }
1913 
1915  struct lookup_subtable *sub ) {
1916  KernClass *newkc;
1917 
1918  newkc = chunkalloc(sizeof(KernClass));
1919  *newkc = *kc;
1920  newkc->subtable = sub;
1921  if ( sub->vertical_kerning ) {
1922  newkc->next = mc->sf_to->vkerns;
1923  mc->sf_to->vkerns = newkc;
1924  } else {
1925  newkc->next = mc->sf_to->kerns;
1926  mc->sf_to->kerns = newkc;
1927  }
1928 
1929  newkc->firsts = ClassCopy(newkc->first_cnt,newkc->firsts);
1930  newkc->seconds = ClassCopy(newkc->second_cnt,newkc->seconds);
1931  newkc->offsets = galloc(newkc->first_cnt*newkc->second_cnt*sizeof(int16));
1932  memcpy(newkc->offsets,kc->offsets,newkc->first_cnt*newkc->second_cnt*sizeof(int16));
1933 return( newkc );
1934 }
1935 
1936 static FPST *SF_AddFPST(struct sfmergecontext *mc,FPST *fpst,
1937  struct lookup_subtable *sub ) {
1938  FPST *newfpst;
1939  int i, k, cur;
1940 
1941  newfpst = chunkalloc(sizeof(FPST));
1942  *newfpst = *fpst;
1943  newfpst->subtable = sub;
1944  newfpst->next = mc->sf_to->possub;
1945  mc->sf_to->possub = newfpst;
1946 
1947  newfpst->nclass = ClassCopy(newfpst->nccnt,newfpst->nclass);
1948  newfpst->bclass = ClassCopy(newfpst->bccnt,newfpst->bclass);
1949  newfpst->fclass = ClassCopy(newfpst->fccnt,newfpst->fclass);
1950 
1951  newfpst->rules = galloc(newfpst->rule_cnt*sizeof(struct fpst_rule));
1952  memcpy(newfpst->rules,fpst->rules,newfpst->rule_cnt*sizeof(struct fpst_rule));
1953 
1954  cur = 0;
1955  for ( i=0; i<newfpst->rule_cnt; ++i ) {
1956  struct fpst_rule *r = &newfpst->rules[i], *oldr = &fpst->rules[i];
1957 
1958  r->lookups = galloc(r->lookup_cnt*sizeof(struct seqlookup));
1959  memcpy(r->lookups,oldr->lookups,r->lookup_cnt*sizeof(struct seqlookup));
1960  for ( k=0; k<r->lookup_cnt; ++k ) {
1961  r->lookups[k].lookup = OTLookupCopyNested(mc,
1962  r->lookups[k].lookup);
1963  }
1964 
1965  switch ( newfpst->format ) {
1966  case pst_glyphs:
1967  r->u.glyph.names = copy( r->u.glyph.names );
1968  r->u.glyph.back = copy( r->u.glyph.back );
1969  r->u.glyph.fore = copy( r->u.glyph.fore );
1970  break;
1971  case pst_class:
1972  r->u.class.nclasses = galloc( r->u.class.ncnt*sizeof(uint16));
1973  memcpy(r->u.class.nclasses,oldr->u.class.nclasses, r->u.class.ncnt*sizeof(uint16));
1974  r->u.class.bclasses = galloc( r->u.class.bcnt*sizeof(uint16));
1975  memcpy(r->u.class.bclasses,oldr->u.class.bclasses, r->u.class.ncnt*sizeof(uint16));
1976  r->u.class.fclasses = galloc( r->u.class.fcnt*sizeof(uint16));
1977  memcpy(r->u.class.fclasses,oldr->u.class.fclasses, r->u.class.fcnt*sizeof(uint16));
1978  break;
1979  case pst_coverage:
1980  r->u.coverage.ncovers = ClassCopy( r->u.coverage.ncnt, r->u.coverage.ncovers );
1981  r->u.coverage.bcovers = ClassCopy( r->u.coverage.bcnt, r->u.coverage.bcovers );
1982  r->u.coverage.fcovers = ClassCopy( r->u.coverage.fcnt, r->u.coverage.fcovers );
1983  break;
1984  case pst_reversecoverage:
1985  r->u.rcoverage.ncovers = ClassCopy( r->u.rcoverage.always1, r->u.rcoverage.ncovers );
1986  r->u.rcoverage.bcovers = ClassCopy( r->u.rcoverage.bcnt, r->u.rcoverage.bcovers );
1987  r->u.rcoverage.fcovers = ClassCopy( r->u.rcoverage.fcnt, r->u.rcoverage.fcovers );
1988  r->u.rcoverage.replacements = copy( r->u.rcoverage.replacements );
1989  break;
1990  }
1991  }
1992 return( newfpst );
1993 }
1994 
1996  int to_index;
1997 
1998  if ( into->cidmaster==NULL && into->fv!=NULL ) {
1999  to_index = SFFindSlot(into,into->fv->map,fromsc->unicodeenc,fromsc->name);
2000  if ( to_index==-1 )
2001 return( NULL );
2002 return( SFMakeChar(into,into->fv->map,to_index));
2003  }
2004 return( SFGetChar(into,fromsc->unicodeenc,fromsc->name));
2005 }
2006 
2007 static void SF_SCAddAP(SplineChar *tosc,AnchorPoint *ap, AnchorClass *newac) {
2008  AnchorPoint *newap;
2009 
2010  newap = chunkalloc(sizeof(AnchorPoint));
2011  *newap = *ap;
2012  newap->anchor = newac;
2013  newap->next = tosc->anchor;
2014  tosc->anchor = newap;
2015 }
2016 
2017 static void SF_AddAnchorClasses(struct sfmergecontext *mc,
2018  struct lookup_subtable *from_sub, struct lookup_subtable *sub ) {
2019  AnchorClass *ac, *nac;
2020  int k, gid;
2021  SplineFont *fsf;
2022  AnchorPoint *ap;
2023  SplineChar *fsc, *tsc;
2024 
2025  for ( ac=mc->sf_from->anchor; ac!=NULL; ac=ac->next ) if ( ac->subtable==from_sub ) {
2026  nac = chunkalloc(sizeof(AnchorClass));
2027  *nac = *ac;
2028  nac->subtable = sub;
2029  nac->name = strconcat(mc->prefix,nac->name);
2030  nac->next = mc->sf_to->anchor;
2031  mc->sf_to->anchor = nac;
2032 
2033  k=0;
2034  do {
2035  fsf = mc->sf_from->subfontcnt==0 ? mc->sf_from : mc->sf_from->subfonts[k];
2036  for ( gid = 0; gid<fsf->glyphcnt; ++gid ) if ( (fsc = fsf->glyphs[gid])!=NULL ) {
2037  for ( ap=fsc->anchor; ap!=NULL; ap=ap->next ) {
2038  if ( ap->anchor==ac ) {
2039  tsc = SCFindOrMake(mc->sf_to,fsc);
2040  if ( tsc==NULL )
2041  break;
2042  SF_SCAddAP(tsc,ap,nac);
2043  }
2044  }
2045  }
2046  ++k;
2047  } while ( k<mc->sf_from->subfontcnt );
2048  }
2049 }
2050 
2051 static int SF_SCAddPST(SplineChar *tosc,PST *pst,struct lookup_subtable *sub) {
2052  PST *newpst;
2053 
2054  newpst = chunkalloc(sizeof(PST));
2055  *newpst = *pst;
2056  newpst->subtable = sub;
2057  newpst->next = tosc->possub;
2058  tosc->possub = newpst;
2059 
2060  switch( newpst->type ) {
2061  case pst_pair:
2062  newpst->u.pair.paired = copy(pst->u.pair.paired);
2063  newpst->u.pair.vr = chunkalloc(sizeof(struct vr [2]));
2064  memcpy(newpst->u.pair.vr,pst->u.pair.vr,sizeof(struct vr [2]));
2065  break;
2066  case pst_ligature:
2067  newpst->u.lig.lig = tosc;
2068  /* Fall through */
2069  case pst_substitution:
2070  case pst_alternate:
2071  case pst_multiple:
2072  newpst->u.subs.variant = copy(pst->u.subs.variant);
2073  break;
2074  }
2075 return( true );
2076 }
2077 
2079  int isvkern, SplineFont *to_sf ) {
2080  SplineChar *tosecond;
2081  KernPair *newkp;
2082 
2083  tosecond = SFGetChar(to_sf,kp->sc->unicodeenc,kp->sc->name);
2084  if ( tosecond==NULL )
2085 return( false );
2086 
2087  newkp = chunkalloc(sizeof(KernPair));
2088  *newkp = *kp;
2089  newkp->subtable = sub;
2090  newkp->sc = tosecond;
2091  if ( isvkern ) {
2092  newkp->next = tosc->vkerns;
2093  tosc->vkerns = newkp;
2094  } else {
2095  newkp->next = tosc->kerns;
2096  tosc->kerns = newkp;
2097  }
2098 return(true);
2099 }
2100 
2101 static void SF_AddPSTKern(struct sfmergecontext *mc,struct lookup_subtable *from_sub, struct lookup_subtable *sub) {
2102  int k, gid, isv;
2103  SplineFont *fsf;
2104  SplineChar *fsc, *tsc;
2105  PST *pst;
2106  KernPair *kp;
2107  int iskern = sub->lookup->lookup_type==gpos_pair;
2108 
2109  k=0;
2110  do {
2111  fsf = mc->sf_from->subfontcnt==0 ? mc->sf_from : mc->sf_from->subfonts[k];
2112  for ( gid = 0; gid<fsf->glyphcnt; ++gid ) if ( (fsc = fsf->glyphs[gid])!=NULL ) {
2113  tsc = (SplineChar *) -1;
2114  for ( pst = fsc->possub; pst!=NULL; pst=pst->next ) {
2115  if ( pst->subtable==from_sub ) {
2116  if ( tsc==(SplineChar *) -1 ) {
2117  tsc = SCFindOrMake(mc->sf_to,fsc);
2118  if ( tsc==NULL )
2119  break;
2120  }
2121  SF_SCAddPST(tsc,pst,sub);
2122  }
2123  }
2124  if ( tsc!=NULL && iskern ) {
2125  for ( isv=0; isv<2 && tsc!=NULL; ++isv ) {
2126  for ( kp= isv ? fsc->vkerns : fsc->kerns; kp!=NULL; kp=kp->next ) {
2127  if ( kp->subtable==sub ) {
2128  /* Kerning data tend to be individualistic. Only copy if */
2129  /* glyphs exist */
2130  if ( tsc==(SplineChar *) -1 ) {
2131  tsc = SFGetChar(mc->sf_to,fsc->unicodeenc,fsc->name);
2132  if ( tsc==NULL )
2133  break;
2134  }
2135  SF_SCAddKP(tsc,kp,sub,isv,mc->sf_to);
2136  }
2137  }
2138  }
2139  }
2140  }
2141  ++k;
2142  } while ( k<mc->sf_from->subfontcnt );
2143 }
2144 
2145 int _FeatureOrderId( int isgpos,uint32 tag ) {
2146  /* This is the order in which features should be executed */
2147 
2148  if ( !isgpos ) switch ( tag ) {
2149 /* GSUB ordering */
2150  case CHR('c','c','m','p'): /* Must be first? */
2151 return( -2 );
2152  case CHR('l','o','c','l'): /* Language dependent letter forms (serbian uses some different glyphs than russian) */
2153 return( -1 );
2154  case CHR('i','s','o','l'):
2155 return( 0 );
2156  case CHR('j','a','l','t'): /* must come after 'isol' */
2157 return( 1 );
2158  case CHR('f','i','n','a'):
2159 return( 2 );
2160  case CHR('f','i','n','2'):
2161  case CHR('f','a','l','t'): /* must come after 'fina' */
2162 return( 3 );
2163  case CHR('f','i','n','3'):
2164 return( 4 );
2165  case CHR('m','e','d','i'):
2166 return( 5 );
2167  case CHR('m','e','d','2'):
2168 return( 6 );
2169  case CHR('i','n','i','t'):
2170 return( 7 );
2171 
2172  case CHR('r','t','l','a'):
2173 return( 100 );
2174  case CHR('s','m','c','p'): case CHR('c','2','s','c'):
2175 return( 200 );
2176 
2177  case CHR('r','l','i','g'):
2178 return( 300 );
2179  case CHR('c','a','l','t'):
2180 return( 301 );
2181  case CHR('l','i','g','a'):
2182 return( 302 );
2183  case CHR('d','l','i','g'): case CHR('h','l','i','g'):
2184 return( 303 );
2185  case CHR('c','s','w','h'):
2186 return( 304 );
2187  case CHR('m','s','e','t'):
2188 return( 305 );
2189 
2190  case CHR('f','r','a','c'):
2191 return( 306 );
2192 
2193 /* Indic processing */
2194  case CHR('n','u','k','t'):
2195  case CHR('p','r','e','f'):
2196 return( 301 );
2197  case CHR('a','k','h','n'):
2198 return( 302 );
2199  case CHR('r','p','h','f'):
2200 return( 303 );
2201  case CHR('b','l','w','f'):
2202 return( 304 );
2203  case CHR('h','a','l','f'):
2204  case CHR('a','b','v','f'):
2205 return( 305 );
2206  case CHR('p','s','t','f'):
2207 return( 306 );
2208  case CHR('v','a','t','u'):
2209 return( 307 );
2210 
2211  case CHR('p','r','e','s'):
2212 return( 310 );
2213  case CHR('b','l','w','s'):
2214 return( 311 );
2215  case CHR('a','b','v','s'):
2216 return( 312 );
2217  case CHR('p','s','t','s'):
2218 return( 313 );
2219  case CHR('c','l','i','g'):
2220 return( 314 );
2221 
2222  case CHR('h','a','l','n'):
2223 return( 320 );
2224 /* end indic ordering */
2225 
2226  case CHR('a','f','r','c'):
2227  case CHR('l','j','m','o'):
2228  case CHR('v','j','m','o'):
2229 return( 350 );
2230  case CHR('v','r','t','2'): case CHR('v','e','r','t'):
2231 return( 1010 ); /* Documented to come last */
2232 
2233 /* Unknown things come after everything but vert/vrt2 */
2234  default:
2235 return( 1000 );
2236 
2237  } else switch ( tag ) {
2238 /* GPOS ordering */
2239  case CHR('c','u','r','s'):
2240 return( 0 );
2241  case CHR('d','i','s','t'):
2242 return( 100 );
2243  case CHR('b','l','w','m'):
2244 return( 201 );
2245  case CHR('a','b','v','m'):
2246 return( 202 );
2247  case CHR('k','e','r','n'):
2248 return( 300 );
2249  case CHR('m','a','r','k'):
2250 return( 400 );
2251  case CHR('m','k','m','k'):
2252 return( 500 );
2253 /* Unknown things come after everything */
2254  default:
2255 return( 1000 );
2256  }
2257 }
2258 
2259 int FeatureOrderId( int isgpos,FeatureScriptLangList *fl ) {
2260  int pos = 9999, temp;
2261 
2262  if ( fl==NULL )
2263 return( 0 );
2264 
2265  while ( fl!=NULL ) {
2266  temp = _FeatureOrderId(isgpos,fl->featuretag );
2267  if ( temp<pos ) pos = temp;
2268  fl = fl->next;
2269  }
2270 return( pos );
2271 }
2272 
2274  int isgpos = newotl->lookup_type>=gpos_start;
2275  int pos;
2276  OTLookup *prev, *otl;
2277 
2278  pos = FeatureOrderId(isgpos,newotl->features);
2279  for ( prev=NULL, otl= isgpos ? sf->gpos_lookups : sf->gsub_lookups ;
2280  otl!=NULL && FeatureOrderId(isgpos,newotl->features)<pos;
2281  prev = otl, otl=otl->next );
2282  newotl->next = otl;
2283  if ( prev!=NULL )
2284  prev->next = newotl;
2285  else if ( isgpos )
2286  sf->gpos_lookups = newotl;
2287  else
2288  sf->gsub_lookups = newotl;
2289 }
2290 
2291 /* Before may be:
2292  * A lookup in into_sf, in which case insert new lookup before it
2293  * NULL , in which case insert new lookup at end
2294  * -1 , in which case insert new lookup at start
2295  * -2 , try to guess a good position
2296 */
2297 static void OrderNewLookup(SplineFont *into_sf,OTLookup *otl,OTLookup *before) {
2298  int isgpos = otl->lookup_type>=gpos_start;
2299  OTLookup **head = isgpos ? &into_sf->gpos_lookups : &into_sf->gsub_lookups;
2300  OTLookup *prev;
2301 
2302  if ( before == (OTLookup *) -2 )
2303  SortInsertLookup(into_sf,otl);
2304  else if ( before == (OTLookup *) -1 || *head==NULL || *head==before ) {
2305  otl->next = *head;
2306  *head = otl;
2307  } else {
2308  for ( prev= *head; prev->next!=NULL && prev->next!=before ; prev=prev->next );
2309  otl->next = prev->next;
2310  prev->next = otl;
2311  }
2312 }
2313 
2315  OTLookup *from_otl, OTLookup *before, int do_contents) {
2316  OTLookup *otl;
2317  struct lookup_subtable *sub, *last, *from_sub;
2318  int scnt, l;
2319 
2320  for ( l=0; l<mc->lcnt; ++l ) {
2321  if ( mc->lks[l].from == from_otl ) {
2322  if ( mc->lks[l].old )
2323 return( mc->lks[l].to );
2324  else
2325  break;
2326  }
2327  }
2328 
2329  if ( l>=mc->lmax )
2330  mc->lks = grealloc(mc->lks,(mc->lmax += 20)*sizeof(struct lookup_cvt));
2331  mc->sf_to->changed = true;
2332 
2333  if ( l>=mc->lcnt ) {
2334  otl = chunkalloc(sizeof(OTLookup));
2335  *otl = *from_otl;
2336  memset(&mc->lks[l],0,sizeof(mc->lks[l]));
2337  mc->lks[l].from = from_otl; mc->lks[l].to = otl; ++mc->lcnt;
2338  otl->lookup_name = strconcat(mc->prefix,from_otl->lookup_name);
2339  otl->features = FeatureListCopy(from_otl->features);
2340  otl->next = NULL; otl->subtables = NULL;
2341  OrderNewLookup(mc->sf_to,otl,before);
2342  if ( !do_contents )
2343  FIOTLookupCopyInto(mc->sf_to,mc->sf_from, from_otl, otl, 0, before);
2344  } else
2345  otl = mc->lks[l].to;
2346  if ( !do_contents )
2347 return( otl );
2348 
2349  last = NULL;
2350  scnt = 0;
2351  for ( from_sub = from_otl->subtables; from_sub!=NULL; from_sub=from_sub->next ) {
2352  sub = chunkalloc(sizeof(struct lookup_subtable));
2353  *sub = *from_sub;
2354  sub->lookup = otl;
2355  sub->subtable_name = strconcat(mc->prefix,from_sub->subtable_name);
2356  sub->suffix = copy(sub->suffix);
2357  if ( last==NULL )
2358  otl->subtables = sub;
2359  else
2360  last->next = sub;
2361  last = sub;
2362  if ( from_sub->kc!=NULL )
2363  sub->kc = SF_AddKernClass(mc, from_sub->kc, sub);
2364  else if ( from_sub->fpst!=NULL )
2365  sub->fpst = SF_AddFPST(mc, from_sub->fpst, sub);
2366  else if ( from_sub->anchor_classes )
2367  SF_AddAnchorClasses(mc, from_sub, sub);
2368  else
2369  SF_AddPSTKern(mc, from_sub, sub);
2370  ++scnt;
2371  }
2372  FIOTLookupCopyInto(mc->sf_to,mc->sf_from, from_otl, otl, scnt, before);
2373 return( otl );
2374 }
2375 
2376 static int NeedsPrefix(SplineFont *into_sf,SplineFont *from_sf, OTLookup **list) {
2377  struct lookup_subtable *from_sub;
2378  int i,j,k;
2379  OTLookup *sublist[2];
2380 
2381  sublist[1] = NULL;
2382 
2383  if ( list==NULL || list[0]==NULL )
2384 return( false );
2385  for ( k=0; list[k]!=NULL; ++k ) {
2386  OTLookup *from_otl = list[k];
2387  if ( SFFindLookup(into_sf,from_otl->lookup_name)!=NULL )
2388 return( true );
2389  for ( from_sub = from_otl->subtables; from_sub!=NULL; from_sub=from_sub->next ) {
2390  if ( from_sub->fpst!=NULL ) {
2391  for ( i=0; i<from_sub->fpst->rule_cnt; ++i ) {
2392  struct fpst_rule *r = &from_sub->fpst->rules[i];
2393  for ( j=0; j<r->lookup_cnt; ++j ) {
2394  sublist[0] = r->lookups[j].lookup;
2395  if ( NeedsPrefix(into_sf,from_sf, sublist))
2396 return( true );
2397  }
2398  }
2399  }
2400  }
2401  }
2402 return( false );
2403 }
2404 
2405 OTLookup *OTLookupCopyInto(SplineFont *into_sf,SplineFont *from_sf, OTLookup *from_otl) {
2406  OTLookup *newotl, *list[2];
2407  struct sfmergecontext mc;
2408 
2409  memset(&mc,0,sizeof(mc));
2410  mc.sf_from = from_sf; mc.sf_to = into_sf;
2411 
2412  list[0] = from_otl; list[1] = NULL;
2413  mc.prefix = NeedsPrefix(into_sf,from_sf,list)
2414  ? strconcat(from_sf->fontname,"-") : copy("");
2415  newotl = _OTLookupCopyInto(&mc,from_otl,(OTLookup *) -2,true);
2416  free(mc.lks);
2417  free(mc.prefix);
2418 return( newotl );
2419 }
2420 
2421 void OTLookupsCopyInto(SplineFont *into_sf,SplineFont *from_sf,
2422  OTLookup **list, OTLookup *before) {
2423  int i, do_contents;
2424  struct sfmergecontext mc;
2425 
2426  memset(&mc,0,sizeof(mc));
2427  mc.sf_from = from_sf; mc.sf_to = into_sf;
2428 
2429  mc.prefix = NeedsPrefix(into_sf,from_sf,list)
2430  ? strconcat(from_sf->fontname,"-") : copy("");
2431  for ( i=0; list[i]!=NULL; ++i );
2432  mc.lks = galloc((mc.lmax=i+5)*sizeof(struct lookup_cvt));
2433  /* First create all the lookups and position them in the right order */
2434  /* then create subtables (which may in turn create some new lookups */
2435  /* for contextual lookups which invoke other lookups, don't care how */
2436  /* those nested lookups are ordered) */
2437  for ( do_contents=0; do_contents<2; ++do_contents )
2438  for ( i=0; list[i]!=NULL; ++i )
2439  (void) _OTLookupCopyInto(&mc,list[i],before,do_contents);
2440  free(mc.lks);
2441  free(mc.prefix);
2442 }
2443 
2444 /* ************************************************************************** */
2445 /* ****************************** Apply lookups ***************************** */
2446 /* ************************************************************************** */
2447 
2448 struct lookup_data {
2450  int cnt, max;
2451 
2454 
2456  int lcnt, lmax;
2457  SplineChar ***ligs; /* For each ligature we have an array of SplineChars that are its components preceded by the ligature glyph itself */
2458  /* NULL terminated */
2460  double scale;
2461 };
2462 
2463 static int ApplyLookupAtPos(uint32 tag, OTLookup *otl,struct lookup_data *data,int pos);
2464 
2465 static int GlyphNameInClass(char *name,char *class ) {
2466  char *pt;
2467  int len = strlen(name);
2468 
2469  if ( class==NULL )
2470 return( false );
2471 
2472  pt = class;
2473  while ( (pt=strstr(pt,name))!=NULL ) {
2474  if ( pt==NULL )
2475 return( false );
2476  if ( (pt==class || pt[-1]==' ') && (pt[len]=='\0' || pt[len]==' '))
2477 return( true );
2478  pt+=len;
2479  }
2480 
2481 return( false );
2482 }
2483 
2484 /* ************************************************************************** */
2485 /* ************************* Apply OpenType Lookups ************************* */
2486 /* ************************************************************************** */
2487 
2488 static void LigatureFree(struct lookup_data *data) {
2489  int i;
2490 
2491  if ( data->ligs==NULL )
2492 return;
2493  for ( i=0; data->ligs[i]!=NULL; ++i )
2494  free(data->ligs[i]);
2495 }
2496 
2497 static void LigatureSearch(struct lookup_subtable *sub, struct lookup_data *data) {
2498  SplineFont *sf = data->sf;
2499  int gid, ccnt, cnt, ch, err;
2500  SplineChar *sc;
2501  PST *pst;
2502  char *pt, *start;
2503 
2504  LigatureFree(data);
2505  cnt = 0;
2506  for ( gid=0; gid<sf->glyphcnt; ++gid ) if ( (sc=sf->glyphs[gid])!=NULL ) {
2507  for ( pst=sc->possub; pst!=NULL; pst=pst->next ) if ( pst->subtable==sub ) {
2508  for ( pt = pst->u.lig.components, ccnt=0; *pt; ++pt )
2509  if ( *pt==' ' )
2510  ++ccnt;
2511  if ( cnt>=data->lmax )
2512  data->ligs = grealloc(data->ligs,(data->lmax+=100)*sizeof(SplineChar **));
2513  data->ligs[cnt] = galloc((ccnt+3)*sizeof(SplineChar *));
2514  data->ligs[cnt][0] = sc;
2515  ccnt = 1;
2516  err = 0;
2517  for ( pt = pst->u.lig.components; *pt; ) {
2518  while ( *pt==' ' ) ++pt;
2519  if ( *pt=='\0' )
2520  break;
2521  for ( start=pt; *pt!='\0' && *pt!=' '; ++pt );
2522  ch = *pt; *pt = '\0';
2523  data->ligs[cnt][ccnt++] = SFGetChar(sf,-1,start);
2524  *pt = ch;
2525  if ( data->ligs[cnt][ccnt-1]==NULL )
2526  err = 1;
2527  }
2528  if ( !err )
2529  data->ligs[cnt++][ccnt] = NULL;
2530  }
2531  }
2532  if ( cnt>=data->lmax )
2533  data->ligs = grealloc(data->ligs,(data->lmax+=1)*sizeof(SplineChar **));
2534  data->ligs[cnt] = NULL;
2535  data->lcnt = cnt;
2536 }
2537 
2538 static int skipglyphs(int lookup_flags, struct lookup_data *data, int pos) {
2539  int mc, glyph_class;
2540  /* The lookup flags tell us what glyphs to ignore. Skip over anything we */
2541  /* should ignore */
2542 
2543  if ( lookup_flags==0 )
2544 return( pos );
2545  mc = (lookup_flags>>8);
2546  if ( mc<0 || mc>=data->sf->mark_class_cnt )
2547  mc = 0;
2548  while ( pos<data->cnt ) {
2549  glyph_class = gdefclass(data->str[pos].sc);
2550  /* 1=>base, 2=>ligature, 3=>mark, 4=>component?, 0=>.notdef */
2551  if ( (glyph_class==1 && (lookup_flags&pst_ignorebaseglyphs)) ||
2552  (glyph_class==2 && (lookup_flags&pst_ignoreligatures)) ||
2553  (glyph_class==3 && (lookup_flags&pst_ignorecombiningmarks)) ||
2554  (glyph_class==3 && mc!=0 &&
2555  !GlyphNameInClass(data->str[pos].sc->name,data->sf->mark_classes[mc])) ) {
2556  ++pos;
2557  } else
2558  break;
2559  }
2560 return( pos );
2561 }
2562 
2563 static int bskipmarkglyphs(int lookup_flags, struct lookup_data *data, int pos) {
2564  int mc, glyph_class;
2565  /* The lookup flags tell us what glyphs to ignore. Skip over anything we */
2566  /* should ignore. Here we skip backward */
2567 
2568  mc = (lookup_flags>>8);
2569  if ( mc<0 || mc>=data->sf->mark_class_cnt )
2570  mc = 0;
2571  while ( pos>=0 ) {
2572  glyph_class = gdefclass(data->str[pos].sc);
2573  /* 1=>base, 2=>ligature, 3=>mark, 4=>component?, 0=>.notdef */
2574  if ( glyph_class==3 )
2575  --pos;
2576  else if ( (glyph_class==1 && (lookup_flags&pst_ignorebaseglyphs)) ||
2577  (glyph_class==2 && (lookup_flags&pst_ignoreligatures)) ||
2578  (glyph_class==3 && (lookup_flags&pst_ignorecombiningmarks)) ||
2579  (glyph_class==3 && mc!=0 &&
2580  !GlyphNameInClass(data->str[pos].sc->name,data->sf->mark_classes[mc])) ) {
2581  --pos;
2582  } else
2583  break;
2584  }
2585 return( pos );
2586 }
2587 
2588 static int bskipglyphs(int lookup_flags, struct lookup_data *data, int pos) {
2589  int mc, glyph_class;
2590  /* The lookup flags tell us what glyphs to ignore. Skip over anything we */
2591  /* should ignore. Here we skip backward */
2592 
2593  if ( lookup_flags==0 )
2594 return( pos );
2595  mc = (lookup_flags>>8);
2596  if ( mc<0 || mc>=data->sf->mark_class_cnt )
2597  mc = 0;
2598  while ( pos>=0 ) {
2599  glyph_class = gdefclass(data->str[pos].sc);
2600  /* 1=>base, 2=>ligature, 3=>mark, 4=>component?, 0=>.notdef */
2601  if ( (glyph_class==1 && (lookup_flags&pst_ignorebaseglyphs)) ||
2602  (glyph_class==2 && (lookup_flags&pst_ignoreligatures)) ||
2603  (glyph_class==3 && (lookup_flags&pst_ignorecombiningmarks)) ||
2604  (glyph_class==3 && mc!=0 &&
2605  !GlyphNameInClass(data->str[pos].sc->name,data->sf->mark_classes[mc])) ) {
2606  --pos;
2607  } else
2608  break;
2609  }
2610 return( pos );
2611 }
2612 
2614  int pos, struct fpst_rule **_rule) {
2615  int i, cpos, retpos, r;
2616  FPST *fpst = sub->fpst;
2617  int lookup_flags = sub->lookup->lookup_flags;
2618  char *pt;
2619 
2620  /* If we should skip the current glyph then don't try for a match here */
2621  cpos = skipglyphs(lookup_flags,data,pos);
2622  if ( cpos!=pos )
2623 return( 0 );
2624 
2625  for ( r=0; r<fpst->rule_cnt; ++r ) {
2626  struct fpst_rule *rule = &fpst->rules[r];
2627  for ( i=pos; i<data->cnt; ++i )
2628  data->str[i].context_pos = -1;
2629 
2630 /* Handle backtrack (backtrace in the rule is stored in reverse textual order) */
2631  if ( fpst->type == pst_chainpos || fpst->type == pst_chainsub ) {
2632  if ( fpst->format==pst_glyphs ) {
2633  pt = rule->u.glyph.back;
2634  for ( i=bskipglyphs(lookup_flags,data,pos-1), cpos=0; i>=0; i = bskipglyphs(lookup_flags,data,i-1)) {
2635  char *name = data->str[i].sc->name;
2636  int len = strlen( name );
2637  if ( strncmp(name,pt,len)!=0 || (pt[len]!='\0' && pt[len]!=' '))
2638  break;
2639  pt += len;
2640  while ( *pt==' ' ) ++pt;
2641  }
2642  if ( *pt!='\0' )
2643  continue; /* didn't match */
2644  } else if ( fpst->format==pst_class ) {
2645  for ( i=bskipglyphs(lookup_flags,data,pos-1), cpos=0; i>=0 && cpos<rule->u.class.bcnt; i = bskipglyphs(lookup_flags,data,i-1)) {
2646  if ( !GlyphNameInClass(data->str[i].sc->name,fpst->bclass[rule->u.class.bclasses[cpos]]) )
2647  break;
2648  ++cpos;
2649  }
2650  if ( cpos!=rule->u.class.bcnt )
2651  continue; /* didn't match */
2652  } else if ( fpst->format==pst_coverage ) {
2653  for ( i=bskipglyphs(lookup_flags,data,pos-1), cpos=0; i>=0 && cpos<rule->u.coverage.bcnt; i = bskipglyphs(lookup_flags,data,i-1)) {
2654  if ( !GlyphNameInClass(data->str[i].sc->name,rule->u.coverage.bcovers[cpos]) )
2655  break;
2656  ++cpos;
2657  }
2658  if ( cpos<rule->u.coverage.bcnt )
2659  continue; /* didn't match */
2660  }
2661  }
2662 /* Handle Match */
2663  if ( fpst->format==pst_glyphs ) {
2664  pt = rule->u.glyph.names;
2665  for ( i=pos, cpos=0; i<data->cnt && *pt!='\0'; i = skipglyphs(lookup_flags,data,i+1)) {
2666  char *name = data->str[i].sc->name;
2667  int len = strlen( name );
2668  if ( strncmp(name,pt,len)!=0 || (pt[len]!='\0' && pt[len]!=' '))
2669  break;
2670  data->str[i].context_pos = cpos++;
2671  pt += len;
2672  while ( *pt==' ' ) ++pt;
2673  }
2674  if ( *pt!='\0' )
2675  continue; /* didn't match */
2676  } else if ( fpst->format==pst_class ) {
2677  for ( i=pos, cpos=0; i<data->cnt && cpos<rule->u.class.ncnt; i = skipglyphs(lookup_flags,data,i+1)) {
2678  int class = rule->u.class.nclasses[cpos];
2679  if ( class!=0 ) {
2680  if ( !GlyphNameInClass(data->str[i].sc->name,fpst->nclass[class]) )
2681  break;
2682  } else {
2683  int c;
2684  /* Ok, to match class 0 we must fail to match all other classes */
2685  for ( c=1; c<fpst->nccnt; ++c )
2686  if ( !GlyphNameInClass(data->str[i].sc->name,fpst->nclass[c]) )
2687  break;
2688  if ( c!=fpst->nccnt )
2689  break; /* It matched another class => not in class 0 */
2690  }
2691  data->str[i].context_pos = cpos++;
2692  }
2693  if ( cpos<rule->u.class.ncnt )
2694  continue; /* didn't match */
2695  } else if ( fpst->format==pst_coverage ) {
2696  for ( i=pos, cpos=0; i<data->cnt && cpos<rule->u.coverage.ncnt; i = skipglyphs(lookup_flags,data,i+1)) {
2697  if ( !GlyphNameInClass(data->str[i].sc->name,rule->u.coverage.ncovers[cpos]) )
2698  break;
2699  data->str[i].context_pos = cpos++;
2700  }
2701  if ( cpos<rule->u.coverage.ncnt )
2702  continue; /* didn't match */
2703  } else
2704 return( 0 ); /* Not ready to deal with reverse chainging */
2705 
2706  retpos = i;
2707 /* Handle lookahead */
2708  if ( fpst->type == pst_chainpos || fpst->type == pst_chainsub ) {
2709  if ( fpst->format==pst_glyphs ) {
2710  pt = rule->u.glyph.fore;
2711  for ( i=retpos; i<data->cnt && *pt!='\0'; i = skipglyphs(lookup_flags,data,i+1)) {
2712  char *name = data->str[i].sc->name;
2713  int len = strlen( name );
2714  if ( strncmp(name,pt,len)!=0 || (pt[len]!='\0' && pt[len]!=' '))
2715  break;
2716  pt += len;
2717  while ( *pt==' ' ) ++pt;
2718  }
2719  if ( *pt!='\0' )
2720  continue; /* didn't match */
2721  } else if ( fpst->format==pst_class ) {
2722  for ( i=retpos, cpos=0; i<data->cnt && cpos<rule->u.class.fcnt; i = skipglyphs(lookup_flags,data,i+1)) {
2723  if ( !GlyphNameInClass(data->str[i].sc->name,fpst->fclass[rule->u.class.fclasses[cpos]]) )
2724  break;
2725  cpos++;
2726  }
2727  if ( cpos<rule->u.class.fcnt )
2728  continue; /* didn't match */
2729  } else if ( fpst->format==pst_coverage ) {
2730  for ( i=retpos, cpos=0; i<data->cnt && cpos<rule->u.coverage.fcnt; i = skipglyphs(lookup_flags,data,i+1)) {
2731  if ( !GlyphNameInClass(data->str[i].sc->name,rule->u.coverage.fcovers[cpos]) )
2732  break;
2733  cpos++;
2734  }
2735  if ( cpos<rule->u.coverage.fcnt )
2736  continue; /* didn't match */
2737  }
2738  }
2739  *_rule = rule;
2740 return( retpos );
2741  }
2742 return( 0 );
2743 }
2744 
2745 static int ApplySingleSubsAtPos(struct lookup_subtable *sub,struct lookup_data *data,int pos) {
2746  PST *pst;
2747  SplineChar *sc;
2748 
2749  for ( pst=data->str[pos].sc->possub; pst!=NULL && pst->subtable!=sub; pst=pst->next );
2750  if ( pst==NULL )
2751 return( 0 );
2752 
2753  sc = SFGetChar(data->sf,-1,pst->u.subs.variant);
2754  if ( sc!=NULL ) {
2755  data->str[pos].sc = sc;
2756 return( pos+1 );
2757  } else if ( strcmp(pst->u.subs.variant,MAC_DELETED_GLYPH_NAME)==0 ) {
2758  /* Under AAT we delete the glyph. But OpenType doesn't have that concept */
2759  int i;
2760  for ( i=pos+1; i<data->cnt; ++i )
2761  data->str[pos-1] = data->str[pos];
2762  --data->cnt;
2763 return( pos );
2764  } else {
2765 return( 0 );
2766  }
2767 }
2768 
2769 static int ApplyMultSubsAtPos(struct lookup_subtable *sub,struct lookup_data *data,int pos) {
2770  PST *pst;
2771  SplineChar *sc;
2772  char *start, *pt;
2773  int mcnt, ch, i;
2774  SplineChar *mults[20];
2775 
2776  for ( pst=data->str[pos].sc->possub; pst!=NULL && pst->subtable!=sub; pst=pst->next );
2777  if ( pst==NULL )
2778 return( 0 );
2779 
2780  mcnt = 0;
2781  for ( start = pst->u.alt.components; *start==' '; ++start);
2782  for ( ; *start; ) {
2783  for ( pt=start; *pt!='\0' && *pt!=' '; ++pt );
2784  ch = *pt; *pt = '\0';
2785  sc = SFGetChar(data->sf,-1,start);
2786  *pt = ch;
2787  if ( sc==NULL )
2788 return( 0 );
2789  if ( mcnt<20 ) mults[mcnt++] = sc;
2790  while ( *pt==' ' ) ++pt;
2791  start = pt;
2792  }
2793 
2794  if ( mcnt==0 ) {
2795  /* Is this legal? that is can we remove a glyph with an empty multiple? */
2796  for ( i=pos+1; i<data->cnt; ++i )
2797  data->str[i-1] = data->str[i];
2798  --data->cnt;
2799 return( pos );
2800  } else if ( mcnt==1 ) {
2801  data->str[pos].sc = mults[0];
2802 return( pos+1 );
2803  } else {
2804  if ( data->cnt+mcnt-1 >= data->max )
2805  data->str = grealloc(data->str,(data->max+=mcnt) * sizeof( struct opentype_str ));
2806  for ( i=data->cnt-1; i>pos; --i )
2807  data->str[i+mcnt-1] = data->str[i];
2808  memset(data->str+pos,0,mcnt*sizeof(struct opentype_str));
2809  for ( i=0; i<mcnt; ++i ) {
2810  data->str[pos+i].sc = mults[i];
2811  data->str[pos+i].orig_index = data->str[pos].orig_index;
2812  }
2813  data->cnt += (mcnt-1);
2814 return( pos+mcnt );
2815  }
2816 }
2817 
2818 static int ApplyAltSubsAtPos(struct lookup_subtable *sub,struct lookup_data *data,int pos) {
2819  PST *pst;
2820  SplineChar *sc;
2821  char *start, *pt, ch;
2822 
2823  for ( pst=data->str[pos].sc->possub; pst!=NULL && pst->subtable!=sub; pst=pst->next );
2824  if ( pst==NULL )
2825 return( 0 );
2826 
2827  for ( start = pst->u.alt.components; *start==' '; ++start);
2828  for ( ; *start; ) {
2829  for ( pt=start; *pt!='\0' && *pt!=' '; ++pt );
2830  ch = *pt; *pt = '\0';
2831  sc = SFGetChar(data->sf,-1,start);
2832  *pt = ch;
2833  if ( sc!=NULL ) {
2834  data->str[pos].sc = sc;
2835 return( pos+1 );
2836  }
2837  while ( *pt==' ' ) ++pt;
2838  start = pt;
2839  }
2840 return( 0 );
2841 }
2842 
2844  int i,k, lpos, npos;
2845  int lookup_flags = sub->lookup->lookup_flags;
2846  int match_found = -1, match_len=0;
2847 
2848  if ( data->lig_owner!=sub )
2850  for ( i=0; i<data->lcnt; ++i ) {
2851  if ( data->ligs[i][1]==data->str[pos].sc ) {
2852  lpos = 0;
2853  npos = pos+1;
2854  for ( k=2; data->ligs[i][k]!=NULL; ++k ) {
2855  npos = skipglyphs(lookup_flags,data,npos);
2856  if ( npos>=data->cnt || data->str[npos].sc != data->ligs[i][k] )
2857  break;
2858  ++npos;
2859  }
2860  if ( data->ligs[i][k]==NULL ) {
2861  if ( match_found==-1 || k>match_len ) {
2862  match_found = i;
2863  match_len = k;
2864  }
2865  }
2866  }
2867  }
2868  if ( match_found!=-1 ) {
2869  /* Matched. Remove the component glyphs, and note which component */
2870  /* any intervening marks should be attached to */
2871  data->str[pos].sc = data->ligs[match_found][0];
2872  npos = pos+1;
2873  for ( k=2; data->ligs[match_found][k]!=NULL; ++k ) {
2874  lpos = skipglyphs(lookup_flags,data,npos);
2875  for ( ; npos<lpos; ++npos )
2876  data->str[npos].lig_pos = k-2;
2877  /* Remove this glyph (copy the final NUL too) */
2878  for ( ++lpos; lpos<=data->cnt; ++lpos )
2879  data->str[lpos-1] = data->str[lpos];
2880  --data->cnt;
2881  }
2882  /* Any marks after the last component (which should be attached */
2883  /* to it) will not have been tagged, so do that now */
2884  lpos = skipglyphs(lookup_flags,data,npos);
2885  for ( ; npos<lpos; ++npos )
2886  data->str[npos].lig_pos = k-2;
2887 return( pos+1 );
2888  }
2889 
2890 return( 0 );
2891 }
2892 
2893 static int ApplyContextual(struct lookup_subtable *sub,struct lookup_data *data,int pos) {
2894  /* On this level there is no difference between GPOS/GSUB contextuals */
2895  /* If the contextual matches, then we apply the lookups, otherwise we */
2896  /* don't. Now the lookups will be different, but we don't care here */
2897  struct fpst_rule *rule;
2898  int retpos, i,j;
2899 
2900  retpos = ContextualMatch(sub,data,pos,&rule);
2901  if ( retpos==0 )
2902 return( 0 );
2903  for ( i=0; i<rule->lookup_cnt; ++i ) {
2904  for ( j=pos; j<data->cnt; ++j ) {
2905  if ( data->str[j].context_pos == rule->lookups[i].seq ) {
2906  ApplyLookupAtPos(0,rule->lookups[i].lookup,data,j);
2907  break;
2908  }
2909  }
2910  }
2911 return( retpos );
2912 }
2913 
2914 #ifdef FONTFORGE_CONFIG_DEVICETABLES
2915 static int FigureDeviceTable(DeviceTable *dt,int pixelsize) {
2916 
2917  if ( dt==NULL || dt->corrections==NULL || pixelsize<dt->first_pixel_size ||
2918  pixelsize>dt->last_pixel_size )
2919 return( 0 );
2920 
2921 return( dt->corrections[pixelsize - dt->last_pixel_size] );
2922 }
2923 #endif
2924 
2925 static int ApplySinglePosAtPos(struct lookup_subtable *sub,struct lookup_data *data,int pos) {
2926  PST *pst;
2927 
2928  for ( pst=data->str[pos].sc->possub; pst!=NULL && pst->subtable!=sub; pst=pst->next );
2929  if ( pst==NULL )
2930 return( 0 );
2931 
2932  data->str[pos].vr.xoff += rint( pst->u.pos.xoff * data->scale );
2933  data->str[pos].vr.yoff += rint( pst->u.pos.yoff * data->scale );
2934  data->str[pos].vr.h_adv_off += rint( pst->u.pos.h_adv_off * data->scale );
2935  data->str[pos].vr.v_adv_off += rint( pst->u.pos.v_adv_off * data->scale );
2936 #ifdef FONTFORGE_CONFIG_DEVICETABLES
2937  if ( pst->u.pos.adjust!=NULL ) {
2938  data->str[pos].vr.xoff += FigureDeviceTable(&pst->u.pos.adjust->xadjust,data->pixelsize);
2939  data->str[pos].vr.yoff += FigureDeviceTable(&pst->u.pos.adjust->yadjust,data->pixelsize);
2940  data->str[pos].vr.h_adv_off += FigureDeviceTable(&pst->u.pos.adjust->xadv,data->pixelsize);
2941  data->str[pos].vr.v_adv_off += FigureDeviceTable(&pst->u.pos.adjust->yadv,data->pixelsize);
2942  }
2943 #endif
2944 return( pos+1 );
2945 }
2946 
2947 static int ApplyPairPosAtPos(struct lookup_subtable *sub,struct lookup_data *data,int pos) {
2948  PST *pst;
2949  int npos, isv, within;
2950  KernPair *kp;
2951 
2952  npos = skipglyphs(sub->lookup->lookup_flags,data,pos+1);
2953  if ( npos>=data->cnt )
2954 return( 0 );
2955  if ( sub->kc!=NULL ) {
2956  within = KCFindIndex(sub->kc,data->str[pos].sc->name,data->str[npos].sc->name);
2957  if ( within==-1 )
2958 return( 0 );
2959  data->str[pos].kc_index = within;
2960  data->str[pos].kc = sub->kc;
2961  if ( sub->vertical_kerning ) {
2962  data->str[pos].vr.v_adv_off += rint( sub->kc->offsets[within] * data->scale );
2963 #ifdef FONTFORGE_CONFIG_DEVICETABLES
2964  data->str[pos].vr.v_adv_off += FigureDeviceTable(&sub->kc->adjusts[within],data->pixelsize);
2965 #endif
2966  } else if ( sub->lookup->lookup_flags & pst_r2l ) {
2967  data->str[npos].vr.h_adv_off += rint( sub->kc->offsets[within] * data->scale );
2968 #ifdef FONTFORGE_CONFIG_DEVICETABLES
2969  data->str[npos].vr.h_adv_off += FigureDeviceTable(&sub->kc->adjusts[within],data->pixelsize);
2970 #endif
2971  } else {
2972  data->str[pos].vr.h_adv_off += rint( sub->kc->offsets[within] * data->scale );
2973 #ifdef FONTFORGE_CONFIG_DEVICETABLES
2974  data->str[pos].vr.h_adv_off += FigureDeviceTable(&sub->kc->adjusts[within],data->pixelsize);
2975 #endif
2976  }
2977 return( pos+1 );
2978  } else {
2979  for ( pst=data->str[pos].sc->possub; pst!=NULL; pst=pst->next ) {
2980  if ( pst->subtable==sub && strcmp(pst->u.pair.paired,data->str[npos].sc->name)==0 ) {
2981  data->str[pos].vr.xoff += rint( pst->u.pair.vr[0].xoff * data->scale);
2982  data->str[pos].vr.yoff += rint( pst->u.pair.vr[0].yoff * data->scale);
2983  data->str[pos].vr.h_adv_off += rint( pst->u.pair.vr[0].h_adv_off * data->scale);
2984  data->str[pos].vr.v_adv_off += rint( pst->u.pair.vr[0].v_adv_off * data->scale);
2985  data->str[npos].vr.xoff += rint( pst->u.pair.vr[1].xoff * data->scale);
2986  data->str[npos].vr.yoff += rint( pst->u.pair.vr[1].yoff * data->scale);
2987  data->str[npos].vr.h_adv_off += rint( pst->u.pair.vr[1].h_adv_off * data->scale);
2988  data->str[npos].vr.v_adv_off += rint( pst->u.pair.vr[1].v_adv_off * data->scale);
2989 #ifdef FONTFORGE_CONFIG_DEVICETABLES
2990  /* I got bored. I should do all of them */
2991  if ( pst->u.pair.vr[0].adjust!=NULL ) {
2992  data->str[pos].vr.h_adv_off += FigureDeviceTable(&pst->u.pair.vr[0].adjust->xadv,data->pixelsize);
2993  }
2994 #endif
2995 return( pos+1 ); /* We do NOT want to return npos+1 */
2996  }
2997  }
2998  for ( isv = 0; isv<2; ++isv ) {
2999  for ( kp = isv ? data->str[pos].sc->vkerns : data->str[pos].sc->kerns; kp!=NULL; kp=kp->next ) {
3000  if ( kp->subtable == sub && kp->sc == data->str[npos].sc ) {
3001  data->str[pos].kp = kp;
3002  if ( isv ) {
3003  data->str[pos].vr.v_adv_off += rint( kp->off * data->scale);
3004 #ifdef FONTFORGE_CONFIG_DEVICETABLES
3005  data->str[pos].vr.v_adv_off += FigureDeviceTable(kp->adjust,data->pixelsize);
3006 #endif
3007  } else if ( sub->lookup->lookup_flags & pst_r2l ) {
3008  data->str[npos].vr.h_adv_off += rint( kp->off * data->scale);
3009 #ifdef FONTFORGE_CONFIG_DEVICETABLES
3010  data->str[npos].vr.h_adv_off += FigureDeviceTable(kp->adjust,data->pixelsize);
3011 #endif
3012  } else {
3013  data->str[pos].vr.h_adv_off += rint( kp->off * data->scale);
3014 #ifdef FONTFORGE_CONFIG_DEVICETABLES
3015  data->str[pos].vr.h_adv_off += FigureDeviceTable(kp->adjust,data->pixelsize);
3016 #endif
3017  }
3018 return( pos+1 );
3019  }
3020  }
3021  }
3022  }
3023 
3024 return( 0 );
3025 }
3026 
3027 static int ApplyAnchorPosAtPos(struct lookup_subtable *sub,struct lookup_data *data,int pos) {
3028  AnchorPoint *ap1, *ap2;
3029  int bpos;
3030 
3031  /* Anchors do not position the base glyph, but the mark (or second glyph */
3032  /* of a cursive attachment). This means we don't apply the attachment when*/
3033  /* we meet the first glyph, but wait until we meet the second, and then */
3034  /* walk backwards */
3035  /* The backwards walk is different depending on the lookup type (I think) */
3036  /* mark to base and mark to ligature lookups will skip all marks even if */
3037  /* lookup flags don't specify that */
3038  /* mark to mark, and cursive attachment only skip what the lookup flags */
3039  /* tell them to skip. */
3040  for ( ap2=data->str[pos].sc->anchor; ap2!=NULL ; ap2=ap2->next ) {
3041  if ( ap2->anchor->subtable==sub && (ap2->type == at_mark || ap2->type == at_centry))
3042  break;
3043  }
3044  if ( ap2==NULL ) {
3045  /* This subtable is not used by this glyph ... at least this glyph is */
3046  /* neither a mark nor an entry point for this subtable */
3047 return( 0 );
3048  }
3049 
3050  /* There's only going to be one mark anchor on a glyph in a given subtable*/
3051  /* And cursive attachments only allow one anchor class per subtable */
3052  /* in either case we have already found the only attachment site possible */
3053  /* in the current glyph */
3054 
3055  if ( sub->lookup->lookup_type == gpos_mark2base ||
3056  sub->lookup->lookup_type == gpos_mark2ligature )
3057  bpos = bskipmarkglyphs(sub->lookup->lookup_flags,data,pos-1);
3058  else
3059  bpos = bskipglyphs(sub->lookup->lookup_flags,data,pos-1);
3060  if ( bpos==-1 )
3061 return( 0 ); /* No match */
3062 
3063  if ( sub->lookup->lookup_type == gpos_cursive ) {
3064  for ( ap1=data->str[bpos].sc->anchor; ap1!=NULL ; ap1=ap1->next ) {
3065  if ( ap1->anchor==ap2->anchor && ap1->type==at_cexit )
3066  break;
3067  }
3068  } else if ( sub->lookup->lookup_type == gpos_mark2ligature ) {
3069  for ( ap1=data->str[bpos].sc->anchor; ap1!=NULL ; ap1=ap1->next ) {
3070  if ( ap1->anchor==ap2->anchor && ap1->type==at_baselig &&
3071  ap1->lig_index == data->str[pos].lig_pos )
3072  break;
3073  }
3074  } else {
3075  for ( ap1=data->str[bpos].sc->anchor; ap1!=NULL ; ap1=ap1->next ) {
3076  if ( ap1->anchor==ap2->anchor &&
3077  (ap1->type==at_basechar || ap1->type==at_basemark) )
3078  break;
3079  }
3080  }
3081  if ( ap1==NULL )
3082 return( 0 ); /* No match */
3083 
3084 /* This probably doesn't work for vertical text */
3085  data->str[pos].vr.yoff = data->str[bpos].vr.yoff +
3086  rint((ap1->me.y - ap2->me.y) * data->scale);
3087 #ifdef FONTFORGE_CONFIG_DEVICETABLES
3088  data->str[pos].vr.yoff += FigureDeviceTable(&ap1->yadjust,data->pixelsize)-
3089  FigureDeviceTable(&ap2->yadjust,data->pixelsize);
3090 #endif
3091  if ( sub->lookup->lookup_flags&pst_r2l ) {
3092  data->str[pos].vr.xoff = data->str[bpos].vr.xoff +
3093  rint( -(ap1->me.x - ap2->me.x)*data->scale );
3094 #ifdef FONTFORGE_CONFIG_DEVICETABLES
3095  data->str[pos].vr.xoff -= FigureDeviceTable(&ap1->xadjust,data->pixelsize)-
3096  FigureDeviceTable(&ap2->xadjust,data->pixelsize);
3097 #endif
3098  } else {
3099  data->str[pos].vr.xoff = data->str[bpos].vr.xoff +
3100  rint( (ap1->me.x - ap2->me.x - data->str[bpos].sc->width)*data->scale -
3101  data->str[bpos].vr.h_adv_off);
3102 #ifdef FONTFORGE_CONFIG_DEVICETABLES
3103  data->str[pos].vr.xoff += FigureDeviceTable(&ap1->xadjust,data->pixelsize)-
3104  FigureDeviceTable(&ap2->xadjust,data->pixelsize);
3105 #endif
3106  }
3107 
3108 return( pos+1 );
3109 }
3110 
3111 static int ConditionalTagOk(uint32 tag, OTLookup *otl,struct lookup_data *data,int pos) {
3112  int npos, bpos;
3113  uint32 script;
3114  int before_in_script, after_in_script;
3115 
3116  if ( tag==CHR('i','n','i','t') || tag==CHR('i','s','o','l') ||
3117  tag==CHR('f','i','n','a') || tag==CHR('m','e','d','i') ) {
3118  npos = skipglyphs(otl->lookup_flags,data,pos+1);
3119  bpos = bskipglyphs(otl->lookup_flags,data,pos-1);
3120  script = SCScriptFromUnicode(data->str[pos].sc);
3121  before_in_script = (bpos>=0 && SCScriptFromUnicode(data->str[bpos].sc)==script);
3122  after_in_script = (npos<data->cnt && SCScriptFromUnicode(data->str[npos].sc)==script);
3123  if ( tag==CHR('i','n','i','t') )
3124 return( !before_in_script && after_in_script );
3125  else if ( tag==CHR('i','s','o','l') )
3126 return( !before_in_script && !after_in_script );
3127  else if ( tag==CHR('f','i','n','a') )
3128 return( before_in_script && !after_in_script );
3129  else
3130 return( before_in_script && after_in_script );
3131  }
3132 
3133 return( true );
3134 }
3135 
3136 static int ApplyLookupAtPos(uint32 tag, OTLookup *otl,struct lookup_data *data,int pos) {
3137  struct lookup_subtable *sub;
3138  int newpos;
3139 
3140  /* Some tags imply a conditional check. Do that now */
3141  if ( !ConditionalTagOk(tag,otl,data,pos))
3142 return( 0 );
3143 
3144  for ( sub=otl->subtables; sub!=NULL; sub=sub->next ) {
3145  switch ( otl->lookup_type ) {
3146  case gsub_single:
3147  newpos = ApplySingleSubsAtPos(sub,data,pos);
3148  break;
3149  case gsub_multiple:
3150  newpos = ApplyMultSubsAtPos(sub,data,pos);
3151  break;
3152  case gsub_alternate:
3153  newpos = ApplyAltSubsAtPos(sub,data,pos);
3154  break;
3155  case gsub_ligature:
3156  newpos = ApplyLigatureSubsAtPos(sub,data,pos);
3157  break;
3158  case gsub_context:
3159  newpos = ApplyContextual(sub,data,pos);
3160  break;
3161  case gsub_contextchain:
3162  newpos = ApplyContextual(sub,data,pos);
3163  break;
3164  case gsub_reversecchain:
3165  newpos = ApplySingleSubsAtPos(sub,data,pos);
3166  break;
3167 
3168  case gpos_single:
3169  newpos = ApplySinglePosAtPos(sub,data,pos);
3170  break;
3171  case gpos_pair:
3172  newpos = ApplyPairPosAtPos(sub,data,pos);
3173  break;
3174  case gpos_cursive:
3175  newpos = ApplyAnchorPosAtPos(sub,data,pos);
3176  break;
3177  case gpos_mark2base:
3178  newpos = ApplyAnchorPosAtPos(sub,data,pos);
3179  break;
3180  case gpos_mark2ligature:
3181  newpos = ApplyAnchorPosAtPos(sub,data,pos);
3182  break;
3183  case gpos_mark2mark:
3184  newpos = ApplyAnchorPosAtPos(sub,data,pos);
3185  break;
3186  case gpos_context:
3187  newpos = ApplyContextual(sub,data,pos);
3188  break;
3189  case gpos_contextchain:
3190  newpos = ApplyContextual(sub,data,pos);
3191  break;
3192  default:
3193  newpos = 0;
3194  break;
3195  }
3196  /* if a subtable worked, we don't try to apply the next one */
3197  if ( newpos!=0 )
3198 return( newpos );
3199  }
3200 return( 0 );
3201 }
3202 
3203 static void ApplyLookup(uint32 tag, OTLookup *otl,struct lookup_data *data) {
3204  int pos, npos;
3205  /* OpenType */
3206  for ( pos = 0; pos<data->cnt; ) {
3207  npos = ApplyLookupAtPos(tag,otl,data,pos);
3208  if ( npos<=pos) /* !!!!! */
3209  npos = pos+1;
3210  pos = npos;
3211  }
3212 }
3213 
3215  int i,l;
3216  struct scriptlanglist *sl;
3217 
3218  if ( flist==NULL )
3219 return( 0 );
3220 
3221  while ( fl!=NULL ) {
3222  for ( i=0; flist[i]!=0; ++i ) {
3223  if ( fl->featuretag==flist[i] )
3224  break;
3225  }
3226  if ( flist[i]!=0 ) {
3227  for ( sl=fl->scripts; sl!=NULL; sl=sl->next ) {
3228  if ( sl->script == script ) {
3229  for ( l=0; l<sl->lang_cnt; ++l )
3230  if ( (l<MAX_LANG && sl->langs[l]==lang) ||
3231  (l>=MAX_LANG && sl->morelangs[l-MAX_LANG]==lang))
3232 return( fl->featuretag );
3233  }
3234  }
3235  }
3236  fl = fl->next;
3237  }
3238 return( 0 );
3239 }
3240 
3241 /* This routine takes a string of glyphs and applies the opentype transformations */
3242 /* indicated by the features (and script and language) we are passed, it returns */
3243 /* a transformed string with substitutions applied and containing positioning */
3244 /* info */
3246  int pixelsize, SplineChar **glyphs) {
3247  int isgpos, cnt;
3248  OTLookup *otl;
3249  struct lookup_data data;
3250  uint32 *langs, templang;
3251  int i;
3252 
3253  memset(&data,0,sizeof(data));
3254  for ( cnt=0; glyphs[cnt]!=NULL; ++cnt );
3255  data.str = gcalloc(cnt+1,sizeof(struct opentype_str));
3256  data.cnt = data.max = cnt;
3257  for ( cnt=0; glyphs[cnt]!=NULL; ++cnt ) {
3258  data.str[cnt].sc = glyphs[cnt];
3259  data.str[cnt].orig_index = cnt;
3260  data.str[cnt].lig_pos = data.str[cnt].context_pos = -1;
3261  }
3262  if ( sf->cidmaster!=NULL ) sf=sf->cidmaster;
3263  data.sf = sf;
3264  data.pixelsize = pixelsize;
3265  data.scale = pixelsize/(double) (sf->ascent+sf->descent);
3266 
3267  /* Indic glyph reordering???? */
3268  for ( isgpos=0; isgpos<2; ++isgpos ) {
3269  /* Check that this table has an entry for this language */
3270  /* if it doesn't use the default language */
3271  /* GPOS/GSUB may have different language sets, so we must be prepared */
3272  templang = lang;
3273  langs = SFLangsInScript(sf,isgpos,script);
3274  for ( i=0; langs[i]!=0 && langs[i]!=lang; ++i );
3275  if ( langs[i]==0 )
3276  templang = DEFAULT_LANG;
3277  free(langs);
3278 
3279  for ( otl = isgpos ? sf->gpos_lookups : sf->gsub_lookups; otl!=NULL ; otl = otl->next ) {
3280  uint32 tag;
3281  if ( (tag=FSLLMatches(otl->features,flist,script,templang))!=0 )
3282  ApplyLookup(tag,otl,&data);
3283  }
3284  }
3285  LigatureFree(&data);
3286  free(data.ligs);
3287 
3288  data.str = grealloc(data.str,(data.cnt+1)*sizeof(struct opentype_str));
3289  memset(&data.str[data.cnt],0,sizeof(struct opentype_str));
3290 return( data.str );
3291 }
3292 
3293 static void doreplace(char **haystack,char *start,char *search,char *rpl,int slen) {
3294  int rlen;
3295  char *pt = start+slen;
3296  (void)search;
3297  rlen = strlen(rpl);
3298  if ( slen>=rlen ) {
3299  memcpy(start,rpl,rlen);
3300  if ( slen>rlen ) {
3301  int diff = slen-rlen;
3302  for ( ; *pt ; ++pt )
3303  pt[-diff] = *pt;
3304  pt[-diff] = '\0';
3305  }
3306  } else {
3307  char *base = *haystack;
3308  char *new = galloc(pt-base+strlen(pt)+rlen-slen+1);
3309  memcpy(new,base,start-base);
3310  memcpy(new+(start-base),rpl,rlen);
3311  strcpy(new+(start-base)+rlen,pt);
3312  free( base );
3313  *haystack = new;
3314  }
3315 }
3316 
3317 static int rplstr(char **haystack,char *search, char *rpl,int multipleoccurances) {
3318  char *start, *pt, *base = *haystack;
3319  int ch, match, slen = strlen(search);
3320  int any = 0;
3321 
3322  if ( base==NULL )
3323 return( false );
3324 
3325  for ( pt=base ; ; ) {
3326  while ( *pt==' ' ) ++pt;
3327  if ( *pt=='\0' )
3328 return( any );
3329  start=pt;
3330  while ( *pt!=' ' && *pt!='\0' ) ++pt;
3331  if ( pt-start!=slen )
3332  match = -1;
3333  else {
3334  ch = *pt; *pt='\0';
3335  match = strcmp(start,search);
3336  *pt = ch;
3337  }
3338  if ( match==0 ) {
3339  doreplace(haystack,start,search,rpl,slen);
3340  if ( !multipleoccurances )
3341 return( true );
3342  any = true;
3343  if ( base!=*haystack ) {
3344  pt = *haystack + (start-base)+strlen(rpl);
3345  base = *haystack;
3346  } else
3347  pt = start+strlen(rpl);
3348  }
3349  }
3350 }
3351 
3352 static int rplglyphname(char **haystack,char *search, char *rpl) {
3353  /* If we change "f" to "uni0066" then we should also change "f.sc" to */
3354  /* "uni0066.sc" and "f_f_l" to "uni0066_uni0066_l" */
3355  char *start, *pt, *base = *haystack;
3356  int ch, match;
3357  unsigned slen = strlen(search);
3358  int any = 0;
3359 
3360  if ( slen>=strlen( base ))
3361 return( false );
3