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