1 /* Copyright (C) 2000-2012 by George Williams */
2 /*
3  * Redistribution and use in source and binary forms, with or without
4  * modification, are permitted provided that the following conditions are met:
5 
6  * Redistributions of source code must retain the above copyright notice, this
7  * list of conditions and the following disclaimer.
8 
9  * Redistributions in binary form must reproduce the above copyright notice,
10  * this list of conditions and the following disclaimer in the documentation
11  * and/or other materials provided with the distribution.
12 
13  * The name of the author may not be used to endorse or promote products
14  * derived from this software without specific prior written permission.
15 
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
17  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
19  * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  */
27 
28 #include <fontforge-config.h>
29 
30 #include "fvfonts.h"
31 
32 #include "chardata.h"
33 #include "encoding.h"
34 #include "fontforgevw.h"
35 #include "gfile.h"
36 #include "lookups.h"
37 #include "namehash.h"
38 #include "namelist.h"
39 #include "splinefill.h"
40 #include "splineorder2.h"
41 #include "splinesaveafm.h"
42 #include "splineutil.h"
43 #include "splineutil2.h"
44 #include "tottfgpos.h"
45 #include "ustring.h"
46 #include "utype.h"
47 
RefCharsCopy(RefChar * ref)48 RefChar *RefCharsCopy(RefChar *ref) {
49     RefChar *rhead=NULL, *last=NULL, *cur;
50 
51     while ( ref!=NULL ) {
52 	cur = RefCharCreate();
53 	{ struct reflayer *layers = cur->layers; int layer;
54 	layers = realloc(layers,ref->layer_cnt*sizeof(struct reflayer));
55 	memcpy(layers,ref->layers,ref->layer_cnt*sizeof(struct reflayer));
56 	*cur = *ref;
57 	cur->layers = layers;
58 	for ( layer=0; layer<cur->layer_cnt; ++layer ) {
59 	    cur->layers[layer].splines = NULL;
60 	    cur->layers[layer].images = NULL;
61 	}
62 	}
63 	if ( cur->sc!=NULL )
64 	    cur->orig_pos = cur->sc->orig_pos;
65 	cur->next = NULL;
66 	if ( rhead==NULL )
67 	    rhead = cur;
68 	else
69 	    last->next = cur;
70 	last = cur;
71 	ref = ref->next;
72     }
73 return( rhead );
74 }
75 
MCConvertLookup(struct sfmergecontext * mc,OTLookup * otl)76 static OTLookup *MCConvertLookup(struct sfmergecontext *mc,OTLookup *otl) {
77     int l;
78     OTLookup *newotl;
79 
80     if ( mc==NULL || mc->sf_from==mc->sf_to )
81 return( otl );		/* No translation needed */
82 
83     for ( l=0; l<mc->lcnt; ++l ) {
84 	if ( mc->lks[l].from == otl )
85     break;
86     }
87     if ( l==mc->lcnt )
88 return( NULL );
89     if ( mc->lks[l].to!=NULL )
90 return( mc->lks[l].to );
91 
92     mc->lks[l].to = newotl = chunkalloc(sizeof(OTLookup));
93     newotl->lookup_name = strconcat(mc->prefix,otl->lookup_name);
94     newotl->lookup_type = otl->lookup_type;
95     newotl->lookup_flags = otl->lookup_flags;
96     newotl->features = FeatureListCopy(otl->features);
97     newotl->store_in_afm = otl->store_in_afm;
98 return( newotl );
99 }
100 
MCConvertSubtable(struct sfmergecontext * mc,struct lookup_subtable * sub)101 struct lookup_subtable *MCConvertSubtable(struct sfmergecontext *mc,struct lookup_subtable *sub) {
102     int s;
103     struct lookup_subtable *newsub;
104 
105     if ( mc==NULL || mc->sf_from==mc->sf_to )
106 return( sub );		/* No translation needed */
107     if ( mc->prefix==NULL ) {
108 	int lcnt, scnt;
109 	OTLookup *otl;
110 	struct lookup_subtable *subs;
111 	int isgpos, doit;
112 	char *temp;
113 
114 	/* Not initialized */
115 	if ( mc->sf_from->cidmaster ) mc->sf_from = mc->sf_from->cidmaster;
116 	else if ( mc->sf_from->mm!=NULL ) mc->sf_from = mc->sf_from->mm->normal;
117 	if ( mc->sf_to->cidmaster ) mc->sf_to = mc->sf_to->cidmaster;
118 	else if ( mc->sf_to->mm!=NULL ) mc->sf_to = mc->sf_to->mm->normal;
119 	if ( mc->sf_from == mc->sf_to )
120 return( sub );
121 	mc->prefix = strconcat(mc->sf_from->fontname,"-");
122 	for ( doit = 0; doit<2; ++doit ) {
123 	    lcnt = scnt = 0;
124 	    for ( isgpos=0; isgpos<2; ++isgpos ) {
125 		for ( otl = isgpos ? mc->sf_from->gpos_lookups : mc->sf_from->gsub_lookups; otl!=NULL; otl=otl->next ) {
126 		    if ( doit ) {
127 			mc->lks[lcnt].from = otl;
128 			temp = strconcat(mc->prefix,otl->lookup_name);
129 			mc->lks[lcnt].to = SFFindLookup(mc->sf_to,temp);
130 			free(temp);
131 			mc->lks[lcnt].old = mc->lks[lcnt].to!=NULL;
132 		    }
133 		    ++lcnt;
134 		    for ( subs=otl->subtables; subs!=NULL; subs=subs->next ) {
135 			if ( doit ) {
136 			    mc->subs[scnt].from = subs;
137 			    temp = strconcat(mc->prefix,subs->subtable_name);
138 			    mc->subs[scnt].to = SFFindLookupSubtable(mc->sf_to,temp);
139 			    free(temp);
140 			    mc->subs[scnt].old = mc->subs[scnt].to!=NULL;
141 			}
142 			++scnt;
143 		    }
144 		}
145 	    }
146 	    if ( !doit ) {
147 		mc->lcnt = lcnt; mc->scnt = scnt;
148 		mc->lks = calloc(lcnt,sizeof(struct lookup_cvt));
149 		mc->subs = calloc(scnt,sizeof(struct sub_cvt));
150 	    }
151 	}
152     }
153 
154     for ( s=0; s<mc->scnt; ++s ) {
155 	if ( mc->subs[s].from == sub )
156     break;
157     }
158     if ( s==mc->scnt )
159 return( NULL );
160     if ( mc->subs[s].to!=NULL )
161 return( mc->subs[s].to );
162 
163     mc->subs[s].to = newsub = chunkalloc(sizeof(struct lookup_subtable));
164     newsub->subtable_name = strconcat(mc->prefix,sub->subtable_name);
165     newsub->lookup = MCConvertLookup(mc,sub->lookup);
166     newsub->anchor_classes = sub->anchor_classes;
167     newsub->per_glyph_pst_or_kern = sub->per_glyph_pst_or_kern;
168     newsub->separation = sub->separation;
169     newsub->minkern = sub->minkern;
170 return( newsub );
171 }
172 
MCConvertAnchorClass(struct sfmergecontext * mc,AnchorClass * ac)173 AnchorClass *MCConvertAnchorClass(struct sfmergecontext *mc,AnchorClass *ac) {
174     int a;
175     AnchorClass *newac;
176 
177     if ( mc==NULL || mc->sf_from==mc->sf_to )
178 return( ac );		/* No translation needed */
179     if ( mc->acnt==0 ) {
180 	int acnt;
181 	AnchorClass *testac, *testac2;
182 	int doit;
183 	char *temp;
184 
185 	/* Not initialized */
186 	for ( doit = 0; doit<2; ++doit ) {
187 	    acnt = 0;
188 	    for ( testac=mc->sf_from->anchor; testac!=NULL; testac=testac->next ) {
189 		if ( doit ) {
190 		    mc->acs[acnt].from = testac;
191 		    temp = strconcat(mc->prefix,testac->name);
192 		    for ( testac2 = mc->sf_to->anchor; testac2!=NULL; testac2=testac2->next )
193 			if ( strcmp(testac2->name,temp)==0 )
194 		    break;
195 		    mc->acs[acnt].to = testac2;
196 		    free(temp);
197 		    mc->acs[acnt].old = mc->acs[acnt].to!=NULL;
198 		}
199 		++acnt;
200 	    }
201 	    if ( !doit ) {
202 		mc->acnt = acnt;
203 		mc->acs = calloc(acnt,sizeof(struct ac_cvt));
204 	    }
205 	}
206     }
207 
208     for ( a=0; a<mc->acnt; ++a ) {
209 	if ( mc->acs[a].from == ac )
210     break;
211     }
212     if ( a==mc->acnt )
213 return( NULL );
214     if ( mc->acs[a].to!=NULL )
215 return( mc->acs[a].to );
216 
217     mc->acs[a].to = newac = chunkalloc(sizeof(AnchorClass));
218     newac->name = strconcat(mc->prefix,ac->name);
219     newac->subtable = ac->subtable ? MCConvertSubtable(mc,ac->subtable) : NULL;
220     newac->next = mc->sf_to->anchor;
221     mc->sf_to->anchor = newac;
222 return( newac );
223 }
224 
SFFinishMergeContext(struct sfmergecontext * mc)225 void SFFinishMergeContext(struct sfmergecontext *mc) {
226     int l,s,slast, isgpos;
227     OTLookup *otl, *last;
228     struct lookup_subtable *sub_last;
229 
230     if ( mc->prefix==NULL )		/* Nothing to do, never initialized, no lookups needed */
231 return;
232 
233     /* Get all the subtables in the right order */
234     for ( s=0; s<mc->scnt; s=slast ) {
235 	if ( mc->subs[s].to==NULL ) {
236 	    slast = s+1;
237     continue;
238 	}
239 	otl = mc->subs[s].to->lookup;
240 	sub_last = otl->subtables = mc->subs[s].to;
241 	for ( slast=s+1; slast<mc->scnt; ++slast ) {
242 	    if ( mc->subs[slast].to==NULL )
243 	continue;
244 	    if ( mc->subs[slast].to->lookup!=otl )
245 	break;
246 	    sub_last->next = mc->subs[slast].to;
247 	    sub_last = sub_last->next;
248 	}
249 	sub_last->next = NULL;
250     }
251 
252     /* Then order the lookups. Leave the old lookups as they are, insert the */
253     /*  new at the end of the list */
254     last = NULL;
255     for ( l=0; l<mc->lcnt; ++l ) {
256 	if ( mc->lks[l].to==NULL || mc->lks[l].old )
257     continue;
258 	otl = mc->lks[l].to;
259 	isgpos = (otl->lookup_type>=gpos_start);
260 	if ( last==NULL || (last->lookup_type>=gpos_start)!=isgpos) {
261 	    last = isgpos ? mc->sf_to->gpos_lookups : mc->sf_to->gsub_lookups;
262 	    if ( last!=NULL )
263 		while ( last->next!=NULL )
264 		    last = last->next;
265 	}
266 	if ( last!=NULL )
267 	    last->next = otl;
268 	else if ( isgpos )
269 	    mc->sf_to->gpos_lookups = otl;
270 	else
271 	    mc->sf_to->gsub_lookups = otl;
272 	last = otl;
273     }
274 
275     free(mc->prefix);
276     free(mc->lks);
277     free(mc->subs);
278     free(mc->acs);
279 }
280 
PSTCopy(PST * base,SplineChar * sc,struct sfmergecontext * mc)281 PST *PSTCopy(PST *base,SplineChar *sc,struct sfmergecontext *mc) {
282     PST *head=NULL, *last=NULL, *cur;
283 
284     for ( ; base!=NULL; base = base->next ) {
285 	cur = chunkalloc(sizeof(PST));
286 	*cur = *base;
287 	cur->subtable = MCConvertSubtable(mc,base->subtable);
288 	if ( cur->type==pst_ligature ) {
289 	    cur->u.lig.components = copy(cur->u.lig.components);
290 	    cur->u.lig.lig = sc;
291 	} else if ( cur->type==pst_pair ) {
292 	    cur->u.pair.paired = copy(cur->u.pair.paired);
293 	    cur->u.pair.vr = chunkalloc(sizeof( struct vr [2]));
294 	    memcpy(cur->u.pair.vr,base->u.pair.vr,sizeof(struct vr [2]));
295 	    cur->u.pair.vr[0].adjust = ValDevTabCopy(base->u.pair.vr[0].adjust);
296 	    cur->u.pair.vr[1].adjust = ValDevTabCopy(base->u.pair.vr[1].adjust);
297 	} else if ( cur->type==pst_lcaret ) {
298 	    cur->u.lcaret.carets = malloc(cur->u.lcaret.cnt*sizeof(int16));
299 	    memcpy(cur->u.lcaret.carets,base->u.lcaret.carets,cur->u.lcaret.cnt*sizeof(uint16));
300 	} else if ( cur->type==pst_substitution || cur->type==pst_multiple || cur->type==pst_alternate )
301 	    cur->u.subs.variant = copy(cur->u.subs.variant);
302 	if ( head==NULL )
303 	    head = cur;
304 	else
305 	    last->next = cur;
306 	last = cur;
307     }
308 return( head );
309 }
310 
AnchorPointsDuplicate(AnchorPoint * base,SplineChar * sc)311 static AnchorPoint *AnchorPointsDuplicate(AnchorPoint *base,SplineChar *sc) {
312     AnchorPoint *head=NULL, *last=NULL, *cur;
313     AnchorClass *ac;
314 
315     for ( ; base!=NULL; base = base->next ) {
316 	cur = chunkalloc(sizeof(AnchorPoint));
317 	*cur = *base;
318 	cur->next = NULL;
319 	for ( ac=sc->parent->anchor; ac!=NULL; ac=ac->next )
320 	    if ( strcmp(ac->name,base->anchor->name)==0 )
321 	break;
322 	cur->anchor = ac;
323 	if ( ac==NULL ) {
324 	    LogError(_("No matching AnchorClass for %s"), base->anchor->name);
325 	    chunkfree(cur,sizeof(AnchorPoint));
326 	} else {
327 	    if ( head==NULL )
328 		head = cur;
329 	    else
330 		last->next = cur;
331 	    last = cur;
332 	}
333     }
334 return( head );
335 }
336 
AnchorClassesAdd(SplineFont * into,SplineFont * from,struct sfmergecontext * mc)337 static void AnchorClassesAdd(SplineFont *into, SplineFont *from, struct sfmergecontext *mc) {
338     AnchorClass *fac, *iac, *last, *cur;
339 
340     if ( into->cidmaster!=NULL )
341 	into = into->cidmaster;
342     if ( from->cidmaster!=NULL )
343 	from = from->cidmaster;
344 
345     for ( fac = from->anchor; fac!=NULL; fac=fac->next ) {
346 	last = NULL;
347 	for ( iac=into->anchor; iac!=NULL; iac=iac->next ) {
348 	    if ( strcmp(iac->name,fac->name)==0 )
349 	break;
350 	    last = iac;
351 	}
352 	if ( iac==NULL ) {
353 	    cur = chunkalloc(sizeof(AnchorClass));
354 	    *cur = *fac;
355 	    cur->next = NULL;
356 	    cur->name = copy(cur->name);
357 	    cur->subtable = cur->subtable ? MCConvertSubtable(mc,cur->subtable) : NULL;
358 	    if ( last==NULL )
359 		into->anchor = cur;
360 	    else
361 		last->next = cur;
362 	} else {
363 	    /* Just use the one that's there and hope it's right. Not sure */
364 	    /*  what else we can do... */
365 	}
366     }
367 }
368 
FPSTsAdd(SplineFont * into,SplineFont * from,struct sfmergecontext * mc)369 static void FPSTsAdd(SplineFont *into, SplineFont *from,struct sfmergecontext *mc) {
370     FPST *fpst, *nfpst, *last;
371     int i,k;
372 
373     last = NULL;
374     if ( into->possub!=NULL )
375 	for ( last = into->possub; last->next!=NULL; last=last->next );
376     for ( fpst = from->possub; fpst!=NULL; fpst=fpst->next ) {
377 	nfpst = FPSTCopy(fpst);
378 	nfpst->subtable = MCConvertSubtable(mc,fpst->subtable);
379 	nfpst->subtable->fpst = nfpst;
380 	for ( i=0; i<nfpst->rule_cnt; ++i ) {
381 	    struct fpst_rule *r = &nfpst->rules[i], *oldr = &fpst->rules[i];
382 	    for ( k=0; k<r->lookup_cnt; ++k ) {
383 		r->lookups[k].lookup = MCConvertLookup(mc,oldr->lookups[k].lookup);
384 	    }
385 	}
386 	if ( last==NULL )
387 	    into->possub = nfpst;
388 	else
389 	    last->next = nfpst;
390 	last = nfpst;
391     }
392 }
393 
ASMsAdd(SplineFont * into,SplineFont * from,struct sfmergecontext * mc)394 static void ASMsAdd(SplineFont *into, SplineFont *from,struct sfmergecontext *mc) {
395     ASM *sm, *nsm, *last;
396     int i;
397 
398     last = NULL;
399     if ( into->sm!=NULL )
400 	for ( last = into->sm; last->next!=NULL; last=last->next );
401     for ( sm = from->sm; sm!=NULL; sm=sm->next ) {
402 	nsm = chunkalloc(sizeof(ASM));
403 	*nsm = *sm;
404 	nsm->subtable = MCConvertSubtable(mc,sm->subtable);
405 	nsm->subtable->sm = nsm;
406 	nsm->classes = malloc(nsm->class_cnt*sizeof(char *));
407 	for ( i=0; i<nsm->class_cnt; ++i )
408 	    nsm->classes[i] = copy(sm->classes[i]);
409 	nsm->state = malloc(nsm->class_cnt*nsm->state_cnt*sizeof(struct asm_state));
410 	memcpy(nsm->state,sm->state,nsm->class_cnt*nsm->state_cnt*sizeof(struct asm_state));
411 	if ( nsm->type == asm_kern ) {
412 	    for ( i=nsm->class_cnt*nsm->state_cnt-1; i>=0; --i ) {
413 		nsm->state[i].u.kern.kerns = malloc(nsm->state[i].u.kern.kcnt*sizeof(int16));
414 		memcpy(nsm->state[i].u.kern.kerns,sm->state[i].u.kern.kerns,nsm->state[i].u.kern.kcnt*sizeof(int16));
415 	    }
416 	} else if ( nsm->type == asm_context ) {
417 	    for ( i=0; i<nsm->class_cnt*nsm->state_cnt; ++i ) {
418 		nsm->state[i].u.context.mark_lookup = MCConvertLookup(mc,
419 			nsm->state[i].u.context.mark_lookup);
420 		nsm->state[i].u.context.cur_lookup = MCConvertLookup(mc,
421 			nsm->state[i].u.context.cur_lookup);
422 	    }
423 	} else if ( nsm->type == asm_insert ) {
424 	    for ( i=nsm->class_cnt*nsm->state_cnt-1; i>=0; --i ) {
425 		nsm->state[i].u.insert.mark_ins = copy(sm->state[i].u.insert.mark_ins);
426 		nsm->state[i].u.insert.cur_ins = copy(sm->state[i].u.insert.cur_ins);
427 	    }
428 	}
429     }
430 }
431 
_KernClassCopy(KernClass * kc,SplineFont * into,SplineFont * from,struct sfmergecontext * mc)432 static KernClass *_KernClassCopy(KernClass *kc,SplineFont *into,SplineFont *from,struct sfmergecontext *mc) {
433     KernClass *nkc;
434 
435     nkc = KernClassCopy(kc);
436     nkc->subtable = MCConvertSubtable(mc,kc->subtable);
437     nkc->subtable->kc = nkc;
438 return( nkc );
439 }
440 
KernClassesAdd(SplineFont * into,SplineFont * from,struct sfmergecontext * mc)441 static void KernClassesAdd(SplineFont *into, SplineFont *from,struct sfmergecontext *mc) {
442     /* Is this a good idea? We could end up with two kern classes that do */
443     /*  the same thing and strange sets of slis so that they didn't all fit */
444     /*  in one lookup... */
445     KernClass *kc, *last, *cur;
446 
447     last = NULL;
448     if ( into->kerns!=NULL )
449 	for ( last = into->kerns; last->next!=NULL; last=last->next );
450     for ( kc=from->kerns; kc!=NULL; kc=kc->next ) {
451 	cur = _KernClassCopy(kc,into,from,mc);
452 	if ( last==NULL )
453 	    into->kerns = cur;
454 	else
455 	    last->next = cur;
456 	last = cur;
457     }
458 
459     last = NULL;
460     if ( into->vkerns!=NULL )
461 	for ( last = into->vkerns; last->next!=NULL; last=last->next )
462     for ( kc=from->vkerns; kc!=NULL; kc=kc->next ) {
463 	cur = _KernClassCopy(kc,into,from,mc);
464 	if ( last==NULL )
465 	    into->vkerns = cur;
466 	else
467 	    last->next = cur;
468 	last = cur;
469     }
470 }
471 
AltUniCopy(struct altuni * altuni,SplineFont * noconflicts)472 struct altuni *AltUniCopy(struct altuni *altuni,SplineFont *noconflicts) {
473     struct altuni *head=NULL, *last=NULL, *cur;
474 
475     while ( altuni!=NULL ) {
476 	if ( noconflicts==NULL || SFGetChar(noconflicts,altuni->unienc,NULL)==NULL ) {
477 	    cur = chunkalloc(sizeof(struct altuni));
478 	    cur->unienc = altuni->unienc;
479 	    cur->vs = altuni->vs;
480 	    cur->fid = altuni->fid;
481 	    if ( head==NULL )
482 		head = cur;
483 	    else
484 		last->next = cur;
485 	    last = cur;
486 	}
487 	altuni = altuni->next;
488     }
489 return( head );
490 }
491 
SplineCharCopy(SplineChar * sc,SplineFont * into,struct sfmergecontext * mc)492 SplineChar *SplineCharCopy(SplineChar *sc,SplineFont *into,struct sfmergecontext *mc) {
493     SplineChar *nsc = SFSplineCharCreate(into);
494     Layer *layers = nsc->layers;
495     int layer, lycopy;
496 
497 	*nsc = *sc;
498 
499 	/* Copy the instrs from the given sc to the new splinechar */
500 	if ( sc->ttf_instrs_len!=0 ) {
501 		nsc->ttf_instrs = malloc(sc->ttf_instrs_len);
502 		memcpy(nsc->ttf_instrs,sc->ttf_instrs,sc->ttf_instrs_len);
503 	}
504 
505 	/* We copy the layers just below */
506     nsc->layer_cnt = into==NULL?2:into->layer_cnt;
507     nsc->layers = layers;
508     lycopy = sc->layer_cnt>nsc->layer_cnt ? nsc->layer_cnt : sc->layer_cnt;
509     memcpy(layers,sc->layers,lycopy*sizeof(Layer));
510     if ( nsc->layer_cnt>lycopy )
511 	memset(layers+lycopy,0,(nsc->layer_cnt-lycopy)*sizeof(Layer));
512     for ( layer = ly_back; layer<lycopy; ++layer ) {
513 	layers[layer].splines = SplinePointListCopy(layers[layer].splines);
514 	layers[layer].refs = RefCharsCopy(layers[layer].refs);
515 	layers[layer].images = ImageListCopy(layers[layer].images);
516 	layers[layer].undoes = NULL;
517 	layers[layer].redoes = NULL;
518 	if ( into!=NULL ) {
519 	    if ( into->layers[layer].order2!=sc->layers[layer].order2 ) {
520 		nsc->layers[layer].order2 = into->layers[layer].order2;
521 		if ( into->layers[layer].order2 ) {
522 		    SCConvertLayerToOrder2(nsc,layer);
523 		} else {
524 		    SCConvertLayerToOrder3(nsc,layer);
525 		}
526 	    }
527 	} else {
528 	    /* Happens in Apple's gvar (MM) fonts */
529 	    nsc->layers[layer].order2 = sc->layers[layer].order2;
530 	}
531     }
532     nsc->parent = into;
533     nsc->orig_pos = -2;
534     nsc->name = copy(sc->name);
535     nsc->hstem = StemInfoCopy(nsc->hstem);
536     nsc->vstem = StemInfoCopy(nsc->vstem);
537     nsc->dstem = DStemInfoCopy(nsc->dstem);
538     nsc->md = NULL;
539     if ( sc->countermask_cnt!=0 ) {
540 	nsc->countermasks = malloc(sc->countermask_cnt*sizeof(HintMask));
541 	memcpy(nsc->countermasks,sc->countermasks,sc->countermask_cnt*sizeof(HintMask));
542     }
543     nsc->anchor = AnchorPointsDuplicate(nsc->anchor,nsc);
544     nsc->changed = true;
545     /* Fix up dependents later when we know more */
546     nsc->dependents = NULL;
547 
548     nsc->kerns = NULL;
549     nsc->vkerns = NULL;
550     nsc->possub = PSTCopy(nsc->possub,nsc,mc);
551     nsc->altuni = AltUniCopy(nsc->altuni,into);
552     nsc->charinfo = NULL;
553     nsc->views = NULL;
554 return(nsc);
555 }
556 
557 static int _SFFindExistingSlot(SplineFont *sf, int unienc, const char *name );
558 
KernsCopy(KernPair * kp,int * mapping,SplineFont * into,struct sfmergecontext * mc)559 static KernPair *KernsCopy(KernPair *kp,int *mapping,SplineFont *into,
560 	struct sfmergecontext *mc) {
561     KernPair *head = NULL, *last=NULL, *new;
562     int index;
563 
564     while ( kp!=NULL ) {
565 	if ( (index=mapping[kp->sc->orig_pos])<0 && mc->preserveCrossFontKerning )
566 	    index =  _SFFindExistingSlot(into,kp->sc->unicodeenc,kp->sc->name);
567 	if ( index>=0 && index<into->glyphcnt &&
568 		into->glyphs[index]!=NULL ) {
569 	    new = chunkalloc(sizeof(KernPair));
570 	    new->off = kp->off;
571 	    new->subtable = MCConvertSubtable(mc,kp->subtable);
572 	    new->sc = into->glyphs[index];
573 	    if ( head==NULL )
574 		head = new;
575 	    else
576 		last->next = new;
577 	    last = new;
578 	}
579 	kp = kp->next;
580     }
581 return( head );
582 }
583 
BDFCharCopy(BDFChar * bc)584 BDFChar *BDFCharCopy(BDFChar *bc) {
585     BDFChar *nbc = malloc(sizeof( BDFChar ));
586 
587     *nbc = *bc;
588     nbc->views = NULL;
589     nbc->selection = NULL;
590     nbc->undoes = NULL;
591     nbc->redoes = NULL;
592     nbc->bitmap = malloc((nbc->ymax-nbc->ymin+1)*nbc->bytes_per_line);
593     memcpy(nbc->bitmap,bc->bitmap,(nbc->ymax-nbc->ymin+1)*nbc->bytes_per_line);
594 return( nbc );
595 }
596 
BitmapsCopy(SplineFont * to,SplineFont * from,int to_index,int from_index)597 void BitmapsCopy(SplineFont *to, SplineFont *from, int to_index, int from_index ) {
598     BDFFont *f_bdf, *t_bdf;
599 
600     /* We assume that the bitmaps are ordered. They should be */
601     for ( t_bdf=to->bitmaps, f_bdf=from->bitmaps; t_bdf!=NULL && f_bdf!=NULL; ) {
602 	if ( t_bdf->pixelsize == f_bdf->pixelsize ) {
603 	    if ( f_bdf->glyphs[from_index]!=NULL ) {
604 		BDFCharFree(t_bdf->glyphs[to_index]);
605 		t_bdf->glyphs[to_index] = BDFCharCopy(f_bdf->glyphs[from_index]);
606 		t_bdf->glyphs[to_index]->sc = to->glyphs[to_index];
607 		t_bdf->glyphs[to_index]->orig_pos = to_index;
608 	    }
609 	    t_bdf = t_bdf->next;
610 	    f_bdf = f_bdf->next;
611 	} else if ( t_bdf->pixelsize < f_bdf->pixelsize ) {
612 	    t_bdf = t_bdf->next;
613 	} else if ( t_bdf->pixelsize > f_bdf->pixelsize ) {
614 	    /* Insert these bitmaps? Or skip? */
615 	    f_bdf = f_bdf->next;
616 	}
617     }
618 }
619 
__GlyphHashFree(struct glyphnamehash * hash)620 void __GlyphHashFree(struct glyphnamehash *hash) {
621     struct glyphnamebucket *test, *next;
622     int i;
623 
624     if ( hash==NULL )
625 return;
626     for ( i=0; i<GN_HSIZE; ++i ) {
627 	for ( test = hash->table[i]; test!=NULL; test = next ) {
628 	    next = test->next;
629 	    chunkfree(test,sizeof(struct glyphnamebucket));
630 	}
631     }
632 }
633 
_GlyphHashFree(SplineFont * sf)634 static void _GlyphHashFree(SplineFont *sf) {
635 
636     if ( sf->glyphnames==NULL )
637 return;
638     __GlyphHashFree(sf->glyphnames);
639     free(sf->glyphnames);
640     sf->glyphnames = NULL;
641 }
642 
GlyphHashFree(SplineFont * sf)643 void GlyphHashFree(SplineFont *sf) {
644     _GlyphHashFree(sf);
645     if ( sf->cidmaster )
646 	_GlyphHashFree(sf->cidmaster);
647 }
648 
GlyphHashCreate(SplineFont * sf)649 static void GlyphHashCreate(SplineFont *sf) {
650     int i, k;
651     unsigned int hash;
652     SplineFont *_sf;
653     struct glyphnamehash *gnh;
654     struct glyphnamebucket *new;
655 
656     if ( sf->glyphnames!=NULL )
657 return;
658     sf->glyphnames = gnh = calloc(1,sizeof(*gnh));
659     k = 0;
660     do {
661 	_sf = k<sf->subfontcnt ? sf->subfonts[k] : sf;
662 	/* I walk backwards because there are some ttf files where multiple */
663 	/*  glyphs get the same name. In the cases I've seen only one of these */
664 	/*  has an encoding. That's the one we want. It will be earlier in the */
665 	/*  font than the others. If we build the list backwards then it will */
666 	/*  be the top name in the bucket, and will be the one we return */
667 	for ( i=_sf->glyphcnt-1; i>=0; --i ) if ( _sf->glyphs[i]!=NULL ) {
668 	    new = chunkalloc(sizeof(struct glyphnamebucket));
669 	    new->sc = _sf->glyphs[i];
670 	    hash = hashname(new->sc->name);
671 	    new->next = gnh->table[hash];
672 	    gnh->table[hash] = new;
673 	}
674 	++k;
675     } while ( k<sf->subfontcnt );
676 }
677 
SFHashGlyph(SplineFont * sf,SplineChar * sc)678 void SFHashGlyph(SplineFont *sf,SplineChar *sc) {
679     /* sc just got added to the font. Put it in the lookup */
680     unsigned int hash;
681     struct glyphnamebucket *new;
682 
683     if ( sf->glyphnames==NULL )
684 return;		/* No hash table, nothing to update */
685 
686     new = chunkalloc(sizeof(struct glyphnamebucket));
687     new->sc = sc;
688     hash = hashname(sc->name);
689     new->next = sf->glyphnames->table[hash];
690     sf->glyphnames->table[hash] = new;
691 }
692 
SFHashName(SplineFont * sf,const char * name)693 SplineChar *SFHashName(SplineFont *sf,const char *name) {
694     struct glyphnamebucket *test;
695 
696     if ( sf->glyphnames==NULL )
697 	GlyphHashCreate(sf);
698 
699     for ( test=sf->glyphnames->table[hashname(name)]; test!=NULL; test = test->next )
700 	if ( strcmp(test->sc->name,name)==0 )
701 return( test->sc );
702 
703 return( NULL );
704 }
705 
SCUniMatch(SplineChar * sc,int unienc)706 static int SCUniMatch(SplineChar *sc,int unienc) {
707     struct altuni *alt;
708 
709     if ( sc->unicodeenc==unienc )
710 return( true );
711     for ( alt=sc->altuni; alt!=NULL; alt=alt->next )
712 	if ( alt->unienc==unienc )
713 return( true );
714 
715 return( false );
716 }
717 
718 /* Find the position in the glyph list where this code point/name is found. */
719 /*  Returns -1 else on error */
SFFindGID(SplineFont * sf,int unienc,const char * name)720 int SFFindGID(SplineFont *sf, int unienc, const char *name ) {
721     int gid;
722     SplineChar *sc;
723 
724     if ( unienc!=-1 ) {
725 	for ( gid=0; gid<sf->glyphcnt; ++gid ) if ( sf->glyphs[gid]!=NULL ) {
726 	    if ( SCUniMatch(sf->glyphs[gid],unienc) )
727 return( gid );
728 	}
729     }
730     if ( name!=NULL ) {
731 	sc = SFHashName(sf,name);
732 	if ( sc!=NULL )
733 return( sc->orig_pos );
734     }
735 
736 return ( -1 );
737 }
738 
739 /* Find the position in the current encoding where this code point/name should*/
740 /*  be found. (or for unencoded glyphs where it is found). Returns -1 else */
SFFindSlot(SplineFont * sf,EncMap * map,int unienc,const char * name)741 int SFFindSlot(SplineFont *sf, EncMap *map, int unienc, const char *name ) {
742     int index=-1, pos;
743     struct cidmap *cidmap;
744 
745     if ( sf->cidmaster!=NULL && !map->enc->is_compact &&
746 		(cidmap = FindCidMap(sf->cidmaster->cidregistry,
747 				    sf->cidmaster->ordering,
748 				    sf->cidmaster->supplement,
749 				    sf->cidmaster))!=NULL )
750 	index = NameUni2CID(cidmap,unienc,name);
751     if ( index!=-1 )
752 	/* All done */;
753     else if ( (map->enc->is_custom || map->enc->is_compact ||
754 	    map->enc->is_original) && unienc!=-1 ) {
755 	/* Just on the off-chance that it is unicode after all */
756 	if ( unienc<map->enccount && map->map[unienc]!=-1 &&
757 		sf->glyphs[map->map[unienc]]!=NULL &&
758 		sf->glyphs[map->map[unienc]]->unicodeenc==unienc )
759 	    index = unienc;
760 	else for ( index = map->enccount-1; index>=0; --index ) {
761 	    if ( (pos = map->map[index])!=-1 && sf->glyphs[pos]!=NULL &&
762 			SCUniMatch(sf->glyphs[pos],unienc) )
763 	break;
764 	}
765     } else if ( unienc!=-1 &&
766 	    ((unienc<0x10000 && map->enc->is_unicodebmp) ||
767 	     (unienc<0x110000 && map->enc->is_unicodefull))) {
768 	 index = unienc;
769     } else if ( unienc!=-1 ) {
770 	index = EncFromUni(unienc,map->enc);
771 	if ( index<0 || index>=map->enccount ) {
772 	    for ( index=map->enc->char_cnt; index<map->enccount; ++index )
773 		if ( (pos = map->map[index])!=-1 && sf->glyphs[pos]!=NULL &&
774 			SCUniMatch(sf->glyphs[pos],unienc) )
775 	    break;
776 	    if ( index>=map->enccount )
777 		index = -1;
778 	}
779     }
780     if ( index==-1 && name!=NULL ) {
781 	SplineChar *sc = SFHashName(sf,name);
782 	if ( sc!=NULL ) index = map->backmap[sc->orig_pos];
783 	if ( index==-1 ) {
784 	    unienc = UniFromName(name,sf->uni_interp,map->enc);
785 	    if ( unienc!=-1 )
786 return( SFFindSlot(sf,map,unienc,NULL));
787 	    if ( map->enc->psnames!=NULL ) {
788 		for ( index = map->enc->char_cnt-1; index>=0; --index )
789 		    if ( map->enc->psnames[index]!=NULL &&
790 			    strcmp(map->enc->psnames[index],name)==0 )
791 return( index );
792 	    }
793 	}
794     }
795 
796 return( index );
797 }
798 
SFCIDFindExistingChar(SplineFont * sf,int unienc,const char * name)799 int SFCIDFindExistingChar(SplineFont *sf, int unienc, const char *name ) {
800     int j,ret;
801 
802     if ( sf->subfonts==NULL && sf->cidmaster==NULL )
803 return( SFFindExistingSlot(sf,unienc,name));
804     if ( sf->cidmaster!=NULL )
805 	sf=sf->cidmaster;
806     for ( j=0; j<sf->subfontcnt; ++j )
807 	if (( ret = SFFindExistingSlot(sf,unienc,name))!=-1 )
808 return( ret );
809 return( -1 );
810 }
811 
SFCIDFindCID(SplineFont * sf,int unienc,const char * name)812 int SFCIDFindCID(SplineFont *sf, int unienc, const char *name ) {
813 	// For a given SplineFont *sf, find the index of the SplineChar with code unienc or name *name.
814     int j,ret;
815     struct cidmap *cidmap;
816 
817 	// If there is a cidmap or if there are multiple subfonts, do complicated things.
818     if ( sf->cidmaster!=NULL || sf->subfontcnt!=0 ) {
819 		if ( sf->cidmaster!=NULL )
820 			sf=sf->cidmaster;
821 		cidmap = FindCidMap(sf->cidregistry,sf->ordering,sf->supplement,sf);
822 		ret = NameUni2CID(cidmap,unienc,name);
823 		if ( ret!=-1 )
824 		    return( ret );
825     }
826 
827 	// If things are simple, perform a flat map.
828     if ( sf->subfonts==NULL && sf->cidmaster==NULL )
829 	return( SFFindGID(sf,unienc,name));
830 
831 	// If the cid lookup from before failed, look through subfonts.
832     if ( sf->cidmaster!=NULL )
833 		sf=sf->cidmaster;
834     for ( j=0; j<sf->subfontcnt; ++j )
835 		if (( ret = SFFindGID(sf,unienc,name))!=-1 )
836 			return( ret );
837 
838 	return( -1 );
839 }
840 
SFHasCID(SplineFont * sf,int cid)841 int SFHasCID(SplineFont *sf,int cid) {
842     int i;
843     /* What subfont (if any) contains this cid? */
844     if ( sf->cidmaster!=NULL )
845 	sf=sf->cidmaster;
846     for ( i=0; i<sf->subfontcnt; ++i )
847 	if ( cid<sf->subfonts[i]->glyphcnt &&
848 		SCWorthOutputting(sf->subfonts[i]->glyphs[cid]) )
849 return( i );
850     for ( i=0; i<sf->subfontcnt; ++i )
851 	if ( cid<sf->subfonts[i]->glyphcnt && sf->subfonts[i]->glyphs[cid]!=NULL )
852 return( i );
853 
854 return( -1 );
855 }
856 
SFGetChar(SplineFont * sf,int unienc,const char * name)857 SplineChar *SFGetChar(SplineFont *sf, int unienc, const char *name ) {
858 	// This function presumably finds a glyph matching the code or name supplied. Undefined code is unienc = -1. Undefined name is name = NULL.
859     int ind = -1;
860     int j;
861     char *pt, *start; int ch;
862 
863     if ( name==NULL )
864 		ind = SFCIDFindCID(sf,unienc,NULL);
865     else {
866 		for ( start=(char *) name; *start==' '; ++start );
867 		for ( pt=start; *pt!='\0' && *pt!='('; ++pt );
868 		ch = *pt;
869 		// We truncate any glyph name before parentheses.
870 		if ( ch=='\0' )
871 			ind = SFCIDFindCID(sf,unienc,start);
872 		else {
873 			char *tmp;
874 			if ( (tmp = copy(name)) ) {
875 				tmp[pt-name] = '\0';
876 				ind = SFCIDFindCID(sf,unienc,tmp+(start-name));
877 				tmp[pt-name] = ch;
878 				free(tmp);
879 			}
880 		}
881     }
882     if ( ind==-1 )
883 		return( NULL );
884 
885 	// If the typeface is simple, return the result from the flat glyph collection.
886     if ( sf->subfonts==NULL && sf->cidmaster==NULL )
887 		return( sf->glyphs[ind]);
888 
889     if ( sf->cidmaster!=NULL )
890 		sf=sf->cidmaster;
891 
892 	// Find a subfont that contains the glyph in question.
893     j = SFHasCID(sf,ind);
894     if ( j==-1 )
895 		return( NULL );
896 
897 	return( sf->subfonts[j]->glyphs[ind] );
898 }
899 
SFGetOrMakeChar(SplineFont * sf,int unienc,const char * name)900 SplineChar *SFGetOrMakeChar(SplineFont *sf, int unienc, const char *name ) {
901     SplineChar *sc=NULL;
902 
903     if ( sf->fv!=NULL ) {
904 	int ind = SFFindSlot(sf,sf->fv->map,unienc,name);
905 	if ( ind!=-1 )
906 	    sc = SFMakeChar(sf,sf->fv->map,ind);
907     } else
908 	sc = SFGetChar(sf,unienc,name);
909     if ( sc==NULL && (unienc!=-1 || name!=NULL)) {
910 	sc = SFSplineCharCreate(sf);
911 	if ( sf->strokedfont ) {
912 	    sc->layers[ly_fore].dostroke = true;
913 	    sc->layers[ly_fore].dofill = false;
914 	}
915 	sc->unicodeenc = unienc;
916 	if ( name!=NULL )
917 	    sc->name = copy(name);
918 	else {
919 	    char buffer[40];
920 	    sprintf(buffer,"glyph%d", sf->glyphcnt);
921 	    sc->name = copy(buffer);
922 	}
923 	SFAddGlyphAndEncode(sf,sc,NULL,-1);
924 	/*SCLigDefault(sc);*/
925     }
926 return( sc );
927 }
928 
SFGetOrMakeCharFromUnicode(SplineFont * sf,EncMap * map,int ch)929 SplineChar *SFGetOrMakeCharFromUnicode( SplineFont *sf, EncMap *map, int ch )
930 {
931     int i;
932     SplineChar *sc;
933 
934     i = SFFindSlot(sf,map,ch,NULL);
935     if ( i==-1 )
936 	return( NULL );
937     else
938     {
939 	sc = SFMakeChar(sf,map,i);
940     }
941     return( sc );
942 }
SFGetOrMakeCharFromUnicodeBasic(SplineFont * sf,int ch)943 SplineChar *SFGetOrMakeCharFromUnicodeBasic( SplineFont *sf, int ch )
944 {
945     return SFGetOrMakeCharFromUnicode( sf, sf->fv->map, ch );
946 }
947 
948 
949 
_SFFindExistingSlot(SplineFont * sf,int unienc,const char * name)950 static int _SFFindExistingSlot(SplineFont *sf, int unienc, const char *name ) {
951     int gid = -1;
952     struct altuni *altuni;
953 
954     if ( unienc!=-1 ) {
955 	for ( gid=sf->glyphcnt-1; gid>=0; --gid ) if ( sf->glyphs[gid]!=NULL ) {
956 	    if ( sf->glyphs[gid]->unicodeenc==unienc )
957 	break;
958 	    for ( altuni=sf->glyphs[gid]->altuni ; altuni!=NULL &&
959 		    (altuni->unienc!=unienc || altuni->vs!=-1 || altuni->fid!=0);
960 		    altuni=altuni->next );
961 	    if ( altuni!=NULL )
962 	break;
963 	}
964     }
965     if ( gid==-1 && name!=NULL ) {
966 	SplineChar *sc = SFHashName(sf,name);
967 	if ( sc==NULL )
968 return( -1 );
969 	gid = sc->orig_pos;
970 	if ( gid<0 || gid>=sf->glyphcnt ) {
971 	    IError("Invalid glyph location when searching for %s", name );
972 return( -1 );
973 	}
974     }
975 return( gid );
976 }
977 
SFFindExistingSlot(SplineFont * sf,int unienc,const char * name)978 int SFFindExistingSlot(SplineFont *sf, int unienc, const char *name ) {
979     int gid = _SFFindExistingSlot(sf,unienc,name);
980 
981     if ( gid==-1 || !SCWorthOutputting(sf->glyphs[gid]) )
982 return( -1 );
983 
984 return( gid );
985 }
986 
MFixupSC(SplineFont * sf,SplineChar * sc,int i)987 static void MFixupSC(SplineFont *sf, SplineChar *sc,int i) {
988     RefChar *ref, *prev;
989     int l;
990 
991     sc->orig_pos = i;
992     sc->parent = sf;
993     sc->ticked = true;
994     for ( l=0; l<sc->layer_cnt; ++l ) {
995      retry:
996 	for ( ref=sc->layers[l].refs; ref!=NULL; ref=ref->next ) {
997 	    /* The sc in the ref is from the old font. It's got to be in the */
998 	    /*  new font too (was either already there or just got copied) */
999 	    ref->orig_pos =  SFFindExistingSlot(sf,ref->sc->unicodeenc,ref->sc->name);
1000 	    if ( ref->orig_pos==-1 ) {
1001 		IError("Bad reference, can't fix it up");
1002 		if ( ref==sc->layers[l].refs ) {
1003 		    sc->layers[l].refs = ref->next;
1004      goto retry;
1005 		} else {
1006 		    for ( prev=sc->layers[l].refs; prev->next!=ref; prev=prev->next );
1007 		    prev->next = ref->next;
1008 		    chunkfree(ref,sizeof(*ref));
1009 		    ref = prev;
1010 		}
1011 	    } else {
1012 		ref->sc = sf->glyphs[ref->orig_pos];
1013 		if ( !ref->sc->ticked )
1014 		    MFixupSC(sf,ref->sc,ref->orig_pos);
1015 		SCReinstanciateRefChar(sc,ref,l);
1016 		SCMakeDependent(sc,ref->sc);
1017 	    }
1018 	}
1019     }
1020     /* I shan't automagically generate bitmaps for any bdf fonts */
1021     /*  but I have copied over the ones which match */
1022 }
1023 
MergeFixupRefChars(SplineFont * sf)1024 static void MergeFixupRefChars(SplineFont *sf) {
1025     int i;
1026 
1027     for ( i=0; i<sf->glyphcnt; ++i ) if ( sf->glyphs[i]!=NULL ) {
1028 	sf->glyphs[i]->ticked = false;
1029     }
1030     for ( i=0; i<sf->glyphcnt; ++i ) if ( sf->glyphs[i]!=NULL && !sf->glyphs[i]->ticked ) {
1031 	MFixupSC(sf,sf->glyphs[i], i);
1032     }
1033 }
1034 
SFHasChar(SplineFont * sf,int unienc,const char * name)1035 int SFHasChar(SplineFont *sf, int unienc, const char *name ) {
1036     SplineChar *sc = SFGetChar(sf,unienc,name);
1037 
1038 return( SCWorthOutputting(sc) );
1039 }
1040 
FVMergeRefigureMapSel(FontViewBase * fv,SplineFont * into,SplineFont * o_sf,int * mapping,int emptypos,int cnt)1041 static void FVMergeRefigureMapSel(FontViewBase *fv,SplineFont *into,SplineFont *o_sf,
1042 	int *mapping, int emptypos, int cnt) {
1043     int extras, doit, i;
1044     EncMap *map = fv->map;
1045     int base = map->enccount;
1046 
1047     base = map->enccount;
1048 
1049     for ( doit=0; doit<2; ++doit ) {
1050 	extras = 0;
1051 	for ( i=0; i<o_sf->glyphcnt; ++i ) if ( mapping[i]>=emptypos ) {
1052 	    int index = SFFindSlot(into,map,o_sf->glyphs[i]->unicodeenc,o_sf->glyphs[i]->name);
1053 	    if ( !doit ) {
1054 		if ( index==-1 )
1055 		    ++extras;
1056 	    } else {
1057 		if ( index==-1 )
1058 		    index = base+ extras++;
1059 		map->map[index] = mapping[i];
1060 		map->backmap[mapping[i]] = index;
1061 	    }
1062 	}
1063 	if ( !doit ) {
1064 	    if ( into->glyphcnt+cnt>map->backmax ) {
1065 		map->backmap = realloc(map->backmap,(into->glyphcnt+cnt)*sizeof(int));
1066 		map->backmax = into->glyphcnt+cnt;
1067 	    }
1068 	    memset(map->backmap+into->glyphcnt,-1,cnt*sizeof(int));
1069 	    if ( map->enccount+extras>map->encmax ) {
1070 		map->map = realloc(map->map,(map->enccount+extras)*sizeof(int));
1071 		map->encmax = map->enccount+extras;
1072 	    }
1073 	    memset(map->map+map->enccount,-1,extras*sizeof(int));
1074 	    map->enccount += extras;
1075 	}
1076     }
1077     if ( extras!=0 ) {
1078 	fv->selected = realloc(fv->selected,map->enccount);
1079 	memset(fv->selected+map->enccount-extras,0,extras);
1080     }
1081 }
1082 
_MergeFont(SplineFont * into,SplineFont * other,struct sfmergecontext * mc)1083 static void _MergeFont(SplineFont *into,SplineFont *other,struct sfmergecontext *mc) {
1084     int i, cnt, doit, emptypos, index, k;
1085     SplineFont *bitmap_into;
1086     BDFFont *bdf;
1087     FontViewBase *fvs;
1088     int *mapping;
1089 
1090     emptypos = into->glyphcnt;
1091 
1092     mapping = malloc(other->glyphcnt*sizeof(int));
1093     memset(mapping,-1,other->glyphcnt*sizeof(int));
1094 
1095     bitmap_into = into->cidmaster!=NULL? into->cidmaster : into;
1096 
1097     /* If other starts as CID it should be flattened before calling */
1098     cnt = 0;
1099     for ( doit=0; doit<2; ++doit ) {
1100 	for ( i=0; i<other->glyphcnt; ++i ) if ( other->glyphs[i]!=NULL ) {
1101 	    if ( doit && (index = mapping[i])!=-1 ) {
1102 		/* Bug here. Suppose someone has a reference to our empty */
1103 		/*  char */
1104 		SplineCharFree(into->glyphs[index]);
1105 		into->glyphs[index] = SplineCharCopy(other->glyphs[i],into,mc);
1106 		into->glyphs[index]->orig_pos = index;
1107 		if ( into->bitmaps!=NULL && other->bitmaps!=NULL )
1108 		    BitmapsCopy(bitmap_into,other,index,i);
1109 	    } else if ( !doit ) {
1110 		if ( !SCWorthOutputting(other->glyphs[i] ))
1111 		    /* Don't bother to copy it */;
1112 		else if ( !SFHasChar(into,other->glyphs[i]->unicodeenc,other->glyphs[i]->name)) {
1113 		    /* Possible for a font to contain a glyph not worth outputting */
1114 		    if ( (index = _SFFindExistingSlot(into,other->glyphs[i]->unicodeenc,other->glyphs[i]->name))==-1 )
1115 			index = emptypos+cnt++;
1116 		    mapping[i] = index;
1117 		}
1118 	    }
1119 	}
1120 	if ( !doit ) {
1121 	    if ( emptypos+cnt >= into->glyphcnt && emptypos+cnt>0 ) {
1122 		into->glyphs = realloc(into->glyphs,(emptypos+cnt)*sizeof(SplineChar *));
1123 		memset(into->glyphs+emptypos,0,cnt*sizeof(SplineChar *));
1124 		for ( bdf = bitmap_into->bitmaps; bdf!=NULL; bdf=bdf->next )
1125 		    if ( emptypos+cnt > bdf->glyphcnt ) {
1126 			bdf->glyphs = realloc(bdf->glyphs,(emptypos+cnt)*sizeof(BDFChar *));
1127 			memset(bdf->glyphs+emptypos,0,cnt*sizeof(BDFChar *));
1128 			bdf->glyphmax = bdf->glyphcnt = emptypos+cnt;
1129 		    }
1130 		for ( fvs = into->fv; fvs!=NULL; fvs=fvs->nextsame )
1131 		    FVBiggerGlyphCache(fvs,emptypos+cnt);
1132 		for ( fvs = into->fv; fvs!=NULL; fvs=fvs->nextsame )
1133 		    if ( fvs->sf == into )
1134 			FVMergeRefigureMapSel(fvs,into,other,mapping,emptypos,cnt);
1135 		into->glyphcnt = into->glyphmax = emptypos+cnt;
1136 	    }
1137 	}
1138     }
1139     for ( i=0; i<other->glyphcnt; ++i ) {
1140 	if ( (index=mapping[i])!=-1 )
1141 	    into->glyphs[index]->kerns = KernsCopy(other->glyphs[i]->kerns,mapping,into,mc);
1142 	else if ( mc->preserveCrossFontKerning && other->glyphs[i]!=NULL ) {
1143 	    KernPair *kpnew, *kpend;
1144 	    index = _SFFindExistingSlot(into,other->glyphs[i]->unicodeenc,other->glyphs[i]->name);
1145 	    if ( index!=-1 ) {
1146 		mc->preserveCrossFontKerning = false;
1147 		kpnew = KernsCopy(other->glyphs[i]->kerns,mapping,into,mc);
1148 		mc->preserveCrossFontKerning = true;
1149 		if ( kpnew ) {
1150 		    for ( kpend=kpnew; kpend->next!=NULL; kpend=kpend->next );
1151 		    kpend->next = into->glyphs[index]->kerns;
1152 		    into->glyphs[index]->kerns = kpnew;
1153 		}
1154 	    }
1155 	}
1156     }
1157 
1158     free(mapping);
1159     GlyphHashFree(into);
1160     MergeFixupRefChars(into);
1161     if ( other->fv==NULL )
1162 	SplineFontFree(other);
1163     into->changed = true;
1164     FontViewReformatAll(into);
1165     GlyphHashFree(into);
1166 }
1167 
__MergeFont(SplineFont * into,SplineFont * other,int preserveCrossFontKerning)1168 static void __MergeFont(SplineFont *into,SplineFont *other, int preserveCrossFontKerning) {
1169     struct sfmergecontext mc;
1170 
1171     memset(&mc,0,sizeof(mc));
1172     mc.sf_from = other; mc.sf_to = into;
1173     mc.preserveCrossFontKerning = preserveCrossFontKerning;
1174 
1175     AnchorClassesAdd(into,other,&mc);
1176     FPSTsAdd(into,other,&mc);
1177     ASMsAdd(into,other,&mc);
1178     KernClassesAdd(into,other,&mc);
1179 
1180     _MergeFont(into,other,&mc);
1181 
1182     SFFinishMergeContext(&mc);
1183 }
1184 
CIDMergeFont(SplineFont * into,SplineFont * other,int preserveCrossFontKerning)1185 static void CIDMergeFont(SplineFont *into,SplineFont *other, int preserveCrossFontKerning) {
1186     int i,j,k;
1187     SplineFont *i_sf, *o_sf;
1188     FontViewBase *fvs;
1189     struct sfmergecontext mc;
1190 
1191     memset(&mc,0,sizeof(mc));
1192     mc.sf_from = other; mc.sf_to = into;
1193     mc.preserveCrossFontKerning = preserveCrossFontKerning;
1194 
1195     AnchorClassesAdd(into,other,&mc);
1196     FPSTsAdd(into,other,&mc);
1197     ASMsAdd(into,other,&mc);
1198     KernClassesAdd(into,other,&mc);
1199 
1200     k = 0;
1201     do {
1202 	o_sf = other->subfonts[k];
1203 	i_sf = into->subfonts[k];
1204 	for ( i=o_sf->glyphcnt-1; i>=0 && o_sf->glyphs[i]==NULL; --i );
1205 	if ( i>=i_sf->glyphcnt ) {
1206 	    i_sf->glyphs = realloc(i_sf->glyphs,(i+1)*sizeof(SplineChar *));
1207 	    for ( j=i_sf->glyphcnt; j<=i; ++j )
1208 		i_sf->glyphs[j] = NULL;
1209 	    for ( fvs = i_sf->fv; fvs!=NULL; fvs=fvs->nextsame )
1210 		if ( fvs->sf==i_sf ) {
1211 		    fvs->selected = realloc(fvs->selected,i+1);
1212 		    for ( j=i_sf->glyphcnt; j<=i; ++j )
1213 			fvs->selected[j] = false;
1214 		}
1215 	    i_sf->glyphcnt = i_sf->glyphmax = i+1;
1216 	}
1217 	for ( i=0; i<o_sf->glyphcnt; ++i ) if ( o_sf->glyphs[i]!=NULL ) {
1218 	    if ( o_sf->glyphs[i]->layers[ly_fore].splines==NULL && o_sf->glyphs[i]->layers[ly_fore].refs==NULL &&
1219 		    !o_sf->glyphs[i]->widthset )
1220 		/* Don't bother to copy it */;
1221 	    else if ( SFHasCID(into,i)==-1 ) {
1222 		SplineCharFree(i_sf->glyphs[i]);
1223 		i_sf->glyphs[i] = SplineCharCopy(o_sf->glyphs[i],i_sf,&mc);
1224 		i_sf->glyphs[i]->orig_pos = i;
1225 		if ( into->bitmaps!=NULL && other->bitmaps!=NULL )
1226 		    BitmapsCopy(into,other,i,i);
1227 	    }
1228 	}
1229 	MergeFixupRefChars(i_sf);
1230 	++k;
1231     } while ( k<other->subfontcnt );
1232     FontViewReformatAll(into);
1233     into->changed = true;
1234     GlyphHashFree(into);
1235 
1236     SFFinishMergeContext(&mc);
1237 }
1238 
MergeFont(FontViewBase * fv,SplineFont * other,int preserveCrossFontKerning)1239 void MergeFont(FontViewBase *fv,SplineFont *other, int preserveCrossFontKerning) {
1240 
1241     if ( fv->sf==other ) {
1242 	ff_post_error(_("Merging Problem"),_("Merging a font with itself achieves nothing"));
1243 return;
1244     }
1245     if ( fv->sf->cidmaster!=NULL && other->subfonts!=NULL &&
1246 	    (strcmp(fv->sf->cidmaster->cidregistry,other->cidregistry)!=0 ||
1247 	     strcmp(fv->sf->cidmaster->ordering,other->ordering)!=0 ||
1248 	     fv->sf->cidmaster->supplement<other->supplement ||
1249 	     fv->sf->cidmaster->subfontcnt<other->subfontcnt )) {
1250 	ff_post_error(_("Merging Problem"),_("When merging two CID keyed fonts, they must have the same Registry and Ordering, and the font being merged into (the mergee) must have a supplement which is at least as recent as the other's. Furthermore the mergee must have at least as many subfonts as the merger."));
1251 return;
1252     }
1253     /* Ok. when merging CID fonts... */
1254     /*  If fv is normal and other is CID then just flatten other and merge everything into fv */
1255     /*  If fv is CID and other is normal then merge other into the currently active font */
1256     /*  If both are CID then merge each subfont separately */
1257     if ( fv->sf->cidmaster!=NULL && other->subfonts!=NULL )
1258 	CIDMergeFont(fv->sf->cidmaster,other,preserveCrossFontKerning);
1259     else {
1260 	if (other->subfonts!=NULL)
1261 	    SFFlatten(&other); /* Non-corrupting because other is freed in _MergeFont() */
1262 	__MergeFont(fv->sf,other,preserveCrossFontKerning);
1263     }
1264 }
1265 
1266 /******************************************************************************/
1267 /* *************************** Font Interpolation *************************** */
1268 /******************************************************************************/
1269 
InterpRefs(RefChar * base,RefChar * other,real amount,SplineChar * sc)1270 static RefChar *InterpRefs(RefChar *base, RefChar *other, real amount, SplineChar *sc) {
1271     RefChar *head=NULL, *last=NULL, *cur;
1272     RefChar *test;
1273     int i;
1274 
1275     for ( test = other; test!=NULL; test=test->next )
1276 	test->checked = false;
1277 
1278     while ( base!=NULL ) {
1279 	for ( test = other; test!=NULL; test=test->next ) {
1280 	    if ( test->checked )
1281 		/* Do nothing */;
1282 	    else if ( test->unicode_enc==base->unicode_enc &&
1283 		    (test->unicode_enc!=-1 || strcmp(test->sc->name,base->sc->name)==0 ) )
1284 	break;
1285 	}
1286 	if ( test!=NULL ) {
1287 	    test->checked = true;
1288 	    cur = RefCharCreate();
1289 	    free(cur->layers);
1290 	    *cur = *base;
1291 	    cur->orig_pos = cur->sc->orig_pos;
1292 	    for ( i=0; i<6; ++i )
1293 		cur->transform[i] = base->transform[i] + amount*(other->transform[i]-base->transform[i]);
1294 	    cur->layers = NULL;
1295 	    cur->layer_cnt = 0;
1296 	    cur->checked = false;
1297 	    if ( head==NULL )
1298 		head = cur;
1299 	    else
1300 		last->next = cur;
1301 	    last = cur;
1302 	} else
1303 	    LogError( _("In character %s, could not find reference to %s\n"),
1304 		    sc->name, base->sc->name );
1305 	base = base->next;
1306 	if ( test==other && other!=NULL )
1307 	    other = other->next;
1308     }
1309 return( head );
1310 }
1311 
InterpPoint(SplineSet * cur,SplinePoint * base,SplinePoint * other,real amount)1312 static void InterpPoint(SplineSet *cur, SplinePoint *base, SplinePoint *other, real amount ) {
1313     SplinePoint *p = chunkalloc(sizeof(SplinePoint));
1314     int order2 = base->prev!=NULL ? base->prev->order2 : base->next!=NULL ? base->next->order2 : false;
1315 
1316     p->me.x = base->me.x + amount*(other->me.x-base->me.x);
1317     p->me.y = base->me.y + amount*(other->me.y-base->me.y);
1318     if ( order2 && base->prev!=NULL && (base->prev->islinear || other->prev->islinear ))
1319 	p->prevcp = p->me;
1320     else {
1321 	p->prevcp.x = base->prevcp.x + amount*(other->prevcp.x-base->prevcp.x);
1322 	p->prevcp.y = base->prevcp.y + amount*(other->prevcp.y-base->prevcp.y);
1323 	if ( order2 && cur->first!=NULL ) {
1324 	    /* In the normal course of events this isn't needed, but if we have */
1325 	    /*  a different number of points on one path than on the other then */
1326 	    /*  all hell breaks lose without this */
1327 	    cur->last->nextcp.x = p->prevcp.x = (cur->last->nextcp.x+p->prevcp.x)/2;
1328 	    cur->last->nextcp.y = p->prevcp.y = (cur->last->nextcp.y+p->prevcp.y)/2;
1329 	}
1330     }
1331     if ( order2 && base->next!=NULL && (base->next->islinear || other->next->islinear ))
1332 	p->nextcp = p->me;
1333     else {
1334 	p->nextcp.x = base->nextcp.x + amount*(other->nextcp.x-base->nextcp.x);
1335 	p->nextcp.y = base->nextcp.y + amount*(other->nextcp.y-base->nextcp.y);
1336     }
1337     p->nonextcp = ( p->nextcp.x==p->me.x && p->nextcp.y==p->me.y );
1338     p->noprevcp = ( p->prevcp.x==p->me.x && p->prevcp.y==p->me.y );
1339     p->prevcpdef = base->prevcpdef && other->prevcpdef;
1340     p->nextcpdef = base->nextcpdef && other->nextcpdef;
1341     p->selected = false;
1342     p->pointtype = (base->pointtype==other->pointtype)?base->pointtype:pt_corner;
1343     /*p->flex = 0;*/
1344     if ( cur->first==NULL ) {
1345 	cur->first = p;
1346 	cur->start_offset = 0;
1347     } else
1348 	SplineMake(cur->last,p,order2);
1349     cur->last = p;
1350 }
1351 
InterpSplineSet(SplineSet * base,SplineSet * other,real amount,SplineChar * sc)1352 static SplineSet *InterpSplineSet(SplineSet *base, SplineSet *other, real amount, SplineChar *sc) {
1353     SplineSet *cur = chunkalloc(sizeof(SplineSet));
1354     SplinePoint *bp, *op;
1355 
1356     for ( bp=base->first, op = other->first; ; ) {
1357 	InterpPoint(cur,bp,op,amount);
1358 	if ( bp->next == NULL && op->next == NULL )
1359 return( cur );
1360 	if ( bp->next!=NULL && op->next!=NULL &&
1361 		bp->next->to==base->first && op->next->to==other->first ) {
1362 	    SplineMake(cur->last,cur->first,bp->next->order2);
1363 	    cur->last = cur->first;
1364 return( cur );
1365 	}
1366 	if ( bp->next == NULL || bp->next->to==base->first ) {
1367 	    LogError( _("In character %s, there are too few points on a path in the base\n"), sc->name);
1368 	    if ( bp->next!=NULL ) {
1369 		if ( bp->next->order2 ) {
1370 		    cur->last->nextcp.x = cur->first->prevcp.x = (cur->last->nextcp.x+cur->first->prevcp.x)/2;
1371 		    cur->last->nextcp.y = cur->first->prevcp.y = (cur->last->nextcp.y+cur->first->prevcp.y)/2;
1372 		}
1373 		SplineMake(cur->last,cur->first,bp->next->order2);
1374 		cur->last = cur->first;
1375 	    }
1376 return( cur );
1377 	} else if ( op->next==NULL || op->next->to==other->first ) {
1378 	    LogError( _("In character %s, there are too many points on a path in the base\n"), sc->name);
1379 	    while ( bp->next!=NULL && bp->next->to!=base->first ) {
1380 		bp = bp->next->to;
1381 		InterpPoint(cur,bp,op,amount);
1382 	    }
1383 	    if ( bp->next!=NULL ) {
1384 		if ( bp->next->order2 ) {
1385 		    cur->last->nextcp.x = cur->first->prevcp.x = (cur->last->nextcp.x+cur->first->prevcp.x)/2;
1386 		    cur->last->nextcp.y = cur->first->prevcp.y = (cur->last->nextcp.y+cur->first->prevcp.y)/2;
1387 		}
1388 		SplineMake(cur->last,cur->first,bp->next->order2);
1389 		cur->last = cur->first;
1390 	    }
1391 return( cur );
1392 	}
1393 	bp = bp->next->to;
1394 	op = op->next->to;
1395     }
1396 }
1397 
SplineSetsInterpolate(SplineSet * base,SplineSet * other,real amount,SplineChar * sc)1398 SplineSet *SplineSetsInterpolate(SplineSet *base, SplineSet *other, real amount, SplineChar *sc) {
1399     SplineSet *head=NULL, *last=NULL, *cur;
1400 
1401     /* we could do something really complex to try and figure out which spline*/
1402     /*  set goes with which, but I'm not sure that it would really accomplish */
1403     /*  much, if things are off the computer probably won't figure it out */
1404     /* Could use path open/closed, direction, point count */
1405     while ( base!=NULL && other!=NULL ) {
1406 	cur = InterpSplineSet(base,other,amount,sc);
1407 	if ( head==NULL )
1408 	    head = cur;
1409 	else
1410 	    last->next = cur;
1411 	last = cur;
1412 	base = base->next;
1413 	other = other->next;
1414     }
1415 return( head );
1416 }
1417 
SCSameChar(SplineChar * sc1,SplineChar * sc2)1418 static int SCSameChar(SplineChar *sc1,SplineChar *sc2) {
1419     if ( sc1->unicodeenc!=-1 )
1420 return( sc1->unicodeenc==sc2->unicodeenc );
1421 
1422 return( strcmp(sc1->name,sc2->name)==0 );
1423 }
1424 
InterpKerns(KernPair * kp1,KernPair * kp2,real amount,SplineFont * new,SplineChar * scnew)1425 static KernPair *InterpKerns(KernPair *kp1, KernPair *kp2, real amount,
1426 	SplineFont *new, SplineChar *scnew) {
1427     KernPair *head=NULL, *last, *nkp, *k;
1428 
1429     if ( kp1==NULL || kp2==NULL )
1430 return( NULL );
1431     while ( kp1!=NULL ) {
1432 	for ( k=kp2; k!=NULL && !SCSameChar(k->sc,kp1->sc); k=k->next );
1433 	if ( k!=NULL ) {
1434 	    if ( k==kp2 ) kp2 = kp2->next;
1435 	    nkp = chunkalloc(sizeof(KernPair));
1436 	    nkp->sc = new->glyphs[kp1->sc->orig_pos];
1437 	    nkp->off = kp1->off + amount*(k->off-kp1->off);
1438 	    nkp->subtable = SFSubTableFindOrMake(new,CHR('k','e','r','n'),
1439 		    SCScriptFromUnicode(scnew),gpos_pair);
1440 	    if ( head==NULL )
1441 		head = nkp;
1442 	    else
1443 		last->next = nkp;
1444 	    last = nkp;
1445 	}
1446 	kp1 = kp1->next;
1447     }
1448 return( head );
1449 }
1450 
InterpColor(uint32 col1,uint32 col2,real amount)1451 static uint32 InterpColor( uint32 col1,uint32 col2, real amount ) {
1452     int r1, g1, b1, r2, b2, g2;
1453 
1454     r1 = (col1>>16)&0xff;
1455     r2 = (col2>>16)&0xff;
1456     g1 = (col1>>8 )&0xff;
1457     g2 = (col2>>8 )&0xff;
1458     b1 = (col1    )&0xff;
1459     b2 = (col2    )&0xff;
1460     r1 += amount * (r2-r1);
1461     g1 += amount * (g2-g1);
1462     b1 += amount * (b2-b1);
1463 return( (r1<<16) | (g1<<8) | b1 );
1464 }
1465 
LayerInterpolate(Layer * to,Layer * base,Layer * other,real amount,SplineChar * sc,int lc)1466 static void LayerInterpolate(Layer *to,Layer *base,Layer *other,real amount,SplineChar *sc, int lc) {
1467 
1468     /* to already has things set to default values, so when an error occurs */
1469     /*  I just leave things as the default (and don't need to set it again) */
1470     if ( base->dostroke==other->dostroke )
1471 	to->dostroke = base->dostroke;
1472     else
1473 	LogError( _("Different settings on whether to stroke in layer %d of %s\n"), lc, sc->name );
1474     if ( base->dofill==other->dofill )
1475 	to->dofill = base->dofill;
1476     else
1477 	LogError(_("Different settings on whether to fill in layer %d of %s\n"), lc, sc->name );
1478     if ( base->fill_brush.col==COLOR_INHERITED && other->fill_brush.col==COLOR_INHERITED )
1479 	to->fill_brush.col = COLOR_INHERITED;
1480     else if ( base->fill_brush.col!=COLOR_INHERITED && other->fill_brush.col!=COLOR_INHERITED )
1481 	to->fill_brush.col = InterpColor( base->fill_brush.col,other->fill_brush.col, amount );
1482     else
1483 	LogError(_("Different settings on whether to inherit fill color in layer %d of %s\n"), lc, sc->name );
1484     if ( base->fill_brush.opacity<0 && other->fill_brush.opacity<0 )
1485 	to->fill_brush.opacity = WIDTH_INHERITED;
1486     else if ( base->fill_brush.opacity>=0 && other->fill_brush.opacity>=0 )
1487 	to->fill_brush.opacity = base->fill_brush.opacity + amount*(other->fill_brush.opacity-base->fill_brush.opacity);
1488     else
1489 	LogError(_("Different settings on whether to inherit fill opacity in layer %d of %s\n"), lc, sc->name );
1490     if ( base->stroke_pen.brush.col==COLOR_INHERITED && other->stroke_pen.brush.col==COLOR_INHERITED )
1491 	to->stroke_pen.brush.col = COLOR_INHERITED;
1492     else if ( base->stroke_pen.brush.col!=COLOR_INHERITED && other->stroke_pen.brush.col!=COLOR_INHERITED )
1493 	to->stroke_pen.brush.col = InterpColor( base->stroke_pen.brush.col,other->stroke_pen.brush.col, amount );
1494     else
1495 	LogError(_("Different settings on whether to inherit fill color in layer %d of %s\n"), lc, sc->name );
1496     if ( base->stroke_pen.brush.opacity<0 && other->stroke_pen.brush.opacity<0 )
1497 	to->stroke_pen.brush.opacity = WIDTH_INHERITED;
1498     else if ( base->stroke_pen.brush.opacity>=0 && other->stroke_pen.brush.opacity>=0 )
1499 	to->stroke_pen.brush.opacity = base->stroke_pen.brush.opacity + amount*(other->stroke_pen.brush.opacity-base->stroke_pen.brush.opacity);
1500     else
1501 	LogError(_("Different settings on whether to inherit stroke opacity in layer %d of %s\n"), lc, sc->name );
1502     if ( base->stroke_pen.width<0 && other->stroke_pen.width<0 )
1503 	to->stroke_pen.width = WIDTH_INHERITED;
1504     else if ( base->stroke_pen.width>=0 && other->stroke_pen.width>=0 )
1505 	to->stroke_pen.width = base->stroke_pen.width + amount*(other->stroke_pen.width-base->stroke_pen.width);
1506     else
1507 	LogError(_("Different settings on whether to inherit stroke width in layer %d of %s\n"), lc, sc->name );
1508     if ( base->stroke_pen.linecap==other->stroke_pen.linecap )
1509 	to->stroke_pen.linecap = base->stroke_pen.linecap;
1510     else
1511 	LogError(_("Different settings on stroke linecap in layer %d of %s\n"), lc, sc->name );
1512     if ( base->stroke_pen.linejoin==other->stroke_pen.linejoin )
1513 	to->stroke_pen.linejoin = base->stroke_pen.linejoin;
1514     else
1515 	LogError(_("Different settings on stroke linejoin in layer %d of %s\n"), lc, sc->name );
1516     if ( base->fill_brush.gradient!=NULL || other->fill_brush.gradient!=NULL ||
1517 	    base->stroke_pen.brush.gradient!=NULL || other->stroke_pen.brush.gradient!=NULL )
1518 	LogError(_("I can't even imagine how to attempt to interpolate gradients in layer %d of %s\n"), lc, sc->name );
1519     if ( base->fill_brush.pattern!=NULL || other->fill_brush.pattern!=NULL )
1520 	LogError(_("Different fill patterns in layer %d of %s\n"), lc, sc->name );
1521     if ( base->stroke_pen.brush.pattern!=NULL || other->stroke_pen.brush.pattern!=NULL )
1522 	LogError(_("Different stroke patterns in layer %d of %s\n"), lc, sc->name );
1523 
1524     to->splines = SplineSetsInterpolate(base->splines,other->splines,amount,sc);
1525     to->refs = InterpRefs(base->refs,other->refs,amount,sc);
1526     if ( base->images!=NULL || other->images!=NULL )
1527 	LogError(_("I can't even imagine how to attempt to interpolate images in layer %d of %s\n"), lc, sc->name );
1528 }
1529 
SplineCharInterpolate(SplineChar * base,SplineChar * other,real amount,SplineFont * newfont)1530 SplineChar *SplineCharInterpolate(SplineChar *base, SplineChar *other,
1531 	real amount, SplineFont *newfont) {
1532     SplineChar *sc;
1533     int i;
1534 
1535     if ( base==NULL || other==NULL )
1536 return( NULL );
1537     sc = SFSplineCharCreate(newfont);
1538     sc->unicodeenc = base->unicodeenc;
1539     sc->changed = true;
1540     sc->views = NULL;
1541     sc->dependents = NULL;
1542     sc->layers[ly_back].splines = NULL;
1543     sc->layers[ly_back].images = NULL;
1544     sc->layers[ly_fore].undoes = sc->layers[ly_back].undoes = NULL;
1545     sc->layers[ly_fore].redoes = sc->layers[ly_back].redoes = NULL;
1546     sc->kerns = NULL;
1547     sc->name = copy(base->name);
1548     sc->width = base->width + amount*(other->width-base->width);
1549     sc->vwidth = base->vwidth + amount*(other->vwidth-base->vwidth);
1550     sc->lsidebearing = base->lsidebearing + amount*(other->lsidebearing-base->lsidebearing);
1551     if ( base->parent->multilayer && other->parent->multilayer ) {
1552 	int lc = base->layer_cnt;
1553 	if ( lc!=other->layer_cnt ) {
1554 	    LogError(_("Different numbers of layers in %s\n"), base->name );
1555 	    if ( other->layer_cnt<lc ) lc = other->layer_cnt;
1556 	}
1557 	if ( lc>2 ) {
1558 	    sc->layers = realloc(sc->layers,lc*sizeof(Layer));
1559 	    for ( i=ly_fore+1; i<lc; ++i )
1560 		LayerDefault(&sc->layers[i]);
1561 	}
1562 	for ( i=ly_fore; i<lc; ++i )
1563 	    LayerInterpolate(&sc->layers[i],&base->layers[i],&other->layers[i],amount,sc,i);
1564     } else {
1565 	for ( i=0; i<sc->layer_cnt; ++i ) {
1566 	    if ( i>=base->layer_cnt || i>= other->layer_cnt )
1567 	break;
1568 	    sc->layers[i].splines = SplineSetsInterpolate(base->layers[i].splines,other->layers[i].splines,amount,sc);
1569 	    sc->layers[i].refs = InterpRefs(base->layers[i].refs,other->layers[i].refs,amount,sc);
1570 	}
1571     }
1572     sc->changedsincelasthinted = true;
1573     sc->widthset = base->widthset;
1574     sc->glyph_class = base->glyph_class;
1575 return( sc );
1576 }
1577 
_SplineCharInterpolate(SplineFont * new,int orig_pos,SplineChar * base,SplineChar * other,real amount)1578 static void _SplineCharInterpolate(SplineFont *new, int orig_pos, SplineChar *base, SplineChar *other, real amount) {
1579     SplineChar *sc;
1580 
1581     sc = SplineCharInterpolate(base,other,amount,new);
1582     if ( sc==NULL )
1583 return;
1584     sc->orig_pos = orig_pos;
1585     new->glyphs[orig_pos] = sc;
1586     if ( orig_pos+1>new->glyphcnt )
1587 	new->glyphcnt = orig_pos+1;
1588     sc->parent = new;
1589 }
1590 
IFixupSC(SplineFont * sf,SplineChar * sc,int i)1591 static void IFixupSC(SplineFont *sf, SplineChar *sc,int i) {
1592     RefChar *ref;
1593 
1594     for ( ref=sc->layers[ly_fore].refs; ref!=NULL; ref=ref->next ) if ( !ref->checked ) {
1595 	/* The sc in the ref is from the base font. It's got to be in the */
1596 	/*  new font too (the ref only gets created if it's present in both fonts)*/
1597 	ref->checked = true;
1598 	ref->orig_pos = SFFindExistingSlot(sf,ref->sc->unicodeenc,ref->sc->name);
1599 	ref->sc = sf->glyphs[ref->orig_pos];
1600 	IFixupSC(sf,ref->sc,ref->orig_pos);
1601 	SCReinstanciateRefChar(sc,ref,ly_fore);
1602 	SCMakeDependent(sc,ref->sc);
1603     }
1604 }
1605 
InterpFixupRefChars(SplineFont * sf)1606 static void InterpFixupRefChars(SplineFont *sf) {
1607     int i;
1608 
1609     for ( i=0; i<sf->glyphcnt; ++i ) if ( sf->glyphs[i]!=NULL ) {
1610 	IFixupSC(sf,sf->glyphs[i], i);
1611     }
1612 }
1613 
InterpolateFont(SplineFont * base,SplineFont * other,real amount,Encoding * enc)1614 SplineFont *InterpolateFont(SplineFont *base, SplineFont *other, real amount,
1615 	Encoding *enc) {
1616     SplineFont *new;
1617     int i, index, lc;
1618 
1619     if ( base==other ) {
1620 	ff_post_error(_("Interpolating Problem"),_("Interpolating a font with itself achieves nothing"));
1621 return( NULL );
1622     } else if ( base->layers[ly_fore].order2!=other->layers[ly_fore].order2 ) {
1623 	ff_post_error(_("Interpolating Problem"),_("Interpolating between fonts with different spline orders (i.e. between postscript and truetype)"));
1624 return( NULL );
1625     } else if ( base->multilayer && other->multilayer ) {
1626 	ff_post_error(_("Interpolating Problem"),_("Interpolating between fonts with different editing types (ie. between type3 and type1)"));
1627 return( NULL );
1628     }
1629     new = SplineFontBlank(base->glyphcnt);
1630     new->ascent = base->ascent + amount*(other->ascent-base->ascent);
1631     new->descent = base->descent + amount*(other->descent-base->descent);
1632     if ( (lc=base->layer_cnt)>other->layer_cnt )
1633 	lc = other->layer_cnt;
1634     if ( lc!=new->layer_cnt ) {
1635 	new->layer_cnt = lc;
1636 	new->layers = realloc(new->layers,lc*sizeof(LayerInfo));
1637 	if ( lc>2 )
1638 	    memset(new->layers+2,0,(lc-2)*sizeof(LayerInfo));
1639 	for ( i=2; i<lc; ++i ) {
1640 	    new->layers[i].name = copy(base->layers[i].name);
1641 	    new->layers[i].background = base->layers[i].background;
1642 	    new->layers[i].order2 = base->layers[i].order2;
1643 	}
1644     }
1645     for ( i=0; i<2; ++i ) {
1646 	new->layers[i].background = base->layers[i].background;
1647 	new->layers[i].order2 = base->layers[i].order2;
1648     }
1649     for ( i=0; i<base->glyphcnt; ++i ) if ( base->glyphs[i]!=NULL ) {
1650 	index = SFFindExistingSlot(other,base->glyphs[i]->unicodeenc,base->glyphs[i]->name);
1651 	if ( index!=-1 && other->glyphs[index]!=NULL ) {
1652 	    _SplineCharInterpolate(new,i,base->glyphs[i],other->glyphs[index],amount);
1653 	    if ( new->glyphs[i]!=NULL )
1654 		new->glyphs[i]->kerns = InterpKerns(base->glyphs[i]->kerns,
1655 			other->glyphs[index]->kerns,amount,new,new->glyphs[i]);
1656 	}
1657     }
1658     InterpFixupRefChars(new);
1659     new->changed = true;
1660     new->map = EncMapFromEncoding(new,enc);
1661 return( new );
1662 }
1663