1 /* Copyright (C) 2000-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 <utype.h>
29 #include <ustring.h>
30 
31 int coverageformatsallowed=3;
32 int use_second_indic_scripts = false;
33 
34 #include "ttf.h"
35 
36 /* This file contains routines to create the otf gpos and gsub tables and their */
37 /*  attendant subtables */
38 
39 /* Undocumented fact: ATM (which does kerning for otf fonts in Word) can't handle features with multiple lookups */
40 
41 /* Undocumented fact: Only one feature with a given tag allowed per script/lang */
42 /*  So if we have multiple lookups with the same tag they must be merged into */
43 /*  one feature with many lookups */
44 
45 /* scripts (for opentype) that I understand */
46     /* see also list in lookups.c mapping script tags to friendly names */
47 
48 static uint32 scripts[][15] = {
49 /* Arabic */	{ CHR('a','r','a','b'), 0x0600, 0x06ff, 0xfb50, 0xfdff, 0xfe70, 0xfefe },
50 /* Aramaic */	{ CHR('a','r','a','m'), 0x820, 0x83f },
51 /* Armenian */	{ CHR('a','r','m','n'), 0x0530, 0x058f, 0xfb13, 0xfb17 },
52 /* Balinese */	{ CHR('b','a','l','i'), 0x1b00, 0x1b7f },
53 /* Bengali */	{ CHR('b','e','n','g'), 0x0980, 0x09ff },
54 /* Bliss symb */{ CHR('b','l','i','s'), 0x12200, 0x124ff },
55 /* Bopomofo */	{ CHR('b','o','p','o'), 0x3100, 0x312f, 0x31a0, 0x31bf },
56 /* Braille */	{ CHR('b','r','a','i'), 0x2800, 0x28ff },
57 /* Buginese */	{ CHR('b','u','g','i'), 0x1a00, 0x1a1f },
58 /* Buhid */	{ CHR('b','u','h','d'), 0x1740, 0x1753 },
59 /* Byzantine M*/{ CHR('b','y','z','m'), 0x1d000, 0x1d0ff },
60 /* Canadian Syl*/{CHR('c','a','n','s'), 0x1400, 0x167f },
61 /* Carian */     {CHR('c','a','r','i'), 0x0, 0x0 },
62 /* Cham */       {CHR('c','h','a','m'), 0x0, 0x0 },
63 /* Cherokee */	{ CHR('c','h','e','r'), 0x13a0, 0x13ff },
64 /* Cirth */	{ CHR('c','i','r','t'), 0x12080, 0x120ff },
65 /* CJKIdeogra */{ CHR('h','a','n','i'), 0x3300, 0x9fff, 0xf900, 0xfaff, 0x020000, 0x02ffff },
66 /* Coptic */	{ CHR('c','o','p','t'), 0x2c80, 0x2cff },
67 /* Cypriot */	{ CHR('c','p','m','n'), 0x10800, 0x1083f },
68 /* Cyrillic */	{ CHR('c','y','r','l'), 0x0400, 0x052f, 0x1d2b, 0x1d2b, 0x1d78, 0x1d78,
69 	0x2de0, 0x2dff, 0xa640, 0xa6ff },
70 /* Deseret */	{ CHR('d','s','r','t'), 0x10400, 0x1044f },
71 /* Devanagari */{ CHR('d','e','v','a'), 0x0900, 0x097f },
72 /* Ethiopic */	{ CHR('e','t','h','i'), 0x1200, 0x139f },
73 /* Georgian */	{ CHR('g','e','o','r'), 0x1080, 0x10ff },
74 /* Glagolitic */{ CHR('g','l','a','g'), 0x1080, 0x10ff },
75 /* Gothic */	{ CHR('g','o','t','h'), 0x10330, 0x1034a },
76 /* Greek */	{ CHR('g','r','e','k'), 0x0370, 0x03ff, 0x1f00, 0x1fff },
77 /* Gujarati */	{ CHR('g','u','j','r'), 0x0a80, 0x0aff },
78 /* Gurmukhi */	{ CHR('g','u','r','u'), 0x0a00, 0x0a7f },
79 /* Hangul */	{ CHR('h','a','n','g'), 0xac00, 0xd7af, 0x3130, 0x319f, 0xffa0, 0xff9f },
80 /* Hanunoo */	{ CHR('h','a','n','o'), 0x1720, 0x1734 },
81  /* I'm not sure what the difference is between the 'hang' tag and the 'jamo' */
82  /*  tag. 'Jamo' is said to be the precomposed forms, but what's 'hang'? */
83 /* Hebrew */	{ CHR('h','e','b','r'), 0x0590, 0x05ff, 0xfb1e, 0xfb4f },
84 #if 0	/* Hiragana used to have its own tag, but has since been merged with katakana */
85 /* Hiragana */	{ CHR('h','i','r','a'), 0x3040, 0x309f },
86 #endif
87 /* Hangul Jamo*/{ CHR('j','a','m','o'), 0x1100, 0x11ff, 0x3130, 0x319f, 0xffa0, 0xffdf },
88 /* Javanese */	{ CHR('j','a','v','a'), 0 },	/* MS has a tag, but there is no unicode range */
89 /* Katakana */	{ CHR('k','a','n','a'), 0x3040, 0x30ff, 0xff60, 0xff9f },
90 /* Kayah Li */	{ CHR('k','a','l','i'), 0 },
91 /* Kannada */	{ CHR('k','n','d','a'), 0x0c80, 0x0cff },
92 /* Kharosthi */	{ CHR('k','h','a','r'), 0x10a00, 0x10a5f },
93 /* Khmer */	{ CHR('k','h','m','r'), 0x1780, 0x17ff },
94 /* Latin */	{ CHR('l','a','t','n'), 0x0041, 0x005a, 0x0061, 0x007a,
95 	0x00c0, 0x02af, 0x1d00, 0x1eff, 0xfb00, 0xfb0f, 0xff00, 0xff5f, 0xa770, 0xa7ff },
96 /* Lao */	{ CHR('l','a','o',' '), 0x0e80, 0x0eff },
97 /* Lepcha */    { CHR('l','e','p','c'), 0 },
98 /* Limbu */	{ CHR('l','i','m','b'), 0x1900, 0x194f },
99 /* Linear A */	/*{ CHR('l','i','n','a'), 0x10180, 0x102cf },*/ /* What happened to linear A? */
100 /* Linear B */	{ CHR('l','i','n','b'), 0x10000, 0x100fa },
101 /* Lycian */    { CHR('l','y','c','i'), 0 },
102 /* Lydian */    { CHR('l','y','d','i'), 0 },
103 /* Malayalam */	{ CHR('m','l','y','m'), 0x0d00, 0x0d7f },
104 /* Mathematical Alphanumeric Symbols */
105 		{ CHR('m','a','t','h'), 0x1d400, 0x1d7ff },
106 /* Mongolian */	{ CHR('m','o','n','g'), 0x1800, 0x18af },
107 /* Musical */	{ CHR('m','u','s','i'), 0x1d100, 0x1d1ff },
108 /* Myanmar */	{ CHR('m','y','m','r'), 0x1000, 0x107f },
109 /* New Tai Lue*/{ CHR('t','a','l','u'), 0 },
110 /* N'Ko */	{ CHR('n','k','o',' '), 0x07c0, 0x07fa },
111 /* Ogham */	{ CHR('o','g','a','m'), 0x1680, 0x169f },
112 /* Ol Chiki */  { CHR('o','l','c','k'), 0 },
113 /* Old Italic */{ CHR('i','t','a','l'), 0x10300, 0x1031e },
114 /* Old Permic */{ CHR('p','e','r','m'), 0x10350, 0x1037f },
115 /* Old Persian cuneiform */
116 		{ CHR('x','p','e','o'), 0x103a0, 0x103df },
117 /* Oriya */	{ CHR('o','r','y','a'), 0x0b00, 0x0b7f },
118 /* Osmanya */	{ CHR('o','s','m','a'), 0x10480, 0x104a9 },
119 /* Phags-pa */	{ CHR('p','h','a','g'), 0xa840, 0xa87f },
120 /* Phoenician */{ CHR('p','h','n','x'), 0x10900, 0x1091f },
121 /* Pollard */	{ CHR('p','l','r','d'), 0x104b0, 0x104d9 },
122 /* Rejang */    { CHR('r','j','n','g'), 0 },
123 /* Rongorongo */{ CHR('r','o','r','o'), 0 },
124 /* Runic */	{ CHR('r','u','n','r'), 0x16a0, 0x16ff },
125 /* Saurashtra*/ { CHR('s','a','u','r'), 0 },
126 /* Shavian */	{ CHR('s','h','a','w'), 0x10450, 0x1047f },
127 /* Sinhala */	{ CHR('s','i','n','h'), 0x0d80, 0x0dff },
128 /* Sumero-Akkadian Cuneiform */
129 		{ CHR('x','s','u','x'), 0x12000, 0x1236e },
130 /* Sundanese */ { CHR('s','u','n','d'), 0 },
131 /* Syloti Nagri */
132 		{ CHR('s','y','l','o'), 0xa800, 0xa82f },
133 /* Syriac */	{ CHR('s','y','r','c'), 0x0700, 0x074f },
134 /* Tagalog */	{ CHR('t','a','g','l'), 0x1700, 0x1714 },
135 /* Tagbanwa */	{ CHR('t','a','g','b'), 0x1760, 0x1773 },
136 /* Tai Le */	{ CHR('t','a','l','e'), 0x1950, 0x1974 },
137 /* Tai Lu */	{ CHR('t','a','l','u'), 0x1980, 0x19df },
138 /* Tamil */	{ CHR('t','a','m','l'), 0x0b80, 0x0bff },
139 /* Telugu */	{ CHR('t','e','l','u'), 0x0c00, 0x0c7f },
140 /* Tengwar */	{ CHR('t','e','n','g'), 0x12000, 0x1207f },
141 /* Thaana */	{ CHR('t','h','a','a'), 0x0780, 0x07bf },
142 /* Thai */	{ CHR('t','h','a','i'), 0x0e00, 0x0e7f },
143 /* Tibetan */	{ CHR('t','i','b','t'), 0x0f00, 0x0fff },
144 /* Tifinagh */	{ CHR('t','f','n','g'), 0x2d30, 0x2d7f },
145 /* Ugaritic */	{ CHR('u','g','a','r'), 0x10380, 0x1039d },
146 /* Yi */	{ CHR('y','i',' ',' '), 0xa000, 0xa4c6 },
147 		{ 0 }
148 };
149 
ScriptIsRightToLeft(uint32 script)150 int ScriptIsRightToLeft(uint32 script) {
151     if ( script==CHR('a','r','a','b') || script==CHR('h','e','b','r') ||
152 	    script==CHR('c','p','m','n') || script==CHR('k','h','a','r') ||
153 	    script==CHR('s','y','r','c') || script==CHR('t','h','a','a') ||
154 	    script==CHR('n','k','o',' '))
155 return( true );
156 
157 return( false );
158 }
159 
ScriptFromUnicode(int u,SplineFont * sf)160 uint32 ScriptFromUnicode(int u,SplineFont *sf) {
161     int s, k;
162 
163     if ( u!=-1 ) {
164 	for ( s=0; scripts[s][0]!=0; ++s ) {
165 	    for ( k=1; scripts[s][k+1]!=0; k += 2 )
166 		if ( u>=scripts[s][k] && u<=scripts[s][k+1] )
167 	    break;
168 	    if ( scripts[s][k+1]!=0 )
169 	break;
170 	}
171 	if ( scripts[s][0]!=0 ) {
172 	    uint32 script = scripts[s][0];
173 	    if ( use_second_indic_scripts ) {
174 		/* MS has a parallel set of script tags for their new */
175 		/*  Indic font shaper */
176 		if ( script == CHR('b','e','n','g' )) script = CHR('b','n','g','2');
177 		else if ( script == CHR('d','e','v','a' )) script = CHR('d','e','v','2');
178 		else if ( script == CHR('g','u','j','r' )) script = CHR('g','j','r','2');
179 		else if ( script == CHR('g','u','r','u' )) script = CHR('g','u','r','2');
180 		else if ( script == CHR('k','n','d','a' )) script = CHR('k','n','d','2');
181 		else if ( script == CHR('m','l','y','m' )) script = CHR('m','l','y','2');
182 		else if ( script == CHR('o','r','y','a' )) script = CHR('o','r','y','2');
183 		else if ( script == CHR('t','a','m','l' )) script = CHR('t','m','l','2');
184 		else if ( script == CHR('t','e','l','u' )) script = CHR('t','e','l','2');
185 	    }
186 return( script );
187 	}
188     } else if ( sf!=NULL ) {
189 	if ( sf->cidmaster!=NULL || sf->subfontcnt!=0 ) {
190 	    if ( sf->cidmaster!=NULL ) sf = sf->cidmaster;
191 	    if ( strmatch(sf->ordering,"Identity")==0 )
192 return( DEFAULT_SCRIPT );
193 	    else if ( strmatch(sf->ordering,"Korean")==0 )
194 return( CHR('h','a','n','g'));
195 	    else
196 return( CHR('h','a','n','i') );
197 	}
198     }
199 
200 return( DEFAULT_SCRIPT );
201 }
202 
SCScriptFromUnicode(SplineChar * sc)203 uint32 SCScriptFromUnicode(SplineChar *sc) {
204     char *pt;
205     PST *pst;
206     SplineFont *sf;
207     int i; unsigned uni;
208     FeatureScriptLangList *features;
209 
210     if ( sc==NULL )
211 return( DEFAULT_SCRIPT );
212 
213     sf = sc->parent;
214     if ( sc->unicodeenc!=-1 &&
215 	    !(sc->unicodeenc>=0xe000 && sc->unicodeenc<0xf8ff) &&
216 	    !(sc->unicodeenc>=0xf0000 && sc->unicodeenc<0x10ffff))
217 return( ScriptFromUnicode( sc->unicodeenc,sf ));
218 
219     pt = sc->name;
220     if ( *pt ) for ( ++pt; *pt!='\0' && *pt!='_' && *pt!='.'; ++pt );
221     if ( *pt!='\0' ) {
222 	char *str = copyn(sc->name,pt-sc->name);
223 	int uni = sf==NULL || sf->fv==NULL ? UniFromName(str,ui_none,&custom) :
224 			    UniFromName(str,sf->uni_interp,sf->fv->map->enc);
225 	free(str);
226 	if ( uni!=-1 )
227 return( ScriptFromUnicode( uni,sf ));
228     }
229     /* Adobe ligature uniXXXXXXXX */
230     if ( strncmp(sc->name,"uni",3)==0 && sscanf(sc->name+3,"%4x", &uni)==1 )
231 return( ScriptFromUnicode( uni,sf ));
232 
233     if ( sf==NULL )
234 return( DEFAULT_SCRIPT );
235 
236     if ( sf->cidmaster ) sf=sf->cidmaster;
237     else if ( sf->mm!=NULL ) sf=sf->mm->normal;
238     for ( i=0; i<2; ++i ) {
239 	for ( pst=sc->possub; pst!=NULL; pst=pst->next ) {
240 	    if ( pst->type == pst_lcaret )
241 	continue;
242 	    for ( features = pst->subtable->lookup->features; features!=NULL; features=features->next ) {
243 		if ( features->scripts!=NULL )
244 return( features->scripts->script );
245 	    }
246 	}
247     }
248 return( ScriptFromUnicode( sc->unicodeenc,sf ));
249 }
250 
251 
SFGlyphsFromNames(SplineFont * sf,char * names)252 SplineChar **SFGlyphsFromNames(SplineFont *sf,char *names) {
253     int cnt, ch;
254     char *pt, *end;
255     SplineChar *sc, **glyphs;
256 
257     cnt = 0;
258     for ( pt = names; *pt; pt = end+1 ) {
259 	++cnt;
260 	end = strchr(pt,' ');
261 	if ( end==NULL )
262     break;
263     }
264 
265     glyphs = galloc((cnt+1)*sizeof(SplineChar *));
266     cnt = 0;
267     for ( pt = names; *pt; pt = end+1 ) {
268 	end = strchr(pt,' ');
269 	if ( end==NULL )
270 	    end = pt+strlen(pt);
271 	ch = *end;
272 	*end = '\0';
273 	sc = SFGetChar(sf,-1,pt);
274 	if ( sc!=NULL && sc->ttf_glyph!=-1 )
275 	    glyphs[cnt++] = sc;
276 	*end = ch;
277 	if ( ch=='\0' )
278     break;
279     }
280     glyphs[cnt] = NULL;
281 return( glyphs );
282 }
283 
284 
glyphnameinlist(char * haystack,char * name)285 static int glyphnameinlist(char *haystack,char *name) {
286     char *start, *pt;
287     int ch, match, slen = strlen(name);
288 
289     for ( pt=haystack ; ; ) {
290 	while ( *pt==' ' ) ++pt;
291 	if ( *pt=='\0' )
292 return( false );
293 	start=pt;
294 	while ( *pt!=' ' && *pt!='\0' ) ++pt;
295 	if ( pt-start==slen ) {
296 	    ch = *pt; *pt='\0';
297 	    match = strcmp(start,name);
298 	    *pt = ch;
299 	    if ( match==0 )
300 return( true );
301 	}
302     }
303 }
304 
ReferencedByGSUB(SplineChar * sc)305 static int ReferencedByGSUB(SplineChar *sc) {
306     PST *pst;
307     SplineFont *sf = sc->parent;
308     int gid;
309     SplineChar *testsc;
310     char *name = sc->name;
311 
312     /* If it is itself a ligature it will be referenced by GSUB */
313     /* (because we store ligatures on the glyph generated) */
314     for ( pst=sc->possub; pst!=NULL; pst=pst->next )
315 	if ( pst->type == pst_ligature )
316 return( true );
317 
318     for ( gid=0; gid<sf->glyphcnt; ++gid ) if ( (testsc=sf->glyphs[gid])!=NULL ) {
319 	for ( pst=testsc->possub; pst!=NULL; pst=pst->next ) {
320 	    if ( pst->type==pst_substitution || pst->type==pst_alternate ||
321 		    pst->type==pst_multiple ) {
322 		if ( glyphnameinlist(pst->u.mult.components,name) )
323 return( true );
324 	    }
325 	}
326     }
327 return( false );
328 }
329 
gdefclass(SplineChar * sc)330 int gdefclass(SplineChar *sc) {
331     PST *pst;
332     AnchorPoint *ap;
333 
334     if ( sc->glyph_class!=0 )
335 return( sc->glyph_class-1 );
336 
337     if ( strcmp(sc->name,".notdef")==0 )
338 return( 0 );
339 
340     /* It isn't clear to me what should be done if a glyph is both a ligature */
341     /*  and a mark (There are some greek accent ligatures, it is probably more*/
342     /*  important that they be indicated as marks). Here I chose mark rather  */
343     /*  than ligature as the mark class is far more likely to be used */
344     ap=sc->anchor;
345     while ( ap!=NULL && (ap->type==at_centry || ap->type==at_cexit) )
346 	ap = ap->next;
347     if ( ap!=NULL && (ap->type==at_mark || ap->type==at_basemark) )
348 return( 3 );
349 
350     for ( pst=sc->possub; pst!=NULL; pst=pst->next ) {
351 	if ( pst->type == pst_ligature )
352 return( 2 );			/* Ligature */
353     }
354 
355 	/* I not quite sure what a componant glyph is. Probably something */
356 	/*  that is not in the cmap table and is referenced in other glyphs */
357 	/* (I've never seen it used by others) */
358 	/* (Note: No glyph in a CID font can be components as all CIDs mean */
359 	/*  something) (I think) */
360     if ( sc->unicodeenc==-1 && sc->dependents!=NULL &&
361 	    sc->parent->cidmaster!=NULL && !ReferencedByGSUB(sc))
362 return( 4 );
363     else
364 return( 1 );
365 }
366 
367