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 "cvundoes.h"
31 
32 #include "autohint.h"
33 #include "basics.h"
34 #include "bitmapchar.h"
35 #include "bvedit.h"
36 #include "cvexport.h"
37 #include "cvimages.h"
38 #include "fontforgevw.h"
39 #include "fvfonts.h"
40 #include "gfile.h"
41 #include "namelist.h"
42 #include "psfont.h"
43 #include "sfd.h"
44 #include "spiro.h"
45 #include "splinefill.h"
46 #include "splineorder2.h"
47 #include "splineutil.h"
48 #include "splineutil2.h"
49 #include "svg.h"
50 #include "tottfgpos.h"
51 #include "ustring.h"
52 #include "utype.h"
53 #include "views.h"
54 
55 #include <math.h>
56 
57 #ifndef HAVE_EXECINFO_H
58 // no backtrace available
59 #else
60     #include <execinfo.h>
61 #endif
62 
63 extern char *coord_sep;
64 
65 int onlycopydisplayed = 0;
66 int copymetadata = 0;
67 int copyttfinstr = 0;
68 #if defined(__Mac)
69 int export_clipboard = 0;
70 #else
71 int export_clipboard = 1;
72 #endif
73 
74 
75 /* ********************************* Undoes ********************************* */
76 
77 int maxundoes = 120;		/* -1 is infinite */
78 int preserve_hint_undoes = true;
79 
bmpcopy(uint8 * bitmap,int bytes_per_line,int lines)80 static uint8 *bmpcopy(uint8 *bitmap,int bytes_per_line, int lines) {
81     uint8 *ret = malloc(bytes_per_line*lines);
82     memcpy(ret,bitmap,bytes_per_line*lines);
83 return( ret );
84 }
85 
RefCharsCopyState(SplineChar * sc,int layer)86 RefChar *RefCharsCopyState(SplineChar *sc,int layer) {
87     RefChar *head=NULL, *last=NULL, *new, *crefs;
88 
89     if ( layer<0 || sc->layers[layer].refs==NULL )
90 return( NULL );
91     for ( crefs = sc->layers[layer].refs; crefs!=NULL; crefs=crefs->next ) {
92 	new = RefCharCreate();
93 	free(new->layers);
94 	*new = *crefs;
95 	new->layers = calloc(new->layer_cnt,sizeof(struct reflayer));
96 	new->next = NULL;
97 	if ( last==NULL )
98 	    head = last = new;
99 	else {
100 	    last->next = new;
101 	    last = new;
102 	}
103     }
104 return( head );
105 }
106 
RefCharsCopyUnlinked(SplinePointList * sofar,SplineChar * sc,int layer)107 static SplinePointList *RefCharsCopyUnlinked(SplinePointList *sofar, SplineChar *sc,int layer) {
108     RefChar *crefs;
109     SplinePointList *last = NULL, *new;
110     int l;
111 
112     if ( layer<0 || sc->layers[layer].refs==NULL )
113 return( sofar );
114     if ( sofar!=NULL )
115 	for ( last=sofar; last->next!=NULL; last=last->next );
116     for ( crefs = sc->layers[layer].refs; crefs!=NULL; crefs=crefs->next ) {
117 	for ( l=0; l<crefs->layer_cnt; ++l ) {
118 	    new = SplinePointListCopy(crefs->layers[l].splines);
119 	    if ( sofar!=NULL ) {
120 		last->next = new;
121 		for ( ; last->next!=NULL; last=last->next );
122 	    } else {
123 		sofar = new;
124 		if ( new!=NULL )
125 		    for ( last=sofar; last->next!=NULL; last=last->next );
126 	    }
127 	}
128     }
129 return( sofar );
130 }
131 
RefCharsMatch(RefChar * urefs,RefChar * crefs)132 static int RefCharsMatch(RefChar *urefs,RefChar *crefs) {
133     /* I assume they are in the same order */
134     while ( urefs!=NULL && crefs!=NULL ) {
135 	if ( urefs->sc!=crefs->sc ||
136 		urefs->transform[0]!=crefs->transform[0] ||
137 		urefs->transform[1]!=crefs->transform[1] ||
138 		urefs->transform[2]!=crefs->transform[2] ||
139 		urefs->transform[3]!=crefs->transform[3] ||
140 		urefs->transform[4]!=crefs->transform[4] ||
141 		urefs->transform[5]!=crefs->transform[5] )
142 return( false );
143 	urefs = urefs->next;
144 	crefs = crefs->next;
145     }
146     if ( urefs==NULL && crefs==NULL )
147 return( true );
148 
149 return( false );
150 }
151 
ImagesMatch(ImageList * uimgs,ImageList * cimgs)152 static int ImagesMatch(ImageList *uimgs,ImageList *cimgs) {
153     /* I assume they are in the same order */
154     while ( uimgs!=NULL && cimgs!=NULL ) {
155 	if ( uimgs->image!=cimgs->image ||
156 		uimgs->xoff!=cimgs->xoff ||
157 		uimgs->yoff!=cimgs->yoff ||
158 		uimgs->xscale!=cimgs->xscale ||
159 		uimgs->yscale!=cimgs->yscale  )
160 return( false );
161 	uimgs = uimgs->next;
162 	cimgs = cimgs->next;
163     }
164     if ( uimgs==NULL && cimgs==NULL )
165 return( true );
166 
167 return( false );
168 }
169 
RefCharInList(RefChar * search,RefChar * list)170 static RefChar *RefCharInList(RefChar *search,RefChar *list) {
171     while ( list!=NULL ) {
172 	if ( search->sc==list->sc &&
173 		search->transform[0]==list->transform[0] &&
174 		search->transform[1]==list->transform[1] &&
175 		search->transform[2]==list->transform[2] &&
176 		search->transform[3]==list->transform[3] &&
177 		search->transform[4]==list->transform[4] &&
178 		search->transform[5]==list->transform[5] )
179 return( list );
180 	list = list->next;
181     }
182 return( NULL );
183 }
184 
ImageInList(ImageList * search,ImageList * list)185 static ImageList *ImageInList(ImageList *search,ImageList *list) {
186     while ( list!=NULL ) {
187 	if ( search->image!=list->image ||
188 		search->xoff!=list->xoff ||
189 		search->yoff!=list->yoff ||
190 		search->xscale!=list->xscale ||
191 		search->yscale!=list->yscale  )
192 return( list );
193 	list = list->next;
194     }
195 return( NULL );
196 }
197 
FixupRefChars(SplineChar * sc,RefChar * urefs,int layer)198 static void FixupRefChars(SplineChar *sc,RefChar *urefs,int layer) {
199     RefChar *crefs, *cend, *cprev, *unext, *cnext;
200 
201     if ( layer==ly_grid )
202 return;
203 
204     crefs = sc->layers[layer].refs;
205 
206     cprev = NULL;
207     while ( crefs!=NULL && urefs!=NULL ) {
208 	if ( urefs->sc==crefs->sc &&
209 		urefs->transform[0]==crefs->transform[0] &&
210 		urefs->transform[1]==crefs->transform[1] &&
211 		urefs->transform[2]==crefs->transform[2] &&
212 		urefs->transform[3]==crefs->transform[3] &&
213 		urefs->transform[4]==crefs->transform[4] &&
214 		urefs->transform[5]==crefs->transform[5] ) {
215 	    unext = urefs->next;
216 	    crefs->selected = urefs->selected;
217 	    RefCharFree(urefs);
218 	    urefs = unext;
219 	    cprev = crefs;
220 	    crefs = crefs->next;
221 	} else if ( (cend = RefCharInList(urefs,crefs->next))!=NULL ) {
222 	    /* if the undo refchar matches something further down the char's */
223 	    /*  ref list, then than means we need to delete everything on the */
224 	    /*  char's list between the two */
225 	    while ( crefs!=cend ) {
226 		cnext = crefs->next;
227 		SCRemoveDependent(sc,crefs,layer);
228 		crefs = cnext;
229 	    }
230 	} else { /* urefs isn't on the list. Add it here */
231 	    unext = urefs->next;
232 	    urefs->next = crefs;
233 	    if ( cprev==NULL )
234 		sc->layers[layer].refs = urefs;
235 	    else
236 		cprev->next = urefs;
237 	    cprev = urefs;
238 	    SCReinstanciateRefChar(sc,urefs,layer);
239 	    SCMakeDependent(sc,urefs->sc);
240 	    urefs = unext;
241 	}
242     }
243     if ( crefs!=NULL ) {
244 	while ( crefs!=NULL ) {
245 	    cnext = crefs->next;
246 	    SCRemoveDependent(sc,crefs,layer);
247 	    crefs = cnext;
248 	}
249     } else if ( urefs!=NULL ) {
250 	if ( cprev==NULL )
251 	    sc->layers[layer].refs = urefs;
252 	else
253 	    cprev->next = urefs;
254 	while ( urefs!=NULL ) {
255 	    SCReinstanciateRefChar(sc,urefs,layer);
256 	    SCMakeDependent(sc,urefs->sc);
257 	    urefs = urefs->next;
258 	}
259     }
260 }
261 
BDFRefCharsMatch(BDFRefChar * urefs,BDFRefChar * crefs)262 static int BDFRefCharsMatch(BDFRefChar *urefs,BDFRefChar *crefs) {
263     /* I assume they are in the same order */
264     while ( urefs!=NULL && crefs!=NULL ) {
265 	if ( urefs->bdfc != crefs->bdfc ||
266 		urefs->xoff != crefs->xoff ||
267 		urefs->yoff != crefs->yoff )
268 return( false );
269 	urefs = urefs->next;
270 	crefs = crefs->next;
271     }
272     if ( urefs==NULL && crefs==NULL )
273 return( true );
274 
275 return( false );
276 }
277 
BDFRefCharInList(BDFRefChar * search,BDFRefChar * list)278 static BDFRefChar *BDFRefCharInList( BDFRefChar *search,BDFRefChar *list ) {
279     while ( list!=NULL ) {
280 	if ( search->bdfc == list->bdfc &&
281 		search->xoff == list->xoff &&
282 		search->yoff == list->yoff )
283 return( list );
284 	list = list->next;
285     }
286 return( NULL );
287 }
288 
FixupBDFRefChars(BDFChar * bc,BDFRefChar * urefs)289 static void FixupBDFRefChars( BDFChar *bc,BDFRefChar *urefs ) {
290     BDFRefChar *crefs, *cend, *cprev, *unext, *cnext;
291 
292     crefs = bc->refs;
293     cprev = NULL;
294     while ( crefs!=NULL && urefs!=NULL ) {
295 	if ( urefs->bdfc == crefs->bdfc &&
296 		urefs->xoff == crefs->xoff &&
297 		urefs->yoff == crefs->yoff ) {
298 	    unext = urefs->next;
299 	    crefs->selected = urefs->selected;
300 	    free( urefs );
301 	    urefs = unext;
302 	    cprev = crefs;
303 	    crefs = crefs->next;
304 	} else if (( cend = BDFRefCharInList( urefs,crefs->next )) != NULL ) {
305 	    /* if the undo refchar matches something further down the char's */
306 	    /*  ref list, then that means we need to delete everything on the */
307 	    /*  char's list between the two */
308 	    while ( crefs != cend ) {
309 		cnext = crefs->next;
310 		BCRemoveDependent( bc,crefs );
311 		crefs = cnext;
312 	    }
313 	} else { /* urefs isn't on the list. Add it here */
314 	    unext = urefs->next;
315 	    urefs->next = crefs;
316 	    if ( cprev==NULL )
317 		bc->refs = urefs;
318 	    else
319 		cprev->next = urefs;
320 	    cprev = urefs;
321 	    BCMakeDependent( bc,urefs->bdfc );
322 	    urefs = unext;
323 	}
324     }
325     if ( crefs!=NULL ) {
326 	while ( crefs!=NULL ) {
327 	    cnext = crefs->next;
328 	    BCRemoveDependent( bc,crefs );
329 	    crefs = cnext;
330 	}
331     } else if ( urefs!=NULL ) {
332 	if ( cprev==NULL )
333 	    bc->refs = urefs;
334 	else
335 	    cprev->next = urefs;
336 	while ( urefs!=NULL ) {
337 	    BCMakeDependent( bc,urefs->bdfc );
338 	    urefs = urefs->next;
339 	}
340     }
341 }
342 
FixupImages(SplineChar * sc,ImageList * uimgs,int layer)343 static void FixupImages(SplineChar *sc,ImageList *uimgs,int layer) {
344     ImageList *cimgs = layer==-1 ? sc->parent->grid.images : sc->layers[layer].images,
345 	    *cend, *cprev, *unext, *cnext;
346 
347     cprev = NULL;
348     while ( cimgs!=NULL && uimgs!=NULL ) {
349 	if ( uimgs->image==cimgs->image &&
350 		uimgs->xoff==cimgs->xoff &&
351 		uimgs->yoff==cimgs->yoff &&
352 		uimgs->xscale==cimgs->xscale &&
353 		uimgs->yscale==cimgs->yscale  ) {
354 	    unext = uimgs->next;
355 	    cimgs->selected = uimgs->selected;
356 	    free(uimgs);
357 	    uimgs = unext;
358 	    cprev = cimgs;
359 	    cimgs = cimgs->next;
360 	} else if ( (cend = ImageInList(uimgs,cimgs->next))!=NULL ) {
361 	    /* if the undo image matches something further down the char's */
362 	    /*  img list, then than means we need to delete everything on the */
363 	    /*  char's list between the two */
364 	    if ( cprev==NULL )
365 		sc->layers[layer].images = cend;
366 	    else
367 		cprev->next = cend;
368 	    while ( cimgs!=cend ) {
369 		cnext = cimgs->next;
370 		free(cimgs);
371 		cimgs = cnext;
372 	    }
373 	} else { /* uimgs isn't on the list. Add it here */
374 	    unext = uimgs->next;
375 	    uimgs->next = cimgs;
376 	    if ( cprev==NULL )
377 		sc->layers[layer].images = uimgs;
378 	    else
379 		cprev->next = uimgs;
380 	    cprev = uimgs;
381 	    uimgs = unext;
382 	}
383     }
384     if ( cimgs!=NULL ) {
385 	ImageListsFree(cimgs);
386 	if ( cprev==NULL )
387 	    sc->layers[layer].images = NULL;
388 	else
389 	    cprev->next = NULL;
390     } else if ( uimgs!=NULL ) {
391 	if ( cprev==NULL )
392 	    sc->layers[layer].images = uimgs;
393 	else
394 	    cprev->next = uimgs;
395     }
396 }
397 
UHintListFree(void * hints)398 static void UHintListFree(void *hints) {
399     StemInfo *h, *t, *p;
400 
401     if ( hints==NULL )
402 return;
403     if ( ((StemInfo *) hints)->hinttype==ht_d )
404 	DStemInfosFree(hints);
405     else {
406 	h = t = hints;
407 	p = NULL;
408 	while ( t!=NULL && t->hinttype!=ht_d ) {
409 	    p = t;
410 	    t = t->next;
411 	}
412 	p->next = NULL;
413 	StemInfosFree(h);
414 	DStemInfosFree((DStemInfo *) t);
415     }
416 }
417 
UHintCopy(SplineChar * sc,int docopy)418 void *UHintCopy(SplineChar *sc,int docopy) {
419     StemInfo *h = sc->hstem, *v = sc->vstem, *last=NULL;
420     DStemInfo *d = sc->dstem;
421     void *ret = NULL;
422 
423     if ( docopy ) {
424 	h = StemInfoCopy(h);
425 	v = StemInfoCopy(v);
426 	d = DStemInfoCopy(d);
427     } else {
428 	sc->hstem = NULL;
429 	sc->vstem = NULL;
430 	sc->dstem = NULL;
431 	sc->hconflicts = sc->vconflicts = false;
432     }
433     ret = h;
434     if ( h!=NULL ) {
435 	h->hinttype = ht_h;
436 	for ( last=h; last->next!=NULL; last=last->next ) last->next->hinttype = ht_unspecified;
437 	last->next = v;
438     } else
439 	ret = v;
440     if ( v!=NULL ) {
441 	v->hinttype = ht_v;
442 	for ( last=v; last->next!=NULL; last=last->next ) last->next->hinttype = ht_unspecified;
443     }
444     if ( last!=NULL )
445 	last->next = (StemInfo *) d;
446     else
447 	ret = d;
448     if ( d!=NULL ) {
449 	d->hinttype = ht_d;
450 	for ( d=d->next; d!=NULL; d=d->next ) d->hinttype = ht_unspecified;
451     }
452 return(ret);
453 }
454 
ExtractHints(SplineChar * sc,void * hints,int docopy)455 void ExtractHints(SplineChar *sc,void *hints,int docopy) {
456     StemInfo *h = NULL, *v = NULL, *p;
457     DStemInfo *d = NULL;
458     StemInfo *pv = NULL, *pd = NULL;
459 
460     p = NULL;
461     while ( hints!=NULL ) {
462 	if ( ((StemInfo *) hints)->hinttype == ht_h )
463 	    h = hints;
464 	else if ( ((StemInfo *) hints)->hinttype == ht_v ) {
465 	    v = hints;
466 	    pv = p;
467 	} else if ( ((StemInfo *) hints)->hinttype == ht_d ) {
468 	    d = hints;
469 	    pd = p;
470     break;
471 	}
472 	p = hints;
473 	hints = ((StemInfo *) hints)->next;
474     }
475 
476     if ( pv!=NULL ) pv->next = NULL;
477     if ( pd!=NULL ) pd->next = NULL;
478     if ( docopy ) {
479 	h = StemInfoCopy(h);
480 	if ( pv!=NULL ) pv->next = v;
481 	v = StemInfoCopy(v);
482 	if ( pd!=NULL ) pd->next = (StemInfo *) d;
483 	d = DStemInfoCopy(d);
484     }
485 
486     StemInfosFree(sc->hstem);
487     StemInfosFree(sc->vstem);
488     DStemInfosFree(sc->dstem);
489     sc->hstem = h;
490     sc->vstem = v;
491     sc->dstem = d;
492     sc->hconflicts = StemInfoAnyOverlaps(h);
493     sc->vconflicts = StemInfoAnyOverlaps(v);
494 }
495 
UndoesFreeButRetainFirstN(Undoes ** undopp,int retainAmount)496 void UndoesFreeButRetainFirstN( Undoes** undopp, int retainAmount )
497 {
498     if( !undopp || !*undopp )
499         return;
500     Undoes* undo = *undopp;
501     // wipe them all will change the list header pointer too
502     if( !retainAmount ) {
503         UndoesFree( undo );
504         *undopp = 0;
505         return;
506     }
507 
508     Undoes* undoprev = undo;
509     for( ; retainAmount > 0 && undo ; retainAmount-- )
510     {
511         undoprev = undo;
512         undo = undo->next;
513     }
514     // not enough items to need to do a trim.
515     if( retainAmount > 0 )
516         return;
517 
518     // break off and free the tail
519     UndoesFree( undo );
520     undoprev->next = 0;
521 }
522 
523 
UndoesFree(Undoes * undo)524 void UndoesFree(Undoes *undo) {
525     Undoes *unext;
526     BDFRefChar *head, *next;
527 
528     while ( undo!=NULL ) {
529 	unext = undo->next;
530 	switch ( undo->undotype ) {
531 	  case ut_noop:
532 	  case ut_width: case ut_vwidth: case ut_lbearing: case ut_rbearing:
533 	    /* Nothing else to free */;
534 	  break;
535 	  case ut_state: case ut_tstate: case ut_statehint: case ut_statename:
536 	  case ut_hints: case ut_anchors: case ut_statelookup:
537 	    SplinePointListsFree(undo->u.state.splines);
538 	    RefCharsFree(undo->u.state.refs);
539 	    UHintListFree(undo->u.state.hints);
540 	    free(undo->u.state.instrs);
541 	    ImageListsFree(undo->u.state.images);
542 	    if ( undo->undotype==ut_statename ) {
543 		free( undo->u.state.charname );
544 		free( undo->u.state.comment );
545 		PSTFree( undo->u.state.possub );
546 	    }
547 	    AnchorPointsFree(undo->u.state.anchor);
548 	    GradientFree(undo->u.state.fill_brush.gradient);
549 	    PatternFree(undo->u.state.fill_brush.pattern);
550 	    GradientFree(undo->u.state.stroke_pen.brush.gradient);
551 	    PatternFree(undo->u.state.stroke_pen.brush.pattern);
552 	  break;
553 	  case ut_bitmap:
554 	    for ( head=undo->u.bmpstate.refs; head != NULL; ) {
555 		next = head->next; free( head ); head = next;
556 	    }
557 	    free(undo->u.bmpstate.bitmap);
558 	    BDFFloatFree(undo->u.bmpstate.selection);
559 	  break;
560 	  case ut_multiple: case ut_layers:
561 	    UndoesFree( undo->u.multiple.mult );
562 	  break;
563 	  case ut_composit:
564 	    UndoesFree(undo->u.composit.state);
565 	    UndoesFree(undo->u.composit.bitmaps);
566 	  break;
567 	  default:
568 	    IError( "Unknown undo type in UndoesFree: %d", undo->undotype );
569 	  break;
570 	}
571 	chunkfree(undo,sizeof(Undoes));
572 	undo = unext;
573     }
574 }
575 
AddUndo(Undoes * undo,Undoes ** uhead,Undoes ** rhead)576 static Undoes *AddUndo(Undoes *undo,Undoes **uhead,Undoes **rhead) {
577     int ucnt;
578     Undoes *u, *prev;
579 
580     UndoesFree(*rhead);
581     *rhead = NULL;
582     if ( maxundoes==0 ) maxundoes = 1;		/* Must be at least one or snap to breaks */
583     if ( maxundoes>0 ) {
584 	ucnt = 0;
585 	prev = NULL;
586 	for ( u= *uhead; u!=NULL; u=u->next ) {
587 	    if ( ++ucnt>=maxundoes )
588 	break;
589 	    prev = u;
590 	}
591 	if ( u!=NULL ) {
592 	    UndoesFree(u);
593 	    if ( prev!=NULL )
594 		prev->next = NULL;
595 	    else
596 		*uhead = NULL;
597 	}
598     }
599     undo->next = *uhead;
600     *uhead = undo;
601 
602     return( undo );
603 }
604 
CVAddUndo(CharViewBase * cv,Undoes * undo)605 static Undoes *CVAddUndo(CharViewBase *cv,Undoes *undo) {
606 
607     Undoes* ret = AddUndo( undo,
608 			   &cv->layerheads[cv->drawmode]->undoes,
609 			   &cv->layerheads[cv->drawmode]->redoes );
610 
611     return( ret );
612 }
613 
CVLayer(CharViewBase * cv)614 int CVLayer(CharViewBase *cv) {
615     if ( cv->drawmode==dm_grid )
616 return( ly_grid );
617 
618 return( cv->layerheads[cv->drawmode]-cv->sc->layers );
619 }
620 
CVPreserveState(CharViewBase * cv)621 Undoes *CVPreserveState(CharViewBase *cv) {
622     Undoes *undo;
623     int layer = CVLayer(cv);
624 
625 //    if (!quiet)
626 //        printf("CVPreserveState() no_windowing_ui:%d maxundoes:%d\n", no_windowing_ui, maxundoes );
627     if ( no_windowing_ui || maxundoes==0 )		/* No use for undoes in scripting */
628 return(NULL);
629 
630     undo = chunkalloc(sizeof(Undoes));
631 
632     undo->undotype = ut_state;
633     undo->was_modified = cv->sc->changed;
634     undo->was_order2 = cv->layerheads[cv->drawmode]->order2;
635     undo->u.state.width = cv->sc->width;
636     undo->u.state.vwidth = cv->sc->vwidth;
637     undo->u.state.splines = SplinePointListCopy(cv->layerheads[cv->drawmode]->splines);
638     undo->u.state.refs = RefCharsCopyState(cv->sc,layer);
639     if ( layer==ly_fore ) {
640 	undo->u.state.anchor = AnchorPointsCopy(cv->sc->anchor);
641     }
642     undo->u.state.images = ImageListCopy(cv->layerheads[cv->drawmode]->images);
643     BrushCopy(&undo->u.state.fill_brush,&cv->layerheads[cv->drawmode]->fill_brush,NULL);
644     PenCopy(&undo->u.state.stroke_pen,&cv->layerheads[cv->drawmode]->stroke_pen,NULL);
645     undo->u.state.dofill = cv->layerheads[cv->drawmode]->dofill;
646     undo->u.state.dostroke = cv->layerheads[cv->drawmode]->dostroke;
647     undo->u.state.fillfirst = cv->layerheads[cv->drawmode]->fillfirst;
648     undo->layer = cv->drawmode;
649 
650 return( CVAddUndo(cv,undo));
651 }
652 
CVPreserveStateHints(CharViewBase * cv)653 Undoes *CVPreserveStateHints(CharViewBase *cv) {
654     Undoes *undo = CVPreserveState(cv);
655     if ( CVLayer(cv)==ly_fore ) {
656 	undo->undotype = ut_statehint;
657 	undo->u.state.hints = UHintCopy(cv->sc,true);
658 	undo->u.state.instrs = (uint8*) copyn((char*) cv->sc->ttf_instrs, cv->sc->ttf_instrs_len);
659 	undo->u.state.instrs_len = cv->sc->ttf_instrs_len;
660     }
661 return( undo );
662 }
663 
SCPreserveHints(SplineChar * sc,int layer)664 Undoes *SCPreserveHints(SplineChar *sc,int layer) {
665     Undoes *undo;
666 
667     if ( layer<0 || layer>=sc->layer_cnt )
668         return( NULL );
669 
670     if ( no_windowing_ui || maxundoes==0 )		/* No use for undoes in scripting */
671 return(NULL);
672     if ( !preserve_hint_undoes )
673 return( NULL );
674 
675     undo = chunkalloc(sizeof(Undoes));
676 
677     undo->was_modified = sc->changed;
678     undo->undotype = ut_hints;
679     undo->u.state.hints = UHintCopy(sc,true);
680     undo->u.state.instrs = (uint8*) copyn((char *) sc->ttf_instrs, sc->ttf_instrs_len);
681     undo->u.state.instrs_len = sc->ttf_instrs_len;
682     undo->copied_from = sc->parent;
683 return( AddUndo(undo,&sc->layers[layer].undoes,&sc->layers[layer].redoes));
684 }
685 
686 /* This routine allows for undoes in scripting -- under controlled conditions */
_SCPreserveLayer(SplineChar * sc,int layer,int dohints)687 Undoes *_SCPreserveLayer(SplineChar *sc,int layer, int dohints) {
688     Undoes *undo;
689 
690     if ( maxundoes==0 )
691 return(NULL);
692 
693     if ( layer==ly_grid )
694 	layer = ly_fore;
695 
696     undo = chunkalloc(sizeof(Undoes));
697 
698     undo->undotype = ut_state;
699     undo->layer = dm_fore;
700     undo->was_modified = sc->changed;
701     undo->was_order2 = sc->layers[layer].order2;
702     undo->u.state.width = sc->width;
703     undo->u.state.vwidth = sc->vwidth;
704     undo->u.state.splines = SplinePointListCopy(sc->layers[layer].splines);
705     undo->u.state.refs = RefCharsCopyState(sc,layer);
706     if ( layer==ly_fore ) {
707 	undo->u.state.anchor = AnchorPointsCopy(sc->anchor);
708     }
709     if ( dohints ) {
710 	undo->undotype = ut_statehint;
711 	undo->u.state.hints = UHintCopy(sc,true);
712 	undo->u.state.instrs = (uint8 *) copyn((char *) sc->ttf_instrs, sc->ttf_instrs_len);
713 	undo->u.state.instrs_len = sc->ttf_instrs_len;
714 	if ( dohints==2 ) {
715 	    undo->undotype = ut_statename;
716 	    undo->u.state.unicodeenc = sc->unicodeenc;
717 	    undo->u.state.charname = copy(sc->name);
718 	    undo->u.state.comment = copy(sc->comment);
719 	    undo->u.state.possub = PSTCopy(sc->possub,sc,NULL);
720 	}
721     }
722     undo->u.state.images = ImageListCopy(sc->layers[layer].images);
723     BrushCopy(&undo->u.state.fill_brush,&sc->layers[layer].fill_brush,NULL);
724     PenCopy(&undo->u.state.stroke_pen,&sc->layers[layer].stroke_pen,NULL);
725     undo->u.state.dofill = sc->layers[layer].dofill;
726     undo->u.state.dostroke = sc->layers[layer].dostroke;
727     undo->u.state.fillfirst = sc->layers[layer].fillfirst;
728     undo->copied_from = sc->parent;
729 return( AddUndo(undo,&sc->layers[layer].undoes,&sc->layers[layer].redoes));
730 }
731 
732 /* This routine does not allow for undoes in scripting */
SCPreserveLayer(SplineChar * sc,int layer,int dohints)733 Undoes *SCPreserveLayer(SplineChar *sc,int layer, int dohints) {
734 
735     if ( no_windowing_ui || maxundoes==0 )		/* No use for undoes in scripting */
736 return(NULL);
737 return( _SCPreserveLayer(sc,layer,dohints));
738 }
739 
740 
SCPreserveState(SplineChar * sc,int dohints)741 Undoes *SCPreserveState(SplineChar *sc,int dohints) {
742     int i;
743 
744     if ( sc->parent->multilayer )
745 	for ( i=ly_fore+1; i<sc->layer_cnt; ++i )
746 	    SCPreserveLayer(sc,i,false);
747 
748     Undoes* ret = SCPreserveLayer( sc, ly_fore, dohints );
749     return( ret );
750 }
751 
SCPreserveBackground(SplineChar * sc)752 Undoes *SCPreserveBackground(SplineChar *sc) {
753 return( SCPreserveLayer(sc,ly_back,false));
754 }
755 
_SFPreserveGuide(SplineFont * sf)756 Undoes *_SFPreserveGuide(SplineFont *sf) {
757     Undoes *undo;
758 
759     undo = chunkalloc(sizeof(Undoes));
760 
761     undo->undotype = ut_state;
762     undo->was_modified = sf->changed;
763     undo->was_order2 = sf->grid.order2;
764     undo->u.state.splines = SplinePointListCopy(sf->grid.splines);
765     undo->u.state.images = ImageListCopy(sf->grid.images);
766     undo->u.state.fill_brush = sf->grid.fill_brush;
767     undo->u.state.stroke_pen = sf->grid.stroke_pen;
768     undo->u.state.dofill = sf->grid.dofill;
769     undo->u.state.dostroke = sf->grid.dostroke;
770     undo->u.state.fillfirst = sf->grid.fillfirst;
771     undo->copied_from = sf;
772 return( AddUndo(undo,&sf->grid.undoes,&sf->grid.redoes));
773 }
774 
SFPreserveGuide(SplineFont * sf)775 Undoes *SFPreserveGuide(SplineFont *sf) {
776     if ( no_windowing_ui || maxundoes==0 )             /* No use for undoes in scripting */
777 return(NULL);
778 return( _SFPreserveGuide(sf) );
779 }
780 
SCUndoSetLBearingChange(SplineChar * sc,int lbc)781 void SCUndoSetLBearingChange(SplineChar *sc,int lbc) {
782     Undoes *undo = sc->layers[ly_fore].undoes;
783 
784     if ( undo==NULL || undo->undotype != ut_state )
785 return;
786     undo->u.state.lbearingchange = lbc;
787 }
788 
_CVPreserveTState(CharViewBase * cv,PressedOn * p)789 Undoes *_CVPreserveTState(CharViewBase *cv,PressedOn *p) {
790     Undoes *undo;
791     RefChar *refs, *urefs;
792     int was0 = false, j;
793 
794     if ( maxundoes==0 ) {
795 	was0 = true;
796 	maxundoes = 1;
797     }
798 
799     undo = CVPreserveState(cv);
800     if ( !p->transany || p->transanyrefs ) {
801 	for ( refs = cv->layerheads[cv->drawmode]->refs, urefs=undo->u.state.refs; urefs!=NULL; refs=refs->next, urefs=urefs->next )
802 	    if ( !p->transany || refs->selected )
803 		for ( j=0; j<urefs->layer_cnt; ++j )
804 		    urefs->layers[j].splines = SplinePointListCopy(refs->layers[j].splines);
805     }
806     undo->undotype = ut_tstate;
807 
808     if ( was0 )
809 	maxundoes = 0;
810 
811 return( undo );
812 }
813 
CVPreserveWidth(CharViewBase * cv,int width)814 Undoes *CVPreserveWidth(CharViewBase *cv,int width) {
815     Undoes *undo;
816 
817     if ( no_windowing_ui || maxundoes==0 )		/* No use for undoes in scripting */
818 return(NULL);
819 
820     undo = chunkalloc(sizeof(Undoes));
821 
822     undo->undotype = ut_width;
823     undo->was_modified = cv->sc->changed;
824     undo->was_order2 = cv->layerheads[cv->drawmode]->order2;
825     undo->u.width = width;
826 return( CVAddUndo(cv,undo));
827 }
828 
CVPreserveVWidth(CharViewBase * cv,int vwidth)829 Undoes *CVPreserveVWidth(CharViewBase *cv,int vwidth) {
830     Undoes *undo;
831 
832     if ( no_windowing_ui || maxundoes==0 )		/* No use for undoes in scripting */
833 return(NULL);
834 
835     undo = chunkalloc(sizeof(Undoes));
836 
837     undo->undotype = ut_vwidth;
838     undo->was_modified = cv->sc->changed;
839     undo->was_order2 = cv->layerheads[cv->drawmode]->order2;
840     undo->u.width = vwidth;
841 return( CVAddUndo(cv,undo));
842 }
843 
SCPreserveWidth(SplineChar * sc)844 Undoes *SCPreserveWidth(SplineChar *sc) {
845     Undoes *undo;
846 
847     if ( no_windowing_ui || maxundoes==0 )		/* No use for undoes in scripting */
848 return(NULL);
849 
850     undo = chunkalloc(sizeof(Undoes));
851 
852     undo->undotype = ut_width;
853     undo->was_modified = sc->changed;
854     undo->was_order2 = sc->layers[ly_fore].order2;
855     undo->u.state.width = sc->width;
856     undo->layer = dm_fore;
857 
858     Undoes* ret = AddUndo(undo,&sc->layers[ly_fore].undoes,&sc->layers[ly_fore].redoes);
859 
860     return(ret);
861 }
862 
SCPreserveVWidth(SplineChar * sc)863 Undoes *SCPreserveVWidth(SplineChar *sc) {
864     Undoes *undo;
865 
866     if ( no_windowing_ui || maxundoes==0 )		/* No use for undoes in scripting */
867 return(NULL);
868 
869     undo = chunkalloc(sizeof(Undoes));
870 
871     undo->undotype = ut_vwidth;
872     undo->was_modified = sc->changed;
873     undo->was_order2 = sc->layers[ly_fore].order2;
874     undo->u.state.width = sc->vwidth;
875 return( AddUndo(undo,&sc->layers[ly_fore].undoes,&sc->layers[ly_fore].redoes));
876 }
877 
BCPreserveState(BDFChar * bc)878 Undoes *BCPreserveState( BDFChar *bc ) {
879     Undoes *undo;
880     BDFRefChar *head, *ref, *prev = NULL;
881 
882     if ( no_windowing_ui || maxundoes==0 )		/* No use for undoes in scripting */
883 return(NULL);
884 
885     undo = chunkalloc(sizeof(Undoes));
886 
887     undo->undotype = ut_bitmap;
888     undo->u.bmpstate.width = bc->width;
889     undo->u.bmpstate.xmin = bc->xmin;
890     undo->u.bmpstate.xmax = bc->xmax;
891     undo->u.bmpstate.ymin = bc->ymin;
892     undo->u.bmpstate.ymax = bc->ymax;
893     undo->u.bmpstate.bytes_per_line = bc->bytes_per_line;
894     undo->u.bmpstate.bitmap = bmpcopy(bc->bitmap,bc->bytes_per_line,
895 	    bc->ymax-bc->ymin+1);
896     undo->u.bmpstate.selection = BDFFloatCopy(bc->selection);
897     for ( head=bc->refs; head!=NULL; head=head->next ) {
898 	ref = calloc( 1,sizeof( BDFRefChar ));
899 	memcpy( ref,head,sizeof( BDFRefChar ));
900 	if ( prev == NULL )
901 	    undo->u.bmpstate.refs = ref;
902 	else
903 	    prev->next = ref;
904 	prev = ref;
905     }
906 return( AddUndo(undo,&bc->undoes,&bc->redoes));
907 }
908 
SCUndoAct(SplineChar * sc,int layer,Undoes * undo)909 static void SCUndoAct(SplineChar *sc,int layer, Undoes *undo) {
910 
911     switch ( undo->undotype ) {
912       case ut_noop:
913       break;
914       case ut_width: {
915 	int width = sc->width;
916 	if ( sc->width!=undo->u.width )
917 	    SCSynchronizeWidth(sc,undo->u.width,width,NULL);
918 	undo->u.width = width;
919       } break;
920       case ut_vwidth: {
921 	int vwidth = sc->vwidth;
922 	sc->vwidth = undo->u.width;
923 	undo->u.width = vwidth;
924       } break;
925       case ut_hints: {
926 	void *hints = UHintCopy(sc,false);
927 	uint8 *instrs = sc->ttf_instrs;
928 	int instrs_len = sc->ttf_instrs_len;
929 	ExtractHints(sc,undo->u.state.hints,false);
930 	sc->ttf_instrs = undo->u.state.instrs;
931 	sc->ttf_instrs_len = undo->u.state.instrs_len;
932 	undo->u.state.hints = hints;
933 	undo->u.state.instrs = instrs;
934 	undo->u.state.instrs_len = instrs_len;
935 	SCOutOfDateBackground(sc);
936       } break;
937       case ut_state: case ut_tstate: case ut_statehint: case ut_statename: {
938 	Layer *head = layer==ly_grid ? &sc->parent->grid : &sc->layers[layer];
939 	SplinePointList *spl = head->splines;
940 
941 //	printf("SCUndoAct() ut_state case, layer:%d sc:%p scn:%s scw:%d uw:%d\n",
942 //	       layer, sc, sc->name, sc->width, undo->u.state.width );
943 
944 	if ( layer==ly_fore ) {
945 	    int width = sc->width;
946 	    int vwidth = sc->vwidth;
947 	    if ( sc->width!=undo->u.state.width )
948 	    {
949 //		printf("SCUndoAct() sc:%p scn:%s scw:%d uw:%d\n",
950 //		       sc, sc->name, sc->width, undo->u.state.width );
951 		SCSynchronizeWidth(sc,undo->u.state.width,width,NULL);
952 	    }
953 	    sc->vwidth = undo->u.state.vwidth;
954 	    undo->u.state.width = width;
955 	    undo->u.state.vwidth = vwidth;
956 	}
957 	head->splines = undo->u.state.splines;
958 	if ( layer==ly_fore ) {
959 	    AnchorPoint *ap = sc->anchor;
960 	    sc->anchor = undo->u.state.anchor;
961 	    undo->u.state.anchor = ap;
962 	}
963 	if ( layer!=ly_grid && !RefCharsMatch(undo->u.state.refs,head->refs)) {
964 	    RefChar *refs = RefCharsCopyState(sc,layer);
965 	    FixupRefChars(sc,undo->u.state.refs,layer);
966 	    undo->u.state.refs = refs;
967 	}
968 	if ( layer==ly_fore &&
969 		(undo->undotype==ut_statehint || undo->undotype==ut_statename)) {
970 	    void *hints = UHintCopy(sc,false);
971 	    uint8 *instrs = sc->ttf_instrs;
972 	    int instrs_len = sc->ttf_instrs_len;
973 	    ExtractHints(sc,undo->u.state.hints,false);
974 	    sc->ttf_instrs = undo->u.state.instrs;
975 	    sc->ttf_instrs_len = undo->u.state.instrs_len;
976 	    undo->u.state.hints = hints;
977 	    undo->u.state.instrs = instrs;
978 	    undo->u.state.instrs_len = instrs_len;
979 	}
980 	if ( !ImagesMatch(undo->u.state.images,head->images)) {
981 	    ImageList *images = ImageListCopy(head->images);
982 	    FixupImages(sc,undo->u.state.images,layer);
983 	    undo->u.state.images = images;
984 	    SCOutOfDateBackground(sc);
985 	}
986 	undo->u.state.splines = spl;
987 	if ( undo->u.state.lbearingchange ) {
988 	    undo->u.state.lbearingchange = -undo->u.state.lbearingchange;
989 	    SCSynchronizeLBearing(sc,undo->u.state.lbearingchange,layer);
990 	}
991 	if ( layer==ly_fore && undo->undotype==ut_statename ) {
992 	    char *temp = sc->name;
993 	    int uni = sc->unicodeenc;
994 	    PST *possub = sc->possub;
995 	    char *comment = sc->comment;
996 	    sc->name = copy(undo->u.state.charname);
997 	    undo->u.state.charname = temp;
998 	    sc->unicodeenc = undo->u.state.unicodeenc;
999 	    undo->u.state.unicodeenc = uni;
1000 	    sc->possub = undo->u.state.possub;
1001 	    undo->u.state.possub = possub;
1002 	    sc->comment = undo->u.state.comment;
1003 	    undo->u.state.comment = comment;
1004 	}
1005       } break;
1006       default:
1007 	IError( "Unknown undo type in SCUndoAct: %d", undo->undotype );
1008       break;
1009     }
1010 }
1011 
CVDoUndo(CharViewBase * cv)1012 void CVDoUndo(CharViewBase *cv) {
1013     Undoes *undo = cv->layerheads[cv->drawmode]->undoes;
1014 
1015 //    printf("CVDoUndo() undo:%p u->next:%p\n", undo, ( undo ? undo->next : 0 ) );
1016     if ( undo==NULL )		/* Shouldn't happen */
1017 	return;
1018 
1019     cv->layerheads[cv->drawmode]->undoes = undo->next;
1020     undo->next = NULL;
1021 
1022     SCUndoAct(cv->sc,CVLayer(cv),undo);
1023     undo->next = cv->layerheads[cv->drawmode]->redoes;
1024     cv->layerheads[cv->drawmode]->redoes = undo;
1025 
1026     _CVCharChangedUpdate(cv,undo->was_modified);
1027 }
1028 
CVDoRedo(CharViewBase * cv)1029 void CVDoRedo(CharViewBase *cv) {
1030     Undoes *undo = cv->layerheads[cv->drawmode]->redoes;
1031 
1032     if ( undo==NULL )		/* Shouldn't happen */
1033 	return;
1034     cv->layerheads[cv->drawmode]->redoes = undo->next;
1035     undo->next = NULL;
1036 
1037     SCUndoAct(cv->sc,CVLayer(cv),undo);
1038     undo->next = cv->layerheads[cv->drawmode]->undoes;
1039     cv->layerheads[cv->drawmode]->undoes = undo;
1040     CVCharChangedUpdate(cv);
1041 }
1042 
SCDoUndo(SplineChar * sc,int layer)1043 void SCDoUndo(SplineChar *sc,int layer) {
1044     Undoes *undo = sc->layers[layer].undoes;
1045 
1046     if ( undo==NULL )		/* Shouldn't happen */
1047 return;
1048     sc->layers[layer].undoes = undo->next;
1049     undo->next = NULL;
1050     SCUndoAct(sc,layer,undo);
1051     undo->next = sc->layers[layer].redoes;
1052     sc->layers[layer].redoes = undo;
1053     _SCCharChangedUpdate(sc,layer,undo->was_modified);
1054 return;
1055 }
1056 
SCDoRedo(SplineChar * sc,int layer)1057 void SCDoRedo(SplineChar *sc, int layer) {
1058     Undoes *undo = sc->layers[layer].redoes;
1059 
1060     if ( undo==NULL )		/* Shouldn't happen */
1061 return;
1062     sc->layers[layer].redoes = undo->next;
1063     undo->next = NULL;
1064     SCUndoAct(sc,layer,undo);
1065     undo->next = sc->layers[layer].undoes;
1066     sc->layers[layer].undoes = undo;
1067     SCCharChangedUpdate(sc,layer);
1068 return;
1069 }
1070 
1071 /* Used when doing incremental transformations. If I just keep doing increments*/
1072 /*  then rounding errors will mount. Instead I go back to the original state */
1073 /*  each time */
_CVRestoreTOriginalState(CharViewBase * cv,PressedOn * p)1074 void _CVRestoreTOriginalState(CharViewBase *cv,PressedOn *p) {
1075     Undoes *undo = cv->layerheads[cv->drawmode]->undoes;
1076     RefChar *ref, *uref;
1077     ImageList *img, *uimg;
1078     int j;
1079 
1080     SplinePointListFree(cv->layerheads[cv->drawmode]->splines);
1081     cv->layerheads[cv->drawmode]->splines = SplinePointListCopy(undo->u.state.splines);
1082     if ( !p->anysel || p->transanyrefs ) {
1083 	for ( ref=cv->layerheads[cv->drawmode]->refs, uref=undo->u.state.refs; uref!=NULL; ref=ref->next, uref=uref->next )
1084 	    for ( j=0; j<uref->layer_cnt; ++j )
1085 		if ( uref->layers[j].splines!=NULL ) {
1086 		    SplinePointListFree(cv->layerheads[cv->drawmode]->splines);
1087 		    cv->layerheads[cv->drawmode]->splines = SplinePointListCopy(undo->u.state.splines);
1088 		    memcpy(&ref->transform,&uref->transform,sizeof(ref->transform));
1089 		}
1090     }
1091     for ( img=cv->layerheads[cv->drawmode]->images, uimg=undo->u.state.images; uimg!=NULL;
1092 	    img = img->next, uimg = uimg->next ) {
1093 	img->xoff = uimg->xoff;
1094 	img->yoff = uimg->yoff;
1095 	img->xscale = uimg->xscale;
1096 	img->yscale = uimg->yscale;
1097     }
1098 }
1099 
_CVUndoCleanup(CharViewBase * cv,PressedOn * p)1100 void _CVUndoCleanup(CharViewBase *cv,PressedOn *p) {
1101     Undoes * undo = cv->layerheads[cv->drawmode]->undoes;
1102     RefChar *uref;
1103 
1104     if ( !p->anysel || p->transanyrefs ) {
1105 	for ( uref=undo->u.state.refs; uref!=NULL; uref=uref->next ) {
1106 	    int i;
1107 	    for ( i=0; i<uref->layer_cnt; ++i ) {
1108 		SplinePointListsFree(uref->layers[i].splines);
1109 		GradientFree(uref->layers[i].fill_brush.gradient);
1110 		PatternFree(uref->layers[i].fill_brush.pattern);
1111 		GradientFree(uref->layers[i].stroke_pen.brush.gradient);
1112 		PatternFree(uref->layers[i].stroke_pen.brush.pattern);
1113 	    }
1114 	    free(uref->layers);
1115 	    uref->layers = NULL;
1116 	    uref->layer_cnt = 0;
1117 	}
1118     }
1119     undo->undotype = ut_state;
1120 }
1121 
CVRemoveTopUndo(CharViewBase * cv)1122 void CVRemoveTopUndo(CharViewBase *cv) {
1123     Undoes * undo = cv->layerheads[cv->drawmode]->undoes;
1124 
1125     if (undo == NULL)
1126 	return; // Shouldn't happen
1127 
1128     cv->layerheads[cv->drawmode]->undoes = undo->next;
1129     undo->next = NULL;
1130     UndoesFree(undo);
1131 }
1132 
BCUndoAct(BDFChar * bc,Undoes * undo)1133 static void BCUndoAct(BDFChar *bc,Undoes *undo) {
1134     uint8 *b;
1135     int temp;
1136     BDFFloat *sel;
1137     BDFRefChar *ref, *head, *prev = NULL, *uhead = NULL;
1138 
1139     switch ( undo->undotype ) {
1140       case ut_bitmap: {
1141 	temp = bc->width; bc->width = undo->u.bmpstate.width; undo->u.bmpstate.width = temp;
1142 	temp = bc->xmin; bc->xmin = undo->u.bmpstate.xmin; undo->u.bmpstate.xmin = temp;
1143 	temp = bc->xmax; bc->xmax = undo->u.bmpstate.xmax; undo->u.bmpstate.xmax = temp;
1144 	temp = bc->ymin; bc->ymin = undo->u.bmpstate.ymin; undo->u.bmpstate.ymin = temp;
1145 	temp = bc->ymax; bc->ymax = undo->u.bmpstate.ymax; undo->u.bmpstate.ymax = temp;
1146 	temp = bc->bytes_per_line; bc->bytes_per_line = undo->u.bmpstate.bytes_per_line; undo->u.bmpstate.bytes_per_line = temp;
1147 	b = bc->bitmap; bc->bitmap = undo->u.bmpstate.bitmap; undo->u.bmpstate.bitmap = b;
1148 	sel = bc->selection; bc->selection = undo->u.bmpstate.selection; undo->u.bmpstate.selection = sel;
1149 
1150 	if ( !BDFRefCharsMatch( undo->u.bmpstate.refs,bc->refs )) {
1151 	    for ( head=bc->refs; head!=NULL; head=head->next ) {
1152 		ref = calloc( 1,sizeof( BDFRefChar ));
1153 		memcpy( ref,head,sizeof( BDFRefChar ));
1154 		if ( prev != NULL )
1155 		    prev->next = ref;
1156 		else
1157 		    uhead = ref;
1158 		prev = ref;
1159 	    }
1160 	    FixupBDFRefChars( bc,undo->u.bmpstate.refs );
1161 	    undo->u.bmpstate.refs = uhead;
1162 	}
1163       } break;
1164       default:
1165 	IError( "Unknown undo type in BCUndoAct: %d", undo->undotype );
1166       break;
1167     }
1168 }
1169 
BCDoUndo(BDFChar * bc)1170 void BCDoUndo(BDFChar *bc) {
1171     Undoes *undo = bc->undoes;
1172 
1173     if ( undo==NULL )		/* Shouldn't happen */
1174 return;
1175     bc->undoes = undo->next;
1176     undo->next = NULL;
1177     BCUndoAct(bc,undo);
1178     undo->next = bc->redoes;
1179     bc->redoes = undo;
1180     BCCharChangedUpdate(bc);
1181 return;
1182 }
1183 
BCDoRedo(BDFChar * bc)1184 void BCDoRedo(BDFChar *bc) {
1185     Undoes *undo = bc->redoes;
1186 
1187     if ( undo==NULL )		/* Shouldn't happen */
1188 return;
1189     bc->redoes = undo->next;
1190     undo->next = NULL;
1191     BCUndoAct(bc,undo);
1192     undo->next = bc->undoes;
1193     bc->undoes = undo;
1194     BCCharChangedUpdate(bc);
1195 return;
1196 }
1197 
1198 /* **************************** Cut, Copy & Paste *************************** */
1199 
1200 static Undoes copybuffer;
1201 
CopyBufferFree(void)1202 void CopyBufferFree(void) {
1203     BDFRefChar *brhead, *brnext;
1204 
1205     switch( copybuffer.undotype ) {
1206       case ut_hints:
1207 	UHintListFree(copybuffer.u.state.hints);
1208 	free(copybuffer.u.state.instrs);
1209       break;
1210       case ut_state: case ut_statehint: case ut_anchors: case ut_statelookup:
1211 	SplinePointListsFree(copybuffer.u.state.splines);
1212 	RefCharsFree(copybuffer.u.state.refs);
1213 	AnchorPointsFree(copybuffer.u.state.anchor);
1214 	UHintListFree(copybuffer.u.state.hints);
1215 	free(copybuffer.u.state.instrs);
1216 	ImageListsFree(copybuffer.u.state.images);
1217 	GradientFree(copybuffer.u.state.fill_brush.gradient);
1218 	PatternFree(copybuffer.u.state.fill_brush.pattern);
1219 	GradientFree(copybuffer.u.state.stroke_pen.brush.gradient);
1220 	PatternFree(copybuffer.u.state.stroke_pen.brush.pattern);
1221       break;
1222       case ut_bitmapsel:
1223 	BDFFloatFree(copybuffer.u.bmpstate.selection);
1224       break;
1225       case ut_bitmap:
1226 	for ( brhead=copybuffer.u.bmpstate.refs; brhead!=NULL; brhead = brnext ) {
1227 	    brnext = brhead->next;
1228 	    free( brhead );
1229 	}
1230         free( copybuffer.u.bmpstate.bitmap );
1231       break;
1232       case ut_multiple: case ut_layers:
1233 	UndoesFree( copybuffer.u.multiple.mult );
1234       break;
1235       case ut_composit:
1236 	UndoesFree( copybuffer.u.composit.state );
1237 	UndoesFree( copybuffer.u.composit.bitmaps );
1238       break;
1239       default:
1240       break;
1241     }
1242     memset(&copybuffer,'\0',sizeof(copybuffer));
1243     copybuffer.undotype = ut_none;
1244 }
1245 
CopyBufferFreeGrab(void)1246 static void CopyBufferFreeGrab(void) {
1247     CopyBufferFree();
1248     if ( FontViewFirst()!=NULL && !no_windowing_ui && export_clipboard )
1249 	ClipboardGrab();
1250 }
1251 
noop(void * UNUSED (_copybuffer))1252 static void noop(void *UNUSED(_copybuffer)) {
1253 }
1254 
copybufferPt2str(void * UNUSED (_copybuffer),int32 * len)1255 static void *copybufferPt2str(void *UNUSED(_copybuffer),int32 *len) {
1256     Undoes *cur = &copybuffer;
1257     SplinePoint *sp;
1258     char buffer[100];
1259 
1260     while ( cur ) {
1261 	switch ( cur->undotype ) {
1262 	  case ut_multiple:
1263 	    cur = cur->u.multiple.mult;
1264 	  break;
1265 	  case ut_composit:
1266 	    cur = cur->u.composit.state;
1267 	  break;
1268 	  case ut_state: case ut_statehint: case ut_statename: case ut_statelookup:
1269     goto out;
1270 	  default:
1271 	    cur = NULL;
1272 	  break;
1273 	}
1274     }
1275     out:
1276     if ( cur==NULL || FontViewFirst()==NULL ||
1277 	    cur->u.state.splines==NULL || cur->u.state.refs!=NULL ||
1278 	    cur->u.state.splines->next!=NULL ||
1279 	    cur->u.state.splines->first->next!=NULL ) {
1280 	*len=0;
1281 return( copy(""));
1282     }
1283 
1284     sp = cur->u.state.splines->first;
1285     sprintf(buffer,"(%g%s%g)", (double) sp->me.x, coord_sep, (double) sp->me.y );
1286     *len = strlen(buffer);
1287 return( copy(buffer));
1288 }
1289 
copybufferName2str(void * UNUSED (_copybuffer),int32 * len)1290 static void *copybufferName2str(void *UNUSED(_copybuffer),int32 *len) {
1291     Undoes *cur = &copybuffer;
1292 
1293     while ( cur ) {
1294 	switch ( cur->undotype ) {
1295 	  case ut_multiple:
1296 	    cur = cur->u.multiple.mult;
1297 	  break;
1298 	  case ut_composit:
1299 	    cur = cur->u.composit.state;
1300 	  break;
1301 	  case ut_statename:
1302     goto out;
1303 	  default:
1304 	    cur = NULL;
1305 	  break;
1306 	}
1307     }
1308     out:
1309     if ( cur==NULL || FontViewFirst()==NULL || cur->u.state.charname==NULL ) {
1310 	*len=0;
1311 return( copy(""));
1312     }
1313     *len = strlen(cur->u.state.charname);
1314 return( copy( cur->u.state.charname ));
1315 }
1316 
XCopyInstanciateRefs(RefChar * refs,SplineChar * container,int layer)1317 static RefChar *XCopyInstanciateRefs(RefChar *refs,SplineChar *container,int layer) {
1318     /* References in the copybuffer don't include the translated splines */
1319     RefChar *head=NULL, *last, *cur;
1320 
1321     while ( refs!=NULL ) {
1322 	cur = RefCharCreate();
1323 	free(cur->layers);
1324 	*cur = *refs;
1325 	cur->layers = NULL;
1326 	cur->layer_cnt = 0;
1327 	cur->next = NULL;
1328 	SCReinstanciateRefChar(container,cur,layer);
1329 	if ( head==NULL )
1330 	    head = cur;
1331 	else
1332 	    last->next = cur;
1333 	last = cur;
1334 	refs = refs->next;
1335     }
1336 return( head );
1337 }
1338 
FFClipToSC(SplineChar * dummy,Undoes * cur)1339 static int FFClipToSC(SplineChar *dummy,Undoes *cur) {
1340     int lcnt;
1341 
1342     if ( cur==NULL )
1343 return( false );
1344 
1345     dummy->name = "dummy";
1346     if ( cur->undotype!=ut_layers )
1347 	dummy->parent = cur->copied_from;
1348     else if ( cur->u.multiple.mult!=NULL && cur->u.multiple.mult->undotype == ut_state )
1349 	dummy->parent = cur->u.multiple.mult->copied_from;
1350     if ( dummy->parent==NULL )
1351 	dummy->parent = FontViewFirst()->sf;		/* Might not be right, but we need something */
1352     dummy->width = cur->u.state.width;
1353     if ( cur->undotype==ut_layers ) {
1354 	Undoes *ulayer;
1355 	for ( ulayer = cur->u.multiple.mult, lcnt=0; ulayer!=NULL; ulayer=ulayer->next, ++lcnt);
1356 	dummy->layer_cnt = lcnt+1;
1357 	if ( lcnt!=1 )
1358 	    dummy->layers = calloc((lcnt+1),sizeof(Layer));
1359 	for ( ulayer = cur->u.multiple.mult, lcnt=1; ulayer!=NULL; ulayer=ulayer->next, ++lcnt) {
1360 	    if ( ulayer->undotype==ut_state || ulayer->undotype==ut_statehint ) {
1361 		dummy->layers[lcnt].fill_brush = ulayer->u.state.fill_brush;
1362 		dummy->layers[lcnt].stroke_pen = ulayer->u.state.stroke_pen;
1363 		dummy->layers[lcnt].dofill = ulayer->u.state.dofill;
1364 		dummy->layers[lcnt].dostroke = ulayer->u.state.dostroke;
1365 		dummy->layers[lcnt].splines = ulayer->u.state.splines;
1366 		dummy->layers[lcnt].refs = XCopyInstanciateRefs(ulayer->u.state.refs,dummy,ly_fore);
1367 	    }
1368 	}
1369     } else
1370     {
1371 	dummy->layers[ly_fore].fill_brush = cur->u.state.fill_brush;
1372 	dummy->layers[ly_fore].stroke_pen = cur->u.state.stroke_pen;
1373 	dummy->layers[ly_fore].dofill = cur->u.state.dofill;
1374 	dummy->layers[ly_fore].dostroke = cur->u.state.dostroke;
1375 	dummy->layers[ly_fore].splines = cur->u.state.splines;
1376 	dummy->layers[ly_fore].refs = XCopyInstanciateRefs(cur->u.state.refs,dummy,ly_fore);
1377     }
1378 return( true );
1379 }
1380 
copybuffer2svg(void * UNUSED (_copybuffer),int32 * len)1381 static void *copybuffer2svg(void *UNUSED(_copybuffer),int32 *len) {
1382     Undoes *cur = &copybuffer;
1383     SplineChar dummy;
1384     static Layer layers[2];
1385     FILE *svg;
1386     char *ret;
1387     int old_order2;
1388     int lcnt;
1389 
1390     while ( cur ) {
1391 	switch ( cur->undotype ) {
1392 	  case ut_multiple:
1393 	    cur = cur->u.multiple.mult;		/* will only handle one char in an "svg" file */
1394 	  break;
1395 	  case ut_composit:
1396 	    cur = cur->u.composit.state;
1397 	  break;
1398 	  case ut_state: case ut_statehint: case ut_layers: case ut_statelookup:
1399     goto out;
1400 	  default:
1401 	    cur = NULL;
1402 	  break;
1403 	}
1404     }
1405     out:
1406     if ( FontViewFirst()==NULL || cur==NULL ) {
1407 	*len=0;
1408 return( copy(""));
1409     }
1410 
1411     svg = GFileTmpfile();
1412     if ( svg==NULL ) {
1413 	*len=0;
1414 return( copy(""));
1415     }
1416 
1417     memset(&dummy,0,sizeof(dummy));
1418     dummy.layers = layers;
1419     dummy.layer_cnt = 2;
1420 
1421     if ( !FFClipToSC(&dummy,cur) ) {
1422 	fclose(svg);
1423 	*len=0;
1424 return( copy(""));
1425     }
1426 
1427     old_order2 = dummy.parent->layers[ly_fore].order2;
1428     dummy.parent->layers[ly_fore].order2 = cur->was_order2;
1429     dummy.layers[ly_fore].order2 = cur->was_order2;
1430     _ExportSVG(svg,&dummy,ly_fore,ExportParamsState());
1431     dummy.parent->layers[ly_fore].order2 = old_order2;
1432 
1433     for ( lcnt = ly_fore; lcnt<dummy.layer_cnt; ++lcnt )
1434 	RefCharsFree(dummy.layers[lcnt].refs);
1435     if ( dummy.layer_cnt!=2 && dummy.layers != layers )
1436 	free( dummy.layers );
1437 
1438     fseek(svg,0,SEEK_END);
1439     *len = ftell(svg);
1440     ret = malloc(*len);
1441     rewind(svg);
1442     fread(ret,1,*len,svg);
1443     fclose(svg);
1444 return( ret );
1445 }
1446 
1447 /* When a selection contains multiple glyphs, save them into an svg font */
copybuffer2svgmult(void * UNUSED (_copybuffer),int32 * len)1448 static void *copybuffer2svgmult(void *UNUSED(_copybuffer),int32 *len) {
1449     Undoes *cur = &copybuffer, *c, *c2;
1450     SplineFont *sf;
1451     int cnt,i;
1452     char *ret;
1453     Layer *ly;
1454     SplineChar *sc=NULL;
1455     int old_order2, o2=false;
1456     FILE *svg;
1457 
1458     if ( cur->undotype!=ut_multiple || !CopyContainsVectors() || FontViewFirst()==NULL ) {
1459 	*len=0;
1460 return( copy(""));
1461     }
1462 
1463     svg = GFileTmpfile();
1464     if ( svg==NULL ) {
1465 	*len=0;
1466 return( copy(""));
1467     }
1468 
1469     cur = cur->u.multiple.mult;
1470     for ( cnt=0, c=cur; c!=NULL; c=c->next, ++cnt );
1471 
1472     sf = SplineFontBlank(cnt);
1473     sf->glyphcnt = cnt;
1474     for ( i=0, c=cur; c!=NULL; c=c->next, ++i ) {
1475 	sf->glyphs[i] = sc = SFSplineCharCreate(sf);
1476 	sc->orig_pos = i;
1477 	ly = sc->layers;
1478 	if ( (c2 = c)->undotype==ut_composit )
1479 	    c2 = c2->u.composit.state;
1480 	FFClipToSC(sc,c2);
1481 	if ( ly!=sc->layers )
1482 	    free(ly);
1483 	o2 = c2->was_order2;
1484     }
1485 
1486     if ( sc!=NULL ) {
1487 	old_order2 = sc->parent->layers[ly_fore].order2;
1488 	sc->parent->layers[ly_fore].order2 = o2;
1489 	sc->layers[ly_fore].order2 = o2;
1490 	sf->ascent = sc->parent->ascent;
1491 	sf->descent = sc->parent->descent;
1492     }
1493     _WriteSVGFont(svg,sf,0,NULL,ly_fore);
1494     if ( sc!=NULL )
1495 	sc->parent->layers[ly_fore].order2 = old_order2;
1496 
1497     for ( i=0, c=cur; c!=NULL; c=c->next, ++i ) {
1498 	sc = sf->glyphs[i];
1499 	sc->layers[ly_fore].splines=NULL;
1500 	sc->layers[ly_fore].refs=NULL;
1501 	sc->name = NULL;
1502     }
1503     SplineFontFree(sf);
1504 
1505     fseek(svg,0,SEEK_END);
1506     *len = ftell(svg);
1507     ret = malloc(*len);
1508     rewind(svg);
1509     fread(ret,1,*len,svg);
1510     fclose(svg);
1511 return( ret );
1512 }
1513 
copybuffer2eps(void * UNUSED (_copybuffer),int32 * len)1514 static void *copybuffer2eps(void *UNUSED(_copybuffer),int32 *len) {
1515     Undoes *cur = &copybuffer;
1516     SplineChar dummy;
1517     static Layer layers[2];
1518     FILE *eps;
1519     char *ret;
1520     int old_order2;
1521     int lcnt;
1522 
1523     while ( cur ) {
1524 	switch ( cur->undotype ) {
1525 	  case ut_multiple:
1526 	    cur = cur->u.multiple.mult;		/* Can only handle one char in an "eps" file */
1527 	  break;
1528 	  case ut_composit:
1529 	    cur = cur->u.composit.state;
1530 	  break;
1531 	  case ut_state: case ut_statehint: case ut_layers: case ut_statelookup:
1532     goto out;
1533 	  default:
1534 	    cur = NULL;
1535 	  break;
1536 	}
1537     }
1538     out:
1539     if ( cur==NULL || FontViewFirst()==NULL ) {
1540 	*len=0;
1541 return( copy(""));
1542     }
1543 
1544     memset(&dummy,0,sizeof(dummy));
1545     dummy.layers = layers;
1546     dummy.layer_cnt = 2;
1547     dummy.name = "dummy";
1548     if ( cur->undotype!=ut_layers )
1549 	dummy.parent = cur->copied_from;
1550     else if ( cur->u.multiple.mult!=NULL && cur->u.multiple.mult->undotype == ut_state )
1551 	dummy.parent = cur->u.multiple.mult->copied_from;
1552     if ( dummy.parent==NULL )
1553 	dummy.parent = FontViewFirst()->sf;		/* Might not be right, but we need something */
1554     if ( cur->undotype==ut_layers ) {
1555 	Undoes *ulayer;
1556 	for ( ulayer = cur->u.multiple.mult, lcnt=0; ulayer!=NULL; ulayer=ulayer->next, ++lcnt);
1557 	dummy.layer_cnt = lcnt+1;
1558 	if ( lcnt!=1 )
1559 	    dummy.layers = calloc((lcnt+1),sizeof(Layer));
1560 	for ( ulayer = cur->u.multiple.mult, lcnt=1; ulayer!=NULL; ulayer=ulayer->next, ++lcnt) {
1561 	    if ( ulayer->undotype==ut_state || ulayer->undotype==ut_statehint ) {
1562 		dummy.layers[lcnt].fill_brush = ulayer->u.state.fill_brush;
1563 		dummy.layers[lcnt].stroke_pen = ulayer->u.state.stroke_pen;
1564 		dummy.layers[lcnt].dofill = ulayer->u.state.dofill;
1565 		dummy.layers[lcnt].dostroke = ulayer->u.state.dostroke;
1566 		dummy.layers[lcnt].splines = ulayer->u.state.splines;
1567 		dummy.layers[lcnt].refs = XCopyInstanciateRefs(ulayer->u.state.refs,&dummy,ly_fore);
1568 	    }
1569 	}
1570     } else {
1571 	dummy.layers[ly_fore].fill_brush = cur->u.state.fill_brush;
1572 	dummy.layers[ly_fore].stroke_pen = cur->u.state.stroke_pen;
1573 	dummy.layers[ly_fore].dofill = cur->u.state.dofill;
1574 	dummy.layers[ly_fore].dostroke = cur->u.state.dostroke;
1575 	dummy.layers[ly_fore].splines = cur->u.state.splines;
1576 	dummy.layers[ly_fore].refs = XCopyInstanciateRefs(cur->u.state.refs,&dummy,ly_fore);
1577     }
1578 
1579     eps = GFileTmpfile();
1580     if ( eps==NULL ) {
1581 	*len=0;
1582 return( copy(""));
1583     }
1584 
1585     old_order2 = dummy.parent->layers[ly_fore].order2;
1586     dummy.parent->layers[ly_fore].order2 = cur->was_order2;
1587     dummy.layers[ly_fore].order2 = cur->was_order2;
1588     /* Don't bother to generate a preview here, that can take too long and */
1589     /*  cause the paster to time out */
1590     _ExportEPS(eps,&dummy,false,ly_fore);
1591     dummy.parent->layers[ly_fore].order2 = old_order2;
1592 
1593     for ( lcnt = ly_fore; lcnt<dummy.layer_cnt; ++lcnt )
1594 	RefCharsFree(dummy.layers[lcnt].refs);
1595     if ( dummy.layer_cnt!=2 )
1596 	free( dummy.layers );
1597 
1598     fseek(eps,0,SEEK_END);
1599     *len = ftell(eps);
1600     ret = malloc(*len);
1601     rewind(eps);
1602     fread(ret,1,*len,eps);
1603     fclose(eps);
1604 return( ret );
1605 }
1606 
XClipCheckEps(void)1607 static void XClipCheckEps(void) {
1608     Undoes *cur = &copybuffer;
1609 
1610     if ( FontViewFirst()==NULL )
1611 return;
1612     if ( no_windowing_ui )
1613 return;
1614 
1615     while ( cur ) {
1616 	switch ( cur->undotype ) {
1617 	  case ut_multiple:
1618 	    if ( CopyContainsVectors())
1619 		ClipboardAddDataType("application/x-font-svg",&copybuffer,0,sizeof(char),
1620 			copybuffer2svgmult,noop);
1621 	    cur = cur->u.multiple.mult;
1622 	  break;
1623 	  case ut_composit:
1624 	    cur = cur->u.composit.state;
1625 	  break;
1626 	  case ut_state: case ut_statehint: case ut_statename: case ut_layers:
1627 	    ClipboardAddDataType("image/eps",&copybuffer,0,sizeof(char),
1628 		    copybuffer2eps,noop);
1629 	    ClipboardAddDataType("image/svg+xml",&copybuffer,0,sizeof(char),
1630 		    copybuffer2svg,noop);
1631 	    ClipboardAddDataType("image/svg",&copybuffer,0,sizeof(char),
1632 		    copybuffer2svg,noop);
1633 	    /* If the selection is one point, then export the coordinates as a string */
1634 	    if ( cur->u.state.splines!=NULL && cur->u.state.refs==NULL &&
1635 		    cur->u.state.splines->next==NULL &&
1636 		    cur->u.state.splines->first->next==NULL )
1637 		ClipboardAddDataType("STRING",&copybuffer,0,sizeof(char),
1638 			copybufferPt2str,noop);
1639 	    else if ( cur->undotype==ut_statename )
1640 		ClipboardAddDataType("STRING",&copybuffer,0,sizeof(char),
1641 			copybufferName2str,noop);
1642 	    cur = NULL;
1643 	  break;
1644 	  default:
1645 	    cur = NULL;
1646 	  break;
1647 	}
1648     }
1649 }
1650 
ClipboardClear(void)1651 void ClipboardClear(void) {
1652     CopyBufferFree();
1653 }
1654 
CopyUndoType(void)1655 enum undotype CopyUndoType(void) {
1656     Undoes *paster;
1657 
1658     paster = &copybuffer;
1659     while ( paster->undotype==ut_composit || paster->undotype==ut_multiple ) {
1660 	if ( paster->undotype==ut_multiple )
1661 	    paster = paster->u.multiple.mult;
1662 	else if ( paster->u.composit.state==NULL )
1663 return( ut_none );
1664 	else
1665 	    paster = paster->u.composit.state;
1666     }
1667 return( paster->undotype );
1668 }
1669 
CopyContainsSomething(void)1670 int CopyContainsSomething(void) {
1671     Undoes *cur = &copybuffer;
1672     if ( cur->undotype==ut_multiple )
1673 	cur = cur->u.multiple.mult;
1674     if ( cur->undotype==ut_composit )
1675 return( cur->u.composit.state!=NULL );
1676 
1677     if ( cur->undotype==ut_statelookup && cur->copied_from==NULL )
1678 return( false );		/* That is, if the source font has been closed, we can't use this any more */
1679 
1680 return( cur->undotype==ut_state || cur->undotype==ut_tstate ||
1681 	cur->undotype==ut_statehint || cur->undotype==ut_statename ||
1682 	cur->undotype==ut_statelookup ||
1683 	cur->undotype==ut_width || cur->undotype==ut_vwidth ||
1684 	cur->undotype==ut_lbearing || cur->undotype==ut_rbearing ||
1685 	cur->undotype==ut_hints ||
1686 	cur->undotype==ut_bitmap || cur->undotype==ut_bitmapsel ||
1687 	cur->undotype==ut_anchors || cur->undotype==ut_noop );
1688 }
1689 
CopyContainsBitmap(void)1690 int CopyContainsBitmap(void) {
1691     Undoes *cur = &copybuffer;
1692     if ( cur->undotype==ut_multiple )
1693 	cur = cur->u.multiple.mult;
1694     if ( cur->undotype==ut_composit )
1695 return( cur->u.composit.bitmaps!=NULL );
1696 
1697 return( cur->undotype==ut_bitmap || cur->undotype==ut_bitmapsel || cur->undotype==ut_noop );
1698 }
1699 
CopyContainsVectors(void)1700 int CopyContainsVectors(void) {
1701     Undoes *cur = &copybuffer;
1702     if ( cur->undotype==ut_multiple )
1703 	cur = cur->u.multiple.mult;
1704     if ( cur->undotype==ut_composit )
1705 return( cur->u.composit.state!=NULL );
1706 
1707 return( cur->undotype==ut_state || cur->undotype==ut_statehint ||
1708 	cur->undotype==ut_statename || cur->undotype==ut_layers );
1709 }
1710 
CopyContainsRef(SplineFont * sf)1711 RefChar *CopyContainsRef(SplineFont *sf) {
1712     Undoes *cur = &copybuffer;
1713     if ( cur->undotype==ut_multiple ) {
1714 	cur = cur->u.multiple.mult;
1715 	if ( cur->next!=NULL )
1716 return( NULL );
1717     }
1718     if ( cur->undotype==ut_composit )
1719 	cur = cur->u.composit.state;
1720     if ( cur==NULL || (cur->undotype!=ut_state && cur->undotype!=ut_tstate &&
1721 	    cur->undotype!=ut_statehint && cur->undotype!=ut_statename ))
1722 return( NULL );
1723     if ( cur->u.state.splines!=NULL || cur->u.state.refs==NULL ||
1724 	    cur->u.state.refs->next != NULL )
1725 return( NULL );
1726     if ( sf!=cur->copied_from )
1727 return( NULL );
1728 
1729 return( cur->u.state.refs );
1730 }
1731 
CopyBufferGet(void)1732 const Undoes *CopyBufferGet(void) {
1733 return( &copybuffer );
1734 }
1735 
_CopyBufferClearCopiedFrom(Undoes * cb,SplineFont * dying)1736 static void _CopyBufferClearCopiedFrom(Undoes *cb, SplineFont *dying) {
1737     switch ( cb->undotype ) {
1738       case ut_noop:
1739       break;
1740       case ut_state: case ut_statehint: case ut_statename: case ut_statelookup:
1741 	if ( cb->copied_from == dying )
1742 	    cb->copied_from = NULL;
1743       break;
1744       case ut_width:
1745       case ut_vwidth:
1746       case ut_rbearing:
1747       case ut_lbearing:
1748       break;
1749       case ut_composit:
1750 	if ( cb->copied_from == dying )
1751 	    cb->copied_from = NULL;
1752 	_CopyBufferClearCopiedFrom(cb->u.composit.state,dying);
1753       break;
1754       case ut_multiple: case ut_layers:
1755 	if ( cb->copied_from == dying )
1756 	    cb->copied_from = NULL;
1757 	for ( cb=cb->u.multiple.mult; cb!=NULL; cb=cb->next )
1758 	    _CopyBufferClearCopiedFrom(cb,dying);
1759       break;
1760       default:
1761       break;
1762     }
1763 }
1764 
CopyBufferClearCopiedFrom(SplineFont * dying)1765 void CopyBufferClearCopiedFrom(SplineFont *dying) {
1766     _CopyBufferClearCopiedFrom(&copybuffer,dying);
1767 }
1768 
getAdobeEnc(const char * name)1769 int getAdobeEnc(const char *name) {
1770     int i;
1771 
1772     for ( i=0; i<256; ++i )
1773 	if ( strcmp(name,AdobeStandardEncoding[i])==0 )
1774     break;
1775     if ( i==256 ) i = -1;
1776 return( i );
1777 }
1778 
CopyReference(SplineChar * sc)1779 void CopyReference(SplineChar *sc) {
1780     RefChar *ref;
1781 
1782     CopyBufferFreeGrab();
1783 
1784     copybuffer.undotype = ut_state;
1785     copybuffer.was_order2 = sc->layers[ly_fore].order2;	/* Largely irrelevant */
1786     copybuffer.u.state.width = sc->width;
1787     copybuffer.u.state.vwidth = sc->vwidth;
1788     copybuffer.u.state.refs = ref = RefCharCreate();
1789     copybuffer.copied_from = sc->parent;
1790     if ( ly_fore<sc->layer_cnt ) {
1791 	BrushCopy(&copybuffer.u.state.fill_brush, &sc->layers[ly_fore].fill_brush,NULL);
1792 	PenCopy(&copybuffer.u.state.stroke_pen, &sc->layers[ly_fore].stroke_pen,NULL);
1793 	copybuffer.u.state.dofill = sc->layers[ly_fore].dofill;
1794 	copybuffer.u.state.dostroke = sc->layers[ly_fore].dostroke;
1795 	copybuffer.u.state.fillfirst = sc->layers[ly_fore].fillfirst;
1796     }
1797     ref->unicode_enc = sc->unicodeenc;
1798     ref->orig_pos = sc->orig_pos;
1799     ref->adobe_enc = getAdobeEnc(sc->name);
1800     ref->transform[0] = ref->transform[3] = 1.0;
1801 
1802     XClipCheckEps();
1803 }
1804 
SCCopyLookupData(SplineChar * sc)1805 void SCCopyLookupData(SplineChar *sc) {
1806     CopyReference(sc);
1807     copybuffer.undotype = ut_statelookup;
1808 }
1809 
CopySelected(CharViewBase * cv,int doanchors)1810 void CopySelected(CharViewBase *cv,int doanchors) {
1811 
1812     CopyBufferFreeGrab();
1813 
1814     copybuffer.undotype = ut_state;
1815     copybuffer.was_order2 = cv->layerheads[cv->drawmode]->order2;
1816     copybuffer.u.state.width = cv->sc->width;
1817     copybuffer.u.state.vwidth = cv->sc->vwidth;
1818     if ( cv->sc->inspiro && hasspiro())
1819 	copybuffer.u.state.splines = SplinePointListCopySpiroSelected(cv->layerheads[cv->drawmode]->splines);
1820     else
1821 	copybuffer.u.state.splines = SplinePointListCopySelected(cv->layerheads[cv->drawmode]->splines);
1822     if ( cv->drawmode!=dm_grid ) {
1823 	RefChar *refs, *new;
1824 	for ( refs = cv->layerheads[cv->drawmode]->refs; refs!=NULL; refs = refs->next ) if ( refs->selected ) {
1825 	    new = RefCharCreate();
1826 	    free(new->layers);
1827 	    *new = *refs;
1828 	    new->layers = NULL;
1829 	    new->layer_cnt = 0;
1830 	    new->orig_pos = new->sc->orig_pos;
1831 	    new->sc = NULL;
1832 	    new->next = copybuffer.u.state.refs;
1833 	    copybuffer.u.state.refs = new;
1834 	}
1835 	if ( doanchors ) {
1836 	    AnchorPoint *ap, *new;
1837 	    for ( ap=cv->sc->anchor; ap!=NULL; ap=ap->next ) if ( ap->selected ) {
1838 		new = chunkalloc(sizeof(AnchorPoint));
1839 		*new = *ap;
1840 		new->next = copybuffer.u.state.anchor;
1841 		copybuffer.u.state.anchor = new;
1842 	    }
1843 	}
1844     }
1845     if ( cv->drawmode!=dm_grid && CVLayer(cv)!=ly_fore ) {
1846 	ImageList *imgs, *new;
1847 	for ( imgs = cv->layerheads[cv->drawmode]->images; imgs!=NULL; imgs = imgs->next ) if ( imgs->selected ) {
1848 	    new = chunkalloc(sizeof(ImageList));
1849 	    *new = *imgs;
1850 	    new->next = copybuffer.u.state.images;
1851 	    copybuffer.u.state.images = new;
1852 	}
1853     }
1854     if ( cv->drawmode==dm_fore || cv->drawmode==dm_back ) {
1855 	BrushCopy(&copybuffer.u.state.fill_brush, &cv->layerheads[cv->drawmode]->fill_brush,NULL);
1856 	PenCopy(&copybuffer.u.state.stroke_pen, &cv->layerheads[cv->drawmode]->stroke_pen,NULL);
1857 	copybuffer.u.state.dofill = cv->layerheads[cv->drawmode]->dofill;
1858 	copybuffer.u.state.dostroke = cv->layerheads[cv->drawmode]->dostroke;
1859 	copybuffer.u.state.fillfirst = cv->layerheads[cv->drawmode]->fillfirst;
1860     }
1861     copybuffer.copied_from = cv->sc->parent;
1862 
1863     XClipCheckEps();
1864 }
1865 
CVCopyGridFit(CharViewBase * cv)1866 void CVCopyGridFit(CharViewBase *cv) {
1867     SplineChar *sc = cv->sc;
1868 
1869     if ( cv->gridfit==NULL )
1870 return;
1871 
1872     CopyBufferFreeGrab();
1873 
1874     copybuffer.undotype = ut_state;
1875     copybuffer.was_order2 = cv->layerheads[cv->drawmode]->order2;
1876     copybuffer.u.state.width = cv->ft_gridfitwidth;
1877     copybuffer.u.state.vwidth = sc->vwidth;
1878     copybuffer.u.state.splines = SplinePointListCopy(cv->gridfit);
1879     copybuffer.copied_from = cv->sc->parent;
1880 
1881     XClipCheckEps();
1882 }
1883 
SCCopyAllLayer(SplineChar * sc,enum fvcopy_type full,int layer)1884 static Undoes *SCCopyAllLayer(SplineChar *sc,enum fvcopy_type full,int layer) {
1885     Undoes *cur;
1886     RefChar *ref;
1887     /* If full==ct_fullcopy copy the glyph as is. */
1888     /* If full==ct_reference put a reference to the glyph in the clipboard */
1889     /* If full==ct_unlinkrefs copy the glyph, but unlink any references it contains */
1890     /*	so we end up with no references and a bunch of splines */
1891 
1892     cur = chunkalloc(sizeof(Undoes));
1893     if ( sc==NULL ) {
1894 	cur->undotype = ut_noop;
1895     } else {
1896 	cur->was_order2 = sc->layers[ly_fore].order2;
1897 	cur->u.state.width = sc->width;
1898 	cur->u.state.vwidth = sc->vwidth;
1899 	if ( full==ct_fullcopy || full == ct_unlinkrefs ) {
1900 	    cur->undotype = copymetadata ? ut_statename : ut_statehint;
1901 	    cur->u.state.splines = SplinePointListCopy(sc->layers[layer].splines);
1902 	    if ( full==ct_unlinkrefs )
1903 		cur->u.state.splines = RefCharsCopyUnlinked(cur->u.state.splines,sc,layer);
1904 	    else
1905 		cur->u.state.refs = RefCharsCopyState(sc,layer);
1906 	    cur->u.state.anchor = AnchorPointsCopy(sc->anchor);
1907 	    cur->u.state.hints = UHintCopy(sc,true);
1908 	    if ( copyttfinstr ) {
1909 		cur->u.state.instrs = (uint8 *) copyn((char *) sc->ttf_instrs, sc->ttf_instrs_len);
1910 		cur->u.state.instrs_len = sc->ttf_instrs_len;
1911 	    }
1912 	    cur->u.state.unicodeenc = sc->unicodeenc;
1913 	    if ( copymetadata && layer==ly_fore ) {
1914 		cur->u.state.charname = copy(sc->name);
1915 		cur->u.state.comment = copy(sc->comment);
1916 		cur->u.state.possub = PSTCopy(sc->possub,sc,NULL);
1917 	    } else {
1918 		cur->u.state.charname = NULL;
1919 		cur->u.state.comment = NULL;
1920 		cur->u.state.possub = NULL;
1921 	    }
1922 	} else {		/* Or just make a reference */
1923 	    cur->undotype = full==ct_reference ? ut_state : ut_statelookup;
1924 	    cur->u.state.refs = ref = RefCharCreate();
1925 	    ref->unicode_enc = sc->unicodeenc;
1926 	    ref->orig_pos = sc->orig_pos;
1927 	    ref->adobe_enc = getAdobeEnc(sc->name);
1928 	    ref->transform[0] = ref->transform[3] = 1.0;
1929 	}
1930 	if ( layer<sc->layer_cnt ) {
1931 	    cur->u.state.images = ImageListCopy(sc->layers[layer].images);
1932 	    BrushCopy(&cur->u.state.fill_brush, &sc->layers[layer].fill_brush,NULL);
1933 	    PenCopy(&cur->u.state.stroke_pen, &sc->layers[layer].stroke_pen,NULL);
1934 	    cur->u.state.dofill = sc->layers[layer].dofill;
1935 	    cur->u.state.dostroke = sc->layers[layer].dostroke;
1936 	    cur->u.state.fillfirst = sc->layers[layer].fillfirst;
1937 	}
1938 	cur->copied_from = sc->parent;
1939     }
1940 return( cur );
1941 }
1942 
SCCopyAll(SplineChar * sc,int layer,enum fvcopy_type full)1943 static Undoes *SCCopyAll(SplineChar *sc,int layer, enum fvcopy_type full) {
1944     Undoes *ret, *cur, *last=NULL;
1945 
1946     if ( sc!=NULL && sc->parent!=NULL && sc->parent->multilayer ) {
1947 	ret = chunkalloc(sizeof(Undoes));
1948 	if ( sc==NULL ) {
1949 	    ret->undotype = ut_noop;
1950 	} else if ( full==ct_reference || full==ct_lookups || !sc->parent->multilayer ) {	/* Make a reference */
1951 	    chunkfree(ret,sizeof(Undoes));
1952 	    ret = SCCopyAllLayer(sc,full,ly_fore );
1953 	} else {
1954 	    ret->undotype = ut_layers;
1955 	    for ( layer=ly_fore; layer<sc->layer_cnt; ++layer ) {
1956 		cur = SCCopyAllLayer(sc,full,layer);
1957 		if ( ret->u.multiple.mult==NULL )
1958 		    ret->u.multiple.mult = cur;
1959 		else
1960 		    last->next = cur;
1961 		last = cur;
1962 		/* full = ct_reference; 	Hunh? What was I thinking? */
1963 	    }
1964 	}
1965 return( ret );
1966     } else
1967 return( SCCopyAllLayer(sc,full,layer));
1968 }
1969 
SCCopyWidth(SplineChar * sc,enum undotype ut)1970 void SCCopyWidth(SplineChar *sc,enum undotype ut) {
1971     DBounds bb;
1972 
1973     CopyBufferFreeGrab();
1974 
1975     copybuffer.undotype = ut;
1976     copybuffer.copied_from = sc->parent;
1977     switch ( ut ) {
1978       case ut_width:
1979 	copybuffer.u.width = sc->width;
1980       break;
1981       case ut_vwidth:
1982 	copybuffer.u.width = sc->width;
1983       break;
1984       case ut_lbearing:
1985 	SplineCharFindBounds(sc,&bb);
1986 	copybuffer.u.lbearing = bb.minx;
1987       break;
1988       case ut_rbearing:
1989 	SplineCharFindBounds(sc,&bb);
1990 	copybuffer.u.rbearing = sc->width-bb.maxx;
1991       break;
1992       default:
1993       break;
1994     }
1995 }
1996 
CopyWidth(CharViewBase * cv,enum undotype ut)1997 void CopyWidth(CharViewBase *cv,enum undotype ut) {
1998     SCCopyWidth(cv->sc,ut);
1999 }
2000 
FindCharacter(SplineFont * into,SplineFont * from,RefChar * rf,SplineChar ** fromsc)2001 static SplineChar *FindCharacter(SplineFont *into, SplineFont *from,RefChar *rf,
2002 	SplineChar **fromsc) {
2003     const char *fromname = NULL;
2004 
2005     if ( !SFIsActive(from))
2006 	from = NULL;
2007     /* A subtler error: If we've closed the "from" font and subsequently */
2008     /*  opened the "into" font, there is a good chance they have the same */
2009     /*  address, and we just found ourselves. */
2010     /* More complicated cases are possible too, where from and into might */
2011     /*  be different -- but from has still been closed and reopened as something */
2012     /*  else */
2013     /* Should be fixed now. We clear copied_from when we close a font */
2014     if ( from!=NULL && (
2015 	    rf->orig_pos>=from->glyphcnt || from->glyphs[rf->orig_pos]==NULL ||
2016 	    from->glyphs[rf->orig_pos]->unicodeenc!=rf->unicode_enc ))
2017 	from = NULL;
2018 
2019     if ( fromsc!=NULL ) *fromsc = NULL;
2020 
2021     if ( from!=NULL && rf->orig_pos<from->glyphcnt && from->glyphs[rf->orig_pos]!=NULL ) {
2022 	fromname = from->glyphs[rf->orig_pos]->name;
2023 	if ( fromsc!=NULL )
2024 	    *fromsc = from->glyphs[rf->orig_pos];
2025     }
2026 
2027     if ( rf->orig_pos<into->glyphcnt && into->glyphs[rf->orig_pos]!=NULL &&
2028 	    ((into->glyphs[rf->orig_pos]->unicodeenc == rf->unicode_enc && rf->unicode_enc!=-1 ) ||
2029 	     (rf->unicode_enc==-1 && fromname!=NULL &&
2030 		     strcmp(into->glyphs[rf->orig_pos]->name,fromname)==0 )) )
2031 return( into->glyphs[rf->orig_pos] );
2032 
2033 return( SFGetChar( into, rf->unicode_enc, fromname ));
2034 }
2035 
SCDependsOnSC(SplineChar * parent,SplineChar * child)2036 int SCDependsOnSC(SplineChar *parent, SplineChar *child) {
2037     RefChar *ref;
2038 
2039     if ( parent==child )
2040 return( true );
2041     for ( ref=parent->layers[ly_fore].refs; ref!=NULL; ref=ref->next ) {
2042 	if ( SCDependsOnSC(ref->sc,child))
2043 return( true );
2044     }
2045 return( false );
2046 }
2047 
BCRefersToBC(BDFChar * parent,BDFChar * child)2048 static int BCRefersToBC( BDFChar *parent, BDFChar *child ) {
2049     BDFRefChar *head;
2050 
2051     if ( parent==child )
2052 return( true );
2053     for ( head=child->refs; head!=NULL; head=head->next ) {
2054 	if ( BCRefersToBC( parent,head->bdfc ))
2055 return( true );
2056     }
2057 return( false );
2058 }
2059 
PasteNonExistantRefCheck(SplineChar * sc,Undoes * paster,RefChar * ref,int * refstate)2060 static void PasteNonExistantRefCheck(SplineChar *sc,Undoes *paster,RefChar *ref,
2061 	int *refstate) {
2062     SplineChar *rsc=NULL, *fromsc;
2063     SplineSet *new, *spl;
2064     int yes = 3;
2065 
2066     rsc = FindCharacter(sc->parent,paster->copied_from,ref,&fromsc);
2067     if ( rsc!=NULL )
2068 	IError("We should never have called PasteNonExistantRefCheck if we had a glyph");
2069     if ( fromsc==NULL ) {
2070 	if ( !(*refstate&0x4) ) {
2071 	    char *buts[3];
2072 	    char buf[80]; const char *name;
2073 	    if ( ref->unicode_enc==-1 )
2074 		name = "<Unknown>";
2075 	    else
2076 		name = StdGlyphName(buf,ref->unicode_enc,ui_none,(NameList *) -1);
2077 	    buts[0] = _("Don't Warn Again"); buts[1] = _("_OK"); buts[2] = NULL;
2078 	    yes = ff_ask(_("Bad Reference"),(const char **) buts,1,1,_("You are attempting to paste a reference to %1$s into %2$s.\nBut %1$s does not exist in this font, nor can I find the original character referred to.\nIt will not be copied."),name,sc->name);
2079 	    if ( yes==0 )
2080 		*refstate |= 0x4;
2081 	}
2082     } else {
2083 	if ( !(*refstate&0x3) ) {
2084 	    char *buts[5];
2085 	    buts[0] = _("_Yes");
2086 	    buts[1] = _("Yes to _All");
2087 	    buts[2] = _("No _to All");
2088 	    buts[3] = _("_No");
2089 	    buts[4] = NULL;
2090 	    ff_progress_pause_timer();
2091 	    yes = ff_ask(_("Bad Reference"),(const char **) buts,0,3,_("You are attempting to paste a reference to %1$s into %2$s.\nBut %1$s does not exist in this font.\nWould you like to copy the original splines (or delete the reference)?"),fromsc->name,sc->name);
2092 	    ff_progress_resume_timer();
2093 	    if ( yes==1 )
2094 		*refstate |= 1;
2095 	    else if ( yes==2 )
2096 		*refstate |= 2;
2097 	}
2098 	if ( (*refstate&1) || yes<=1 ) {
2099 	    new = SplinePointListTransform(SplinePointListCopy(fromsc->layers[ly_fore].splines),ref->transform,tpt_AllPoints);
2100 	    SplinePointListSelect(new,true);
2101 	    if ( new!=NULL ) {
2102 		for ( spl = new; spl->next!=NULL; spl = spl->next );
2103 		spl->next = sc->layers[ly_fore].splines;
2104 		sc->layers[ly_fore].splines = new;
2105 	    }
2106 	}
2107     }
2108 }
2109 
SCGetPasteableClipboardType(int * type)2110 static const char* SCGetPasteableClipboardType(int* type) {
2111     static const char* mimes[] = {
2112         "image/svg+xml",
2113         "image/svg-xml",
2114         "image/svg",
2115         "image/x-inkscape-svg",
2116         "image/eps",
2117         "image/ps",
2118 #ifndef _NO_LIBPNG
2119         "image/png",
2120 #endif
2121         "image/bmp",
2122         NULL
2123     };
2124 
2125     if (no_windowing_ui) {
2126         return NULL;
2127     }
2128 
2129     for (int tp = 0; mimes[tp]; ++tp) {
2130         if (ClipboardHasType(mimes[tp])) {
2131             if (type) {
2132                 *type = tp;
2133             }
2134             return mimes[tp];
2135         }
2136     }
2137     return NULL;
2138 }
2139 
SCClipboardHasPasteableContents(void)2140 int SCClipboardHasPasteableContents(void) {
2141     return SCGetPasteableClipboardType(NULL) != NULL;
2142 }
2143 
SCCheckXClipboard(SplineChar * sc,int layer,int doclear)2144 static void SCCheckXClipboard(SplineChar *sc,int layer,int doclear) {
2145     int type; int32 len;
2146     const char *mime;
2147     char *paste;
2148     FILE *temp;
2149     GImage *image;
2150 
2151     if ((mime = SCGetPasteableClipboardType(&type)) == NULL) {
2152         return;
2153     }
2154 
2155     paste = ClipboardRequest(mime, &len);
2156     if ( paste==NULL )
2157 return;
2158 
2159     temp = GFileTmpfile();
2160     if ( temp!=NULL ) {
2161 	fwrite(paste,1,len,temp);
2162 	rewind(temp);
2163 	if ( type==4 || type==5 ) {	/* eps/ps */
2164 	    SCImportPSFile(sc,layer,temp,doclear,ImportParamsState());
2165 	} else if ( type<=3 ) {
2166 	    SCImportSVG(sc,layer,NULL,paste,len,doclear,ImportParamsState());
2167 	} else {
2168 #ifndef _NO_LIBPNG
2169 	    if ( type==6 )
2170 		image = GImageRead_Png(temp);
2171 	    else
2172 #endif
2173 		image = GImageRead_Bmp(temp);
2174 	    SCAddScaleImage(sc,image,doclear,layer,ImportParamsState());
2175 	}
2176 	fclose(temp);
2177     }
2178     free(paste);
2179 }
2180 
XClipFontToFFClip(void)2181 static void XClipFontToFFClip(void) {
2182     int32 len;
2183     int i;
2184     char *paste;
2185     SplineFont *sf;
2186     SplineChar *sc;
2187     Undoes *head=NULL, *last=NULL, *cur;
2188 
2189     paste = ClipboardRequest("application/x-font-svg",&len);
2190     if ( paste==NULL )
2191 return;
2192     sf = SFReadSVGMem(paste,0);
2193     if ( sf==NULL )
2194 return;
2195     for ( i=0; i<sf->glyphcnt; ++i ) if ( (sc=sf->glyphs[i])!=NULL ) {
2196 	if ( strcmp(sc->name,".notdef")==0 )
2197     continue;
2198 	cur = SCCopyAll(sc,ly_fore,ct_fullcopy);
2199 	if ( cur!=NULL ) {
2200 	    if ( head==NULL )
2201 		head = cur;
2202 	    else
2203 		last->next = cur;
2204 	    last = cur;
2205 	}
2206     }
2207 
2208     SplineFontFree(sf);
2209     free(paste);
2210 
2211     if ( head==NULL )
2212 return;
2213 
2214     CopyBufferFree();
2215     copybuffer.undotype = ut_multiple;
2216     copybuffer.u.multiple.mult = head;
2217     copybuffer.copied_from = NULL;
2218 }
2219 
PasteFigureScale(SplineFont * newsf,SplineFont * oldsf)2220 static double PasteFigureScale(SplineFont *newsf,SplineFont *oldsf) {
2221 
2222     if ( newsf==oldsf )
2223 return( 1.0 );
2224     if ( !SFIsActive(oldsf))		/* Font we copied from has been closed */
2225 return( 1.0 );
2226 
2227 return( (newsf->ascent+newsf->descent) / (double) (oldsf->ascent+oldsf->descent) );
2228 }
2229 
2230 static int anchor_lost_warning = false;
2231 
APMerge(SplineChar * sc,AnchorPoint * anchor)2232 static void APMerge(SplineChar *sc,AnchorPoint *anchor) {
2233     AnchorPoint *ap, *prev, *next, *test;
2234     AnchorClass *ac;
2235 
2236     if ( anchor==NULL )
2237 return;
2238     anchor = AnchorPointsCopy(anchor);
2239     /* If we pasted from one font to another, the anchor class list will be */
2240     /*  different. */
2241     for ( ac = sc->parent->anchor; ac!=NULL && ac!=anchor->anchor; ac=ac->next );
2242     if ( ac==NULL ) {		/* Into a different font. See if we can find a class with same name in new font */
2243 	prev = NULL;
2244 	for ( ap = anchor; ap!=NULL; ap=next ) {
2245 	    next = ap->next;
2246 	    for ( ac = sc->parent->anchor; ac!=NULL && strcmp(ac->name,ap->anchor->name)!=0; ac = ac->next );
2247 	    if ( ac!=NULL ) {
2248 		ap->anchor = ac;
2249 		prev = ap;
2250 	    } else {
2251 		if ( prev==NULL )
2252 		    anchor = next;
2253 		else
2254 		    prev->next = next;
2255 		ap->next = NULL;
2256 		AnchorPointsFree(ap);
2257 		anchor_lost_warning = true;
2258 	    }
2259 	}
2260 	if ( anchor_lost_warning )
2261 	    ff_post_error(_("Anchor Lost"),_("At least one anchor point was lost when pasting from one font to another because no matching anchor class could be found in the new font."));
2262 	if ( anchor==NULL )
2263 return;
2264     }
2265     if ( sc->anchor==NULL ) {
2266 	sc->anchor = anchor;
2267 return;
2268     }
2269 
2270     prev = NULL;
2271     for ( ap=anchor; ap!=NULL; ap=next ) {
2272 	next = ap->next;
2273 	for ( test=sc->anchor; test!=NULL; test=test->next )
2274 	    if ( test->anchor==ap->anchor ) {
2275 		if (( test->type==at_centry && ap->type==at_cexit) ||
2276 			(test->type==at_cexit && ap->type==at_centry))
2277 		    /* It's ok */;
2278 		else if ( test->type!=at_baselig || ap->type!=at_baselig ||
2279 			test->lig_index==ap->lig_index )
2280 	break;
2281 	    }
2282 	if ( test!=NULL ) {
2283 	    ff_post_error(_("Duplicate Anchor"),_("There is already an anchor point named %1$.40s in %2$.40s."),test->anchor->name,sc->name);
2284 	    if ( prev==NULL )
2285 		anchor = next;
2286 	    else
2287 		prev->next = next;
2288 	    ap->next = NULL;
2289 	    AnchorPointsFree(ap);
2290 	} else
2291 	    prev = ap;
2292     }
2293     if ( prev!=NULL ) {
2294 	prev->next = sc->anchor;
2295 	sc->anchor = anchor;
2296     }
2297 }
2298 
InstrsSameParent(SplineChar * sc,SplineFont * copied_from)2299 static int InstrsSameParent( SplineChar *sc, SplineFont *copied_from) {
2300     static SplineFont *dontask_parent = NULL, *dontask_copied_from;
2301     static int dontask_ret=0;
2302     char *buts[5];
2303     int ret;
2304 
2305     if ( sc->parent==copied_from )
2306 return( true );
2307     if ( sc->parent == dontask_parent && copied_from==dontask_copied_from )
2308 return( dontask_ret );
2309     buts[0] = _("_Yes"); buts[3] = _("_No");
2310     buts[1] = _("Yes to _All");
2311     buts[2] = _("No _to All");
2312     buts[4] = NULL;
2313     ret = ff_ask(_("Different Fonts"),(const char **) buts,0,3,_("You are attempting to paste glyph instructions from one font to another. Generally this will not work unless the 'prep', 'fpgm' and 'cvt ' tables are the same.\nDo you want to continue anyway?"));
2314     if ( ret==0 )
2315 return( true );
2316     if ( ret==3 )
2317 return( false );
2318     dontask_parent = sc->parent;
2319     dontask_copied_from = copied_from;
2320     dontask_ret = ret==1;
2321 return( dontask_ret );
2322 }
2323 
SCWasEmpty(SplineChar * sc,int skip_this_layer)2324 int SCWasEmpty(SplineChar *sc, int skip_this_layer) {
2325     int i;
2326 
2327     for ( i=ly_fore; i<sc->layer_cnt; ++i ) if ( i!=skip_this_layer && !sc->layers[i].background ) {
2328 	if ( sc->layers[i].refs!=NULL )
2329 return( false );
2330 	else if ( sc->layers[i].splines!=NULL ) {
2331 	    SplineSet *ss;
2332 	    for ( ss = sc->layers[i].splines; ss!=NULL; ss=ss->next ) {
2333 		if ( ss->first->prev!=NULL )
2334 return( false );			/* Closed contour */
2335 	    }
2336 	}
2337     }
2338 return( true );
2339 }
2340 
2341 /* when pasting from the fontview we do a clear first */
_PasteToSC(SplineChar * sc,Undoes * paster,FontViewBase * fv,int pasteinto,int layer,real trans[6],struct sfmergecontext * mc,int * refstate,int * already_complained)2342 static void _PasteToSC(SplineChar *sc,Undoes *paster,FontViewBase *fv,int pasteinto,
2343 	int layer, real trans[6], struct sfmergecontext *mc,int *refstate,
2344 	int *already_complained) {
2345     DBounds bb;
2346     real transform[6];
2347     int width, vwidth;
2348     int xoff=0, yoff=0;
2349     int was_empty;
2350     RefChar *ref;
2351 
2352     switch ( paster->undotype ) {
2353       case ut_noop:
2354       break;
2355       case ut_anchors:
2356 	if ( !sc->searcherdummy )
2357 	    APMerge(sc,paster->u.state.anchor);
2358       break;
2359       case ut_state: case ut_statehint: case ut_statename:
2360 	if ( paster->u.state.splines!=NULL || paster->u.state.refs!=NULL )
2361 	    sc->parent->onlybitmaps = false;
2362 	SCPreserveLayer(sc,layer,paster->undotype==ut_statehint);
2363 	width = paster->u.state.width;
2364 	vwidth = paster->u.state.vwidth;
2365 	was_empty = sc->hstem==NULL && sc->vstem==NULL && sc->layers[ly_fore].splines==NULL && sc->layers[ly_fore].refs == NULL;
2366 	if ( !pasteinto ) {
2367 	    if ( !sc->layers[layer].background &&
2368 		    SCWasEmpty(sc,pasteinto==0?layer:-1) ) {
2369 		if ( !sc->parent->onlybitmaps )
2370 		    SCSynchronizeWidth(sc,width,sc->width,fv);
2371 		sc->vwidth = vwidth;
2372 	    }
2373 	    SplinePointListsFree(sc->layers[layer].splines);
2374 	    sc->layers[layer].splines = NULL;
2375 	    ImageListsFree(sc->layers[layer].images);
2376 	    sc->layers[layer].images = NULL;
2377 	    SCRemoveLayerDependents(sc,layer);
2378 	    AnchorPointsFree(sc->anchor);
2379 	    sc->anchor = NULL;
2380 	    if ( paster->undotype==ut_statehint ) {
2381 		StemInfosFree(sc->hstem);
2382 		StemInfosFree(sc->vstem);
2383 		sc->hstem = sc->vstem = NULL;
2384 		sc->hconflicts = sc->vconflicts = false;
2385 	    }
2386 	    GradientFree(sc->layers[layer].fill_brush.gradient); sc->layers[layer].fill_brush.gradient = NULL;
2387 	    PatternFree(sc->layers[layer].fill_brush.pattern); sc->layers[layer].fill_brush.pattern = NULL;
2388 	    GradientFree(sc->layers[layer].stroke_pen.brush.gradient); sc->layers[layer].stroke_pen.brush.gradient = NULL;
2389 	    PatternFree(sc->layers[layer].stroke_pen.brush.pattern); sc->layers[layer].stroke_pen.brush.pattern = NULL;
2390 	    was_empty = true;
2391 	} else if ( pasteinto==2 ) {
2392 	    if ( sc->parent->hasvmetrics ) {
2393 		yoff = -sc->vwidth;
2394 		sc->vwidth += vwidth;
2395 	    } else if ( SCRightToLeft(sc) ) {
2396 		xoff = 0;
2397 		SCSynchronizeWidth(sc,sc->width+width,sc->width,fv);
2398 		transform[0] = transform[3] = 1; transform[1] = transform[2] = transform[5] = 0;
2399 		transform[4] = width;
2400 		sc->layers[layer].splines = SplinePointListTransform(
2401 			sc->layers[layer].splines,transform,tpt_AllPoints);
2402 		for ( ref = sc->layers[layer].refs; ref!=NULL; ref=ref->next ) {
2403 		    ref->transform[4] += width;
2404 		    SCReinstanciateRefChar(sc,ref,layer);
2405 		}
2406 	    } else {
2407 		xoff = sc->width;
2408 		SCSynchronizeWidth(sc,sc->width+width,sc->width,fv);
2409 	    }
2410 	} else if ( pasteinto==3 && trans!=NULL ) {
2411 	    xoff = trans[4]; yoff = trans[5];
2412 	}
2413 	if ( layer>=ly_fore && sc->layers[layer].splines==NULL &&
2414 		sc->layers[layer].refs==NULL && sc->layers[layer].images==NULL &&
2415 		sc->parent->multilayer ) {
2416 	    /* pasting into an empty layer sets the fill/stroke */
2417 	    BrushCopy(&sc->layers[layer].fill_brush, &paster->u.state.fill_brush,NULL);
2418 	    PenCopy(&sc->layers[layer].stroke_pen, &paster->u.state.stroke_pen,NULL);
2419 	    sc->layers[layer].dofill = paster->u.state.dofill;
2420 	    sc->layers[layer].dostroke = paster->u.state.dostroke;
2421 	    sc->layers[layer].fillfirst = paster->u.state.fillfirst;
2422 	}
2423 	if ( sc->layers[layer].order2 &&
2424 		!sc->layers[layer].background ) {
2425 	    if ( paster->undotype==ut_statehint ) {
2426 		/* if they are pasting instructions, I hope they know what */
2427 		/*  they are doing... */
2428 	    } else if (( paster->u.state.splines!=NULL || paster->u.state.refs!=NULL || pasteinto==0 ) &&
2429 		    !sc->instructions_out_of_date &&
2430 		    sc->ttf_instrs!=NULL ) {
2431 		/* The normal change check doesn't respond properly to pasting a reference */
2432 		SCClearInstrsOrMark(sc,layer,!*already_complained);
2433 		*already_complained = true;
2434 	    }
2435 	}
2436 	if ( paster->u.state.splines!=NULL ) {
2437 	    SplinePointList *temp = SplinePointListCopy(paster->u.state.splines);
2438 	    if ( (pasteinto==2 || pasteinto==3 ) && (xoff!=0 || yoff!=0)) {
2439 		transform[0] = transform[3] = 1; transform[1] = transform[2] = 0;
2440 		transform[4] = xoff; transform[5] = yoff;
2441 		temp = SplinePointListTransform(temp,transform,tpt_AllPoints);
2442 	    }
2443 	    if ( paster->was_order2 != sc->layers[layer].order2 )
2444 		temp = SplineSetsConvertOrder(temp,sc->layers[layer].order2);
2445 	    if ( sc->layers[layer].splines!=NULL ) {
2446 		SplinePointList *e = sc->layers[layer].splines;
2447 		while ( e->next!=NULL ) e = e->next;
2448 		e->next = temp;
2449 	    } else
2450 		sc->layers[layer].splines = temp;
2451 	}
2452 	if ( !sc->searcherdummy )
2453 	    APMerge(sc,paster->u.state.anchor);
2454 	if ( paster->u.state.images!=NULL && sc->parent->multilayer ) {
2455 	    ImageList *new, *cimg;
2456 	    for ( cimg = paster->u.state.images; cimg!=NULL; cimg=cimg->next ) {
2457 		new = malloc(sizeof(ImageList));
2458 		*new = *cimg;
2459 		new->selected = true;
2460 		new->next = sc->layers[layer].images;
2461 		sc->layers[layer].images = new;
2462 	    }
2463 	    SCOutOfDateBackground(sc);
2464 	}
2465 	if ( (paster->undotype==ut_statehint || paster->undotype==ut_statename ) &&
2466 		!sc->layers[layer].background ) {
2467 	    if ( !pasteinto ) {	/* Hints aren't meaningful unless we've cleared first */
2468 		ExtractHints(sc,paster->u.state.hints,true);
2469 		if ( sc->layers[layer].order2 ) {
2470 		    free(sc->ttf_instrs);
2471 		    if ( paster->u.state.instrs_len!=0 && sc->layers[layer].order2 &&
2472 			    InstrsSameParent(sc,paster->copied_from)) {
2473 			sc->ttf_instrs = (uint8 *) copyn((char *) paster->u.state.instrs,paster->u.state.instrs_len);
2474 			sc->ttf_instrs_len = paster->u.state.instrs_len;
2475 		    } else {
2476 			sc->ttf_instrs = NULL;
2477 			sc->ttf_instrs_len = 0;
2478 		    }
2479 		    sc->instructions_out_of_date = false;
2480 		}
2481 	    }
2482 	}
2483 	if ( paster->undotype==ut_statename ) {
2484 	    SCSetMetaData(sc,paster->u.state.charname,
2485 		    paster->u.state.unicodeenc==0xffff?-1:paster->u.state.unicodeenc,
2486 		    paster->u.state.comment);
2487 	    if ( SFIsActive(paster->copied_from) ) {
2488 		/* Only copy PSTs if we can find and translate their lookups */
2489 		PSTFree(sc->possub);
2490 		mc->sf_from = paster->copied_from; mc->sf_to = sc->parent;
2491 		sc->possub = PSTCopy(paster->u.state.possub,sc,mc);
2492 	    }
2493 	}
2494 	if ( paster->u.state.refs!=NULL ) {
2495 	    RefChar *last = sc->layers[layer].refs;
2496 	    while ( last != NULL && last->next != NULL) {
2497 	       last = last->next;
2498 	    }
2499 	    RefChar *new, *refs;
2500 	    SplineChar *rsc;
2501 	    double scale = PasteFigureScale(sc->parent,paster->copied_from);
2502 	    for ( refs = paster->u.state.refs; refs!=NULL; refs=refs->next ) {
2503 		if ( sc->views!=NULL && sc->views->container!=NULL ) {
2504 		    if ( sc->views->container->funcs->type == cvc_searcher ||
2505 			    sc->views->container->funcs->type == cvc_multiplepattern )
2506 			rsc = FindCharacter((sc->views->container->funcs->sf_of_container)(sc->views->container),
2507 				paster->copied_from,refs,NULL);
2508 		    else {
2509 			ff_post_error(_("Please don't do that"),_("You may not paste a reference into this window"));
2510 			rsc = (SplineChar *) -1;
2511 		    }
2512 		} else
2513 		    rsc = FindCharacter(sc->parent,paster->copied_from,refs,NULL);
2514 		if ( rsc==(SplineChar *) -1 )
2515 		    /* Error above */;
2516 		else if ( rsc!=NULL && SCDependsOnSC(rsc,sc))
2517 		    ff_post_error(_("Self-referential glyph"),_("Attempt to make a glyph that refers to itself"));
2518 		else if ( rsc!=NULL ) {
2519 		    new = RefCharCreate();
2520 		    free(new->layers);
2521 		    *new = *refs;
2522 		    new->transform[4] *= scale; new->transform[5] *= scale;
2523 		    new->transform[4] += xoff;  new->transform[5] += yoff;
2524 		    new->layers = NULL;
2525 		    new->layer_cnt = 0;
2526 		    new->sc = rsc;
2527 		    FFLIST_SINGLE_LINKED_APPEND( sc->layers[layer].refs, last, new );
2528 		    SCReinstanciateRefChar(sc,new,layer);
2529 		    SCMakeDependent(sc,rsc);
2530 		} else {
2531 		    PasteNonExistantRefCheck(sc,paster,refs,refstate);
2532 		}
2533 	    }
2534 	}
2535 	SCCharChangedUpdate(sc,layer);
2536 	/* Bug here. we are assuming that the pasted hints are up to date */
2537 	if ( was_empty && (sc->hstem!=NULL || sc->vstem!=NULL))
2538 	    sc->changedsincelasthinted = false;
2539       break;
2540       case ut_width:
2541 	SCPreserveWidth(sc);
2542 	SCSynchronizeWidth(sc,paster->u.width,sc->width,fv);
2543 	SCCharChangedUpdate(sc,layer);
2544       break;
2545       case ut_vwidth:
2546 	if ( !sc->parent->hasvmetrics )
2547 	    ff_post_error(_("No Vertical Metrics"),_("This font does not have vertical metrics enabled.\nUse Element->Font Info to enable them."));
2548 	else {
2549 	    SCPreserveVWidth(sc);
2550 	    sc->vwidth = paster->u.width;
2551 	    SCCharChangedUpdate(sc,layer);
2552 	}
2553       break;
2554       case ut_rbearing:
2555 	SCPreserveWidth(sc);
2556 	SplineCharFindBounds(sc,&bb);
2557 	SCSynchronizeWidth(sc,bb.maxx + paster->u.rbearing,sc->width,fv);
2558 	SCCharChangedUpdate(sc,layer);
2559       break;
2560       case ut_lbearing:
2561 	SplineCharFindBounds(sc,&bb);
2562 	transform[0] = transform[3] = 1.0;
2563 	transform[1] = transform[2] = transform[5] = 0;
2564 	transform[4] = paster->u.lbearing-bb.minx;
2565 	if ( transform[4]!=0 )
2566 	    FVTrans(fv,sc,transform,NULL,false);
2567 	/* FVTrans will preserve the state and update the chars */
2568       break;
2569       default:
2570       break;
2571     }
2572 }
2573 
PasteToSC(SplineChar * sc,int layer,Undoes * paster,FontViewBase * fv,int pasteinto,real trans[6],struct sfmergecontext * mc,int * refstate,int * already_complained)2574 static void PasteToSC(SplineChar *sc,int layer,Undoes *paster,FontViewBase *fv,
2575 	int pasteinto, real trans[6], struct sfmergecontext *mc,int *refstate,
2576 	int *already_complained) {
2577     if ( paster->undotype==ut_layers && sc->parent->multilayer ) {
2578 	int lc, start, layer;
2579 	Undoes *pl;
2580 	Layer *old = sc->layers;
2581 	for ( lc=0, pl = paster->u.multiple.mult; pl!=NULL; pl=pl->next, ++lc );
2582 	if ( !pasteinto ) {
2583 	    start = ly_fore;
2584 	    for ( layer=ly_fore; layer<sc->layer_cnt; ++layer ) {
2585 		SplinePointListsFree(sc->layers[layer].splines);
2586 		sc->layers[layer].splines = NULL;
2587 		ImageListsFree(sc->layers[layer].images);
2588 		sc->layers[layer].images = NULL;
2589 		SCRemoveLayerDependents(sc,layer);
2590 		GradientFree(sc->layers[layer].fill_brush.gradient); sc->layers[layer].fill_brush.gradient = NULL;
2591 		PatternFree(sc->layers[layer].fill_brush.pattern); sc->layers[layer].fill_brush.pattern = NULL;
2592 		GradientFree(sc->layers[layer].stroke_pen.brush.gradient); sc->layers[layer].stroke_pen.brush.gradient = NULL;
2593 		PatternFree(sc->layers[layer].stroke_pen.brush.pattern); sc->layers[layer].stroke_pen.brush.pattern = NULL;
2594 	    }
2595 	} else
2596 	    start = sc->layer_cnt;
2597 	if ( start+lc > sc->layer_cnt ) {
2598 	    sc->layers = realloc(sc->layers,(start+lc)*sizeof(Layer));
2599 	    for ( layer = sc->layer_cnt; layer<start+lc; ++layer )
2600 		LayerDefault(&sc->layers[layer]);
2601 	    sc->layer_cnt = start+lc;
2602 	}
2603 	for ( lc=0, pl = paster->u.multiple.mult; pl!=NULL; pl=pl->next, ++lc )
2604 	    _PasteToSC(sc,pl,fv,pasteinto,start+lc,trans,mc,refstate,already_complained);
2605 	SCMoreLayers(sc,old);
2606     } else if ( paster->undotype==ut_layers ) {
2607 	Undoes *pl;
2608 	for ( pl = paster->u.multiple.mult; pl!=NULL; pl=pl->next ) {
2609 	    _PasteToSC(sc,pl,fv,pasteinto,ly_fore,trans,mc,refstate,already_complained);
2610 	    pasteinto = true;		/* Merge other layers in */
2611 	}
2612     } else
2613 	_PasteToSC(sc,paster,fv,pasteinto,layer,trans,mc,refstate,already_complained);
2614 }
2615 
DevTabInto(struct vr * vr)2616 static void DevTabInto(struct vr *vr) {
2617     ValDevTab *adjust;
2618 
2619     if ( vr->adjust==NULL )
2620 return;		/* Nothing to do */
2621     adjust = chunkalloc(sizeof(ValDevTab));
2622     *adjust = *vr->adjust;
2623     if ( adjust->xadjust.corrections!=NULL ) {
2624 	adjust->xadjust.corrections = malloc(adjust->xadjust.last_pixel_size-adjust->xadjust.first_pixel_size+1);
2625 	memcpy(adjust->xadjust.corrections,vr->adjust->xadjust.corrections,adjust->xadjust.last_pixel_size-adjust->xadjust.first_pixel_size+1);
2626     }
2627     if ( adjust->yadjust.corrections!=NULL ) {
2628 	adjust->yadjust.corrections = malloc(adjust->yadjust.last_pixel_size-adjust->yadjust.first_pixel_size+1);
2629 	memcpy(adjust->yadjust.corrections,vr->adjust->yadjust.corrections,adjust->yadjust.last_pixel_size-adjust->yadjust.first_pixel_size+1);
2630     }
2631     if ( adjust->xadv.corrections!=NULL ) {
2632 	adjust->xadv.corrections = malloc(adjust->xadv.last_pixel_size-adjust->xadv.first_pixel_size+1);
2633 	memcpy(adjust->xadv.corrections,vr->adjust->xadv.corrections,adjust->xadv.last_pixel_size-adjust->xadv.first_pixel_size+1);
2634     }
2635     if ( adjust->yadv.corrections!=NULL ) {
2636 	adjust->yadv.corrections = malloc(adjust->yadv.last_pixel_size-adjust->yadv.first_pixel_size+1);
2637 	memcpy(adjust->yadv.corrections,vr->adjust->yadv.corrections,adjust->yadv.last_pixel_size-adjust->yadv.first_pixel_size+1);
2638     }
2639 }
2640 
PSTInto(SplineChar * sc,PST * pst,PST * frompst,struct lookup_subtable * sub)2641 static void PSTInto(SplineChar *sc,PST *pst,PST *frompst, struct lookup_subtable *sub) {
2642     if ( pst==NULL ) {
2643 	pst = chunkalloc(sizeof(PST));
2644 	*pst = *frompst;
2645 	pst->subtable = sub;
2646 	pst->next = sc->possub;
2647 	sc->possub = pst;
2648     } else {
2649 	if ( pst->type == pst_pair ) {
2650 	    free(pst->u.pair.paired);
2651 	    chunkfree(pst->u.pair.vr,sizeof(struct vr[2]));	/* We fail to free device tables */
2652 	} else if ( pst->type == pst_substitution || pst->type == pst_alternate ||
2653 		pst->type == pst_multiple || pst->type == pst_ligature )
2654 	    free(pst->u.subs.variant);
2655     }
2656     if ( pst->type == pst_substitution || pst->type == pst_alternate ||
2657 		pst->type == pst_multiple )
2658 	pst->u.subs.variant = copy( frompst->u.subs.variant );
2659     else if ( pst->type == pst_ligature ) {
2660 	pst->u.lig.components = copy( frompst->u.lig.components );
2661 	pst->u.lig.lig = sc;
2662     } else if ( pst->type==pst_pair ) {
2663 	pst->u.pair.paired = copy( frompst->u.pair.paired );
2664 	pst->u.pair.vr = chunkalloc(sizeof(struct vr[2]));
2665 	memcpy(pst->u.pair.vr,frompst->u.pair.vr,sizeof(struct vr[2]));
2666 	DevTabInto(&pst->u.pair.vr[0]);
2667 	DevTabInto(&pst->u.pair.vr[1]);
2668     } else if ( pst->type==pst_position ) {
2669 	memcpy(&pst->u.pos,&frompst->u.pos,sizeof(struct vr));
2670 	DevTabInto(&pst->u.pos);
2671     }
2672 }
2673 
APInto(SplineChar * sc,AnchorPoint * ap,AnchorPoint * fromap,AnchorClass * ac)2674 static void APInto(SplineChar *sc,AnchorPoint *ap,AnchorPoint *fromap,
2675 	AnchorClass *ac) {
2676     if ( ap==NULL ) {
2677 	ap = chunkalloc(sizeof(AnchorPoint));
2678 	*ap = *fromap;
2679 	ap->anchor = ac;
2680 	ap->next = sc->anchor;
2681 	sc->anchor = ap;
2682     } else {
2683 	free(ap->xadjust.corrections); free(ap->yadjust.corrections);
2684 	ap->xadjust = fromap->xadjust;
2685 	ap->yadjust = fromap->yadjust;
2686 	ap->me = fromap->me;
2687     }
2688     if ( fromap->xadjust.corrections!=NULL ) {
2689 	ap->xadjust.corrections = malloc(ap->xadjust.last_pixel_size-ap->xadjust.first_pixel_size+1);
2690 	memcpy(ap->xadjust.corrections,fromap->xadjust.corrections,ap->xadjust.last_pixel_size-ap->xadjust.first_pixel_size+1);
2691     }
2692     if ( fromap->yadjust.corrections!=NULL ) {
2693 	ap->yadjust.corrections = malloc(ap->yadjust.last_pixel_size-ap->yadjust.first_pixel_size+1);
2694 	memcpy(ap->yadjust.corrections,fromap->yadjust.corrections,ap->yadjust.last_pixel_size-ap->yadjust.first_pixel_size+1);
2695     }
2696 }
2697 
KPInto(SplineChar * owner,KernPair * kp,KernPair * fromkp,int isv,SplineChar * other,struct lookup_subtable * sub)2698 static void KPInto(SplineChar *owner,KernPair *kp,KernPair *fromkp,int isv,
2699 	SplineChar *other, struct lookup_subtable *sub) {
2700     if ( kp==NULL ) {
2701 	kp = chunkalloc(sizeof(KernPair));
2702 	*kp = *fromkp;
2703 	kp->subtable = sub;
2704 	if ( isv ) {
2705 	    kp->next = owner->vkerns;
2706 	    owner->vkerns = kp;
2707 	} else {
2708 	    kp->next = owner->kerns;
2709 	    owner->kerns = kp;
2710 	}
2711     }
2712     kp->sc = other;
2713     kp->off = fromkp->off;
2714     if ( kp->adjust!=NULL )
2715 	DeviceTableFree(kp->adjust);
2716     if ( fromkp->adjust!=NULL )
2717 	kp->adjust = DeviceTableCopy(fromkp->adjust);
2718     else
2719 	kp->adjust = NULL;
2720 }
2721 
SCPasteLookups(SplineChar * sc,SplineChar * fromsc,OTLookup ** list,OTLookup ** backpairlist,struct sfmergecontext * mc)2722 static void SCPasteLookups(SplineChar *sc,SplineChar *fromsc,
2723 	OTLookup **list, OTLookup **backpairlist, struct sfmergecontext *mc) {
2724     PST *frompst, *pst;
2725     int isv, gid;
2726     KernPair *fromkp, *kp;
2727     AnchorPoint *fromap, *ap;
2728     AnchorClass *ac;
2729     int i;
2730     OTLookup *otl;
2731     struct lookup_subtable *sub;
2732     SplineFont *fromsf;
2733     SplineChar *othersc;
2734     SplineChar *test, *test2;
2735     int changed = false;
2736 
2737     for ( frompst = fromsc->possub; frompst!=NULL; frompst=frompst->next ) {
2738 	if ( frompst->subtable==NULL )
2739     continue;
2740 	if ( frompst->type == pst_ligature && fromsc->parent==sc->parent )
2741     continue;
2742 	otl = frompst->subtable->lookup;
2743 	for ( i=0; list[i]!=NULL && list[i]!=otl; ++i );
2744 	if ( list[i]==NULL )
2745     continue;
2746 	sub = MCConvertSubtable(mc,frompst->subtable);
2747 	if ( otl->lookup_type!=gpos_pair ) {
2748 	    for ( pst=sc->possub; pst!=NULL && pst->subtable!=sub; pst=pst->next );
2749 	} else {
2750 	    for ( pst=sc->possub; pst!=NULL ; pst=pst->next ) {
2751 		if ( pst->subtable==sub &&
2752 			strcmp(frompst->u.pair.paired,pst->u.pair.paired)==0 )
2753 	    break;
2754 	    }
2755 	}
2756 	PSTInto(sc,pst,frompst,sub);
2757 	changed = true;
2758     }
2759 
2760     for ( fromap = fromsc->anchor; fromap!=NULL; fromap=fromap->next ) {
2761 	otl = fromap->anchor->subtable->lookup;
2762 	for ( i=0; list[i]!=NULL && list[i]!=otl; ++i );
2763 	if ( list[i]==NULL )
2764     continue;
2765 	ac = MCConvertAnchorClass(mc,fromap->anchor);
2766 	for ( ap=sc->anchor; ap!=NULL &&
2767 		!(ap->anchor==ac && ap->type==fromap->type && ap->lig_index==fromap->lig_index);
2768 		ap=ap->next );
2769 	APInto(sc,ap,fromap,ac);
2770 	changed = true;
2771     }
2772 
2773     for ( isv=0; isv<2; ++isv ) {
2774 	for ( fromkp = isv ? fromsc->vkerns : fromsc->kerns; fromkp!=NULL; fromkp=fromkp->next ) {
2775 	    otl = fromkp->subtable->lookup;
2776 	    for ( i=0; list[i]!=NULL && list[i]!=otl; ++i );
2777 	    if ( list[i]==NULL )
2778     continue;
2779 	    sub = MCConvertSubtable(mc,fromkp->subtable);
2780 	    if ( sub==NULL )
2781     continue;
2782 	    if ( fromsc->parent==sc->parent )
2783 		othersc = fromkp->sc;
2784 	    else
2785 		othersc = SFGetChar(sc->parent,fromkp->sc->unicodeenc,fromkp->sc->name);
2786 	    if ( othersc!=NULL ) {
2787 		for ( kp = isv ? sc->vkerns : sc->kerns; kp!=NULL; kp=kp->next ) {
2788 		    if ( kp->subtable == sub && kp->sc == othersc )
2789 		break;
2790 		}
2791 		KPInto(sc,kp,fromkp,isv,othersc,sub);
2792 		changed = true;
2793 	    }
2794 	}
2795 	if ( backpairlist==NULL )
2796     continue;
2797 	fromsf = fromsc->parent;
2798 	for ( gid=fromsf->glyphcnt-1; gid>=0; --gid ) if ( (test=fromsf->glyphs[gid])!=NULL ) {
2799 	    for ( fromkp = isv ? test->vkerns : test->kerns; fromkp!=NULL; fromkp=fromkp->next ) {
2800 		if ( fromkp->sc!=fromsc )
2801 	    continue;
2802 		otl = fromkp->subtable->lookup;
2803 		for ( i=0; backpairlist[i]!=NULL && backpairlist[i]!=otl; ++i );
2804 		if ( backpairlist[i]==NULL )
2805 	    continue;
2806 		sub = MCConvertSubtable(mc,fromkp->subtable);
2807 		if ( fromsf==sc->parent )
2808 		    test2 = test;
2809 		else
2810 		    test2 = SFGetChar(sc->parent,test->unicodeenc,test->name);
2811 		if ( test2==NULL || sub==NULL )
2812 	    continue;
2813 		for ( kp = isv ? test2->vkerns : test2->kerns; kp!=NULL; kp=kp->next ) {
2814 		    if ( kp->subtable==sub && kp->sc == sc )
2815 		break;
2816 		}
2817 		KPInto(test2,kp,fromkp,isv,sc,sub);
2818 		_SCCharChangedUpdate(test2,ly_none,2);
2819 	    }
2820 	}
2821     }
2822     if ( changed )
2823 	_SCCharChangedUpdate(sc,ly_none,2);
2824 }
2825 
SCPasteLookupsMid(SplineChar * sc,Undoes * paster,OTLookup ** list,OTLookup ** backpairlist,struct sfmergecontext * mc)2826 static void SCPasteLookupsMid(SplineChar *sc,Undoes *paster,
2827 	OTLookup **list, OTLookup **backpairlist, struct sfmergecontext *mc) {
2828     SplineChar *fromsc;
2829 
2830     (void) FindCharacter(sc->parent,paster->copied_from,
2831 	    paster->u.state.refs,&fromsc);
2832     if ( fromsc==NULL ) {
2833 	ff_post_error(_("Missing glyph"),_("Could not find original glyph"));
2834 return;
2835     }
2836     SCPasteLookups(sc,fromsc,list,backpairlist,mc);
2837 }
2838 
HasNonClass(OTLookup * otl)2839 static int HasNonClass(OTLookup *otl) {
2840     struct lookup_subtable *sub;
2841     for ( sub = otl->subtables; sub!=NULL; sub=sub->next )
2842 	if ( sub->kc==NULL )
2843 return( true );
2844 
2845 return( false );
2846 }
2847 
GetLookupsToCopy(SplineFont * sf,OTLookup *** backpairlist)2848 static OTLookup **GetLookupsToCopy(SplineFont *sf,OTLookup ***backpairlist) {
2849     int cnt, bcnt, ftot=0, doit, isgpos, i, ret;
2850     char **choices = NULL, *sel = NULL;
2851     OTLookup *otl, **list1=NULL, **list2=NULL, **list, **blist;
2852     char *buttons[3];
2853     buttons[0] = _("_OK");
2854     buttons[1] = _("_Cancel");
2855     buttons[2] = NULL;
2856 
2857     *backpairlist = NULL;
2858 
2859     for ( doit=0; doit<2; ++doit ) {
2860 	bcnt = cnt = 0;
2861 	for ( isgpos=0; isgpos<2; ++isgpos ) {
2862 	    for ( otl = isgpos ? sf->gpos_lookups : sf->gsub_lookups ; otl!=NULL; otl=otl->next ) {
2863 		if ( otl->lookup_type == gsub_single ||
2864 			otl->lookup_type == gsub_multiple ||
2865 			otl->lookup_type == gsub_alternate ||
2866 			otl->lookup_type == gsub_ligature ||
2867 			otl->lookup_type == gpos_single ||
2868 			otl->lookup_type == gpos_cursive ||
2869 			otl->lookup_type == gpos_mark2base ||
2870 			otl->lookup_type == gpos_mark2ligature ||
2871 			otl->lookup_type == gpos_mark2mark ||
2872 			(otl->lookup_type == gpos_pair && HasNonClass(otl))) {
2873 		    if ( doit ) {
2874 			list1[cnt] = otl;
2875 			choices[cnt++] = copy(otl->lookup_name);
2876 			if ( otl->lookup_type==gpos_pair ) {
2877 /* GT: I'm not happy with this phrase. Suggestions for improvements are welcome */
2878 /* GT:  Here I am generating a list of lookup names representing data that can */
2879 /* GT:  be copied from one glyph to another. For a kerning (pairwise) lookup */
2880 /* GT:  the first entry in the list (marked by the lookup name by itself) will */
2881 /* GT:  mean all data where the current glyph is the first glyph in a kerning */
2882 /* GT:  pair. But we can also (separately) copy data where the current glyph */
2883 /* GT:  is the second glyph in the kerning pair, and that's what this line */
2884 /* GT:  refers to. The "%s" will be filled in with the lookup name */
2885 			    char *format = _("Second glyph of %s");
2886 			    char *space = malloc(strlen(format)+strlen(otl->lookup_name)+1);
2887 			    sprintf(space, format, otl->lookup_name );
2888 			    list2[bcnt] = otl;
2889 			    choices[ftot+1+bcnt++] = space;
2890 			}
2891 		    } else {
2892 			++cnt;
2893 			if ( otl->lookup_type==gpos_pair )
2894 			    ++bcnt;
2895 		    }
2896 		}
2897 	    }
2898 	}
2899 	if ( cnt==0 ) {	/* If cnt==0 then bcnt must be too */
2900 	    ff_post_error(_("No Lookups"),_("No lookups to copy"));
2901 return( NULL );
2902 	}
2903 	if ( !doit ) {
2904 	    ftot = cnt;
2905 	    choices = malloc((cnt+bcnt+2)*sizeof(char *));
2906 	    sel = calloc(cnt+bcnt+1,1);
2907 	    list1 = malloc(cnt*sizeof(OTLookup *));
2908 	    if ( bcnt==0 ) {
2909 		choices[cnt] = NULL;
2910 		list2 = NULL;
2911 	    } else {
2912 		choices[cnt] = copy("-");
2913 		choices[bcnt+cnt+1] = NULL;
2914 		list2 = malloc(bcnt*sizeof(OTLookup *));
2915 	    }
2916 	}
2917     }
2918     ret = ff_choose_multiple(_("Lookups"),(const char **) choices,sel,bcnt==0?cnt: cnt+bcnt+1,
2919 	    buttons, _("Choose which lookups to copy"));
2920     list = NULL;
2921     if ( ret>=0 ) {
2922 	for ( i=cnt=0; i<ftot; ++i ) {
2923 	    if ( sel[i] )
2924 		++cnt;
2925 	}
2926 	list = malloc((cnt+1)*sizeof(OTLookup *));
2927 	for ( i=cnt=0; i<ftot; ++i ) {
2928 	    if ( sel[i] )
2929 		list[cnt++] = list1[i];
2930 	}
2931 	list[cnt] = NULL;
2932 	blist = NULL;
2933 	if ( bcnt!=0 ) {
2934 	    for ( i=cnt=0; i<bcnt; ++i ) {
2935 		if ( sel[i+ftot+1] )
2936 		    ++cnt;
2937 	    }
2938 	    if ( cnt!=0 ) {
2939 		blist = malloc((cnt+1)*sizeof(OTLookup *));
2940 		for ( i=cnt=0; i<bcnt; ++i ) {
2941 		    if ( sel[i+ftot+1] )
2942 			blist[cnt++] = list2[i];
2943 		}
2944 		blist[cnt] = NULL;
2945 	    }
2946 	    *backpairlist = blist;
2947 	}
2948 	if ( blist==NULL && list[0]==NULL ) {
2949 	    free(list);
2950 	    list = NULL;
2951 	}
2952     }
2953     free( sel );
2954     for ( i=0; choices[i]!=NULL; ++i )
2955 	free( choices[i]);
2956     free(choices);
2957     free(list1);
2958     free(list2);
2959 return( list );
2960 }
2961 
SCPasteLookupsTop(SplineChar * sc,Undoes * paster)2962 static void SCPasteLookupsTop(SplineChar *sc,Undoes *paster) {
2963     OTLookup **list, **backpairlist;
2964     SplineChar *fromsc;
2965     struct sfmergecontext mc;
2966 
2967     if ( paster->copied_from==NULL )
2968 return;
2969     (void) FindCharacter(sc->parent,paster->copied_from,
2970 	    paster->u.state.refs,&fromsc);
2971     if ( fromsc==NULL ) {
2972 	ff_post_error(_("Missing glyph"),_("Could not find original glyph"));
2973 return;
2974     }
2975     list = GetLookupsToCopy(fromsc->parent,&backpairlist);
2976     if ( list==NULL )
2977 return;
2978     memset(&mc,0,sizeof(mc));
2979     mc.sf_from = paster->copied_from; mc.sf_to = sc->parent;
2980     SCPasteLookups(sc,fromsc,list,backpairlist,&mc);
2981     free(list);
2982     free(backpairlist);
2983     SFFinishMergeContext(&mc);
2984 }
2985 
_PasteToCV(CharViewBase * cv,SplineChar * cvsc,Undoes * paster)2986 static void _PasteToCV(CharViewBase *cv,SplineChar *cvsc,Undoes *paster) {
2987     int refstate = 0;
2988     DBounds bb;
2989     real transform[6];
2990     int wasempty = false;
2991     int wasemptylayer = false;
2992     int layer = CVLayer(cv);
2993 
2994     if ( copybuffer.undotype == ut_none ) {
2995 	if ( cv->drawmode==dm_grid )
2996 return;
2997 	SCCheckXClipboard(cvsc,cv->layerheads[cv->drawmode]-cvsc->layers,false);
2998 return;
2999     }
3000 
3001     anchor_lost_warning = false;
3002 
3003     switch ( paster->undotype ) {
3004       case ut_noop:
3005       break;
3006       case ut_anchors:
3007 	APMerge(cvsc,paster->u.state.anchor);
3008       break;
3009       case ut_statelookup:
3010 	SCPasteLookupsTop(cvsc,paster);
3011       break;
3012       case ut_state: case ut_statehint: case ut_statename:
3013 	wasempty = SCWasEmpty(cvsc,-1);
3014 	wasemptylayer = layer!=ly_grid && cvsc->layers[layer].splines==NULL &&
3015 		cvsc->layers[layer].refs==NULL;
3016 	if ( wasemptylayer && cv->layerheads[dm_fore]->images==NULL &&
3017 		cvsc->parent->multilayer ) {
3018 	    /* pasting into an empty layer sets the fill/stroke */
3019 	    BrushCopy(&cv->layerheads[dm_fore]->fill_brush, &paster->u.state.fill_brush,NULL);
3020 	    PenCopy(&cv->layerheads[dm_fore]->stroke_pen, &paster->u.state.stroke_pen,NULL);
3021 	    cv->layerheads[dm_fore]->dofill = paster->u.state.dofill;
3022 	    cv->layerheads[dm_fore]->dostroke = paster->u.state.dostroke;
3023 	    cv->layerheads[dm_fore]->fillfirst = paster->u.state.fillfirst;
3024 	}
3025 	if ( cv->layerheads[cv->drawmode]->order2 &&
3026 		!cv->layerheads[cv->drawmode]->background ) {
3027 	    if ( paster->undotype==ut_statehint ) {
3028 		/* if they are pasting instructions, I hope they know what */
3029 		/*  they are doing... */
3030 	    } else if (( paster->u.state.splines!=NULL || paster->u.state.refs!=NULL ) &&
3031 		    !cvsc->instructions_out_of_date &&
3032 		    cvsc->ttf_instrs!=NULL ) {
3033 		/* The normal change check doesn't respond properly to pasting a reference */
3034 		SCClearInstrsOrMark(cvsc,CVLayer(cv),true);
3035 	    }
3036 	}
3037 	if ( paster->u.state.splines!=NULL ) {
3038 	    SplinePointList *spl, *new = SplinePointListCopy(paster->u.state.splines);
3039 	    if ( paster->was_order2 != cv->layerheads[cv->drawmode]->order2 )
3040 		new = SplineSetsConvertOrder(new,cv->layerheads[cv->drawmode]->order2 );
3041 	    SplinePointListSelect(new,true);
3042 	    for ( spl = new; spl->next!=NULL; spl = spl->next );
3043 	    spl->next = cv->layerheads[cv->drawmode]->splines;
3044 	    cv->layerheads[cv->drawmode]->splines = new;
3045 	}
3046 	if ( paster->undotype==ut_state && paster->u.state.images!=NULL ) {
3047 	    /* Can't paste images to foreground layer (unless type3 font) */
3048 	    ImageList *new, *cimg;
3049 	    int ly = cvsc->parent->multilayer || cv->layerheads[cv->drawmode]->background ?
3050 		    CVLayer(cv) : ly_back;
3051 	    if ( ly==ly_grid ) ly = ly_back;
3052 	    for ( cimg = paster->u.state.images; cimg!=NULL; cimg=cimg->next ) {
3053 		new = malloc(sizeof(ImageList));
3054 		*new = *cimg;
3055 		new->selected = true;
3056 		new->next = cvsc->layers[ly].images;
3057 		cvsc->layers[ly].images = new;
3058 	    }
3059 	    SCOutOfDateBackground(cvsc);
3060 	} else if ( paster->undotype==ut_statehint && cv->container==NULL &&
3061 		!cv->layerheads[cv->drawmode]->background ) {
3062 	    ExtractHints(cvsc,paster->u.state.hints,true);
3063 	    if ( cv->layerheads[cv->drawmode]->order2 ) {
3064 		free(cvsc->ttf_instrs);
3065 		if ( paster->u.state.instrs_len!=0 && cv->layerheads[cv->drawmode]->order2 &&
3066 			InstrsSameParent(cvsc,paster->copied_from)) {
3067 		    cvsc->ttf_instrs = (uint8 *) copyn((char *) paster->u.state.instrs,paster->u.state.instrs_len);
3068 		    cvsc->ttf_instrs_len = paster->u.state.instrs_len;
3069 		} else {
3070 		    cvsc->ttf_instrs = NULL;
3071 		    cvsc->ttf_instrs_len = 0;
3072 		}
3073 		cvsc->instructions_out_of_date = false;
3074 	    }
3075 	}
3076 	if ( paster->u.state.anchor!=NULL && !cvsc->searcherdummy )
3077 	    APMerge(cvsc,paster->u.state.anchor);
3078 	if ( paster->u.state.refs!=NULL && cv->drawmode!=dm_grid ) {
3079 	    RefChar *new, *refs;
3080 	    SplineChar *sc;
3081 	    for ( refs = paster->u.state.refs; refs!=NULL; refs=refs->next ) {
3082 		if ( cv->container==NULL ) {
3083 		    sc = FindCharacter(cvsc->parent,paster->copied_from,refs,NULL);
3084 		    if ( sc!=NULL && SCDependsOnSC(sc,cvsc)) {
3085 			ff_post_error(_("Self-referential character"),_("Attempt to make a character that refers to itself"));
3086 			sc = (SplineChar *) -1;
3087 		    }
3088 		} else if ( cv->container->funcs->type == cvc_searcher ||
3089 			cv->container->funcs->type == cvc_multiplepattern )
3090 		    sc = FindCharacter((cv->container->funcs->sf_of_container)(cv->container),paster->copied_from,refs,NULL);
3091 		else
3092 		    sc = (SplineChar *) -1;
3093 		if ( sc==(SplineChar *) -1 )
3094 		    /* Already complained */;
3095 		else if ( sc!=NULL ) {
3096 		    new = RefCharCreate();
3097 		    free(new->layers);
3098 		    *new = *refs;
3099 		    new->layers = NULL;
3100 		    new->layer_cnt = 0;
3101 		    new->sc = sc;
3102 		    new->selected = true;
3103 		    new->next = cvsc->layers[layer].refs;
3104 		    cvsc->layers[layer].refs = new;
3105 		    SCReinstanciateRefChar(cvsc,new,layer);
3106 		    SCMakeDependent(cvsc,sc);
3107 		} else {
3108 		    PasteNonExistantRefCheck(cvsc,paster,refs,&refstate);
3109 		}
3110 	    }
3111 	}
3112 	if ( paster->undotype==ut_statename ) {
3113 	    SCSetMetaData(cvsc,paster->u.state.charname,
3114 		    paster->u.state.unicodeenc==0xffff?-1:paster->u.state.unicodeenc,
3115 		    paster->u.state.comment);
3116 	    PSTFree(cvsc->possub);
3117 	    cvsc->possub = paster->u.state.possub;
3118 	}
3119 	if ( wasempty && layer>=ly_fore && !cvsc->layers[layer].background ) {
3120 	    /* Don't set the width in background or grid layers */
3121 	    /* Don't set the width if any potential foreground layer contained something */
3122 	    int width = paster->u.state.width;
3123 	    int vwidth = paster->u.state.vwidth;
3124 	    if ( cvsc->layers[ly_fore].splines==NULL && cvsc->layers[ly_fore].refs!=NULL ) {
3125 		RefChar *r;
3126 		/* If we copied a glyph containing refs from a different font */
3127 		/*  then the glyphs referred to will be in this font, and the */
3128 		/*  width should not be the original width, but the width in */
3129 		/*  the current font */
3130 		for ( r=cvsc->layers[ly_fore].refs; r!=NULL; r=r->next )
3131 		    if ( r->use_my_metrics ) {
3132 			width = r->sc->width;
3133 			vwidth = r->sc->vwidth;
3134 		break;
3135 		    }
3136 	    }
3137 	    SCSynchronizeWidth(cvsc,width,cvsc->width,NULL);
3138 	    cvsc->vwidth = vwidth;
3139 	}
3140       break;
3141       case ut_width:
3142 	SCSynchronizeWidth(cvsc,paster->u.width,cvsc->width,NULL);
3143       break;
3144       case ut_vwidth:
3145 	if ( !cvsc->parent->hasvmetrics )
3146 	    ff_post_error(_("No Vertical Metrics"),_("This font does not have vertical metrics enabled.\nUse Element->Font Info to enable them."));
3147 	else
3148 	    cvsc->vwidth = paster->u.state.vwidth;
3149       break;
3150       case ut_rbearing:
3151 	SplineCharFindBounds(cvsc,&bb);
3152 	SCSynchronizeWidth(cvsc,bb.maxx + paster->u.rbearing,cvsc->width,cv->fv);
3153       break;
3154       case ut_lbearing:
3155 	SplineCharFindBounds(cvsc,&bb);
3156 	transform[0] = transform[3] = 1.0;
3157 	transform[1] = transform[2] = transform[5] = 0;
3158 	transform[4] = paster->u.lbearing-bb.minx;
3159 	if ( transform[4]!=0 )
3160 	    FVTrans(cv->fv,cvsc,transform,NULL,false);
3161 	/* FVTrans will preserve the state and update the chars */
3162 	/* CVPaste depends on this behavior */
3163       break;
3164       case ut_composit:
3165 	if ( paster->u.composit.state!=NULL )
3166 	    _PasteToCV(cv,cvsc,paster->u.composit.state);
3167       break;
3168       case ut_multiple: case ut_layers:
3169 	_PasteToCV(cv,cvsc,paster->u.multiple.mult);
3170       break;
3171       default:
3172       break;
3173     }
3174 }
3175 
PasteToCV(CharViewBase * cv)3176 void PasteToCV(CharViewBase *cv) {
3177     _PasteToCV(cv,cv->sc,&copybuffer);
3178     if ( cv->sc->blended && cv->drawmode==dm_fore ) {
3179 	int j, gid = cv->sc->orig_pos;
3180 	MMSet *mm = cv->sc->parent->mm;
3181 	for ( j=0; j<mm->instance_count; ++j )
3182 	    _PasteToCV(cv,mm->instances[j]->glyphs[gid],&copybuffer);
3183     }
3184 }
3185 
3186 
ClipBoardToSplineSet(void)3187 SplineSet *ClipBoardToSplineSet(void) {
3188     Undoes *paster = &copybuffer;
3189 
3190     while ( paster!=NULL ) {
3191 	switch ( paster->undotype ) {
3192 	  default:
3193 	  case ut_noop: case ut_none:
3194 return( NULL );
3195 	  break;
3196 	  case ut_state: case ut_statehint: case ut_statename:
3197 	    if ( paster->u.state.refs!=NULL )
3198 return( NULL );
3199 
3200 return( paster->u.state.splines );
3201 	  break;
3202 	  case ut_width:
3203 return( NULL );
3204 	  case ut_vwidth:
3205 return( NULL );
3206 	  case ut_rbearing:
3207 return( NULL );
3208 	  case ut_lbearing:
3209 return( NULL );
3210 	  case ut_composit:
3211 	    paster = paster->u.composit.state;
3212 	  break;
3213 	  case ut_multiple:
3214 	    paster = paster->u.multiple.mult;
3215 	  break;
3216 	}
3217     }
3218 return( NULL );
3219 }
3220 
BCCopyAll(BDFChar * bc,int pixelsize,int depth,enum fvcopy_type full)3221 static Undoes *BCCopyAll(BDFChar *bc,int pixelsize, int depth, enum fvcopy_type full) {
3222     Undoes *cur;
3223     BDFRefChar *ref, *head;
3224 
3225     cur = chunkalloc(sizeof(Undoes));
3226     memset(&cur->u.bmpstate,'\0',sizeof( BDFChar ));
3227     if ( bc==NULL )
3228 	cur->undotype = ut_noop;
3229     else {
3230 	BCCompressBitmap(bc);
3231 	cur->undotype = ut_bitmap;
3232 	cur->u.bmpstate.width = bc->width;
3233 	if ( full==ct_fullcopy || full == ct_unlinkrefs ) {
3234 	    cur->u.bmpstate.xmin = bc->xmin;
3235 	    cur->u.bmpstate.xmax = bc->xmax;
3236 	    cur->u.bmpstate.ymin = bc->ymin;
3237 	    cur->u.bmpstate.ymax = bc->ymax;
3238 	    cur->u.bmpstate.bytes_per_line = bc->bytes_per_line;
3239 	    cur->u.bmpstate.bitmap = bmpcopy(bc->bitmap,bc->bytes_per_line,
3240 		bc->ymax-bc->ymin+1);
3241 	    cur->u.bmpstate.selection = BDFFloatCopy(bc->selection);
3242 
3243 	    for ( head = bc->refs; head != NULL; head = head->next ) {
3244 		ref = calloc( 1,sizeof( BDFRefChar ));
3245 		memcpy( ref,head,sizeof( BDFRefChar ));
3246 		ref->next = cur->u.bmpstate.refs;
3247 		cur->u.bmpstate.refs = ref;
3248 	    }
3249 	} else {		/* Or just make a reference */
3250 	    cur->u.bmpstate.bytes_per_line = 1;
3251 	    cur->u.bmpstate.bitmap = calloc(1,sizeof(uint8));
3252 
3253 	    ref = calloc(1,sizeof(BDFRefChar));
3254 	    ref->bdfc = bc;
3255 	    ref->xoff = 0; ref->yoff = 0;
3256 	    cur->u.bmpstate.refs = ref;
3257 	}
3258     }
3259     cur->u.bmpstate.pixelsize = pixelsize;
3260     cur->u.bmpstate.depth = depth;
3261 return( cur );
3262 }
3263 
BCCopySelected(BDFChar * bc,int pixelsize,int depth)3264 void BCCopySelected(BDFChar *bc,int pixelsize,int depth) {
3265     int has_selected_refs = false;
3266     BDFRefChar *head, *ref;
3267 
3268     CopyBufferFreeGrab();
3269 
3270     memset(&copybuffer,'\0',sizeof(copybuffer));
3271     if ( bc->selection!=NULL ) {
3272 	copybuffer.undotype = ut_bitmapsel;
3273 	copybuffer.u.bmpstate.selection = BDFFloatCopy(bc->selection);
3274     } else {
3275 	for ( head=bc->refs; head!=NULL; head=head->next ) if ( head->selected ) {
3276 	    has_selected_refs = true;
3277 	    ref = calloc( 1,sizeof( BDFRefChar ));
3278 	    memcpy( ref,head,sizeof( BDFRefChar ));
3279 	    ref->next = copybuffer.u.bmpstate.refs;
3280 	    copybuffer.u.bmpstate.refs = ref;
3281 	}
3282 	if ( has_selected_refs ) {
3283 	    copybuffer.undotype = ut_bitmap;
3284 	    copybuffer.u.bmpstate.width = bc->width;
3285 	    copybuffer.u.bmpstate.bytes_per_line = 1;
3286 	    copybuffer.u.bmpstate.bitmap = calloc(1,sizeof(uint8));
3287 	    copybuffer.u.bmpstate.selection = NULL;
3288 	} else {
3289 	    copybuffer.undotype = ut_bitmapsel;
3290 	    copybuffer.u.bmpstate.selection = BDFFloatCreate(bc,bc->xmin,bc->xmax,
3291 		bc->ymin,bc->ymax, false);
3292 	}
3293     }
3294     copybuffer.u.bmpstate.pixelsize = pixelsize;
3295     copybuffer.u.bmpstate.depth = depth;
3296 }
3297 
BCCopyReference(BDFChar * bc,int pixelsize,int depth)3298 void BCCopyReference(BDFChar *bc,int pixelsize,int depth) {
3299     Undoes *tmp;
3300 
3301     CopyBufferFreeGrab();
3302     tmp = BCCopyAll( bc,pixelsize,depth,ct_reference );
3303 
3304     memcpy( &copybuffer,tmp,sizeof( Undoes ));
3305     chunkfree( tmp,sizeof( Undoes ));
3306     XClipCheckEps();
3307 }
3308 
_PasteToBC(BDFChar * bc,int pixelsize,int depth,Undoes * paster,int clearfirst)3309 static void _PasteToBC(BDFChar *bc,int pixelsize, int depth, Undoes *paster, int clearfirst) {
3310     BDFRefChar *head, *cur;
3311 
3312     switch ( paster->undotype ) {
3313       case ut_noop:
3314       break;
3315       case ut_bitmapsel:
3316 	BCPreserveState(bc);
3317 	BCFlattenFloat(bc);
3318 	if ( clearfirst )
3319 	    memset(bc->bitmap,'\0',bc->bytes_per_line*(bc->ymax-bc->ymin+1));
3320 	bc->selection = BDFFloatConvert(paster->u.bmpstate.selection,depth,paster->u.bmpstate.depth);
3321 	BCCharChangedUpdate(bc);
3322       break;
3323       case ut_bitmap:
3324 	BCPreserveState(bc);
3325 	BCFlattenFloat(bc);
3326 	if ( clearfirst ) {
3327 	    for ( head = bc->refs; head != NULL; ) {
3328 		cur = head; head = head->next; free( cur );
3329 	    }
3330 	    bc->refs = NULL;
3331 	    memset(bc->bitmap,0,bc->bytes_per_line*(bc->ymax-bc->ymin+1));
3332 	    bc->width = paster->u.bmpstate.width;
3333 	}
3334 	BCPasteInto(bc,&paster->u.bmpstate,0,0, false, false);
3335 	for ( head = paster->u.bmpstate.refs; head != NULL; head = head->next ) {
3336 	    if ( BCRefersToBC( bc,head->bdfc )) {
3337 		ff_post_error(_("Self-referential glyph"),_("Attempt to make a glyph that refers to itself"));
3338 	    } else {
3339 		cur = calloc( 1,sizeof( BDFRefChar ));
3340 		memcpy( cur,head,sizeof( BDFRefChar ));
3341 		cur->next = bc->refs; bc->refs = cur;
3342 		BCMakeDependent( bc,head->bdfc );
3343 	    }
3344 	}
3345 
3346 	BCCompressBitmap(bc);
3347 	bc->selection = BDFFloatConvert(paster->u.bmpstate.selection,depth,paster->u.bmpstate.depth);
3348 	BCCharChangedUpdate(bc);
3349       break;
3350       case ut_composit:
3351 	/* if there's only one bitmap and no outline state (so we only copied a bitmap) */
3352 	/*  then paste that thing with no questions. Otherwise search for a */
3353 	/*  bitmap with the right pixel size. If we find it, paste it, else */
3354 	/*  noop */
3355 	if ( paster->u.composit.bitmaps==NULL )
3356 	    /* Nothing to be done */;
3357 	else if ( paster->u.composit.state==NULL && paster->u.composit.bitmaps->next==NULL )
3358 	    _PasteToBC(bc,pixelsize,depth,paster->u.composit.bitmaps,clearfirst);
3359 	else {
3360 	    Undoes *b;
3361 	    for ( b = paster->u.composit.bitmaps;
3362 		    b!=NULL && b->u.bmpstate.pixelsize!=pixelsize;
3363 		    b = b->next ) ;
3364 	    if ( b!=NULL )
3365 		_PasteToBC(bc,pixelsize,depth,b,clearfirst);
3366 	}
3367       break;
3368       case ut_multiple:
3369 	_PasteToBC(bc,pixelsize,depth,paster->u.multiple.mult,clearfirst);
3370       break;
3371       default:
3372       break;
3373     }
3374 }
3375 
PasteToBC(BDFChar * bc,int pixelsize,int depth)3376 void PasteToBC(BDFChar *bc,int pixelsize,int depth) {
3377     _PasteToBC(bc,pixelsize,depth,&copybuffer,false);
3378 }
3379 
FVCopyWidth(FontViewBase * fv,enum undotype ut)3380 void FVCopyWidth(FontViewBase *fv,enum undotype ut) {
3381     Undoes *head=NULL, *last=NULL, *cur;
3382     int i, any=false, gid;
3383     SplineChar *sc;
3384     DBounds bb;
3385 
3386     CopyBufferFreeGrab();
3387 
3388     for ( i=0; i<fv->map->enccount; ++i ) if ( fv->selected[i] ) {
3389 	any = true;
3390 	cur = chunkalloc(sizeof(Undoes));
3391 	cur->undotype = ut;
3392 	if ( (gid=fv->map->map[i])!=-1 && (sc=fv->sf->glyphs[gid])!=NULL ) {
3393 	    switch ( ut ) {
3394 	      case ut_width:
3395 		cur->u.width = sc->width;
3396 	      break;
3397 	      case ut_vwidth:
3398 		cur->u.width = sc->vwidth;
3399 	      break;
3400 	      case ut_lbearing:
3401 		SplineCharFindBounds(sc,&bb);
3402 		cur->u.lbearing = bb.minx;
3403 	      break;
3404 	      case ut_rbearing:
3405 		SplineCharFindBounds(sc,&bb);
3406 		cur->u.rbearing = sc->width-bb.maxx;
3407 	      break;
3408 	      default:
3409 	      break;
3410 	    }
3411 	} else
3412 	    cur->undotype = ut_noop;
3413 	if ( head==NULL )
3414 	    head = cur;
3415 	else
3416 	    last->next = cur;
3417 	last = cur;
3418     }
3419     copybuffer.undotype = ut_multiple;
3420     copybuffer.u.multiple.mult = head;
3421     copybuffer.copied_from = fv->sf;
3422     if ( !any )
3423 	LogError( _("No selection\n") );
3424 }
3425 
FVCopyAnchors(FontViewBase * fv)3426 void FVCopyAnchors(FontViewBase *fv) {
3427     Undoes *head=NULL, *last=NULL, *cur;
3428     int i, any=false, gid;
3429     SplineChar *sc;
3430 
3431     CopyBufferFreeGrab();
3432 
3433     for ( i=0; i<fv->map->enccount; ++i ) if ( fv->selected[i] ) {
3434 	any = true;
3435 	cur = chunkalloc(sizeof(Undoes));
3436 	if ( (gid=fv->map->map[i])!=-1 && (sc=fv->sf->glyphs[gid])!=NULL ) {
3437 	    cur->undotype = ut_anchors;
3438 	    cur->u.state.anchor = AnchorPointsCopy(sc->anchor);
3439 	} else
3440 	    cur->undotype = ut_noop;
3441 	if ( head==NULL )
3442 	    head = cur;
3443 	else
3444 	    last->next = cur;
3445 	last = cur;
3446     }
3447     copybuffer.undotype = ut_multiple;
3448     copybuffer.u.multiple.mult = head;
3449     copybuffer.copied_from = fv->sf;
3450     if ( !any )
3451 	LogError( _("No selection\n") );
3452 }
3453 
FVCopy(FontViewBase * fv,enum fvcopy_type fullcopy)3454 void FVCopy(FontViewBase *fv, enum fvcopy_type fullcopy) {
3455     int i, any = false;
3456     BDFFont *bdf;
3457     Undoes *head=NULL, *last=NULL, *cur;
3458     Undoes *bhead=NULL, *blast=NULL, *bcur;
3459     Undoes *state;
3460     int gid;
3461     SplineChar *sc;
3462     /* If fullcopy==ct_fullcopy copy the glyph as is. */
3463     /* If fullcopy==ct_reference put a reference to the glyph in the clipboard */
3464     /* If fullcopy==ct_lookups put a reference to the glyph in the clip but mark that we are only interested in its lookups */
3465     /* If fullcopy==ct_unlinkrefs copy the glyph, but unlink any references it contains */
3466     /*	so we end up with no references and a bunch of splines */
3467 
3468     for ( i=0; i<fv->map->enccount; ++i ) if ( fv->selected[i] ) {
3469 	any = true;
3470 	sc = (gid = fv->map->map[i])==-1 ? NULL : fv->sf->glyphs[gid];
3471 	if (( onlycopydisplayed && fv->active_bitmap==NULL ) || fullcopy==ct_lookups ) {
3472 	    cur = SCCopyAll(sc,fv->active_layer,fullcopy);
3473 	} else if ( onlycopydisplayed ) {
3474 	    cur = BCCopyAll(gid==-1?NULL:fv->active_bitmap->glyphs[gid],fv->active_bitmap->pixelsize,BDFDepth(fv->active_bitmap),fullcopy);
3475 	} else {
3476 	    state = SCCopyAll(sc,fv->active_layer,fullcopy);
3477 	    bhead = NULL;
3478 	    for ( bdf=fv->sf->bitmaps; bdf!=NULL; bdf = bdf->next ) {
3479 		BDFChar *bdfc = gid==-1 || gid>=bdf->glyphcnt? NULL : bdf->glyphs[gid];
3480 		bcur = BCCopyAll(bdfc,bdf->pixelsize,BDFDepth(bdf),fullcopy);
3481 		if ( bhead==NULL )
3482 		    bhead = bcur;
3483 		else
3484 		    blast->next = bcur;
3485 		blast = bcur;
3486 	    }
3487 	    if ( bhead!=NULL || state!=NULL ) {
3488 		cur = chunkalloc(sizeof(Undoes));
3489 		cur->undotype = ut_composit;
3490 		cur->u.composit.state = state;
3491 		cur->u.composit.bitmaps = bhead;
3492 	    } else
3493 		cur = NULL;
3494 	}
3495 	if ( cur!=NULL ) {
3496 	    if ( head==NULL )
3497 		head = cur;
3498 	    else
3499 		last->next = cur;
3500 	    last = cur;
3501 	}
3502     }
3503 
3504     if ( !any )
3505 	fprintf( stderr, "No selection\n" );
3506 
3507     if ( head==NULL )
3508 return;
3509     CopyBufferFreeGrab();
3510     copybuffer.undotype = ut_multiple;
3511     copybuffer.u.multiple.mult = head;
3512     copybuffer.copied_from = fv->sf;
3513 
3514     XClipCheckEps();
3515 }
3516 
MVCopyChar(FontViewBase * fv,BDFFont * mvbdf,SplineChar * sc,enum fvcopy_type fullcopy)3517 void MVCopyChar(FontViewBase *fv, BDFFont *mvbdf, SplineChar *sc, enum fvcopy_type fullcopy) {
3518     BDFFont *bdf;
3519     Undoes *cur=NULL;
3520     Undoes *bhead=NULL, *blast=NULL, *bcur;
3521     Undoes *state;
3522 
3523     if (( onlycopydisplayed && mvbdf==NULL ) || fullcopy == ct_lookups ) {
3524 	cur = SCCopyAll(sc,fv->active_layer,fullcopy);
3525     } else if ( onlycopydisplayed ) {
3526 	cur = BCCopyAll(BDFMakeGID(mvbdf,sc->orig_pos),mvbdf->pixelsize,BDFDepth(mvbdf),fullcopy);
3527     } else {
3528 	state = SCCopyAll(sc,fv->active_layer,fullcopy);
3529 	bhead = NULL;
3530 	for ( bdf=fv->sf->bitmaps; bdf!=NULL; bdf = bdf->next ) {
3531 	    bcur = BCCopyAll(BDFMakeGID(bdf,sc->orig_pos),bdf->pixelsize,BDFDepth(bdf),fullcopy);
3532 	    if ( bhead==NULL )
3533 		bhead = bcur;
3534 	    else
3535 		blast->next = bcur;
3536 	    blast = bcur;
3537 	}
3538 	if ( bhead!=NULL || state!=NULL ) {
3539 	    cur = chunkalloc(sizeof(Undoes));
3540 	    cur->undotype = ut_composit;
3541 	    cur->u.composit.state = state;
3542 	    cur->u.composit.bitmaps = bhead;
3543 	} else
3544 	    cur = NULL;
3545     }
3546 
3547     if ( cur==NULL )
3548 return;
3549     CopyBufferFreeGrab();
3550     copybuffer.undotype = ut_multiple;
3551     copybuffer.u.multiple.mult = cur;
3552 
3553     XClipCheckEps();
3554 }
3555 
BitmapCreateCheck(FontViewBase * fv,int * yestoall,int first,int pixelsize,int depth)3556 static BDFFont *BitmapCreateCheck(FontViewBase *fv,int *yestoall, int first, int pixelsize, int depth) {
3557     int yes = 0;
3558     BDFFont *bdf = NULL;
3559 
3560     if ( *yestoall>0 && first ) {
3561 	char *buts[5];
3562 	char buf[20];
3563 	if ( depth!=1 )
3564 	    sprintf( buf, "%d@%d", pixelsize, depth );
3565 	else
3566 	    sprintf( buf, "%d", pixelsize );
3567 	buts[0] = _("_Yes");
3568 	buts[1] = _("Yes to _All");
3569 	buts[2] = _("No _to All");
3570 	buts[3] = _("_No");
3571 	buts[4] = NULL;
3572 	yes = ff_ask(_("Bitmap Paste"),(const char **) buts,0,3,"The clipboard contains a bitmap character of size %s,\na size which is not in your database.\nWould you like to create a bitmap font of that size,\nor ignore this character?",buf);
3573 	if ( yes==1 )
3574 	    *yestoall = true;
3575 	else if ( yes==2 )
3576 	    *yestoall = -1;
3577 	else
3578 	    yes= yes!=3;
3579     }
3580     if ( yes==1 || *yestoall ) {
3581 	void *freetypecontext = FreeTypeFontContext(fv->sf,NULL,NULL,fv->active_layer);
3582 	if ( freetypecontext )
3583 	    bdf = SplineFontFreeTypeRasterize(freetypecontext,pixelsize,depth);
3584 	else
3585 	    bdf = SplineFontAntiAlias(fv->sf,fv->active_layer,pixelsize,1<<(depth/2));
3586 	bdf->next = fv->sf->bitmaps;
3587 	fv->sf->bitmaps = bdf;
3588 	fv->sf->changed = true;
3589 	SFOrderBitmapList(fv->sf);
3590     }
3591 return( bdf );
3592 }
3593 
copybufferHasLookups(Undoes * cb)3594 static int copybufferHasLookups(Undoes *cb) {
3595     if ( cb->undotype==ut_multiple )
3596 	cb = cb->u.multiple.mult;
3597 return( cb->undotype==ut_statelookup );
3598 }
3599 
PasteIntoFV(FontViewBase * fv,int pasteinto,real trans[6])3600 void PasteIntoFV(FontViewBase *fv,int pasteinto,real trans[6]) {
3601     Undoes *cur=NULL, *bmp;
3602     BDFFont *bdf;
3603     int i, j, cnt=0, gid;
3604     int yestoall=0, first=true;
3605     uint8 *oldsel = fv->selected;
3606     SplineFont *sf = fv->sf, *origsf = sf;
3607     MMSet *mm = sf->mm;
3608     struct sfmergecontext mc;
3609     OTLookup **list = NULL, **backpairlist=NULL;
3610     int refstate = 0, already_complained = 0;
3611 
3612     memset(&mc,0,sizeof(mc));
3613     mc.sf_to = fv->sf; mc.sf_from = copybuffer.copied_from;
3614 
3615     cur = &copybuffer;
3616     for ( i=0; i<fv->map->enccount; ++i ) if ( fv->selected[i] )
3617 	++cnt;
3618     if ( cnt==0 ) {
3619 	fprintf( stderr, "No Selection\n" );
3620 return;
3621     }
3622 
3623     if ( copybufferHasLookups(&copybuffer)) {
3624 	list = GetLookupsToCopy(copybuffer.copied_from,&backpairlist);
3625 	if ( list==NULL )
3626 return;
3627     }
3628 
3629     if ( copybuffer.undotype == ut_none && ClipboardHasType("application/x-font-svg"))
3630 	XClipFontToFFClip();
3631 
3632     if ( copybuffer.undotype == ut_none ) {
3633 	j = -1;
3634 	while ( 1 ) {
3635 	    for ( i=0; i<fv->map->enccount; ++i ) if ( fv->selected[i] )
3636 		SCCheckXClipboard(SFMakeChar(sf,fv->map,i),ly_fore,!pasteinto);
3637 	    ++j;
3638 	    if ( mm==NULL || mm->normal!=origsf || j>=mm->instance_count )
3639 	break;
3640 	    sf = mm->instances[j];
3641 	}
3642 return;
3643     }
3644 
3645     /* If they select exactly one character but there are more things in the */
3646     /*  copy buffer, then temporarily change the selection so that everything*/
3647     /*  in the copy buffer gets pasted (into chars immediately following sele*/
3648     /*  cted one (unless we run out of chars...)) */
3649     if ( cnt==1 && cur->undotype==ut_multiple && cur->u.multiple.mult->next!=NULL ) {
3650 	Undoes *tot; int j;
3651 	for ( cnt=0, tot=cur->u.multiple.mult; tot!=NULL; ++cnt, tot=tot->next );
3652 	fv->selected = malloc(fv->map->enccount);
3653 	memcpy(fv->selected,oldsel,fv->map->enccount);
3654 	for ( i=0; i<fv->map->enccount && !fv->selected[i]; ++i );
3655 	for ( j=0; j<cnt && i+j<fv->map->enccount; ++j )
3656 	    fv->selected[i+j] = 1;
3657 	cnt = j;
3658     }
3659 
3660     anchor_lost_warning = false;
3661     ff_progress_start_indicator(10,_("Pasting..."),_("Pasting..."),0,cnt,1);
3662 
3663     if ( cur->undotype==ut_multiple )
3664 	cur = cur->u.multiple.mult;
3665     /* This little gem of code is to keep us from throwing out forward */
3666     /*  references. Say we are pasting into both "i" and dotlessi (and */
3667     /*  dotlessi isn't defined yet) without this the paste to "i" will */
3668     /*  search for dotlessi, not find it and ignore the reference */
3669     if ( cur->undotype==ut_state || cur->undotype==ut_statehint || cur->undotype==ut_statename ||
3670 	    (cur->undotype==ut_composit && cur->u.composit.state!=NULL)) {
3671 	for ( i=0; i<fv->map->enccount; ++i )
3672 	    if ( fv->selected[i] && ((gid = fv->map->map[i])==-1 || sf->glyphs[gid]==NULL ))
3673 		SFMakeChar(sf,fv->map,i);
3674     }
3675     cur = NULL;
3676 
3677     for ( i=0; i<fv->map->enccount; ++i ) if ( fv->selected[i] ) {
3678 	j=-1;
3679 	if ( cur==NULL ) {
3680 	    cur = &copybuffer;
3681 	    if ( cur->undotype==ut_multiple )
3682 		cur = cur->u.multiple.mult;
3683 	}
3684 	while ( 1 ) {
3685 	    switch ( cur->undotype ) {
3686 	      case ut_noop:
3687 	      break;
3688 	      case ut_statelookup:
3689 		SCPasteLookupsMid(SFMakeChar(sf,fv->map,i),cur,list,backpairlist,&mc);
3690 	      break;
3691 	      case ut_state: case ut_width: case ut_vwidth:
3692 	      case ut_lbearing: case ut_rbearing:
3693 	      case ut_statehint: case ut_statename:
3694 	      case ut_layers: case ut_anchors:
3695 		if ( !sf->hasvmetrics && cur->undotype==ut_vwidth) {
3696 		    ff_post_error(_("No Vertical Metrics"),_("This font does not have vertical metrics enabled.\nUse Element->Font Info to enable them."));
3697  goto err;
3698 		}
3699 		PasteToSC(SFMakeChar(sf,fv->map,i),fv->active_layer,cur,fv,pasteinto,trans,&mc,&refstate,&already_complained);
3700 	      break;
3701 	      case ut_bitmapsel: case ut_bitmap:
3702 		if ( onlycopydisplayed && fv->active_bitmap!=NULL )
3703 		    _PasteToBC(BDFMakeChar(fv->active_bitmap,fv->map,i),fv->active_bitmap->pixelsize,BDFDepth(fv->active_bitmap),cur,!pasteinto);
3704 		else {
3705 		    for ( bdf=sf->bitmaps; bdf!=NULL && (bdf->pixelsize!=cur->u.bmpstate.pixelsize || BDFDepth(bdf)!=cur->u.bmpstate.depth); bdf=bdf->next );
3706 		    if ( bdf==NULL ) {
3707 			bdf = BitmapCreateCheck(fv,&yestoall,first,cur->u.bmpstate.pixelsize,cur->u.bmpstate.depth);
3708 			first = false;
3709 		    }
3710 		    if ( bdf!=NULL )
3711 			_PasteToBC(BDFMakeChar(bdf,fv->map,i),bdf->pixelsize,BDFDepth(bdf),cur,!pasteinto);
3712 		}
3713 	      break;
3714 	      case ut_composit:
3715 		if ( cur->u.composit.state!=NULL )
3716 		    PasteToSC(SFMakeChar(sf,fv->map,i),fv->active_layer,cur->u.composit.state,fv,pasteinto,trans,&mc,&refstate,&already_complained);
3717 		for ( bmp=cur->u.composit.bitmaps; bmp!=NULL; bmp = bmp->next ) {
3718 		    for ( bdf=sf->bitmaps; bdf!=NULL &&
3719 			    (bdf->pixelsize!=bmp->u.bmpstate.pixelsize || BDFDepth(bdf)!=bmp->u.bmpstate.depth);
3720 			    bdf=bdf->next );
3721 		    if ( bdf==NULL )
3722 			bdf = BitmapCreateCheck(fv,&yestoall,first,bmp->u.bmpstate.pixelsize,bmp->u.bmpstate.depth);
3723 		    if ( bdf!=NULL )
3724 			_PasteToBC(BDFMakeChar(bdf,fv->map,i),bdf->pixelsize,BDFDepth(bdf),bmp,!pasteinto);
3725 		}
3726 		first = false;
3727 	      break;
3728 	      default:
3729 	      break;
3730 	    }
3731 	    ++j;
3732 	    if ( mm==NULL || mm->normal!=origsf || j>=mm->instance_count )
3733 	break;
3734 	    sf = mm->instances[j];
3735 	}
3736 	cur = cur->next;
3737 	if ( !ff_progress_next())
3738     break;
3739     }
3740     /* If we copy glyphs from one font to another, and if some of those glyphs*/
3741     /*  contain references, and the width of the original glyph is the same as*/
3742     /*  the width of the original referred character, then we should make sure */
3743     /*  that the new width of the glyph is the same as the current width of   */
3744     /*  the referred char. We can't do this earlier because of foreward refs.  */
3745     for ( i=0; i<fv->map->enccount; ++i ) if ( fv->selected[i] ) {
3746 	SplineChar *sc = SFMakeChar(sf,fv->map,i);
3747 	if ( sc->layers[ly_fore].refs!=NULL && sc->layers[ly_fore].splines==NULL ) {
3748 	    RefChar *r;
3749 	    for ( r=sc->layers[ly_fore].refs; r!=NULL; r=r->next ) {
3750 		if ( r->use_my_metrics ) {
3751 		    sc->vwidth = r->sc->vwidth;
3752 		    if ( sc->width!=r->sc->width )
3753 			SCSynchronizeWidth(sc,r->sc->width,sc->width,NULL);
3754 		}
3755 	    }
3756 	}
3757     }
3758  err:
3759     ff_progress_end_indicator();
3760     if ( oldsel!=fv->selected )
3761 	free(oldsel);
3762     SFFinishMergeContext(&mc);
3763     free(list); free(backpairlist);
3764 }
3765 
PasteIntoMV(FontViewBase * fv,BDFFont * mvbdf,SplineChar * sc,int doclear)3766 void PasteIntoMV(FontViewBase *fv, BDFFont *mvbdf,SplineChar *sc, int doclear) {
3767     Undoes *cur=NULL, *bmp;
3768     BDFFont *bdf;
3769     int yestoall=0, first=true;
3770     struct sfmergecontext mc;
3771     int refstate = 0, already_complained = 0;
3772 
3773     memset(&mc,0,sizeof(mc));
3774     mc.sf_to = fv->sf;
3775 
3776     cur = &copybuffer;
3777 
3778     if ( copybuffer.undotype == ut_none ) {
3779 	SCCheckXClipboard(sc,ly_fore,doclear);
3780 return;
3781     }
3782 
3783     if ( cur->undotype==ut_multiple )
3784 	cur = cur->u.multiple.mult;
3785     switch ( cur->undotype ) {
3786       case ut_noop:
3787       break;
3788       case ut_state: case ut_width: case ut_vwidth:
3789       case ut_lbearing: case ut_rbearing:
3790       case ut_statehint: case ut_statename:
3791 	if ( !fv->sf->hasvmetrics && cur->undotype==ut_vwidth) {
3792 	    ff_post_error(_("No Vertical Metrics"),_("This font does not have vertical metrics enabled.\nUse Element->Font Info to enable them."));
3793 return;
3794 	}
3795 	PasteToSC(sc,fv->active_layer,cur,fv,!doclear,NULL,&mc,&refstate,&already_complained);
3796       break;
3797       case ut_bitmapsel: case ut_bitmap:
3798 	if ( onlycopydisplayed && mvbdf!=NULL )
3799 	    _PasteToBC(BDFMakeChar(mvbdf,fv->map,fv->map->backmap[sc->orig_pos]),mvbdf->pixelsize,BDFDepth(mvbdf),cur,doclear);
3800 	else {
3801 	    for ( bdf=fv->sf->bitmaps; bdf!=NULL &&
3802 		    (bdf->pixelsize!=cur->u.bmpstate.pixelsize || BDFDepth(bdf)!=cur->u.bmpstate.depth);
3803 		    bdf=bdf->next );
3804 	    if ( bdf==NULL ) {
3805 		bdf = BitmapCreateCheck(fv,&yestoall,first,cur->u.bmpstate.pixelsize,cur->u.bmpstate.depth);
3806 		first = false;
3807 	    }
3808 	    if ( bdf!=NULL )
3809 		_PasteToBC(BDFMakeChar(bdf,fv->map,fv->map->backmap[sc->orig_pos]),bdf->pixelsize,BDFDepth(bdf),cur,doclear);
3810 	}
3811       break;
3812       case ut_composit:
3813 	if ( cur->u.composit.state!=NULL )
3814 	    PasteToSC(sc,fv->active_layer,cur->u.composit.state,fv,!doclear,NULL,&mc,&refstate,&already_complained);
3815 	for ( bmp=cur->u.composit.bitmaps; bmp!=NULL; bmp = bmp->next ) {
3816 	    for ( bdf=fv->sf->bitmaps; bdf!=NULL &&
3817 		    (bdf->pixelsize!=bmp->u.bmpstate.pixelsize || BDFDepth(bdf)!=bmp->u.bmpstate.depth);
3818 		    bdf=bdf->next );
3819 	    if ( bdf==NULL )
3820 		bdf = BitmapCreateCheck(fv,&yestoall,first,bmp->u.bmpstate.pixelsize,bmp->u.bmpstate.depth);
3821 	    if ( bdf!=NULL )
3822 		_PasteToBC(BDFMakeChar(bdf,fv->map,fv->map->backmap[sc->orig_pos]),bdf->pixelsize,BDFDepth(bdf),bmp,doclear);
3823 	}
3824 	first = false;
3825       break;
3826       default:
3827       break;
3828     }
3829     SFFinishMergeContext(&mc);
3830 }
3831 
3832 /* Look through the copy buffer. If it wasn't copied from the given font, then */
3833 /*  we can stop. Otherwise: */
3834 /*	If "from" is NULL, then remove all anchorpoints from the buffer */
3835 /*	If "into" is NULL, then remove all anchorpoints with class "from" */
3836 /*	Else replace the anchor class of all anchorpoints with class "from" with "info" */
_PasteAnchorClassManip(SplineFont * sf,AnchorClass * into,AnchorClass * from)3837 static void _PasteAnchorClassManip(SplineFont *sf,AnchorClass *into,AnchorClass *from) {
3838     Undoes *cur = &copybuffer, *temp;
3839 
3840     if ( cur->undotype==ut_multiple )
3841 	cur = cur->u.multiple.mult;
3842     while ( cur!=NULL ) {
3843 	temp = cur;
3844 	switch ( temp->undotype ) {
3845 	  case ut_composit:
3846 	    if ( temp->u.composit.state==NULL )
3847 	break;
3848 	    temp = temp->u.composit.state;
3849 	    /* Fall through */
3850 	  case ut_state: case ut_statehint: case ut_statename:
3851 	    if ( temp->copied_from!=sf )
3852 return;
3853 	    if ( from==NULL ) {
3854 		AnchorPointsFree(temp->u.state.anchor);
3855 		temp->u.state.anchor = NULL;
3856 	    } else
3857 		temp->u.state.anchor = APAnchorClassMerge(temp->u.state.anchor,into,from);
3858 	  break;
3859 	  default:
3860 	  break;
3861 	}
3862 	cur=cur->next;
3863     }
3864 }
3865 
PasteRemoveSFAnchors(SplineFont * sf)3866 void PasteRemoveSFAnchors(SplineFont *sf) {
3867     _PasteAnchorClassManip(sf,NULL,NULL);
3868 }
3869 
PasteAnchorClassMerge(SplineFont * sf,AnchorClass * into,AnchorClass * from)3870 void PasteAnchorClassMerge(SplineFont *sf,AnchorClass *into,AnchorClass *from) {
3871     _PasteAnchorClassManip(sf,into,from);
3872 }
3873 
PasteRemoveAnchorClass(SplineFont * sf,AnchorClass * dying)3874 void PasteRemoveAnchorClass(SplineFont *sf,AnchorClass *dying) {
3875     _PasteAnchorClassManip(sf,NULL,dying);
3876 }
3877 
UndoToString(SplineChar * sc,Undoes * undo)3878 char* UndoToString( SplineChar* sc, Undoes *undo )
3879 {
3880     int idx = 0;
3881     char filename[PATH_MAX];
3882     snprintf(filename, PATH_MAX, "/tmp/fontforge-undo-to-string.sfd");
3883     FILE* f = fopen( filename, "w" );
3884     SFDDumpUndo( f, sc, undo, "Undo", idx );
3885     fclose(f);
3886     char* sfd = GFileReadAll( filename );
3887     return sfd;
3888 }
3889 
dumpUndoChain(char * msg,SplineChar * sc,Undoes * undo)3890 void dumpUndoChain( char* msg, SplineChar* sc, Undoes *undo )
3891 {
3892     int idx = 0;
3893 
3894     printf("dumpUndoChain(start) %s\n", msg );
3895     for( ; undo; undo = undo->next, idx++ )
3896     {
3897 	char* str = UndoToString( sc, undo );
3898 	printf("\n\n*** undo: %d\n%s\n", idx, str );
3899     }
3900     printf("dumpUndoChain(end) %s\n", msg );
3901 }
3902 
3903 
3904