beta-0.89.2
[luatex.git] / source / texk / web2c / luatexdir / luafontloader / fontforge / fontforge / splineutil.c
blobf68ddc81d39a101dbfdb62663b0257fda9f234f6
1 /* Copyright (C) 2000-2008 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:
6 * Redistributions of source code must retain the above copyright notice, this
7 * list of conditions and the following disclaimer.
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.
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.
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.
27 #include "fontforgevw.h"
28 #include <math.h>
29 #include "psfont.h"
30 #include "ustring.h"
31 #include "utype.h"
32 #ifdef HAVE_IEEEFP_H
33 # include <ieeefp.h> /* Solaris defines isnan in ieeefp rather than math.h */
34 #endif
36 /*#define DEBUG 1*/
38 typedef struct quartic {
39 double a,b,c,d,e;
40 } Quartic;
42 /* In an attempt to make allocation more efficient I just keep preallocated */
43 /* lists of certain common sizes. It doesn't seem to make much difference */
44 /* when allocating stuff, but does when freeing. If the extra complexity */
45 /* is bad then put: */
46 /* #define chunkalloc(size) gcalloc(1,size) */
47 /* #define chunkfree(item,size) free(item) */
48 /* into splinefont.h after (or instead of) the definition of chunkalloc()*/
50 #ifndef chunkalloc
51 #define ALLOC_CHUNK 100 /* Number of small chunks to malloc at a time */
52 #if !defined(FONTFORGE_CONFIG_USE_LONGDOUBLE) && !defined(FONTFORGE_CONFIG_USE_DOUBLE)
53 # define CHUNK_MAX 100 /* Maximum size (in chunk units) that we are prepared to allocate */
54 /* The size of our data structures */
55 #else
56 # define CHUNK_MAX 129
57 #endif
58 # define CHUNK_UNIT sizeof(void *) /* will vary with the word size of */
59 /* the machine. if pointers are 64 bits*/
60 /* we may need twice as much space as for 32 bits */
62 #ifdef FLAG
63 #undef FLAG
64 #define FLAG 0xbadcafe
65 #endif
67 #ifdef CHUNKDEBUG
68 static int chunkdebug = 0; /* When this is set we never free anything, insuring that each chunk is unique */
69 #endif
71 #if ALLOC_CHUNK>1
72 struct chunk { struct chunk *next; };
73 struct chunk2 { struct chunk2 *next; int flag; };
74 static struct chunk *chunklists[CHUNK_MAX] = { 0 };
75 #endif
77 #if defined(FLAG) && ALLOC_CHUNK>1
78 void chunktest(void) {
79 int i;
80 struct chunk2 *c;
82 for ( i=2; i<CHUNK_MAX; ++i )
83 for ( c=(struct chunk2 *) chunklists[i]; c!=NULL; c=c->next )
84 if ( c->flag!=FLAG ) {
85 fprintf( stderr, "Chunk memory list has been corrupted\n" );
86 abort();
89 #endif
91 void *chunkalloc(int size) {
92 # if ALLOC_CHUNK<=1
93 return( gcalloc(1,size));
94 # else
95 struct chunk *item;
96 int index;
98 if ( size&(CHUNK_UNIT-1) )
99 size = (size+CHUNK_UNIT-1)&~(CHUNK_UNIT-1);
101 if ( (size&(CHUNK_UNIT-1)) || size>=(int)(CHUNK_MAX*CHUNK_UNIT) || size<=(int)sizeof(struct chunk)) {
102 fprintf( stderr, "Attempt to allocate something of size %d\n", size );
103 return( gcalloc(1,size));
105 #ifdef FLAG
106 chunktest();
107 #endif
108 index = (size+CHUNK_UNIT-1)/CHUNK_UNIT;
109 if ( chunklists[index]==NULL ) {
110 char *pt, *end;
111 pt = galloc(ALLOC_CHUNK*size);
112 chunklists[index] = (struct chunk *) pt;
113 end = pt+(ALLOC_CHUNK-1)*size;
114 while ( pt<end ) {
115 ((struct chunk *) pt)->next = (struct chunk *) (pt + size);
116 #ifdef FLAG
117 ((struct chunk2 *) pt)->flag = FLAG;
118 #endif
119 pt += size;
121 ((struct chunk *) pt)->next = NULL;
122 #ifdef FLAG
123 ((struct chunk2 *) pt)->flag = FLAG;
124 #endif
126 item = chunklists[index];
127 chunklists[index] = item->next;
128 memset(item,'\0',size);
129 return( item );
130 # endif
133 void chunkfree(void *item,int size) {
134 int index = (size+CHUNK_UNIT-1)/CHUNK_UNIT;
135 #ifdef CHUNKDEBUG
136 if ( chunkdebug )
137 return;
138 #endif
139 # if ALLOC_CHUNK<=1
140 free(item);
141 # else
142 if ( item==NULL )
143 return;
145 if ( size&(CHUNK_UNIT-1) )
146 size = (size+CHUNK_UNIT-1)&~(CHUNK_UNIT-1);
148 if ( (size&(CHUNK_UNIT-1)) || size>=(int)(CHUNK_MAX*CHUNK_UNIT) || size<=(int)sizeof(struct chunk)) {
149 fprintf( stderr, "Attempt to free something of size %d\n", size );
150 free(item);
151 } else {
152 #ifdef LOCAL_DEBUG
153 if ( (char *) (chunklists[index]) == (char *) item ||
154 ( ((char *) (chunklists[index]))<(char *) item &&
155 ((char *) (chunklists[index]))+size>(char *) item) ||
156 ( ((char *) (chunklists[index]))>(char *) item &&
157 ((char *) (chunklists[index]))<((char *) item)+size))
158 IError( "Memory mixup. Chunk list is wrong!!!" );
159 #endif
160 ((struct chunk *) item)->next = chunklists[index];
161 # ifdef FLAG
162 if ( size>=sizeof(struct chunk2))
163 ((struct chunk2 *) item)->flag = FLAG;
164 # endif
165 chunklists[index] = (struct chunk *) item;
167 # ifdef FLAG
168 chunktest();
169 # endif
170 # endif
172 #endif
174 char *strconcat(const char *str1,const char *str2) {
175 int len1 = strlen(str1);
176 char *ret = galloc(len1+strlen(str2)+1);
177 strcpy(ret,str1);
178 strcpy(ret+len1,str2);
179 return( ret );
182 char *strconcat3(const char *str1,const char *str2, const char *str3) {
183 int len1 = strlen(str1), len2 = strlen(str2);
184 char *ret = galloc(len1+len2+strlen(str3)+1);
185 strcpy(ret,str1);
186 strcpy(ret+len1,str2);
187 strcpy(ret+len1+len2,str3);
188 return( ret );
191 void LineListFree(LineList *ll) {
192 LineList *next;
194 while ( ll!=NULL ) {
195 next = ll->next;
196 chunkfree(ll,sizeof(LineList));
197 ll = next;
201 void LinearApproxFree(LinearApprox *la) {
202 LinearApprox *next;
204 while ( la!=NULL ) {
205 next = la->next;
206 LineListFree(la->lines);
207 chunkfree(la,sizeof(LinearApprox));
208 la = next;
212 void SplineFree(Spline *spline) {
213 LinearApproxFree(spline->approx);
214 chunkfree(spline,sizeof(Spline));
217 SplinePoint *SplinePointCreate(real x, real y) {
218 SplinePoint *sp = chunkalloc(sizeof(SplinePoint));
219 sp->me.x = x; sp->me.y = y;
220 sp->nextcp = sp->prevcp = sp->me;
221 sp->nonextcp = sp->noprevcp = true;
222 sp->nextcpdef = sp->prevcpdef = false;
223 sp->ttfindex = sp->nextcpindex = 0xfffe;
224 return( sp );
227 Spline *SplineMake3(SplinePoint *from, SplinePoint *to) {
228 Spline *spline = chunkalloc(sizeof(Spline));
230 spline->from = from; spline->to = to;
231 from->next = to->prev = spline;
232 SplineRefigure3(spline);
233 return( spline );
236 void SplinePointFree(SplinePoint *sp) {
237 chunkfree(sp->hintmask,sizeof(HintMask));
238 chunkfree(sp,sizeof(SplinePoint));
241 void SplinePointMDFree(SplineChar *sc, SplinePoint *sp) {
242 MinimumDistance *md, *prev, *next;
244 if ( sc!=NULL ) {
245 prev = NULL;
246 for ( md = sc->md; md!=NULL; md = next ) {
247 next = md->next;
248 if ( md->sp1==sp || md->sp2==sp ) {
249 if ( prev==NULL )
250 sc->md = next;
251 else
252 prev->next = next;
253 chunkfree(md,sizeof(MinimumDistance));
254 } else
255 prev = md;
259 chunkfree(sp->hintmask,sizeof(HintMask));
260 chunkfree(sp,sizeof(SplinePoint));
263 void SplinePointsFree(SplinePointList *spl) {
264 Spline *first, *spline, *next;
265 int nonext;
267 if ( spl==NULL )
268 return;
269 nonext = spl->first->next==NULL;
270 if ( spl->first!=NULL ) {
271 first = NULL;
272 for ( spline = spl->first->next; spline!=NULL && spline!=first; spline = next ) {
273 next = spline->to->next;
274 SplinePointFree(spline->to);
275 SplineFree(spline);
276 if ( first==NULL ) first = spline;
278 if ( spl->last!=spl->first || nonext )
279 SplinePointFree(spl->first);
283 void SplineSetBeziersClear(SplinePointList *spl) {
284 Spline *first, *spline, *next;
285 int nonext;
287 if ( spl==NULL )
288 return;
289 if ( spl->first!=NULL ) {
290 nonext = spl->first->next==NULL;
291 first = NULL;
292 for ( spline = spl->first->next; spline!=NULL && spline!=first; spline = next ) {
293 next = spline->to->next;
294 SplinePointFree(spline->to);
295 SplineFree(spline);
296 if ( first==NULL ) first = spline;
298 if ( spl->last!=spl->first || nonext )
299 SplinePointFree(spl->first);
301 spl->first = spl->last = NULL;
304 void SplinePointListFree(SplinePointList *spl) {
305 Spline *first, *spline, *next;
306 int nonext;
308 if ( spl==NULL )
309 return;
310 if ( spl->first!=NULL ) {
311 nonext = spl->first->next==NULL;
312 first = NULL;
313 for ( spline = spl->first->next; spline!=NULL && spline!=first; spline = next ) {
314 next = spline->to->next;
315 SplinePointFree(spline->to);
316 SplineFree(spline);
317 if ( first==NULL ) first = spline;
319 if ( spl->last!=spl->first || nonext )
320 SplinePointFree(spl->first);
322 free(spl->contour_name);
323 chunkfree(spl,sizeof(SplinePointList));
326 void SplinePointListMDFree(SplineChar *sc,SplinePointList *spl) {
327 Spline *first, *spline, *next;
328 int freefirst;
330 if ( spl==NULL )
331 return;
332 if ( spl->first!=NULL ) {
333 first = NULL;
334 freefirst = ( spl->last!=spl->first || spl->first->next==NULL );
335 for ( spline = spl->first->next; spline!=NULL && spline!=first; spline = next ) {
336 next = spline->to->next;
337 SplinePointMDFree(sc,spline->to);
338 SplineFree(spline);
339 if ( first==NULL ) first = spline;
341 if ( freefirst )
342 SplinePointMDFree(sc,spl->first);
344 free(spl->contour_name);
345 chunkfree(spl,sizeof(SplinePointList));
348 void SplinePointListsMDFree(SplineChar *sc,SplinePointList *spl) {
349 SplinePointList *next;
351 while ( spl!=NULL ) {
352 next = spl->next;
353 SplinePointListMDFree(sc,spl);
354 spl = next;
358 void SplinePointListsFree(SplinePointList *head) {
359 SplinePointList *spl, *next;
361 for ( spl=head; spl!=NULL; spl=next ) {
362 next = spl->next;
363 SplinePointListFree(spl);
367 void ImageListsFree(ImageList *imgs) {
368 ImageList *inext;
370 while ( imgs!=NULL ) {
371 inext = imgs->next;
372 chunkfree(imgs,sizeof(ImageList));
373 imgs = inext;
377 void RefCharFree(RefChar *ref) {
378 int i;
380 if ( ref==NULL )
381 return;
382 for ( i=0; i<ref->layer_cnt; ++i ) {
383 SplinePointListsFree(ref->layers[i].splines);
384 ImageListsFree(ref->layers[i].images);
386 free(ref->layers);
387 chunkfree(ref,sizeof(RefChar));
390 RefChar *RefCharCreate(void) {
391 RefChar *ref = chunkalloc(sizeof(RefChar));
392 ref->layer_cnt = 1;
393 ref->layers = gcalloc(1,sizeof(struct reflayer));
394 ref->round_translation_to_grid = true;
395 return( ref );
398 void RefCharsFree(RefChar *ref) {
399 RefChar *rnext;
401 while ( ref!=NULL ) {
402 rnext = ref->next;
403 RefCharFree(ref);
404 ref = rnext;
409 typedef struct spline1 {
410 Spline1D sp;
411 real s0, s1;
412 real c0, c1;
413 } Spline1;
415 static void FigureSpline1(Spline1 *sp1,bigreal t0, bigreal t1, Spline1D *sp ) {
416 bigreal s = (t1-t0);
417 if ( sp->a==0 && sp->b==0 ) {
418 sp1->sp.d = sp->d + t0*sp->c;
419 sp1->sp.c = s*sp->c;
420 sp1->sp.b = sp1->sp.a = 0;
421 } else {
422 sp1->sp.d = sp->d + t0*(sp->c + t0*(sp->b + t0*sp->a));
423 sp1->sp.c = s*(sp->c + t0*(2*sp->b + 3*sp->a*t0));
424 sp1->sp.b = s*s*(sp->b+3*sp->a*t0);
425 sp1->sp.a = s*s*s*sp->a;
426 #if 0 /* Got invoked once on a perfectly good spline */
427 sp1->s1 = sp1->sp.a+sp1->sp.b+sp1->sp.c+sp1->sp.d;
428 if ( ((sp1->s1>.001 || sp1->s1<-.001) && !RealNear((double) sp1->sp.a+sp1->sp.b+sp1->sp.c+sp1->sp.d,sp1->s1)) ||
429 !RealNear(sp1->sp.d,sp1->s0))
430 IError( "Created spline does not work in FigureSpline1");
431 #endif
433 sp1->c0 = sp1->sp.c/3 + sp1->sp.d;
434 sp1->c1 = sp1->c0 + (sp1->sp.b+sp1->sp.c)/3;
438 static void SplineFindBounds(const Spline *sp, DBounds *bounds) {
439 real t, b2_fourac, v;
440 real min, max;
441 const Spline1D *sp1;
442 int i;
444 /* first try the end points */
445 for ( i=0; i<2; ++i ) {
446 sp1 = &sp->splines[i];
447 if ( i==0 ) {
448 if ( sp->to->me.x<bounds->minx ) bounds->minx = sp->to->me.x;
449 if ( sp->to->me.x>bounds->maxx ) bounds->maxx = sp->to->me.x;
450 min = bounds->minx; max = bounds->maxx;
451 } else {
452 if ( sp->to->me.y<bounds->miny ) bounds->miny = sp->to->me.y;
453 if ( sp->to->me.y>bounds->maxy ) bounds->maxy = sp->to->me.y;
454 min = bounds->miny; max = bounds->maxy;
457 /* then try the extrema of the spline (assuming they are between t=(0,1) */
458 /* (I don't bother fixing up for tiny rounding errors here. they don't matter */
459 /* But we could call CheckExtremaForSingleBitErrors */
460 if ( sp1->a!=0 ) {
461 b2_fourac = 4*sp1->b*sp1->b - 12*sp1->a*sp1->c;
462 if ( b2_fourac>=0 ) {
463 b2_fourac = sqrt(b2_fourac);
464 t = (-2*sp1->b + b2_fourac) / (6*sp1->a);
465 if ( t>0 && t<1 ) {
466 v = ((sp1->a*t+sp1->b)*t+sp1->c)*t + sp1->d;
467 if ( v<min ) min = v;
468 if ( v>max ) max = v;
470 t = (-2*sp1->b - b2_fourac) / (6*sp1->a);
471 if ( t>0 && t<1 ) {
472 v = ((sp1->a*t+sp1->b)*t+sp1->c)*t + sp1->d;
473 if ( v<min ) min = v;
474 if ( v>max ) max = v;
477 } else if ( sp1->b!=0 ) {
478 t = -sp1->c/(2.0*sp1->b);
479 if ( t>0 && t<1 ) {
480 v = (sp1->b*t+sp1->c)*t + sp1->d;
481 if ( v<min ) min = v;
482 if ( v>max ) max = v;
485 if ( i==0 ) {
486 bounds->minx = min; bounds->maxx = max;
487 } else {
488 bounds->miny = min; bounds->maxy = max;
493 static void _SplineSetFindBounds(const SplinePointList *spl, DBounds *bounds) {
494 Spline *spline, *first;
495 /* Ignore contours consisting of a single point (used for hinting, anchors */
496 /* for mark to base, etc. */
498 for ( ; spl!=NULL; spl = spl->next ) if ( spl->first->next!=NULL && spl->first->next->to != spl->first ) {
499 first = NULL;
500 if ( bounds->minx==0 && bounds->maxx==0 && bounds->miny==0 && bounds->maxy == 0 ) {
501 bounds->minx = bounds->maxx = spl->first->me.x;
502 bounds->miny = bounds->maxy = spl->first->me.y;
503 } else {
504 if ( spl->first->me.x<bounds->minx ) bounds->minx = spl->first->me.x;
505 if ( spl->first->me.x>bounds->maxx ) bounds->maxx = spl->first->me.x;
506 if ( spl->first->me.y<bounds->miny ) bounds->miny = spl->first->me.y;
507 if ( spl->first->me.y>bounds->maxy ) bounds->maxy = spl->first->me.y;
509 for ( spline = spl->first->next; spline!=NULL && spline!=first; spline=spline->to->next ) {
510 SplineFindBounds(spline,bounds);
511 if ( first==NULL ) first = spline;
517 void SplineSetFindBounds(const SplinePointList *spl, DBounds *bounds) {
518 memset(bounds,'\0',sizeof(*bounds));
519 _SplineSetFindBounds(spl,bounds);
522 static void _SplineCharLayerFindBounds(SplineChar *sc,int layer, DBounds *bounds) {
523 RefChar *rf;
525 for ( rf=sc->layers[layer].refs; rf!=NULL; rf = rf->next ) {
526 if ( bounds->minx==0 && bounds->maxx==0 && bounds->miny==0 && bounds->maxy == 0 )
527 *bounds = rf->bb;
528 else if ( rf->bb.minx!=0 || rf->bb.maxx != 0 || rf->bb.maxy != 0 || rf->bb.miny!=0 ) {
529 if ( rf->bb.minx < bounds->minx ) bounds->minx = rf->bb.minx;
530 if ( rf->bb.miny < bounds->miny ) bounds->miny = rf->bb.miny;
531 if ( rf->bb.maxx > bounds->maxx ) bounds->maxx = rf->bb.maxx;
532 if ( rf->bb.maxy > bounds->maxy ) bounds->maxy = rf->bb.maxy;
535 _SplineSetFindBounds(sc->layers[layer].splines,bounds);
537 if ( sc->parent!=NULL && sc->parent->strokedfont &&
538 (bounds->minx!=bounds->maxx || bounds->miny!=bounds->maxy)) {
539 real sw = sc->parent->strokewidth;
540 bounds->minx -= sw; bounds->miny -= sw;
541 bounds->maxx += sw; bounds->maxy += sw;
545 void SplineCharLayerFindBounds(SplineChar *sc,int layer,DBounds *bounds) {
547 if ( sc->parent!=NULL && sc->parent->multilayer ) {
548 SplineCharFindBounds(sc,bounds);
549 return;
552 /* a char with no splines (ie. a space) must have an lbearing of 0 */
553 bounds->minx = bounds->maxx = 0;
554 bounds->miny = bounds->maxy = 0;
556 _SplineCharLayerFindBounds(sc,layer,bounds);
559 void SplineCharFindBounds(SplineChar *sc,DBounds *bounds) {
560 int i;
561 int first,last;
563 /* a char with no splines (ie. a space) must have an lbearing of 0 */
564 bounds->minx = bounds->maxx = 0;
565 bounds->miny = bounds->maxy = 0;
567 first = last = ly_fore;
568 if ( sc->parent!=NULL && sc->parent->multilayer )
569 last = sc->layer_cnt-1;
570 for ( i=first; i<=last; ++i )
571 _SplineCharLayerFindBounds(sc,i,bounds);
574 void SplineFontLayerFindBounds(SplineFont *sf,int layer,DBounds *bounds) {
575 int i, k, first, last;
576 (void)layer;
577 if ( sf->multilayer ) {
578 SplineFontFindBounds(sf,bounds);
579 return;
582 bounds->minx = bounds->maxx = 0;
583 bounds->miny = bounds->maxy = 0;
585 for ( i = 0; i<sf->glyphcnt; ++i ) {
586 SplineChar *sc = sf->glyphs[i];
587 if ( sc!=NULL ) {
588 first = last = ly_fore;
589 if ( sc->parent != NULL && sc->parent->multilayer )
590 last = sc->layer_cnt-1;
591 for ( k=first; k<=last; ++k )
592 _SplineCharLayerFindBounds(sc,k,bounds);
597 void SplineFontFindBounds(SplineFont *sf,DBounds *bounds) {
598 int i, k, first, last;
600 bounds->minx = bounds->maxx = 0;
601 bounds->miny = bounds->maxy = 0;
603 for ( i = 0; i<sf->glyphcnt; ++i ) {
604 SplineChar *sc = sf->glyphs[i];
605 if ( sc!=NULL ) {
606 first = last = ly_fore;
607 if ( sf->multilayer )
608 last = sc->layer_cnt-1;
609 for ( k=first; k<=last; ++k )
610 _SplineCharLayerFindBounds(sc,k,bounds);
615 void CIDLayerFindBounds(SplineFont *cidmaster,int layer,DBounds *bounds) {
616 SplineFont *sf;
617 int i;
618 DBounds b;
619 real factor;
621 if ( cidmaster->cidmaster )
622 cidmaster = cidmaster->cidmaster;
623 if ( cidmaster->subfonts==NULL ) {
624 SplineFontLayerFindBounds(cidmaster,layer,bounds);
625 return;
628 sf = cidmaster->subfonts[0];
629 SplineFontLayerFindBounds(sf,layer,bounds);
630 factor = 1000.0/(sf->ascent+sf->descent);
631 bounds->maxx *= factor; bounds->minx *= factor; bounds->miny *= factor; bounds->maxy *= factor;
632 for ( i=1; i<cidmaster->subfontcnt; ++i ) {
633 sf = cidmaster->subfonts[i];
634 SplineFontLayerFindBounds(sf,layer,&b);
635 factor = 1000.0/(sf->ascent+sf->descent);
636 b.maxx *= factor; b.minx *= factor; b.miny *= factor; b.maxy *= factor;
637 if ( b.maxx>bounds->maxx ) bounds->maxx = b.maxx;
638 if ( b.maxy>bounds->maxy ) bounds->maxy = b.maxy;
639 if ( b.miny<bounds->miny ) bounds->miny = b.miny;
640 if ( b.minx<bounds->minx ) bounds->minx = b.minx;
644 static void _SplineSetFindTop(SplineSet *ss,BasePoint *top) {
645 SplinePoint *sp;
647 for ( ; ss!=NULL; ss=ss->next ) {
648 for ( sp=ss->first; ; ) {
649 if ( sp->me.y > top->y ) *top = sp->me;
650 if ( sp->next==NULL )
651 break;
652 sp = sp->next->to;
653 if ( sp==ss->first )
654 break;
659 static void SplineSetFindTop(SplineSet *ss,BasePoint *top) {
661 top->y = -1e10;
662 _SplineSetFindTop(ss,top);
663 if ( top->y < -65536 ) top->y = top->x = 0;
666 void SplineSetQuickBounds(SplineSet *ss,DBounds *b) {
667 SplinePoint *sp;
669 b->minx = b->miny = 1e10;
670 b->maxx = b->maxy = -1e10;
671 for ( ; ss!=NULL; ss=ss->next ) {
672 for ( sp=ss->first; ; ) {
673 if ( sp->me.y < b->miny ) b->miny = sp->me.y;
674 if ( sp->me.x < b->minx ) b->minx = sp->me.x;
675 if ( sp->me.y > b->maxy ) b->maxy = sp->me.y;
676 if ( sp->me.x > b->maxx ) b->maxx = sp->me.x;
677 if ( sp->next==NULL )
678 break;
679 sp = sp->next->to;
680 if ( sp==ss->first )
681 break;
684 if ( b->minx>65536 ) b->minx = 0;
685 if ( b->miny>65536 ) b->miny = 0;
686 if ( b->maxx<-65536 ) b->maxx = 0;
687 if ( b->maxy<-65536 ) b->maxy = 0;
690 void SplineCharQuickBounds(SplineChar *sc, DBounds *b) {
691 RefChar *ref;
692 int i,first, last;
693 DBounds temp;
695 memset(b,0,sizeof(*b));
696 first = last = ly_fore;
697 if ( sc->parent!=NULL && sc->parent->multilayer )
698 last = sc->layer_cnt-1;
699 for ( i=first; i<=last; ++i ) {
700 SplineSetQuickBounds(sc->layers[i].splines,&temp);
701 if ( temp.minx!=0 || temp.maxx != 0 || temp.maxy != 0 || temp.miny!=0 ) {
702 if ( temp.minx < b->minx ) b->minx = temp.minx;
703 if ( temp.miny < b->miny ) b->miny = temp.miny;
704 if ( temp.maxx > b->maxx ) b->maxx = temp.maxx;
705 if ( temp.maxy > b->maxy ) b->maxy = temp.maxy;
707 for ( ref = sc->layers[i].refs; ref!=NULL; ref = ref->next ) {
708 /*SplineSetQuickBounds(ref->layers[0].splines,&temp);*/
709 if ( b->minx==0 && b->maxx==0 && b->miny==0 && b->maxy == 0 )
710 *b = ref->bb;
711 else if ( ref->bb.minx!=0 || ref->bb.maxx != 0 || ref->bb.maxy != 0 || ref->bb.miny!=0 ) {
712 if ( ref->bb.minx < b->minx ) b->minx = ref->bb.minx;
713 if ( ref->bb.miny < b->miny ) b->miny = ref->bb.miny;
714 if ( ref->bb.maxx > b->maxx ) b->maxx = ref->bb.maxx;
715 if ( ref->bb.maxy > b->maxy ) b->maxy = ref->bb.maxy;
719 if ( sc->parent!=NULL && sc->parent->strokedfont &&
720 (b->minx!=b->maxx || b->miny!=b->maxy)) {
721 real sw = sc->parent->strokewidth;
722 b->minx -= sw; b->miny -= sw;
723 b->maxx += sw; b->maxy += sw;
727 void SplineSetQuickConservativeBounds(SplineSet *ss,DBounds *b) {
728 SplinePoint *sp;
730 b->minx = b->miny = 1e10;
731 b->maxx = b->maxy = -1e10;
732 for ( ; ss!=NULL; ss=ss->next ) {
733 for ( sp=ss->first; ; ) {
734 if ( sp->me.y < b->miny ) b->miny = sp->me.y;
735 if ( sp->me.x < b->minx ) b->minx = sp->me.x;
736 if ( sp->me.y > b->maxy ) b->maxy = sp->me.y;
737 if ( sp->me.x > b->maxx ) b->maxx = sp->me.x;
738 if ( sp->nextcp.y < b->miny ) b->miny = sp->nextcp.y;
739 if ( sp->nextcp.x < b->minx ) b->minx = sp->nextcp.x;
740 if ( sp->nextcp.y > b->maxy ) b->maxy = sp->nextcp.y;
741 if ( sp->nextcp.x > b->maxx ) b->maxx = sp->nextcp.x;
742 if ( sp->prevcp.y < b->miny ) b->miny = sp->prevcp.y;
743 if ( sp->prevcp.x < b->minx ) b->minx = sp->prevcp.x;
744 if ( sp->prevcp.y > b->maxy ) b->maxy = sp->prevcp.y;
745 if ( sp->prevcp.x > b->maxx ) b->maxx = sp->prevcp.x;
746 if ( sp->next==NULL )
747 break;
748 sp = sp->next->to;
749 if ( sp==ss->first )
750 break;
753 if ( b->minx>65536 ) b->minx = 0;
754 if ( b->miny>65536 ) b->miny = 0;
755 if ( b->maxx<-65536 ) b->maxx = 0;
756 if ( b->maxy<-65536 ) b->maxy = 0;
759 void SplineCharQuickConservativeBounds(SplineChar *sc, DBounds *b) {
760 RefChar *ref;
761 int i, first,last;
762 DBounds temp;
764 memset(b,0,sizeof(*b));
765 first = last = ly_fore;
766 if ( sc->parent!=NULL && sc->parent->multilayer )
767 last = sc->layer_cnt-1;
768 for ( i=first; i<=last; ++i ) {
769 SplineSetQuickConservativeBounds(sc->layers[i].splines,&temp);
770 if ( temp.minx!=0 || temp.maxx != 0 || temp.maxy != 0 || temp.miny!=0 ) {
771 if ( temp.minx < b->minx ) b->minx = temp.minx;
772 if ( temp.miny < b->miny ) b->miny = temp.miny;
773 if ( temp.maxx > b->maxx ) b->maxx = temp.maxx;
774 if ( temp.maxy > b->maxy ) b->maxy = temp.maxy;
776 for ( ref = sc->layers[i].refs; ref!=NULL; ref = ref->next ) {
777 /*SplineSetQuickConservativeBounds(ref->layers[0].splines,&temp);*/
778 if ( b->minx==0 && b->maxx==0 && b->miny==0 && b->maxy == 0 )
779 *b = ref->bb;
780 else if ( ref->bb.minx!=0 || ref->bb.maxx != 0 || ref->bb.maxy != 0 || ref->bb.miny!=0 ) {
781 if ( ref->bb.minx < b->minx ) b->minx = ref->bb.minx;
782 if ( ref->bb.miny < b->miny ) b->miny = ref->bb.miny;
783 if ( ref->bb.maxx > b->maxx ) b->maxx = ref->bb.maxx;
784 if ( ref->bb.maxy > b->maxy ) b->maxy = ref->bb.maxy;
788 if ( sc->parent->strokedfont && (b->minx!=b->maxx || b->miny!=b->maxy)) {
789 real sw = sc->parent->strokewidth;
790 b->minx -= sw; b->miny -= sw;
791 b->maxx += sw; b->maxy += sw;
795 void SplineFontQuickConservativeBounds(SplineFont *sf,DBounds *b) {
796 DBounds bb;
797 int i;
799 b->minx = b->miny = 1e10;
800 b->maxx = b->maxy = -1e10;
801 for ( i=0; i<sf->glyphcnt; ++i ) if ( sf->glyphs[i]!=NULL ) {
802 SplineCharQuickConservativeBounds(sf->glyphs[i],&bb);
803 if ( bb.minx < b->minx ) b->minx = bb.minx;
804 if ( bb.miny < b->miny ) b->miny = bb.miny;
805 if ( bb.maxx > b->maxx ) b->maxx = bb.maxx;
806 if ( bb.maxy > b->maxy ) b->maxy = bb.maxy;
808 if ( b->minx>65536 ) b->minx = 0;
809 if ( b->miny>65536 ) b->miny = 0;
810 if ( b->maxx<-65536 ) b->maxx = 0;
811 if ( b->maxy<-65536 ) b->maxy = 0;
814 void SplinePointCatagorize(SplinePoint *sp) {
815 int oldpointtype = sp->pointtype;
817 sp->pointtype = pt_corner;
818 if ( sp->next==NULL && sp->prev==NULL )
820 else if ( (sp->next!=NULL && sp->next->to->me.x==sp->me.x && sp->next->to->me.y==sp->me.y) ||
821 (sp->prev!=NULL && sp->prev->from->me.x==sp->me.x && sp->prev->from->me.y==sp->me.y ))
823 else if ( sp->next==NULL ) {
824 sp->pointtype = sp->noprevcp ? pt_corner : pt_curve;
825 } else if ( sp->prev==NULL ) {
826 sp->pointtype = sp->nonextcp ? pt_corner : pt_curve;
827 } else if ( sp->nonextcp && sp->noprevcp ) {
829 } else {
830 BasePoint ndir, ncdir, ncunit, pdir, pcdir, pcunit;
831 double nlen, nclen, plen, pclen;
832 double dot;
834 ncdir.x = sp->nextcp.x - sp->me.x; ncdir.y = sp->nextcp.y - sp->me.y;
835 pcdir.x = sp->prevcp.x - sp->me.x; pcdir.y = sp->prevcp.y - sp->me.y;
836 ndir.x = ndir.y = pdir.x = pdir.y = 0;
837 if ( sp->next!=NULL ) {
838 ndir.x = sp->next->to->me.x - sp->me.x; ndir.y = sp->next->to->me.y - sp->me.y;
840 if ( sp->prev!=NULL ) {
841 pdir.x = sp->prev->from->me.x - sp->me.x; pdir.y = sp->prev->from->me.y - sp->me.y;
843 nclen = sqrt(ncdir.x*ncdir.x + ncdir.y*ncdir.y);
844 pclen = sqrt(pcdir.x*pcdir.x + pcdir.y*pcdir.y);
845 nlen = sqrt(ndir.x*ndir.x + ndir.y*ndir.y);
846 plen = sqrt(pdir.x*pdir.x + pdir.y*pdir.y);
847 ncunit = ncdir; pcunit = pcdir;
848 if ( nclen!=0 ) { ncunit.x /= nclen; ncunit.y /= nclen; }
849 if ( pclen!=0 ) { pcunit.x /= pclen; pcunit.y /= pclen; }
850 if ( nlen!=0 ) { ndir.x /= nlen; ndir.y /= nlen; }
851 if ( plen!=0 ) { pdir.x /= plen; pdir.y /= plen; }
853 /* find out which side has the shorter control vector. Dot that vector */
854 /* with the normal of the unit vector on the other side. If the */
855 /* result is less than 1 em-unit then we've got colinear control points */
856 /* (within the resolution of the integer grid) */
857 if ( nclen!=0 && pclen!=0 &&
858 ((nclen>=pclen && (dot = pcdir.x*ncunit.y - pcdir.y*ncunit.x)<1.0 && dot>-1.0 ) ||
859 (pclen>nclen && (dot = ncdir.x*pcunit.y - ncdir.y*pcunit.x)<1.0 && dot>-1.0 )))
860 sp->pointtype = pt_curve;
861 /* Dot product of control point with unit vector normal to line in */
862 /* opposite direction should be less than an em-unit for a tangent */
863 else if (( nclen==0 && pclen!=0 && (dot = pcdir.x*ndir.y-pcdir.y*ndir.x)<1.0 && dot>-1.0 ) ||
864 ( pclen==0 && nclen!=0 && (dot = ncdir.x*pdir.y-ncdir.y*pdir.x)<1.0 && dot>-1.0 ))
865 sp->pointtype = pt_tangent;
867 /* If a point started out hv, and could still be hv, them make it so */
868 /* but don't make hv points de novo, Alexey doesn't like change */
869 /* (this only works because hv isn't a default setting, so if it's */
870 /* there it was done intentionally) */
871 if ( sp->pointtype == pt_curve && oldpointtype == pt_hvcurve &&
872 ((sp->nextcp.x==sp->me.x && sp->prevcp.x==sp->me.x && sp->nextcp.y!=sp->me.y) ||
873 (sp->nextcp.y==sp->me.y && sp->prevcp.y==sp->me.y && sp->nextcp.x!=sp->me.x)))
874 sp->pointtype = pt_hvcurve;
878 int SplinePointIsACorner(SplinePoint *sp) {
879 enum pointtype old = sp->pointtype, new;
881 SplinePointCatagorize(sp);
882 new = sp->pointtype;
883 sp->pointtype = old;
884 return( new==pt_corner );
887 void SPLCatagorizePoints(SplinePointList *spl) {
888 Spline *spline, *first, *last=NULL;
890 for ( ; spl!=NULL; spl = spl->next ) {
891 first = NULL;
892 for ( spline = spl->first->next; spline!=NULL && spline!=first; spline=spline->to->next ) {
893 SplinePointCatagorize(spline->from);
894 last = spline;
895 if ( first==NULL ) first = spline;
897 if ( spline==NULL && last!=NULL )
898 SplinePointCatagorize(last->to);
902 void SCCatagorizePoints(SplineChar *sc) {
903 SPLCatagorizePoints(sc->layers[ly_fore].splines);
906 static int CharsNotInEncoding(FontDict *fd) {
907 int i, cnt, j;
909 for ( i=cnt=0; i<fd->chars->cnt; ++i ) {
910 if ( fd->chars->keys[i]!=NULL ) {
911 for ( j=0; j<256; ++j )
912 if ( fd->encoding[j]!=NULL &&
913 strcmp(fd->encoding[j],fd->chars->keys[i])==0 )
914 break;
915 if ( j==256 )
916 ++cnt;
919 /* And for type 3 fonts... */
920 if ( fd->charprocs!=NULL ) for ( i=0; i<fd->charprocs->cnt; ++i ) {
921 if ( fd->charprocs->keys[i]!=NULL ) {
922 for ( j=0; j<256; ++j )
923 if ( fd->encoding[j]!=NULL &&
924 strcmp(fd->encoding[j],fd->charprocs->keys[i])==0 )
925 break;
926 if ( j==256 )
927 ++cnt;
930 return( cnt );
933 static int LookupCharString(char *encname,struct pschars *chars) {
934 int k;
936 if ( encname==NULL ) encname = ".notdef"; /* In case of an incomplete encoding array */
938 for ( k=0; k<chars->cnt; ++k ) {
939 if ( chars->keys[k]!=NULL )
940 if ( strcmp(encname,chars->keys[k])==0 )
941 return( k );
943 return( -1 );
946 SplinePointList *SplinePointListCopy1(const SplinePointList *spl) {
947 SplinePointList *cur;
948 const SplinePoint *pt; SplinePoint *cpt;
949 Spline *spline;
951 cur = chunkalloc(sizeof(SplinePointList));
952 cur->is_clip_path = spl->is_clip_path;
954 for ( pt=spl->first; ; ) {
955 cpt = chunkalloc(sizeof(SplinePoint));
956 *cpt = *pt;
957 if ( pt->hintmask!=NULL ) {
958 cpt->hintmask = chunkalloc(sizeof(HintMask));
959 memcpy(cpt->hintmask,pt->hintmask,sizeof(HintMask));
961 cpt->next = cpt->prev = NULL;
962 if ( cur->first==NULL )
963 cur->first = cur->last = cpt;
964 else {
965 spline = chunkalloc(sizeof(Spline));
966 *spline = *pt->prev;
967 spline->from = cur->last;
968 cur->last->next = spline;
969 cpt->prev = spline;
970 spline->to = cpt;
971 spline->approx = NULL;
972 cur->last = cpt;
974 if ( pt->next==NULL )
975 break;
976 pt = pt->next->to;
977 if ( pt==spl->first )
978 break;
980 if ( spl->first->prev!=NULL ) {
981 cpt = cur->first;
982 spline = chunkalloc(sizeof(Spline));
983 *spline = *pt->prev;
984 spline->from = cur->last;
985 cur->last->next = spline;
986 cpt->prev = spline;
987 spline->to = cpt;
988 spline->approx = NULL;
989 cur->last = cpt;
991 return( cur );
994 /* If this routine is called we are guarenteed that:
995 at least one point on the splineset is selected
996 not all points on the splineset are selected
998 static SplinePointList *SplinePointListCopySelected1(SplinePointList *spl) {
999 SplinePointList *head=NULL, *last=NULL, *cur;
1000 SplinePoint *cpt, *first, *start;
1001 Spline *spline;
1003 start = spl->first;
1004 if ( spl->first==spl->last ) {
1005 /* If it's a closed contour and the start point is selected then we */
1006 /* don't know where that selection began (and we have to keep it with */
1007 /* the things that precede it when we make the new splinesets), so */
1008 /* loop until we find something unselected */
1009 while ( start->selected )
1010 start = start->next->to;
1012 first = NULL;
1013 while ( start != NULL && start!=first ) {
1014 while ( start!=NULL && start!=first && !start->selected ) {
1015 if ( first==NULL ) first = start;
1016 if ( start->next==NULL ) {
1017 start = NULL;
1018 break;
1020 start = start->next->to;
1022 if ( start==NULL || start==first )
1023 break;
1024 cur = chunkalloc(sizeof(SplinePointList));
1025 if ( head==NULL )
1026 head = cur;
1027 else
1028 last->next = cur;
1029 last = cur;
1031 while ( start!=NULL && start->selected && start!=first ) {
1032 cpt = chunkalloc(sizeof(SplinePoint));
1033 *cpt = *start;
1034 cpt->hintmask = NULL;
1035 cpt->next = cpt->prev = NULL;
1036 if ( cur->first==NULL )
1037 cur->first = cur->last = cpt;
1038 else {
1039 spline = chunkalloc(sizeof(Spline));
1040 *spline = *start->prev;
1041 spline->from = cur->last;
1042 cur->last->next = spline;
1043 cpt->prev = spline;
1044 spline->to = cpt;
1045 spline->approx = NULL;
1046 cur->last = cpt;
1048 if ( first==NULL ) first = start;
1049 if ( start->next==NULL ) {
1050 start = NULL;
1051 break;
1053 start = start->next->to;
1056 return( head );
1060 SplinePointList *SplinePointListCopy(const SplinePointList *base) {
1061 SplinePointList *head=NULL, *last=NULL, *cur;
1063 for ( ; base!=NULL; base = base->next ) {
1064 cur = SplinePointListCopy1(base);
1065 if ( head==NULL )
1066 head = cur;
1067 else
1068 last->next = cur;
1069 last = cur;
1071 return( head );
1074 SplinePointList *SplinePointListCopySelected(SplinePointList *base) {
1075 SplinePointList *head=NULL, *last=NULL, *cur=NULL;
1076 SplinePoint *pt, *first;
1077 int anysel, allsel;
1079 for ( ; base!=NULL; base = base->next ) {
1080 anysel = false; allsel = true;
1081 first = NULL;
1082 for ( pt=base->first; pt!=NULL && pt!=first; pt = pt->next->to ) {
1083 if ( pt->selected ) anysel = true;
1084 else allsel = false;
1085 if ( first==NULL ) first = pt;
1086 if ( pt->next==NULL )
1087 break;
1089 if ( allsel )
1090 cur = SplinePointListCopy1(base);
1091 else if ( anysel )
1092 cur = SplinePointListCopySelected1(base);
1093 if ( anysel ) {
1094 if ( head==NULL )
1095 head = cur;
1096 else
1097 last->next = cur;
1098 for ( last = cur; last->next ; last = last->next );
1101 return( head );
1106 static SplinePointList *SplinePointListSplit(SplineChar *sc,SplinePointList *spl) {
1107 SplinePointList *head=NULL, *last=NULL, *cur;
1108 SplinePoint *first, *start, *next;
1110 start = spl->first;
1111 if ( spl->first==spl->last ) {
1112 /* If it's a closed contour and the start point is selected then we */
1113 /* don't know where that selection began (and we have to keep it with */
1114 /* the things that precede it when we make the new splinesets), so */
1115 /* loop until we find something unselected */
1116 while ( !start->selected )
1117 start = start->next->to;
1119 first = NULL;
1120 while ( start != NULL && start!=first ) {
1121 while ( start!=NULL && start!=first && start->selected ) {
1122 if ( first==NULL ) first = start;
1123 if ( start->prev!=NULL ) {
1124 start->prev->from->next = NULL;
1125 SplineFree(start->prev);
1127 if ( start->next!=NULL ) {
1128 next = start->next->to;
1129 next->prev = NULL;
1130 SplineFree(start->next);
1131 } else
1132 next = NULL;
1133 SplinePointMDFree(sc,start);
1134 start = next;
1136 if ( start==NULL || start==first )
1137 break;
1138 if ( head==NULL ) {
1139 head = cur = spl;
1140 spl->first = spl->last = NULL;
1141 } else {
1142 cur = chunkalloc(sizeof(SplinePointList));
1143 last->next = cur;
1145 last = cur;
1147 while ( start!=NULL && !start->selected && start!=first ) {
1148 if ( cur->first==NULL )
1149 cur->first = start;
1150 cur->last = start;
1151 if ( start->next!=NULL ) {
1152 next = start->next->to;
1153 if ( next->selected ) {
1154 SplineFree(start->next);
1155 start->next = NULL;
1156 next->prev = NULL;
1158 } else
1159 next = NULL;
1160 if ( first==NULL ) first = start;
1161 start = next;
1164 return( last );
1167 SplinePointList *SplinePointListRemoveSelected(SplineChar *sc,SplinePointList *base) {
1168 SplinePointList *head=NULL, *last=NULL, *next;
1169 SplinePoint *pt, *first;
1170 int anysel, allsel;
1172 for ( ; base!=NULL; base = next ) {
1173 next = base->next;
1174 anysel = false; allsel = true;
1175 first = NULL;
1176 for ( pt=base->first; pt!=NULL && pt!=first; pt = pt->next->to ) {
1177 if ( pt->selected ) anysel = true;
1178 else allsel = false;
1179 if ( first==NULL ) first = pt;
1180 if ( pt->next==NULL )
1181 break;
1183 if ( allsel ) {
1184 SplinePointListMDFree(sc,base);
1185 continue;
1187 if ( !anysel ) {
1188 if ( head==NULL )
1189 head = base;
1190 else
1191 last->next = base;
1192 last = base;
1193 if ( anysel )
1194 last = SplinePointListSplit(sc,base);
1197 if ( last!=NULL ) last->next = NULL;
1198 return( head );
1201 ImageList *ImageListCopy(ImageList *cimg) {
1202 ImageList *head=NULL, *last=NULL, *new;
1204 for ( ; cimg!=NULL; cimg=cimg->next ) {
1205 new = chunkalloc(sizeof(ImageList));
1206 *new = *cimg;
1207 new->next = NULL;
1208 if ( last==NULL )
1209 head = last = new;
1210 else {
1211 last->next = new;
1212 last = new;
1215 return( head );
1219 void ApTransform(AnchorPoint *ap, real transform[6]) {
1220 BasePoint p;
1221 p.x = transform[0]*ap->me.x + transform[2]*ap->me.y + transform[4];
1222 p.y = transform[1]*ap->me.x + transform[3]*ap->me.y + transform[5];
1223 ap->me.x = rint(1024*p.x)/1024;
1224 ap->me.y = rint(1024*p.y)/1024;
1227 static void TransformPoint(SplinePoint *sp, real transform[6]) {
1228 BasePoint p;
1229 p.x = transform[0]*sp->me.x + transform[2]*sp->me.y + transform[4];
1230 p.y = transform[1]*sp->me.x + transform[3]*sp->me.y + transform[5];
1231 p.x = rint(1024*p.x)/1024;
1232 p.y = rint(1024*p.y)/1024;
1233 sp->me = p;
1234 if ( !sp->nonextcp ) {
1235 p.x = transform[0]*sp->nextcp.x + transform[2]*sp->nextcp.y + transform[4];
1236 p.y = transform[1]*sp->nextcp.x + transform[3]*sp->nextcp.y + transform[5];
1237 p.x = rint(1024*p.x)/1024;
1238 p.y = rint(1024*p.y)/1024;
1239 sp->nextcp = p;
1240 } else
1241 sp->nextcp = sp->me;
1242 if ( !sp->noprevcp ) {
1243 p.x = transform[0]*sp->prevcp.x + transform[2]*sp->prevcp.y + transform[4];
1244 p.y = transform[1]*sp->prevcp.x + transform[3]*sp->prevcp.y + transform[5];
1245 p.x = rint(1024*p.x)/1024;
1246 p.y = rint(1024*p.y)/1024;
1247 sp->prevcp = p;
1248 } else
1249 sp->prevcp = sp->me;
1250 if ( sp->pointtype == pt_hvcurve ) {
1251 if (
1252 ((sp->nextcp.x==sp->me.x && sp->prevcp.x==sp->me.x && sp->nextcp.y!=sp->me.y) ||
1253 (sp->nextcp.y==sp->me.y && sp->prevcp.y==sp->me.y && sp->nextcp.x!=sp->me.x)))
1254 /* Do Nothing */;
1255 else
1256 sp->pointtype = pt_curve;
1260 SplinePointList *SplinePointListTransform(SplinePointList *base, real transform[6], int allpoints ) {
1261 Spline *spline, *first;
1262 SplinePointList *spl;
1263 SplinePoint *spt, *pfirst;
1264 int allsel, anysel, alldone=true;
1266 for ( spl = base; spl!=NULL; spl = spl->next ) {
1267 pfirst = NULL;
1268 allsel = true; anysel=false;
1269 for ( spt = spl->first ; spt!=pfirst; spt = spt->next->to ) {
1270 if ( pfirst==NULL ) pfirst = spt;
1271 if ( allpoints || spt->selected ) {
1272 TransformPoint(spt,transform);
1273 if ( !allpoints ) {
1274 if ( spt->next!=NULL && spt->next->order2 && !spt->next->to->selected && spt->next->to->ttfindex==0xffff ) {
1275 SplinePoint *to = spt->next->to;
1276 to->prevcp = spt->nextcp;
1277 to->me.x = (to->prevcp.x+to->nextcp.x)/2;
1278 to->me.y = (to->prevcp.y+to->nextcp.y)/2;
1280 if ( spt->prev!=NULL && spt->prev->order2 && !spt->prev->from->selected && spt->prev->from->ttfindex==0xffff ) {
1281 SplinePoint *from = spt->prev->from;
1282 from->nextcp = spt->prevcp;
1283 from->me.x = (from->prevcp.x+from->nextcp.x)/2;
1284 from->me.y = (from->prevcp.y+from->nextcp.y)/2;
1287 anysel = true;
1288 } else
1289 allsel = alldone = false;
1290 if ( spt->next==NULL )
1291 break;
1293 if ( !anysel ) /* This splineset had no selected points it's unchanged */
1294 continue;
1296 /* if we changed all the points then the control points are right */
1297 /* otherwise those near the edges may be wonky, fix 'em up */
1298 /* Figuring out where the edges of the selection are is difficult */
1299 /* so let's just tweak all points, it shouldn't matter */
1300 /* It does matter. Let's tweak all default points */
1301 if ( !allpoints && !allsel && spl->first->next!=NULL && !spl->first->next->order2 ) {
1302 pfirst = NULL;
1303 for ( spt = spl->first ; spt!=pfirst; spt = spt->next->to ) {
1304 if ( pfirst==NULL ) pfirst = spt;
1305 if ( spt->selected && spt->prev!=NULL && !spt->prev->from->selected &&
1306 spt->prev->from->pointtype == pt_tangent )
1307 SplineCharTangentPrevCP(spt->prev->from);
1308 if ( spt->selected && spt->next!=NULL && !spt->next->to->selected &&
1309 spt->next->to->pointtype == pt_tangent )
1310 SplineCharTangentNextCP(spt->next->to);
1311 if ( spt->prev!=NULL && spt->prevcpdef )
1312 SplineCharDefaultPrevCP(spt);
1313 if ( spt->next==NULL )
1314 break;
1315 if ( spt->nextcpdef )
1316 SplineCharDefaultNextCP(spt);
1319 first = NULL;
1320 for ( spline = spl->first->next; spline!=NULL && spline!=first; spline=spline->to->next ) {
1321 if ( !alldone ) SplineRefigureFixup(spline); else SplineRefigure(spline);
1322 if ( first==NULL ) first = spline;
1325 return( base );
1329 SplinePointList *SplinePointListShift(SplinePointList *base,real xoff,int allpoints ) {
1330 real transform[6];
1331 if ( xoff==0 )
1332 return( base );
1333 transform[0] = transform[3] = 1;
1334 transform[1] = transform[2] = transform[5] = 0;
1335 transform[4] = xoff;
1336 return( SplinePointListTransform(base,transform,allpoints));
1339 HintMask *HintMaskFromTransformedRef(RefChar *ref,BasePoint *trans,
1340 SplineChar *basesc,HintMask *hm) {
1341 StemInfo *st, *st2;
1342 int hst_cnt, bcnt;
1343 real start, width;
1344 int i;
1346 if ( ref->transform[1]!=0 || ref->transform[2]!=0 )
1347 return(NULL);
1349 memset(hm,0,sizeof(HintMask));
1350 for ( st = ref->sc->hstem; st!=NULL; st=st->next ) {
1351 start = st->start*ref->transform[3] + ref->transform[5] + trans->y;
1352 width = st->width*ref->transform[3];
1353 for ( st2=basesc->hstem,bcnt=0; st2!=NULL; st2=st2->next, bcnt++ )
1354 if ( st2->start == start && st2->width == width )
1355 break;
1356 if ( st2!=NULL )
1357 (*hm)[bcnt>>3] |= (0x80>>(bcnt&7));
1359 for ( st2=basesc->hstem,hst_cnt=0; st2!=NULL; st2=st2->next, hst_cnt++ );
1361 for ( st = ref->sc->vstem; st!=NULL; st=st->next ) {
1362 start = st->start*ref->transform[0] + ref->transform[4] + trans->x;
1363 width = st->width*ref->transform[0];
1364 for ( st2=basesc->vstem,bcnt=hst_cnt; st2!=NULL; st2=st2->next, bcnt++ )
1365 if ( st2->start == start && st2->width == width )
1366 break;
1367 if ( st2!=NULL )
1368 (*hm)[bcnt>>3] |= (0x80>>(bcnt&7));
1370 for ( i=0; i<HntMax/8; ++i )
1371 if ( (*hm)[i]!=0 )
1372 return( hm );
1374 return( NULL );
1377 static HintMask *HintMaskTransform(HintMask *oldhm,real transform[6],
1378 SplineChar *basesc,SplineChar *subsc) {
1379 HintMask *newhm;
1380 StemInfo *st, *st2;
1381 int cnt, hst_cnt, bcnt;
1382 real start, width;
1384 if ( transform[1]!=0 || transform[2]!=0 )
1385 return( NULL );
1387 newhm = chunkalloc(sizeof(HintMask));
1388 for ( st = subsc->hstem,cnt = 0; st!=NULL; st=st->next, cnt++ ) {
1389 if ( (*oldhm)[cnt>>3]&(0x80>>(cnt&7)) ) {
1390 start = st->start*transform[3] + transform[5];
1391 width = st->width*transform[3];
1392 for ( st2=basesc->hstem,bcnt=0; st2!=NULL; st2=st2->next, bcnt++ )
1393 if ( st2->start == start && st2->width == width )
1394 break;
1395 if ( st2!=NULL )
1396 (*newhm)[bcnt>>3] |= (0x80>>(bcnt&7));
1399 for ( st2=basesc->hstem,hst_cnt=0; st2!=NULL; st2=st2->next, hst_cnt++ );
1401 for ( st = subsc->vstem; st!=NULL; st=st->next, cnt++ ) {
1402 if ( (*oldhm)[cnt>>3]&(0x80>>(cnt&7)) ) {
1403 start = st->start*transform[0] + transform[4];
1404 width = st->width*transform[0];
1405 for ( st2=basesc->vstem,bcnt=hst_cnt; st2!=NULL; st2=st2->next, bcnt++ )
1406 if ( st2->start == start && st2->width == width )
1407 break;
1408 if ( st2!=NULL )
1409 (*newhm)[bcnt>>3] |= (0x80>>(bcnt&7));
1412 return( newhm );
1415 SplinePointList *SPLCopyTranslatedHintMasks(SplinePointList *base,
1416 SplineChar *basesc, SplineChar *subsc, BasePoint *trans ) {
1417 SplinePointList *spl, *spl2, *head;
1418 SplinePoint *spt, *spt2, *pfirst;
1419 real transform[6];
1420 Spline *s, *first;
1422 head = SplinePointListCopy(base);
1424 transform[0] = transform[3] = 1; transform[1] = transform[2] = 0;
1425 transform[4] = trans->x; transform[5] = trans->y;
1427 for ( spl = head, spl2=base; spl!=NULL; spl = spl->next, spl2 = spl2->next ) {
1428 pfirst = NULL;
1429 for ( spt = spl->first, spt2 = spl2->first ; spt!=pfirst; spt = spt->next->to, spt2 = spt2->next->to ) {
1430 if ( pfirst==NULL ) pfirst = spt;
1431 TransformPoint(spt,transform);
1432 if ( spt2->hintmask ) {
1433 chunkfree(spt->hintmask,sizeof(HintMask));
1434 spt->hintmask = HintMaskTransform(spt2->hintmask,transform,basesc,subsc);
1436 if ( spt->next==NULL )
1437 break;
1439 first = NULL;
1440 for ( s = spl->first->next; s!=NULL && s!=first; s=s->to->next ) {
1441 SplineRefigure(s);
1442 if ( first==NULL ) first = s;
1445 return( head );
1448 static SplinePointList *_SPLCopyTransformedHintMasks(SplineChar *subsc,int layer,
1449 real transform[6], SplineChar *basesc ) {
1450 SplinePointList *spl, *spl2, *head, *last=NULL, *cur, *base;
1451 SplinePoint *spt, *spt2, *pfirst;
1452 Spline *s, *first;
1453 real trans[6];
1454 RefChar *rf;
1456 base = subsc->layers[layer].splines;
1457 head = SplinePointListCopy(base);
1458 if ( head!=NULL )
1459 for ( last = head; last->next!=NULL; last=last->next );
1461 for ( spl = head, spl2=base; spl!=NULL; spl = spl->next, spl2=spl2->next ) {
1462 pfirst = NULL;
1463 for ( spt = spl->first, spt2 = spl2->first ; spt!=pfirst; spt = spt->next->to, spt2 = spt2->next->to ) {
1464 if ( pfirst==NULL ) pfirst = spt;
1465 TransformPoint(spt,transform);
1466 if ( spt2->hintmask ) {
1467 chunkfree(spt->hintmask,sizeof(HintMask));
1468 spt->hintmask = HintMaskTransform(spt2->hintmask,transform,basesc,subsc);
1470 if ( spt->next==NULL )
1471 break;
1473 first = NULL;
1474 for ( s = spl->first->next; s!=NULL && s!=first; s=s->to->next ) {
1475 SplineRefigure(s);
1476 if ( first==NULL ) first = s;
1479 for ( rf=subsc->layers[layer].refs; rf!=NULL; rf=rf->next ) {
1480 trans[0] = rf->transform[0]*transform[0] +
1481 rf->transform[1]*transform[2];
1482 trans[1] = rf->transform[0]*transform[1] +
1483 rf->transform[1]*transform[3];
1484 trans[2] = rf->transform[2]*transform[0] +
1485 rf->transform[3]*transform[2];
1486 trans[3] = rf->transform[2]*transform[1] +
1487 rf->transform[3]*transform[3];
1488 trans[4] = rf->transform[4]*transform[0] +
1489 rf->transform[5]*transform[2] +
1490 transform[4];
1491 trans[5] = rf->transform[4]*transform[1] +
1492 rf->transform[5]*transform[3] +
1493 transform[5];
1494 cur = _SPLCopyTransformedHintMasks(rf->sc,layer,trans,basesc);
1495 if ( head==NULL )
1496 head = cur;
1497 else
1498 last->next = cur;
1499 if ( cur!=NULL ) {
1500 while ( cur->next!=NULL ) cur = cur->next;
1501 last = cur;
1504 return( head );
1507 SplinePointList *SPLCopyTransformedHintMasks(RefChar *r,
1508 SplineChar *basesc, BasePoint *trans,int layer ) {
1509 real transform[6];
1511 memcpy(transform,r->transform,sizeof(transform));
1512 transform[4] += trans->x; transform[5] += trans->y;
1513 return( _SPLCopyTransformedHintMasks(r->sc,layer,transform,basesc));
1516 void SplinePointListSelect(SplinePointList *spl,int sel) {
1517 Spline *spline, *first;
1519 for ( ; spl!=NULL; spl = spl->next ) {
1520 first = NULL;
1521 spl->first->selected = sel;
1522 for ( spline = spl->first->next; spline!=NULL && spline!=first; spline=spline->to->next ) {
1523 spline->to->selected = sel;
1524 if ( first==NULL ) first = spline;
1529 void SCMakeDependent(SplineChar *dependent,SplineChar *base) {
1530 struct splinecharlist *dlist;
1532 if ( dependent->searcherdummy )
1533 return;
1535 for ( dlist=base->dependents; dlist!=NULL && dlist->sc!=dependent; dlist = dlist->next);
1536 if ( dlist==NULL ) {
1537 dlist = chunkalloc(sizeof(struct splinecharlist));
1538 dlist->sc = dependent;
1539 dlist->next = base->dependents;
1540 base->dependents = dlist;
1544 static void InstanciateReference(SplineFont *sf, RefChar *topref, RefChar *refs,
1545 real transform[6], SplineChar *dsc, int layer) {
1546 real trans[6];
1547 RefChar *rf;
1548 SplineChar *rsc;
1549 SplinePointList *spl, *new;
1550 int i;
1552 if ( !refs->checked ) {
1553 if ( refs->sc!=NULL )
1554 i = refs->sc->orig_pos; /* Can happen in type3 fonts */
1555 else for ( i=0; i<sf->glyphcnt; ++i ) if ( sf->glyphs[i]!=NULL )
1556 if ( strcmp(sf->glyphs[i]->name,AdobeStandardEncoding[refs->adobe_enc])==0 )
1557 break;
1558 if ( i!=sf->glyphcnt && !sf->glyphs[i]->ticked ) {
1559 refs->checked = true;
1560 refs->sc = rsc = sf->glyphs[i];
1561 refs->orig_pos = rsc->orig_pos;
1562 refs->unicode_enc = rsc->unicodeenc;
1563 SCMakeDependent(dsc,rsc);
1564 } else {
1565 LogError( _("Couldn't find referenced character \"%s\" in %s\n"),
1566 AdobeStandardEncoding[refs->adobe_enc], dsc->name);
1567 return;
1569 } else if ( refs->sc->ticked )
1570 return;
1572 rsc = refs->sc;
1573 rsc->ticked = true;
1575 for ( rf=rsc->layers[ly_fore].refs; rf!=NULL; rf = rf->next ) {
1576 trans[0] = rf->transform[0]*transform[0] +
1577 rf->transform[1]*transform[2];
1578 trans[1] = rf->transform[0]*transform[1] +
1579 rf->transform[1]*transform[3];
1580 trans[2] = rf->transform[2]*transform[0] +
1581 rf->transform[3]*transform[2];
1582 trans[3] = rf->transform[2]*transform[1] +
1583 rf->transform[3]*transform[3];
1584 trans[4] = rf->transform[4]*transform[0] +
1585 rf->transform[5]*transform[2] +
1586 transform[4];
1587 trans[5] = rf->transform[4]*transform[1] +
1588 rf->transform[5]*transform[3] +
1589 transform[5];
1590 InstanciateReference(sf,topref,rf,trans,rsc,layer);
1592 rsc->ticked = false;
1595 new = SplinePointListTransform(SplinePointListCopy(rsc->layers[layer].splines),transform,true);
1596 if ( new!=NULL ) {
1597 for ( spl = new; spl->next!=NULL; spl = spl->next );
1598 spl->next = topref->layers[0].splines;
1599 topref->layers[0].splines = new;
1604 static char *copyparse(char *str) {
1605 char *ret, *rpt;
1606 int ch,i;
1608 if ( str==NULL )
1609 return( str );
1611 rpt=ret=galloc(strlen(str)+1);
1612 while ( *str ) {
1613 if ( *str=='\\' ) {
1614 ++str;
1615 if ( *str=='n' ) ch = '\n';
1616 else if ( *str=='r' ) ch = '\r';
1617 else if ( *str=='t' ) ch = '\t';
1618 else if ( *str=='b' ) ch = '\b';
1619 else if ( *str=='f' ) ch = '\f';
1620 else if ( *str=='\\' ) ch = '\\';
1621 else if ( *str=='(' ) ch = '(';
1622 else if ( *str==')' ) ch = ')';
1623 else if ( *str>='0' && *str<='7' ) {
1624 for ( i=ch = 0; i<3 && *str>='0' && *str<='7'; ++i )
1625 ch = (ch<<3) + *str++-'0';
1626 --str;
1627 } else
1628 ch = *str;
1629 ++str;
1630 *rpt++ = ch;
1631 } else
1632 *rpt++ = *str++;
1634 *rpt = '\0';
1635 if ( !utf8_valid(ret)) {
1636 /* Assume latin1, convert to utf8 */
1637 rpt = latin1_2_utf8_copy(ret);
1638 free(ret);
1639 ret = rpt;
1641 return(ret);
1644 char *XUIDFromFD(int xuid[20]) {
1645 int i;
1646 char *ret=NULL;
1648 for ( i=19; i>=0 && xuid[i]==0; --i );
1649 if ( i>=0 ) {
1650 int j; char *pt;
1651 ret = galloc(2+20*(i+1));
1652 pt = ret;
1653 *pt++ = '[';
1654 for ( j=0; j<=i; ++j ) {
1655 sprintf(pt,"%d ", xuid[j]);
1656 pt += strlen(pt);
1658 pt[-1] = ']';
1660 return( ret );
1663 static void SplineFontMetaData(SplineFont *sf,struct fontdict *fd) {
1664 int em;
1666 sf->fontname = utf8_verify_copy(fd->cidfontname?fd->cidfontname:fd->fontname);
1667 sf->display_size = -default_fv_font_size;
1668 sf->display_antialias = default_fv_antialias;
1669 if ( fd->fontinfo!=NULL ) {
1670 if ( sf->fontname==NULL && fd->fontinfo->fullname!=NULL ) {
1671 sf->fontname = EnforcePostScriptName(fd->fontinfo->fullname);
1673 if ( sf->fontname==NULL ) sf->fontname = EnforcePostScriptName(fd->fontinfo->familyname);
1674 sf->fullname = copyparse(fd->fontinfo->fullname);
1675 sf->familyname = copyparse(fd->fontinfo->familyname);
1676 sf->weight = copyparse(fd->fontinfo->weight);
1677 sf->version = copyparse(fd->fontinfo->version);
1678 sf->copyright = copyparse(fd->fontinfo->notice);
1679 sf->italicangle = fd->fontinfo->italicangle;
1680 sf->upos = fd->fontinfo->underlineposition;
1681 sf->uwidth = fd->fontinfo->underlinethickness;
1682 sf->strokedfont = fd->painttype==2;
1683 sf->strokewidth = fd->strokewidth;
1684 sf->ascent = fd->fontinfo->ascent;
1685 sf->descent = fd->fontinfo->descent;
1687 if ( sf->uniqueid==0 ) sf->uniqueid = fd->uniqueid;
1688 if ( sf->fontname==NULL ) sf->fontname = GetNextUntitledName();
1689 if ( sf->fullname==NULL ) sf->fullname = copy(sf->fontname);
1690 if ( sf->familyname==NULL ) sf->familyname = copy(sf->fontname);
1691 if ( sf->weight==NULL ) sf->weight = copy("");
1692 if ( fd->modificationtime!=0 ) {
1693 sf->modificationtime = fd->modificationtime;
1694 sf->creationtime = fd->creationtime;
1696 sf->cidversion = fd->cidversion;
1697 sf->xuid = XUIDFromFD(fd->xuid);
1698 /*sf->wasbinary = fd->wasbinary;*/
1699 if ( fd->fontmatrix[0]==0 )
1700 em = 1000;
1701 else
1702 em = rint(1/fd->fontmatrix[0]);
1703 if ( sf->ascent==0 && sf->descent!=0 )
1704 sf->ascent = em-sf->descent;
1705 else if ( fd->fontbb[3]-fd->fontbb[1]==em ) {
1706 if ( sf->ascent==0 ) sf->ascent = fd->fontbb[3];
1707 if ( sf->descent==0 ) sf->descent = fd->fontbb[1];
1708 } else if ( sf->ascent==0 )
1709 sf->ascent = 8*em/10;
1710 sf->descent = em-sf->ascent;
1712 sf->private = fd->private->private; fd->private->private = NULL;
1713 PSDictRemoveEntry(sf->private, "OtherSubrs");
1715 sf->cidregistry = copy(fd->registry);
1716 sf->ordering = copy(fd->ordering);
1717 sf->supplement = fd->supplement;
1718 sf->pfminfo.fstype = fd->fontinfo->fstype;
1719 if ( sf->ordering!=NULL ) {
1720 if ( strnmatch(sf->ordering,"Japan",5)==0 )
1721 sf->uni_interp = ui_japanese;
1722 else if ( strnmatch(sf->ordering,"Korea",5)==0 )
1723 sf->uni_interp = ui_korean;
1724 else if ( strnmatch(sf->ordering,"CNS",3)==0 )
1725 sf->uni_interp = ui_trad_chinese;
1726 else if ( strnmatch(sf->ordering,"GB",2)==0 )
1727 sf->uni_interp = ui_simp_chinese;
1731 static void TransByFontMatrix(SplineFont *sf,real fontmatrix[6]) {
1732 real trans[6];
1733 int em = sf->ascent+sf->descent, i;
1734 SplineChar *sc;
1735 RefChar *refs;
1737 if ( fontmatrix[0]==fontmatrix[3] &&
1738 fontmatrix[1]==0 && fontmatrix[2]==0 &&
1739 fontmatrix[4]==0 && fontmatrix[5]==0 )
1740 return; /* It's just the expected matrix */
1742 trans[0] = 1;
1743 if ( fontmatrix[0]==fontmatrix[3] ) trans[3] = 1;
1744 else trans[3] = rint(fontmatrix[3]*em);
1745 trans[1] = fontmatrix[1]*em;
1746 trans[2] = fontmatrix[2]*em;
1747 trans[4] = rint(fontmatrix[4]*em);
1748 trans[5] = rint(fontmatrix[5]*em);
1750 for ( i=0; i<sf->glyphcnt; ++i ) if ( (sc=sf->glyphs[i])!=NULL ) {
1751 SplinePointListTransform(sc->layers[ly_fore].splines,trans,true);
1752 for ( refs=sc->layers[ly_fore].refs; refs!=NULL; refs=refs->next ) {
1753 /* Just scale the offsets. we'll do all the base characters */
1754 real temp = refs->transform[4]*trans[0] +
1755 refs->transform[5]*trans[2] +
1756 /*transform[4]*/0;
1757 refs->transform[5] = refs->transform[4]*trans[1] +
1758 refs->transform[5]*trans[3] +
1759 /*transform[5]*/0;
1760 refs->transform[4] = temp;
1762 sc->changedsincelasthinted = true;
1763 sc->manualhints = false;
1765 for ( i=0; i<sf->glyphcnt; ++i ) if ( (sc=sf->glyphs[i])!=NULL ) {
1766 for ( refs=sc->layers[ly_fore].refs; refs!=NULL; refs=refs->next )
1767 SCReinstanciateRefChar(sc,refs,ly_fore);
1771 void SFInstanciateRefs(SplineFont *sf) {
1772 int i, layer;
1773 RefChar *refs, *next, *pr;
1775 for ( i=0; i<sf->glyphcnt; ++i ) if ( sf->glyphs[i]!=NULL )
1776 sf->glyphs[i]->ticked = false;
1778 for ( i=0; i<sf->glyphcnt; ++i ) if ( sf->glyphs[i]!=NULL ) {
1779 SplineChar *sc = sf->glyphs[i];
1781 for ( layer=ly_back; layer<sc->layer_cnt; ++layer ) {
1782 for ( pr=NULL, refs = sc->layers[layer].refs; refs!=NULL; refs=next ) {
1783 next = refs->next;
1784 sc->ticked = true;
1785 InstanciateReference(sf, refs, refs, refs->transform,sc,layer);
1786 if ( refs->sc!=NULL ) {
1787 SplineSetFindBounds(refs->layers[0].splines,&refs->bb);
1788 sc->ticked = false;
1789 pr = refs;
1790 } else {
1791 /* In some mal-formed postscript fonts we can have a reference */
1792 /* to a character that is not actually in the font. I even */
1793 /* generated one by mistake once... */
1794 if ( pr==NULL )
1795 sc->layers[layer].refs = next;
1796 else
1797 pr->next = next;
1798 refs->next = NULL;
1799 RefCharsFree(refs);
1806 /* Also handles type3s */
1807 static void _SplineFontFromType1(SplineFont *sf, FontDict *fd, struct pscontext *pscontext) {
1808 int i, j, notdefpos;
1809 RefChar *refs, *next;
1810 int istype2 = fd->fonttype==2; /* Easy enough to deal with even though it will never happen... */
1811 int istype3 = fd->charprocs->next!=0;
1812 EncMap *map;
1814 if ( istype2 )
1815 fd->private->subrs->bias = fd->private->subrs->cnt<1240 ? 107 :
1816 fd->private->subrs->cnt<33900 ? 1131 : 32768;
1817 sf->glyphmax = sf->glyphcnt = istype3 ? fd->charprocs->next : fd->chars->next;
1818 if ( sf->map==NULL ) {
1819 sf->map = map = EncMapNew(256+CharsNotInEncoding(fd),sf->glyphcnt,fd->encoding_name);
1820 } else
1821 map = sf->map;
1822 sf->glyphs = gcalloc(map->backmax,sizeof(SplineChar *));
1823 if ( istype3 )
1824 notdefpos = LookupCharString(".notdef",(struct pschars *) (fd->charprocs));
1825 else
1826 notdefpos = LookupCharString(".notdef",fd->chars);
1827 for ( i=0; i<256; ++i ) {
1828 int k;
1829 if ( istype3 ) {
1830 k = LookupCharString(fd->encoding[i],(struct pschars *) (fd->charprocs));
1831 } else {
1832 k = LookupCharString(fd->encoding[i],fd->chars);
1834 if ( k==-1 ) k = notdefpos;
1835 map->map[i] = k;
1836 if ( k!=-1 && map->backmap[k]==-1 )
1837 map->backmap[k] = i;
1839 if ( map->enccount>256 ) {
1840 int k, j;
1841 for ( k=0; k<fd->chars->cnt; ++k ) {
1842 if ( fd->chars->keys[k]!=NULL ) {
1843 for ( j=0; j<256; ++j )
1844 if ( fd->encoding[j]!=NULL &&
1845 strcmp(fd->encoding[j],fd->chars->keys[k])==0 )
1846 break;
1847 if ( j==256 ) {
1848 map->map[i] = k;
1849 if ( map->backmap[k]==-1 )
1850 map->backmap[k] = i;
1851 ++i;
1855 /* And for type3s */
1856 for ( k=0; k<fd->charprocs->cnt; ++k ) {
1857 if ( fd->charprocs->keys[k]!=NULL ) {
1858 for ( j=0; j<256; ++j )
1859 if ( fd->encoding[j]!=NULL &&
1860 strcmp(fd->encoding[j],fd->charprocs->keys[k])==0 )
1861 break;
1862 if ( j==256 ) {
1863 map->map[i] = k;
1864 if ( map->backmap[k]==-1 )
1865 map->backmap[k] = i;
1866 ++i;
1871 for ( i=0; i<map->enccount; ++i ) if ( map->map[i]==-1 )
1872 map->map[i] = notdefpos;
1874 for ( i=0; i<sf->glyphcnt; ++i ) {
1875 if ( !istype3 )
1876 sf->glyphs[i] = PSCharStringToSplines(fd->chars->values[i],fd->chars->lens[i],
1877 pscontext,fd->private->subrs,NULL,fd->chars->keys[i]);
1878 else
1879 sf->glyphs[i] = fd->charprocs->values[i];
1880 if ( sf->glyphs[i]!=NULL ) {
1881 sf->glyphs[i]->orig_pos = i;
1882 sf->glyphs[i]->vwidth = sf->ascent+sf->descent;
1883 sf->glyphs[i]->unicodeenc = UniFromName(sf->glyphs[i]->name,sf->uni_interp,map->enc);
1884 sf->glyphs[i]->parent = sf;
1885 /* SCLigDefault(sf->glyphs[i]);*/ /* Also reads from AFM file, but it probably doesn't exist */
1887 ff_progress_next();
1889 SFInstanciateRefs(sf);
1890 if ( fd->metrics!=NULL ) {
1891 for ( i=0; i<fd->metrics->next; ++i ) {
1892 int width = strtol(fd->metrics->values[i],NULL,10);
1893 for ( j=sf->glyphcnt-1; j>=0; --j ) {
1894 if ( sf->glyphs[j]!=NULL && sf->glyphs[j]->name!=NULL &&
1895 strcmp(fd->metrics->keys[i],sf->glyphs[j]->name)==0 ) {
1896 sf->glyphs[j]->width = width;
1897 break;
1902 for ( i=0; i<sf->glyphcnt; ++i ) if ( sf->glyphs[i]!=NULL )
1903 for ( refs = sf->glyphs[i]->layers[ly_fore].refs; refs!=NULL; refs=next ) {
1904 next = refs->next;
1905 if ( refs->adobe_enc==' ' && refs->layers[0].splines==NULL ) {
1906 /* When I have a link to a single character I will save out a */
1907 /* seac to that character and a space (since I can only make */
1908 /* real char links), so if we find a space link, get rid of*/
1909 /* it. It's an artifact */
1910 SCRefToSplines(sf->glyphs[i],refs,ly_fore);
1913 /* sometimes (some apple oblique fonts) the fontmatrix is not just a */
1914 /* formality, it acutally contains a skew. So be ready */
1915 if ( fd->fontmatrix[0]!=0 )
1916 TransByFontMatrix(sf,fd->fontmatrix);
1919 static void SplineFontFromType1(SplineFont *sf, FontDict *fd, struct pscontext *pscontext) {
1920 int i;
1921 SplineChar *sc;
1923 _SplineFontFromType1(sf,fd,pscontext);
1925 /* Clean up the hint masks, We create an initial hintmask whether we need */
1926 /* it or not */
1927 for ( i=0; i<sf->glyphcnt; ++i ) {
1928 if ( (sc = sf->glyphs[i])!=NULL && !sc->hconflicts && !sc->vconflicts &&
1929 sc->layers[ly_fore].splines!=NULL ) {
1930 chunkfree( sc->layers[ly_fore].splines->first->hintmask,sizeof(HintMask) );
1931 sc->layers[ly_fore].splines->first->hintmask = NULL;
1936 static SplineFont *SplineFontFromMMType1(SplineFont *sf, FontDict *fd, struct pscontext *pscontext) {
1937 char *pt, *end, *origweight;
1938 MMSet *mm;
1939 int ipos, apos, ppos, item, i;
1940 real blends[12]; /* At most twelve points/axis in a blenddesignmap */
1941 real designs[12];
1942 EncMap *map;
1944 if ( fd->weightvector==NULL || fd->fontinfo->blenddesignpositions==NULL ||
1945 fd->fontinfo->blenddesignmap==NULL || fd->fontinfo->blendaxistypes==NULL ) {
1946 ff_post_error(_("Bad Multiple Master Font"),_("Bad Multiple Master Font"));
1947 SplineFontFree(sf);
1948 return( NULL );
1951 mm = chunkalloc(sizeof(MMSet));
1953 pt = fd->weightvector;
1954 while ( *pt==' ' || *pt=='[' ) ++pt;
1955 while ( *pt!=']' && *pt!='\0' ) {
1956 pscontext->blend_values[ pscontext->instance_count ] =
1957 strtod(pt,&end);
1958 if ( pt==end )
1959 break;
1960 ++(pscontext->instance_count);
1961 if ( pscontext->instance_count>=(int)(sizeof(pscontext->blend_values)/sizeof(pscontext->blend_values[0]))) {
1962 LogError( _("Multiple master font with more than 16 instances\n") );
1963 break;
1965 for ( pt = end; *pt==' '; ++pt );
1968 mm->instance_count = pscontext->instance_count;
1969 mm->instances = galloc(pscontext->instance_count*sizeof(SplineFont *));
1970 mm->defweights = galloc(mm->instance_count*sizeof(real));
1971 memcpy(mm->defweights,pscontext->blend_values,mm->instance_count*sizeof(real));
1972 mm->normal = sf;
1973 _SplineFontFromType1(mm->normal,fd,pscontext);
1974 map = sf->map;
1975 for ( i=0; i<sf->glyphcnt; ++i ) if ( sf->glyphs[i]!=NULL )
1976 sf->glyphs[i]->blended = true;
1977 sf->mm = mm;
1979 pt = fd->fontinfo->blendaxistypes;
1980 while ( *pt==' ' || *pt=='[' ) ++pt;
1981 while ( *pt!=']' && *pt!='\0' ) {
1982 if ( *pt=='/' ) ++pt;
1983 for ( end=pt; *end!=' ' && *end!=']' && *end!='\0'; ++end );
1984 if ( pt==end )
1985 break;
1986 if ( mm->axis_count>=(int)(sizeof(mm->axes)/sizeof(mm->axes[0]))) {
1987 LogError( _("Multiple master font with more than 4 axes\n") );
1988 break;
1990 mm->axes[ mm->axis_count++ ] = copyn( pt,end-pt );
1991 for ( pt = end; *pt==' '; ++pt );
1994 if ( mm->instance_count < (1<<mm->axis_count) )
1995 ff_post_error(_("Bad Multiple Master Font"),_("This multiple master font has %1$d instance fonts, but it needs at least %2$d master fonts for %3$d axes. FontForge will not be able to edit this correctly"),mm->instance_count,1<<mm->axis_count,mm->axis_count);
1996 else if ( mm->instance_count > (1<<mm->axis_count) )
1997 ff_post_error(_("Bad Multiple Master Font"),_("This multiple master font has %1$d instance fonts, but FontForge can only handle %2$d master fonts for %3$d axes. FontForge will not be able to edit this correctly"),mm->instance_count,1<<mm->axis_count,mm->axis_count);
1998 mm->positions = gcalloc(mm->axis_count*mm->instance_count,sizeof(real));
1999 pt = fd->fontinfo->blenddesignpositions;
2000 while ( *pt==' ' ) ++pt;
2001 if ( *pt=='[' ) ++pt;
2002 ipos = 0;
2003 while ( *pt!=']' && *pt!='\0' ) {
2004 while ( *pt==' ' ) ++pt;
2005 if ( *pt==']' || *pt=='\0' )
2006 break;
2007 if ( ipos>=mm->instance_count )
2008 break;
2009 if ( *pt=='[' ) {
2010 ++pt;
2011 apos=0;
2012 while ( *pt!=']' && *pt!='\0' ) {
2013 if ( apos>=mm->axis_count ) {
2014 LogError( _("Too many axis positions specified in /BlendDesignPositions.\n") );
2015 break;
2017 mm->positions[ipos*mm->axis_count+apos] =
2018 strtod(pt,&end);
2019 if ( pt==end )
2020 break;
2021 ++apos;
2022 for ( pt = end; *pt==' '; ++pt );
2024 if ( *pt==']' ) ++pt;
2025 ++ipos;
2026 } else
2027 ++pt;
2030 mm->axismaps = gcalloc(mm->axis_count,sizeof(struct axismap));
2031 pt = fd->fontinfo->blenddesignmap;
2032 while ( *pt==' ' ) ++pt;
2033 if ( *pt=='[' ) ++pt;
2034 apos = 0;
2035 while ( *pt!=']' && *pt!='\0' ) {
2036 while ( *pt==' ' ) ++pt;
2037 if ( *pt==']' || *pt=='\0' )
2038 break;
2039 if ( apos>=mm->axis_count )
2040 break;
2041 if ( *pt=='[' ) {
2042 ++pt;
2043 ppos=0;
2044 while ( *pt!=']' && *pt!='\0' ) {
2045 if ( ppos>=12 ) {
2046 LogError( _("Too many mapping data points specified in /BlendDesignMap for axis %s.\n"), mm->axes[apos] );
2047 break;
2049 while ( *pt==' ' ) ++pt;
2050 if ( *pt=='[' ) {
2051 ++pt;
2052 designs[ppos] = strtod(pt,&end);
2053 blends[ppos] = strtod(end,&end);
2054 if ( blends[ppos]<0 || blends[ppos]>1 ) {
2055 LogError( _("Bad value for blend in /BlendDesignMap for axis %s.\n"), mm->axes[apos] );
2056 if ( blends[ppos]<0 ) blends[ppos] = 0;
2057 if ( blends[ppos]>1 ) blends[ppos] = 1;
2059 pt = end;
2060 while ( *pt!=']' && *pt!='\0' ) ++pt;
2061 ppos ++;
2063 ++pt;
2064 while ( *pt==' ' ) ++pt;
2066 if ( *pt==']' ) ++pt;
2067 if ( ppos<2 )
2068 LogError( _("Bad few values in /BlendDesignMap for axis %s.\n"), mm->axes[apos] );
2069 mm->axismaps[apos].points = ppos;
2070 mm->axismaps[apos].blends = galloc(ppos*sizeof(real));
2071 mm->axismaps[apos].designs = galloc(ppos*sizeof(real));
2072 memcpy(mm->axismaps[apos].blends,blends,ppos*sizeof(real));
2073 memcpy(mm->axismaps[apos].designs,designs,ppos*sizeof(real));
2074 ++apos;
2075 } else
2076 ++pt;
2079 mm->cdv = copy(fd->cdv);
2080 mm->ndv = copy(fd->ndv);
2082 origweight = fd->fontinfo->weight;
2084 /* Now figure out the master designs, being careful to interpolate */
2085 /* BlueValues, ForceBold, UnderlinePosition etc. We need to copy private */
2086 /* generate a font name */
2087 for ( ipos = 0; ipos<mm->instance_count; ++ipos ) {
2088 free(fd->fontname);
2089 free(fd->fontinfo->fullname);
2090 fd->fontname = MMMakeMasterFontname(mm,ipos,&fd->fontinfo->fullname);
2091 fd->fontinfo->weight = MMGuessWeight(mm,ipos,copy(origweight));
2092 if ( fd->blendfontinfo!=NULL ) {
2093 for ( item=0; item<3; ++item ) {
2094 static char *names[] = { "ItalicAngle", "UnderlinePosition", "UnderlineThickness" };
2095 pt = PSDictHasEntry(fd->blendfontinfo,names[item]);
2096 if ( pt!=NULL ) {
2097 pt = MMExtractNth(pt,ipos);
2098 if ( pt!=NULL ) {
2099 double val = strtod(pt,NULL);
2100 free(pt);
2101 switch ( item ) {
2102 case 0: fd->fontinfo->italicangle = val; break;
2103 case 1: fd->fontinfo->underlineposition = val; break;
2104 case 2: fd->fontinfo->underlinethickness = val; break;
2110 fd->private->private = PSDictCopy(sf->private);
2111 if ( fd->blendprivate!=NULL ) {
2112 static char *arrnames[] = { "BlueValues", "OtherBlues", "FamilyBlues", "FamilyOtherBlues", "StdHW", "StdVW", "StemSnapH", "StemSnapV", NULL };
2113 static char *scalarnames[] = { "ForceBold", "BlueFuzz", "BlueScale", "BlueShift", NULL };
2114 for ( item=0; scalarnames[item]!=NULL; ++item ) {
2115 pt = PSDictHasEntry(fd->blendprivate,scalarnames[item]);
2116 if ( pt!=NULL ) {
2117 pt = MMExtractNth(pt,ipos);
2118 PSDictChangeEntry(fd->private->private,scalarnames[item],pt);
2119 free(pt);
2122 for ( item=0; arrnames[item]!=NULL; ++item ) {
2123 pt = PSDictHasEntry(fd->blendprivate,arrnames[item]);
2124 if ( pt!=NULL ) {
2125 pt = MMExtractArrayNth(pt,ipos);
2126 PSDictChangeEntry(fd->private->private,arrnames[item],pt);
2127 free(pt);
2131 for ( item=0; item<mm->instance_count; ++item )
2132 pscontext->blend_values[item] = 0;
2133 pscontext->blend_values[ipos] = 1;
2135 mm->instances[ipos] = SplineFontEmpty();
2136 SplineFontMetaData(mm->instances[ipos],fd);
2137 free(fd->fontinfo->weight);
2138 mm->instances[ipos]->map = map;
2139 _SplineFontFromType1(mm->instances[ipos],fd,pscontext);
2140 mm->instances[ipos]->mm = mm;
2142 fd->fontinfo->weight = origweight;
2144 /* Clean up hintmasks. We always create a hintmask on the first point */
2145 /* only keep them if we actually have conflicts. */
2146 for ( i=0; i<mm->normal->glyphcnt; ++i )
2147 if ( mm->normal->glyphs[i]!=NULL &&
2148 mm->normal->glyphs[i]->layers[ly_fore].splines != NULL ) {
2149 for ( item=0; item<mm->instance_count; ++item )
2150 if ( mm->instances[item]->glyphs[i]->vconflicts ||
2151 mm->instances[item]->glyphs[i]->hconflicts )
2152 break;
2153 if ( item==mm->instance_count ) { /* No conflicts */
2154 for ( item=0; item<mm->instance_count; ++item ) {
2155 chunkfree( mm->instances[item]->glyphs[i]->layers[ly_fore].splines->first->hintmask, sizeof(HintMask) );
2156 mm->instances[item]->glyphs[i]->layers[ly_fore].splines->first->hintmask = NULL;
2158 chunkfree( mm->normal->glyphs[i]->layers[ly_fore].splines->first->hintmask, sizeof(HintMask) );
2159 mm->normal->glyphs[i]->layers[ly_fore].splines->first->hintmask = NULL;
2163 return( sf );
2166 static SplineFont *SplineFontFromCIDType1(SplineFont *sf, FontDict *fd,
2167 struct pscontext *pscontext) {
2168 int i,j,k, uni;
2169 unsigned bad;
2170 SplineChar **chars;
2171 char buffer[100];
2172 struct cidmap *map;
2173 SplineFont *_sf;
2174 SplineChar *sc;
2175 EncMap *encmap;
2177 bad = 0x80000000;
2178 for ( i=0; i<fd->fdcnt; ++i )
2179 if ( fd->fds[i]->fonttype!=1 && fd->fds[i]->fonttype!=2 )
2180 bad = fd->fds[i]->fonttype;
2181 if ( bad!=0x80000000 || fd->cidfonttype!=0 ) {
2182 LogError( _("Could not parse a CID font, %sCIDFontType %d, %sfonttype %d\n"),
2183 ( fd->cidfonttype!=0 ) ? "unexpected " : "",
2184 ( bad!=0x80000000 ) ? "unexpected " : "",
2185 fd->cidfonttype, bad );
2186 SplineFontFree(sf);
2187 return( NULL );
2189 if ( fd->cidstrs==NULL || fd->cidcnt==0 ) {
2190 LogError( _("CID format doesn't contain what we expected it to.\n") );
2191 SplineFontFree(sf);
2192 return( NULL );
2195 encmap = EncMap1to1(fd->cidcnt);
2197 sf->subfontcnt = fd->fdcnt;
2198 sf->subfonts = galloc((sf->subfontcnt+1)*sizeof(SplineFont *));
2199 for ( i=0; i<fd->fdcnt; ++i ) {
2200 if ( fd->fontmatrix[0]!=0 ) {
2201 MatMultiply(fd->fontmatrix,fd->fds[i]->fontmatrix,fd->fds[i]->fontmatrix);
2203 sf->subfonts[i] = SplineFontEmpty();
2204 SplineFontMetaData(sf->subfonts[i],fd->fds[i]);
2205 sf->subfonts[i]->cidmaster = sf;
2206 sf->subfonts[i]->uni_interp = sf->uni_interp;
2207 sf->subfonts[i]->map = encmap;
2208 if ( fd->fds[i]->fonttype==2 )
2209 fd->fds[i]->private->subrs->bias =
2210 fd->fds[i]->private->subrs->cnt<1240 ? 107 :
2211 fd->fds[i]->private->subrs->cnt<33900 ? 1131 : 32768;
2214 map = FindCidMap(sf->cidregistry,sf->ordering,sf->supplement,sf);
2216 chars = gcalloc(fd->cidcnt,sizeof(SplineChar *));
2217 for ( i=0; i<fd->cidcnt; ++i ) if ( fd->cidlens[i]>0 ) {
2218 j = fd->cidfds[i]; /* We get font indexes of 255 for non-existant chars */
2219 uni = CID2NameUni(map,i,buffer,sizeof(buffer));
2220 pscontext->is_type2 = fd->fds[j]->fonttype==2;
2221 chars[i] = PSCharStringToSplines(fd->cidstrs[i],fd->cidlens[i],
2222 pscontext,fd->fds[j]->private->subrs,
2223 NULL,buffer);
2224 chars[i]->vwidth = sf->subfonts[j]->ascent+sf->subfonts[j]->descent;
2225 chars[i]->unicodeenc = uni;
2226 chars[i]->orig_pos = i;
2227 /* There better not be any references (seac's) because we have no */
2228 /* encoding on which to base any fixups */
2229 if ( chars[i]->layers[ly_fore].refs!=NULL )
2230 IError( "Reference found in CID font. Can't fix it up");
2231 sf->subfonts[j]->glyphcnt = sf->subfonts[j]->glyphmax = i+1;
2232 ff_progress_next();
2234 for ( i=0; i<fd->fdcnt; ++i )
2235 sf->subfonts[i]->glyphs = gcalloc(sf->subfonts[i]->glyphcnt,sizeof(SplineChar *));
2236 for ( i=0; i<fd->cidcnt; ++i ) if ( chars[i]!=NULL ) {
2237 j = fd->cidfds[i];
2238 if ( j<sf->subfontcnt ) {
2239 sf->subfonts[j]->glyphs[i] = chars[i];
2240 chars[i]->parent = sf->subfonts[j];
2243 free(chars);
2245 /* Clean up the hint masks, We create an initial hintmask whether we */
2246 /* need it or not */
2247 k=0;
2248 do {
2249 _sf = k<sf->subfontcnt?sf->subfonts[k]:sf;
2250 for ( i=0; i<_sf->glyphcnt; ++i ) {
2251 if ( (sc = _sf->glyphs[i])!=NULL && !sc->hconflicts && !sc->vconflicts &&
2252 sc->layers[ly_fore].splines!=NULL ) {
2253 chunkfree( sc->layers[ly_fore].splines->first->hintmask,sizeof(HintMask) );
2254 sc->layers[ly_fore].splines->first->hintmask = NULL;
2257 ++k;
2258 } while ( k<sf->subfontcnt );
2259 return( sf );
2262 SplineFont *SplineFontFromPSFont(FontDict *fd) {
2263 SplineFont *sf;
2264 struct pscontext pscontext;
2266 if ( fd->sf!=NULL )
2267 sf = fd->sf;
2268 else {
2269 memset(&pscontext,0,sizeof(pscontext));
2270 pscontext.is_type2 = fd->fonttype==2;
2271 pscontext.painttype = fd->painttype;
2273 sf = SplineFontEmpty();
2274 SplineFontMetaData(sf,fd);
2275 if ( fd->wascff ) {
2276 SplineFontFree(sf);
2277 sf = fd->sf;
2278 } else if ( fd->fdcnt!=0 )
2279 sf = SplineFontFromCIDType1(sf,fd,&pscontext);
2280 else if ( fd->weightvector!=NULL )
2281 SplineFontFromMMType1(sf,fd,&pscontext);
2282 else
2283 SplineFontFromType1(sf,fd,&pscontext);
2285 return( sf );
2288 void RefCharFindBounds(RefChar *rf) {
2289 SplineSetFindBounds(rf->layers[0].splines,&rf->bb);
2290 SplineSetFindTop(rf->layers[0].splines,&rf->top);
2293 void SCReinstanciateRefChar(SplineChar *sc,RefChar *rf,int layer) {
2294 SplinePointList *new, *last;
2295 RefChar *refs;
2296 (void)sc;
2298 if ( rf->layer_cnt>0 ) {
2299 SplinePointListsFree(rf->layers[0].splines);
2300 rf->layers[0].splines = NULL;
2302 rf->layers = gcalloc(1,sizeof(struct reflayer));
2303 rf->layer_cnt = 1;
2304 new = SplinePointListTransform(SplinePointListCopy(rf->sc->layers[layer].splines),rf->transform,true);
2305 rf->layers[0].splines = new;
2306 last = NULL;
2307 if ( new!=NULL )
2308 for ( last = new; last->next!=NULL; last = last->next );
2309 for ( refs = rf->sc->layers[layer].refs; refs!=NULL; refs = refs->next ) {
2310 new = SplinePointListTransform(SplinePointListCopy(refs->layers[0].splines),rf->transform,true);
2311 if ( last!=NULL )
2312 last->next = new;
2313 else
2314 rf->layers[0].splines = new;
2315 if ( new!=NULL )
2316 for ( last = new; last->next!=NULL; last = last->next );
2319 RefCharFindBounds(rf);
2322 static void _SFReinstanciateRefs(SplineFont *sf) {
2323 int i, undone, undoable, j, cnt;
2324 RefChar *ref;
2326 for ( i=0; i<sf->glyphcnt; ++i ) if ( sf->glyphs[i]!=NULL )
2327 sf->glyphs[i]->ticked = false;
2329 undone = true;
2330 cnt = 0;
2331 while ( undone && cnt<200) {
2332 undone = false;
2333 for ( i=0; i<sf->glyphcnt; ++i ) if ( sf->glyphs[i]!=NULL && !sf->glyphs[i]->ticked ) {
2334 undoable = false;
2335 for ( j=0; j<sf->glyphs[i]->layer_cnt; ++j ) {
2336 for ( ref=sf->glyphs[i]->layers[j].refs; ref!=NULL; ref=ref->next ) {
2337 if ( !ref->sc->ticked )
2338 undoable = true;
2341 if ( undoable )
2342 undone = true;
2343 else {
2344 for ( j=0; j<sf->glyphs[i]->layer_cnt; ++j ) {
2345 for ( ref=sf->glyphs[i]->layers[j].refs; ref!=NULL; ref=ref->next )
2346 SCReinstanciateRefChar(sf->glyphs[i],ref,j);
2348 sf->glyphs[i]->ticked = true;
2351 ++cnt;
2355 void SFReinstanciateRefs(SplineFont *sf) {
2356 int i;
2358 if ( sf->cidmaster!=NULL || sf->subfontcnt!=0 ) {
2359 if ( sf->cidmaster!=NULL ) sf = sf->cidmaster;
2360 for ( i=0; i<sf->subfontcnt; ++i )
2361 _SFReinstanciateRefs(sf->subfonts[i]);
2362 } else
2363 _SFReinstanciateRefs(sf);
2366 void SCReinstanciateRef(SplineChar *sc,SplineChar *rsc,int layer) {
2367 RefChar *rf;
2369 for ( rf=sc->layers[layer].refs; rf!=NULL; rf=rf->next ) if ( rf->sc==rsc ) {
2370 SCReinstanciateRefChar(sc,rf,layer);
2374 void SCRemoveDependent(SplineChar *dependent,RefChar *rf,int layer) {
2375 struct splinecharlist *dlist, *pd;
2376 RefChar *prev;
2378 if ( dependent->layers[layer].refs==rf )
2379 dependent->layers[layer].refs = rf->next;
2380 else {
2381 for ( prev = dependent->layers[layer].refs; prev->next!=rf; prev=prev->next );
2382 prev->next = rf->next;
2384 /* Check for multiple dependencies (colon has two refs to period) */
2385 /* if there are none, then remove dependent from ref->sc's dependents list */
2386 for ( prev = dependent->layers[ly_fore].refs; prev!=NULL && (prev==rf || prev->sc!=rf->sc); prev = prev->next );
2387 if ( prev==NULL ) {
2388 dlist = rf->sc->dependents;
2389 if ( dlist==NULL )
2390 /* Do nothing */;
2391 else if ( dlist->sc==dependent ) {
2392 rf->sc->dependents = dlist->next;
2393 } else {
2394 for ( pd=dlist, dlist = pd->next; dlist!=NULL && dlist->sc!=dependent; pd=dlist, dlist = pd->next );
2395 if ( dlist!=NULL )
2396 pd->next = dlist->next;
2398 chunkfree(dlist,sizeof(struct splinecharlist));
2400 RefCharFree(rf);
2403 void SCRemoveLayerDependents(SplineChar *dependent,int layer) {
2404 RefChar *rf, *next;
2406 for ( rf=dependent->layers[layer].refs; rf!=NULL; rf=next ) {
2407 next = rf->next;
2408 SCRemoveDependent(dependent,rf,layer);
2410 dependent->layers[layer].refs = NULL;
2413 void SCRemoveDependents(SplineChar *dependent) {
2414 int layer;
2416 for ( layer=ly_fore; layer<dependent->layer_cnt; ++layer )
2417 SCRemoveLayerDependents(dependent,layer);
2420 void SCRefToSplines(SplineChar *sc,RefChar *rf,int layer) {
2421 SplineSet *spl;
2423 if ( (spl = rf->layers[0].splines)!=NULL ) {
2424 while ( spl->next!=NULL )
2425 spl = spl->next;
2426 spl->next = sc->layers[layer].splines;
2427 sc->layers[layer].splines = rf->layers[0].splines;
2428 rf->layers[0].splines = NULL;
2431 SCRemoveDependent(sc,rf,layer);
2434 /* This returns all real solutions, even those out of bounds */
2435 /* I use -999999 as an error flag, since we're really only interested in */
2436 /* solns near 0 and 1 that should be ok. -1 is perhaps a little too close */
2437 static int _CubicSolve(const Spline1D *sp,extended ts[3]) {
2438 extended d, xN, yN, delta2, temp, delta, h, t2, t3, theta;
2439 int i=0;
2441 ts[0] = ts[1] = ts[2] = -999999;
2442 if ( sp->d==0 && sp->a!=0 ) {
2443 /* one of the roots is 0, the other two are the soln of a quadratic */
2444 ts[0] = 0;
2445 if ( sp->c==0 ) {
2446 ts[1] = -sp->b/(extended) sp->a; /* two zero roots */
2447 } else {
2448 temp = sp->b*(extended) sp->b-4*(extended) sp->a*sp->c;
2449 if ( RealNear(temp,0))
2450 ts[1] = -sp->b/(2*(extended) sp->a);
2451 else if ( temp>=0 ) {
2452 temp = sqrt(temp);
2453 ts[1] = (-sp->b+temp)/(2*(extended) sp->a);
2454 ts[2] = (-sp->b-temp)/(2*(extended) sp->a);
2457 } else if ( sp->a!=0 ) {
2458 /* http://www.m-a.org.uk/eb/mg/mg077ch.pdf */
2459 /* this nifty solution to the cubic neatly avoids complex arithmatic */
2460 xN = -sp->b/(3*(extended) sp->a);
2461 yN = ((sp->a*xN + sp->b)*xN+sp->c)*xN + sp->d;
2463 delta2 = (sp->b*(extended) sp->b-3*(extended) sp->a*sp->c)/(9*(extended) sp->a*sp->a);
2464 if ( RealNear(delta2,0) ) delta2 = 0;
2466 /* the descriminant is yN^2-h^2, but delta might be <0 so avoid using h */
2467 d = yN*yN - 4*sp->a*sp->a*delta2*delta2*delta2;
2468 if ( ((yN>.01 || yN<-.01) && RealNear(d/yN,0)) || ((yN<=.01 && yN>=-.01) && RealNear(d,0)) )
2469 d = 0;
2470 if ( d>0 ) {
2471 temp = sqrt(d);
2472 t2 = (-yN-temp)/(2*sp->a);
2473 t2 = (t2==0) ? 0 : (t2<0) ? -pow(-t2,1./3.) : pow(t2,1./3.);
2474 t3 = (-yN+temp)/(2*sp->a);
2475 t3 = t3==0 ? 0 : (t3<0) ? -pow(-t3,1./3.) : pow(t3,1./3.);
2476 ts[0] = xN + t2 + t3;
2477 } else if ( d<0 ) {
2478 if ( delta2>=0 ) {
2479 delta = sqrt(delta2);
2480 h = 2*sp->a*delta2*delta;
2481 temp = -yN/h;
2482 if ( temp>=-1.0001 && temp<=1.0001 ) {
2483 if ( temp<-1 ) temp = -1; else if ( temp>1 ) temp = 1;
2484 theta = acos(temp)/3;
2485 ts[i++] = xN+2*delta*cos(theta);
2486 ts[i++] = xN+2*delta*cos(2.0943951+theta);
2487 ts[i++] = xN+2*delta*cos(4.1887902+theta);
2490 } else if ( /* d==0 && */ delta2!=0 ) {
2491 delta = yN/(2*sp->a);
2492 delta = delta==0 ? 0 : delta>0 ? pow(delta,1./3.) : -pow(-delta,1./3.);
2493 ts[i++] = xN + delta; /* this root twice, but that's irrelevant to me */
2494 ts[i++] = xN - 2*delta;
2495 } else if ( /* d==0 && */ delta2==0 ) {
2496 if ( xN>=-0.0001 && xN<=1.0001 ) ts[0] = xN;
2498 } else if ( sp->b!=0 ) {
2499 extended d = sp->c*(extended) sp->c-4*(extended) sp->b*sp->d;
2500 if ( RealNear(d,0)) d=0;
2501 if ( d<0 )
2502 return(false); /* All roots imaginary */
2503 d = sqrt(d);
2504 ts[0] = (-sp->c-d)/(2*(extended) sp->b);
2505 ts[1] = (-sp->c+d)/(2*(extended) sp->b);
2506 } else if ( sp->c!=0 ) {
2507 ts[0] = -sp->d/(extended) sp->c;
2508 } else {
2509 /* If it's a point then either everything is a solution, or nothing */
2511 return( ts[0]!=-999999 );
2514 int CubicSolve(const Spline1D *sp,extended ts[3]) {
2515 extended t;
2516 int i;
2517 /* This routine gives us all solutions between [0,1] with -1 as an error flag */
2518 /* http://mathforum.org/dr.math/faq/faq.cubic.equations.html */
2520 if ( !_CubicSolve(sp,ts)) {
2521 ts[0] = ts[1] = ts[2] = -1;
2522 return( false );
2525 for ( i=0; i<3; ++i )
2526 if ( ts[i]==-999999 ) ts[i] = -1;
2527 if (ts[0]>1.0001 || ts[0]<-.0001 ) ts[0] = -1;
2528 else if ( ts[0]<0 ) ts[0] = 0; else if ( ts[0]>1 ) ts[0] = 1;
2529 if (ts[1]>1.0001 || ts[1]<-.0001 ) ts[1] = -1;
2530 else if ( ts[1]<0 ) ts[1] = 0; else if ( ts[1]>1 ) ts[1] = 1;
2531 if (ts[2]>1.0001 || ts[2]<-.0001 ) ts[2] = -1;
2532 else if ( ts[2]<0 ) ts[2] = 0; else if ( ts[2]>1 ) ts[2] = 1;
2533 if ( ts[1]==-1 ) { ts[1] = ts[2]; ts[2] = -1;}
2534 if ( ts[0]==-1 ) { ts[0] = ts[1]; ts[1] = ts[2]; ts[2] = -1; }
2535 if ( ts[0]==-1 )
2536 return( false );
2537 if ( ts[0]>ts[2] && ts[2]!=-1 ) {
2538 t = ts[0]; ts[0] = ts[2]; ts[2] = t;
2540 if ( ts[0]>ts[1] && ts[1]!=-1 ) {
2541 t = ts[0]; ts[0] = ts[1]; ts[1] = t;
2543 if ( ts[1]>ts[2] && ts[2]!=-1 ) {
2544 t = ts[1]; ts[1] = ts[2]; ts[2] = t;
2546 return( true );
2550 extended SplineSolve(const Spline1D *sp, real tmin, real tmax, extended sought,real err) {
2551 /* We want to find t so that spline(t) = sought */
2552 /* the curve must be monotonic */
2553 /* returns t which is near sought or -1 */
2554 Spline1D temp;
2555 extended ts[3];
2556 int i;
2557 extended t;
2558 (void)err;
2559 temp = *sp;
2560 temp.d -= sought;
2561 CubicSolve(&temp,ts);
2562 if ( tmax<tmin ) { t = tmax; tmax = tmin; tmin = t; }
2563 for ( i=0; i<3; ++i )
2564 if ( ts[i]>=tmin && ts[i]<=tmax )
2565 return( ts[i] );
2567 return( -1 );
2570 #ifndef EXTENDED_IS_LONG_DOUBLE
2571 double CheckExtremaForSingleBitErrors(const Spline1D *sp, double t) {
2572 union { double dval; int32 ival[2]; } u1, um1, temp;
2573 double slope, slope1, slopem1;
2574 #ifdef WORDS_BIGENDIAN
2575 const int index = 1;
2576 #else
2577 const int index = 0;
2578 #endif
2580 slope = (3*(double) sp->a*t+2*sp->b)*t+sp->c;
2582 u1.dval = t;
2583 u1.ival[index] += 1;
2584 slope1 = (3*(double) sp->a*u1.dval+2*sp->b)*u1.dval+sp->c;
2586 um1.dval = t;
2587 um1.ival[index] -= 1;
2588 slopem1 = (3*(double) sp->a*um1.dval+2*sp->b)*um1.dval+sp->c;
2590 if ( slope<0 ) slope = -slope;
2591 if ( slope1<0 ) slope1 = -slope1;
2592 if ( slopem1<0 ) slopem1 = -slopem1;
2594 if ( slope1<slope && slope1<=slopem1 ) {
2595 /* Ok, things got better when we added 1. */
2596 /* Do they improve further if we add 1 more? */
2597 temp = u1;
2598 temp.ival[index] += 1;
2599 slope = (3*(double) sp->a*temp.dval+2*sp->b)*temp.dval+sp->c;
2600 if ( slope<0 ) slope = -slope;
2601 if ( slope<slope1 )
2602 return( temp.dval );
2603 else
2604 return( u1.dval );
2605 } else if ( slopem1<slope && slopem1<=slope ) {
2606 /* Ok, things got better when we subtracted 1. */
2607 /* Do they improve further if we subtract 1 more? */
2608 temp = um1;
2609 temp.ival[index] -= 1;
2610 slope = (3*(double) sp->a*temp.dval+2*sp->b)*temp.dval+sp->c;
2611 if ( slope<0 ) slope = -slope;
2612 if ( slope<slopem1 )
2613 return( temp.dval );
2614 else
2615 return( um1.dval );
2617 /* that seems as good as it gets */
2619 return( t );
2621 #else
2622 extended esqrt(extended e) {
2623 extended rt, temp;
2625 rt = sqrt( (double) e );
2626 if ( e<=0 )
2627 return( rt );
2629 temp = e/rt;
2630 rt = (rt+temp)/2;
2631 temp = e/rt;
2632 rt = (rt+temp)/2;
2633 return( rt );
2635 #endif
2637 static void _SplineFindExtrema(const Spline1D *sp, extended *_t1, extended *_t2 ) {
2638 extended t1= -1, t2= -1;
2639 extended b2_fourac;
2641 /* Find the extreme points on the curve */
2642 /* Set to -1 if there are none or if they are outside the range [0,1] */
2643 /* Order them so that t1<t2 */
2644 /* If only one valid extremum it will be t1 */
2645 /* (Does not check the end points unless they have derivative==0) */
2646 /* (Does not check to see if d/dt==0 points are inflection points (rather than extrema) */
2647 if ( sp->a!=0 ) {
2648 /* cubic, possibly 2 extrema (possibly none) */
2649 b2_fourac = 4*(extended)sp->b*sp->b - 12*(extended)sp->a*sp->c;
2650 if ( b2_fourac>=0 ) {
2651 b2_fourac = esqrt(b2_fourac);
2652 t1 = (-2*sp->b - b2_fourac) / (6*sp->a);
2653 t2 = (-2*sp->b + b2_fourac) / (6*sp->a);
2654 t1 = CheckExtremaForSingleBitErrors(sp,t1);
2655 t2 = CheckExtremaForSingleBitErrors(sp,t2);
2656 if ( t1>t2 ) { extended temp = t1; t1 = t2; t2 = temp; }
2657 else if ( t1==t2 ) t2 = -1;
2658 if ( RealNear(t1,0)) t1=0; else if ( RealNear(t1,1)) t1=1;
2659 if ( RealNear(t2,0)) t2=0; else if ( RealNear(t2,1)) t2=1;
2661 } else if ( sp->b!=0 ) {
2662 /* Quadratic, at most one extremum */
2663 t1 = -sp->c/(2.0*(extended) sp->b);
2664 } else /*if ( sp->c!=0 )*/ {
2665 /* linear, no extrema */
2667 *_t1 = t1; *_t2 = t2;
2670 void SplineFindExtrema(const Spline1D *sp, extended *_t1, extended *_t2 ) {
2671 extended t1= -1, t2= -1;
2672 extended b2_fourac;
2674 /* Find the extreme points on the curve */
2675 /* Set to -1 if there are none or if they are outside the range [0,1] */
2676 /* Order them so that t1<t2 */
2677 /* If only one valid extremum it will be t1 */
2678 /* (Does not check the end points unless they have derivative==0) */
2679 /* (Does not check to see if d/dt==0 points are inflection points (rather than extrema) */
2680 if ( sp->a!=0 ) {
2681 /* cubic, possibly 2 extrema (possibly none) */
2682 b2_fourac = 4*(extended) sp->b*sp->b - 12*(extended) sp->a*sp->c;
2683 if ( b2_fourac>=0 ) {
2684 b2_fourac = esqrt(b2_fourac);
2685 t1 = (-2*sp->b - b2_fourac) / (6*sp->a);
2686 t2 = (-2*sp->b + b2_fourac) / (6*sp->a);
2687 t1 = CheckExtremaForSingleBitErrors(sp,t1);
2688 t2 = CheckExtremaForSingleBitErrors(sp,t2);
2689 if ( t1>t2 ) { extended temp = t1; t1 = t2; t2 = temp; }
2690 else if ( t1==t2 ) t2 = -1;
2691 if ( RealNear(t1,0)) t1=0; else if ( RealNear(t1,1)) t1=1;
2692 if ( RealNear(t2,0)) t2=0; else if ( RealNear(t2,1)) t2=1;
2693 if ( t2<=0 || t2>=1 ) t2 = -1;
2694 if ( t1<=0 || t1>=1 ) { t1 = t2; t2 = -1; }
2696 } else if ( sp->b!=0 ) {
2697 /* Quadratic, at most one extremum */
2698 t1 = -sp->c/(2.0*(extended) sp->b);
2699 if ( t1<=0 || t1>=1 ) t1 = -1;
2700 } else /*if ( sp->c!=0 )*/ {
2701 /* linear, no extrema */
2703 *_t1 = t1; *_t2 = t2;
2706 double SplineCurvature(Spline *s, double t) {
2707 /* Kappa = (x'y'' - y'x'') / (x'^2 + y'^2)^(3/2) */
2708 double dxdt, dydt, d2xdt2, d2ydt2, denom, numer;
2710 if ( s==NULL )
2711 return( CURVATURE_ERROR );
2713 dxdt = (3*s->splines[0].a*t+2*s->splines[0].b)*t+s->splines[0].c;
2714 dydt = (3*s->splines[1].a*t+2*s->splines[1].b)*t+s->splines[1].c;
2715 d2xdt2 = 6*s->splines[0].a*t + 2*s->splines[0].b;
2716 d2ydt2 = 6*s->splines[1].a*t + 2*s->splines[1].b;
2717 denom = pow( dxdt*dxdt + dydt*dydt, 3.0/2.0 );
2718 numer = dxdt*d2ydt2 - dydt*d2xdt2;
2720 if ( numer==0 )
2721 return( 0 );
2722 if ( denom==0 )
2723 return( CURVATURE_ERROR );
2725 return( numer/denom );
2728 int SplineAtInflection(Spline1D *sp, double t ) {
2729 /* It's a point of inflection if d sp/dt==0 and d2 sp/dt^2==0 */
2730 return ( RealNear( (3*sp->a*t + 2*sp->b)*t + sp->c,0) &&
2731 RealNear( 6*sp->a*t + 2*sp->b, 0));
2734 int SplineAtMinMax(Spline1D *sp, double t ) {
2735 /* It's a point of inflection if d sp/dt==0 and d2 sp/dt^2!=0 */
2736 return ( RealNear( (3*sp->a*t + 2*sp->b)*t + sp->c,0) &&
2737 !RealNear( 6*sp->a*t + 2*sp->b, 0));
2740 int Spline2DFindExtrema(const Spline *sp, extended extrema[4] ) {
2741 int i,j;
2742 BasePoint last, cur, mid;
2744 SplineFindExtrema(&sp->splines[0],&extrema[0],&extrema[1]);
2745 SplineFindExtrema(&sp->splines[1],&extrema[2],&extrema[3]);
2747 for ( i=0; i<3; ++i ) for ( j=i+1; j<4; ++j ) {
2748 if ( (extrema[i]==-1 && extrema[j]!=-1) || (extrema[i]>extrema[j] && extrema[j]!=-1) ) {
2749 extended temp = extrema[i];
2750 extrema[i] = extrema[j];
2751 extrema[j] = temp;
2754 for ( i=j=0; i<3 && extrema[i]!=-1; ++i ) {
2755 if ( extrema[i]==extrema[i+1] ) {
2756 for ( j=i+1; j<3; ++j )
2757 extrema[j] = extrema[j+1];
2758 extrema[3] = -1;
2762 /* Extrema which are too close together are not interesting */
2763 last = sp->from->me;
2764 for ( i=0; i<4 && extrema[i]!=-1; ++i ) {
2765 cur.x = ((sp->splines[0].a*extrema[i]+sp->splines[0].b)*extrema[i]+
2766 sp->splines[0].c)*extrema[i]+sp->splines[0].d;
2767 cur.y = ((sp->splines[1].a*extrema[i]+sp->splines[1].b)*extrema[i]+
2768 sp->splines[1].c)*extrema[i]+sp->splines[1].d;
2769 mid.x = (last.x+cur.x)/2; mid.y = (last.y+cur.y)/2;
2770 if ( (mid.x==last.x || mid.x==cur.x) &&
2771 (mid.y==last.y || mid.y==cur.y)) {
2772 for ( j=i+1; j<3; ++j )
2773 extrema[j] = extrema[j+1];
2774 } else
2775 last = cur;
2777 for ( i=0; i<4 && extrema[i]!=-1; ++i );
2778 if ( i!=0 ) {
2779 cur = sp->to->me;
2780 mid.x = (last.x+cur.x)/2; mid.y = (last.y+cur.y)/2;
2781 if ( (mid.x==last.x || mid.x==cur.x) &&
2782 (mid.y==last.y || mid.y==cur.y))
2783 extrema[--i] = -1;
2786 return( i );
2789 int Spline2DFindPointsOfInflection(const Spline *sp, extended poi[2] ) {
2790 int cnt=0;
2791 extended a, b, c, b2_fourac, t;
2792 /* A POI happens when d2 y/dx2 is zero. This is not the same as d2y/dt2 / d2x/dt2 */
2793 /* d2 y/dx^2 = d/dt ( dy/dt / dx/dt ) / dx/dt */
2794 /* = ( (dx/dt) * d2 y/dt2 - ((dy/dt) * d2 x/dt2) )/ (dx/dt)^3 */
2795 /* (3ax*t^2+2bx*t+cx) * (6ay*t+2by) - (3ay*t^2+2by*t+cy) * (6ax*t+2bx) == 0 */
2796 /* (3ax*t^2+2bx*t+cx) * (3ay*t+by) - (3ay*t^2+2by*t+cy) * (3ax*t+bx) == 0 */
2797 /* 9*ax*ay*t^3 + (3ax*by+6bx*ay)*t^2 + (2bx*by+3cx*ay)*t + cx*by */
2798 /* -(9*ax*ay*t^3 + (3ay*bx+6by*ax)*t^2 + (2by*bx+3cy*ax)*t + cy*bx)==0 */
2799 /* 3*(ax*by-ay*bx)*t^2 + 3*(cx*ay-cy*ax)*t+ (cx*by-cy*bx) == 0 */
2801 a = 3*((extended) sp->splines[1].a*sp->splines[0].b-(extended) sp->splines[0].a*sp->splines[1].b);
2802 b = 3*((extended) sp->splines[0].c*sp->splines[1].a - (extended) sp->splines[1].c*sp->splines[0].a);
2803 c = (extended) sp->splines[0].c*sp->splines[1].b-(extended) sp->splines[1].c*sp->splines[0].b;
2804 if ( !RealNear(a,0) ) {
2805 b2_fourac = b*b - 4*a*c;
2806 poi[0] = poi[1] = -1;
2807 if ( b2_fourac<0 )
2808 return( 0 );
2809 b2_fourac = esqrt( b2_fourac );
2810 t = (-b+b2_fourac)/(2*a);
2811 if ( t>=0 && t<=1.0 )
2812 poi[cnt++] = t;
2813 t = (-b-b2_fourac)/(2*a);
2814 if ( t>=0 && t<=1.0 ) {
2815 if ( cnt==1 && poi[0]>t ) {
2816 poi[1] = poi[0];
2817 poi[0] = t;
2818 ++cnt;
2819 } else
2820 poi[cnt++] = t;
2822 } else if ( !RealNear(b,0) ) {
2823 t = -c/b;
2824 if ( t>=0 && t<=1.0 )
2825 poi[cnt++] = t;
2827 if ( cnt<2 )
2828 poi[cnt] = -1;
2830 return( cnt );
2833 /* Ok, if the above routine finds an extremum that less than 1 unit */
2834 /* from an endpoint or another extremum, then many things are */
2835 /* just going to skip over it, and other things will be confused by this */
2836 /* so just remove it. It should be so close the difference won't matter */
2837 void SplineRemoveExtremaTooClose(Spline1D *sp, extended *_t1, extended *_t2 ) {
2838 extended last, test;
2839 extended t1= *_t1, t2 = *_t2;
2841 if ( t1>t2 && t2!=-1 ) {
2842 t1 = t2;
2843 t2 = *_t1;
2845 last = sp->d;
2846 if ( t1!=-1 ) {
2847 test = ((sp->a*t1+sp->b)*t1+sp->c)*t1+sp->d;
2848 if ( (test-last)*(test-last)<1 )
2849 t1 = -1;
2850 else
2851 last = test;
2853 if ( t2!=-1 ) {
2854 test = ((sp->a*t2+sp->b)*t2+sp->c)*t2+sp->d;
2855 if ( (test-last)*(test-last)<1 )
2856 t2 = -1;
2857 else
2858 last = test;
2860 test = sp->a+sp->b+sp->c+sp->d;
2861 if ( (test-last)*(test-last)<1 ) {
2862 if ( t2!=-1 )
2863 t2 = -1;
2864 else if ( t1!=-1 )
2865 t1 = -1;
2866 else {
2867 /* Well we should just remove the whole spline? */;
2870 *_t1 = t1; *_t2 = t2;
2873 int SplineSolveFull(const Spline1D *sp,extended val, extended ts[3]) {
2874 Spline1D temp;
2876 temp = *sp;
2877 temp.d -= val;
2878 CubicSolve(&temp,ts);
2879 return( ts[0]!=-1 );
2882 static int AddPoint(extended x,extended y,extended t,extended s,BasePoint *pts,
2883 extended t1s[3],extended t2s[3], int soln) {
2884 int i;
2886 for ( i=0; i<soln; ++i )
2887 if ( x==pts[i].x && y==pts[i].y )
2888 return( soln );
2889 if ( soln>=9 )
2890 IError( "Too many solutions!\n" );
2891 t1s[soln] = t;
2892 t2s[soln] = s;
2893 pts[soln].x = x;
2894 pts[soln].y = y;
2895 return( soln+1 );
2898 static void IterateSolve(const Spline1D *sp,extended ts[3]) {
2899 /* The closed form solution has too many rounding errors for my taste... */
2900 int i,j;
2902 ts[0] = ts[1] = ts[2] = -1;
2904 if ( sp->a!=0 ) {
2905 extended e[4];
2906 e[0] = 0; e[1] = e[2] = e[3] = 1.0;
2907 SplineFindExtrema(sp,&e[1],&e[2]);
2908 if ( e[1]==-1 ) e[1] = 1;
2909 if ( e[2]==-1 ) e[2] = 1;
2910 for ( i=j=0; i<3; ++i ) {
2911 ts[j] = IterateSplineSolve(sp,e[i],e[i+1],0,.0001);
2912 if ( ts[j]!=-1 ) ++j;
2913 if ( e[i+1]==1.0 )
2914 break;
2916 } else if ( sp->b!=0 ) {
2917 extended b2_4ac = sp->c*(extended) sp->c - 4*sp->b*(extended) sp->d;
2918 if ( b2_4ac>=0 ) {
2919 b2_4ac = esqrt(b2_4ac);
2920 ts[0] = (-sp->c-b2_4ac)/(2*sp->b);
2921 ts[1] = (-sp->c+b2_4ac)/(2*sp->b);
2922 if ( ts[0]>ts[1] ) { bigreal t = ts[0]; ts[0] = ts[1]; ts[1] = t; }
2924 } else if ( sp->c!=0 ) {
2925 ts[0] = -sp->d/(extended) sp->c;
2926 } else {
2927 /* No solutions, or all solutions */;
2929 for ( i=j=0; i<3; ++i )
2930 if ( ts[i]>=0 && ts[i]<=1 )
2931 ts[j++] = ts[i];
2932 for ( i=0; i<j-1; ++i )
2933 if ( ts[i]+.0000001>ts[i+1]) {
2934 ts[i] = (ts[i]+ts[i+1])/2;
2935 --j;
2936 for ( ++i; i<j; ++i )
2937 ts[i] = ts[i+1];
2939 if ( j!=0 ) {
2940 if ( ts[0]!=0 ) {
2941 extended d0 = sp->d;
2942 extended dt = ((sp->a*ts[0]+sp->b)*ts[0]+sp->c)*ts[0]+sp->d;
2943 if ( d0<0 ) d0=-d0;
2944 if ( dt<0 ) dt=-dt;
2945 if ( d0<dt )
2946 ts[0] = 0;
2948 if ( ts[j-1]!=1.0 ) {
2949 extended d1 = sp->a+(extended) sp->b+sp->c+sp->d;
2950 extended dt = ((sp->a*ts[j-1]+sp->b)*ts[j-1]+sp->c)*ts[j-1]+sp->d;
2951 if ( d1<0 ) d1=-d1;
2952 if ( dt<0 ) dt=-dt;
2953 if ( d1<dt )
2954 ts[j-1] = 1;
2957 for ( ; j<3; ++j )
2958 ts[j] = -1;
2961 static extended ISolveWithin(const Spline1D *sp,extended val,extended tlow, extended thigh) {
2962 Spline1D temp;
2963 extended ts[3];
2964 int i;
2966 temp = *sp;
2967 temp.d -= val;
2968 IterateSolve(&temp,ts);
2969 if ( tlow<thigh ) {
2970 for ( i=0; i<3; ++i )
2971 if ( ts[i]>=tlow && ts[i]<=thigh )
2972 return( ts[i] );
2973 for ( i=0; i<3; ++i ) {
2974 if ( ts[i]>=tlow-1./1024. && ts[i]<=tlow )
2975 return( tlow );
2976 if ( ts[i]>=thigh && ts[i]<=thigh+1./1024 )
2977 return( thigh );
2979 } else {
2980 for ( i=0; i<3; ++i )
2981 if ( ts[i]>=thigh && ts[i]<=tlow )
2982 return( ts[i] );
2983 for ( i=0; i<3; ++i ) {
2984 if ( ts[i]>=thigh-1./1024. && ts[i]<=thigh )
2985 return( thigh );
2986 if ( ts[i]>=tlow && ts[i]<=tlow+1./1024 )
2987 return( tlow );
2990 return( -1 );
2993 static int ICAddInter(int cnt,BasePoint *foundpos,extended *foundt1,extended *foundt2,
2994 const Spline *s1,const Spline *s2,extended t1,extended t2, int maxcnt) {
2995 (void)s2;
2996 if ( cnt>=maxcnt )
2997 return( cnt );
2999 foundt1[cnt] = t1;
3000 foundt2[cnt] = t2;
3001 foundpos[cnt].x = ((s1->splines[0].a*t1+s1->splines[0].b)*t1+
3002 s1->splines[0].c)*t1+s1->splines[0].d;
3003 foundpos[cnt].y = ((s1->splines[1].a*t1+s1->splines[1].b)*t1+
3004 s1->splines[1].c)*t1+s1->splines[1].d;
3005 return( cnt+1 );
3008 static int ICBinarySearch(int cnt,BasePoint *foundpos,extended *foundt1,extended *foundt2,
3009 int other,
3010 const Spline *s1,const Spline *s2,extended t1low,extended t1high,extended t2low,extended t2high,
3011 int maxcnt) {
3012 int major;
3013 extended t1, t2;
3014 extended o1o, o2o, o1n, o2n, m;
3016 major = !other;
3017 o1o = ((s1->splines[other].a*t1low+s1->splines[other].b)*t1low+
3018 s1->splines[other].c)*t1low+s1->splines[other].d;
3019 o2o = ((s2->splines[other].a*t2low+s2->splines[other].b)*t2low+
3020 s2->splines[other].c)*t2low+s2->splines[other].d;
3021 forever {
3022 t1 = (t1low+t1high)/2;
3023 m = ((s1->splines[major].a*t1+s1->splines[major].b)*t1+
3024 s1->splines[major].c)*t1+s1->splines[major].d;
3025 t2 = ISolveWithin(&s2->splines[major],m,t2low,t2high);
3026 if ( t2==-1 )
3027 return( cnt );
3029 o1n = ((s1->splines[other].a*t1+s1->splines[other].b)*t1+
3030 s1->splines[other].c)*t1+s1->splines[other].d;
3031 o2n = ((s2->splines[other].a*t2+s2->splines[other].b)*t2+
3032 s2->splines[other].c)*t2+s2->splines[other].d;
3033 if (( o1n-o2n<.001 && o1n-o2n>-.001) ||
3034 (t1-t1low<.0001 && t1-t1low>-.0001))
3035 return( ICAddInter(cnt,foundpos,foundt1,foundt2,s1,s2,t1,t2,maxcnt));
3036 if ( (o1o>o2o && o1n<o2n) || (o1o<o2o && o1n>o2n)) {
3037 t1high = t1;
3038 t2high = t2;
3039 } else {
3040 t1low = t1;
3041 t2low = t2;
3046 static int CubicsIntersect(const Spline *s1,extended lowt1,extended hight1,BasePoint *min1,BasePoint *max1,
3047 const Spline *s2,extended lowt2,extended hight2,BasePoint *min2,BasePoint *max2,
3048 BasePoint *foundpos,extended *foundt1,extended *foundt2,
3049 int maxcnt) {
3050 int major, other;
3051 BasePoint max, min;
3052 extended t1max, t1min, t2max, t2min, t1, t2, t1diff, oldt2;
3053 extended o1o, o2o, o1n, o2n, m;
3054 int cnt=0;
3056 if ( (min.x = min1->x)<min2->x ) min.x = min2->x;
3057 if ( (min.y = min1->y)<min2->y ) min.y = min2->y;
3058 if ( (max.x = max1->x)>max2->x ) max.x = max2->x;
3059 if ( (max.y = max1->y)>max2->y ) max.y = max2->y;
3060 if ( max.x<min.x || max.y<min.y )
3061 return( 0 );
3062 if ( max.x-min.x > max.y-min.y )
3063 major = 0;
3064 else
3065 major = 1;
3066 other = 1-major;
3068 t1max = ISolveWithin(&s1->splines[major],(&max.x)[major],lowt1,hight1);
3069 t1min = ISolveWithin(&s1->splines[major],(&min.x)[major],lowt1,hight1);
3070 t2max = ISolveWithin(&s2->splines[major],(&max.x)[major],lowt2,hight2);
3071 t2min = ISolveWithin(&s2->splines[major],(&min.x)[major],lowt2,hight2);
3072 if ( t1max==-1 || t1min==-1 || t2max==-1 || t1min==-1 )
3073 return( 0 );
3074 t1diff = (t1max-t1min)/64.0;
3075 if ( t1diff==0 )
3076 return( 0 );
3078 t1 = t1min; t2 = t2min;
3079 o1o = ((s1->splines[other].a*t1+s1->splines[other].b)*t1+
3080 s1->splines[other].c)*t1+s1->splines[other].d;
3081 o2o = ((s2->splines[other].a*t2+s2->splines[other].b)*t2+
3082 s2->splines[other].c)*t2+s2->splines[other].d;
3083 if ( o1o==o2o )
3084 cnt = ICAddInter(cnt,foundpos,foundt1,foundt2,s1,s2,t1,t2,maxcnt);
3085 forever {
3086 if ( cnt>=maxcnt )
3087 break;
3088 t1 += t1diff;
3089 if (( t1max>t1min && t1>t1max ) || (t1max<t1min && t1<t1max) || cnt>3 )
3090 break;
3091 m = ((s1->splines[major].a*t1+s1->splines[major].b)*t1+
3092 s1->splines[major].c)*t1+s1->splines[major].d;
3093 oldt2 = t2;
3094 t2 = ISolveWithin(&s2->splines[major],m,lowt2,hight2);
3095 if ( t2==-1 )
3096 continue;
3098 o1n = ((s1->splines[other].a*t1+s1->splines[other].b)*t1+
3099 s1->splines[other].c)*t1+s1->splines[other].d;
3100 o2n = ((s2->splines[other].a*t2+s2->splines[other].b)*t2+
3101 s2->splines[other].c)*t2+s2->splines[other].d;
3102 if ( o1n==o2n )
3103 cnt = ICAddInter(cnt,foundpos,foundt1,foundt2,s1,s2,t1,t2,maxcnt);
3104 if ( (o1o>o2o && o1n<o2n) || (o1o<o2o && o1n>o2n))
3105 cnt = ICBinarySearch(cnt,foundpos,foundt1,foundt2,other,
3106 s1,s2,t1-t1diff,t1,oldt2,t2,maxcnt);
3107 o1o = o1n; o2o = o2n;
3109 return( cnt );
3112 static int Closer(const Spline *s1,const Spline *s2,extended t1,extended t2,extended t1p,extended t2p) {
3113 double x1 = ((s1->splines[0].a*t1+s1->splines[0].b)*t1+s1->splines[0].c)*t1+s1->splines[0].c;
3114 double y1 = ((s1->splines[1].a*t1+s1->splines[1].b)*t1+s1->splines[1].c)*t1+s1->splines[1].c;
3115 double x2 = ((s2->splines[0].a*t2+s2->splines[0].b)*t2+s2->splines[0].c)*t2+s2->splines[0].c;
3116 double y2 = ((s2->splines[1].a*t2+s2->splines[1].b)*t2+s2->splines[1].c)*t2+s2->splines[1].c;
3117 double diff = abs(x1-x2) + abs(y1-y2);
3118 double x1p = ((s1->splines[0].a*t1p+s1->splines[0].b)*t1p+s1->splines[0].c)*t1p+s1->splines[0].c;
3119 double y1p = ((s1->splines[1].a*t1p+s1->splines[1].b)*t1p+s1->splines[1].c)*t1p+s1->splines[1].c;
3120 double x2p = ((s2->splines[0].a*t2p+s2->splines[0].b)*t2p+s2->splines[0].c)*t2p+s2->splines[0].c;
3121 double y2p = ((s2->splines[1].a*t2p+s2->splines[1].b)*t2p+s2->splines[1].c)*t2p+s2->splines[1].c;
3122 double diffp = abs(x1p-x2p) + abs(y1p-y2p);
3124 if ( diff<diffp )
3125 return( false );
3127 return( true );
3130 /* returns 0=>no intersection, 1=>at least one, location in pts, t1s, t2s */
3131 /* -1 => We couldn't figure it out in a closed form, have to do a numerical */
3132 /* approximation */
3133 int SplinesIntersect(const Spline *s1, const Spline *s2, BasePoint pts[9],
3134 extended t1s[10], extended t2s[10]) { /* One extra for a trailing -1 */
3135 BasePoint min1, max1, min2, max2;
3136 int soln = 0;
3137 extended x,y,t, ac0, ac1;
3138 int i,j,found;
3139 Spline1D spline;
3140 extended tempts[4]; /* 3 solns for cubics, 4 for quartics */
3141 extended extrema1[6], extrema2[6];
3142 int ecnt1, ecnt2;
3144 t1s[0] = t1s[1] = t1s[2] = t1s[3] = -1;
3145 t2s[0] = t2s[1] = t2s[2] = t2s[3] = -1;
3147 if ( s1==s2 && !s1->knownlinear && !s1->isquadratic )
3148 /* Special case see if it doubles back on itself anywhere */;
3149 else if ( s1==s2 )
3150 return( 0 ); /* Linear and quadratics can't double back, can't self-intersect */
3151 else if ( s1->splines[0].a == s2->splines[0].a &&
3152 s1->splines[0].b == s2->splines[0].b &&
3153 s1->splines[0].c == s2->splines[0].c &&
3154 s1->splines[0].d == s2->splines[0].d &&
3155 s1->splines[1].a == s2->splines[1].a &&
3156 s1->splines[1].b == s2->splines[1].b &&
3157 s1->splines[1].c == s2->splines[1].c &&
3158 s1->splines[1].d == s2->splines[1].d )
3159 return( -1 ); /* Same spline. Intersects everywhere */
3161 /* Ignore splines which are just a point */
3162 if ( s1->knownlinear && s1->splines[0].c==0 && s1->splines[1].c==0 )
3163 return( 0 );
3164 if ( s2->knownlinear && s2->splines[0].c==0 && s2->splines[1].c==0 )
3165 return( 0 );
3167 if ( s1->knownlinear )
3168 /* Do Nothing */;
3169 else if ( s2->knownlinear || (!s1->isquadratic && s2->isquadratic)) {
3170 const Spline *stemp = s1;
3171 extended *ts = t1s;
3172 t1s = t2s; t2s = ts;
3173 s1 = s2; s2 = stemp;
3176 min1 = s1->from->me; max1 = min1;
3177 min2 = s2->from->me; max2 = min2;
3178 if ( s1->from->nextcp.x>max1.x ) max1.x = s1->from->nextcp.x;
3179 else if ( s1->from->nextcp.x<min1.x ) min1.x = s1->from->nextcp.x;
3180 if ( s1->from->nextcp.y>max1.y ) max1.y = s1->from->nextcp.y;
3181 else if ( s1->from->nextcp.y<min1.y ) min1.y = s1->from->nextcp.y;
3182 if ( s1->to->prevcp.x>max1.x ) max1.x = s1->to->prevcp.x;
3183 else if ( s1->to->prevcp.x<min1.x ) min1.x = s1->to->prevcp.x;
3184 if ( s1->to->prevcp.y>max1.y ) max1.y = s1->to->prevcp.y;
3185 else if ( s1->to->prevcp.y<min1.y ) min1.y = s1->to->prevcp.y;
3186 if ( s1->to->me.x>max1.x ) max1.x = s1->to->me.x;
3187 else if ( s1->to->me.x<min1.x ) min1.x = s1->to->me.x;
3188 if ( s1->to->me.y>max1.y ) max1.y = s1->to->me.y;
3189 else if ( s1->to->me.y<min1.y ) min1.y = s1->to->me.y;
3191 if ( s2->from->nextcp.x>max2.x ) max2.x = s2->from->nextcp.x;
3192 else if ( s2->from->nextcp.x<min2.x ) min2.x = s2->from->nextcp.x;
3193 if ( s2->from->nextcp.y>max2.y ) max2.y = s2->from->nextcp.y;
3194 else if ( s2->from->nextcp.y<min2.y ) min2.y = s2->from->nextcp.y;
3195 if ( s2->to->prevcp.x>max2.x ) max2.x = s2->to->prevcp.x;
3196 else if ( s2->to->prevcp.x<min2.x ) min2.x = s2->to->prevcp.x;
3197 if ( s2->to->prevcp.y>max2.y ) max2.y = s2->to->prevcp.y;
3198 else if ( s2->to->prevcp.y<min2.y ) min2.y = s2->to->prevcp.y;
3199 if ( s2->to->me.x>max2.x ) max2.x = s2->to->me.x;
3200 else if ( s2->to->me.x<min2.x ) min2.x = s2->to->me.x;
3201 if ( s2->to->me.y>max2.y ) max2.y = s2->to->me.y;
3202 else if ( s2->to->me.y<min2.y ) min2.y = s2->to->me.y;
3203 if ( min1.x>max2.x || min2.x>max1.x || min1.y>max2.y || min2.y>max1.y )
3204 return( false ); /* no intersection of bounding boxes */
3206 #if 0
3207 soln = CheckEndpoint(&s1->from->me,s2,0,pts,t1s,t2s,soln);
3208 soln = CheckEndpoint(&s1->to->me,s2,1,pts,t1s,t2s,soln);
3209 soln = CheckEndpoint(&s2->from->me,s1,0,pts,t2s,t1s,soln);
3210 soln = CheckEndpoint(&s2->to->me,s1,1,pts,t2s,t1s,soln);
3211 #endif
3213 if ( s1->knownlinear ) {
3214 spline.d = s1->splines[1].c*((bigreal) s2->splines[0].d-(bigreal) s1->splines[0].d)-
3215 s1->splines[0].c*((bigreal) s2->splines[1].d-(bigreal) s1->splines[1].d);
3216 spline.c = s1->splines[1].c*(bigreal) s2->splines[0].c - s1->splines[0].c*(bigreal) s2->splines[1].c;
3217 spline.b = s1->splines[1].c*(bigreal) s2->splines[0].b - s1->splines[0].c*(bigreal) s2->splines[1].b;
3218 spline.a = s1->splines[1].c*(bigreal) s2->splines[0].a - s1->splines[0].c*(bigreal) s2->splines[1].a;
3219 IterateSolve(&spline,tempts);
3220 if ( tempts[0]==-1 )
3221 return( false );
3222 for ( i = 0; i<3 && tempts[i]!=-1; ++i ) {
3223 x = ((s2->splines[0].a*tempts[i]+s2->splines[0].b)*tempts[i]+
3224 s2->splines[0].c)*tempts[i]+s2->splines[0].d;
3225 y = ((s2->splines[1].a*tempts[i]+s2->splines[1].b)*tempts[i]+
3226 s2->splines[1].c)*tempts[i]+s2->splines[1].d;
3227 if ( (ac0 = s1->splines[0].c)<0 ) ac0 = -ac0;
3228 if ( (ac1 = s1->splines[1].c)<0 ) ac1 = -ac1;
3229 if ( ac0>ac1 )
3230 t = (x-s1->splines[0].d)/s1->splines[0].c;
3231 else
3232 t = (y-s1->splines[1].d)/s1->splines[1].c;
3233 if ( tempts[i]>.999 && Closer(s1,s2,tempts[i],t,1,t))
3234 tempts[i] = 1;
3235 else if ( tempts[i]<.001 && Closer(s1,s2,tempts[i],t,0,t))
3236 tempts[i] = 0;
3237 if ( t>.999 && Closer(s1,s2,tempts[i],t,tempts[i],1))
3238 t = 1;
3239 else if ( t<.001 && Closer(s1,s2,tempts[i],t,tempts[i],0))
3240 t = 0;
3241 if ( t<-.001 || t>1.001 || x<min1.x-.01 || y<min1.y-.01 || x>max1.x+.01 || y>max1.y+.01 )
3242 continue;
3243 if ( t<=0 ) {t=0; x=s1->from->me.x; y = s1->from->me.y; }
3244 else if ( t>=1 ) { t=1; x=s1->to->me.x; y = s1->to->me.y; }
3245 if ( s1->from->me.x==s1->to->me.x ) /* Avoid rounding errors */
3246 x = s1->from->me.x; /* on hor/vert lines */
3247 else if ( s1->from->me.y==s1->to->me.y )
3248 y = s1->from->me.y;
3249 if ( s2->knownlinear ) {
3250 if ( s2->from->me.x==s2->to->me.x )
3251 x = s2->from->me.x;
3252 else if ( s2->from->me.y==s2->to->me.y )
3253 y = s2->from->me.y;
3255 soln = AddPoint(x,y,t,tempts[i],pts,t1s,t2s,soln);
3257 return( soln!=0 );
3258 #if 0 /* This doesn't work. */
3259 } else if ( s1->isquadratic && s2->isquadratic ) {
3260 temp.a = 0;
3261 temp.b = s1->splines[1].b*s2->splines[0].b - s1->splines[0].b*s2->splines[1].b;
3262 temp.c = s1->splines[1].b*s2->splines[0].c - s1->splines[0].b*s2->splines[1].c;
3263 temp.d = s1->splines[1].b*(s2->splines[0].d-s1->splines[0].d) -
3264 s1->splines[0].b*(s2->splines[1].d-s1->splines[1].d);
3265 d = s1->splines[1].b*s1->splines[0].c - s1->splines[0].b*s1->splines[1].c;
3266 if ( RealNear(d,0)) d=0;
3267 if ( d!=0 ) {
3268 temp.b /= d; temp.c /= d; temp.d /= d;
3269 /* At this point t= temp.b*s^2 + temp.c*s + temp.d */
3270 /* We substitute this back into one of our equations and get a */
3271 /* quartic in s */
3272 quad.a = s1->splines[0].b*temp.b*temp.b;
3273 quad.b = s1->splines[0].b*2*temp.b*temp.c;
3274 quad.c = s1->splines[0].b*(2*temp.b*temp.d+temp.c*temp.c);
3275 quad.d = s1->splines[0].b*2*temp.d*temp.c;
3276 quad.e = s1->splines[0].b*temp.d*temp.d;
3277 quad.b+= s1->splines[0].c*temp.b;
3278 quad.c+= s1->splines[0].c*temp.c;
3279 quad.d+= s1->splines[0].c*temp.d;
3280 quad.e+= s1->splines[0].d;
3281 quad.e-= s2->splines[0].d;
3282 quad.d-= s2->splines[0].c;
3283 quad.c-= s2->splines[0].b;
3284 if ( QuarticSolve(&quad,tempts)==-1 )
3285 return( -1 );
3286 for ( i=0; i<4 && tempts[i]!=-999999; ++i )
3287 soln = AddQuadraticSoln(tempts[i],s1,s2,pts,t1s,t2s,soln);
3288 } else {
3289 d = temp.c*temp.c-4*temp.b*temp.c;
3290 if ( RealNear(d,0)) d = 0;
3291 if ( d<0 )
3292 return( soln!=0 );
3293 d = sqrt(d);
3294 s = (-temp.c-d)/(2*temp.b);
3295 soln = AddQuadraticSoln(s,s1,s2,pts,t1s,t2s,soln);
3296 s = (-temp.c+d)/(2*temp.b);
3297 soln = AddQuadraticSoln(s,s1,s2,pts,t1s,t2s,soln);
3299 return( soln!=0 );
3300 #endif
3302 /* if one of the splines is quadratic then we can get an expression */
3303 /* relating c*t+d to poly(s^3), and substituting this back we get */
3304 /* a poly of degree 6 in s which could be solved iteratively */
3305 /* however mixed quadratics and cubics are unlikely */
3307 /* but if both splines are degree 3, the t is expressed as the sqrt of */
3308 /* a third degree poly, which must be substituted into a cubic, and */
3309 /* then squared to get rid of the sqrts leaving us with an ?18? degree */
3310 /* poly. Ick. */
3312 /* So let's do it the hard way... we break the splines into little bits */
3313 /* where they are monotonic in both dimensions, then check these for */
3314 /* possible intersections */
3315 extrema1[0] = extrema2[0] = 0;
3316 ecnt1 = Spline2DFindExtrema(s1,extrema1+1);
3317 ecnt2 = Spline2DFindExtrema(s2,extrema2+1);
3318 extrema1[++ecnt1] = 1.0;
3319 extrema2[++ecnt2] = 1.0;
3320 found=0;
3321 for ( i=0; i<ecnt1; ++i ) {
3322 min1.x = ((s1->splines[0].a*extrema1[i]+s1->splines[0].b)*extrema1[i]+
3323 s1->splines[0].c)*extrema1[i]+s1->splines[0].d;
3324 min1.y = ((s1->splines[1].a*extrema1[i]+s1->splines[1].b)*extrema1[i]+
3325 s1->splines[1].c)*extrema1[i]+s1->splines[1].d;
3326 max1.x = ((s1->splines[0].a*extrema1[i+1]+s1->splines[0].b)*extrema1[i+1]+
3327 s1->splines[0].c)*extrema1[i+1]+s1->splines[0].d;
3328 max1.y = ((s1->splines[1].a*extrema1[i+1]+s1->splines[1].b)*extrema1[i+1]+
3329 s1->splines[1].c)*extrema1[i+1]+s1->splines[1].d;
3330 if ( max1.x<min1.x ) { extended temp = max1.x; max1.x = min1.x; min1.x = temp; }
3331 if ( max1.y<min1.y ) { extended temp = max1.y; max1.y = min1.y; min1.y = temp; }
3332 for ( j=(s1==s2)?i+1:0; j<ecnt2; ++j ) {
3333 min2.x = ((s2->splines[0].a*extrema2[j]+s2->splines[0].b)*extrema2[j]+
3334 s2->splines[0].c)*extrema2[j]+s2->splines[0].d;
3335 min2.y = ((s2->splines[1].a*extrema2[j]+s2->splines[1].b)*extrema2[j]+
3336 s2->splines[1].c)*extrema2[j]+s2->splines[1].d;
3337 max2.x = ((s2->splines[0].a*extrema2[j+1]+s2->splines[0].b)*extrema2[j+1]+
3338 s2->splines[0].c)*extrema2[j+1]+s2->splines[0].d;
3339 max2.y = ((s2->splines[1].a*extrema2[j+1]+s2->splines[1].b)*extrema2[j+1]+
3340 s2->splines[1].c)*extrema2[j+1]+s2->splines[1].d;
3341 if ( max2.x<min2.x ) { extended temp = max2.x; max2.x = min2.x; min2.x = temp; }
3342 if ( max2.y<min2.y ) { extended temp = max2.y; max2.y = min2.y; min2.y = temp; }
3343 if ( min1.x>max2.x || min2.x>max1.x || min1.y>max2.y || min2.y>max1.y )
3344 /* No possible intersection */;
3345 else if ( s1!=s2 )
3346 found += CubicsIntersect(s1,extrema1[i],extrema1[i+1],&min1,&max1,
3347 s2,extrema2[j],extrema2[j+1],&min2,&max2,
3348 &pts[found],&t1s[found],&t2s[found],9-found);
3349 else {
3350 int k,l;
3351 int cnt = CubicsIntersect(s1,extrema1[i],extrema1[i+1],&min1,&max1,
3352 s2,extrema2[j],extrema2[j+1],&min2,&max2,
3353 &pts[found],&t1s[found],&t2s[found],9-found);
3354 for ( k=0; k<cnt; ++k ) {
3355 if ( RealNear(t1s[found+k],t2s[found+k]) ) {
3356 for ( l=k+1; l<cnt; ++l ) {
3357 pts[found+l-1] = pts[found+l];
3358 t1s[found+l-1] = t1s[found+l];
3359 t2s[found+l-1] = t2s[found+l];
3361 --cnt; --k;
3364 found += cnt;
3366 if ( found>=8 ) {
3367 /* If the splines are colinear then we might get an unbounded */
3368 /* number of intersections */
3369 break;
3373 t1s[found] = t2s[found] = -1;
3374 return( found!=0 );
3377 int SplineSetIntersect(SplineSet *spl, Spline **_spline, Spline **_spline2) {
3378 BasePoint pts[9];
3379 extended t1s[10], t2s[10];
3380 int found = false,i;
3381 SplineSet *test, *test2;
3382 Spline *spline, *spline2, *first, *first2;
3384 for ( test=spl; test!=NULL ; test=test->next ) {
3385 first = NULL;
3386 for ( spline = test->first->next; spline!=NULL && spline!=first; spline=spline->to->next ) {
3387 if ( first==NULL ) first = spline;
3388 for ( test2=test; test2!=NULL; test2=test2->next ) {
3389 first2 = test2==test && first!=spline ? first : NULL;
3390 for ( spline2=(test2==test)?spline : test2->first->next;
3391 spline2!=NULL && spline2!=first2; spline2 = spline2->to->next ) {
3392 if ( first2==NULL ) first2 = spline2;
3393 if ( SplinesIntersect(spline,spline2,pts,t1s,t2s)) {
3394 if ( spline->to->next!=spline2 && spline->from->prev!=spline2 )
3395 found = true;
3396 else for ( i=0; i<10 && t1s[i]!=-1; ++i ) {
3397 if ( (t1s[i]<.9 && t1s[i]>.1) || (t2s[i]<.9 && t2s[i]>.1)) {
3398 found = true;
3399 break;
3402 if ( found )
3403 break;
3406 if ( found )
3407 break;
3409 if ( found )
3410 break;
3412 if ( found )
3413 break;
3415 if ( found ) {
3416 *_spline = spline;
3417 *_spline2 = spline2;
3419 return( found );
3422 void StemInfoFree(StemInfo *h) {
3423 HintInstance *hi, *n;
3425 for ( hi=h->where; hi!=NULL; hi=n ) {
3426 n = hi->next;
3427 chunkfree(hi,sizeof(HintInstance));
3429 chunkfree(h,sizeof(StemInfo));
3432 void StemInfosFree(StemInfo *h) {
3433 StemInfo *hnext;
3434 HintInstance *hi, *n;
3436 for ( ; h!=NULL; h = hnext ) {
3437 for ( hi=h->where; hi!=NULL; hi=n ) {
3438 n = hi->next;
3439 chunkfree(hi,sizeof(HintInstance));
3441 hnext = h->next;
3442 chunkfree(h,sizeof(StemInfo));
3446 void DStemInfoFree(DStemInfo *h) {
3447 HintInstance *hi, *n;
3449 for ( hi=h->where; hi!=NULL; hi=n ) {
3450 n = hi->next;
3451 chunkfree(hi,sizeof(HintInstance));
3453 chunkfree(h,sizeof(DStemInfo));
3456 void DStemInfosFree(DStemInfo *h) {
3457 DStemInfo *hnext;
3458 HintInstance *hi, *n;
3460 for ( ; h!=NULL; h = hnext ) {
3461 for ( hi=h->where; hi!=NULL; hi=n ) {
3462 n = hi->next;
3463 chunkfree(hi,sizeof(HintInstance));
3465 hnext = h->next;
3466 chunkfree(h,sizeof(DStemInfo));
3470 StemInfo *StemInfoCopy(StemInfo *h) {
3471 StemInfo *head=NULL, *last=NULL, *cur;
3472 HintInstance *hilast, *hicur, *hi;
3474 for ( ; h!=NULL; h = h->next ) {
3475 cur = chunkalloc(sizeof(StemInfo));
3476 *cur = *h;
3477 cur->next = NULL;
3478 if ( head==NULL )
3479 head = last = cur;
3480 else {
3481 last->next = cur;
3482 last = cur;
3484 cur->where = hilast = NULL;
3485 for ( hi=h->where; hi!=NULL; hi=hi->next ) {
3486 hicur = chunkalloc(sizeof(StemInfo));
3487 *hicur = *hi;
3488 hicur->next = NULL;
3489 if ( hilast==NULL )
3490 cur->where = hilast = hicur;
3491 else {
3492 hilast->next = hicur;
3493 hilast = hicur;
3497 return( head );
3500 DStemInfo *DStemInfoCopy(DStemInfo *h) {
3501 DStemInfo *head=NULL, *last=NULL, *cur;
3502 HintInstance *hilast, *hicur, *hi;
3504 for ( ; h!=NULL; h = h->next ) {
3505 cur = chunkalloc(sizeof(DStemInfo));
3506 *cur = *h;
3507 cur->next = NULL;
3508 if ( head==NULL )
3509 head = last = cur;
3510 else {
3511 last->next = cur;
3512 last = cur;
3514 cur->where = hilast = NULL;
3515 for ( hi=h->where; hi!=NULL; hi=hi->next ) {
3516 hicur = chunkalloc(sizeof(StemInfo));
3517 *hicur = *hi;
3518 hicur->next = NULL;
3519 if ( hilast==NULL )
3520 cur->where = hilast = hicur;
3521 else {
3522 hilast->next = hicur;
3523 hilast = hicur;
3527 return( head );
3530 MinimumDistance *MinimumDistanceCopy(MinimumDistance *md) {
3531 MinimumDistance *head=NULL, *last=NULL, *cur;
3533 for ( ; md!=NULL; md = md->next ) {
3534 cur = chunkalloc(sizeof(DStemInfo));
3535 *cur = *md;
3536 cur->next = NULL;
3537 if ( head==NULL )
3538 head = last = cur;
3539 else {
3540 last->next = cur;
3541 last = cur;
3544 return( head );
3547 void KernPairsFree(KernPair *kp) {
3548 KernPair *knext;
3549 for ( ; kp!=NULL; kp = knext ) {
3550 knext = kp->next;
3551 chunkfree(kp,sizeof(KernPair));
3555 static AnchorPoint *AnchorPointsRemoveName(AnchorPoint *alist,AnchorClass *an) {
3556 AnchorPoint *prev=NULL, *ap, *next;
3558 for ( ap=alist; ap!=NULL; ap=next ) {
3559 next = ap->next;
3560 if ( ap->anchor == an ) {
3561 if ( prev==NULL )
3562 alist = next;
3563 else
3564 prev->next = next;
3565 ap->next = NULL;
3566 AnchorPointsFree(ap);
3567 if ( an->type == act_mark || (an->type==act_mklg && ap->type==at_mark))
3568 next = NULL; /* Only one instance of an anchor class in a glyph for mark to base anchors */
3569 /* Or for the mark glyphs of ligature classes */
3570 /* Mark to mark & cursive will (probably) have 2 occurances */
3571 /* and ligatures may have lots */
3572 } else
3573 prev = ap;
3575 return( alist );
3578 static void SCRemoveAnchorClass(SplineChar *sc,AnchorClass *an) {
3579 Undoes *test;
3581 if ( sc==NULL )
3582 return;
3583 sc->anchor = AnchorPointsRemoveName(sc->anchor,an);
3584 for ( test = sc->layers[ly_fore].undoes; test!=NULL; test=test->next )
3585 if ( test->undotype==ut_state || test->undotype==ut_tstate ||
3586 test->undotype==ut_statehint || test->undotype==ut_statename )
3587 test->u.state.anchor = AnchorPointsRemoveName(test->u.state.anchor,an);
3588 for ( test = sc->layers[ly_fore].redoes; test!=NULL; test=test->next )
3589 if ( test->undotype==ut_state || test->undotype==ut_tstate ||
3590 test->undotype==ut_statehint || test->undotype==ut_statename )
3591 test->u.state.anchor = AnchorPointsRemoveName(test->u.state.anchor,an);
3594 void SFRemoveAnchorClass(SplineFont *sf,AnchorClass *an) {
3595 int i;
3596 AnchorClass *prev, *test;
3598 for ( i=0; i<sf->glyphcnt; ++i )
3599 SCRemoveAnchorClass(sf->glyphs[i],an);
3600 prev = NULL;
3601 for ( test=sf->anchor; test!=NULL; test=test->next ) {
3602 if ( test==an ) {
3603 if ( prev==NULL )
3604 sf->anchor = test->next;
3605 else
3606 prev->next = test->next;
3607 chunkfree(test,sizeof(AnchorClass));
3608 break;
3609 } else
3610 prev = test;
3614 AnchorPoint *APAnchorClassMerge(AnchorPoint *anchors,AnchorClass *into,AnchorClass *from) {
3615 AnchorPoint *api=NULL, *prev, *ap, *next;
3617 prev = NULL;
3618 for ( ap=anchors; ap!=NULL; ap=next ) {
3619 next = ap->next;
3620 if ( ap->anchor==from ) {
3621 for ( api=anchors; api!=NULL; api=api->next ) {
3622 if ( api->anchor==into &&
3623 (api->type!=at_baselig || ap->type!=at_baselig || api->lig_index==ap->lig_index))
3624 break;
3626 if ( api==NULL && into!=NULL ) {
3627 ap->anchor = into;
3628 prev = ap;
3629 } else {
3630 if ( prev==NULL )
3631 anchors = next;
3632 else
3633 prev->next = next;
3634 ap->next = NULL;
3635 AnchorPointsFree(ap);
3637 } else
3638 prev = ap;
3640 return( anchors );
3643 AnchorPoint *AnchorPointsCopy(AnchorPoint *alist) {
3644 AnchorPoint *head=NULL, *last=NULL, *ap;
3646 while ( alist!=NULL ) {
3647 ap = chunkalloc(sizeof(AnchorPoint));
3648 *ap = *alist;
3649 if ( head==NULL )
3650 head = ap;
3651 else
3652 last->next = ap;
3653 last = ap;
3654 alist = alist->next;
3656 return( head );
3659 void AnchorPointsFree(AnchorPoint *ap) {
3660 AnchorPoint *anext;
3661 for ( ; ap!=NULL; ap = anext ) {
3662 anext = ap->next;
3663 chunkfree(ap,sizeof(AnchorPoint));
3668 void PSTFree(PST *pst) {
3669 PST *pnext;
3670 for ( ; pst!=NULL; pst = pnext ) {
3671 pnext = pst->next;
3672 if ( pst->type==pst_lcaret )
3673 free(pst->u.lcaret.carets);
3674 else if ( pst->type==pst_pair ) {
3675 free(pst->u.pair.paired);
3676 chunkfree(pst->u.pair.vr,sizeof(struct vr [2]));
3677 } else if ( pst->type!=pst_position ) {
3678 free(pst->u.subs.variant);
3679 } else if ( pst->type==pst_position ) {
3681 chunkfree(pst,sizeof(PST));
3685 void FPSTRuleContentsFree(struct fpst_rule *r, enum fpossub_format format) {
3686 int j;
3688 switch ( format ) {
3689 case pst_glyphs:
3690 free(r->u.glyph.names);
3691 free(r->u.glyph.back);
3692 free(r->u.glyph.fore);
3693 break;
3694 case pst_class:
3695 free(r->u.class.nclasses);
3696 free(r->u.class.bclasses);
3697 free(r->u.class.fclasses);
3698 break;
3699 case pst_reversecoverage:
3700 free(r->u.rcoverage.replacements);
3701 case pst_coverage:
3702 for ( j=0 ; j<r->u.coverage.ncnt ; ++j )
3703 free(r->u.coverage.ncovers[j]);
3704 free(r->u.coverage.ncovers);
3705 for ( j=0 ; j<r->u.coverage.bcnt ; ++j )
3706 free(r->u.coverage.bcovers[j]);
3707 free(r->u.coverage.bcovers);
3708 for ( j=0 ; j<r->u.coverage.fcnt ; ++j )
3709 free(r->u.coverage.fcovers[j]);
3710 free(r->u.coverage.fcovers);
3711 break;
3712 default:
3713 break;
3715 free(r->lookups);
3718 void FPSTRulesFree(struct fpst_rule *r, enum fpossub_format format, int rcnt) {
3719 int i;
3720 for ( i=0; i<rcnt; ++i )
3721 FPSTRuleContentsFree(&r[i],format);
3722 free(r);
3725 static struct fpst_rule *RulesCopy(struct fpst_rule *from, int cnt,
3726 enum fpossub_format format ) {
3727 int i, j;
3728 struct fpst_rule *to, *f, *t;
3730 if ( cnt==0 )
3731 return( NULL );
3733 to = gcalloc(cnt,sizeof(struct fpst_rule));
3734 for ( i=0; i<cnt; ++i ) {
3735 f = from+i; t = to+i;
3736 switch ( format ) {
3737 case pst_glyphs:
3738 t->u.glyph.names = copy(f->u.glyph.names);
3739 t->u.glyph.back = copy(f->u.glyph.back);
3740 t->u.glyph.fore = copy(f->u.glyph.fore);
3741 break;
3742 case pst_class:
3743 t->u.class.ncnt = f->u.class.ncnt;
3744 t->u.class.bcnt = f->u.class.bcnt;
3745 t->u.class.fcnt = f->u.class.fcnt;
3746 t->u.class.nclasses = galloc( f->u.class.ncnt*sizeof(uint16));
3747 memcpy(t->u.class.nclasses,f->u.class.nclasses,
3748 f->u.class.ncnt*sizeof(uint16));
3749 if ( t->u.class.bcnt!=0 ) {
3750 t->u.class.bclasses = galloc( f->u.class.bcnt*sizeof(uint16));
3751 memcpy(t->u.class.bclasses,f->u.class.bclasses,
3752 f->u.class.bcnt*sizeof(uint16));
3754 if ( t->u.class.fcnt!=0 ) {
3755 t->u.class.fclasses = galloc( f->u.class.fcnt*sizeof(uint16));
3756 memcpy(t->u.class.fclasses,f->u.class.fclasses,
3757 f->u.class.fcnt*sizeof(uint16));
3759 break;
3760 case pst_reversecoverage:
3761 t->u.rcoverage.replacements = copy(f->u.rcoverage.replacements);
3762 case pst_coverage:
3763 t->u.coverage.ncnt = f->u.coverage.ncnt;
3764 t->u.coverage.bcnt = f->u.coverage.bcnt;
3765 t->u.coverage.fcnt = f->u.coverage.fcnt;
3766 t->u.coverage.ncovers = galloc( f->u.coverage.ncnt*sizeof(char *));
3767 for ( j=0; j<t->u.coverage.ncnt; ++j )
3768 t->u.coverage.ncovers[j] = copy(f->u.coverage.ncovers[j]);
3769 if ( t->u.coverage.bcnt!=0 ) {
3770 t->u.coverage.bcovers = galloc( f->u.coverage.bcnt*sizeof(char *));
3771 for ( j=0; j<t->u.coverage.bcnt; ++j )
3772 t->u.coverage.bcovers[j] = copy(f->u.coverage.bcovers[j]);
3774 if ( t->u.coverage.fcnt!=0 ) {
3775 t->u.coverage.fcovers = galloc( f->u.coverage.fcnt*sizeof(char *));
3776 for ( j=0; j<t->u.coverage.fcnt; ++j )
3777 t->u.coverage.fcovers[j] = copy(f->u.coverage.fcovers[j]);
3779 break;
3780 default:
3781 break;
3783 if ( f->lookup_cnt!=0 ) {
3784 t->lookup_cnt = f->lookup_cnt;
3785 t->lookups = galloc(t->lookup_cnt*sizeof(struct seqlookup));
3786 memcpy(t->lookups,f->lookups,t->lookup_cnt*sizeof(struct seqlookup));
3789 return( to );
3792 FPST *FPSTCopy(FPST *fpst) {
3793 FPST *nfpst;
3794 int i;
3796 nfpst = chunkalloc(sizeof(FPST));
3797 *nfpst = *fpst;
3798 nfpst->next = NULL;
3799 if ( nfpst->nccnt!=0 ) {
3800 nfpst->nclass = galloc(nfpst->nccnt*sizeof(char *));
3801 for ( i=0; i<nfpst->nccnt; ++i )
3802 nfpst->nclass[i] = copy(fpst->nclass[i]);
3804 if ( nfpst->bccnt!=0 ) {
3805 nfpst->bclass = galloc(nfpst->bccnt*sizeof(char *));
3806 for ( i=0; i<nfpst->bccnt; ++i )
3807 nfpst->bclass[i] = copy(fpst->bclass[i]);
3809 if ( nfpst->fccnt!=0 ) {
3810 nfpst->fclass = galloc(nfpst->fccnt*sizeof(char *));
3811 for ( i=0; i<nfpst->fccnt; ++i )
3812 nfpst->fclass[i] = copy(fpst->fclass[i]);
3814 nfpst->rules = RulesCopy(fpst->rules,fpst->rule_cnt,fpst->format);
3815 return( nfpst );
3818 void FPSTFree(FPST *fpst) {
3819 FPST *next;
3820 int i;
3822 while ( fpst!=NULL ) {
3823 next = fpst->next;
3824 for ( i=0; i<fpst->nccnt; ++i )
3825 free(fpst->nclass[i]);
3826 for ( i=0; i<fpst->bccnt; ++i )
3827 free(fpst->bclass[i]);
3828 for ( i=0; i<fpst->fccnt; ++i )
3829 free(fpst->fclass[i]);
3830 free(fpst->nclass); free(fpst->bclass); free(fpst->fclass);
3831 for ( i=0; i<fpst->rule_cnt; ++i ) {
3832 FPSTRuleContentsFree( &fpst->rules[i],fpst->format );
3834 free(fpst->rules);
3835 chunkfree(fpst,sizeof(FPST));
3836 fpst = next;
3840 void MinimumDistancesFree(MinimumDistance *md) {
3841 MinimumDistance *next;
3843 while ( md!=NULL ) {
3844 next = md->next;
3845 chunkfree(md,sizeof(MinimumDistance));
3846 md = next;
3850 void TTFLangNamesFree(struct ttflangname *l) {
3851 struct ttflangname *next;
3852 int i;
3854 while ( l!=NULL ) {
3855 next = l->next;
3856 for ( i=0; i<ttf_namemax; ++i )
3857 free(l->names[i]);
3858 chunkfree(l,sizeof(*l));
3859 l = next;
3863 void AltUniFree(struct altuni *altuni) {
3864 struct altuni *next;
3866 while ( altuni ) {
3867 next = altuni->next;
3868 chunkfree(altuni,sizeof(struct altuni));
3869 altuni = next;
3873 void LayerDefault(Layer *layer) {
3874 memset(layer,0,sizeof(Layer));
3877 SplineChar *SplineCharCreate(int layer_cnt) {
3878 SplineChar *sc = chunkalloc(sizeof(SplineChar));
3879 int i;
3881 sc->color = COLOR_DEFAULT;
3882 sc->orig_pos = 0xffff;
3883 sc->unicodeenc = -1;
3884 sc->layer_cnt = layer_cnt;
3885 sc->layers = gcalloc(layer_cnt,sizeof(Layer));
3886 for ( i=0; i<layer_cnt; ++i )
3887 LayerDefault(&sc->layers[i]);
3888 sc->tex_height = sc->tex_depth = sc->italic_correction = sc->top_accent_horiz =
3889 TEX_UNDEF;
3890 return( sc );
3893 SplineChar *SFSplineCharCreate(SplineFont *sf) {
3894 SplineChar *sc = SplineCharCreate(sf->layer_cnt);
3895 int i;
3897 for ( i=0; i<sf->layer_cnt; ++i ) {
3898 sc->layers[i].background = sf->layers[i].background;
3899 sc->layers[i].order2 = sf->layers[i].order2;
3901 sc->parent = sf;
3902 return( sc );
3905 void GlyphVariantsFree(struct glyphvariants *gv) {
3906 int i;
3908 if ( gv==NULL )
3909 return;
3910 free(gv->variants);
3911 for ( i=0; i<gv->part_cnt; ++i )
3912 free( gv->parts[i].component );
3913 free(gv->parts);
3914 chunkfree(gv,sizeof(*gv));
3917 struct mathkern *MathKernCopy(struct mathkern *mk) {
3918 int i,j;
3919 struct mathkern *mknew;
3921 if ( mk==NULL )
3922 return( NULL );
3923 mknew = chunkalloc(sizeof(*mknew));
3924 for ( i=0; i<4; ++i ) {
3925 struct mathkernvertex *mkv = &(&mk->top_right)[i];
3926 struct mathkernvertex *mknewv = &(&mknew->top_right)[i];
3927 mknewv->cnt = mkv->cnt;
3928 if ( mknewv->cnt!=0 ) {
3929 mknewv->mkd = gcalloc(mkv->cnt,sizeof(struct mathkerndata));
3930 for ( j=0; j<mkv->cnt; ++j ) {
3931 mknewv->mkd[j].height = mkv->mkd[j].height;
3932 mknewv->mkd[j].kern = mkv->mkd[j].kern;
3936 return( mknew );
3939 void MathKernVContentsFree(struct mathkernvertex *mk) {
3940 free(mk->mkd);
3943 void MathKernFree(struct mathkern *mk) {
3944 int i;
3946 if ( mk==NULL )
3947 return;
3948 for ( i=0; i<4; ++i )
3949 MathKernVContentsFree( &(&mk->top_right)[i] );
3950 chunkfree(mk,sizeof(*mk));
3953 void SplineCharListsFree(struct splinecharlist *dlist) {
3954 struct splinecharlist *dnext;
3955 for ( ; dlist!=NULL; dlist = dnext ) {
3956 dnext = dlist->next;
3957 chunkfree(dlist,sizeof(struct splinecharlist));
3961 void LayerFreeContents(SplineChar *sc,int layer) {
3962 SplinePointListsFree(sc->layers[layer].splines);
3963 RefCharsFree(sc->layers[layer].refs);
3964 ImageListsFree(sc->layers[layer].images);
3965 /* image garbage collection????!!!! */
3966 UndoesFree(sc->layers[layer].undoes);
3967 UndoesFree(sc->layers[layer].redoes);
3970 void SplineCharFreeContents(SplineChar *sc) {
3971 int i;
3973 if ( sc==NULL )
3974 return;
3975 free(sc->name);
3976 free(sc->comment);
3977 for ( i=0; i<sc->layer_cnt; ++i )
3978 LayerFreeContents(sc,i);
3979 StemInfosFree(sc->hstem);
3980 StemInfosFree(sc->vstem);
3981 DStemInfosFree(sc->dstem);
3982 MinimumDistancesFree(sc->md);
3983 KernPairsFree(sc->kerns);
3984 KernPairsFree(sc->vkerns);
3985 AnchorPointsFree(sc->anchor);
3986 SplineCharListsFree(sc->dependents);
3987 PSTFree(sc->possub);
3988 free(sc->ttf_instrs);
3989 free(sc->countermasks);
3990 free(sc->layers);
3991 AltUniFree(sc->altuni);
3992 GlyphVariantsFree(sc->horiz_variants);
3993 GlyphVariantsFree(sc->vert_variants);
3994 MathKernFree(sc->mathkern);
3995 #if defined(_NO_PYTHON)
3996 free( sc->python_persistent ); /* It's a string of pickled data which we leave as a string */
3997 #else
3998 PyFF_FreeSC(sc);
3999 #endif
4002 void SplineCharFree(SplineChar *sc) {
4004 if ( sc==NULL )
4005 return;
4006 SplineCharFreeContents(sc);
4007 chunkfree(sc,sizeof(SplineChar));
4010 void AnchorClassesFree(AnchorClass *an) {
4011 AnchorClass *anext;
4012 for ( ; an!=NULL; an = anext ) {
4013 anext = an->next;
4014 free(an->name);
4015 chunkfree(an,sizeof(AnchorClass));
4019 void TtfTablesFree(struct ttf_table *tab) {
4020 struct ttf_table *next;
4022 for ( ; tab!=NULL; tab = next ) {
4023 next = tab->next;
4024 free(tab->data);
4025 chunkfree(tab,sizeof(struct ttf_table));
4029 void ScriptLangListFree(struct scriptlanglist *sl) {
4030 struct scriptlanglist *next;
4032 while ( sl!=NULL ) {
4033 next = sl->next;
4034 free(sl->morelangs);
4035 chunkfree(sl,sizeof(*sl));
4036 sl = next;
4040 void FeatureScriptLangListFree(FeatureScriptLangList *fl) {
4041 FeatureScriptLangList *next;
4043 while ( fl!=NULL ) {
4044 next = fl->next;
4045 ScriptLangListFree(fl->scripts);
4046 chunkfree(fl,sizeof(*fl));
4047 fl = next;
4051 void OTLookupFree(OTLookup *lookup) {
4052 struct lookup_subtable *st, *stnext;
4054 free(lookup->lookup_name);
4055 FeatureScriptLangListFree(lookup->features);
4056 for ( st=lookup->subtables; st!=NULL; st=stnext ) {
4057 stnext = st->next;
4058 free(st->subtable_name);
4059 free(st->suffix);
4060 chunkfree(st,sizeof(struct lookup_subtable));
4062 chunkfree( lookup,sizeof(OTLookup) );
4065 void OTLookupListFree(OTLookup *lookup ) {
4066 OTLookup *next;
4068 for ( ; lookup!=NULL; lookup = next ) {
4069 next = lookup->next;
4070 OTLookupFree(lookup);
4074 KernClass *KernClassCopy(KernClass *kc) {
4075 KernClass *new;
4076 int i;
4078 if ( kc==NULL )
4079 return( NULL );
4080 new = chunkalloc(sizeof(KernClass));
4081 *new = *kc;
4082 new->firsts = galloc(new->first_cnt*sizeof(char *));
4083 new->seconds = galloc(new->second_cnt*sizeof(char *));
4084 new->offsets = galloc(new->first_cnt*new->second_cnt*sizeof(int16));
4085 memcpy(new->offsets,kc->offsets, new->first_cnt*new->second_cnt*sizeof(int16));
4086 for ( i=0; i<new->first_cnt; ++i )
4087 new->firsts[i] = copy(kc->firsts[i]);
4088 for ( i=0; i<new->second_cnt; ++i )
4089 new->seconds[i] = copy(kc->seconds[i]);
4090 new->next = NULL;
4091 return( new );
4094 void KernClassFreeContents(KernClass *kc) {
4095 int i;
4096 /* Issue 863 */
4097 for ( i=0; i<kc->first_cnt; ++i )
4098 free(kc->firsts[i]);
4099 for ( i=0; i<kc->second_cnt; ++i )
4100 free(kc->seconds[i]);
4101 free(kc->firsts);
4102 free(kc->seconds);
4103 free(kc->offsets);
4106 void KernClassListFree(KernClass *kc) {
4107 KernClass *n;
4109 while ( kc ) {
4110 KernClassFreeContents(kc);
4111 n = kc->next;
4112 chunkfree(kc,sizeof(KernClass));
4113 kc = n;
4117 void OtfNameListFree(struct otfname *on) {
4118 struct otfname *on_next;
4120 for ( ; on!=NULL; on = on_next ) {
4121 on_next = on->next;
4122 free(on->name);
4123 chunkfree(on,sizeof(*on));
4127 EncMap *EncMapNew(int enccount,int backmax,Encoding *enc) {
4128 EncMap *map = chunkalloc(sizeof(EncMap));
4130 map->enccount = map->encmax = enccount;
4131 map->backmax = backmax;
4132 map->map = galloc(enccount*sizeof(int));
4133 memset(map->map,-1,enccount*sizeof(int));
4134 map->backmap = galloc(backmax*sizeof(int));
4135 memset(map->backmap,-1,backmax*sizeof(int));
4136 map->enc = enc;
4137 return(map);
4140 EncMap *EncMap1to1(int enccount) {
4141 EncMap *map = chunkalloc(sizeof(EncMap));
4142 /* Used for CID fonts where CID is same as orig_pos */
4143 int i;
4145 map->enccount = map->encmax = map->backmax = enccount;
4146 map->map = galloc(enccount*sizeof(int));
4147 map->backmap = galloc(enccount*sizeof(int));
4148 for ( i=0; i<enccount; ++i )
4149 map->map[i] = map->backmap[i] = i;
4150 map->enc = &custom;
4151 return(map);
4154 static void EncodingFree(Encoding *enc) {
4155 int i;
4157 if ( enc==NULL )
4158 return;
4159 free(enc->enc_name);
4160 free(enc->unicode);
4161 if ( enc->psnames!=NULL ) {
4162 for ( i=0; i<enc->char_cnt; ++i )
4163 free(enc->psnames[i]);
4164 free(enc->psnames);
4166 free(enc);
4169 void EncMapFree(EncMap *map) {
4170 if ( map==NULL )
4171 return;
4173 if ( map->enc->is_temporary )
4174 EncodingFree(map->enc);
4175 free(map->map);
4176 free(map->backmap);
4177 free(map->remap);
4178 chunkfree(map,sizeof(EncMap));
4181 EncMap *EncMapCopy(EncMap *map) {
4182 EncMap *new;
4184 new = chunkalloc(sizeof(EncMap));
4185 *new = *map;
4186 new->map = galloc(new->encmax*sizeof(int));
4187 new->backmap = galloc(new->backmax*sizeof(int));
4188 memcpy(new->map,map->map,new->enccount*sizeof(int));
4189 memcpy(new->backmap,map->backmap,new->backmax*sizeof(int));
4190 if ( map->remap ) {
4191 int n;
4192 for ( n=0; map->remap[n].infont!=-1; ++n );
4193 new->remap = galloc(n*sizeof(struct remap));
4194 memcpy(new->remap,map->remap,n*sizeof(struct remap));
4196 return( new );
4199 void MarkClassFree(int cnt,char **classes,char **names) {
4200 int i;
4202 for ( i=1; i<cnt; ++i ) {
4203 free( classes[i] );
4204 free( names[i] );
4206 free( classes );
4207 free( names );
4210 struct baselangextent *BaseLangCopy(struct baselangextent *extent) {
4211 struct baselangextent *head, *last, *cur;
4213 last = head = NULL;
4214 for ( ; extent!=NULL; extent = extent->next ) {
4215 cur = chunkalloc(sizeof(struct baselangextent));
4216 *cur = *extent;
4217 cur->features = BaseLangCopy(cur->features);
4218 if ( head==NULL )
4219 head = cur;
4220 else
4221 last->next = cur;
4222 last = cur;
4224 return( head );
4227 void BaseLangFree(struct baselangextent *extent) {
4228 struct baselangextent *next;
4230 while ( extent!=NULL ) {
4231 next = extent->next;
4232 BaseLangFree(extent->features);
4233 chunkfree(extent,sizeof(struct baselangextent));
4234 extent = next;
4238 void BaseScriptFree(struct basescript *bs) {
4239 struct basescript *next;
4241 while ( bs!=NULL ) {
4242 next = bs->next;
4243 free(bs->baseline_pos);
4244 BaseLangFree(bs->langs);
4245 chunkfree(bs,sizeof(struct basescript));
4246 bs = next;
4250 void BaseFree(struct Base *base) {
4251 if ( base==NULL )
4252 return;
4254 free(base->baseline_tags);
4255 BaseScriptFree(base->scripts);
4256 chunkfree(base,sizeof(struct Base));
4259 void SplineFontFree(SplineFont *sf) {
4260 int i;
4262 if ( sf==NULL )
4263 return;
4264 if ( sf->mm!=NULL ) {
4265 MMSetFree(sf->mm);
4266 return;
4268 for ( i=0; i<sf->glyphcnt; ++i ) if ( sf->glyphs[i]!=NULL )
4269 SplineCharFree(sf->glyphs[i]);
4270 free(sf->glyphs);
4271 free(sf->fontname);
4272 free(sf->fullname);
4273 free(sf->familyname);
4274 free(sf->weight);
4275 free(sf->copyright);
4276 free(sf->comments);
4277 free(sf->filename);
4278 free(sf->origname);
4279 free(sf->autosavename);
4280 free(sf->version);
4281 free(sf->xuid);
4282 free(sf->cidregistry);
4283 free(sf->ordering);
4284 /* We don't free the EncMap. That field is only a temporary pointer. Let the FontViewBase free it, that's where it really lives */
4285 SplinePointListsFree(sf->grid.splines);
4286 AnchorClassesFree(sf->anchor);
4287 TtfTablesFree(sf->ttf_tables);
4288 TtfTablesFree(sf->ttf_tab_saved);
4289 UndoesFree(sf->grid.undoes);
4290 UndoesFree(sf->grid.redoes);
4291 PSDictFree(sf->private);
4292 TTFLangNamesFree(sf->names);
4293 for ( i=0; i<sf->subfontcnt; ++i )
4294 SplineFontFree(sf->subfonts[i]);
4295 free(sf->subfonts);
4296 GlyphHashFree(sf);
4297 OTLookupListFree(sf->gpos_lookups);
4298 OTLookupListFree(sf->gsub_lookups);
4299 KernClassListFree(sf->kerns);
4300 KernClassListFree(sf->vkerns);
4301 FPSTFree(sf->possub);
4302 OtfNameListFree(sf->fontstyle_name);
4303 MarkClassFree(sf->mark_class_cnt,sf->mark_classes,sf->mark_class_names);
4304 free( sf->gasp );
4305 #if defined(_NO_PYTHON)
4306 free( sf->python_persistent ); /* It's a string of pickled data which we leave as a string */
4307 #else
4308 PyFF_FreeSF(sf);
4309 #endif
4310 BaseFree(sf->horiz_base);
4311 BaseFree(sf->vert_base);
4312 /* issue 863 */
4313 for ( i=0; i < sf->layer_cnt; ++i )
4314 free (sf->layers[i].name);
4315 free(sf->layers);
4316 free(sf->MATH);
4317 free(sf);
4320 void MMSetFreeContents(MMSet *mm) {
4321 int i;
4323 free(mm->instances);
4325 free(mm->positions);
4326 free(mm->defweights);
4328 for ( i=0; i<mm->axis_count; ++i ) {
4329 free(mm->axes[i]);
4330 free(mm->axismaps[i].blends);
4331 free(mm->axismaps[i].designs);
4333 free(mm->axismaps);
4334 free(mm->cdv);
4335 free(mm->ndv);
4338 void MMSetFree(MMSet *mm) {
4339 int i;
4341 for ( i=0; i<mm->instance_count; ++i ) {
4342 mm->instances[i]->mm = NULL;
4343 mm->instances[i]->map = NULL;
4344 SplineFontFree(mm->instances[i]);
4346 mm->normal->mm = NULL;
4347 SplineFontFree(mm->normal); /* EncMap gets freed here */
4348 MMSetFreeContents(mm);
4350 chunkfree(mm,sizeof(*mm));
4353 static int SplineRemoveAnnoyingExtrema1(Spline *s,int which,double err_sq) {
4354 /* Remove extrema which are very close to one of the spline end-points */
4355 /* and which are in the oposite direction (along the normal of the */
4356 /* close end-point's cp) from the other end-point */
4357 extended ts[2], t1, t2;
4358 bigreal df, dt;
4359 bigreal dp, d_o;
4360 int i;
4361 BasePoint pos, norm;
4362 SplinePoint *close, *other;
4363 BasePoint *ccp;
4364 bigreal c_, b_, nextcp, prevcp, prop;
4365 int changed = false;
4367 SplineFindExtrema(&s->splines[which],&ts[0],&ts[1]);
4369 for ( i=0; i<2; ++i ) if ( ts[i]!=-1 && ts[i]!=0 && ts[i]!=1 ) {
4370 pos.x = ((s->splines[0].a*ts[i]+s->splines[0].b)*ts[i]+s->splines[0].c)*ts[i]+s->splines[0].d;
4371 pos.y = ((s->splines[1].a*ts[i]+s->splines[1].b)*ts[i]+s->splines[1].c)*ts[i]+s->splines[1].d;
4372 df = (pos.x-s->from->me.x)*(pos.x-s->from->me.x) + (pos.y-s->from->me.y)*(pos.y-s->from->me.y);
4373 dt = (pos.x-s->to->me.x)*(pos.x-s->to->me.x) + (pos.y-s->to->me.y)*(pos.y-s->to->me.y);
4374 if ( df<dt && df<err_sq ) {
4375 close = s->from;
4376 ccp = &s->from->nextcp;
4377 other = s->to;
4378 } else if ( dt<df && dt<err_sq ) {
4379 close = s->to;
4380 ccp = &s->to->prevcp;
4381 other = s->from;
4382 } else
4383 continue;
4384 if ( ccp->x==close->me.x && ccp->y==close->me.y )
4385 continue;
4387 norm.x = (ccp->y-close->me.y);
4388 norm.y = -(ccp->x-close->me.x);
4389 dp = (pos.x-close->me.x)*norm.x + (pos.y-close->me.y)*norm.y;
4390 d_o = (other->me.x-close->me.x)*norm.x + (other->me.y-close->me.y)*norm.y;
4391 if ( dp!=0 && dp*d_o>=0 )
4392 continue;
4394 _SplineFindExtrema(&s->splines[which],&t1,&t2);
4395 if ( t1==ts[i] ) {
4396 if ( close==s->from ) t1=0;
4397 else t1 = 1;
4398 } else if ( t2==ts[i] ) {
4399 if ( close==s->from ) t2=0;
4400 else t2 = 1;
4401 } else
4402 continue;
4404 if ( t2==-1 ) /* quadratic */
4405 continue; /* Can't happen in a quadratic */
4407 /* The roots of the "slope" quadratic were t1, t2. We have shifted one*/
4408 /* root so that that extremum is exactly on an end point */
4409 /* Figure out the new slope quadratic, from that what the cubic must */
4410 /* be, and from that what the control points must be */
4411 /* Quad = 3at^2 + 2bt + c */
4412 /* New quad = 3a * (t^2 -(t1+t2)t + t1*t2) */
4413 /* a' = a, b' = -(t1+t2)/6a, c' = t1*t2/3a, d' = d */
4414 /* nextcp = from + c'/3, prevcp = nextcp + (b' + c')/3 */
4415 /* Then for each cp figure what percentage of the original cp vector */
4416 /* (or at least this one dimension of that vector) this represents */
4417 /* and scale both dimens by this amount */
4418 b_ = -(t1+t2)*3*s->splines[which].a/2;
4419 c_ = (t1*t2)*3*s->splines[which].a;
4420 nextcp = (&s->from->me.x)[which] + c_/3;
4421 prevcp = nextcp + (b_ + c_)/3;
4423 if ( (&s->from->nextcp.x)[which] != (&s->from->me.x)[which] ) {
4424 prop = (c_/3) / ( (&s->from->nextcp.x)[which] - (&s->from->me.x)[which] );
4425 if ( prop<0 && (c_/3 < .1 && c_/3 > -.1))
4426 (&s->to->prevcp.x)[which] = nextcp;
4427 else if ( prop>=0 && prop<=10 ) {
4428 s->from->nextcp.x = s->from->me.x + prop*(s->from->nextcp.x-s->from->me.x);
4429 s->from->nextcp.y = s->from->me.y + prop*(s->from->nextcp.y-s->from->me.y);
4430 s->from->nonextcp = (prop == 0);
4434 if ( (&s->to->prevcp.x)[which] != (&s->to->me.x)[which] ) {
4435 prop = ( prevcp - (&s->to->me.x)[which]) /
4436 ( (&s->to->prevcp.x)[which] - (&s->to->me.x)[which] );
4437 if ( prop<0 && (prevcp - (&s->to->me.x)[which] < .1 && prevcp - (&s->to->me.x)[which] > -.1))
4438 (&s->to->prevcp.x)[which] = prevcp;
4439 else if ( prop>=0 && prop<=10 ) {
4440 s->to->prevcp.x = s->to->me.x + prop*(s->to->prevcp.x-s->to->me.x);
4441 s->to->prevcp.y = s->to->me.y + prop*(s->to->prevcp.y-s->to->me.y);
4442 s->to->noprevcp = (prop == 0);
4445 SplineRefigure(s);
4446 changed = true;
4448 return( changed );
4451 static int SplineRemoveAnnoyingExtrema(Spline *s,double err_sq) {
4452 int changed;
4454 changed = SplineRemoveAnnoyingExtrema1(s,0,err_sq);
4455 if ( SplineRemoveAnnoyingExtrema1(s,1,err_sq) )
4456 changed = true;
4457 return( changed );
4460 int SplineSetsRemoveAnnoyingExtrema(SplineSet *ss,double err) {
4461 int changed = false;
4462 double err_sq = err*err;
4463 Spline *s, *first;
4466 while ( ss!=NULL ) {
4467 first = NULL;
4468 for ( s = ss->first->next; s!=NULL && s!=first; s = s->to->next ) {
4469 if ( first == NULL ) first = s;
4470 if ( SplineRemoveAnnoyingExtrema(s,err_sq))
4471 changed = true;
4473 ss = ss->next;
4475 return( changed );
4478 SplinePoint *SplineBisect(Spline *spline, extended t) {
4479 Spline1 xstart, xend;
4480 Spline1 ystart, yend;
4481 Spline *spline1, *spline2;
4482 SplinePoint *mid;
4483 SplinePoint *old0, *old1;
4484 Spline1D *xsp = &spline->splines[0], *ysp = &spline->splines[1];
4485 int order2 = spline->order2;
4487 #ifdef DEBUG
4488 if ( t<=1e-3 || t>=1-1e-3 )
4489 IError("Bisection to create a zero length spline");
4490 #endif
4491 xstart.s0 = xsp->d; ystart.s0 = ysp->d;
4492 xend.s1 = (extended) xsp->a+xsp->b+xsp->c+xsp->d;
4493 yend.s1 = (extended) ysp->a+ysp->b+ysp->c+ysp->d;
4494 xstart.s1 = xend.s0 = ((xsp->a*t+xsp->b)*t+xsp->c)*t + xsp->d;
4495 ystart.s1 = yend.s0 = ((ysp->a*t+ysp->b)*t+ysp->c)*t + ysp->d;
4496 FigureSpline1(&xstart,0,t,xsp);
4497 FigureSpline1(&xend,t,1,xsp);
4498 FigureSpline1(&ystart,0,t,ysp);
4499 FigureSpline1(&yend,t,1,ysp);
4501 mid = chunkalloc(sizeof(SplinePoint));
4502 mid->me.x = xstart.s1; mid->me.y = ystart.s1;
4503 if ( order2 ) {
4504 mid->nextcp.x = xend.sp.d + xend.sp.c/2;
4505 mid->nextcp.y = yend.sp.d + yend.sp.c/2;
4506 mid->prevcp.x = xstart.sp.d + xstart.sp.c/2;
4507 mid->prevcp.y = ystart.sp.d + ystart.sp.c/2;
4508 } else {
4509 mid->nextcp.x = xend.c0; mid->nextcp.y = yend.c0;
4510 mid->prevcp.x = xstart.c1; mid->prevcp.y = ystart.c1;
4512 if ( mid->me.x==mid->nextcp.x && mid->me.y==mid->nextcp.y )
4513 mid->nonextcp = true;
4514 if ( mid->me.x==mid->prevcp.x && mid->me.y==mid->prevcp.y )
4515 mid->noprevcp = true;
4517 old0 = spline->from; old1 = spline->to;
4518 if ( order2 ) {
4519 old0->nextcp = mid->prevcp;
4520 old1->prevcp = mid->nextcp;
4521 } else {
4522 old0->nextcp.x = xstart.c0; old0->nextcp.y = ystart.c0;
4523 old1->prevcp.x = xend.c1; old1->prevcp.y = yend.c1;
4525 old0->nonextcp = (old0->nextcp.x==old0->me.x && old0->nextcp.y==old0->me.y);
4526 old1->noprevcp = (old1->prevcp.x==old1->me.x && old1->prevcp.y==old1->me.y);
4527 old0->nextcpdef = false;
4528 old1->prevcpdef = false;
4529 SplineFree(spline);
4531 spline1 = chunkalloc(sizeof(Spline));
4532 spline1->splines[0] = xstart.sp; spline1->splines[1] = ystart.sp;
4533 spline1->from = old0;
4534 spline1->to = mid;
4535 spline1->order2 = order2;
4536 old0->next = spline1;
4537 mid->prev = spline1;
4538 if ( SplineIsLinear(spline1)) {
4539 spline1->islinear = spline1->from->nonextcp = spline1->to->noprevcp = true;
4540 spline1->from->nextcp = spline1->from->me;
4541 spline1->to->prevcp = spline1->to->me;
4543 SplineRefigure(spline1);
4545 spline2 = chunkalloc(sizeof(Spline));
4546 spline2->splines[0] = xend.sp; spline2->splines[1] = xend.sp;
4547 spline2->from = mid;
4548 spline2->to = old1;
4549 spline2->order2 = order2;
4550 mid->next = spline2;
4551 old1->prev = spline2;
4552 if ( SplineIsLinear(spline2)) {
4553 spline2->islinear = spline2->from->nonextcp = spline2->to->noprevcp = true;
4554 spline2->from->nextcp = spline2->from->me;
4555 spline2->to->prevcp = spline2->to->me;
4557 SplineRefigure(spline2);
4558 return( mid );