1 /* -*- coding: utf-8 -*- */
2 /* Copyright (C) 2000-2012 by George Williams */
3 /*
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are met:
6
7 * Redistributions of source code must retain the above copyright notice, this
8 * list of conditions and the following disclaimer.
9
10 * Redistributions in binary form must reproduce the above copyright notice,
11 * this list of conditions and the following disclaimer in the documentation
12 * and/or other materials provided with the distribution.
13
14 * The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
18 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
19 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
20 * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
22 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
23 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
24 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
25 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
26 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29 #include <fontforge-config.h>
30
31 #include "autohint.h"
32 #include "autosave.h"
33 #include "baseviews.h"
34 #include "bitmapchar.h"
35 #include "bvedit.h"
36 #include "chardata.h"
37 #include "cvundoes.h"
38 #include "encoding.h"
39 #include "fontforge.h"
40 #include "fvcomposite.h"
41 #include "fvfonts.h"
42 #include "gfile.h"
43 #include "gio.h"
44 #include "gresource.h"
45 #include "groups.h"
46 #include "namelist.h"
47 #include "psfont.h"
48 #include "pua.h"
49 #include "scripting.h"
50 #include "sfd.h"
51 #include "spiro.h"
52 #include "splineoverlap.h"
53 #include "splinesaveafm.h"
54 #include "splineutil.h"
55 #include "splineutil2.h"
56 #include "ustring.h"
57 #include "utype.h"
58
59 #include <math.h>
60 #include <unistd.h>
61
62 static FontViewBase *fv_list=NULL;
63
64 extern int onlycopydisplayed;
65 float joinsnap=0;
66
SCUnselectedDependents(FontViewBase * fv,SplineChar * sc)67 static int SCUnselectedDependents(FontViewBase *fv, SplineChar *sc) {
68 struct splinecharlist *dep;
69
70 if ( sc == NULL )
71 return( false );
72
73 for ( dep=sc->dependents; dep!=NULL; dep=dep->next ) {
74 if ( !fv->selected[fv->map->backmap[dep->sc->orig_pos]] )
75 return( true );
76 if ( SCUnselectedDependents(fv,dep->sc))
77 return( true );
78 }
79 return( false );
80 }
81
BCUnselectedDependents(FontViewBase * fv,BDFChar * bc)82 static int BCUnselectedDependents(FontViewBase *fv, BDFChar *bc) {
83 struct bdfcharlist *dep;
84
85 if ( bc == NULL )
86 return( false );
87
88 for ( dep=bc->dependents; dep!=NULL; dep=dep->next ) {
89 if ( !fv->selected[fv->map->backmap[dep->bc->orig_pos]] )
90 return( true );
91 if ( BCUnselectedDependents(fv,dep->bc))
92 return( true );
93 }
94 return( false );
95 }
96
UnselectedDependents(FontViewBase * fv,int gid)97 static int UnselectedDependents(FontViewBase *fv,int gid) {
98 int ret = false;
99 BDFFont *bdf;
100
101 if ( onlycopydisplayed && fv->active_bitmap == NULL ) {
102 ret = SCUnselectedDependents( fv,fv->sf->glyphs[gid] );
103 } else if ( onlycopydisplayed ) {
104 ret = BCUnselectedDependents( fv,fv->active_bitmap->glyphs[gid] );
105 } else {
106 ret = SCUnselectedDependents( fv,fv->sf->glyphs[gid] );
107 for ( bdf=fv->sf->cidmaster?fv->sf->cidmaster->bitmaps:fv->sf->bitmaps; bdf!=NULL; bdf=bdf->next )
108 ret |= BCUnselectedDependents( fv,bdf->glyphs[gid] );
109 }
110 return( ret );
111 }
112
FVClear(FontViewBase * fv)113 void FVClear(FontViewBase *fv) {
114 int i;
115 BDFFont *bdf;
116 int refstate = 0;
117 char *buts[6];
118 int yes, unsel, gid;
119 /* refstate==0 => ask, refstate==1 => clearall, refstate==-1 => skip all */
120
121 for ( i=0; i<fv->map->enccount; ++i ) if ( fv->selected[i] && (gid=fv->map->map[i])!=-1 ) {
122 /* If we are messing with the outline character, check for dependencies */
123 if ( refstate<=0 && ( unsel = UnselectedDependents( fv,gid ))) {
124 if ( refstate==0 ) {
125 buts[0] = _("_Yes");
126 buts[1] = _("Yes to _All");
127 buts[2] = _("_Unlink All");
128 buts[3] = _("No _to All");
129 buts[4] = _("_No");
130 buts[5] = NULL;
131 yes = ff_ask(_("Bad Reference"),(const char **) buts,2,4,_("You are attempting to clear %.30s which is referred to by\nanother character. Are you sure you want to clear it?"),fv->sf->glyphs[gid]->name);
132 if ( yes==1 )
133 refstate = 1;
134 else if ( yes==2 )
135 refstate = -2;
136 else if ( yes==3 )
137 refstate = -1;
138 else if ( yes==4 )
139 continue;
140 }
141 if ( refstate==-2 ) {
142 if ( onlycopydisplayed && fv->active_bitmap == NULL )
143 UnlinkThisReference( fv,fv->sf->glyphs[gid],fv->active_layer );
144 else if ( onlycopydisplayed && fv->active_bitmap != NULL )
145 BCUnlinkThisReference( fv,fv->active_bitmap->glyphs[gid] );
146 else {
147 UnlinkThisReference(fv,fv->sf->glyphs[gid],fv->active_layer);
148 for ( bdf=fv->sf->cidmaster?fv->sf->cidmaster->bitmaps:fv->sf->bitmaps; bdf!=NULL; bdf = bdf->next )
149 BCUnlinkThisReference( fv,bdf->glyphs[gid] );
150 }
151 } else if ( refstate == -1 )
152 continue;
153 }
154
155 if ( onlycopydisplayed && fv->active_bitmap==NULL ) {
156 SCClearAll(fv->sf->glyphs[gid],fv->active_layer);
157 } else if ( onlycopydisplayed ) {
158 BCClearAll(fv->active_bitmap->glyphs[gid]);
159 } else {
160 SCClearAll(fv->sf->glyphs[gid],fv->active_layer);
161 for ( bdf=fv->sf->cidmaster?fv->sf->cidmaster->bitmaps:fv->sf->bitmaps; bdf!=NULL; bdf = bdf->next )
162 BCClearAll(bdf->glyphs[gid]);
163 }
164 }
165 }
166
FVClearBackground(FontViewBase * fv)167 void FVClearBackground(FontViewBase *fv) {
168 SplineFont *sf = fv->sf;
169 int i, gid;
170
171 if ( onlycopydisplayed && fv->active_bitmap!=NULL )
172 return;
173
174 for ( i=0; i<fv->map->enccount; ++i ) if ( fv->selected[i] &&
175 (gid = fv->map->map[i])!=-1 && sf->glyphs[gid]!=NULL ) {
176 SCClearBackground(sf->glyphs[gid]);
177 }
178 }
179
FVCopyFgtoBg(FontViewBase * fv)180 void FVCopyFgtoBg(FontViewBase *fv) {
181 int i, gid;
182
183 for ( i=0; i<fv->map->enccount; ++i )
184 if ( fv->selected[i] && (gid = fv->map->map[i])!=-1 &&
185 fv->sf->glyphs[gid]!=NULL )
186 SCCopyLayerToLayer(fv->sf->glyphs[gid],fv->active_layer,ly_back,true);
187 }
188
FVUnlinkRef(FontViewBase * fv)189 void FVUnlinkRef(FontViewBase *fv) {
190 int i,layer, first, last, gid;
191 SplineChar *sc;
192 RefChar *rf, *next;
193 BDFFont *bdf;
194 BDFChar *bdfc;
195 BDFRefChar *head, *cur;
196
197 for ( i=0; i<fv->map->enccount; ++i ) if ( fv->selected[i] &&
198 (gid = fv->map->map[i])!=-1 && (sc = fv->sf->glyphs[gid])!=NULL) {
199 if (( fv->active_bitmap==NULL || !onlycopydisplayed ) &&
200 sc->layers[fv->active_layer].refs!=NULL) {
201 SCPreserveLayer(sc,fv->active_layer,false);
202 if ( sc->parent->multilayer ) {
203 first = ly_fore;
204 last = sc->layer_cnt-1;
205 } else
206 first = last = fv->active_layer;
207 for ( layer=first; layer<=last; ++layer ) {
208 for ( rf=sc->layers[layer].refs; rf!=NULL ; rf=next ) {
209 next = rf->next;
210 SCRefToSplines(sc,rf,layer);
211 }
212 }
213 SCCharChangedUpdate( sc,fv->active_layer );
214 }
215
216 for ( bdf = fv->sf->bitmaps; bdf!=NULL; bdf=bdf->next ) {
217 if ( bdf != fv->active_bitmap && onlycopydisplayed )
218 continue;
219
220 bdfc = gid==-1 || gid>=bdf->glyphcnt? NULL : bdf->glyphs[gid];
221 if ( bdfc != NULL && bdfc->refs != NULL ) {
222 BCMergeReferences( bdfc,bdfc,0,0 );
223 for ( head = bdfc->refs; head != NULL; ) {
224 cur = head; head = cur->next; free( cur );
225 }
226 bdfc->refs = NULL;
227 BCCharChangedUpdate(bdfc);
228 }
229 }
230 }
231 }
232
FVUndo(FontViewBase * fv)233 void FVUndo(FontViewBase *fv) {
234 int i,j,layer,first,last, gid;
235 MMSet *mm = fv->sf->mm;
236 int was_blended = mm!=NULL && mm->normal==fv->sf;
237 BDFFont *bdf;
238 BDFChar *bdfc;
239
240 SFUntickAll(fv->sf);
241 for ( i=0; i<fv->map->enccount; ++i )
242 if ( fv->selected[i] && (gid = fv->map->map[i])!=-1 &&
243 fv->sf->glyphs[gid]!=NULL && !fv->sf->glyphs[gid]->ticked) {
244 if ( fv->active_bitmap==NULL || !onlycopydisplayed ) {
245 SplineChar *sc = fv->sf->glyphs[gid];
246 if ( sc->parent->multilayer ) {
247 first = ly_fore;
248 last = sc->layer_cnt-1;
249 } else
250 first = last = fv->active_layer;
251 for ( layer=first; layer<=last; ++layer ) {
252 if ( sc->layers[layer].undoes!=NULL ) {
253 SCDoUndo(sc,layer);
254 if ( was_blended ) {
255 for ( j=0; j<mm->instance_count; ++j )
256 SCDoUndo(mm->instances[j]->glyphs[gid],layer);
257 }
258 }
259 }
260 sc->ticked = true;
261 }
262 for ( bdf=fv->sf->bitmaps; bdf!=NULL; bdf=bdf->next ) {
263 if ( bdf != fv->active_bitmap && onlycopydisplayed )
264 continue;
265
266 bdfc = bdf->glyphs[gid];
267 if ( bdfc != NULL && bdfc->undoes != NULL )
268 BCDoUndo( bdfc );
269 }
270 }
271 }
272
FVRedo(FontViewBase * fv)273 void FVRedo(FontViewBase *fv) {
274 int i,j,layer,first,last, gid;
275 MMSet *mm = fv->sf->mm;
276 int was_blended = mm!=NULL && mm->normal==fv->sf;
277 BDFFont *bdf;
278 BDFChar *bdfc;
279
280 SFUntickAll(fv->sf);
281 for ( i=0; i<fv->map->enccount; ++i )
282 if ( fv->selected[i] && (gid = fv->map->map[i])!=-1 &&
283 fv->sf->glyphs[gid]!=NULL && !fv->sf->glyphs[gid]->ticked) {
284 if ( fv->active_bitmap==NULL || !onlycopydisplayed ) {
285 SplineChar *sc = fv->sf->glyphs[gid];
286 if ( sc->parent->multilayer ) {
287 first = ly_fore;
288 last = sc->layer_cnt-1;
289 } else
290 first = last = fv->active_layer;
291 for ( layer=first; layer<=last; ++layer ) {
292 if ( sc->layers[layer].redoes!=NULL ) {
293 SCDoRedo(sc,layer);
294 if ( was_blended ) {
295 for ( j=0; j<mm->instance_count; ++j )
296 SCDoRedo(mm->instances[j]->glyphs[gid],layer);
297 }
298 }
299 }
300 sc->ticked = true;
301 }
302 for ( bdf=fv->sf->bitmaps; bdf!=NULL; bdf=bdf->next ) {
303 if ( bdf != fv->active_bitmap && onlycopydisplayed )
304 continue;
305
306 bdfc = bdf->glyphs[gid];
307 if ( bdfc != NULL && bdfc->redoes != NULL )
308 BCDoRedo( bdfc );
309 }
310 }
311 }
312
FVJoin(FontViewBase * fv)313 void FVJoin(FontViewBase *fv) {
314 SplineFont *sf = fv->sf;
315 int i,changed,gid;
316
317 if ( onlycopydisplayed && fv->active_bitmap!=NULL )
318 return;
319
320 for ( i=0; i<fv->map->enccount; ++i ) if ( fv->selected[i] &&
321 (gid = fv->map->map[i])!=-1 && sf->glyphs[gid]!=NULL ) {
322 SCPreserveLayer(sf->glyphs[gid],fv->active_layer,false);
323 sf->glyphs[gid]->layers[fv->active_layer].splines = SplineSetJoin(sf->glyphs[gid]->layers[fv->active_layer].splines,true,joinsnap,&changed);
324 if ( changed )
325 SCCharChangedUpdate(sf->glyphs[gid],fv->active_layer);
326 }
327 }
328
LinkEncToGid(FontViewBase * fv,int enc,int gid)329 static void LinkEncToGid(FontViewBase *fv,int enc, int gid) {
330 EncMap *map = fv->map;
331 int old_gid;
332 int flags = -1;
333 int j;
334
335 if ( map->map[enc]!=-1 && map->map[enc]!=gid ) {
336 SplineFont *sf = fv->sf;
337 old_gid = map->map[enc];
338 for ( j=0; j<map->enccount; ++j )
339 if ( j!=enc && map->map[j]==old_gid )
340 break;
341 /* If the glyph is used elsewhere in the encoding then reusing this */
342 /* slot causes no problems */
343 if ( j==map->enccount ) {
344 /* However if this is the only use and the glyph is interesting */
345 /* then add it to the unencoded area. If it is uninteresting we*/
346 /* can just get rid of it */
347 if ( SCWorthOutputting(sf->glyphs[old_gid]) )
348 SFAddEncodingSlot(sf,old_gid);
349 else
350 SFRemoveGlyph(sf,sf->glyphs[old_gid]);
351 }
352 }
353 map->map[enc] = gid;
354 if ( map->backmap[gid]==-1 )
355 map->backmap[gid] = enc;
356 if ( map->enc!=&custom ) {
357 int uni = UniFromEnc(enc,map->enc);
358 AltUniAdd(fv->sf->glyphs[gid],uni);
359 }
360 }
361
FVSameGlyphAs(FontViewBase * fv)362 void FVSameGlyphAs(FontViewBase *fv) {
363 SplineFont *sf = fv->sf;
364 RefChar *base = CopyContainsRef(sf);
365 int i;
366 EncMap *map = fv->map;
367
368 if ( base==NULL || fv->cidmaster!=NULL )
369 return;
370 for ( i=0; i<map->enccount; ++i ) if ( fv->selected[i] ) {
371 LinkEncToGid(fv,i,base->orig_pos);
372 }
373 }
374
FVBuildDuplicate(FontViewBase * fv)375 void FVBuildDuplicate(FontViewBase *fv) {
376 const int *pua = fv->sf->uni_interp==ui_trad_chinese ? cns14pua : fv->sf->uni_interp==ui_ams ? amspua : NULL;
377 int i, cnt=0, gid;
378 SplineChar dummy;
379 const unichar_t *pt;
380
381 for ( i=0; i<fv->map->enccount; ++i ) if ( fv->selected[i] )
382 ++cnt;
383 ff_progress_start_indicator(10,_("Building duplicate encodings"),
384 _("Building duplicate encodings"),NULL,cnt,1);
385
386 for ( i=0; i<fv->map->enccount; ++i ) if ( fv->selected[i] ) {
387 SplineChar *sc;
388 int baseuni = 0;
389 if ( (gid = fv->map->map[i])==-1 || (sc = fv->sf->glyphs[gid])==NULL )
390 sc = SCBuildDummy(&dummy,fv->sf,fv->map,i);
391 if ( pua!=NULL && sc->unicodeenc>=0xe000 && sc->unicodeenc<=0xf8ff )
392 baseuni = pua[sc->unicodeenc-0xe000];
393 if ( baseuni==0 && ( pt = SFGetAlternate(fv->sf,sc->unicodeenc,sc,false))!=NULL &&
394 pt[0]!='\0' && pt[1]=='\0' )
395 baseuni = pt[0];
396
397 if ( baseuni!=0 && (gid = SFFindExistingSlot(fv->sf,baseuni,NULL))!=-1 )
398 LinkEncToGid(fv,i,gid);
399 if ( !ff_progress_next())
400 break;
401 }
402 ff_progress_end_indicator();
403 }
404
TransHints(StemInfo * stem,real mul1,real off1,real mul2,real off2,int round_to_int)405 void TransHints(StemInfo *stem,real mul1, real off1, real mul2, real off2, int round_to_int ) {
406 HintInstance *hi;
407
408 for ( ; stem!=NULL; stem=stem->next ) {
409 stem->start = stem->start*mul1 + off1;
410 stem->width *= mul1;
411 if ( round_to_int ) {
412 stem->start = rint(stem->start);
413 stem->width = rint(stem->width);
414 }
415 if ( mul1<0 ) {
416 stem->start += stem->width;
417 stem->width = -stem->width;
418 }
419 for ( hi=stem->where; hi!=NULL; hi=hi->next ) {
420 hi->begin = hi->begin*mul2 + off2;
421 hi->end = hi->end*mul2 + off2;
422 if ( round_to_int ) {
423 hi->begin = rint(hi->begin);
424 hi->end = rint(hi->end);
425 }
426 if ( mul2<0 ) {
427 double temp = hi->begin;
428 hi->begin = hi->end;
429 hi->end = temp;
430 }
431 }
432 }
433 }
434
435 /* added by akryukov 01/01/2008 to enable resizing and flipping DStem hints */
TransDStemHints(DStemInfo * ds,real xmul,real xoff,real ymul,real yoff,int round_to_int)436 void TransDStemHints( DStemInfo *ds,real xmul,real xoff,real ymul,real yoff,int round_to_int ) {
437 HintInstance *hi;
438 double dmul, temp;
439
440 for ( ; ds!=NULL; ds=ds->next ) {
441 ds->left.x = xmul*ds->left.x + xoff;
442 ds->left.y = ymul*ds->left.y + yoff;
443 ds->right.x = xmul*ds->right.x + xoff;
444 ds->right.y = ymul*ds->right.y + yoff;
445 if ( round_to_int ) {
446 ds->left.x = rint( ds->left.x );
447 ds->left.y = rint( ds->left.y );
448 ds->right.x = rint( ds->right.x );
449 ds->right.y = rint( ds->right.y );
450 }
451
452 if (( xmul < 0 && ymul > 0 ) || ( xmul > 0 && ymul < 0 ))
453 ds->unit.y = -ds->unit.y;
454 ds->unit.x *= fabs( xmul ); ds->unit.y *= fabs( ymul );
455 dmul = sqrt( pow( ds->unit.x,2 ) + pow( ds->unit.y,2 ));
456 ds->unit.x /= dmul; ds->unit.y /= dmul;
457 if ( xmul < 0 ) dmul = -dmul;
458
459 for ( hi=ds->where; hi!=NULL; hi=hi->next ) {
460 if ( dmul > 0 ) {
461 hi->begin = hi->begin * dmul;
462 hi->end = hi->end * dmul;
463 } else {
464 temp = hi->begin;
465 hi->begin = hi->end * dmul;
466 hi->end = temp * dmul;
467 }
468 }
469 }
470 }
471
VrTrans(struct vr * vr,real transform[6])472 void VrTrans(struct vr *vr,real transform[6]) {
473 /* I'm interested in scaling and skewing. I think translation should */
474 /* not affect these guys (they are offsets, so offsets should be */
475 /* unchanged by translation */
476 double x,y;
477
478 x = vr->xoff; y=vr->yoff;
479 vr->xoff = rint(transform[0]*x + transform[1]*y);
480 vr->yoff = rint(transform[2]*x + transform[3]*y);
481 x = vr->h_adv_off; y=vr->v_adv_off;
482 vr->h_adv_off = rint(transform[0]*x + transform[1]*y);
483 vr->v_adv_off = rint(transform[2]*x + transform[3]*y);
484 }
485
BackgroundImageTransform(SplineChar * sc,ImageList * img,real transform[6])486 void BackgroundImageTransform(SplineChar *sc, ImageList *img,real transform[6]) {
487 if ( transform[1]==0 && transform[2]==0 && transform[0]>0 && transform[3]>0 ) {
488 img->xoff = transform[0]*img->xoff + transform[4];
489 img->yoff = transform[3]*img->yoff + transform[5];
490 if (( img->xscale *= transform[0])<0 ) img->xscale = -img->xscale;
491 if (( img->yscale *= transform[3])<0 ) img->yscale = -img->yscale;
492 img->bb.minx = img->xoff; img->bb.maxy = img->yoff;
493 img->bb.maxx = img->xoff + GImageGetWidth(img->image)*img->xscale;
494 img->bb.miny = img->yoff - GImageGetHeight(img->image)*img->yscale;
495 } else {
496 /* Don't support rotating, flipping or skewing images */
497 ;
498 }
499 SCOutOfDateBackground(sc);
500 }
501
GV_Trans(struct glyphvariants * gv,real transform[6],int is_v)502 static void GV_Trans(struct glyphvariants *gv,real transform[6], int is_v) {
503 int i;
504
505 if ( gv==NULL )
506 return;
507 gv->italic_correction = rint(gv->italic_correction*transform[0]);
508 is_v = 3*is_v;
509 for ( i=0; i<gv->part_cnt; ++i ) {
510 gv->parts[i].startConnectorLength = rint( gv->parts[i].startConnectorLength*transform[is_v] );
511 gv->parts[i].endConnectorLength = rint( gv->parts[i].endConnectorLength*transform[is_v] );
512 gv->parts[i].fullAdvance = rint( gv->parts[i].fullAdvance*transform[is_v] );
513 }
514 }
515
MKV_Trans(struct mathkernvertex * mkv,real transform[6])516 static void MKV_Trans(struct mathkernvertex *mkv,real transform[6]) {
517 int i;
518
519 for ( i=0; i<mkv->cnt; ++i ) {
520 mkv->mkd[i].kern = rint( mkv->mkd[i].kern *transform[0]);
521 mkv->mkd[i].height= rint( mkv->mkd[i].height*transform[0]);
522 }
523 }
524
MK_Trans(struct mathkern * mk,real transform[6])525 static void MK_Trans(struct mathkern *mk,real transform[6]) {
526 if ( mk==NULL )
527 return;
528 MKV_Trans(&mk->top_right,transform);
529 MKV_Trans(&mk->top_left ,transform);
530 MKV_Trans(&mk->bottom_right,transform);
531 MKV_Trans(&mk->bottom_left ,transform);
532 }
533
MATH_Trans(struct MATH * math,real transform[6])534 static void MATH_Trans(struct MATH *math,real transform[6]) {
535 if ( math==NULL )
536 return;
537 math->DelimitedSubFormulaMinHeight = rint( math->DelimitedSubFormulaMinHeight*transform[3]);
538 math->DisplayOperatorMinHeight = rint( math->DisplayOperatorMinHeight*transform[3]);
539 math->MathLeading = rint( math->MathLeading*transform[3]);
540 math->AxisHeight = rint( math->AxisHeight*transform[3]);
541 math->AccentBaseHeight = rint( math->AccentBaseHeight*transform[3]);
542 math->FlattenedAccentBaseHeight = rint( math->FlattenedAccentBaseHeight*transform[3]);
543 math->SubscriptShiftDown = rint( math->SubscriptShiftDown*transform[3]);
544 math->SubscriptTopMax = rint( math->SubscriptTopMax*transform[3]);
545 math->SubscriptBaselineDropMin = rint( math->SubscriptBaselineDropMin*transform[3]);
546 math->SuperscriptShiftUp = rint( math->SuperscriptShiftUp*transform[3]);
547 math->SuperscriptShiftUpCramped = rint( math->SuperscriptShiftUpCramped*transform[3]);
548 math->SuperscriptBottomMin = rint( math->SuperscriptBottomMin*transform[3]);
549 math->SuperscriptBaselineDropMax = rint( math->SuperscriptBaselineDropMax*transform[3]);
550 math->SubSuperscriptGapMin = rint( math->SubSuperscriptGapMin*transform[3]);
551 math->SuperscriptBottomMaxWithSubscript = rint( math->SuperscriptBottomMaxWithSubscript*transform[3]);
552 /* SpaceAfterScript is horizontal and is below */
553 math->UpperLimitGapMin = rint( math->UpperLimitGapMin*transform[3]);
554 math->UpperLimitBaselineRiseMin = rint( math->UpperLimitBaselineRiseMin*transform[3]);
555 math->LowerLimitGapMin = rint( math->LowerLimitGapMin*transform[3]);
556 math->LowerLimitBaselineDropMin = rint( math->LowerLimitBaselineDropMin*transform[3]);
557 math->StackTopShiftUp = rint( math->StackTopShiftUp*transform[3]);
558 math->StackTopDisplayStyleShiftUp = rint( math->StackTopDisplayStyleShiftUp*transform[3]);
559 math->StackBottomShiftDown = rint( math->StackBottomShiftDown*transform[3]);
560 math->StackBottomDisplayStyleShiftDown = rint( math->StackBottomDisplayStyleShiftDown*transform[3]);
561 math->StackGapMin = rint( math->StackGapMin*transform[3]);
562 math->StackDisplayStyleGapMin = rint( math->StackDisplayStyleGapMin*transform[3]);
563 math->StretchStackTopShiftUp = rint( math->StretchStackTopShiftUp*transform[3]);
564 math->StretchStackBottomShiftDown = rint( math->StretchStackBottomShiftDown*transform[3]);
565 math->StretchStackGapAboveMin = rint( math->StretchStackGapAboveMin*transform[3]);
566 math->StretchStackGapBelowMin = rint( math->StretchStackGapBelowMin*transform[3]);
567 math->FractionNumeratorShiftUp = rint( math->FractionNumeratorShiftUp*transform[3]);
568 math->FractionNumeratorDisplayStyleShiftUp = rint( math->FractionNumeratorDisplayStyleShiftUp*transform[3]);
569 math->FractionDenominatorShiftDown = rint( math->FractionDenominatorShiftDown*transform[3]);
570 math->FractionDenominatorDisplayStyleShiftDown = rint( math->FractionDenominatorDisplayStyleShiftDown*transform[3]);
571 math->FractionNumeratorGapMin = rint( math->FractionNumeratorGapMin*transform[3]);
572 math->FractionNumeratorDisplayStyleGapMin = rint( math->FractionNumeratorDisplayStyleGapMin*transform[3]);
573 math->FractionRuleThickness = rint( math->FractionRuleThickness*transform[3]);
574 math->FractionDenominatorGapMin = rint( math->FractionDenominatorGapMin*transform[3]);
575 math->FractionDenominatorDisplayStyleGapMin = rint( math->FractionDenominatorDisplayStyleGapMin*transform[3]);
576 /* SkewedFractionHorizontalGap is horizontal and is below */
577 math->SkewedFractionVerticalGap = rint( math->SkewedFractionVerticalGap*transform[3]);
578 math->OverbarVerticalGap = rint( math->OverbarVerticalGap*transform[3]);
579 math->OverbarRuleThickness = rint( math->OverbarRuleThickness*transform[3]);
580 math->OverbarExtraAscender = rint( math->OverbarExtraAscender*transform[3]);
581 math->UnderbarVerticalGap = rint( math->UnderbarVerticalGap*transform[3]);
582 math->UnderbarRuleThickness = rint( math->UnderbarRuleThickness*transform[3]);
583 math->UnderbarExtraDescender = rint( math->UnderbarExtraDescender*transform[3]);
584 math->RadicalVerticalGap = rint( math->RadicalVerticalGap*transform[3]);
585 math->RadicalDisplayStyleVerticalGap = rint( math->RadicalDisplayStyleVerticalGap*transform[3]);
586 math->RadicalRuleThickness = rint( math->RadicalRuleThickness*transform[3]);
587 math->RadicalExtraAscender = rint( math->RadicalExtraAscender*transform[3]);
588 math->RadicalDegreeBottomRaisePercent = rint( math->RadicalDegreeBottomRaisePercent*transform[3]);
589
590 /* Horizontals */
591 math->SpaceAfterScript = rint( math->SpaceAfterScript*transform[0]);
592 math->SkewedFractionHorizontalGap = rint( math->SkewedFractionHorizontalGap*transform[0]);
593 math->RadicalKernBeforeDegree = rint( math->RadicalKernBeforeDegree*transform[0]);
594 math->RadicalKernAfterDegree = rint( math->RadicalKernAfterDegree*transform[0]);
595
596 /* This number is the same for both horizontal and vertical connections */
597 /* Use the vertical amount as a) will probably be the same and */
598 /* b) most are vertical anyway */
599 math->RadicalKernAfterDegree = rint( math->RadicalKernAfterDegree*transform[0]);
600 }
601
KCTrans(KernClass * kc,double scale)602 static void KCTrans(KernClass *kc,double scale) {
603 /* Again these are offsets, so I don't apply translation */
604 int i;
605
606 for ( i=kc->first_cnt*kc->second_cnt-1; i>=0; --i )
607 kc->offsets[i] = rint(scale*kc->offsets[i]);
608 }
609
SCTransLayer(FontViewBase * fv,SplineChar * sc,int flags,int i,real transform[6],uint8 * sel)610 static void SCTransLayer(FontViewBase *fv, SplineChar *sc, int flags, int i, real transform[6], uint8 *sel) {
611 int j;
612 RefChar *refs;
613 real t[6];
614 ImageList *img;
615
616 SplinePointListTransform(sc->layers[i].splines,transform,tpt_AllPoints);
617 for ( refs = sc->layers[i].refs; refs!=NULL; refs=refs->next ) {
618 if ( (sel!=NULL && sel[fv->map->backmap[refs->sc->orig_pos]]) ||
619 (flags&fvt_partialreftrans)) {
620 /* if the character referred to is selected then it's going to */
621 /* be scaled too (or will have been) so we don't want to scale */
622 /* it twice */
623 t[4] = refs->transform[4]*transform[0] +
624 refs->transform[5]*transform[2] +
625 /*transform[4]*/0;
626 t[5] = refs->transform[4]*transform[1] +
627 refs->transform[5]*transform[3] +
628 /*transform[5]*/0;
629 t[0] = refs->transform[4]; t[1] = refs->transform[5];
630 refs->transform[4] = t[4];
631 refs->transform[5] = t[5];
632 /* Now update the splines to match */
633 t[4] -= t[0]; t[5] -= t[1];
634 if ( t[4]!=0 || t[5]!=0 ) {
635 t[0] = t[3] = 1; t[1] = t[2] = 0;
636 for ( j=0; j<refs->layer_cnt; ++j )
637 SplinePointListTransform(refs->layers[j].splines,t,tpt_AllPoints);
638 }
639 } else {
640 for ( j=0; j<refs->layer_cnt; ++j )
641 SplinePointListTransform(refs->layers[j].splines,transform,tpt_AllPoints);
642 t[0] = refs->transform[0]*transform[0] +
643 refs->transform[1]*transform[2];
644 t[1] = refs->transform[0]*transform[1] +
645 refs->transform[1]*transform[3];
646 t[2] = refs->transform[2]*transform[0] +
647 refs->transform[3]*transform[2];
648 t[3] = refs->transform[2]*transform[1] +
649 refs->transform[3]*transform[3];
650 t[4] = refs->transform[4]*transform[0] +
651 refs->transform[5]*transform[2] +
652 transform[4];
653 t[5] = refs->transform[4]*transform[1] +
654 refs->transform[5]*transform[3] +
655 transform[5];
656 memcpy(refs->transform,t,sizeof(t));
657 }
658 RefCharFindBounds(refs);
659 }
660 for ( img = sc->layers[i].images; img!=NULL; img=img->next )
661 BackgroundImageTransform(sc, img, transform);
662 }
663
664 /* If sel is specified then we decide how to transform references based on */
665 /* whether the refered glyph is selected. (If we tranform a reference that */
666 /* is selected we are, in effect, transforming it twice -- since the glyph */
667 /* itself will be transformed -- so instead we just transform the offsets */
668 /* of the reference */
669 /* If sel is NULL then we transform the reference */
670 /* if flags&fvt_partialreftrans then we always just transform the offsets */
FVTrans(FontViewBase * fv,SplineChar * sc,real transform[6],uint8 * sel,enum fvtrans_flags flags)671 void FVTrans(FontViewBase *fv,SplineChar *sc,real transform[6], uint8 *sel,
672 enum fvtrans_flags flags) {
673 AnchorPoint *ap;
674 int i,first,last;
675 KernPair *kp;
676 PST *pst;
677
678 if ( sc->blended ) {
679 int j;
680 MMSet *mm = sc->parent->mm;
681 for ( j=0; j<mm->instance_count; ++j )
682 FVTrans(fv,mm->instances[j]->glyphs[sc->orig_pos],transform,sel,flags);
683 }
684
685 if (!(flags & fvt_nopreserve)) {
686 if ( flags&fvt_alllayers ) {
687 for ( i=0; i<sc->layer_cnt; ++i )
688 SCPreserveLayer(sc,i,fv->active_layer==i);
689 } else if ( fv->sf->multilayer )
690 SCPreserveState(sc,true);
691 else
692 SCPreserveLayer(sc,fv->active_layer,true);
693 }
694 if ( !(flags&fvt_dontmovewidth) )
695 if ( transform[0]>0 && transform[3]>0 && transform[1]==0 && transform[2]==0 ) {
696 int widthset = sc->widthset;
697 SCSynchronizeWidth(sc,sc->width*transform[0]+transform[4],sc->width,fv);
698 if ( !(flags&fvt_dontsetwidth) ) sc->widthset = widthset;
699 sc->vwidth = sc->vwidth*transform[3]+transform[5];
700 }
701 if ( flags & fvt_scalepstpos ) {
702 for ( kp=sc->kerns; kp!=NULL; kp=kp->next )
703 kp->off = rint(kp->off*transform[0]);
704 for ( kp=sc->vkerns; kp!=NULL; kp=kp->next )
705 kp->off = rint(kp->off*transform[3]);
706 for ( pst = sc->possub; pst!=NULL; pst=pst->next ) {
707 if ( pst->type == pst_position )
708 VrTrans(&pst->u.pos,transform);
709 else if ( pst->type==pst_pair ) {
710 VrTrans(&pst->u.pair.vr[0],transform);
711 VrTrans(&pst->u.pair.vr[1],transform);
712 } else if ( pst->type == pst_lcaret ) {
713 int j;
714 for ( j=0; j<pst->u.lcaret.cnt; ++j )
715 pst->u.lcaret.carets[j] = rint(pst->u.lcaret.carets[j]*transform[0]+transform[4]);
716 }
717 }
718 }
719
720 if ( sc->tex_height!=TEX_UNDEF )
721 sc->tex_height = rint(sc->tex_height*transform[3]);
722 if ( sc->tex_depth !=TEX_UNDEF )
723 sc->tex_depth = rint(sc->tex_depth *transform[3]);
724 if ( sc->italic_correction!=TEX_UNDEF )
725 sc->italic_correction = rint(sc->italic_correction *transform[0]);
726 if ( sc->top_accent_horiz !=TEX_UNDEF )
727 sc->top_accent_horiz = rint(sc->top_accent_horiz *transform[0]);
728 GV_Trans(sc->vert_variants ,transform, true);
729 GV_Trans(sc->horiz_variants,transform, false);
730 MK_Trans(sc->mathkern,transform);
731
732 for ( ap=sc->anchor; ap!=NULL; ap=ap->next )
733 ApTransform(ap,transform);
734 if ( flags&fvt_alllayers ) {
735 first = 0;
736 last = sc->layer_cnt-1;
737 } else if ( sc->parent->multilayer ) {
738 first = ly_fore;
739 last = sc->layer_cnt-1;
740 } else
741 first = last = fv->active_layer;
742 for ( i=first; i<=last; ++i )
743 SCTransLayer(fv,sc,flags,i,transform,sel);
744 if ( transform[1]==0 && transform[2]==0 ) {
745 if ( transform[0]==1 && transform[3]==1 &&
746 transform[5]==0 && transform[4]!=0 &&
747 sc->unicodeenc!=-1 && sc->unicodeenc<0x10000 &&
748 isalpha(sc->unicodeenc)) {
749 SCUndoSetLBearingChange(sc,(int) rint(transform[4]));
750 SCSynchronizeLBearing(sc,transform[4],fv->active_layer); /* this moves the hints */
751 } else {
752 TransHints(sc->hstem,transform[3],transform[5],transform[0],transform[4],flags&fvt_round_to_int);
753 TransHints(sc->vstem,transform[0],transform[4],transform[3],transform[5],flags&fvt_round_to_int);
754 TransDStemHints(sc->dstem,transform[0],transform[4],transform[3],transform[5],flags&fvt_round_to_int);
755 }
756 }
757 /*if ( flags&fvt_round_to_int )*/
758 if ( (flags&fvt_round_to_int) && (!sc->inspiro || !hasspiro())) {
759 /* Rounding the spiros might be a bad idea. */
760 /* Not rounding the spiros is also a bad idea. */
761 /* Not sure which is worse */
762 /* Barry thinks rounding them is a bad idea. */
763 SCRound2Int(sc,fv->active_layer,1.0);
764 }
765 if ( !(flags&fvt_noupdate) )
766 SCCharChangedUpdate(sc,fv->active_layer);
767 }
768
FVTransFunc(void * _fv,real transform[6],int otype,BVTFunc * bvts,enum fvtrans_flags flags)769 void FVTransFunc(void *_fv,real transform[6],int otype, BVTFunc *bvts,
770 enum fvtrans_flags flags ) {
771 FontViewBase *fv = _fv;
772 real transx = transform[4], transy=transform[5];
773 DBounds bb;
774 BasePoint base;
775 int i, cnt=0, gid;
776 BDFFont *bdf;
777
778 for ( i=0; i<fv->map->enccount; ++i )
779 if ( fv->selected[i] && (gid = fv->map->map[i])!=-1 &&
780 SCWorthOutputting(fv->sf->glyphs[gid]) )
781 ++cnt;
782
783
784 ff_progress_start_indicator(10,_("Transforming..."),_("Transforming..."),0,cnt,1);
785
786 SFUntickAll(fv->sf);
787 for ( i=0; i<fv->map->enccount; ++i ) if ( fv->selected[i] &&
788 (gid = fv->map->map[i])!=-1 &&
789 SCWorthOutputting(fv->sf->glyphs[gid]) &&
790 !fv->sf->glyphs[gid]->ticked ) {
791 SplineChar *sc = fv->sf->glyphs[gid];
792
793 if ( onlycopydisplayed && fv->active_bitmap!=NULL ) {
794 if ( fv->active_bitmap->glyphs[gid]!=NULL )
795 BCTrans(fv->active_bitmap,fv->active_bitmap->glyphs[gid],bvts,fv);
796 } else {
797 if ( otype==1 ) {
798 SplineCharFindBounds(sc,&bb);
799 base.x = (bb.minx+bb.maxx)/2;
800 base.y = (bb.miny+bb.maxy)/2;
801 transform[4]=transx+base.x-
802 (transform[0]*base.x+transform[2]*base.y);
803 transform[5]=transy+base.y-
804 (transform[1]*base.x+transform[3]*base.y);
805 }
806 FVTrans(fv,sc,transform,fv->selected,flags);
807 if ( !onlycopydisplayed ) {
808 for ( bdf = fv->sf->bitmaps; bdf!=NULL; bdf=bdf->next )
809 if ( gid<bdf->glyphcnt && bdf->glyphs[gid]!=NULL )
810 BCTrans(bdf,bdf->glyphs[gid],bvts,fv);
811 }
812 }
813 sc->ticked = true;
814 if ( !ff_progress_next())
815 break;
816 }
817 if ( flags&fvt_dogrid ) {
818 SFPreserveGuide(fv->sf);
819 SplinePointListTransform(fv->sf->grid.splines,transform,tpt_AllPoints);
820 }
821 ff_progress_end_indicator();
822
823 if ( flags&fvt_scalekernclasses ) {
824 KernClass *kc;
825 SplineFont *sf = fv->cidmaster!=NULL ? fv->cidmaster : fv->sf;
826 for ( kc=sf->kerns; kc!=NULL; kc=kc->next )
827 KCTrans(kc,transform[0]);
828 for ( kc=sf->vkerns; kc!=NULL; kc=kc->next )
829 KCTrans(kc,transform[3]);
830 if ( sf->MATH!=NULL )
831 MATH_Trans(sf->MATH,transform);
832 }
833 }
834
FVReencode(FontViewBase * fv,Encoding * enc)835 void FVReencode(FontViewBase *fv,Encoding *enc) {
836 EncMap *map;
837
838 if ( enc==&custom )
839 fv->map->enc = &custom;
840 else {
841 map = EncMapFromEncoding(fv->sf,enc);
842 fv->selected = realloc(fv->selected,map->enccount);
843 memset(fv->selected,0,map->enccount);
844 EncMapFree(fv->map);
845 if (fv->sf != NULL && fv->map == fv->sf->map) { fv->sf->map = map; }
846 fv->map = map;
847 }
848 if ( fv->normal!=NULL ) {
849 EncMapFree(fv->normal);
850 if (fv->sf != NULL && fv->normal == fv->sf->map) { fv->sf->map = NULL; }
851 fv->normal = NULL;
852 }
853 SFReplaceEncodingBDFProps(fv->sf,fv->map);
854 FVSetTitle(fv);
855 FontViewReformatOne(fv);
856 }
857
FVOverlap(FontViewBase * fv,enum overlap_type ot)858 void FVOverlap(FontViewBase *fv,enum overlap_type ot) {
859 int i, cnt=0, layer, first, last, gid;
860 SplineChar *sc;
861
862 /* We know it's more likely that we'll find a problem in the overlap code */
863 /* than anywhere else, so let's save the current state against a crash */
864 DoAutoSaves();
865
866 for ( i=0; i<fv->map->enccount; ++i )
867 if ( fv->selected[i] && (gid = fv->map->map[i])!=-1 &&
868 SCWorthOutputting(fv->sf->glyphs[gid]) )
869 ++cnt;
870
871 ff_progress_start_indicator(10,_("Removing overlaps..."),_("Removing overlaps..."),0,cnt,1);
872
873 SFUntickAll(fv->sf);
874 for ( i=0; i<fv->map->enccount; ++i ) if ( fv->selected[i] &&
875 (gid = fv->map->map[i])!=-1 &&
876 SCWorthOutputting((sc=fv->sf->glyphs[gid])) &&
877 !sc->ticked ) {
878 sc->ticked = true;
879 #if 0
880 // We await testing on the necessity of this operation.
881 if ( !SCRoundToCluster(sc,ly_all,false,.03,.12))
882 SCPreserveLayer(sc,fv->active_layer,false);
883 #else
884 SCPreserveLayer(sc,fv->active_layer,false);
885 #endif // 0
886 MinimumDistancesFree(sc->md);
887 if ( sc->parent->multilayer ) {
888 first = ly_fore;
889 last = sc->layer_cnt-1;
890 } else
891 first = last = fv->active_layer;
892 for ( layer = first; layer<=last; ++layer )
893 sc->layers[layer].splines = SplineSetRemoveOverlap(sc,sc->layers[layer].splines,ot);
894 SCCharChangedUpdate(sc,fv->active_layer);
895 if ( !ff_progress_next())
896 break;
897 }
898 ff_progress_end_indicator();
899 }
900
FVAddExtrema(FontViewBase * fv,int force_adding)901 void FVAddExtrema(FontViewBase *fv, int force_adding ) {
902 int i, cnt=0, layer, first, last, gid;
903 SplineChar *sc;
904 SplineFont *sf = fv->sf;
905 int emsize = sf->ascent+sf->descent;
906
907 for ( i=0; i<fv->map->enccount; ++i )
908 if ( fv->selected[i] && (gid = fv->map->map[i])!=-1 &&
909 SCWorthOutputting(fv->sf->glyphs[gid]) )
910 ++cnt;
911 ff_progress_start_indicator(10,_("Adding points at Extrema..."),_("Adding points at Extrema..."),0,cnt,1);
912
913 SFUntickAll(fv->sf);
914 for ( i=0; i<fv->map->enccount; ++i ) if ( fv->selected[i] &&
915 (gid = fv->map->map[i])!=-1 &&
916 SCWorthOutputting((sc = fv->sf->glyphs[gid])) &&
917 !sc->ticked) {
918 sc->ticked = true;
919 if ( sc->parent->multilayer ) {
920 first = ly_fore;
921 last = sc->layer_cnt-1;
922 } else
923 first = last = fv->active_layer;
924 for ( layer = first; layer<=last; ++layer ) {
925 SCPreserveLayer(sc,layer,false);
926 SplineCharAddExtrema(sc, sc->layers[layer].splines,
927 force_adding? ae_all : ae_only_good, emsize);
928 }
929 SCCharChangedUpdate(sc,fv->active_layer);
930 if ( !ff_progress_next())
931 break;
932 }
933 ff_progress_end_indicator();
934 }
935
FVCanonicalStart(FontViewBase * fv)936 void FVCanonicalStart(FontViewBase *fv) {
937 int i, gid;
938
939 for ( i=0; i<fv->map->enccount; ++i )
940 if ( fv->selected[i] && (gid = fv->map->map[i])!=-1 )
941 SPLsStartToLeftmost(fv->sf->glyphs[gid],fv->active_layer);
942 }
943
FVCanonicalContours(FontViewBase * fv)944 void FVCanonicalContours(FontViewBase *fv) {
945 int i, gid;
946
947 for ( i=0; i<fv->map->enccount; ++i )
948 if ( fv->selected[i] && (gid = fv->map->map[i])!=-1 )
949 CanonicalContours(fv->sf->glyphs[gid],fv->active_layer);
950 }
951
FVRound2Int(FontViewBase * fv,real factor)952 void FVRound2Int(FontViewBase *fv,real factor) {
953 int i, cnt=0, gid;
954
955 for ( i=0; i<fv->map->enccount; ++i )
956 if ( fv->selected[i] && (gid = fv->map->map[i])!=-1 &&
957 SCWorthOutputting(fv->sf->glyphs[gid]) )
958 ++cnt;
959 ff_progress_start_indicator(10,_("Rounding to integer..."),_("Rounding to integer..."),0,cnt,1);
960
961 for ( i=0; i<fv->map->enccount; ++i ) if ( fv->selected[i] &&
962 (gid = fv->map->map[i])!=-1 && SCWorthOutputting(fv->sf->glyphs[gid]) ) {
963 SplineChar *sc = fv->sf->glyphs[gid];
964
965 SCPreserveLayer(sc,fv->active_layer,false);
966 SCRound2Int( sc,fv->active_layer,factor);
967 if ( !ff_progress_next())
968 break;
969 }
970 ff_progress_end_indicator();
971 }
972
FVCluster(FontViewBase * fv)973 void FVCluster(FontViewBase *fv) {
974 int i, cnt=0, gid;
975
976 for ( i=0; i<fv->map->enccount; ++i )
977 if ( fv->selected[i] && (gid = fv->map->map[i])!=-1 &&
978 SCWorthOutputting(fv->sf->glyphs[gid]) )
979 ++cnt;
980 ff_progress_start_indicator(10,_("Rounding to integer..."),_("Rounding to integer..."),0,cnt,1);
981
982 for ( i=0; i<fv->map->enccount; ++i ) if ( fv->selected[i] &&
983 (gid = fv->map->map[i])!=-1 && SCWorthOutputting(fv->sf->glyphs[gid]) ) {
984 SCRoundToCluster(fv->sf->glyphs[gid],ly_all,false,.1,.5);
985 if ( !ff_progress_next())
986 break;
987 }
988 ff_progress_end_indicator();
989 }
990
FVCorrectDir(FontViewBase * fv)991 void FVCorrectDir(FontViewBase *fv) {
992 int i, cnt=0, changed, refchanged, preserved, layer, first, last, gid;
993 int askedall=-1, asked;
994 RefChar *ref, *next;
995 SplineChar *sc;
996
997 for ( i=0; i<fv->map->enccount; ++i )
998 if ( fv->selected[i] && (gid = fv->map->map[i])!=-1 &&
999 SCWorthOutputting(fv->sf->glyphs[gid]) )
1000 ++cnt;
1001 ff_progress_start_indicator(10,_("Correcting Direction..."),_("Correcting Direction..."),0,cnt,1);
1002
1003 SFUntickAll(fv->sf);
1004 for ( i=0; i<fv->map->enccount; ++i ) if ( fv->selected[i] &&
1005 (gid = fv->map->map[i])!=-1 && SCWorthOutputting((sc=fv->sf->glyphs[gid])) &&
1006 !sc->ticked ) {
1007 sc->ticked = true;
1008 changed = refchanged = preserved = false;
1009 asked = askedall;
1010 if ( sc->parent->multilayer ) {
1011 first = ly_fore;
1012 last = sc->layer_cnt-1;
1013 } else
1014 first = last = fv->active_layer;
1015 for ( layer = first; layer<=last; ++layer ) {
1016 for ( ref=sc->layers[layer].refs; ref!=NULL; ref=next ) {
1017 next = ref->next;
1018 if ( ref->transform[0]*ref->transform[3]<0 ||
1019 (ref->transform[0]==0 && ref->transform[1]*ref->transform[2]>0)) {
1020 if ( asked==-1 ) {
1021 char *buts[5];
1022 buts[0] = _("Unlink All");
1023 buts[1] = _("Unlink");
1024 buts[2] = _("_Cancel");
1025 buts[3] = NULL;
1026 asked = ff_ask(_("Flipped Reference"),(const char **) buts,0,2,_("%.50s contains a flipped reference. This cannot be corrected as is. Would you like me to unlink it and then correct it?"), sc->name );
1027 if ( asked==3 )
1028 return;
1029 else if ( asked==2 )
1030 break;
1031 else if ( asked==0 )
1032 askedall = 0;
1033 }
1034 if ( asked==0 || asked==1 ) {
1035 if ( !preserved ) {
1036 preserved = refchanged = true;
1037 SCPreserveLayer(sc,layer,false);
1038 }
1039 SCRefToSplines(sc,ref,layer);
1040 }
1041 }
1042 }
1043
1044 if ( !preserved && sc->layers[layer].splines!=NULL ) {
1045 SCPreserveLayer(sc,layer,false);
1046 preserved = true;
1047 }
1048 sc->layers[layer].splines = SplineSetsCorrect(sc->layers[layer].splines,&changed);
1049 }
1050 if ( changed || refchanged )
1051 SCCharChangedUpdate(sc,fv->active_layer);
1052 if ( !ff_progress_next())
1053 break;
1054 }
1055 ff_progress_end_indicator();
1056 }
1057
_FVSimplify(FontViewBase * fv,struct simplifyinfo * smpl)1058 void _FVSimplify(FontViewBase *fv,struct simplifyinfo *smpl) {
1059 int i, cnt=0, layer, first, last, gid;
1060 SplineChar *sc;
1061
1062 for ( i=0; i<fv->map->enccount; ++i )
1063 if ( fv->selected[i] && (gid = fv->map->map[i])!=-1 &&
1064 SCWorthOutputting(fv->sf->glyphs[gid]) )
1065 ++cnt;
1066 ff_progress_start_indicator(10,_("Simplifying..."),_("Simplifying..."),0,cnt,1);
1067
1068 SFUntickAll(fv->sf);
1069 for ( i=0; i<fv->map->enccount; ++i )
1070 if ( (gid=fv->map->map[i])!=-1 && SCWorthOutputting((sc=fv->sf->glyphs[gid])) &&
1071 fv->selected[i] && !sc->ticked ) {
1072 sc->ticked = true;
1073 SCPreserveLayer(sc,fv->active_layer,false);
1074 if ( sc->parent->multilayer ) {
1075 first = ly_fore;
1076 last = sc->layer_cnt-1;
1077 } else
1078 first = last = fv->active_layer;
1079 for ( layer = first; layer<=last; ++layer )
1080 sc->layers[layer].splines = SplineCharSimplify(sc,sc->layers[layer].splines,smpl);
1081 SCCharChangedUpdate(sc,fv->active_layer);
1082 if ( !ff_progress_next())
1083 break;
1084 }
1085 ff_progress_end_indicator();
1086 }
1087
FVAutoHint(FontViewBase * fv)1088 void FVAutoHint(FontViewBase *fv) {
1089 int i, cnt=0, gid;
1090 BlueData *bd = NULL, _bd;
1091 SplineChar *sc;
1092
1093 if ( fv->sf->mm==NULL ) {
1094 QuickBlues(fv->sf,fv->active_layer,&_bd);
1095 bd = &_bd;
1096 }
1097
1098 /* Tick the ones we don't want to AH, untick the ones that need AH */
1099 for ( gid = 0; gid<fv->sf->glyphcnt; ++gid ) if ( (sc = fv->sf->glyphs[gid])!=NULL )
1100 sc->ticked = true;
1101
1102 for ( i=0; i<fv->map->enccount; ++i )
1103 if ( fv->selected[i] && (gid = fv->map->map[i])!=-1 &&
1104 SCWorthOutputting(sc = fv->sf->glyphs[gid]) ) {
1105 ++cnt;
1106 sc->ticked = false;
1107 }
1108 ff_progress_start_indicator(10,_("Auto Hinting Font..."),_("Auto Hinting Font..."),0,cnt,1);
1109
1110 for ( i=0; i<fv->map->enccount; ++i ) if ( fv->selected[i] &&
1111 (gid = fv->map->map[i])!=-1 && SCWorthOutputting(fv->sf->glyphs[gid]) ) {
1112 sc = fv->sf->glyphs[gid];
1113 sc->manualhints = false;
1114 /* Hint undoes are done in _SplineCharAutoHint */
1115 SFSCAutoHint(sc,fv->active_layer,bd);
1116 if ( !ff_progress_next())
1117 break;
1118 }
1119 ff_progress_end_indicator();
1120 FVRefreshAll(fv->sf);
1121 }
1122
FVAutoHintSubs(FontViewBase * fv)1123 void FVAutoHintSubs(FontViewBase *fv) {
1124 int i, cnt=0, gid;
1125
1126 if ( fv->sf->mm!=NULL && fv->sf->mm->apple )
1127 return;
1128 for ( i=0; i<fv->map->enccount; ++i )
1129 if ( fv->selected[i] && (gid = fv->map->map[i])!=-1 &&
1130 SCWorthOutputting(fv->sf->glyphs[gid]) )
1131 ++cnt;
1132 ff_progress_start_indicator(10,_("Finding Substitution Points..."),_("Finding Substitution Points..."),0,cnt,1);
1133
1134 for ( i=0; i<fv->map->enccount; ++i ) if ( fv->selected[i] &&
1135 (gid = fv->map->map[i])!=-1 && SCWorthOutputting(fv->sf->glyphs[gid]) ) {
1136 SplineChar *sc = fv->sf->glyphs[gid];
1137 SCFigureHintMasks(sc,fv->active_layer);
1138 SCUpdateAll(sc);
1139 if ( !ff_progress_next())
1140 break;
1141 }
1142 ff_progress_end_indicator();
1143 }
1144
FVAutoCounter(FontViewBase * fv)1145 void FVAutoCounter(FontViewBase *fv) {
1146 int i, cnt=0, gid;
1147
1148 for ( i=0; i<fv->map->enccount; ++i )
1149 if ( fv->selected[i] && (gid = fv->map->map[i])!=-1 &&
1150 SCWorthOutputting(fv->sf->glyphs[gid]) )
1151 ++cnt;
1152 ff_progress_start_indicator(10,_("Finding Counter Masks..."),_("Finding Counter Masks..."),0,cnt,1);
1153
1154 for ( i=0; i<fv->map->enccount; ++i ) if ( fv->selected[i] &&
1155 (gid = fv->map->map[i])!=-1 && SCWorthOutputting(fv->sf->glyphs[gid]) ) {
1156 SplineChar *sc = fv->sf->glyphs[gid];
1157 SCFigureCounterMasks(sc);
1158 if ( !ff_progress_next())
1159 break;
1160 }
1161 ff_progress_end_indicator();
1162 }
1163
FVDontAutoHint(FontViewBase * fv)1164 void FVDontAutoHint(FontViewBase *fv) {
1165 int i, gid;
1166
1167 for ( i=0; i<fv->map->enccount; ++i ) if ( fv->selected[i] &&
1168 (gid = fv->map->map[i])!=-1 && SCWorthOutputting(fv->sf->glyphs[gid]) ) {
1169 SplineChar *sc = fv->sf->glyphs[gid];
1170 sc->manualhints = true;
1171 }
1172 }
1173
AllGlyphsSelected(FontViewBase * fv)1174 static int AllGlyphsSelected(FontViewBase *fv) {
1175 SplineFont *sf = fv->sf;
1176 int gid, enc;
1177 SplineChar *sc;
1178
1179 for ( gid=0; gid<sf->glyphcnt; ++gid ) if ( (sc = sf->glyphs[gid])!=NULL )
1180 sc->ticked = false;
1181
1182 for ( enc=0; enc<fv->map->enccount; ++enc ) {
1183 if ( fv->selected[enc] && (gid=fv->map->map[enc])!=-1 &&
1184 (sc = sf->glyphs[gid])!=NULL )
1185 sc->ticked = true;
1186 }
1187 for ( gid=0; gid<sf->glyphcnt; ++gid ) if ( (sc = sf->glyphs[gid])!=NULL )
1188 if ( !sc->ticked )
1189 return( false );
1190
1191 return( true );
1192 }
1193
AnySelectedHints(FontViewBase * fv)1194 static int AnySelectedHints(FontViewBase *fv) {
1195 SplineFont *sf = fv->sf;
1196 int gid, enc;
1197 SplineChar *sc;
1198
1199 for ( enc=0; enc<fv->map->enccount; ++enc ) {
1200 if ( fv->selected[enc] && (gid=fv->map->map[enc])!=-1 &&
1201 (sc = sf->glyphs[gid])!=NULL &&
1202 (sc->hstem!=NULL || sc->vstem!=NULL || sc->dstem!=NULL ))
1203 return( true ); /* A glyph with hints! */
1204 }
1205
1206 return( false );
1207 }
1208
CIDSetEncMap(FontViewBase * fv,SplineFont * new)1209 void CIDSetEncMap(FontViewBase *fv, SplineFont *new ) {
1210 int gcnt = new->glyphcnt;
1211
1212 if ( fv->cidmaster!=NULL && gcnt!=fv->sf->glyphcnt ) {
1213 int i;
1214 if ( fv->map->encmax<gcnt ) {
1215 fv->map->map = realloc(fv->map->map,gcnt*sizeof(int32));
1216 fv->map->backmap = realloc(fv->map->backmap,gcnt*sizeof(int32));
1217 fv->map->backmax = fv->map->encmax = gcnt;
1218 }
1219 for ( i=0; i<gcnt; ++i )
1220 fv->map->map[i] = fv->map->backmap[i] = i;
1221 if ( gcnt<fv->map->enccount )
1222 memset(fv->selected+gcnt,0,fv->map->enccount-gcnt);
1223 else {
1224 free(fv->selected);
1225 fv->selected = calloc(gcnt,sizeof(uint8));
1226 }
1227 fv->map->enccount = gcnt;
1228 }
1229 fv->sf = new;
1230 new->fv = fv;
1231 FVSetTitle(fv);
1232 FontViewReformatOne(fv);
1233 }
1234
FVInsertInCID(FontViewBase * fv,SplineFont * sf)1235 void FVInsertInCID(FontViewBase *fv,SplineFont *sf) {
1236 SplineFont *cidmaster = fv->cidmaster;
1237 SplineFont **subs;
1238 int i;
1239
1240 subs = malloc((cidmaster->subfontcnt+1)*sizeof(SplineFont *));
1241 for ( i=0; i<cidmaster->subfontcnt && cidmaster->subfonts[i]!=fv->sf; ++i )
1242 subs[i] = cidmaster->subfonts[i];
1243 subs[i] = sf;
1244 if ( sf->uni_interp == ui_none || sf->uni_interp == ui_unset )
1245 sf->uni_interp = cidmaster->uni_interp;
1246 for ( ; i<cidmaster->subfontcnt ; ++i )
1247 subs[i+1] = cidmaster->subfonts[i];
1248 ++cidmaster->subfontcnt;
1249 free(cidmaster->subfonts);
1250 cidmaster->subfonts = subs;
1251 cidmaster->changed = true;
1252 sf->cidmaster = cidmaster;
1253
1254 CIDSetEncMap( fv,sf);
1255 }
1256
ClearFpgmPrepCvt(SplineFont * sf)1257 static void ClearFpgmPrepCvt(SplineFont *sf) {
1258 struct ttf_table *tab, *prev = NULL, *next;
1259
1260 for ( tab = sf->ttf_tables; tab!=NULL ; tab=next ) {
1261 next = tab->next;
1262 if ( tab->tag==CHR('c','v','t',' ') ||
1263 tab->tag==CHR('f','p','g','m') ||
1264 tab->tag==CHR('p','r','e','p') ) {
1265 if ( prev==NULL )
1266 sf->ttf_tables = next;
1267 else
1268 prev->next = next;
1269 tab->next = NULL;
1270 TtfTablesFree(tab);
1271 } else
1272 prev = tab;
1273 }
1274 }
1275
FVAutoInstr(FontViewBase * fv)1276 void FVAutoInstr(FontViewBase *fv) {
1277 BlueData bd;
1278 int i, cnt=0, gid;
1279 GlobalInstrCt gic;
1280
1281 /* If all glyphs are selected, then no legacy hint will remain after */
1282 /* instructing, so we might as well clear all the legacy tables too */
1283 /* (This way the auto hinter won't complain if they existed) */
1284 if ( fv->sf->ttf_tables!=NULL && AllGlyphsSelected(fv))
1285 ClearFpgmPrepCvt(fv->sf);
1286 if ( fv->sf->private==NULL && !no_windowing_ui )
1287 ff_post_notice( _("Things could be better..."), _("You will get better instructions if you fill in the Private dictionary, Element->Font Info->Private, for the font"));
1288 if ( !no_windowing_ui && !AnySelectedHints(fv))
1289 ff_post_notice(_("Things could be better..."), _("The selected glyphs have no hints. FontForge will not produce many instructions."));
1290
1291 QuickBlues(fv->sf,fv->active_layer,&bd);
1292
1293 InitGlobalInstrCt(&gic,fv->sf,fv->active_layer,&bd);
1294
1295 for ( i=0; i<fv->map->enccount; ++i )
1296 if ( fv->selected[i] && (gid = fv->map->map[i])!=-1 &&
1297 SCWorthOutputting(fv->sf->glyphs[gid]) )
1298 ++cnt;
1299 ff_progress_start_indicator(10,_("Auto Instructing Font..."),_("Auto Instructing Font..."),0,cnt,1);
1300
1301 for ( i=0; i<fv->map->enccount; ++i ) if ( fv->selected[i] &&
1302 (gid = fv->map->map[i])!=-1 && SCWorthOutputting(fv->sf->glyphs[gid]) ) {
1303 SplineChar *sc = fv->sf->glyphs[gid];
1304 NowakowskiSCAutoInstr(&gic,sc);
1305 if ( !ff_progress_next())
1306 break;
1307 }
1308
1309 FreeGlobalInstrCt(&gic);
1310
1311 ff_progress_end_indicator();
1312 }
1313
FVClearInstrs(FontViewBase * fv)1314 void FVClearInstrs(FontViewBase *fv) {
1315 SplineChar *sc;
1316 int i, gid;
1317
1318 if ( !SFCloseAllInstrs(fv->sf))
1319 return;
1320
1321 for ( i=0; i<fv->map->enccount; ++i ) if ( fv->selected[i] &&
1322 (gid = fv->map->map[i])!=-1 && SCWorthOutputting((sc = fv->sf->glyphs[gid])) ) {
1323 if ( sc->ttf_instrs_len!=0 ) {
1324 free(sc->ttf_instrs);
1325 sc->ttf_instrs = NULL;
1326 sc->ttf_instrs_len = 0;
1327 sc->instructions_out_of_date = false;
1328 SCCharChangedUpdate(sc,ly_none);
1329 sc->complained_about_ptnums = false;
1330 }
1331 }
1332 }
1333
FVClearHints(FontViewBase * fv)1334 void FVClearHints(FontViewBase *fv) {
1335 int i, gid;
1336
1337 for ( i=0; i<fv->map->enccount; ++i ) if ( fv->selected[i] &&
1338 (gid = fv->map->map[i])!=-1 && SCWorthOutputting(fv->sf->glyphs[gid]) ) {
1339 SplineChar *sc = fv->sf->glyphs[gid];
1340 sc->manualhints = true;
1341 SCPreserveHints(sc,fv->active_layer);
1342 SCClearHints(sc);
1343 SCUpdateAll(sc);
1344 }
1345 }
1346
ViewPostScriptFont(const char * filename,int openflags)1347 FontViewBase *ViewPostScriptFont(const char *filename,int openflags) {
1348 SplineFont *sf = LoadSplineFont(filename,openflags);
1349 extern NameList *force_names_when_opening;
1350 if ( sf==NULL )
1351 return( NULL );
1352 if ( sf->fv==NULL && force_names_when_opening!=NULL )
1353 SFRenameGlyphsToNamelist(sf,force_names_when_opening );
1354 return( FontViewCreate(sf,openflags&of_hidewindow)); /* Always make a new view now */
1355 }
1356
tester(SplineChar * sc,struct lookup_subtable * sub)1357 static int tester(SplineChar *sc, struct lookup_subtable *sub) {
1358 PST *pst;
1359 KernPair *kp;
1360 int isv;
1361 AnchorPoint *ap;
1362
1363 if ( sc==NULL )
1364 return( false );
1365
1366 for ( ap=sc->anchor; ap!=NULL; ap=ap->next )
1367 if ( ap->anchor->subtable == sub )
1368 return( true );
1369 for ( pst=sc->possub; pst!=NULL; pst=pst->next )
1370 if ( pst->subtable==sub )
1371 return( true );
1372 for ( isv=0; isv<2; ++isv )
1373 for ( kp = isv ? sc->vkerns : sc->kerns; kp!=NULL; kp=kp->next )
1374 if ( kp->subtable == sub )
1375 return( true );
1376
1377 return( false );
1378 }
1379
FVBParseSelectByPST(FontViewBase * fv,struct lookup_subtable * sub,int search_type)1380 int FVBParseSelectByPST(FontViewBase *fv,struct lookup_subtable *sub,
1381 int search_type) {
1382 int i;
1383 SplineFont *sf;
1384 int first;
1385 int gid;
1386
1387 sf = fv->sf;
1388 first = -1;
1389 if ( search_type==1 ) { /* Select results */
1390 for ( i=0; i<fv->map->enccount; ++i ) {
1391 gid=fv->map->map[i];
1392 if ( (fv->selected[i] = tester(gid==-1?NULL:sf->glyphs[gid],sub)) && first==-1 )
1393 first = i;
1394 }
1395 } else if ( search_type==2) {/* merge results */
1396 for ( i=0; i<fv->map->enccount; ++i ) if ( !fv->selected[i] ) {
1397 gid=fv->map->map[i];
1398 if ( (fv->selected[i] = tester(gid==-1?NULL:sf->glyphs[gid],sub)) && first==-1 )
1399 first = i;
1400 }
1401 } else { /* restrict selection */
1402 for ( i=0; i<fv->map->enccount; ++i ) if ( fv->selected[i] ) {
1403 gid=fv->map->map[i];
1404 if ( (fv->selected[i] = tester(gid==-1?NULL:sf->glyphs[gid],sub)) && first==-1 )
1405 first = i;
1406 }
1407 }
1408 return( first );
1409 }
1410
FVBuildAccent(FontViewBase * fv,int onlyaccents)1411 void FVBuildAccent(FontViewBase *fv,int onlyaccents) {
1412 int i, cnt=0, gid;
1413 SplineChar dummy;
1414 SplineChar *sc;
1415
1416 for ( i=0; i<fv->map->enccount; ++i )
1417 if ( fv->selected[i] && (gid = fv->map->map[i])!=-1 &&
1418 SCWorthOutputting(fv->sf->glyphs[gid]) )
1419 ++cnt;
1420 ff_progress_start_indicator(10,_("Building accented glyphs"),
1421 _("Building accented glyphs"),NULL,cnt,1);
1422
1423 SFUntickAll(fv->sf);
1424 for ( i=0; i<fv->map->enccount; ++i ) if ( fv->selected[i] ) {
1425 gid = fv->map->map[i];
1426 sc = NULL;
1427 if ( gid!=-1 ) {
1428 sc = fv->sf->glyphs[gid];
1429 if ( sc!=NULL && sc->ticked )
1430 continue;
1431 }
1432 if ( sc==NULL )
1433 sc = SCBuildDummy(&dummy,fv->sf,fv->map,i);
1434 else if ( !no_windowing_ui && sc->unicodeenc == 0x00c5 /* Aring */ &&
1435 sc->layers[fv->active_layer].splines!=NULL ) {
1436 char *buts[3];
1437 buts[0] = _("_Yes");
1438 buts[1] = _("_No");
1439 buts[2] = NULL;
1440 if ( ff_ask(U_("Replace Å"),(const char **) buts,0,1,U_("Are you sure you want to replace Å?\nThe ring will not join to the A."))==1 )
1441 continue;
1442 }
1443 if ( SFIsSomethingBuildable(fv->sf,sc,fv->active_layer,onlyaccents) ) {
1444 sc = SFMakeChar(fv->sf,fv->map,i);
1445 sc->ticked = true;
1446 SCBuildComposit(fv->sf,sc,fv->active_layer,fv->active_bitmap,onlycopydisplayed,onlyaccents);
1447 }
1448 if ( !ff_progress_next())
1449 break;
1450 }
1451 ff_progress_end_indicator();
1452 }
1453
FVAddUnencoded(FontViewBase * fv,int cnt)1454 void FVAddUnencoded(FontViewBase *fv, int cnt) {
1455 int i;
1456 EncMap *map = fv->map;
1457
1458 if ( fv->normal!=NULL ) {
1459 /* If it's compacted, lose the base encoding and the fact that it's */
1460 /* compact and make it be custom. That's what Alexey Kryukov asked */
1461 /* for */
1462 EncMapFree(fv->normal);
1463 // If fv->normal happens to be fv->sf->map, freeing it leaves an invalid pointer in the splinefont.
1464 // So we tell the splinefont to use the fontview map.
1465 if (fv->sf != NULL && fv->normal == fv->sf->map) { fv->sf->map = NULL; }
1466 fv->normal = NULL;
1467 fv->map->enc = &custom;
1468 FVSetTitle(fv);
1469 }
1470 if ( fv->cidmaster ) {
1471 SplineFont *sf = fv->sf;
1472 FontViewBase *fvs;
1473 if ( sf->glyphcnt+cnt>=sf->glyphmax )
1474 sf->glyphs = realloc(sf->glyphs,(sf->glyphmax = sf->glyphcnt+cnt+10)*sizeof(SplineChar *));
1475 memset(sf->glyphs+sf->glyphcnt,0,cnt*sizeof(SplineChar *));
1476 for ( fvs=sf->fv; fvs!=NULL; fvs=fvs->nextsame ) {
1477 EncMap *map = fvs->map;
1478 if ( map->enccount+cnt>=map->encmax )
1479 map->map = realloc(map->map,(map->encmax += cnt+10)*sizeof(int));
1480 if ( sf->glyphcnt+cnt>=map->backmax )
1481 map->backmap = realloc(map->backmap,(map->backmax += cnt+10)*sizeof(int));
1482 for ( i=map->enccount; i<map->enccount+cnt; ++i )
1483 map->map[i] = map->backmap[i] = i;
1484 fvs->selected = realloc(fvs->selected,(map->enccount+cnt));
1485 memset(fvs->selected+map->enccount,0,cnt);
1486 map->enccount += cnt;
1487 }
1488 sf->glyphcnt += cnt;
1489 FontViewReformatAll(fv->sf);
1490 } else {
1491 if ( map->enccount+cnt>=map->encmax )
1492 map->map = realloc(map->map,(map->encmax += cnt+10)*sizeof(int));
1493 for ( i=map->enccount; i<map->enccount+cnt; ++i )
1494 map->map[i] = -1;
1495 fv->selected = realloc(fv->selected,(map->enccount+cnt));
1496 memset(fv->selected+map->enccount,0,cnt);
1497 map->enccount += cnt;
1498 FontViewReformatOne(fv);
1499 FVDisplayEnc(fv,map->enccount-cnt);
1500 }
1501 }
1502
FVRemoveUnused(FontViewBase * fv)1503 void FVRemoveUnused(FontViewBase *fv) {
1504 SplineFont *sf = fv->sf;
1505 EncMap *map = fv->map;
1506 int oldcount = map->enccount;
1507 int gid, i;
1508 int flags = -1;
1509
1510 for ( i=map->enccount-1;
1511 i>=map->enc->char_cnt &&
1512 ((gid=map->map[i])==-1 || !SCWorthOutputting(sf->glyphs[gid]));
1513 --i ) {
1514 if ( gid!=-1 )
1515 SFRemoveGlyph(sf,sf->glyphs[gid]);
1516 map->enccount = i;
1517 }
1518 /* We reduced the encoding, so don't really need to reallocate the selection */
1519 /* array. It's just bigger than it needs to be. */
1520 if ( oldcount!=map->enccount )
1521 FontViewReformatOne(fv);
1522 }
1523
FVCompact(FontViewBase * fv)1524 void FVCompact(FontViewBase *fv) {
1525 int oldcount = fv->map->enccount;
1526
1527 if ( fv->normal!=NULL ) {
1528 EncMapFree(fv->map);
1529 if (fv->sf != NULL && fv->sf->map == fv->map) { fv->sf->map = fv->normal ; }
1530 fv->map = fv->normal;
1531 fv->normal = NULL;
1532 fv->selected = realloc(fv->selected,fv->map->enccount);
1533 memset(fv->selected,0,fv->map->enccount);
1534 } else {
1535 /* We reduced the encoding, so don't really need to reallocate the selection */
1536 /* array. It's just bigger than it needs to be. */
1537 fv->normal = EncMapCopy(fv->map);
1538 CompactEncMap(fv->map,fv->sf);
1539 fv->sf->map = fv->map;
1540 }
1541 if ( oldcount!=fv->map->enccount )
1542 FontViewReformatOne(fv);
1543 FVSetTitle(fv);
1544 }
1545
FVDetachGlyphs(FontViewBase * fv)1546 void FVDetachGlyphs(FontViewBase *fv) {
1547 int i, j, gid;
1548 EncMap *map = fv->map;
1549 int altered = false;
1550 SplineFont *sf = fv->sf;
1551
1552 for ( i=0; i<map->enccount; ++i ) if ( fv->selected[i] && (gid=map->map[i])!=-1 ) {
1553 altered = true;
1554 map->map[i] = -1;
1555 if ( map->backmap[gid]==i ) {
1556 for ( j=map->enccount-1; j>=0 && map->map[j]!=gid; --j );
1557 map->backmap[gid] = j;
1558 }
1559 if ( sf->glyphs[gid]!=NULL && sf->glyphs[gid]->altuni != NULL && map->enc!=&custom )
1560 AltUniRemove(sf->glyphs[gid],UniFromEnc(i,map->enc));
1561 }
1562 if ( altered )
1563 FVRefreshAll(sf);
1564 }
1565
FVDetachAndRemoveGlyphs(FontViewBase * fv)1566 void FVDetachAndRemoveGlyphs(FontViewBase *fv) {
1567 int i, j, gid;
1568 EncMap *map = fv->map;
1569 SplineFont *sf = fv->sf;
1570 int flags = -1;
1571 int changed = false, altered = false;
1572 FontViewBase *fvs;
1573
1574 for ( i=0; i<map->enccount; ++i ) if ( fv->selected[i] && (gid=map->map[i])!=-1 ) {
1575 altered = true;
1576 map->map[i] = -1;
1577 if ( map->backmap[gid]==i ) {
1578 for ( j=map->enccount-1; j>=0 && map->map[j]!=gid; --j );
1579 map->backmap[gid] = j;
1580 if ( j==-1 ) {
1581 SFRemoveGlyph(sf,sf->glyphs[gid]);
1582 changed = true;
1583 } else if ( sf->glyphs[gid]!=NULL && sf->glyphs[gid]->altuni != NULL && map->enc!=&custom )
1584 AltUniRemove(sf->glyphs[gid],UniFromEnc(i,map->enc));
1585 }
1586 }
1587 if ( changed && !fv->sf->changed ) {
1588 fv->sf->changed = true;
1589 for ( fvs=sf->fv; fvs!=NULL; fvs=fvs->nextsame )
1590 FVSetTitle(fvs);
1591 }
1592 if ( altered )
1593 FVRefreshAll(sf);
1594 }
1595
FVMetricsCenter(FontViewBase * fv,int docenter)1596 void FVMetricsCenter(FontViewBase *fv,int docenter) {
1597 int i, gid;
1598 SplineChar *sc;
1599 DBounds bb;
1600 IBounds ib;
1601 real transform[6], itransform[6];
1602 BVTFunc bvts[2];
1603 BDFFont *bdf;
1604
1605 memset(transform,0,sizeof(transform));
1606 memset(itransform,0,sizeof(itransform));
1607 transform[0] = transform[3] = 1.0;
1608 itransform[0] = itransform[3] = 1.0;
1609 itransform[2] = tan( fv->sf->italicangle * FF_PI/180.0 );
1610 bvts[1].func = bvt_none;
1611 bvts[0].func = bvt_transmove; bvts[0].y = 0;
1612 if ( !fv->sf->onlybitmaps ) {
1613 for ( i=0; i<fv->map->enccount; ++i ) {
1614 if ( fv->selected[i] && (gid=fv->map->map[i])!=-1 &&
1615 (sc = fv->sf->glyphs[gid])!=NULL ) {
1616 if ( itransform[2] == 0 )
1617 SplineCharFindBounds(sc,&bb);
1618 else {
1619 SplineSet *base, *temp;
1620 base = LayerAllSplines(&sc->layers[fv->active_layer]);
1621 temp = SplinePointListTransform(SplinePointListCopy(base),itransform,tpt_AllPoints);
1622 LayerUnAllSplines(&sc->layers[fv->active_layer]);
1623 SplineSetFindBounds(temp,&bb);
1624 SplinePointListsFree(temp);
1625 }
1626 if ( docenter )
1627 transform[4] = (sc->width-(bb.maxx-bb.minx))/2 - bb.minx;
1628 else
1629 transform[4] = (sc->width-(bb.maxx-bb.minx))/3 - bb.minx;
1630 if ( transform[4]!=0 ) {
1631 FVTrans(fv,sc,transform,NULL, fvt_dontmovewidth | fvt_alllayers );
1632 bvts[0].x = transform[4];
1633 for ( bdf = fv->sf->bitmaps; bdf!=NULL; bdf=bdf->next )
1634 if ( gid<bdf->glyphcnt && bdf->glyphs[gid]!=NULL )
1635 BCTrans(bdf,bdf->glyphs[gid],bvts,fv);
1636 }
1637 }
1638 }
1639 } else {
1640 double scale = (fv->sf->ascent+fv->sf->descent)/(double) (fv->active_bitmap->pixelsize);
1641 for ( i=0; i<fv->map->enccount; ++i ) {
1642 if ( fv->selected[i] && (gid=fv->map->map[i])!=-1 &&
1643 fv->sf->glyphs[gid]!=NULL ) {
1644 BDFChar *bc = fv->active_bitmap->glyphs[gid];
1645 if ( bc==NULL ) bc = BDFMakeChar(fv->active_bitmap,fv->map,i);
1646 BDFCharFindBounds(bc,&ib);
1647 if ( docenter )
1648 transform[4] = scale * ((bc->width-(ib.maxx-ib.minx))/2 - ib.minx);
1649 else
1650 transform[4] = scale * ((bc->width-(ib.maxx-ib.minx))/3 - ib.minx);
1651 if ( transform[4]!=0 ) {
1652 FVTrans(fv,fv->sf->glyphs[gid],transform,NULL,fvt_dontmovewidth);
1653 bvts[0].x = transform[4];
1654 for ( bdf = fv->sf->bitmaps; bdf!=NULL; bdf=bdf->next )
1655 if ( gid<bdf->glyphcnt && bdf->glyphs[gid]!=NULL )
1656 BCTrans(bdf,bdf->glyphs[gid],bvts,fv);
1657 }
1658 }
1659 }
1660 }
1661 }
1662
RevertAskChanged(char * fontname,char * filename)1663 static int RevertAskChanged(char *fontname,char *filename) {
1664 int ret;
1665 char *buts[3];
1666
1667 if ( filename==NULL ) filename = "untitled.sfd";
1668 filename = GFileNameTail(filename);
1669 buts[0] = _("_Revert");
1670 buts[1] = _("_Cancel");
1671 buts[2] = NULL;
1672 ret = ff_ask( _("Font changed"),(const char **) buts,0,1,_("Font %1$.40s in file %2$.40s has been changed.\nReverting the file will lose those changes.\nIs that what you want?"),fontname,filename);
1673 return( ret==0 );
1674 }
1675
_FVRevert(FontViewBase * fv,int tobackup)1676 static void _FVRevert(FontViewBase *fv,int tobackup) {
1677 SplineFont *temp, *old = fv->cidmaster?fv->cidmaster:fv->sf;
1678 BDFFont *bdf;
1679 int i;
1680 FontViewBase *fvs;
1681 EncMap *map;
1682
1683 if ( old->origname==NULL )
1684 return;
1685 if ( old->changed )
1686 if ( !RevertAskChanged(old->fontname,old->origname))
1687 return;
1688 if ( tobackup ) {
1689 /* we can only revert to backup if it's an sfd file. So we use filename*/
1690 /* here. In the normal case we revert to whatever file we read it from*/
1691 /* (sfd or not) so we use origname */
1692 char *buf = malloc(strlen(old->filename)+20);
1693 strcpy(buf,old->filename);
1694 if ( old->compression!=0 ) {
1695 char *tmpf;
1696 strcat(buf,compressors[old->compression-1].ext);
1697 strcat(buf,"~");
1698 tmpf = Decompress(buf,old->compression-1);
1699 if ( tmpf==NULL )
1700 temp = NULL;
1701 else {
1702 temp = ReadSplineFont(tmpf,0);
1703 unlink(tmpf);
1704 free(tmpf);
1705 }
1706 } else {
1707 strcat(buf,"~");
1708 temp = ReadSplineFont(buf,0);
1709 }
1710 free(buf);
1711 } else {
1712 if ( old->compression!=0 ) {
1713 char *tmpf;
1714 char *buf = malloc(strlen(old->filename)+20);
1715 strcpy(buf,old->filename);
1716 strcat(buf,compressors[old->compression-1].ext);
1717 tmpf = Decompress(buf,old->compression-1);
1718 if ( tmpf==NULL )
1719 temp = NULL;
1720 else {
1721 temp = ReadSplineFont(tmpf,0);
1722 unlink(tmpf);
1723 free(tmpf);
1724 }
1725 } else
1726 temp = ReadSplineFont(old->origname,0);
1727 }
1728 if ( temp==NULL ) {
1729 return;
1730 }
1731 if ( temp->filename!=NULL ) {
1732 free(temp->filename);
1733 temp->filename = copy(old->filename);
1734 }
1735 if ( temp->origname!=NULL ) {
1736 free(temp->origname);
1737 temp->origname = copy(old->origname);
1738 }
1739 temp->compression = old->compression;
1740 temp->fv = old->fv;
1741 FVReattachCVs(old,temp);
1742 for ( i=0; i<old->subfontcnt; ++i )
1743 FVReattachCVs(old->subfonts[i],temp);
1744 if ( fv->sf->fontinfo )
1745 FontInfo_Destroy(fv->sf);
1746 for ( bdf=old->bitmaps; bdf!=NULL; bdf=bdf->next )
1747 for ( i=0; i<bdf->glyphcnt; ++i ) if ( bdf->glyphs[i]!=NULL )
1748 BCDestroyAll(bdf->glyphs[i]);
1749 MVDestroyAll(old);
1750 for ( fvs=fv->sf->fv; fvs!=NULL; fvs=fvs->nextsame ) {
1751 if ( fvs==fv )
1752 map = temp->map;
1753 else
1754 map = EncMapFromEncoding(fv->sf,fv->map->enc);
1755 if ( map->enccount>fvs->map->enccount ) {
1756 fvs->selected = realloc(fvs->selected,map->enccount);
1757 memset(fvs->selected+fvs->map->enccount,0,map->enccount-fvs->map->enccount);
1758 }
1759 EncMapFree(fv->map);
1760 if (fv->sf != NULL && fv->map == fv->sf->map) { fv->sf->map = map; }
1761 fv->map = map;
1762 if ( fvs->normal!=NULL ) {
1763 EncMapFree(fvs->normal);
1764 fvs->normal = EncMapCopy(fvs->map);
1765 CompactEncMap(fvs->map,temp);
1766 }
1767 }
1768 ff_progress_allow_events();
1769 SFClearAutoSave(old);
1770 temp->fv = fv->sf->fv;
1771 for ( fvs=fv->sf->fv; fvs!=NULL; fvs=fvs->nextsame )
1772 fvs->sf = temp;
1773 FontViewReformatAll(fv->sf);
1774 SplineFontFree(old);
1775 }
1776
FVRevert(FontViewBase * fv)1777 void FVRevert(FontViewBase *fv) {
1778 _FVRevert(fv,false);
1779 }
1780
FVRevertBackup(FontViewBase * fv)1781 void FVRevertBackup(FontViewBase *fv) {
1782 _FVRevert(fv,true);
1783 }
1784
FVRevertGlyph(FontViewBase * fv)1785 void FVRevertGlyph(FontViewBase *fv) {
1786 int i, gid;
1787 int nc_state = -1;
1788 SplineFont *sf = fv->sf;
1789 SplineChar *sc, *tsc;
1790 SplineChar temp;
1791 Undoes **undoes;
1792 int layer, lc;
1793 EncMap *map = fv->map;
1794 CharViewBase *cvs;
1795 int alayer = ly_fore;
1796
1797 if ( fv->sf->sfd_version<2 )
1798 ff_post_error(_("Old sfd file"),_("This font comes from an old format sfd file. Not all aspects of it can be reverted successfully."));
1799
1800 for ( i=0; i<map->enccount; ++i ) if ( fv->selected[i] && (gid=map->map[i])!=-1 && sf->glyphs[gid]!=NULL ) {
1801 tsc = sf->glyphs[gid];
1802 if ( tsc->namechanged ) {
1803 if ( nc_state==-1 ) {
1804 ff_post_error(_("Glyph Name Changed"),_("The name of glyph %.40s has changed. This is what I use to find the glyph in the file, so I cannot revert this glyph.\n(You will not be warned for subsequent glyphs.)"),tsc->name);
1805 nc_state = 0;
1806 }
1807 } else {
1808 sc = SFDReadOneChar(sf,tsc->name);
1809 if ( sc==NULL ) {
1810 ff_post_error(_("Can't Find Glyph"),_("The glyph, %.80s, can't be found in the sfd file"),tsc->name);
1811 tsc->namechanged = true;
1812 } else {
1813 SCPreserveState(tsc,true);
1814 SCPreserveBackground(tsc);
1815 if ( tsc->views!=NULL )
1816 alayer = CVLayer(tsc->views);
1817 temp = *tsc;
1818 tsc->dependents = NULL;
1819 lc = tsc->layer_cnt;
1820 undoes = malloc(lc*sizeof(Undoes *));
1821 for ( layer=0; layer<lc; ++layer ) {
1822 undoes[layer] = tsc->layers[layer].undoes;
1823 tsc->layers[layer].undoes = NULL;
1824 }
1825 SplineCharFreeContents(tsc);
1826 *tsc = *sc;
1827 chunkfree(sc,sizeof(SplineChar));
1828 tsc->parent = sf;
1829 tsc->dependents = temp.dependents;
1830 tsc->views = temp.views;
1831 for ( layer = 0; layer<lc && layer<tsc->layer_cnt; ++layer )
1832 tsc->layers[layer].undoes = undoes[layer];
1833 for ( ; layer<lc; ++layer )
1834 UndoesFree(undoes[layer]);
1835 free(undoes);
1836 /* tsc->changed = temp.changed; */
1837 /* tsc->orig_pos = temp.orig_pos; */
1838 for ( cvs=tsc->views; cvs!=NULL; cvs= cvs->next ) {
1839 cvs->layerheads[dm_back] = &tsc->layers[ly_back];
1840 cvs->layerheads[dm_fore] = &tsc->layers[ly_fore];
1841 if ( sf->multilayer ) {
1842 if ( alayer!=ly_back )
1843 cvs->layerheads[dm_fore] = &tsc->layers[alayer];
1844 } else {
1845 if ( alayer!=ly_fore )
1846 cvs->layerheads[dm_back] = &tsc->layers[alayer];
1847 }
1848 }
1849 RevertedGlyphReferenceFixup(tsc, sf);
1850 _SCCharChangedUpdate(tsc,alayer,false);
1851 }
1852 }
1853 }
1854 }
1855
FVClearSpecialData(FontViewBase * fv)1856 void FVClearSpecialData(FontViewBase *fv) {
1857 SplineFont *sf = fv->sf;
1858 if (sf) SplineFontClearSpecial(sf);
1859 }
1860
isuniname(char * name)1861 static int isuniname(char *name) {
1862 int i;
1863 if ( name[0]!='u' || name[1]!='n' || name[2]!='i' )
1864 return( false );
1865 for ( i=3; i<7; ++i )
1866 if ( name[i]<'0' || (name[i]>'9' && name[i]<'A') || name[i]>'F' )
1867 return( false );
1868 if ( name[7]!='\0' )
1869 return( false );
1870
1871 return( true );
1872 }
1873
isuname(char * name)1874 static int isuname(char *name) {
1875 int i;
1876 if ( name[0]!='u' )
1877 return( false );
1878 for ( i=1; i<5; ++i )
1879 if ( name[i]<'0' || (name[i]>'9' && name[i]<'A') || name[i]>'F' )
1880 return( false );
1881 if ( name[5]!='\0' )
1882 return( false );
1883
1884 return( true );
1885 }
1886
FVB_MakeNamelist(FontViewBase * fv,FILE * file)1887 void FVB_MakeNamelist(FontViewBase *fv, FILE *file) {
1888 SplineChar *sc;
1889 int i;
1890
1891 for ( i=0; i<fv->sf->glyphcnt; ++i ) {
1892 if ( (sc = fv->sf->glyphs[i])!=NULL && sc->unicodeenc!=-1 ) {
1893 if ( !isuniname(sc->name) && !isuname(sc->name ) )
1894 fprintf( file, "0x%04X %s\n", sc->unicodeenc, sc->name );
1895 }
1896 }
1897 }
1898
1899 /* FV Interface */
1900
_FontViewBaseCreate(SplineFont * sf)1901 static FontViewBase *_FontViewBaseCreate(SplineFont *sf) {
1902 FontViewBase *fv = calloc(1,sizeof(FontViewBase));
1903 int i;
1904
1905 fv->nextsame = sf->fv;
1906 fv->active_layer = ly_fore;
1907 sf->fv = fv;
1908 if ( sf->mm!=NULL ) {
1909 sf->mm->normal->fv = fv;
1910 for ( i = 0; i<sf->mm->instance_count; ++i )
1911 sf->mm->instances[i]->fv = fv;
1912 }
1913 if ( sf->subfontcnt==0 ) {
1914 fv->sf = sf;
1915 if ( fv->nextsame!=NULL ) {
1916 fv->map = EncMapCopy(fv->nextsame->map);
1917 fv->normal = fv->nextsame->normal==NULL ? NULL : EncMapCopy(fv->nextsame->normal);
1918 fprintf(stderr, "There are two FontViews using the same SplineFont. Please report on the issue tracker or the mailing list how you reached this point.\n");
1919 } else if ( sf->compacted ) {
1920 fv->normal = sf->map;
1921 fv->map = CompactEncMap(EncMapCopy(sf->map),sf);
1922 sf->map = fv->map;
1923 } else {
1924 fv->map = sf->map;
1925 fv->normal = NULL;
1926 }
1927 } else {
1928 fv->cidmaster = sf;
1929 for ( i=0; i<sf->subfontcnt; ++i )
1930 sf->subfonts[i]->fv = fv;
1931 for ( i=0; i<sf->subfontcnt; ++i ) /* Search for a subfont that contains more than ".notdef" (most significant in .gai fonts) */
1932 if ( sf->subfonts[i]->glyphcnt>1 ) {
1933 fv->sf = sf->subfonts[i];
1934 break;
1935 }
1936 if ( fv->sf==NULL )
1937 fv->sf = sf->subfonts[0];
1938 sf = fv->sf;
1939 if ( fv->nextsame==NULL ) { EncMapFree(sf->map); sf->map = NULL; }
1940 fv->map = EncMap1to1(sf->glyphcnt);
1941 if ( fv->nextsame==NULL ) { sf->map = fv->map; }
1942 }
1943 fv->selected = calloc(fv->map->enccount,sizeof(uint8));
1944
1945 #ifndef _NO_PYTHON
1946 PyFF_InitFontHook(fv);
1947 #endif
1948 return( fv );
1949 }
1950
FontViewBase_Create(SplineFont * sf,int UNUSED (hide))1951 static FontViewBase *FontViewBase_Create(SplineFont *sf,int UNUSED(hide)) {
1952 FontViewBase *fv = _FontViewBaseCreate(sf);
1953 return( fv );
1954 }
1955
FontViewBase_Append(FontViewBase * fv)1956 static FontViewBase *FontViewBase_Append(FontViewBase *fv)
1957 {
1958 /* Normally fontviews get added to the fv list when their windows are */
1959 /* created. but we don't create any windows here, so... */
1960 FontViewBase *test;
1961
1962 if ( fv_list==NULL ) fv_list = fv;
1963 else {
1964 for ( test = fv_list; test->next!=NULL; test=test->next );
1965 test->next = fv;
1966 }
1967 return( fv );
1968 }
1969
FontViewBase_Free(FontViewBase * fv)1970 static void FontViewBase_Free(FontViewBase *fv) {
1971 int i;
1972 FontViewBase *prev;
1973
1974 if ( fv->nextsame==NULL && fv->sf->fv==fv ) {
1975 EncMapFree(fv->map);
1976 if (fv->sf != NULL && fv->map == fv->sf->map) { fv->sf->map = NULL; }
1977 fv->map = NULL;
1978 SplineFontFree(fv->cidmaster?fv->cidmaster:fv->sf);
1979 } else {
1980 EncMapFree(fv->map);
1981 if (fv->sf != NULL && fv->map == fv->sf->map) { fv->sf->map = NULL; }
1982 fv->map = NULL;
1983 if ( fv->sf->fv==fv ) {
1984 if ( fv->cidmaster==NULL )
1985 fv->sf->fv = fv->nextsame;
1986 else {
1987 fv->cidmaster->fv = fv->nextsame;
1988 for ( i=0; i<fv->cidmaster->subfontcnt; ++i )
1989 fv->cidmaster->subfonts[i]->fv = fv->nextsame;
1990 }
1991 } else {
1992 for ( prev = fv->sf->fv; prev->nextsame!=fv; prev=prev->nextsame );
1993 prev->nextsame = fv->nextsame;
1994 }
1995 }
1996 #ifndef _NO_FFSCRIPT
1997 DictionaryFree(fv->fontvars);
1998 free(fv->fontvars);
1999 #endif
2000 free(fv->selected);
2001 #ifndef _NO_PYTHON
2002 PyFF_FreeFV(fv);
2003 #endif
2004 free(fv);
2005 }
2006
FontViewBaseWinInfo(FontViewBase * UNUSED (fv),int * cc,int * rc)2007 static int FontViewBaseWinInfo(FontViewBase *UNUSED(fv), int *cc, int *rc) {
2008 *cc = 16; *rc = 4;
2009 return( -1 );
2010 }
2011
FontViewBaseSetTitle(FontViewBase * UNUSED (foo))2012 static void FontViewBaseSetTitle(FontViewBase *UNUSED(foo)) { }
FontViewBaseSetTitles(SplineFont * UNUSED (foo))2013 static void FontViewBaseSetTitles(SplineFont *UNUSED(foo)) { }
FontViewBaseRefreshAll(SplineFont * UNUSED (foo))2014 static void FontViewBaseRefreshAll(SplineFont *UNUSED(foo)) { }
FontViewBaseReformatOne(FontViewBase * UNUSED (foo))2015 static void FontViewBaseReformatOne(FontViewBase *UNUSED(foo)) { }
FontViewBaseReformatAll(SplineFont * UNUSED (foo))2016 static void FontViewBaseReformatAll(SplineFont *UNUSED(foo)) { }
FontViewBaseLayerChanged(FontViewBase * UNUSED (foo))2017 static void FontViewBaseLayerChanged(FontViewBase *UNUSED(foo)) { }
FV_ToggleCharChanged(SplineChar * UNUSED (foo))2018 static void FV_ToggleCharChanged(SplineChar *UNUSED(foo)) { }
FVAny(void)2019 static FontViewBase *FVAny(void) { return fv_list; }
FontIsActive(SplineFont * sf)2020 static int FontIsActive(SplineFont *sf) {
2021 FontViewBase *fv;
2022
2023 for ( fv=fv_list; fv!=NULL; fv=fv->next )
2024 if ( fv->sf == sf )
2025 return( true );
2026
2027 return( false );
2028 }
2029
FontOfFilename(const char * filename)2030 static SplineFont *FontOfFilename(const char *filename) {
2031 char buffer[1025];
2032 FontViewBase *fv;
2033
2034 GFileGetAbsoluteName((char *) filename,buffer,sizeof(buffer));
2035 for ( fv=fv_list; fv!=NULL ; fv=fv->next ) {
2036 if ( fv->sf->filename!=NULL && strcmp(fv->sf->filename,buffer)==0 )
2037 return( fv->sf );
2038 else if ( fv->sf->origname!=NULL && strcmp(fv->sf->origname,buffer)==0 )
2039 return( fv->sf );
2040 }
2041 return( NULL );
2042 }
2043
FVExtraEncSlots(FontViewBase * UNUSED (fv),int UNUSED (encmax))2044 static void FVExtraEncSlots(FontViewBase *UNUSED(fv), int UNUSED(encmax)) {
2045 }
2046
FontViewBase_Close(FontViewBase * fv)2047 static void FontViewBase_Close(FontViewBase *fv) {
2048 if ( fv_list==fv )
2049 fv_list = fv->next;
2050 else {
2051 FontViewBase *n;
2052 for ( n=fv_list; n->next!=fv; n=n->next );
2053 n->next = fv->next;
2054 }
2055 FontViewFree(fv);
2056 }
2057
FVB_ChangeDisplayBitmap(FontViewBase * fv,BDFFont * bdf)2058 static void FVB_ChangeDisplayBitmap(FontViewBase *fv, BDFFont *bdf) {
2059 fv->active_bitmap = bdf;
2060 }
2061
FVB_ShowFilled(FontViewBase * fv)2062 static void FVB_ShowFilled(FontViewBase *fv) {
2063 fv->active_bitmap = NULL;
2064 }
2065
FVB_ReattachCVs(SplineFont * UNUSED (old),SplineFont * UNUSED (new))2066 static void FVB_ReattachCVs(SplineFont *UNUSED(old), SplineFont *UNUSED(new)) {
2067 }
2068
FVB_DeselectAll(FontViewBase * fv)2069 static void FVB_DeselectAll(FontViewBase *fv) {
2070 memset(fv->selected,0,fv->map->encmax);
2071 }
2072
FVB_DisplayChar(FontViewBase * UNUSED (fv),int UNUSED (gid))2073 static void FVB_DisplayChar(FontViewBase *UNUSED(fv),int UNUSED(gid)) {
2074 }
2075
SFB_CloseAllInstrs(SplineFont * UNUSED (sf))2076 static int SFB_CloseAllInstrs(SplineFont *UNUSED(sf)) {
2077 return( true );
2078 }
2079
2080 struct fv_interface noui_fv = {
2081 FontViewBase_Create,
2082 _FontViewBaseCreate,
2083 FontViewBase_Close,
2084 FontViewBase_Free,
2085 FontViewBaseSetTitle,
2086 FontViewBaseSetTitles,
2087 FontViewBaseRefreshAll,
2088 FontViewBaseReformatOne,
2089 FontViewBaseReformatAll,
2090 FontViewBaseLayerChanged,
2091 FV_ToggleCharChanged,
2092 FontViewBaseWinInfo,
2093 FontIsActive,
2094 FVAny,
2095 FontViewBase_Append,
2096 FontOfFilename,
2097 FVExtraEncSlots,
2098 FVExtraEncSlots,
2099 FVB_ChangeDisplayBitmap,
2100 FVB_ShowFilled,
2101 FVB_ReattachCVs,
2102 FVB_DeselectAll,
2103 FVB_DisplayChar,
2104 FVB_DisplayChar,
2105 FVB_DisplayChar,
2106 SFB_CloseAllInstrs
2107 };
2108
2109 struct fv_interface *fv_interface = &noui_fv;
2110
FF_SetFVInterface(struct fv_interface * fvi)2111 void FF_SetFVInterface(struct fv_interface *fvi) {
2112 fv_interface = fvi;
2113 }
2114
2115
2116 /******************************************************************************/
NoGlyphs(struct metricsview * UNUSED (mv))2117 static int NoGlyphs(struct metricsview *UNUSED(mv)) {
2118 return( 0 );
2119 }
2120
Nothing(struct metricsview * UNUSED (mv),int UNUSED (i))2121 static SplineChar *Nothing(struct metricsview *UNUSED(mv), int UNUSED(i)) {
2122 return( NULL );
2123 }
2124
NoReKern(struct splinefont * UNUSED (sf))2125 static void NoReKern(struct splinefont *UNUSED(sf)) {
2126 }
2127
NoReFeature(struct splinefont * UNUSED (sf))2128 static void NoReFeature(struct splinefont *UNUSED(sf)) {
2129 }
2130
NoCloseAll(struct splinefont * UNUSED (sf))2131 static void NoCloseAll(struct splinefont *UNUSED(sf)) {
2132 }
2133
2134 struct mv_interface noui_mv = {
2135 NoGlyphs,
2136 Nothing,
2137 NoReKern,
2138 NoReFeature,
2139 NoCloseAll
2140 };
2141
2142 struct mv_interface *mv_interface = &noui_mv;
2143
FF_SetMVInterface(struct mv_interface * mvi)2144 void FF_SetMVInterface(struct mv_interface *mvi) {
2145 mv_interface = mvi;
2146 }
2147
2148