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(©buffer,'\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 = ©buffer;
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 = ©buffer;
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 = ©buffer;
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 = ©buffer, *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 = ©buffer;
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 = ©buffer;
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",©buffer,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",©buffer,0,sizeof(char),
1628 copybuffer2eps,noop);
1629 ClipboardAddDataType("image/svg+xml",©buffer,0,sizeof(char),
1630 copybuffer2svg,noop);
1631 ClipboardAddDataType("image/svg",©buffer,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",©buffer,0,sizeof(char),
1638 copybufferPt2str,noop);
1639 else if ( cur->undotype==ut_statename )
1640 ClipboardAddDataType("STRING",©buffer,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 = ©buffer;
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 = ©buffer;
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 = ©buffer;
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 = ©buffer;
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 = ©buffer;
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( ©buffer );
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(©buffer,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(©buffer.u.state.fill_brush, &sc->layers[ly_fore].fill_brush,NULL);
1792 PenCopy(©buffer.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(©buffer.u.state.fill_brush, &cv->layerheads[cv->drawmode]->fill_brush,NULL);
1856 PenCopy(©buffer.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,©buffer);
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],©buffer);
3183 }
3184 }
3185
3186
ClipBoardToSplineSet(void)3187 SplineSet *ClipBoardToSplineSet(void) {
3188 Undoes *paster = ©buffer;
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(©buffer,'\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( ©buffer,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,©buffer,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 = ©buffer;
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(©buffer)) {
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 = ©buffer;
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 = ©buffer;
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 = ©buffer, *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