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 "pfaedit.h"
28 #include <math.h>
29 #include <time.h>
30 #include <utype.h>
31 #include <ustring.h>
32 #include <gimage.h>		/* For COLOR_DEFAULT */
33 
34 #include "ttf.h"
35 
36 /* This file contains routines to generate non-standard true/opentype tables */
37 /* The first is the 'PfEd' table containing PfaEdit specific information */
38 /*	glyph comments & colours ... perhaps other info later */
39 
40 /* ************************************************************************** */
41 /* *************************    The 'PfEd' table    ************************* */
42 /* *************************         Output         ************************* */
43 /* ************************************************************************** */
44 
45 #include "PfEd.h"	/* This describes the format of the 'PfEd' table */
46 			/*  and its many subtables. */
47 
48 #define MAX_SUBTABLE_TYPES	20
49 
50 /* *************************    The 'PfEd' table    ************************* */
51 /* *************************          Input         ************************* */
52 
pfed_readfontcomment(FILE * ttf,struct ttfinfo * info,uint32 base,uint32 tag)53 static void pfed_readfontcomment(FILE *ttf,struct ttfinfo *info,uint32 base,
54 	uint32 tag) {
55     int len;
56     char *start, *pt, *end;
57     int use_utf8;
58 
59     fseek(ttf,base,SEEK_SET);
60     use_utf8 = getushort(ttf);
61     if ( use_utf8!=0 && use_utf8!=1 )
62 return;			/* Bad version number */
63     len = getushort(ttf);
64     start = pt = galloc(len+1);
65 
66     end = pt+len;
67     if ( use_utf8 ) {
68 	while ( pt<end )
69 	    *pt++ = getc(ttf);
70     } else {
71 	while ( pt<end )
72 	    *pt++ = getushort(ttf);
73     }
74     *pt = '\0';
75     if ( !use_utf8 ) {
76 	pt = latin1_2_utf8_copy(info->fontcomments);
77 	free(start);
78 	start = pt;
79     }
80     if ( tag==flog_TAG )
81 	info->fontlog = start;
82     else
83 	info->fontcomments = start;
84 }
85 
pfed_read_utf8(FILE * ttf,uint32 start)86 static char *pfed_read_utf8(FILE *ttf, uint32 start) {
87     int ch, len;
88     char *str, *pt;
89 
90     fseek( ttf, start, SEEK_SET);
91     len = 0;
92     while ( (ch=getc(ttf))!='\0' && ch!=EOF )
93 	++len;
94     fseek( ttf, start, SEEK_SET);
95     str = pt = galloc(len+1);
96     while ( (ch=getc(ttf))!='\0' && ch!=EOF )
97 	*pt++ = ch;
98     *pt = '\0';
99 return( str );
100 }
101 
pfed_read_ucs2_len(FILE * ttf,uint32 offset,int len)102 static char *pfed_read_ucs2_len(FILE *ttf,uint32 offset,int len) {
103     char *pt, *str;
104     uint32 uch, uch2;
105     int i;
106 
107     if ( len<0 )
108 return( NULL );
109 
110     len>>=1;
111     pt = str = galloc(3*len);
112     fseek(ttf,offset,SEEK_SET);
113     for ( i=0; i<len; ++i ) {
114 	uch = getushort(ttf);
115 	if ( uch>=0xd800 && uch<0xdc00 ) {
116 	    uch2 = getushort(ttf);
117 	    if ( uch2>=0xdc00 && uch2<0xe000 )
118 		uch = ((uch-0xd800)<<10) | (uch2&0x3ff);
119 	    else {
120 		pt = utf8_idpb(pt,uch);
121 		uch = uch2;
122 	    }
123 	}
124 	pt = utf8_idpb(pt,uch);
125     }
126     *pt++ = 0;
127 return( grealloc(str,pt-str) );
128 }
129 
pfed_read_utf8_len(FILE * ttf,uint32 offset,int len)130 static char *pfed_read_utf8_len(FILE *ttf,uint32 offset,int len) {
131     char *pt, *str;
132     int i;
133 
134     if ( len<0 )
135 return( NULL );
136 
137     pt = str = galloc(len+1);
138     fseek(ttf,offset,SEEK_SET);
139     for ( i=0; i<len; ++i )
140 	*pt++ = getc(ttf);
141     *pt = '\0';
142 return( str );
143 }
144 
pfed_readcvtcomments(FILE * ttf,struct ttfinfo * info,uint32 base)145 static void pfed_readcvtcomments(FILE *ttf,struct ttfinfo *info,uint32 base ) {
146     int count, i;
147     uint16 *offsets;
148 
149     fseek(ttf,base,SEEK_SET);
150     if ( getushort(ttf)!=0 )
151 return;			/* Bad version number */
152     count = getushort(ttf);
153 
154     offsets = galloc(count*sizeof(uint16));
155     info->cvt_names = galloc((count+1)*sizeof(char *));
156     for ( i=0; i<count; ++i )
157 	offsets[i] = getushort(ttf);
158     for ( i=0; i<count; ++i ) {
159 	if ( offsets[i]==0 )
160 	    info->cvt_names[i] = NULL;
161 	else
162 	    info->cvt_names[i] = pfed_read_utf8(ttf,base+offsets[i]);
163     }
164     free(offsets);
165 }
166 
pfed_readglyphcomments(FILE * ttf,struct ttfinfo * info,uint32 base)167 static void pfed_readglyphcomments(FILE *ttf,struct ttfinfo *info,uint32 base) {
168     int n, i, j;
169     struct grange { int start, end; uint32 offset; } *grange;
170     uint32 offset, next;
171     int use_utf8;
172 
173     fseek(ttf,base,SEEK_SET);
174     use_utf8 = getushort(ttf);
175     if ( use_utf8!=0 && use_utf8!=1 )
176 return;			/* Bad version number */
177     n = getushort(ttf);
178     grange = galloc(n*sizeof(struct grange));
179     for ( i=0; i<n; ++i ) {
180 	grange[i].start = getushort(ttf);
181 	grange[i].end = getushort(ttf);
182 	grange[i].offset = getlong(ttf);
183 	if ( grange[i].start>grange[i].end || grange[i].end>info->glyph_cnt ) {
184 	    LogError( _("Bad glyph range specified in glyph comment subtable of PfEd table\n") );
185 	    grange[i].start = 1; grange[i].end = 0;
186 	}
187     }
188     for ( i=0; i<n; ++i ) {
189 	for ( j=grange[i].start; j<=grange[i].end; ++j ) {
190 	    fseek( ttf,base+grange[i].offset+(j-grange[i].start)*sizeof(uint32),SEEK_SET);
191 	    offset = getlong(ttf);
192 	    next = getlong(ttf);
193 	    if ( use_utf8 )
194 		info->chars[j]->comment = pfed_read_utf8_len(ttf,base+offset,next-offset);
195 	    else
196 		info->chars[j]->comment = pfed_read_ucs2_len(ttf,base+offset,next-offset);
197 	    if ( info->chars[j]->comment == NULL )
198 		LogError("Invalid comment string (negative length?) in 'PfEd' table for glyph %s.",
199 			info->chars[j]->name );
200 	}
201     }
202     free(grange);
203 }
204 
pfed_readcolours(FILE * ttf,struct ttfinfo * info,uint32 base)205 static void pfed_readcolours(FILE *ttf,struct ttfinfo *info,uint32 base) {
206     int n, i, j, start, end;
207     uint32 col;
208 
209     fseek(ttf,base,SEEK_SET);
210     if ( getushort(ttf)!=0 )
211 return;			/* Bad version number */
212     n = getushort(ttf);
213     for ( i=0; i<n; ++i ) {
214 	start = getushort(ttf);
215 	end = getushort(ttf);
216 	col = getlong(ttf);
217 	if ( start>end || end>info->glyph_cnt )
218 	    LogError( _("Bad glyph range specified in colour subtable of PfEd table\n") );
219 	else {
220 	    for ( j=start; j<=end; ++j )
221 		info->chars[j]->color = col;
222 	}
223     }
224 }
225 
pfed_readlookupnames(FILE * ttf,struct ttfinfo * info,uint32 base,OTLookup * lookups)226 static void pfed_readlookupnames(FILE *ttf,struct ttfinfo *info,uint32 base,
227 	OTLookup *lookups) {
228     OTLookup *otl;
229     struct lookup_subtable *sub;
230     AnchorClass *ac;
231     int i, j, k, n, s, a;
232     struct lstruct { int name_off, subs_off; } *ls, *ss, *as;
233 
234     fseek(ttf,base,SEEK_SET);
235     if ( getushort(ttf)!=0 )
236 return;			/* Bad version number */
237     n = getushort(ttf);
238     ls = galloc(n*sizeof(struct lstruct));
239     for ( i=0; i<n; ++i ) {
240 	ls[i].name_off = getushort(ttf);
241 	ls[i].subs_off = getushort(ttf);
242     }
243     for ( i=0, otl=lookups; i<n && otl!=NULL; ++i, otl=otl->next ) {
244 	if ( ls[i].name_off!=0 ) {
245 	    free( otl->lookup_name );
246 	    otl->lookup_name = pfed_read_utf8(ttf,base+ls[i].name_off);
247 	}
248 	if ( ls[i].subs_off!=0 ) {
249 	    fseek(ttf,base+ls[i].subs_off,SEEK_SET);
250 	    s = getushort(ttf);
251 	    ss = galloc(s*sizeof(struct lstruct));
252 	    for ( j=0; j<s; ++j ) {
253 		ss[j].name_off = getushort(ttf);
254 		ss[j].subs_off = getushort(ttf);
255 	    }
256 	    for ( j=0, sub=otl->subtables; j<s && sub!=NULL; ++j, sub=sub->next ) {
257 		if ( ss[j].name_off!=0 ) {
258 		    free( sub->subtable_name );
259 		    sub->subtable_name = pfed_read_utf8(ttf,base+ss[j].name_off);
260 		}
261 		if ( ss[j].subs_off!=0 ) {
262 		    if ( !sub->anchor_classes )
263 			LogError("Whoops, attempt to name anchors in a subtable which doesn't contain any\n");
264 		    else {
265 			fseek(ttf,base+ss[j].subs_off,SEEK_SET);
266 			a = getushort(ttf);
267 			as = galloc(a*sizeof(struct lstruct));
268 			for ( k=0; k<a; ++k ) {
269 			    as[k].name_off = getushort(ttf);
270 			}
271 			k=0;
272 			for ( ac=info->ahead; ac!=NULL; ac=ac->next ) {
273 			    if ( ac->subtable==sub ) {
274 				if ( as[k].name_off!=0 ) {
275 				    free( ac->name );
276 				    ac->name = pfed_read_utf8(ttf,base+as[k].name_off);
277 				}
278 			        ++k;
279 			    }
280 			}
281 			free(as);
282 		    }
283 		}
284 	    }
285 	    /* I guess it's ok for some subtables to be unnamed, so no check for sub!=NULL */
286 	    if ( j<s )
287 		LogError("Whoops, more names than subtables of lookup %s\n", otl->lookup_name );
288 	    free(ss);
289 	}
290     }
291     /* I guess it's ok for some lookups to be unnamed, so no check for otf!=NULL */
292     if ( i<n )
293 	LogError("Whoops, more names than lookups\n" );
294     free(ls);
295 }
296 
pfed_get_coord(FILE * ttf,int mod)297 static float pfed_get_coord(FILE *ttf,int mod) {
298     if ( mod==V_B )
299 return( (float) (signed char) getc(ttf) );
300     else if ( mod==V_S )
301 return( (float) (short) getushort(ttf));
302     else if ( mod==V_F )
303 return( getlong(ttf)/256.0 );
304     else {
305 	LogError( "Bad data type in contour verb in 'PfEd'\n");
306 return( 0 );
307     }
308 }
309 
pfed_read_normal_contour(FILE * ttf,SplineSet * ss,uint32 base,int type)310 static void pfed_read_normal_contour(FILE *ttf,SplineSet *ss,
311 	uint32 base, int type) {
312     SplinePoint *sp, *current;
313     int verb, v, m;
314     float offx, offy, offx1 = 0, offy1 = 0, offx2, offy2;
315     int was_implicit=false;
316 
317     fseek(ttf,base,SEEK_SET);
318 
319     verb = getc(ttf);
320     if ( COM_VERB(verb)!=V_MoveTo ) {
321 	LogError("Whoops, contours must begin with a move to\n" );
322 	ss->first = ss->last = SplinePointCreate(0,0);
323 return;
324     }
325     offx = pfed_get_coord(ttf,COM_MOD(verb));
326     offy = pfed_get_coord(ttf,COM_MOD(verb));
327     ss->first = current = SplinePointCreate(offx,offy);
328     forever {
329 	verb = getc(ttf);
330 	v = COM_VERB(verb); m = COM_MOD(verb);
331 	if ( m==3 ) {
332 	    LogError("Bad data modifier in contour command in 'PfEd'\n" );
333     break;
334 	}
335 	if ( verb==V_Close || verb==V_End )
336     break;
337 	else if ( v>=V_LineTo && v<=V_VLineTo ) {
338 	    offx = offy = 0;
339 	    if ( v==V_LineTo ) {
340 		offx = pfed_get_coord(ttf,m);
341 		offy = pfed_get_coord(ttf,m);
342 	    } else if ( v==V_HLineTo )
343 		offx = pfed_get_coord(ttf,m);
344 	    else if ( v==V_VLineTo )
345 		offy = pfed_get_coord(ttf,m);
346 	    sp = SplinePointCreate(current->me.x+offx,current->me.y+offy);
347 	} else if ( v>=V_QCurveTo && v<=V_QVImplicit ) {
348 	    int will_be_implicit = true;
349 	    offx = offy = 0; offx1 = offy1 = 1;	/* else implicit points become straight lines too soon */
350 	    if ( v==V_QCurveTo ) {
351 		offx = pfed_get_coord(ttf,m);
352 		offy = pfed_get_coord(ttf,m);
353 		offx1 = pfed_get_coord(ttf,m);
354 		offy1 = pfed_get_coord(ttf,m);
355 		will_be_implicit = false;
356 	    } else if ( v==V_QImplicit ) {
357 		offx = pfed_get_coord(ttf,m);
358 		offy = pfed_get_coord(ttf,m);
359 	    } else if ( v==V_QHImplicit ) {
360 		offx = pfed_get_coord(ttf,m);
361 	    } else if ( v==V_QVImplicit ) {
362 		offy = pfed_get_coord(ttf,m);
363 	    }
364 
365 	    current->nextcp.x = current->me.x+offx;
366 	    current->nextcp.y = current->me.y+offy;
367 	    current->nonextcp = false;
368 	    sp = SplinePointCreate(current->nextcp.x+offx1,current->nextcp.y+offy1);
369 	    sp->prevcp = current->nextcp;
370 	    sp->noprevcp = false;
371 	    if ( was_implicit ) {
372 		current->me.x = (current->prevcp.x + current->nextcp.x)/2;
373 		current->me.y = (current->prevcp.y + current->nextcp.y)/2;
374 		SplineRefigure(current->prev);
375 	    }
376 	    was_implicit = will_be_implicit;
377 	} else if ( v>=V_CurveTo && v<=V_HVCurveTo ) {
378 	    offx=offy=offx2=offy2=0;
379 	    if ( v==V_CurveTo ) {
380 		offx = pfed_get_coord(ttf,m);
381 		offy = pfed_get_coord(ttf,m);
382 		offx1 = pfed_get_coord(ttf,m);
383 		offy1 = pfed_get_coord(ttf,m);
384 		offx2 = pfed_get_coord(ttf,m);
385 		offy2 = pfed_get_coord(ttf,m);
386 	    } else if ( v==V_VHCurveTo ) {
387 		offy = pfed_get_coord(ttf,m);
388 		offx1 = pfed_get_coord(ttf,m);
389 		offy1 = pfed_get_coord(ttf,m);
390 		offx2 = pfed_get_coord(ttf,m);
391 	    } else if ( v==V_HVCurveTo ) {
392 		offx = pfed_get_coord(ttf,m);
393 		offx1 = pfed_get_coord(ttf,m);
394 		offy1 = pfed_get_coord(ttf,m);
395 		offy2 = pfed_get_coord(ttf,m);
396 	    }
397 	    current->nextcp.x = current->me.x+offx;
398 	    current->nextcp.y = current->me.y+offy;
399 	    current->nonextcp = false;
400 	    sp = SplinePointCreate(current->nextcp.x+offx1+offx2,current->nextcp.y+offy1+offy2);
401 	    sp->prevcp.x = current->nextcp.x+offx1;
402 	    sp->prevcp.y = current->nextcp.y+offy1;
403 	    sp->noprevcp = false;
404 	} else {
405 	    LogError("Whoops, unexpected verb in contour %d.%d\n", v, m );
406     break;
407 	}
408 	SplineMake(current,sp,type==2);
409 	current = sp;
410     }
411     if ( verb==V_Close ) {
412 	if ( was_implicit ) {
413 	    current->me.x = (current->prevcp.x + ss->first->nextcp.x)/2;
414 	    current->me.y = (current->prevcp.y + ss->first->nextcp.y)/2;
415 	}
416 	if ( current->me.x==ss->first->me.x && current->me.y==ss->first->me.y ) {
417 	    current->prev->to = ss->first;
418 	    ss->first->prev = current->prev;
419 	    ss->first->prevcp = current->prevcp;
420 	    ss->first->noprevcp = current->noprevcp;
421 	    SplinePointFree(current);
422 	} else
423 	    SplineMake(current,ss->first,type==2);
424 	ss->last = ss->first;
425     } else {
426 	ss->last = current;
427     }
428     SPLCatagorizePoints(ss);
429 }
430 
431 
pfed_read_glyph_layer(FILE * ttf,struct ttfinfo * info,Layer * ly,uint32 base,int type,int version)432 static void pfed_read_glyph_layer(FILE *ttf,struct ttfinfo *info,Layer *ly,
433 	uint32 base, int type, int version) {
434     int cc, ic, rc, i, j;
435     SplineSet *ss;
436     struct contours { int data_off, name_off; SplineSet *ss; } *contours;
437     int gid;
438     RefChar *last, *cur;
439 
440     fseek(ttf,base,SEEK_SET);
441     cc = getushort(ttf);
442     rc = 0;
443     if ( version==1 )
444 	rc = getushort(ttf);
445     ic = getushort(ttf);
446     contours = galloc(cc*sizeof(struct contours));
447     for ( i=0; i<cc; ++i ) {
448 	contours[i].data_off = getushort(ttf);
449 	contours[i].name_off = getushort(ttf);
450     }
451     last = NULL;
452     for ( i=0; i<rc; ++i ) {
453 	cur = RefCharCreate();
454 	for ( j=0; j<6; ++j )
455 	    cur->transform[j] = getlong(ttf)/32768.0;
456 	gid = getushort(ttf);
457 	cur->sc = info->chars[gid];
458 	cur->orig_pos = gid;
459 	cur->unicode_enc = cur->sc->unicodeenc;
460 	if ( last==NULL )
461 	    ly->refs = cur;
462 	else
463 	    last->next = cur;
464 	last = cur;
465     }
466 
467     ss = ly->splines;			/* Only relevant for spiros where they live in someone else's layer */
468     for ( i=0; i<cc; ++i ) {
469 	if ( type!=1 ) {		/* Not spiros */
470 	    contours[i].ss = chunkalloc(sizeof(SplineSet));
471 	    if ( i==0 )
472 		ly->splines = contours[i].ss;
473 	    else
474 		contours[i-1].ss->next = contours[i].ss;
475 	    if ( contours[i].name_off!=0 )
476 		contours[i].ss->contour_name = pfed_read_utf8(ttf,base+contours[i].name_off);
477 	    pfed_read_normal_contour(ttf,contours[i].ss,base+contours[i].data_off,type);
478 	}
479     }
480     free(contours);
481 }
482 
pfed_readguidelines(FILE * ttf,struct ttfinfo * info,uint32 base)483 static void pfed_readguidelines(FILE *ttf,struct ttfinfo *info,uint32 base) {
484     int i,v,h,off;
485     int version;
486     SplinePoint *sp, *nsp;
487     SplineSet *ss;
488 
489     fseek(ttf,base,SEEK_SET);
490     version = getushort(ttf);
491     if ( version>1 )
492 return;			/* Bad version number */
493     v = getushort(ttf);
494     h = getushort(ttf);
495     (void) getushort(ttf);
496     off = getushort(ttf);
497 
498     if ( off!=0 ) {
499 	pfed_read_glyph_layer(ttf,info,&info->guidelines,base+off,info->to_order2?2:3,version);
500     } else {
501 	struct npos { int pos; int offset; } *vs, *hs;
502 	vs = galloc(v*sizeof(struct npos));
503 	hs = galloc(h*sizeof(struct npos));
504 	for ( i=0; i<v; ++i ) {
505 	    vs[i].pos = (short) getushort(ttf);
506 	    vs[i].offset = getushort(ttf);
507 	}
508 	for ( i=0; i<h; ++i ) {
509 	    hs[i].pos = (short) getushort(ttf);
510 	    hs[i].offset = getushort(ttf);
511 	}
512 	for ( i=0; i<v; ++i ) {
513 	    sp = SplinePointCreate(vs[i].pos,-info->emsize);
514 	    nsp = SplinePointCreate(vs[i].pos,2*info->emsize);
515 	    SplineMake(sp,nsp,info->to_order2);
516 	    ss = chunkalloc(sizeof(SplineSet));
517 	    ss->first = sp; ss->last = nsp;
518 	    if ( vs[i].offset!=0 )
519 		ss->contour_name = pfed_read_utf8(ttf,base+vs[i].offset);
520 	    ss->next = info->guidelines.splines;
521 	    info->guidelines.splines = ss;
522 	}
523 	for ( i=0; i<h; ++i ) {
524 	    sp = SplinePointCreate(-info->emsize,hs[i].pos);
525 	    nsp = SplinePointCreate(2*info->emsize,hs[i].pos);
526 	    SplineMake(sp,nsp,info->to_order2);
527 	    ss = chunkalloc(sizeof(SplineSet));
528 	    ss->first = sp; ss->last = nsp;
529 	    if ( hs[i].offset!=0 )
530 		ss->contour_name = pfed_read_utf8(ttf,base+hs[i].offset);
531 	    ss->next = info->guidelines.splines;
532 	    info->guidelines.splines = ss;
533 	}
534 	SPLCatagorizePoints(info->guidelines.splines);
535 	free(vs); free(hs);
536     }
537 }
538 
pfed_redo_refs(SplineChar * sc,int layer)539 static void pfed_redo_refs(SplineChar *sc,int layer) {
540     RefChar *refs;
541 
542     sc->ticked = true;
543     for ( refs=sc->layers[layer].refs; refs!=NULL; refs=refs->next ) {
544 	if ( !refs->sc->ticked )
545 	    pfed_redo_refs(refs->sc,layer);
546 	SCReinstanciateRefChar(sc,refs,layer);
547     }
548 }
549 
pfed_read_layer(FILE * ttf,struct ttfinfo * info,int layer,int type,uint32 base,uint32 start,int version)550 static void pfed_read_layer(FILE *ttf,struct ttfinfo *info,int layer,int type, uint32 base,
551 	uint32 start,int version) {
552     uint32 *loca = gcalloc(info->glyph_cnt,sizeof(uint32));
553     int i,j;
554     SplineChar *sc;
555     int rcnt;
556     struct range { int start, last; uint32 offset; } *ranges;
557 
558     fseek(ttf,start,SEEK_SET);
559     rcnt = getushort(ttf);
560     ranges = galloc(rcnt*sizeof(struct range));
561     for ( i=0; i<rcnt; ++i ) {
562 	ranges[i].start  = getushort(ttf);
563 	ranges[i].last   = getushort(ttf);
564 	ranges[i].offset = getlong(ttf);
565     }
566     for ( i=0; i<rcnt; ++i ) {
567 	fseek(ttf,base+ranges[i].offset,SEEK_SET);
568 	for ( j=ranges[i].start; j<=ranges[i].last; ++j )
569 	    loca[j] = getlong(ttf);
570 	for ( j=ranges[i].start; j<=ranges[i].last; ++j ) {
571 	    Layer *ly;
572 	    sc = info->chars[j];
573 	    ly = &sc->layers[layer];
574 	    if ( loca[j]!=0 )
575 		pfed_read_glyph_layer(ttf,info,ly,base+loca[j],type,version);
576 	}
577     }
578     free(ranges); free(loca);
579 
580     for ( i=0; i<info->glyph_cnt; ++i ) if ( info->chars[i]!=NULL )
581 	info->chars[i]->ticked = false;
582     for ( i=0; i<info->glyph_cnt; ++i ) if ( info->chars[i]!=NULL )
583 	pfed_redo_refs(info->chars[i],layer);
584 }
585 
pfed_readotherlayers(FILE * ttf,struct ttfinfo * info,uint32 base)586 static void pfed_readotherlayers(FILE *ttf,struct ttfinfo *info,uint32 base) {
587     int i, l, lcnt, spiro_index, gid;
588     int version;
589     struct layer_info { int type, name_off, data_off, sf_layer; char *name; } *layers;
590     int non_spiro_cnt=0;
591     SplineChar *sc;
592 
593     fseek(ttf,base,SEEK_SET);
594     version = getushort(ttf);
595     if ( version>1 )
596 return;			/* Bad version number */
597     lcnt = getushort(ttf);
598     layers = galloc(lcnt*sizeof(struct layer_info));
599     for ( i=0; i<lcnt; ++i ) {
600 	layers[i].type     = getushort(ttf);
601 	layers[i].name_off = getushort(ttf);
602 	layers[i].data_off = getlong(ttf);
603 	layers[i].sf_layer = -1;
604     }
605     spiro_index = -1;
606     non_spiro_cnt = 0;
607     for ( i=0; i<lcnt; ++i ) {
608 	if ( layers[i].name_off==0 )
609 	    layers[i].name = copy("Unnamed");
610 	else {
611 	    layers[i].name = pfed_read_utf8(ttf,base+layers[i].name_off);
612 	    if ( layers[i].type==1 && strcmp(layers[i].name,"Spiro")==0 )
613 		spiro_index = i;
614 	}
615 	if ( layers[i].type==2 || layers[i].type==3 || layers[i].type==0x102 || layers[i].type==0x103 )
616 	    ++non_spiro_cnt;
617     }
618     if ( spiro_index==-1 ) {
619 	for ( i=0; i<lcnt; ++i )
620 	    if ( layers[i].type==1 ) {
621 		spiro_index=i;
622 	break;
623 	    }
624     }
625 
626     if ( non_spiro_cnt!=0 ) {
627 	info->layer_cnt = non_spiro_cnt+1;
628 	info->layers = gcalloc(info->layer_cnt+1,sizeof(LayerInfo));
629 	info->layers[ly_back].background = true;
630 	info->layers[ly_fore].order2 = info->to_order2;
631 	info->layers[ly_fore].background = false;
632 	l = i = 0;
633 	if ( (layers[i].type&0xff)==1 )
634 	    ++i;
635 	if ( layers[i].type&0x100 ) {
636 	    /* first layer output is foreground, so it can't replace the background layer */
637 	    ++info->layer_cnt;
638 	    l = 2;
639 	    info->layers[ly_back].order2 = info->to_order2;
640 	}
641 	for ( ; i<lcnt; ++i ) if ( (layers[i].type&0xff)==2 || (layers[i].type&0xff)==3 ) {
642 	    info->layers[l].name   = layers[i].name;
643 	    layers[i].name = NULL;
644 	    layers[i].sf_layer = l;
645 	    info->layers[l].order2 = (layers[i].type&0xff)==2;
646 	    info->layers[l].background = (layers[i].type&0x100)?0:1;
647 	    if ( l==0 ) l=2; else ++l;
648 	}
649 	if ( info->layer_cnt!=2 ) {
650 	    for ( gid = 0; gid<info->glyph_cnt; ++gid ) if ((sc=info->chars[gid])!=NULL ) {
651 		sc->layers = grealloc(sc->layers,info->layer_cnt*sizeof(Layer));
652 		memset(sc->layers+2,0,(info->layer_cnt-2)*sizeof(Layer));
653 		sc->layer_cnt = info->layer_cnt;
654 	    }
655 	}
656     }
657     if ( spiro_index!=-1 )
658 	pfed_read_layer(ttf,info,ly_fore,layers[spiro_index].type,base,base+layers[spiro_index].data_off,version);
659     for ( i=0; i<lcnt; ++i ) if ( layers[i].sf_layer!=-1 ) {
660 	pfed_read_layer(ttf,info,layers[i].sf_layer,layers[i].type&0xff,
661 		base,base+layers[i].data_off,version);
662     }
663     for ( i=0; i<lcnt; ++i )
664 	free( layers[i].name );
665     free( layers );
666 }
667 
pfed_read(FILE * ttf,struct ttfinfo * info)668 void pfed_read(FILE *ttf,struct ttfinfo *info) {
669     int n,i;
670     struct tagoff { uint32 tag, offset; } tagoff[MAX_SUBTABLE_TYPES+30];
671 
672     fseek(ttf,info->pfed_start,SEEK_SET);
673 
674     if ( getlong(ttf)!=0x00010000 )
675 return;
676     n = getlong(ttf);
677     if ( n>=MAX_SUBTABLE_TYPES+30 )
678 	n = MAX_SUBTABLE_TYPES+30;
679     for ( i=0; i<n; ++i ) {
680 	tagoff[i].tag = getlong(ttf);
681 	tagoff[i].offset = getlong(ttf);
682     }
683     for ( i=0; i<n; ++i ) switch ( tagoff[i].tag ) {
684       case fcmt_TAG: case flog_TAG:
685 	pfed_readfontcomment(ttf,info,info->pfed_start+tagoff[i].offset, tagoff[i].tag);
686       break;
687       case cvtc_TAG:
688 	pfed_readcvtcomments(ttf,info,info->pfed_start+tagoff[i].offset);
689       break;
690       case cmnt_TAG:
691 	pfed_readglyphcomments(ttf,info,info->pfed_start+tagoff[i].offset);
692       break;
693       case colr_TAG:
694 	pfed_readcolours(ttf,info,info->pfed_start+tagoff[i].offset);
695       break;
696       case GPOS_TAG:
697 	pfed_readlookupnames(ttf,info,info->pfed_start+tagoff[i].offset,info->gpos_lookups);
698       break;
699       case GSUB_TAG:
700 	pfed_readlookupnames(ttf,info,info->pfed_start+tagoff[i].offset,info->gsub_lookups);
701       break;
702       case layr_TAG:
703 	pfed_readotherlayers(ttf,info,info->pfed_start+tagoff[i].offset);
704       break;
705       case guid_TAG:
706 	pfed_readguidelines(ttf,info,info->pfed_start+tagoff[i].offset);
707       break;
708       default:
709 	LogError( _("Unknown subtable '%c%c%c%c' in 'PfEd' table, ignored\n"),
710 		tagoff[i].tag>>24, (tagoff[i].tag>>16)&0xff, (tagoff[i].tag>>8)&0xff, tagoff[i].tag&0xff );
711       break;
712     }
713 }
714 
715 /* 'TeX ' table format is as follows...				 */
716 /* uint32  version number 0x00010000				 */
717 /* uint32  subtable count					 */
718 /* struct { uint32 tab, offset } tag/offset for first subtable	 */
719 /* struct { uint32 tab, offset } tag/offset for second subtable	 */
720 /* ...								 */
721 
722 /* 'TeX ' 'ftpm' font parameter subtable format			 */
723 /*  short version number 0					 */
724 /*  parameter count						 */
725 /*  array of { 4chr tag, value }				 */
726 
727 /* 'TeX ' 'htdp' per-glyph height/depth subtable format		 */
728 /*  short  version number 0					 */
729 /*  short  glyph-count						 */
730 /*  array[glyph-count] of { int16 height,depth }		 */
731 
732 /* 'TeX ' 'itlc' per-glyph italic correction subtable		 */
733 /*  short  version number 0					 */
734 /*  short  glyph-count						 */
735 /*  array[glyph-count] of int16 italic_correction		 */
736 
737 /* !!!!!!!!!!! OBSOLETE !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */
738 /* 'TeX ' 'sbsp' per-glyph sub/super script positioning subtable */
739 /*  short  version number 0					 */
740 /*  short  glyph-count						 */
741 /*  array[glyph-count] of { int16 sub,super }			 */
742 
743 #undef MAX_SUBTABLE_TYPES
744 #define MAX_SUBTABLE_TYPES	4
745 
746 struct TeX_subtabs {
747     int next;
748     struct {
749 	FILE *data;
750 	uint32 tag;
751 	uint32 offset;
752     } subtabs[MAX_SUBTABLE_TYPES];
753 };
754 
755 static uint32 tex_text_params[] = {
756     TeX_Slant,
757     TeX_Space,
758     TeX_Stretch,
759     TeX_Shrink,
760     TeX_XHeight,
761     TeX_Quad,
762     TeX_ExtraSp,
763     0
764 };
765 static uint32 tex_math_params[] = {
766     TeX_Slant,
767     TeX_Space,
768     TeX_Stretch,
769     TeX_Shrink,
770     TeX_XHeight,
771     TeX_Quad,
772     TeX_MathSp,
773     TeX_Num1,
774     TeX_Num2,
775     TeX_Num3,
776     TeX_Denom1,
777     TeX_Denom2,
778     TeX_Sup1,
779     TeX_Sup2,
780     TeX_Sup3,
781     TeX_Sub1,
782     TeX_Sub2,
783     TeX_SupDrop,
784     TeX_SubDrop,
785     TeX_Delim1,
786     TeX_Delim2,
787     TeX_AxisHeight,
788     0};
789 static uint32 tex_mathext_params[] = {
790     TeX_Slant,
791     TeX_Space,
792     TeX_Stretch,
793     TeX_Shrink,
794     TeX_XHeight,
795     TeX_Quad,
796     TeX_MathSp,
797     TeX_DefRuleThick,
798     TeX_BigOpSpace1,
799     TeX_BigOpSpace2,
800     TeX_BigOpSpace3,
801     TeX_BigOpSpace4,
802     TeX_BigOpSpace5,
803     0};
804 
805 
806 /* *************************    The 'TeX ' table    ************************* */
807 /* *************************          Input         ************************* */
808 
TeX_readFontParams(FILE * ttf,struct ttfinfo * info,uint32 base)809 static void TeX_readFontParams(FILE *ttf,struct ttfinfo *info,uint32 base) {
810     int i,pcnt;
811     static uint32 *alltags[] = { tex_text_params, tex_math_params, tex_mathext_params };
812     int j,k;
813     uint32 tag;
814     int32 val;
815 
816     fseek(ttf,base,SEEK_SET);
817     if ( getushort(ttf)!=0 )	/* Don't know how to read this version of the subtable */
818 return;
819     pcnt = getushort(ttf);
820     if ( pcnt==22 ) info->texdata.type = tex_math;
821     else if ( pcnt==13 ) info->texdata.type = tex_mathext;
822     else if ( pcnt>=7 ) info->texdata.type = tex_text;
823     for ( i=0; i<pcnt; ++i ) {
824 	tag = getlong(ttf);
825 	val = getlong(ttf);
826 	for ( j=0; j<3; ++j ) {
827 	    for ( k=0; alltags[j][k]!=0; ++k )
828 		if ( alltags[j][k]==tag )
829 	    break;
830 	    if ( alltags[j][k]==tag )
831 	break;
832 	}
833 	if ( j<3 )
834 	    info->texdata.params[k] = val;
835     }
836 }
837 
TeX_readHeightDepth(FILE * ttf,struct ttfinfo * info,uint32 base)838 static void TeX_readHeightDepth(FILE *ttf,struct ttfinfo *info,uint32 base) {
839     int i,gcnt;
840 
841     fseek(ttf,base,SEEK_SET);
842     if ( getushort(ttf)!=0 )	/* Don't know how to read this version of the subtable */
843 return;
844     gcnt = getushort(ttf);
845     for ( i=0; i<gcnt && i<info->glyph_cnt; ++i ) {
846 	int h, d;
847 	h = getushort(ttf);
848 	d = getushort(ttf);
849 	if ( info->chars[i]!=NULL ) {
850 	    info->chars[i]->tex_height = h;
851 	    info->chars[i]->tex_depth = d;
852 	}
853     }
854 }
855 
TeX_readItalicCorr(FILE * ttf,struct ttfinfo * info,uint32 base)856 static void TeX_readItalicCorr(FILE *ttf,struct ttfinfo *info,uint32 base) {
857     int i,gcnt;
858 
859     fseek(ttf,base,SEEK_SET);
860     if ( getushort(ttf)!=0 )	/* Don't know how to read this version of the subtable */
861 return;
862     gcnt = getushort(ttf);
863     for ( i=0; i<gcnt && i<info->glyph_cnt; ++i ) {
864 	int ital;
865 	ital = getushort(ttf);
866 	if ( info->chars[i]!=NULL ) {
867 	    info->chars[i]->italic_correction = ital;
868 	}
869     }
870 }
871 
tex_read(FILE * ttf,struct ttfinfo * info)872 void tex_read(FILE *ttf,struct ttfinfo *info) {
873     int n,i;
874     struct tagoff { uint32 tag, offset; } tagoff[MAX_SUBTABLE_TYPES+30];
875 
876     fseek(ttf,info->tex_start,SEEK_SET);
877 
878     if ( getlong(ttf)!=0x00010000 )
879 return;
880     n = getlong(ttf);
881     if ( n>=MAX_SUBTABLE_TYPES+30 )
882 	n = MAX_SUBTABLE_TYPES+30;
883     for ( i=0; i<n; ++i ) {
884 	tagoff[i].tag = getlong(ttf);
885 	tagoff[i].offset = getlong(ttf);
886     }
887     for ( i=0; i<n; ++i ) switch ( tagoff[i].tag ) {
888       case CHR('f','t','p','m'):
889 	TeX_readFontParams(ttf,info,info->tex_start+tagoff[i].offset);
890       break;
891       case CHR('h','t','d','p'):
892 	TeX_readHeightDepth(ttf,info,info->tex_start+tagoff[i].offset);
893       break;
894       case CHR('i','t','l','c'):
895 	TeX_readItalicCorr(ttf,info,info->tex_start+tagoff[i].offset);
896       break;
897       default:
898 	LogError( _("Unknown subtable '%c%c%c%c' in 'TeX ' table, ignored\n"),
899 		tagoff[i].tag>>24, (tagoff[i].tag>>16)&0xff, (tagoff[i].tag>>8)&0xff, tagoff[i].tag&0xff );
900       break;
901     }
902 }
903 
904