1 /* Copyright (C) 2000-2012 by George Williams */
2 /*
3 * Redistribution and use in source and binary forms, with or without
4 * modification, are permitted provided that the following conditions are met:
5
6 * Redistributions of source code must retain the above copyright notice, this
7 * list of conditions and the following disclaimer.
8
9 * Redistributions in binary form must reproduce the above copyright notice,
10 * this list of conditions and the following disclaimer in the documentation
11 * and/or other materials provided with the distribution.
12
13 * The name of the author may not be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
19 * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28 #include <fontforge-config.h>
29
30 #include "splineutil.h"
31
32 #include "cvundoes.h"
33 #include "dumppfa.h"
34 #include "encoding.h"
35 #include "ffglib.h"
36 #include "fontforgevw.h"
37 #include "fvfonts.h"
38 #include "fvimportbdf.h"
39 #include "glif_name_hash.h"
40 #include "mm.h"
41 #include "namelist.h"
42 #include "parsepfa.h"
43 #include "parsettf.h"
44 #include "psfont.h"
45 #include "psread.h"
46 #include "sfd1.h" // This has the extended SplineFont type SplineFont1 for old file versions.
47 #include "spiro.h"
48 #include "splinefill.h"
49 #include "splineorder2.h"
50 #include "splinerefigure.h"
51 #include "splineutil2.h"
52 #include "tottf.h"
53 #include "ustring.h"
54 #include "utype.h"
55 #include "views.h" /* for FindSel structure */
56
57 #include <locale.h>
58
59 #include <math.h>
60 #ifdef HAVE_IEEEFP_H
61 # include <ieeefp.h> /* Solaris defines isnan in ieeefp rather than math.h */
62 #endif
63
64 /*#define DEBUG 1*/
65
66 typedef struct quartic {
67 bigreal a,b,c,d,e;
68 } Quartic;
69
70 /* In an attempt to make allocation more efficient I just keep preallocated */
71 /* lists of certain common sizes. It doesn't seem to make much difference */
72 /* when allocating stuff, but does when freeing. If the extra complexity */
73 /* is bad then put: */
74 /* #define chunkalloc(size) calloc(1,size) */
75 /* #define chunkfree(item,size) free(item) */
76 /* into splinefont.h after (or instead of) the definition of chunkalloc()*/
77
78 #define ALLOC_CHUNK 100 /* Number of small chunks to malloc at a time */
79 #ifndef FONTFORGE_CONFIG_USE_DOUBLE
80 # define CHUNK_MAX 100 /* Maximum size (in chunk units) that we are prepared to allocate */
81 /* The size of our data structures */
82 #else
83 # define CHUNK_MAX 129
84 #endif
85 # define CHUNK_UNIT sizeof(void *) /* will vary with the word size of */
86 /* the machine. if pointers are 64 bits*/
87 /* we may need twice as much space as for 32 bits */
88
89 #ifdef FLAG
90 #undef FLAG
91 #define FLAG 0xbadcafe
92 #endif
93
94 #ifdef CHUNKDEBUG
95 static int chunkdebug = 0; /* When this is set we never free anything, insuring that each chunk is unique */
96 #endif
97
98 #if ALLOC_CHUNK>1
99 struct chunk { struct chunk *next; };
100 struct chunk2 { struct chunk2 *next; int flag; };
101 #endif
102
103 #if defined(FLAG) && ALLOC_CHUNK>1
chunktest(void)104 void chunktest(void) {
105 int i;
106 struct chunk2 *c;
107
108 for ( i=2; i<CHUNK_MAX; ++i )
109 for ( c=(struct chunk2 *) chunklists[i]; c!=NULL; c=c->next )
110 if ( c->flag!=FLAG ) {
111 fprintf( stderr, "Chunk memory list has been corrupted\n" );
112 abort();
113 }
114 }
115 #endif
116
strconcat(const char * str1,const char * str2)117 char *strconcat(const char *str1,const char *str2) {
118 char *ret;
119 int len1 = strlen(str1);
120 if ( (ret=malloc(len1+strlen(str2)+1))!=NULL ) {
121 strcpy(ret,str1);
122 strcpy(ret+len1,str2);
123 }
124 return( ret );
125 }
126
strconcat3(const char * str1,const char * str2,const char * str3)127 char *strconcat3(const char *str1,const char *str2, const char *str3) {
128 char *ret;
129 int len1 = strlen(str1), len2 = strlen(str2);
130 if ( (ret=malloc(len1+len2+strlen(str3)+1))!=NULL ) {
131 strcpy(ret,str1);
132 strcpy(ret+len1,str2);
133 strcpy(ret+len1+len2,str3);
134 }
135 return( ret );
136 }
137
LineListFree(LineList * ll)138 void LineListFree(LineList *ll) {
139 LineList *next;
140
141 while ( ll!=NULL ) {
142 next = ll->next;
143 chunkfree(ll,sizeof(LineList));
144 ll = next;
145 }
146 }
147
LinearApproxFree(LinearApprox * la)148 void LinearApproxFree(LinearApprox *la) {
149 LinearApprox *next;
150
151 while ( la!=NULL ) {
152 next = la->next;
153 LineListFree(la->lines);
154 chunkfree(la,sizeof(LinearApprox));
155 la = next;
156 }
157 }
158
SplineFree(Spline * spline)159 void SplineFree(Spline *spline) {
160 LinearApproxFree(spline->approx);
161 chunkfree(spline,sizeof(Spline));
162 }
163
SplinePointCreate(real x,real y)164 SplinePoint *SplinePointCreate(real x, real y) {
165 SplinePoint *sp;
166 if ( (sp=chunkalloc(sizeof(SplinePoint)))!=NULL ) {
167 sp->me.x = x; sp->me.y = y;
168 sp->nextcp = sp->prevcp = sp->me;
169 sp->nonextcp = sp->noprevcp = true;
170 sp->nextcpdef = sp->prevcpdef = false;
171 sp->ttfindex = sp->nextcpindex = 0xfffe;
172 sp->name = NULL;
173 }
174 return( sp );
175 }
176
SplineMake3(SplinePoint * from,SplinePoint * to)177 Spline *SplineMake3(SplinePoint *from, SplinePoint *to) {
178 Spline *spline = chunkalloc(sizeof(Spline));
179
180 spline->from = from; spline->to = to;
181 from->next = to->prev = spline;
182 SplineRefigure3(spline);
183 return( spline );
184 }
185
SplinePointFree(SplinePoint * sp)186 void SplinePointFree(SplinePoint *sp) {
187 chunkfree(sp->hintmask,sizeof(HintMask));
188 free(sp->name);
189 chunkfree(sp,sizeof(SplinePoint));
190 }
191
SplinePointMDFree(SplineChar * sc,SplinePoint * sp)192 void SplinePointMDFree(SplineChar *sc, SplinePoint *sp) {
193 MinimumDistance *md, *prev, *next;
194
195 if ( sc!=NULL ) {
196 prev = NULL;
197 for ( md = sc->md; md!=NULL; md = next ) {
198 next = md->next;
199 if ( md->sp1==sp || md->sp2==sp ) {
200 if ( prev==NULL )
201 sc->md = next;
202 else
203 prev->next = next;
204 chunkfree(md,sizeof(MinimumDistance));
205 } else
206 prev = md;
207 }
208 }
209
210 chunkfree(sp->hintmask,sizeof(HintMask));
211 free(sp->name);
212 chunkfree(sp,sizeof(SplinePoint));
213 }
214
SplinePointsFree(SplinePointList * spl)215 void SplinePointsFree(SplinePointList *spl) {
216 Spline *first, *spline, *next;
217 int nonext;
218
219 if ( spl==NULL )
220 return;
221 if ( spl->first!=NULL ) {
222 nonext = spl->first->next==NULL; // If there is no spline, we set a flag.
223 first = NULL;
224 // We start on the first spline if it exists.
225 for ( spline = spl->first->next; spline!=NULL && spline!=first; spline = next ) {
226 next = spline->to->next; // Cache the location of the next spline.
227 SplinePointFree(spline->to); // Free the destination point.
228 SplineFree(spline); // Free the spline.
229 if ( first==NULL ) first = spline; // We want to avoid repeating the circuit.
230 }
231 // If the path is open or has no splines, free the starting point.
232 if ( spl->last!=spl->first || nonext )
233 SplinePointFree(spl->first);
234 }
235 }
236
SplineSetBeziersClear(SplinePointList * spl)237 void SplineSetBeziersClear(SplinePointList *spl) {
238
239 if ( spl==NULL ) return;
240 SplinePointsFree(spl);
241 spl->first = spl->last = NULL;
242 spl->start_offset = 0;
243 }
244
SplinePointListFree(SplinePointList * spl)245 void SplinePointListFree(SplinePointList *spl) {
246
247 if ( spl==NULL ) return;
248 SplinePointsFree(spl);
249 free(spl->spiros);
250 free(spl->contour_name);
251 chunkfree(spl,sizeof(SplinePointList));
252 }
253
SplinePointListMDFree(SplineChar * sc,SplinePointList * spl)254 void SplinePointListMDFree(SplineChar *sc,SplinePointList *spl) {
255 Spline *first, *spline, *next;
256 int freefirst;
257
258 if ( spl==NULL )
259 return;
260 if ( spl->first!=NULL ) {
261 first = NULL;
262 freefirst = ( spl->last!=spl->first || spl->first->next==NULL );
263 for ( spline = spl->first->next; spline!=NULL && spline!=first; spline = next ) {
264 next = spline->to->next;
265 SplinePointMDFree(sc,spline->to);
266 SplineFree(spline);
267 if ( first==NULL ) first = spline;
268 }
269 if ( freefirst )
270 SplinePointMDFree(sc,spl->first);
271 }
272 free(spl->spiros);
273 free(spl->contour_name);
274 chunkfree(spl,sizeof(SplinePointList));
275 }
276
SplinePointListsMDFree(SplineChar * sc,SplinePointList * spl)277 void SplinePointListsMDFree(SplineChar *sc,SplinePointList *spl) {
278 SplinePointList *next;
279
280 while ( spl!=NULL ) {
281 next = spl->next;
282 SplinePointListMDFree(sc,spl);
283 spl = next;
284 }
285 }
286
SplinePointListsFree(SplinePointList * spl)287 void SplinePointListsFree(SplinePointList *spl) {
288 SplinePointList *next;
289
290 while ( spl!=NULL ) {
291 next = spl->next;
292 SplinePointListFree(spl);
293 spl = next;
294 }
295 }
296
SplineSetSpirosClear(SplineSet * spl)297 void SplineSetSpirosClear(SplineSet *spl) {
298 free(spl->spiros);
299 spl->spiros = NULL;
300 spl->spiro_cnt = spl->spiro_max = 0;
301 }
302
ImageListsFree(ImageList * imgs)303 void ImageListsFree(ImageList *imgs) {
304 ImageList *inext;
305
306 while ( imgs!=NULL ) {
307 inext = imgs->next;
308 chunkfree(imgs,sizeof(ImageList));
309 imgs = inext;
310 }
311 }
312
RefCharFree(RefChar * ref)313 void RefCharFree(RefChar *ref) {
314 int i;
315
316 if ( ref==NULL )
317 return;
318 for ( i=0; i<ref->layer_cnt; ++i ) {
319 SplinePointListsFree(ref->layers[i].splines);
320 ImageListsFree(ref->layers[i].images);
321 GradientFree(ref->layers[i].fill_brush.gradient);
322 GradientFree(ref->layers[i].stroke_pen.brush.gradient);
323 PatternFree(ref->layers[i].fill_brush.pattern);
324 PatternFree(ref->layers[i].stroke_pen.brush.pattern);
325 }
326 free(ref->layers);
327 chunkfree(ref,sizeof(RefChar));
328 }
329
RefCharCreate(void)330 RefChar *RefCharCreate(void) {
331 RefChar *ref = chunkalloc(sizeof(RefChar));
332 ref->layer_cnt = 1;
333 ref->layers = calloc(1,sizeof(struct reflayer));
334 ref->layers[0].fill_brush.opacity = ref->layers[0].stroke_pen.brush.opacity = 1.0;
335 ref->layers[0].fill_brush.col = ref->layers[0].stroke_pen.brush.col = COLOR_INHERITED;
336 ref->layers[0].stroke_pen.width = WIDTH_INHERITED;
337 ref->layers[0].stroke_pen.linecap = lc_inherited;
338 ref->layers[0].stroke_pen.linejoin = lj_inherited;
339 ref->layers[0].dofill = true;
340 ref->round_translation_to_grid = true;
341 return( ref );
342 }
343
RefCharsFree(RefChar * ref)344 void RefCharsFree(RefChar *ref) {
345 RefChar *rnext;
346
347 while ( ref!=NULL ) {
348 rnext = ref->next;
349 RefCharFree(ref);
350 ref = rnext;
351 }
352 }
353
354 /* Remove line segments which are just one point long */
355 /* Merge colinear line segments */
356 /* Merge two segments each of which involves a single pixel change in one dimension (cut corners) */
SimplifyLineList(LineList * prev)357 static void SimplifyLineList(LineList *prev) {
358 LineList *next, *lines;
359
360 if ( prev->next==NULL )
361 return;
362 lines = prev->next;
363 while ( (next = lines->next)!=NULL ) {
364 if ( (prev->here.x==lines->here.x && prev->here.y == lines->here.y ) ||
365 ( prev->here.x==lines->here.x && lines->here.x==next->here.x ) ||
366 ( prev->here.y==lines->here.y && lines->here.y==next->here.y ) ||
367 (( prev->here.x==next->here.x+1 || prev->here.x==next->here.x-1 ) &&
368 ( prev->here.y==next->here.y+1 || prev->here.y==next->here.y-1 )) ) {
369 lines->here = next->here;
370 lines->next = next->next;
371 chunkfree(next,sizeof(*next));
372 } else {
373 prev = lines;
374 lines = next;
375 }
376 }
377 if ( prev!=NULL &&
378 prev->here.x==lines->here.x && prev->here.y == lines->here.y ) {
379 prev->next = lines->next;
380 chunkfree(lines,sizeof(*lines));
381 lines = prev->next;
382 }
383
384 if ( lines!=NULL ) while ( (next = lines->next)!=NULL ) {
385 if ( prev->here.x!=next->here.x ) {
386 bigreal slope = (next->here.y-prev->here.y) / (bigreal) (next->here.x-prev->here.x);
387 bigreal inter = prev->here.y - slope*prev->here.x;
388 int y = rint(lines->here.x*slope + inter);
389 if ( y == lines->here.y ) {
390 lines->here = next->here;
391 lines->next = next->next;
392 chunkfree(next,sizeof(*next));
393 } else
394 lines = next;
395 } else
396 lines = next;
397 }
398 }
399
400 typedef struct spline1 {
401 Spline1D sp;
402 real s0, s1;
403 real c0, c1;
404 } Spline1;
405
FigureSpline1(Spline1 * sp1,bigreal t0,bigreal t1,Spline1D * sp)406 static void FigureSpline1(Spline1 *sp1,bigreal t0, bigreal t1, Spline1D *sp ) {
407 bigreal s = (t1-t0);
408 if ( sp->a==0 && sp->b==0 ) {
409 sp1->sp.d = sp->d + t0*sp->c;
410 sp1->sp.c = s*sp->c;
411 sp1->sp.b = sp1->sp.a = 0;
412 } else {
413 sp1->sp.d = sp->d + t0*(sp->c + t0*(sp->b + t0*sp->a));
414 sp1->sp.c = s*(sp->c + t0*(2*sp->b + 3*sp->a*t0));
415 sp1->sp.b = s*s*(sp->b+3*sp->a*t0);
416 sp1->sp.a = s*s*s*sp->a;
417 }
418 sp1->c0 = sp1->sp.c/3 + sp1->sp.d;
419 sp1->c1 = sp1->c0 + (sp1->sp.b+sp1->sp.c)/3;
420 }
421
SplineSegApprox(LineList * last,Spline * spline,bigreal start,bigreal end,real scale)422 static LineList *SplineSegApprox(LineList *last, Spline *spline, bigreal start, bigreal end, real scale) {
423 /* Divide into n equal segments */
424 /* (first point is already on the line list) */
425 /* what's a good value for n? Perhaps the normal distance of the control */
426 /* points to the line between the end points. */
427 int i,n;
428 bigreal t, diff, len;
429 bigreal x,y;
430 LineList *cur;
431 BasePoint startp, endp, slope, off;
432 bigreal temp;
433
434 n = 6;
435 if ( start==0 && end==1 ) {
436 /* No different from the latter case, except we can optimize here */
437 /* and it's easier to understand what is happening in the simple */
438 /* case */
439 slope.x = spline->to->me.x - spline->from->me.x;
440 slope.y = spline->to->me.y - spline->from->me.y;
441 len = slope.x*slope.x + slope.y*slope.y;
442 if ( len==0 )
443 return( last );
444 len = sqrt(len);
445 slope.x /= len; slope.y /= len;
446 off.x = spline->from->nextcp.x - spline->from->me.x;
447 off.y = spline->from->nextcp.y - spline->from->me.y;
448 temp = (off.x*slope.y - off.y*slope.x) * scale;
449 if ( temp<0 ) temp = -temp;
450 if ( temp>n ) n = temp;
451 off.x = spline->to->prevcp.x - spline->from->me.x;
452 off.y = spline->to->prevcp.y - spline->from->me.y;
453 temp = (off.x*slope.y - off.y*slope.x) * scale;
454 if ( temp<0 ) temp = -temp;
455 if ( temp>n ) n = temp;
456 } else {
457 Spline1 xsp, ysp;
458 startp.x = ((spline->splines[0].a*start+spline->splines[0].b)*start+spline->splines[0].c)*start + spline->splines[0].d;
459 startp.y = ((spline->splines[1].a*start+spline->splines[1].b)*start+spline->splines[1].c)*start + spline->splines[1].d;
460 endp.x = ((spline->splines[0].a*end+spline->splines[0].b)*end+spline->splines[0].c)*end + spline->splines[0].d;
461 endp.y = ((spline->splines[1].a*end+spline->splines[1].b)*end+spline->splines[1].c)*end + spline->splines[1].d;
462 slope.x = endp.x - startp.x;
463 slope.y = endp.y - startp.y;
464 FigureSpline1(&xsp,start,end,&spline->splines[0]);
465 FigureSpline1(&ysp,start,end,&spline->splines[1]);
466 len = slope.x*slope.x + slope.y*slope.y;
467 if ( len==0 )
468 return( last );
469 len = sqrt(len);
470 slope.x /= len; slope.y /= len;
471 off.x = xsp.c0 - startp.x;
472 off.y = ysp.c0 - startp.y;
473 temp = (off.x*slope.y - off.y*slope.x) * scale;
474 if ( temp<0 ) temp = -temp;
475 if ( temp>n ) n = temp;
476 off.x = xsp.c1 - endp.x;
477 off.y = ysp.c1 - endp.y;
478 temp = (off.x*slope.y - off.y*slope.x) * scale;
479 if ( temp<0 ) temp = -temp;
480 if ( temp>n ) n = temp;
481 }
482
483 diff = (end-start)/n;
484 for ( t=start+diff, i=1; i<=n; ++i, t+=diff ) {
485 if ( i==n ) t = end; /* Avoid rounding errors */
486 cur = chunkalloc(sizeof(LineList) );
487 x = ((spline->splines[0].a*t+spline->splines[0].b)*t+spline->splines[0].c)*t + spline->splines[0].d;
488 y = ((spline->splines[1].a*t+spline->splines[1].b)*t+spline->splines[1].c)*t + spline->splines[1].d;
489 cur->here.x = rint(x*scale);
490 cur->here.y = rint(y*scale);
491 last->next = cur;
492 last = cur;
493 }
494 return( last );
495 }
496
SplineApproximate(Spline * spline,real scale)497 LinearApprox *SplineApproximate(Spline *spline, real scale) {
498 LinearApprox *test;
499 LineList *cur, *last=NULL;
500 extended poi[2], lastt;
501 int i,n;
502
503 for ( test = spline->approx; test!=NULL && test->scale!=scale; test = test->next );
504 if ( test!=NULL )
505 return( test );
506
507 test = chunkalloc(sizeof(LinearApprox));
508 test->scale = scale;
509 test->next = spline->approx;
510 spline->approx = test;
511
512 cur = chunkalloc(sizeof(LineList) );
513 cur->here.x = rint(spline->from->me.x*scale);
514 cur->here.y = rint(spline->from->me.y*scale);
515 test->lines = last = cur;
516
517 if ( spline->knownlinear ) {
518 cur = chunkalloc(sizeof(LineList) );
519 cur->here.x = rint(spline->to->me.x*scale);
520 cur->here.y = rint(spline->to->me.y*scale);
521 last->next = cur;
522 } else if ( spline->isquadratic ) {
523 last = SplineSegApprox(last,spline,0,1,scale);
524 } else {
525 n = Spline2DFindPointsOfInflection(spline,poi);
526 lastt=0;
527 for ( i=0; i<n; ++i ) {
528 last = SplineSegApprox(last,spline,lastt,poi[i],scale);
529 lastt = poi[i];
530 }
531 last = SplineSegApprox(last,spline,lastt,1,scale);
532 }
533 SimplifyLineList(test->lines);
534 if ( test->lines->next==NULL ) {
535 test->oneline = 1;
536 test->onepoint = 1;
537 } else if ( test->lines->next->next == NULL ) {
538 test->oneline = 1;
539 }
540 return( test );
541 }
542
SplineFindBounds(const Spline * sp,DBounds * bounds)543 static void SplineFindBounds(const Spline *sp, DBounds *bounds) {
544 real t, b2_fourac, v;
545 real min, max;
546 const Spline1D *sp1;
547 int i;
548
549 /* first try the end points */
550 for ( i=0; i<2; ++i ) {
551 sp1 = &sp->splines[i];
552 if ( i==0 ) {
553 if ( sp->to->me.x<bounds->minx ) bounds->minx = sp->to->me.x;
554 if ( sp->to->me.x>bounds->maxx ) bounds->maxx = sp->to->me.x;
555 min = bounds->minx; max = bounds->maxx;
556 } else {
557 if ( sp->to->me.y<bounds->miny ) bounds->miny = sp->to->me.y;
558 if ( sp->to->me.y>bounds->maxy ) bounds->maxy = sp->to->me.y;
559 min = bounds->miny; max = bounds->maxy;
560 }
561
562 /* then try the extrema of the spline (assuming they are between t=(0,1) */
563 /* (I don't bother fixing up for tiny rounding errors here. they don't matter */
564 /* But we could call CheckExtremaForSingleBitErrors */
565 if ( sp1->a!=0 ) {
566 b2_fourac = 4*sp1->b*sp1->b - 12*sp1->a*sp1->c;
567 if ( b2_fourac>=0 ) {
568 b2_fourac = sqrt(b2_fourac);
569 t = (-2*sp1->b + b2_fourac) / (6*sp1->a);
570 if ( t>0 && t<1 ) {
571 v = ((sp1->a*t+sp1->b)*t+sp1->c)*t + sp1->d;
572 if ( v<min ) min = v;
573 if ( v>max ) max = v;
574 }
575 t = (-2*sp1->b - b2_fourac) / (6*sp1->a);
576 if ( t>0 && t<1 ) {
577 v = ((sp1->a*t+sp1->b)*t+sp1->c)*t + sp1->d;
578 if ( v<min ) min = v;
579 if ( v>max ) max = v;
580 }
581 }
582 } else if ( sp1->b!=0 ) {
583 t = -sp1->c/(2.0*sp1->b);
584 if ( t>0 && t<1 ) {
585 v = (sp1->b*t+sp1->c)*t + sp1->d;
586 if ( v<min ) min = v;
587 if ( v>max ) max = v;
588 }
589 }
590 if ( i==0 ) {
591 bounds->minx = min; bounds->maxx = max;
592 } else {
593 bounds->miny = min; bounds->maxy = max;
594 }
595 }
596 }
597
_SplineSetFindBounds(const SplinePointList * spl,DBounds * bounds)598 static void _SplineSetFindBounds(const SplinePointList *spl, DBounds *bounds) {
599 Spline *spline, *first;
600 /* Ignore contours consisting of a single point (used for hinting, anchors */
601 /* for mark to base, etc. */
602
603 for ( ; spl!=NULL; spl = spl->next ) if ( spl->first->next!=NULL && spl->first->next->to != spl->first ) {
604 first = NULL;
605 if ( bounds->minx==0 && bounds->maxx==0 && bounds->miny==0 && bounds->maxy == 0 ) {
606 bounds->minx = bounds->maxx = spl->first->me.x;
607 bounds->miny = bounds->maxy = spl->first->me.y;
608 } else {
609 if ( spl->first->me.x<bounds->minx ) bounds->minx = spl->first->me.x;
610 if ( spl->first->me.x>bounds->maxx ) bounds->maxx = spl->first->me.x;
611 if ( spl->first->me.y<bounds->miny ) bounds->miny = spl->first->me.y;
612 if ( spl->first->me.y>bounds->maxy ) bounds->maxy = spl->first->me.y;
613 }
614 for ( spline = spl->first->next; spline!=NULL && spline!=first; spline=spline->to->next ) {
615 SplineFindBounds(spline,bounds);
616 if ( first==NULL ) first = spline;
617 }
618 }
619 }
620
_SplineSetFindClippedBounds(const SplinePointList * spl,DBounds * bounds,DBounds * clipb)621 static void _SplineSetFindClippedBounds(const SplinePointList *spl, DBounds *bounds,DBounds *clipb) {
622 Spline *spline, *first;
623 /* Ignore contours consisting of a single point (used for hinting, anchors */
624 /* for mark to base, etc. */
625
626 for ( ; spl!=NULL; spl = spl->next ) if ( spl->first->next!=NULL && spl->first->next->to != spl->first ) {
627 first = NULL;
628 if ( !spl->is_clip_path ) {
629 if ( bounds->minx==0 && bounds->maxx==0 && bounds->miny==0 && bounds->maxy == 0 ) {
630 bounds->minx = bounds->maxx = spl->first->me.x;
631 bounds->miny = bounds->maxy = spl->first->me.y;
632 } else {
633 if ( spl->first->me.x<bounds->minx ) bounds->minx = spl->first->me.x;
634 if ( spl->first->me.x>bounds->maxx ) bounds->maxx = spl->first->me.x;
635 if ( spl->first->me.y<bounds->miny ) bounds->miny = spl->first->me.y;
636 if ( spl->first->me.y>bounds->maxy ) bounds->maxy = spl->first->me.y;
637 }
638 for ( spline = spl->first->next; spline!=NULL && spline!=first; spline=spline->to->next ) {
639 SplineFindBounds(spline,bounds);
640 if ( first==NULL ) first = spline;
641 }
642 } else {
643 if ( clipb->minx==0 && clipb->maxx==0 && clipb->miny==0 && clipb->maxy == 0 ) {
644 clipb->minx = clipb->maxx = spl->first->me.x;
645 clipb->miny = clipb->maxy = spl->first->me.y;
646 } else {
647 if ( spl->first->me.x<clipb->minx ) clipb->minx = spl->first->me.x;
648 if ( spl->first->me.x>clipb->maxx ) clipb->maxx = spl->first->me.x;
649 if ( spl->first->me.y<clipb->miny ) clipb->miny = spl->first->me.y;
650 if ( spl->first->me.y>clipb->maxy ) clipb->maxy = spl->first->me.y;
651 }
652 for ( spline = spl->first->next; spline!=NULL && spline!=first; spline=spline->to->next ) {
653 SplineFindBounds(spline,clipb);
654 if ( first==NULL ) first = spline;
655 }
656 }
657 }
658 }
659
SplineSetFindBounds(const SplinePointList * spl,DBounds * bounds)660 void SplineSetFindBounds(const SplinePointList *spl, DBounds *bounds) {
661 DBounds clipb;
662 memset(bounds,'\0',sizeof(*bounds));
663 memset(&clipb,'\0',sizeof(clipb));
664 _SplineSetFindClippedBounds(spl, bounds,&clipb);
665 if ( clipb.minx!=0 || clipb.miny!=0 || clipb.maxx!=0 || clipb.maxy!=0 ) {
666 if ( bounds->minx<clipb.minx ) bounds->minx = clipb.minx;
667 if ( bounds->miny<clipb.miny ) bounds->miny = clipb.miny;
668 if ( bounds->maxx>clipb.maxx ) bounds->maxx = clipb.maxx;
669 if ( bounds->maxy>clipb.maxy ) bounds->maxy = clipb.maxy;
670 }
671 }
672
_ImageFindBounds(ImageList * img,DBounds * bounds)673 static void _ImageFindBounds(ImageList *img,DBounds *bounds) {
674 if ( bounds->minx==0 && bounds->maxx==0 && bounds->miny==0 && bounds->maxy == 0 )
675 *bounds = img->bb;
676 else if ( img->bb.minx!=0 || img->bb.maxx != 0 || img->bb.maxy != 0 || img->bb.miny!=0 ) {
677 if ( img->bb.minx < bounds->minx ) bounds->minx = img->bb.minx;
678 if ( img->bb.miny < bounds->miny ) bounds->miny = img->bb.miny;
679 if ( img->bb.maxx > bounds->maxx ) bounds->maxx = img->bb.maxx;
680 if ( img->bb.maxy > bounds->maxy ) bounds->maxy = img->bb.maxy;
681 }
682 }
683
_SplineCharLayerFindBounds(SplineChar * sc,int layer,DBounds * bounds)684 static void _SplineCharLayerFindBounds(SplineChar *sc,int layer, DBounds *bounds) {
685 RefChar *rf;
686 ImageList *img;
687 real e;
688 DBounds b, clipb;
689
690 for ( rf=sc->layers[layer].refs; rf!=NULL; rf = rf->next ) {
691 if ( bounds->minx==0 && bounds->maxx==0 && bounds->miny==0 && bounds->maxy == 0 )
692 *bounds = rf->bb;
693 else if ( rf->bb.minx!=0 || rf->bb.maxx != 0 || rf->bb.maxy != 0 || rf->bb.miny!=0 ) {
694 if ( rf->bb.minx < bounds->minx ) bounds->minx = rf->bb.minx;
695 if ( rf->bb.miny < bounds->miny ) bounds->miny = rf->bb.miny;
696 if ( rf->bb.maxx > bounds->maxx ) bounds->maxx = rf->bb.maxx;
697 if ( rf->bb.maxy > bounds->maxy ) bounds->maxy = rf->bb.maxy;
698 }
699 }
700 memset(&b,0,sizeof(b));
701 memset(&clipb,0,sizeof(clipb));
702 _SplineSetFindClippedBounds(sc->layers[layer].splines,&b,&clipb);
703 for ( img=sc->layers[layer].images; img!=NULL; img=img->next )
704 _ImageFindBounds(img,bounds);
705 if ( sc->layers[layer].dostroke ) {
706 if ( sc->layers[layer].stroke_pen.width!=WIDTH_INHERITED )
707 e = sc->layers[layer].stroke_pen.width*sc->layers[layer].stroke_pen.trans[0];
708 else
709 e = sc->layers[layer].stroke_pen.trans[0];
710 b.minx -= e; b.maxx += e;
711 b.miny -= e; b.maxy += e;
712 }
713 if ( clipb.minx!=0 || clipb.miny!=0 || clipb.maxx!=0 || clipb.maxy!=0 ) {
714 if ( b.minx<clipb.minx ) b.minx = clipb.minx;
715 if ( b.miny<clipb.miny ) b.miny = clipb.miny;
716 if ( b.maxx>clipb.maxx ) b.maxx = clipb.maxx;
717 if ( b.maxy>clipb.maxy ) b.maxy = clipb.maxy;
718 }
719 if ( bounds->minx==0 && bounds->maxx==0 && bounds->miny==0 && bounds->maxy == 0 )
720 *bounds = b;
721 else if ( b.minx!=0 || b.maxx != 0 || b.maxy != 0 || b.miny!=0 ) {
722 if ( b.minx < bounds->minx ) bounds->minx = b.minx;
723 if ( b.miny < bounds->miny ) bounds->miny = b.miny;
724 if ( b.maxx > bounds->maxx ) bounds->maxx = b.maxx;
725 if ( b.maxy > bounds->maxy ) bounds->maxy = b.maxy;
726 }
727
728 if ( sc->parent!=NULL && sc->parent->strokedfont &&
729 (bounds->minx!=bounds->maxx || bounds->miny!=bounds->maxy)) {
730 real sw = sc->parent->strokewidth;
731 bounds->minx -= sw; bounds->miny -= sw;
732 bounds->maxx += sw; bounds->maxy += sw;
733 }
734 }
735
SplineCharLayerFindBounds(SplineChar * sc,int layer,DBounds * bounds)736 void SplineCharLayerFindBounds(SplineChar *sc,int layer,DBounds *bounds) {
737
738 if ( sc->parent!=NULL && sc->parent->multilayer ) {
739 SplineCharFindBounds(sc,bounds);
740 return;
741 }
742
743 /* a char with no splines (ie. a space) must have an lbearing of 0 */
744 bounds->minx = bounds->maxx = 0;
745 bounds->miny = bounds->maxy = 0;
746
747 _SplineCharLayerFindBounds(sc,layer,bounds);
748 }
749
SplineCharFindBounds(SplineChar * sc,DBounds * bounds)750 void SplineCharFindBounds(SplineChar *sc,DBounds *bounds) {
751 int i;
752 int first,last;
753
754 /* a char with no splines (ie. a space) must have an lbearing of 0 */
755 bounds->minx = bounds->maxx = 0;
756 bounds->miny = bounds->maxy = 0;
757
758 first = last = ly_fore;
759 if ( sc->parent!=NULL )
760 last = sc->layer_cnt-1;
761 for ( i=first; i<=last; ++i )
762 _SplineCharLayerFindBounds(sc,i,bounds);
763 }
764
SplineFontLayerFindBounds(SplineFont * sf,int layer,DBounds * bounds)765 void SplineFontLayerFindBounds(SplineFont *sf,int layer,DBounds *bounds) {
766 int i, k, first, last;
767
768 if ( sf->multilayer ) {
769 SplineFontFindBounds(sf,bounds);
770 return;
771 }
772
773 bounds->minx = bounds->maxx = 0;
774 bounds->miny = bounds->maxy = 0;
775
776 for ( i = 0; i<sf->glyphcnt; ++i ) {
777 SplineChar *sc = sf->glyphs[i];
778 if ( sc!=NULL ) {
779 first = last = ly_fore;
780 if ( sc->parent != NULL && sc->parent->multilayer )
781 last = sc->layer_cnt-1;
782 for ( k=first; k<=last; ++k )
783 _SplineCharLayerFindBounds(sc,k,bounds);
784 }
785 }
786 }
787
SplineFontFindBounds(SplineFont * sf,DBounds * bounds)788 void SplineFontFindBounds(SplineFont *sf,DBounds *bounds) {
789 int i, k, first, last;
790
791 bounds->minx = bounds->maxx = 0;
792 bounds->miny = bounds->maxy = 0;
793
794 for ( i = 0; i<sf->glyphcnt; ++i ) {
795 SplineChar *sc = sf->glyphs[i];
796 if ( sc!=NULL ) {
797 first = last = ly_fore;
798 if ( sf->multilayer )
799 last = sc->layer_cnt-1;
800 for ( k=first; k<=last; ++k )
801 _SplineCharLayerFindBounds(sc,k,bounds);
802 }
803 }
804 }
805
CIDLayerFindBounds(SplineFont * cidmaster,int layer,DBounds * bounds)806 void CIDLayerFindBounds(SplineFont *cidmaster,int layer,DBounds *bounds) {
807 SplineFont *sf;
808 int i;
809 DBounds b;
810 real factor;
811
812 if ( cidmaster->cidmaster )
813 cidmaster = cidmaster->cidmaster;
814 if ( cidmaster->subfonts==NULL ) {
815 SplineFontLayerFindBounds(cidmaster,layer,bounds);
816 return;
817 }
818
819 sf = cidmaster->subfonts[0];
820 SplineFontLayerFindBounds(sf,layer,bounds);
821 factor = 1000.0/(sf->ascent+sf->descent);
822 bounds->maxx *= factor; bounds->minx *= factor; bounds->miny *= factor; bounds->maxy *= factor;
823 for ( i=1; i<cidmaster->subfontcnt; ++i ) {
824 sf = cidmaster->subfonts[i];
825 SplineFontLayerFindBounds(sf,layer,&b);
826 factor = 1000.0/(sf->ascent+sf->descent);
827 b.maxx *= factor; b.minx *= factor; b.miny *= factor; b.maxy *= factor;
828 if ( b.maxx>bounds->maxx ) bounds->maxx = b.maxx;
829 if ( b.maxy>bounds->maxy ) bounds->maxy = b.maxy;
830 if ( b.miny<bounds->miny ) bounds->miny = b.miny;
831 if ( b.minx<bounds->minx ) bounds->minx = b.minx;
832 }
833 }
834
_SplineSetFindTop(SplineSet * ss,BasePoint * top)835 static void _SplineSetFindTop(SplineSet *ss,BasePoint *top) {
836 SplinePoint *sp;
837
838 for ( ; ss!=NULL; ss=ss->next ) {
839 for ( sp=ss->first; ; ) {
840 if ( sp->me.y > top->y ) *top = sp->me;
841 if ( sp->next==NULL )
842 break;
843 sp = sp->next->to;
844 if ( sp==ss->first )
845 break;
846 }
847 }
848 }
849
SplineSetQuickBounds(SplineSet * ss,DBounds * b)850 void SplineSetQuickBounds(SplineSet *ss,DBounds *b) {
851 SplinePoint *sp;
852
853 b->minx = b->miny = 1e10;
854 b->maxx = b->maxy = -1e10;
855 for ( ; ss!=NULL; ss=ss->next ) {
856 for ( sp=ss->first; ; ) {
857 if ( sp->me.y < b->miny ) b->miny = sp->me.y;
858 if ( sp->me.x < b->minx ) b->minx = sp->me.x;
859 if ( sp->me.y > b->maxy ) b->maxy = sp->me.y;
860 if ( sp->me.x > b->maxx ) b->maxx = sp->me.x;
861 // Frank added the control points to the calculation since,
862 // according to Adam Twardoch,
863 // the OpenType values that rely upon this function
864 // expect control points to be included.
865 if ( !sp->noprevcp ) {
866 if ( sp->prevcp.y < b->miny ) b->miny = sp->prevcp.y;
867 if ( sp->prevcp.x < b->minx ) b->minx = sp->prevcp.x;
868 if ( sp->prevcp.y > b->maxy ) b->maxy = sp->prevcp.y;
869 if ( sp->prevcp.x > b->maxx ) b->maxx = sp->prevcp.x;
870 }
871 if ( !sp->nonextcp ) {
872 if ( sp->nextcp.y < b->miny ) b->miny = sp->nextcp.y;
873 if ( sp->nextcp.x < b->minx ) b->minx = sp->nextcp.x;
874 if ( sp->nextcp.y > b->maxy ) b->maxy = sp->nextcp.y;
875 if ( sp->nextcp.x > b->maxx ) b->maxx = sp->nextcp.x;
876 }
877 if ( sp->next==NULL )
878 break;
879 sp = sp->next->to;
880 if ( sp==ss->first )
881 break;
882 }
883 }
884 if ( b->minx>65536 ) b->minx = 0;
885 if ( b->miny>65536 ) b->miny = 0;
886 if ( b->maxx<-65536 ) b->maxx = 0;
887 if ( b->maxy<-65536 ) b->maxy = 0;
888 }
889
SplineCharQuickBounds(SplineChar * sc,DBounds * b)890 void SplineCharQuickBounds(SplineChar *sc, DBounds *b) {
891 RefChar *ref;
892 int i,first, last;
893 DBounds temp;
894 real e;
895 ImageList *img;
896
897 b->minx = b->miny = 1e10;
898 b->maxx = b->maxy = -1e10;
899 first = last = ly_fore;
900 if ( sc->parent!=NULL && sc->parent->multilayer )
901 last = sc->layer_cnt-1;
902 for ( i=first; i<=last; ++i ) {
903 SplineSetQuickBounds(sc->layers[i].splines,&temp);
904 for ( img=sc->layers[i].images; img!=NULL; img=img->next )
905 _ImageFindBounds(img,b);
906 if ( sc->layers[i].dostroke && sc->layers[i].splines!=NULL ) {
907 if ( sc->layers[i].stroke_pen.width!=WIDTH_INHERITED )
908 e = sc->layers[i].stroke_pen.width*sc->layers[i].stroke_pen.trans[0];
909 else
910 e = sc->layers[i].stroke_pen.trans[0];
911 temp.minx -= e; temp.maxx += e;
912 temp.miny -= e; temp.maxy += e;
913 }
914 if ( temp.minx!=0 || temp.maxx != 0 || temp.maxy != 0 || temp.miny!=0 ) {
915 if ( temp.minx < b->minx ) b->minx = temp.minx;
916 if ( temp.miny < b->miny ) b->miny = temp.miny;
917 if ( temp.maxx > b->maxx ) b->maxx = temp.maxx;
918 if ( temp.maxy > b->maxy ) b->maxy = temp.maxy;
919 }
920 for ( ref = sc->layers[i].refs; ref!=NULL; ref = ref->next ) {
921 /*SplineSetQuickBounds(ref->layers[0].splines,&temp);*/
922 if ( b->minx==0 && b->maxx==0 && b->miny==0 && b->maxy == 0 )
923 *b = ref->bb;
924 else if ( ref->bb.minx!=0 || ref->bb.maxx != 0 || ref->bb.maxy != 0 || ref->bb.miny!=0 ) {
925 if ( ref->bb.minx < b->minx ) b->minx = ref->bb.minx;
926 if ( ref->bb.miny < b->miny ) b->miny = ref->bb.miny;
927 if ( ref->bb.maxx > b->maxx ) b->maxx = ref->bb.maxx;
928 if ( ref->bb.maxy > b->maxy ) b->maxy = ref->bb.maxy;
929 }
930 }
931 }
932 if ( sc->parent!=NULL && sc->parent->strokedfont &&
933 (b->minx!=b->maxx || b->miny!=b->maxy)) {
934 real sw = sc->parent->strokewidth;
935 b->minx -= sw; b->miny -= sw;
936 b->maxx += sw; b->maxy += sw;
937 }
938 if ( b->minx>1e9 )
939 memset(b,0,sizeof(*b));
940 }
941
SplineCharLayerQuickBounds(SplineChar * sc,int layer,DBounds * bounds)942 void SplineCharLayerQuickBounds(SplineChar *sc,int layer,DBounds *bounds) {
943 RefChar *ref;
944 DBounds temp;
945
946 if ( sc->parent!=NULL && sc->parent->multilayer ) {
947 SplineCharQuickBounds(sc,bounds);
948 return;
949 }
950
951 bounds->minx = bounds->miny = 1e10;
952 bounds->maxx = bounds->maxy = -1e10;
953
954 SplineSetQuickBounds(sc->layers[layer].splines,bounds);
955
956 for ( ref = sc->layers[layer].refs; ref!=NULL; ref = ref->next ) {
957 SplineSetQuickBounds(ref->layers[0].splines,&temp);
958 if ( bounds->minx==0 && bounds->maxx==0 && bounds->miny==0 && bounds->maxy == 0 )
959 *bounds = temp;
960 else if ( temp.minx!=0 || temp.maxx != 0 || temp.maxy != 0 || temp.miny!=0 ) {
961 if ( temp.minx < bounds->minx ) bounds->minx = temp.minx;
962 if ( temp.miny < bounds->miny ) bounds->miny = temp.miny;
963 if ( temp.maxx > bounds->maxx ) bounds->maxx = temp.maxx;
964 if ( temp.maxy > bounds->maxy ) bounds->maxy = temp.maxy;
965 }
966 }
967 /* a char with no splines (ie. a space) must have an lbearing of 0 */
968 if ( bounds->minx>1e9 )
969 memset(bounds,0,sizeof(*bounds));
970 }
971
SplineSetQuickConservativeBounds(SplineSet * ss,DBounds * b)972 void SplineSetQuickConservativeBounds(SplineSet *ss,DBounds *b) {
973 SplinePoint *sp;
974
975 b->minx = b->miny = 1e10;
976 b->maxx = b->maxy = -1e10;
977 for ( ; ss!=NULL; ss=ss->next ) {
978 for ( sp=ss->first; ; ) {
979 if ( sp->me.y < b->miny ) b->miny = sp->me.y;
980 if ( sp->me.x < b->minx ) b->minx = sp->me.x;
981 if ( sp->me.y > b->maxy ) b->maxy = sp->me.y;
982 if ( sp->me.x > b->maxx ) b->maxx = sp->me.x;
983 if ( sp->nextcp.y < b->miny ) b->miny = sp->nextcp.y;
984 if ( sp->nextcp.x < b->minx ) b->minx = sp->nextcp.x;
985 if ( sp->nextcp.y > b->maxy ) b->maxy = sp->nextcp.y;
986 if ( sp->nextcp.x > b->maxx ) b->maxx = sp->nextcp.x;
987 if ( sp->prevcp.y < b->miny ) b->miny = sp->prevcp.y;
988 if ( sp->prevcp.x < b->minx ) b->minx = sp->prevcp.x;
989 if ( sp->prevcp.y > b->maxy ) b->maxy = sp->prevcp.y;
990 if ( sp->prevcp.x > b->maxx ) b->maxx = sp->prevcp.x;
991 if ( sp->next==NULL )
992 break;
993 sp = sp->next->to;
994 if ( sp==ss->first )
995 break;
996 }
997 }
998 if ( b->minx>65536 ) b->minx = 0;
999 if ( b->miny>65536 ) b->miny = 0;
1000 if ( b->maxx<-65536 ) b->maxx = 0;
1001 if ( b->maxy<-65536 ) b->maxy = 0;
1002 }
1003
SplineCharQuickConservativeBounds(SplineChar * sc,DBounds * b)1004 void SplineCharQuickConservativeBounds(SplineChar *sc, DBounds *b) {
1005 RefChar *ref;
1006 int i, first,last;
1007 DBounds temp;
1008 real e;
1009 ImageList *img;
1010
1011 memset(b,0,sizeof(*b));
1012 first = last = ly_fore;
1013 if ( sc->parent!=NULL && sc->parent->multilayer )
1014 last = sc->layer_cnt-1;
1015 for ( i=first; i<=last; ++i ) {
1016 SplineSetQuickConservativeBounds(sc->layers[i].splines,&temp);
1017 for ( img=sc->layers[i].images; img!=NULL; img=img->next )
1018 _ImageFindBounds(img,b);
1019 if ( sc->layers[i].dostroke && sc->layers[i].splines!=NULL ) {
1020 if ( sc->layers[i].stroke_pen.width!=WIDTH_INHERITED )
1021 e = sc->layers[i].stroke_pen.width*sc->layers[i].stroke_pen.trans[0];
1022 else
1023 e = sc->layers[i].stroke_pen.trans[0];
1024 temp.minx -= e; temp.maxx += e;
1025 temp.miny -= e; temp.maxy += e;
1026 }
1027 if ( temp.minx!=0 || temp.maxx != 0 || temp.maxy != 0 || temp.miny!=0 ) {
1028 if ( temp.minx < b->minx ) b->minx = temp.minx;
1029 if ( temp.miny < b->miny ) b->miny = temp.miny;
1030 if ( temp.maxx > b->maxx ) b->maxx = temp.maxx;
1031 if ( temp.maxy > b->maxy ) b->maxy = temp.maxy;
1032 }
1033 for ( ref = sc->layers[i].refs; ref!=NULL; ref = ref->next ) {
1034 /*SplineSetQuickConservativeBounds(ref->layers[0].splines,&temp);*/
1035 if ( b->minx==0 && b->maxx==0 && b->miny==0 && b->maxy == 0 )
1036 *b = ref->bb;
1037 else if ( ref->bb.minx!=0 || ref->bb.maxx != 0 || ref->bb.maxy != 0 || ref->bb.miny!=0 ) {
1038 if ( ref->bb.minx < b->minx ) b->minx = ref->bb.minx;
1039 if ( ref->bb.miny < b->miny ) b->miny = ref->bb.miny;
1040 if ( ref->bb.maxx > b->maxx ) b->maxx = ref->bb.maxx;
1041 if ( ref->bb.maxy > b->maxy ) b->maxy = ref->bb.maxy;
1042 }
1043 }
1044 }
1045 if ( sc->parent->strokedfont && (b->minx!=b->maxx || b->miny!=b->maxy)) {
1046 real sw = sc->parent->strokewidth;
1047 b->minx -= sw; b->miny -= sw;
1048 b->maxx += sw; b->maxy += sw;
1049 }
1050 }
1051
SplineFontQuickConservativeBounds(SplineFont * sf,DBounds * b)1052 void SplineFontQuickConservativeBounds(SplineFont *sf,DBounds *b) {
1053 DBounds bb;
1054 int i;
1055
1056 b->minx = b->miny = 1e10;
1057 b->maxx = b->maxy = -1e10;
1058 for ( i=0; i<sf->glyphcnt; ++i ) if ( sf->glyphs[i]!=NULL ) {
1059 SplineCharQuickConservativeBounds(sf->glyphs[i],&bb);
1060 if ( bb.minx < b->minx ) b->minx = bb.minx;
1061 if ( bb.miny < b->miny ) b->miny = bb.miny;
1062 if ( bb.maxx > b->maxx ) b->maxx = bb.maxx;
1063 if ( bb.maxy > b->maxy ) b->maxy = bb.maxy;
1064 }
1065 if ( b->minx>65536 ) b->minx = 0;
1066 if ( b->miny>65536 ) b->miny = 0;
1067 if ( b->maxx<-65536 ) b->maxx = 0;
1068 if ( b->maxy<-65536 ) b->maxy = 0;
1069 }
1070
SplinePointCategory(SplinePoint * sp)1071 static int SplinePointCategory(SplinePoint *sp) {
1072 enum pointtype pt;
1073
1074 pt = pt_corner;
1075 if ( sp->next==NULL && sp->prev==NULL )
1076 ;
1077 else if ( (sp->next!=NULL && sp->next->to->me.x==sp->me.x && sp->next->to->me.y==sp->me.y) ||
1078 (sp->prev!=NULL && sp->prev->from->me.x==sp->me.x && sp->prev->from->me.y==sp->me.y ))
1079 ;
1080 else if ( sp->next==NULL ) {
1081 pt = sp->noprevcp ? pt_corner : pt_curve;
1082 } else if ( sp->prev==NULL ) {
1083 pt = sp->nonextcp ? pt_corner : pt_curve;
1084 } else if ( sp->nonextcp && sp->noprevcp ) {
1085 ;
1086 } else {
1087 BasePoint ndir, ncdir, ncunit, pdir, pcdir, pcunit;
1088 bigreal nlen, nclen, plen, pclen;
1089 bigreal cross, bounds;
1090
1091 ncdir.x = sp->nextcp.x - sp->me.x; ncdir.y = sp->nextcp.y - sp->me.y;
1092 pcdir.x = sp->prevcp.x - sp->me.x; pcdir.y = sp->prevcp.y - sp->me.y;
1093 ndir.x = ndir.y = pdir.x = pdir.y = 0;
1094 if ( sp->next!=NULL ) {
1095 ndir.x = sp->next->to->me.x - sp->me.x; ndir.y = sp->next->to->me.y - sp->me.y;
1096 }
1097 if ( sp->prev!=NULL ) {
1098 pdir.x = sp->prev->from->me.x - sp->me.x; pdir.y = sp->prev->from->me.y - sp->me.y;
1099 }
1100 nclen = sqrt(ncdir.x*ncdir.x + ncdir.y*ncdir.y);
1101 pclen = sqrt(pcdir.x*pcdir.x + pcdir.y*pcdir.y);
1102 nlen = sqrt(ndir.x*ndir.x + ndir.y*ndir.y);
1103 plen = sqrt(pdir.x*pdir.x + pdir.y*pdir.y);
1104 ncunit = ncdir; pcunit = pcdir;
1105 if ( nclen!=0 ) { ncunit.x /= nclen; ncunit.y /= nclen; }
1106 if ( pclen!=0 ) { pcunit.x /= pclen; pcunit.y /= pclen; }
1107 if ( nlen!=0 ) { ndir.x /= nlen; ndir.y /= nlen; }
1108 if ( plen!=0 ) { pdir.x /= plen; pdir.y /= plen; }
1109
1110 /* find out which side has the shorter control vector. Cross that vector */
1111 /* with the normal of the unit vector on the other side. If the */
1112 /* result is less than 1 em-unit then we've got colinear control points */
1113 /* (within the resolution of the integer grid) */
1114 /* Not quite... they could point in the same direction */
1115 if ( sp->pointtype==pt_curve )
1116 bounds = 4.0;
1117 else
1118 bounds = 1.0;
1119 if ( nclen!=0 && pclen!=0 &&
1120 ((nclen>=pclen && (cross = pcdir.x*ncunit.y - pcdir.y*ncunit.x)<bounds && cross>-bounds ) ||
1121 (pclen>nclen && (cross = ncdir.x*pcunit.y - ncdir.y*pcunit.x)<bounds && cross>-bounds )) &&
1122 ncdir.x*pcdir.x + ncdir.y*pcdir.y < 0 )
1123 pt = pt_curve;
1124 /* Cross product of control point with unit vector normal to line in */
1125 /* opposite direction should be less than an em-unit for a tangent */
1126 else if ( ( nclen==0 && pclen!=0
1127 && (cross = pcdir.x*ndir.y-pcdir.y*ndir.x)<bounds
1128 && cross>-bounds && (pcdir.x*ndir.x+pcdir.y*ndir.y)<0 )
1129 ||
1130 ( pclen==0 && nclen!=0
1131 && (cross = ncdir.x*pdir.y-ncdir.y*pdir.x)<bounds
1132 && cross>-bounds && (ncdir.x*pdir.x+ncdir.y*pdir.y)<0 ) )
1133 pt = pt_tangent;
1134
1135 if (pt == pt_curve &&
1136 ((sp->nextcp.x==sp->me.x && sp->prevcp.x==sp->me.x && sp->nextcp.y!=sp->me.y) ||
1137 (sp->nextcp.y==sp->me.y && sp->prevcp.y==sp->me.y && sp->nextcp.x!=sp->me.x)))
1138 pt = pt_hvcurve;
1139 }
1140 return pt;
1141 }
1142
SplinePointIsACorner(SplinePoint * sp)1143 int SplinePointIsACorner(SplinePoint *sp) {
1144 return SplinePointCategory(sp) == pt_corner;
1145 }
1146
SplinePointDowngrade(int current,int geom)1147 static enum pointtype SplinePointDowngrade(int current, int geom) {
1148 enum pointtype np = current;
1149
1150 if ( current==pt_curve && geom!=pt_curve ) {
1151 if ( geom==pt_hvcurve )
1152 np = pt_curve;
1153 else
1154 np = pt_corner;
1155 } else if ( current==pt_hvcurve && geom!=pt_hvcurve ) {
1156 if ( geom==pt_curve )
1157 np = pt_curve;
1158 else
1159 np = pt_corner;
1160 } else if ( current==pt_tangent && geom!=pt_tangent ) {
1161 np = pt_corner;
1162 }
1163
1164 return np;
1165 }
1166
1167 // Assumes flag combinations are already verified. Only returns false
1168 // when called with check_compat
_SplinePointCategorize(SplinePoint * sp,int flags)1169 int _SplinePointCategorize(SplinePoint *sp, int flags) {
1170 enum pointtype geom, dg, cur;
1171
1172 if ( flags & pconvert_flag_none )
1173 // No points selected for conversion -- keep type as is
1174 return true;
1175 if ( flags & pconvert_flag_smooth && sp->pointtype == pt_corner )
1176 // Convert only "smooth" points, not corners
1177 return true;
1178
1179 geom = SplinePointCategory(sp);
1180 dg = SplinePointDowngrade(sp->pointtype, geom);
1181
1182 if ( flags & pconvert_flag_incompat && sp->pointtype == dg )
1183 // Only convert points incompatible with current type
1184 return true;
1185
1186 if ( flags & pconvert_flag_by_geom ) {
1187 if ( ! ( flags & pconvert_flag_hvcurve ) && geom == pt_hvcurve )
1188 sp->pointtype = pt_curve;
1189 else
1190 sp->pointtype = geom;
1191 } else if ( flags & pconvert_flag_downgrade ) {
1192 sp->pointtype = dg;
1193 } else if ( flags & pconvert_flag_force_type ) {
1194 if ( sp->pointtype != dg ) {
1195 cur = sp->pointtype;
1196 sp->pointtype = dg;
1197 SPChangePointType(sp,cur);
1198 }
1199 } else if ( flags & pconvert_flag_check_compat ) {
1200 if ( sp->pointtype != dg )
1201 return false;
1202 }
1203 return true;
1204 }
1205
SplinePointCategorize(SplinePoint * sp)1206 void SplinePointCategorize(SplinePoint *sp) {
1207 _SplinePointCategorize(sp, pconvert_flag_all|pconvert_flag_by_geom);
1208 }
1209
1210 // _SplinePointCategorize only returns false when called with check_compat flag,
1211 // in which case no point values are altered and the "early" return will not leave
1212 // splines partially adjusted.
_SPLCategorizePoints(SplinePointList * spl,int flags)1213 int _SPLCategorizePoints(SplinePointList *spl, int flags) {
1214 Spline *spline, *first, *last=NULL;
1215 int ok = true;
1216
1217 for ( ; spl!=NULL; spl = spl->next ) {
1218 first = NULL;
1219 for ( spline = spl->first->next; spline!=NULL && spline!=first && ok; spline=spline->to->next ) {
1220 ok = _SplinePointCategorize(spline->from, flags);
1221 last = spline;
1222 if ( first==NULL ) first = spline;
1223 }
1224 if ( spline==NULL && last!=NULL && ok )
1225 _SplinePointCategorize(last->to, flags);
1226 }
1227 return ok;
1228 }
1229
SPLCategorizePoints(SplinePointList * spl)1230 void SPLCategorizePoints(SplinePointList *spl) {
1231 _SPLCategorizePoints(spl, pconvert_flag_all|pconvert_flag_by_geom);
1232 }
1233
SCCategorizePoints(SplineChar * sc)1234 void SCCategorizePoints(SplineChar *sc) {
1235 int i;
1236 for ( i=ly_fore; i<sc->layer_cnt; ++i )
1237 SPLCategorizePoints(sc->layers[i].splines);
1238 }
1239
CharsNotInEncoding(FontDict * fd)1240 static int CharsNotInEncoding(FontDict *fd) {
1241 int i, cnt, j;
1242
1243 for ( i=cnt=0; i<fd->chars->cnt; ++i ) {
1244 if ( fd->chars->keys[i]!=NULL ) {
1245 for ( j=0; j<256; ++j )
1246 if ( fd->encoding[j]!=NULL &&
1247 strcmp(fd->encoding[j],fd->chars->keys[i])==0 )
1248 break;
1249 if ( j==256 )
1250 ++cnt;
1251 }
1252 }
1253 /* And for type 3 fonts... */
1254 if ( fd->charprocs!=NULL ) for ( i=0; i<fd->charprocs->cnt; ++i ) {
1255 if ( fd->charprocs->keys[i]!=NULL ) {
1256 for ( j=0; j<256; ++j )
1257 if ( fd->encoding[j]!=NULL &&
1258 strcmp(fd->encoding[j],fd->charprocs->keys[i])==0 )
1259 break;
1260 if ( j==256 )
1261 ++cnt;
1262 }
1263 }
1264 return( cnt );
1265 }
1266
LookupCharString(char * encname,struct pschars * chars)1267 static int LookupCharString(char *encname,struct pschars *chars) {
1268 int k;
1269
1270 if ( encname==NULL ) encname = ".notdef"; /* In case of an incomplete encoding array */
1271
1272 for ( k=0; k<chars->cnt; ++k ) {
1273 if ( chars->keys[k]!=NULL )
1274 if ( strcmp(encname,chars->keys[k])==0 )
1275 return( k );
1276 }
1277 return( -1 );
1278 }
1279
SplinePointListCopy1(const SplinePointList * spl)1280 SplinePointList *SplinePointListCopy1(const SplinePointList *spl) {
1281 SplinePointList *cur;
1282 const SplinePoint *pt; SplinePoint *cpt;
1283 Spline *spline;
1284
1285 cur = chunkalloc(sizeof(SplinePointList));
1286 cur->is_clip_path = spl->is_clip_path;
1287 cur->spiro_cnt = cur->spiro_max = 0;
1288 cur->spiros = 0;
1289 if (spl->contour_name != NULL) cur->contour_name = copy(spl->contour_name);
1290 for ( pt=spl->first; ; ) {
1291 cpt = SplinePointCreate( 0, 0 );
1292 *cpt = *pt;
1293 if ( pt->hintmask!=NULL ) {
1294 cpt->hintmask = chunkalloc(sizeof(HintMask));
1295 memcpy(cpt->hintmask,pt->hintmask,sizeof(HintMask));
1296 }
1297 if ( pt->name!=NULL ) {
1298 cpt->name = copy(pt->name);
1299 }
1300 cpt->next = cpt->prev = NULL;
1301 if ( cur->first==NULL ) {
1302 cur->first = cur->last = cpt;
1303 cur->start_offset = 0;
1304 } else {
1305 spline = chunkalloc(sizeof(Spline));
1306 *spline = *pt->prev;
1307 spline->from = cur->last;
1308 cur->last->next = spline;
1309 cpt->prev = spline;
1310 spline->to = cpt;
1311 spline->approx = NULL;
1312 cur->last = cpt;
1313 }
1314 if ( pt->next==NULL )
1315 break;
1316 pt = pt->next->to;
1317 if ( pt==spl->first )
1318 break;
1319 }
1320 if ( spl->first->prev!=NULL ) {
1321 cpt = cur->first;
1322 spline = chunkalloc(sizeof(Spline));
1323 *spline = *pt->prev;
1324 spline->from = cur->last;
1325 cur->last->next = spline;
1326 cpt->prev = spline;
1327 spline->to = cpt;
1328 spline->approx = NULL;
1329 cur->last = cpt;
1330 }
1331 if ( spl->spiro_cnt!=0 ) {
1332 cur->spiro_cnt = cur->spiro_max = spl->spiro_cnt;
1333 cur->spiros = malloc(cur->spiro_cnt*sizeof(spiro_cp));
1334 memcpy(cur->spiros,spl->spiros,cur->spiro_cnt*sizeof(spiro_cp));
1335 }
1336 return( cur );
1337 }
1338
1339 /* If this routine is called we are guarenteed that:
1340 at least one point on the splineset is selected
1341 not all points on the splineset are selected
1342 */
SplinePointListCopySelected1(SplinePointList * spl)1343 static SplinePointList *SplinePointListCopySelected1(SplinePointList *spl) {
1344 SplinePointList *head=NULL, *last=NULL, *cur;
1345 SplinePoint *cpt, *first, *start;
1346 Spline *spline;
1347
1348 start = spl->first;
1349 if ( spl->first==spl->last ) {
1350 /* If it's a closed contour and the start point is selected then we */
1351 /* don't know where that selection began (and we have to keep it with */
1352 /* the things that precede it when we make the new splinesets), so */
1353 /* loop until we find something unselected */
1354 while ( start->selected )
1355 start = start->next->to;
1356 }
1357 first = NULL;
1358 while ( start != NULL && start!=first ) {
1359 while ( start!=NULL && start!=first && !start->selected ) {
1360 if ( first==NULL ) first = start;
1361 if ( start->next==NULL ) {
1362 start = NULL;
1363 break;
1364 }
1365 start = start->next->to;
1366 }
1367 if ( start==NULL || start==first )
1368 break;
1369 cur = chunkalloc(sizeof(SplinePointList));
1370 if ( head==NULL )
1371 head = cur;
1372 else
1373 last->next = cur;
1374 last = cur;
1375
1376 while ( start!=NULL && start->selected && start!=first ) {
1377 cpt = chunkalloc(sizeof(SplinePoint));
1378 *cpt = *start;
1379 cpt->hintmask = NULL;
1380 cpt->name = NULL;
1381 cpt->next = cpt->prev = NULL;
1382 if ( cur->first==NULL ) {
1383 cur->first = cur->last = cpt;
1384 cur->start_offset = 0;
1385 } else {
1386 spline = chunkalloc(sizeof(Spline));
1387 *spline = *start->prev;
1388 spline->from = cur->last;
1389 cur->last->next = spline;
1390 cpt->prev = spline;
1391 spline->to = cpt;
1392 spline->approx = NULL;
1393 cur->last = cpt;
1394 }
1395 if ( first==NULL ) first = start;
1396 if ( start->next==NULL ) {
1397 start = NULL;
1398 break;
1399 }
1400 start = start->next->to;
1401 }
1402 }
1403 return( head );
1404 }
1405
1406 /* If this routine is called we are guarenteed that:
1407 at least one point on the splineset is selected
1408 not all points on the splineset are selected
1409 */
SplinePointListCopySpiroSelected1(SplinePointList * spl)1410 static SplinePointList *SplinePointListCopySpiroSelected1(SplinePointList *spl) {
1411 SplinePointList *head=NULL, *last=NULL, *cur;
1412 int i,j;
1413 spiro_cp *list = spl->spiros, *freeme = NULL, *temp = NULL;
1414
1415 if ( !SPIRO_SPL_OPEN(spl)) {
1416 /* If it's a closed contour and the start point is selected then we */
1417 /* don't know where that selection began (and we have to keep it with */
1418 /* the things that precede it when we make the new splinesets), so */
1419 /* loop until we find something unselected */
1420 for ( i=0 ; i<spl->spiro_cnt-1; ++i )
1421 if ( !(SPIRO_SELECTED(&list[i])) )
1422 break;
1423 if ( i!=0 ) {
1424 freeme = malloc(spl->spiro_cnt*sizeof(spiro_cp));
1425 memcpy(freeme,list+i,(spl->spiro_cnt-1-i)*sizeof(spiro_cp));
1426 memcpy(freeme+(spl->spiro_cnt-1-i),list,i*sizeof(spiro_cp));
1427 /* And copy the list terminator */
1428 memcpy(freeme+spl->spiro_cnt-1,list+spl->spiro_cnt-1,sizeof(spiro_cp));
1429 list = freeme;
1430 }
1431 }
1432 for ( i=0 ; i<spl->spiro_cnt-1; ) {
1433 /* Skip unselected things */
1434 for ( ; i<spl->spiro_cnt-1 && !SPIRO_SELECTED(&list[i]); ++i );
1435 if ( i==spl->spiro_cnt-1 )
1436 break;
1437 for ( j=i; j<spl->spiro_cnt-1 && SPIRO_SELECTED(&list[j]); ++j );
1438 temp = malloc((j-i+2)*sizeof(spiro_cp));
1439 memcpy(temp,list+i,(j-i)*sizeof(spiro_cp));
1440 temp[0].ty = SPIRO_OPEN_CONTOUR;
1441 memset(temp+(j-i),0,sizeof(spiro_cp));
1442 temp[j-i].ty = SPIRO_END;
1443 cur = SpiroCP2SplineSet( temp );
1444 if ( head==NULL )
1445 head = cur;
1446 else
1447 last->next = cur;
1448 last = cur;
1449 i = j;
1450 }
1451 return( head );
1452 }
1453
SplinePointListCheckSelected1(const SplinePointList * base,bool spiro,bool * allsel,bool skip_spiro_end)1454 bool SplinePointListCheckSelected1(const SplinePointList *base, bool spiro, bool *allsel, bool skip_spiro_end) {
1455 bool anysel = false;
1456 if (allsel) {
1457 *allsel = true;
1458 }
1459 if (spiro) {
1460 for (int i = 0; i < base->spiro_cnt-(skip_spiro_end?1:0); ++i) {
1461 if (SPIRO_SELECTED(&base->spiros[i])) {
1462 anysel = true;
1463 if (!allsel) {
1464 return anysel;
1465 }
1466 } else if (allsel) {
1467 *allsel = false;
1468 }
1469 }
1470 } else {
1471 SplinePoint *first = NULL, *pt;
1472 for (pt = base->first; pt != NULL && pt != first; pt = pt->next->to) {
1473 if (pt->selected) {
1474 anysel = true;
1475 if (!allsel) {
1476 return anysel;
1477 }
1478 } else if (allsel) {
1479 *allsel = false;
1480 }
1481 if (first == NULL)
1482 first = pt;
1483 if (pt->next == NULL)
1484 break;
1485 }
1486 }
1487 return anysel;
1488 }
1489
SplinePointListCopy(const SplinePointList * base)1490 SplinePointList *SplinePointListCopy(const SplinePointList *base) {
1491 SplinePointList *head=NULL, *last=NULL, *cur;
1492
1493 for ( ; base!=NULL; base = base->next ) {
1494 cur = SplinePointListCopy1(base);
1495 if ( head==NULL )
1496 head = cur;
1497 else
1498 last->next = cur;
1499 last = cur;
1500 }
1501 return( head );
1502 }
1503
SplinePointListCopySelected(SplinePointList * base)1504 SplinePointList *SplinePointListCopySelected(SplinePointList *base) {
1505 SplinePointList *head=NULL, *last=NULL, *cur=NULL;
1506 SplinePoint *pt, *first;
1507 bool anysel, allsel;
1508
1509 for ( ; base!=NULL; base = base->next ) {
1510 anysel = SplinePointListCheckSelected1(base, false, &allsel, false);
1511 if ( allsel )
1512 cur = SplinePointListCopy1(base);
1513 else if ( anysel )
1514 cur = SplinePointListCopySelected1(base);
1515 if ( anysel ) {
1516 if ( head==NULL )
1517 head = cur;
1518 else
1519 last->next = cur;
1520 for ( last = cur; last->next ; last = last->next );
1521 }
1522 }
1523 return( head );
1524 }
1525
SplinePointListCopySpiroSelected(SplinePointList * base)1526 SplinePointList *SplinePointListCopySpiroSelected(SplinePointList *base) {
1527 SplinePointList *head=NULL, *last=NULL, *cur=NULL;
1528 bool anysel, allsel;
1529 int i;
1530
1531 for ( ; base!=NULL; base = base->next ) {
1532 anysel = SplinePointListCheckSelected1(base, true, &allsel, true);
1533 if ( allsel )
1534 cur = SplinePointListCopy1(base);
1535 else if ( anysel )
1536 cur = SplinePointListCopySpiroSelected1(base);
1537 if ( anysel ) {
1538 if ( head==NULL )
1539 head = cur;
1540 else
1541 last->next = cur;
1542 for ( last = cur; last->next ; last = last->next );
1543 }
1544 }
1545 return( head );
1546 }
1547
SplinePointListSplitSpiros(SplineChar * sc,SplinePointList * spl)1548 static SplinePointList *SplinePointListSplitSpiros(SplineChar *sc,SplinePointList *spl) {
1549 SplinePointList *head=NULL, *last=NULL, *cur;
1550 int i;
1551 spiro_cp *list = spl->spiros, *freeme = NULL, *temp = NULL;
1552
1553 if ( !SPIRO_SPL_OPEN(spl)) {
1554 /* If it's a closed contour and the start point is selected then we */
1555 /* don't know where that selection began (and we have to keep it with */
1556 /* the things that precede it when we make the new splinesets), so */
1557 /* loop until we find something unselected */
1558 for ( i=0 ; i<spl->spiro_cnt-1; ++i )
1559 if ( !(SPIRO_SELECTED(&list[i])) )
1560 break;
1561 if ( i!=0 ) {
1562 freeme = malloc(spl->spiro_cnt*sizeof(spiro_cp));
1563 memcpy(freeme,list+i,(spl->spiro_cnt-1-i)*sizeof(spiro_cp));
1564 memcpy(freeme+(spl->spiro_cnt-1-i),list,i*sizeof(spiro_cp));
1565 /* And copy the list terminator */
1566 memcpy(freeme+spl->spiro_cnt-1,list+spl->spiro_cnt-1,sizeof(spiro_cp));
1567 list = freeme;
1568 }
1569 }
1570 for ( i=0 ; i<spl->spiro_cnt-1; ) {
1571 int start = i;
1572 /* Retain unselected things */
1573 for ( ; i<spl->spiro_cnt-1 && !SPIRO_SELECTED(&list[i]); ++i );
1574 if ( i!=start ) {
1575 temp = malloc((i-start+2)*sizeof(spiro_cp));
1576 memcpy(temp,list+start,(i-start)*sizeof(spiro_cp));
1577 temp[0].ty = SPIRO_OPEN_CONTOUR;
1578 memset(temp+(i-start),0,sizeof(spiro_cp));
1579 temp[i-start].ty = SPIRO_END;
1580 cur = SpiroCP2SplineSet( temp );
1581 if ( head==NULL )
1582 head = cur;
1583 else
1584 last->next = cur;
1585 last = cur;
1586 }
1587 for ( ; i<spl->spiro_cnt-1 && SPIRO_SELECTED(&list[i]); ++i );
1588 }
1589 SplinePointListFree(spl);
1590 return( head );
1591 }
1592
SplinePointListSplit(SplineChar * sc,SplinePointList * spl)1593 static SplinePointList *SplinePointListSplit(SplineChar *sc,SplinePointList *spl) {
1594 SplinePointList *head=NULL, *last=NULL, *cur;
1595 SplinePoint *first, *start, *next;
1596
1597 start = spl->first;
1598 if ( spl->first==spl->last ) {
1599 /* If it's a closed contour and the start point is selected then we */
1600 /* don't know where that selection began (and we have to keep it with */
1601 /* the things that precede it when we make the new splinesets), so */
1602 /* loop until we find something unselected */
1603 while ( !start->selected )
1604 start = start->next->to;
1605 }
1606 first = NULL;
1607 while ( start != NULL && start!=first ) {
1608 while ( start!=NULL && start!=first && start->selected ) {
1609 if ( first==NULL ) first = start;
1610 if ( start->prev!=NULL ) {
1611 start->prev->from->next = NULL;
1612 SplineFree(start->prev);
1613 }
1614 if ( start->next!=NULL ) {
1615 next = start->next->to;
1616 next->prev = NULL;
1617 SplineFree(start->next);
1618 } else
1619 next = NULL;
1620 SplinePointMDFree(sc,start);
1621 start = next;
1622 }
1623 if ( start==NULL || start==first )
1624 break;
1625 if ( head==NULL ) {
1626 head = cur = spl;
1627 spl->first = spl->last = NULL;
1628 spl->start_offset = 0;
1629 } else {
1630 cur = chunkalloc(sizeof(SplinePointList));
1631 last->next = cur;
1632 }
1633 last = cur;
1634
1635 while ( start!=NULL && !start->selected && start!=first ) {
1636 if ( cur->first==NULL ) {
1637 cur->first = start;
1638 cur->start_offset = 0;
1639 }
1640 cur->last = start;
1641 if ( start->next!=NULL ) {
1642 next = start->next->to;
1643 if ( next->selected ) {
1644 SplineFree(start->next);
1645 start->next = NULL;
1646 next->prev = NULL;
1647 }
1648 } else
1649 next = NULL;
1650 if ( first==NULL ) first = start;
1651 start = next;
1652 }
1653 }
1654 return( last );
1655 }
1656
SplinePointListRemoveSelected(SplineChar * sc,SplinePointList * base)1657 SplinePointList *SplinePointListRemoveSelected(SplineChar *sc,SplinePointList *base) {
1658 SplinePointList *head=NULL, *last=NULL, *next;
1659 SplinePoint *pt, *first;
1660 bool anysel, allsel;
1661
1662 for ( ; base!=NULL; base = next ) {
1663 next = base->next;
1664 anysel = SplinePointListCheckSelected1(base, sc->inspiro && hasspiro(), &allsel, false);
1665 if ( allsel ) {
1666 SplinePointListMDFree(sc,base);
1667 continue;
1668 }
1669 if ( !sc->inspiro || !anysel || !hasspiro()) {
1670 if ( head==NULL )
1671 head = base;
1672 else
1673 last->next = base;
1674 last = base;
1675 if ( anysel )
1676 last = SplinePointListSplit(sc,base);
1677 } else {
1678 SplineSet *ret;
1679 ret = SplinePointListSplitSpiros(sc,base);
1680 if ( head==NULL )
1681 head = ret;
1682 else
1683 last->next = ret;
1684 if ( ret!=NULL )
1685 for ( last=ret; last->next!=NULL; last=last->next );
1686 }
1687 }
1688 if ( last!=NULL ) last->next = NULL;
1689 return( head );
1690 }
1691
ImageListCopy(ImageList * cimg)1692 ImageList *ImageListCopy(ImageList *cimg) {
1693 ImageList *head=NULL, *last=NULL, *new;
1694
1695 for ( ; cimg!=NULL; cimg=cimg->next ) {
1696 new = chunkalloc(sizeof(ImageList));
1697 *new = *cimg;
1698 new->next = NULL;
1699 if ( last==NULL )
1700 head = last = new;
1701 else {
1702 last->next = new;
1703 last = new;
1704 }
1705 }
1706 return( head );
1707 }
1708
ImageListTransform(ImageList * img,real transform[6],int everything)1709 ImageList *ImageListTransform(ImageList *img, real transform[6],int everything) {
1710 ImageList *head = img;
1711
1712 /* Don't support rotating, flipping or skewing images */;
1713 if ( transform[0]!=0 && transform[3]!=0 ) {
1714 while ( img!=NULL ) {
1715 if ( everything || (!everything && img->selected)) {
1716 bigreal x = img->xoff;
1717 img->xoff = transform[0]*x + transform[2]*img->yoff + transform[4];
1718 img->yoff = transform[1]*x + transform[3]*img->yoff + transform[5];
1719 if (( img->xscale *= transform[0])<0 ) {
1720 img->xoff += img->xscale *
1721 (img->image->list_len==0?img->image->u.image:img->image->u.images[0])->width;
1722 img->xscale = -img->xscale;
1723 }
1724 if (( img->yscale *= transform[3])<0 ) {
1725 img->yoff += img->yscale *
1726 (img->image->list_len==0?img->image->u.image:img->image->u.images[0])->height;
1727 img->yscale = -img->yscale;
1728 }
1729 img->bb.minx = img->xoff; img->bb.maxy = img->yoff;
1730 img->bb.maxx = img->xoff + GImageGetWidth(img->image)*img->xscale;
1731 img->bb.miny = img->yoff - GImageGetHeight(img->image)*img->yscale;
1732 }
1733 img = img->next;
1734 }
1735 }
1736 return( head );
1737 }
1738
_BpTransform(BasePoint * to,BasePoint * from,real transform[6],enum transformPointMask tpmask)1739 static void _BpTransform(BasePoint *to, BasePoint *from, real transform[6], enum transformPointMask tpmask) {
1740 BasePoint p;
1741 p.x = transform[0]*from->x + transform[2]*from->y + transform[4];
1742 p.y = transform[1]*from->x + transform[3]*from->y + transform[5];
1743 if ( ! (tpmask & tpmask_dontTrimValues ) ) {
1744 to->x = rint(1024*p.x)/1024;
1745 to->y = rint(1024*p.y)/1024;
1746 } else {
1747 to->x = p.x;
1748 to->y = p.y;
1749 }
1750 }
1751
BpTransform(BasePoint * to,BasePoint * from,real transform[6])1752 void BpTransform(BasePoint *to, BasePoint *from, real transform[6]) {
1753 _BpTransform(to, from, transform, 0);
1754 }
1755
ApTransform(AnchorPoint * ap,real transform[6])1756 void ApTransform(AnchorPoint *ap, real transform[6]) {
1757 BpTransform(&ap->me,&ap->me,transform);
1758 }
1759
TransformPointExtended(SplinePoint * sp,real transform[6],enum transformPointMask tpmask)1760 static void TransformPointExtended(SplinePoint *sp, real transform[6], enum transformPointMask tpmask )
1761 {
1762 /**
1763 * If we are to transform selected BCP instead of their base splinepoint
1764 * then lets do that.
1765 */
1766 if( tpmask & tpmask_operateOnSelectedBCP
1767 && (sp->nextcpselected || sp->prevcpselected ))
1768 {
1769 if( sp->nextcpselected )
1770 {
1771 int order2 = sp->next ? sp->next->order2 : 0;
1772 _BpTransform(&sp->nextcp,&sp->nextcp,transform,tpmask);
1773 SPTouchControl( sp, &sp->nextcp, order2 );
1774 }
1775 else if( sp->prevcpselected )
1776 {
1777 int order2 = sp->next ? sp->next->order2 : 0;
1778 _BpTransform(&sp->prevcp,&sp->prevcp,transform,tpmask);
1779 SPTouchControl( sp, &sp->prevcp, order2 );
1780 }
1781 }
1782 else
1783 {
1784 /**
1785 * Transform the base splinepoints.
1786 */
1787 _BpTransform(&sp->me,&sp->me,transform,tpmask);
1788
1789 if ( !sp->nonextcp )
1790 {
1791 _BpTransform(&sp->nextcp,&sp->nextcp,transform,tpmask);
1792 }
1793 else
1794 {
1795 sp->nextcp = sp->me;
1796 }
1797
1798 if ( !sp->noprevcp )
1799 {
1800 _BpTransform(&sp->prevcp,&sp->prevcp,transform,tpmask);
1801 }
1802 else
1803 {
1804 sp->prevcp = sp->me;
1805 }
1806 }
1807
1808
1809
1810 if ( sp->pointtype == pt_hvcurve )
1811 {
1812 if(
1813 ((sp->nextcp.x==sp->me.x && sp->prevcp.x==sp->me.x && sp->nextcp.y!=sp->me.y) ||
1814 (sp->nextcp.y==sp->me.y && sp->prevcp.y==sp->me.y && sp->nextcp.x!=sp->me.x)))
1815 {
1816 /* Do Nothing */;
1817 }
1818 else
1819 {
1820 sp->pointtype = pt_curve;
1821 }
1822 }
1823 }
1824
TransformPoint(SplinePoint * sp,real transform[6])1825 static void TransformPoint(SplinePoint *sp, real transform[6])
1826 {
1827 TransformPointExtended( sp, transform, 0 );
1828 }
1829
TransformSpiro(spiro_cp * cp,real transform[6])1830 static void TransformSpiro(spiro_cp *cp, real transform[6]) {
1831 bigreal x;
1832
1833 x = transform[0]*cp->x + transform[2]*cp->y + transform[4];
1834 cp->y = transform[1]*cp->x + transform[3]*cp->y + transform[5];
1835 cp->x = x;
1836 }
1837
TransformPTsInterpolateCPs(BasePoint * fromorig,Spline * spline,BasePoint * toorig,real transform[6],enum transformPointMask tpmask)1838 static void TransformPTsInterpolateCPs(BasePoint *fromorig,Spline *spline,
1839 BasePoint *toorig,real transform[6], enum transformPointMask tpmask ) {
1840 BasePoint totrans, temp;
1841 bigreal fraction;
1842
1843 /* Normally the "from" point will already have been translated, and the "to" */
1844 /* point will need to be. But if we have a closed contour then on the */
1845 /* last spline both from and to will have been transform. We can detect */
1846 /* this because toorig will be different from &spline->to->me */
1847 if ( spline->to->selected && toorig==&spline->to->me )
1848 _BpTransform(&totrans,&spline->to->me,transform,tpmask);
1849 else
1850 totrans = spline->to->me;
1851
1852 /* None of the control points will have been transformed yet */
1853 if ( fromorig->x!=toorig->x ) {
1854 fraction = (spline->from->nextcp.x-fromorig->x)/( toorig->x-fromorig->x );
1855 spline->from->nextcp.x = spline->from->me.x + fraction*( totrans.x-spline->from->me.x );
1856 fraction = (spline->to->prevcp.x-fromorig->x)/( toorig->x-fromorig->x );
1857 spline->to->prevcp.x = spline->from->me.x + fraction*( totrans.x-spline->from->me.x );
1858 } else {
1859 _BpTransform(&temp,&spline->from->nextcp,transform,tpmask);
1860 spline->from->nextcp.x = temp.x;
1861 _BpTransform(&temp,&spline->to->prevcp,transform,tpmask);
1862 spline->to->prevcp.x = temp.x;
1863 }
1864 if ( fromorig->y!=toorig->y ) {
1865 fraction = (spline->from->nextcp.y-fromorig->y)/( toorig->y-fromorig->y );
1866 spline->from->nextcp.y = spline->from->me.y + fraction*( totrans.y-spline->from->me.y );
1867 fraction = (spline->to->prevcp.y-fromorig->y)/( toorig->y-fromorig->y );
1868 spline->to->prevcp.y = spline->from->me.y + fraction*( totrans.y-spline->from->me.y );
1869 } else {
1870 _BpTransform(&temp,&spline->from->nextcp,transform,tpmask);
1871 spline->from->nextcp.y = temp.y;
1872 _BpTransform(&temp,&spline->to->prevcp,transform,tpmask);
1873 spline->to->prevcp.y = temp.y;
1874 }
1875
1876 if ( spline->to->selected )
1877 spline->to->me = totrans;
1878 }
1879
1880
SplinePointListTransformExtended(SplinePointList * base,real transform[6],enum transformPointType tpt,enum transformPointMask tpmask)1881 SplinePointList *SplinePointListTransformExtended(SplinePointList *base, real transform[6],
1882 enum transformPointType tpt, enum transformPointMask tpmask ) {
1883 Spline *spline, *first;
1884 SplinePointList *spl;
1885 SplinePoint *spt, *pfirst;
1886 int allsel, anysel, alldone=true;
1887 BasePoint lastpointorig, firstpointorig, orig;
1888
1889 for ( spl = base; spl!=NULL; spl = spl->next ) {
1890 pfirst = NULL; first = NULL;
1891 allsel = true; anysel=false;
1892 if ( tpt==tpt_OnlySelectedInterpCPs && spl->first->next!=NULL && !spl->first->next->order2 ) {
1893 lastpointorig = firstpointorig = spl->first->me;
1894 printf("SplinePointListTransformExtended() spl->first->selected %d\n", spl->first->selected );
1895 if ( spl->first->selected ) {
1896 anysel = true;
1897 _BpTransform(&spl->first->me,&spl->first->me,transform,tpmask);
1898 } else
1899 allsel = false;
1900 for ( spline = spl->first->next; spline!=NULL && spline!=first; spline=spline->to->next ) {
1901 if ( first==NULL ) first = spline;
1902 orig = spline->to->me;
1903 if ( spline->from->selected || spline->to->selected )
1904 {
1905 TransformPTsInterpolateCPs( &lastpointorig, spline,
1906 spl->first==spline->to? &firstpointorig : &spline->to->me,
1907 transform, tpmask );
1908 }
1909 lastpointorig = orig;
1910 if ( spline->to->selected ) anysel = true; else allsel = false;
1911 }
1912
1913 } else {
1914 for ( spt = spl->first ; spt!=pfirst; spt = spt->next->to ) {
1915 if ( pfirst==NULL ) pfirst = spt;
1916 if ( tpt==tpt_AllPoints || spt->selected ) {
1917 TransformPointExtended(spt,transform,tpmask);
1918 if ( tpt!=tpt_AllPoints ) {
1919 if ( spt->next!=NULL && spt->next->order2 && !spt->next->to->selected && spt->next->to->ttfindex==0xffff ) {
1920 SplinePoint *to = spt->next->to;
1921 to->prevcp = spt->nextcp;
1922 to->me.x = (to->prevcp.x+to->nextcp.x)/2;
1923 to->me.y = (to->prevcp.y+to->nextcp.y)/2;
1924 }
1925 if ( spt->prev!=NULL && spt->prev->order2 && !spt->prev->from->selected && spt->prev->from->ttfindex==0xffff ) {
1926 SplinePoint *from = spt->prev->from;
1927 from->nextcp = spt->prevcp;
1928 from->me.x = (from->prevcp.x+from->nextcp.x)/2;
1929 from->me.y = (from->prevcp.y+from->nextcp.y)/2;
1930 }
1931 }
1932 anysel = true;
1933 } else
1934 allsel = alldone = false;
1935 if ( spt->next==NULL )
1936 break;
1937 }
1938 }
1939 if ( !anysel ) /* This splineset had no selected points it's unchanged */
1940 continue;
1941
1942 /* If we changed all the points, then transform the spiro version too */
1943 /* otherwise if we just changed some points, throw away the spiro */
1944 if ( allsel ) {
1945 int i;
1946 for ( i=0; i<spl->spiro_cnt-1; ++i )
1947 TransformSpiro(&spl->spiros[i], transform);
1948 } else
1949 SplineSetSpirosClear(spl);
1950
1951 /* if we changed all the points then the control points are right */
1952 /* otherwise those near the edges may be wonky, fix 'em up */
1953 /* Figuring out where the edges of the selection are is difficult */
1954 /* so let's just tweak all points, it shouldn't matter */
1955 /* It does matter. Let's tweak all default points */
1956 if( !(tpmask & tpmask_dontFixControlPoints))
1957 {
1958 if ( tpt!=tpt_AllPoints && !allsel && spl->first->next!=NULL && !spl->first->next->order2 )
1959 {
1960 pfirst = NULL;
1961 for ( spt = spl->first ; spt!=pfirst; spt = spt->next->to )
1962 {
1963 if ( pfirst==NULL ) pfirst = spt;
1964 if ( spt->selected && spt->prev!=NULL && !spt->prev->from->selected &&
1965 spt->prev->from->pointtype == pt_tangent )
1966 SplineCharTangentPrevCP(spt->prev->from);
1967 if ( spt->selected && spt->next!=NULL && !spt->next->to->selected &&
1968 spt->next->to->pointtype == pt_tangent )
1969 SplineCharTangentNextCP(spt->next->to);
1970 if ( spt->prev!=NULL && spt->prevcpdef && tpt==tpt_OnlySelected )
1971 SplineCharDefaultPrevCP(spt);
1972 if ( spt->next==NULL )
1973 break;
1974 if ( spt->nextcpdef && tpt==tpt_OnlySelected )
1975 SplineCharDefaultNextCP(spt);
1976 }
1977 }
1978 }
1979 first = NULL;
1980 for ( spline = spl->first->next; spline!=NULL && spline!=first; spline=spline->to->next ) {
1981 if ( !alldone ) SplineRefigureFixup(spline); else SplineRefigure(spline);
1982 if ( first==NULL ) first = spline;
1983 }
1984 }
1985 return( base );
1986 }
1987
SplinePointListTransform(SplinePointList * base,real transform[6],enum transformPointType tpt)1988 SplinePointList *SplinePointListTransform( SplinePointList *base, real transform[6],
1989 enum transformPointType tpt )
1990 {
1991 enum transformPointMask tpmask = 0;
1992 return SplinePointListTransformExtended( base, transform, tpt, tpmask );
1993 }
1994
SplinePointListSpiroTransform(SplinePointList * base,real transform[6],int allpoints)1995 SplinePointList *SplinePointListSpiroTransform(SplinePointList *base, real transform[6], int allpoints ) {
1996 SplinePointList *spl;
1997 bool allsel, anysel;
1998 int i;
1999
2000
2001 if ( allpoints )
2002 return( SplinePointListTransform(base,transform,tpt_AllPoints));
2003
2004 for ( spl = base; spl!=NULL; spl = spl->next ) {
2005 anysel = SplinePointListCheckSelected1(spl, true, &allsel, true);
2006 if ( !anysel )
2007 continue;
2008 if ( allsel ) {
2009 SplinePointList *next = spl->next;
2010 /* If we are transforming everything, then we can just transform */
2011 /* the beziers too */
2012 spl->next = NULL;
2013 SplinePointListTransform(spl,transform,tpt_AllPoints);
2014 spl->next = next;
2015 continue;
2016 }
2017 /* If we are transformings some things, then we need to transform the */
2018 /* selected spiros and then regenerate the beziers */
2019 for ( i=0; i<spl->spiro_cnt-1; ++i )
2020 if ( spl->spiros[i].ty & 0x80 )
2021 TransformSpiro(&spl->spiros[i], transform);
2022 SSRegenerateFromSpiros(spl);
2023 }
2024 return( base );
2025 }
2026
SplinePointListShift(SplinePointList * base,real xoff,enum transformPointType allpoints)2027 SplinePointList *SplinePointListShift(SplinePointList *base,real xoff,enum transformPointType allpoints ) {
2028 real transform[6];
2029 if ( xoff==0 )
2030 return( base );
2031 transform[0] = transform[3] = 1;
2032 transform[1] = transform[2] = transform[5] = 0;
2033 transform[4] = xoff;
2034 return( SplinePointListTransform(base,transform,allpoints));
2035 }
2036
HintMaskFromTransformedRef(RefChar * ref,BasePoint * trans,SplineChar * basesc,HintMask * hm)2037 HintMask *HintMaskFromTransformedRef(RefChar *ref,BasePoint *trans,
2038 SplineChar *basesc,HintMask *hm) {
2039 StemInfo *st, *st2;
2040 int hst_cnt, bcnt;
2041 real start, width;
2042 int i;
2043
2044 if ( ref->transform[1]!=0 || ref->transform[2]!=0 )
2045 return(NULL);
2046
2047 memset(hm,0,sizeof(HintMask));
2048 for ( st = ref->sc->hstem; st!=NULL; st=st->next ) {
2049 start = st->start*ref->transform[3] + ref->transform[5] + trans->y;
2050 width = st->width*ref->transform[3];
2051 for ( st2=basesc->hstem,bcnt=0; st2!=NULL; st2=st2->next, bcnt++ )
2052 if ( st2->start == start && st2->width == width )
2053 break;
2054 if ( st2!=NULL )
2055 (*hm)[bcnt>>3] |= (0x80>>(bcnt&7));
2056 }
2057 for ( st2=basesc->hstem,hst_cnt=0; st2!=NULL; st2=st2->next, hst_cnt++ );
2058
2059 for ( st = ref->sc->vstem; st!=NULL; st=st->next ) {
2060 start = st->start*ref->transform[0] + ref->transform[4] + trans->x;
2061 width = st->width*ref->transform[0];
2062 for ( st2=basesc->vstem,bcnt=hst_cnt; st2!=NULL; st2=st2->next, bcnt++ )
2063 if ( st2->start == start && st2->width == width )
2064 break;
2065 if ( st2!=NULL )
2066 (*hm)[bcnt>>3] |= (0x80>>(bcnt&7));
2067 }
2068 for ( i=0; i<HntMax/8; ++i )
2069 if ( (*hm)[i]!=0 )
2070 return( hm );
2071
2072 return( NULL );
2073 }
2074
HintMaskTransform(HintMask * oldhm,real transform[6],SplineChar * basesc,SplineChar * subsc)2075 static HintMask *HintMaskTransform(HintMask *oldhm,real transform[6],
2076 SplineChar *basesc,SplineChar *subsc) {
2077 HintMask *newhm;
2078 StemInfo *st, *st2;
2079 int cnt, hst_cnt, bcnt;
2080 real start, width;
2081
2082 if ( transform[1]!=0 || transform[2]!=0 )
2083 return( NULL );
2084
2085 newhm = chunkalloc(sizeof(HintMask));
2086 for ( st = subsc->hstem,cnt = 0; st!=NULL; st=st->next, cnt++ ) {
2087 if ( (*oldhm)[cnt>>3]&(0x80>>(cnt&7)) ) {
2088 start = st->start*transform[3] + transform[5];
2089 width = st->width*transform[3];
2090 for ( st2=basesc->hstem,bcnt=0; st2!=NULL; st2=st2->next, bcnt++ )
2091 if ( st2->start == start && st2->width == width )
2092 break;
2093 if ( st2!=NULL )
2094 (*newhm)[bcnt>>3] |= (0x80>>(bcnt&7));
2095 }
2096 }
2097 for ( st2=basesc->hstem,hst_cnt=0; st2!=NULL; st2=st2->next, hst_cnt++ );
2098
2099 for ( st = subsc->vstem; st!=NULL; st=st->next, cnt++ ) {
2100 if ( (*oldhm)[cnt>>3]&(0x80>>(cnt&7)) ) {
2101 start = st->start*transform[0] + transform[4];
2102 width = st->width*transform[0];
2103 for ( st2=basesc->vstem,bcnt=hst_cnt; st2!=NULL; st2=st2->next, bcnt++ )
2104 if ( st2->start == start && st2->width == width )
2105 break;
2106 if ( st2!=NULL )
2107 (*newhm)[bcnt>>3] |= (0x80>>(bcnt&7));
2108 }
2109 }
2110 return( newhm );
2111 }
2112
SPLCopyTranslatedHintMasks(SplinePointList * base,SplineChar * basesc,SplineChar * subsc,BasePoint * trans)2113 SplinePointList *SPLCopyTranslatedHintMasks(SplinePointList *base,
2114 SplineChar *basesc, SplineChar *subsc, BasePoint *trans ) {
2115 SplinePointList *spl, *spl2, *head;
2116 SplinePoint *spt, *spt2, *pfirst;
2117 real transform[6];
2118 Spline *s, *first;
2119
2120 head = SplinePointListCopy(base);
2121
2122 transform[0] = transform[3] = 1; transform[1] = transform[2] = 0;
2123 transform[4] = trans->x; transform[5] = trans->y;
2124
2125 for ( spl = head, spl2=base; spl!=NULL; spl = spl->next, spl2 = spl2->next ) {
2126 pfirst = NULL;
2127 for ( spt = spl->first, spt2 = spl2->first ; spt!=pfirst; spt = spt->next->to, spt2 = spt2->next->to ) {
2128 if ( pfirst==NULL ) pfirst = spt;
2129 TransformPoint(spt,transform);
2130 if ( spt2->hintmask ) {
2131 chunkfree(spt->hintmask,sizeof(HintMask));
2132 spt->hintmask = HintMaskTransform(spt2->hintmask,transform,basesc,subsc);
2133 }
2134 if ( spt->next==NULL )
2135 break;
2136 }
2137 first = NULL;
2138 for ( s = spl->first->next; s!=NULL && s!=first; s=s->to->next ) {
2139 SplineRefigure(s);
2140 if ( first==NULL ) first = s;
2141 }
2142 }
2143 return( head );
2144 }
2145
_SPLCopyTransformedHintMasks(SplineChar * subsc,int layer,real transform[6],SplineChar * basesc)2146 static SplinePointList *_SPLCopyTransformedHintMasks(SplineChar *subsc,int layer,
2147 real transform[6], SplineChar *basesc ) {
2148 SplinePointList *spl, *spl2, *head, *last=NULL, *cur, *base;
2149 SplinePoint *spt, *spt2, *pfirst;
2150 Spline *s, *first;
2151 real trans[6];
2152 RefChar *rf;
2153
2154 base = subsc->layers[layer].splines;
2155 head = SplinePointListCopy(base);
2156 if ( head!=NULL )
2157 for ( last = head; last->next!=NULL; last=last->next );
2158
2159 for ( spl = head, spl2=base; spl!=NULL; spl = spl->next, spl2=spl2->next ) {
2160 pfirst = NULL;
2161 for ( spt = spl->first, spt2 = spl2->first ; spt!=pfirst; spt = spt->next->to, spt2 = spt2->next->to ) {
2162 if ( pfirst==NULL ) pfirst = spt;
2163 TransformPoint(spt,transform);
2164 if ( spt2->hintmask ) {
2165 chunkfree(spt->hintmask,sizeof(HintMask));
2166 spt->hintmask = HintMaskTransform(spt2->hintmask,transform,basesc,subsc);
2167 }
2168 if ( spt->next==NULL )
2169 break;
2170 }
2171 first = NULL;
2172 for ( s = spl->first->next; s!=NULL && s!=first; s=s->to->next ) {
2173 SplineRefigure(s);
2174 if ( first==NULL ) first = s;
2175 }
2176 }
2177 for ( rf=subsc->layers[layer].refs; rf!=NULL; rf=rf->next ) {
2178 trans[0] = rf->transform[0]*transform[0] +
2179 rf->transform[1]*transform[2];
2180 trans[1] = rf->transform[0]*transform[1] +
2181 rf->transform[1]*transform[3];
2182 trans[2] = rf->transform[2]*transform[0] +
2183 rf->transform[3]*transform[2];
2184 trans[3] = rf->transform[2]*transform[1] +
2185 rf->transform[3]*transform[3];
2186 trans[4] = rf->transform[4]*transform[0] +
2187 rf->transform[5]*transform[2] +
2188 transform[4];
2189 trans[5] = rf->transform[4]*transform[1] +
2190 rf->transform[5]*transform[3] +
2191 transform[5];
2192 cur = _SPLCopyTransformedHintMasks(rf->sc,layer,trans,basesc);
2193 if ( head==NULL )
2194 head = cur;
2195 else
2196 last->next = cur;
2197 if ( cur!=NULL ) {
2198 while ( cur->next!=NULL ) cur = cur->next;
2199 last = cur;
2200 }
2201 }
2202 return( head );
2203 }
2204
SPLCopyTransformedHintMasks(RefChar * r,SplineChar * basesc,BasePoint * trans,int layer)2205 SplinePointList *SPLCopyTransformedHintMasks(RefChar *r,
2206 SplineChar *basesc, BasePoint *trans,int layer ) {
2207 real transform[6];
2208
2209 memcpy(transform,r->transform,sizeof(transform));
2210 transform[4] += trans->x; transform[5] += trans->y;
2211 return( _SPLCopyTransformedHintMasks(r->sc,layer,transform,basesc));
2212 }
2213
SplinePointListClearCPSel(SplinePointList * spl)2214 void SplinePointListClearCPSel(SplinePointList *spl) {
2215 Spline *spline, *first;
2216
2217 for ( ; spl!=NULL; spl = spl->next ) {
2218 first = NULL;
2219 spl->first->nextcpselected = false;
2220 spl->first->prevcpselected = false;
2221 for ( spline = spl->first->next; spline!=NULL && spline!=first; spline=spline->to->next ) {
2222 spline->to->nextcpselected = false;
2223 spline->to->prevcpselected = false;
2224 if ( first==NULL ) first = spline;
2225 }
2226 }
2227 }
2228
SplinePointListSelect(SplinePointList * spl,int sel)2229 void SplinePointListSelect(SplinePointList *spl,int sel) {
2230 Spline *spline, *first;
2231
2232 for ( ; spl!=NULL; spl = spl->next ) {
2233 first = NULL;
2234 spl->first->selected = sel;
2235 for ( spline = spl->first->next; spline!=NULL && spline!=first; spline=spline->to->next ) {
2236 spline->to->selected = sel;
2237 if ( first==NULL ) first = spline;
2238 }
2239 }
2240 }
2241
SCMakeDependent(SplineChar * dependent,SplineChar * base)2242 void SCMakeDependent(SplineChar *dependent,SplineChar *base) {
2243 struct splinecharlist *dlist;
2244
2245 if ( dependent->searcherdummy )
2246 return;
2247
2248 for ( dlist=base->dependents; dlist!=NULL && dlist->sc!=dependent; dlist = dlist->next);
2249 if ( dlist==NULL ) {
2250 dlist = chunkalloc(sizeof(struct splinecharlist));
2251 dlist->sc = dependent;
2252 dlist->next = base->dependents;
2253 base->dependents = dlist;
2254 }
2255 }
2256
InstanciateReference(SplineFont * sf,RefChar * topref,RefChar * refs,real transform[6],SplineChar * dsc,int layer)2257 static void InstanciateReference(SplineFont *sf, RefChar *topref, RefChar *refs,
2258 real transform[6], SplineChar *dsc, int layer) {
2259 real trans[6];
2260 RefChar *rf;
2261 SplineChar *rsc;
2262 SplinePointList *spl, *new;
2263 int i;
2264
2265 if ( !refs->checked ) {
2266 if ( refs->sc!=NULL )
2267 i = refs->sc->orig_pos; /* Can happen in type3 fonts */
2268 else for ( i=0; i<sf->glyphcnt; ++i ) if ( sf->glyphs[i]!=NULL )
2269 if ( strcmp(sf->glyphs[i]->name,AdobeStandardEncoding[refs->adobe_enc])==0 )
2270 break;
2271 if ( i!=sf->glyphcnt && !sf->glyphs[i]->ticked ) {
2272 refs->checked = true;
2273 refs->sc = rsc = sf->glyphs[i];
2274 refs->orig_pos = rsc->orig_pos;
2275 refs->unicode_enc = rsc->unicodeenc;
2276 SCMakeDependent(dsc,rsc);
2277 } else {
2278 LogError( _("Couldn't find referenced character \"%s\" in %s\n"),
2279 AdobeStandardEncoding[refs->adobe_enc], dsc->name);
2280 return;
2281 }
2282 } else if ( refs->sc->ticked )
2283 return;
2284
2285 rsc = refs->sc;
2286 rsc->ticked = true;
2287
2288 for ( rf=rsc->layers[ly_fore].refs; rf!=NULL; rf = rf->next ) {
2289 trans[0] = rf->transform[0]*transform[0] +
2290 rf->transform[1]*transform[2];
2291 trans[1] = rf->transform[0]*transform[1] +
2292 rf->transform[1]*transform[3];
2293 trans[2] = rf->transform[2]*transform[0] +
2294 rf->transform[3]*transform[2];
2295 trans[3] = rf->transform[2]*transform[1] +
2296 rf->transform[3]*transform[3];
2297 trans[4] = rf->transform[4]*transform[0] +
2298 rf->transform[5]*transform[2] +
2299 transform[4];
2300 trans[5] = rf->transform[4]*transform[1] +
2301 rf->transform[5]*transform[3] +
2302 transform[5];
2303 InstanciateReference(sf,topref,rf,trans,rsc,layer);
2304 }
2305 rsc->ticked = false;
2306
2307 if ( sf->multilayer ) {
2308 int lbase = topref->layer_cnt;
2309 if ( topref->layer_cnt==0 ) {
2310 topref->layers = calloc(rsc->layer_cnt-1,sizeof(struct reflayer));
2311 topref->layer_cnt = rsc->layer_cnt-1;
2312 } else {
2313 topref->layer_cnt += rsc->layer_cnt-1;
2314 topref->layers = realloc(topref->layers,topref->layer_cnt*sizeof(struct reflayer));
2315 memset(topref->layers+lbase,0,(rsc->layer_cnt-1)*sizeof(struct reflayer));
2316 }
2317 for ( i=ly_fore; i<rsc->layer_cnt; ++i ) {
2318 topref->layers[i-ly_fore+lbase].splines = SplinePointListTransform(SplinePointListCopy(rsc->layers[i].splines),transform,tpt_AllPoints);
2319 BrushCopy(&topref->layers[i-ly_fore+lbase].fill_brush, &rsc->layers[i].fill_brush,transform);
2320 PenCopy(&topref->layers[i-ly_fore+lbase].stroke_pen, &rsc->layers[i].stroke_pen,transform);
2321 topref->layers[i-ly_fore+lbase].dofill = rsc->layers[i].dofill;
2322 topref->layers[i-ly_fore+lbase].dostroke = rsc->layers[i].dostroke;
2323 topref->layers[i-ly_fore+lbase].fillfirst = rsc->layers[i].fillfirst;
2324 /* ??? and images? */
2325 }
2326 } else {
2327 if ( topref->layer_cnt==0 ) {
2328 topref->layers = calloc(1,sizeof(struct reflayer));
2329 topref->layer_cnt = 1;
2330 }
2331 new = SplinePointListTransform(SplinePointListCopy(rsc->layers[layer].splines),transform,tpt_AllPoints);
2332 if ( new!=NULL ) {
2333 for ( spl = new; spl->next!=NULL; spl = spl->next );
2334 spl->next = topref->layers[0].splines;
2335 topref->layers[0].splines = new;
2336 }
2337 }
2338 }
2339
copyparse(char * str)2340 static char *copyparse(char *str) {
2341 char *ret, *rpt;
2342 int ch,i;
2343
2344 if ( str==NULL )
2345 return( str );
2346
2347 rpt=ret=malloc(strlen(str)+1);
2348 while ( *str ) {
2349 if ( *str=='\\' ) {
2350 ++str;
2351 if ( *str=='n' ) ch = '\n';
2352 else if ( *str=='r' ) ch = '\r';
2353 else if ( *str=='t' ) ch = '\t';
2354 else if ( *str=='b' ) ch = '\b';
2355 else if ( *str=='f' ) ch = '\f';
2356 else if ( *str=='\\' ) ch = '\\';
2357 else if ( *str=='(' ) ch = '(';
2358 else if ( *str==')' ) ch = ')';
2359 else if ( *str>='0' && *str<='7' ) {
2360 for ( i=ch = 0; i<3 && *str>='0' && *str<='7'; ++i )
2361 ch = (ch<<3) + *str++-'0';
2362 --str;
2363 } else
2364 ch = *str;
2365 ++str;
2366 *rpt++ = ch;
2367 } else
2368 *rpt++ = *str++;
2369 }
2370 *rpt = '\0';
2371 if ( !utf8_valid(ret)) {
2372 /* Assume latin1, convert to utf8 */
2373 rpt = latin1_2_utf8_copy(ret);
2374 free(ret);
2375 ret = rpt;
2376 }
2377 if ( !AllAscii(ret)) {
2378 rpt = StripToASCII(ret);
2379 free(ret);
2380 ret = rpt;
2381 }
2382 return(ret);
2383 }
2384
XUIDFromFD(int xuid[20])2385 char *XUIDFromFD(int xuid[20]) {
2386 int i;
2387 char *ret=NULL;
2388
2389 for ( i=19; i>=0 && xuid[i]==0; --i );
2390 if ( i>=0 ) {
2391 int j; char *pt;
2392 ret = malloc(2+20*(i+1));
2393 pt = ret;
2394 *pt++ = '[';
2395 for ( j=0; j<=i; ++j ) {
2396 sprintf(pt,"%d ", xuid[j]);
2397 pt += strlen(pt);
2398 }
2399 pt[-1] = ']';
2400 }
2401 return( ret );
2402 }
2403
SplineFontMetaData(SplineFont * sf,struct fontdict * fd)2404 static void SplineFontMetaData(SplineFont *sf,struct fontdict *fd) {
2405 int em;
2406
2407 if ( fd->cidfontname || fd->fontname ) sf->fontname = utf8_verify_copy(fd->cidfontname?fd->cidfontname:fd->fontname);
2408 sf->display_size = -default_fv_font_size;
2409 sf->display_antialias = default_fv_antialias;
2410 if ( fd->fontinfo!=NULL ) {
2411 if ( sf->fontname==NULL && fd->fontinfo->fullname!=NULL ) {
2412 sf->fontname = EnforcePostScriptName(fd->fontinfo->fullname);
2413 }
2414 if ( sf->fontname==NULL && fd->fontinfo->familyname!=NULL ){
2415 sf->fontname = EnforcePostScriptName(fd->fontinfo->familyname);
2416 }
2417 sf->fullname = copyparse(fd->fontinfo->fullname);
2418 sf->familyname = copyparse(fd->fontinfo->familyname);
2419 sf->weight = copyparse(fd->fontinfo->weight);
2420 sf->version = copyparse(fd->fontinfo->version);
2421 sf->copyright = copyparse(fd->fontinfo->notice);
2422 sf->italicangle = fd->fontinfo->italicangle;
2423 sf->upos = fd->fontinfo->underlineposition;
2424 sf->uwidth = fd->fontinfo->underlinethickness;
2425 sf->strokedfont = fd->painttype==2;
2426 sf->strokewidth = fd->strokewidth;
2427 sf->ascent = fd->fontinfo->ascent;
2428 sf->descent = fd->fontinfo->descent;
2429 }
2430 if ( sf->uniqueid==0 ) sf->uniqueid = fd->uniqueid;
2431 if ( sf->fontname==NULL ) sf->fontname = GetNextUntitledName();
2432 if ( sf->fullname==NULL ) sf->fullname = copy(sf->fontname);
2433 if ( sf->familyname==NULL ) sf->familyname = copy(sf->fontname);
2434 if ( sf->weight==NULL ) sf->weight = copy("");
2435 if ( fd->modificationtime!=0 ) {
2436 sf->modificationtime = fd->modificationtime;
2437 sf->creationtime = fd->creationtime;
2438 }
2439 sf->cidversion = fd->cidversion;
2440 sf->xuid = XUIDFromFD(fd->xuid);
2441 /*sf->wasbinary = fd->wasbinary;*/
2442 if ( fd->fontmatrix[0]==0 )
2443 em = 1000;
2444 else
2445 em = rint(1/fd->fontmatrix[0]);
2446 if ( sf->ascent==0 && sf->descent!=0 )
2447 sf->ascent = em-sf->descent;
2448 else if ( fd->fontbb[3]-fd->fontbb[1]==em ) {
2449 if ( sf->ascent==0 ) sf->ascent = fd->fontbb[3];
2450 if ( sf->descent==0 ) sf->descent = fd->fontbb[1];
2451 } else if ( sf->ascent==0 )
2452 sf->ascent = 8*em/10;
2453 sf->descent = em-sf->ascent;
2454
2455 sf->private = fd->private->private; fd->private->private = NULL;
2456 PSDictRemoveEntry(sf->private, "OtherSubrs");
2457
2458 sf->cidregistry = copy(fd->registry);
2459 sf->ordering = copy(fd->ordering);
2460 sf->supplement = fd->supplement;
2461 sf->pfminfo.fstype = fd->fontinfo->fstype;
2462 if ( sf->ordering!=NULL ) {
2463 if ( strnmatch(sf->ordering,"Japan",5)==0 )
2464 sf->uni_interp = ui_japanese;
2465 else if ( strnmatch(sf->ordering,"Korea",5)==0 )
2466 sf->uni_interp = ui_korean;
2467 else if ( strnmatch(sf->ordering,"CNS",3)==0 )
2468 sf->uni_interp = ui_trad_chinese;
2469 else if ( strnmatch(sf->ordering,"GB",2)==0 )
2470 sf->uni_interp = ui_simp_chinese;
2471 }
2472 }
2473
TransByFontMatrix(SplineFont * sf,real fontmatrix[6])2474 static void TransByFontMatrix(SplineFont *sf,real fontmatrix[6]) {
2475 real trans[6];
2476 int em = sf->ascent+sf->descent, i;
2477 SplineChar *sc;
2478 RefChar *refs;
2479
2480 if ( fontmatrix[0]==fontmatrix[3] &&
2481 fontmatrix[1]==0 && fontmatrix[2]==0 &&
2482 fontmatrix[4]==0 && fontmatrix[5]==0 )
2483 return; /* It's just the expected matrix */
2484
2485 trans[0] = 1;
2486 if ( fontmatrix[0]==fontmatrix[3] ) trans[3] = 1;
2487 else trans[3] = rint(fontmatrix[3]*em);
2488 trans[1] = fontmatrix[1]*em;
2489 trans[2] = fontmatrix[2]*em;
2490 trans[4] = rint(fontmatrix[4]*em);
2491 trans[5] = rint(fontmatrix[5]*em);
2492
2493 for ( i=0; i<sf->glyphcnt; ++i ) if ( (sc=sf->glyphs[i])!=NULL ) {
2494 SplinePointListTransform(sc->layers[ly_fore].splines,trans,tpt_AllPoints);
2495 for ( refs=sc->layers[ly_fore].refs; refs!=NULL; refs=refs->next ) {
2496 /* Just scale the offsets. we'll do all the base characters */
2497 real temp = refs->transform[4]*trans[0] +
2498 refs->transform[5]*trans[2] +
2499 /*transform[4]*/0;
2500 refs->transform[5] = refs->transform[4]*trans[1] +
2501 refs->transform[5]*trans[3] +
2502 /*transform[5]*/0;
2503 refs->transform[4] = temp;
2504 }
2505 sc->changedsincelasthinted = true;
2506 sc->manualhints = false;
2507 }
2508 for ( i=0; i<sf->glyphcnt; ++i ) if ( (sc=sf->glyphs[i])!=NULL ) {
2509 for ( refs=sc->layers[ly_fore].refs; refs!=NULL; refs=refs->next )
2510 SCReinstanciateRefChar(sc,refs,ly_fore);
2511 }
2512 }
2513
SFInstanciateRefs(SplineFont * sf)2514 void SFInstanciateRefs(SplineFont *sf) {
2515 int i, layer;
2516 RefChar *refs, *next, *pr;
2517
2518 for ( i=0; i<sf->glyphcnt; ++i ) if ( sf->glyphs[i]!=NULL )
2519 sf->glyphs[i]->ticked = false;
2520
2521 for ( i=0; i<sf->glyphcnt; ++i ) if ( sf->glyphs[i]!=NULL ) {
2522 SplineChar *sc = sf->glyphs[i];
2523
2524 for ( layer=ly_back; layer<sc->layer_cnt; ++layer ) {
2525 for ( pr=NULL, refs = sc->layers[layer].refs; refs!=NULL; refs=next ) {
2526 next = refs->next;
2527 sc->ticked = true;
2528 InstanciateReference(sf, refs, refs, refs->transform,sc,layer);
2529 if ( refs->sc!=NULL ) {
2530 SplineSetFindBounds(refs->layers[0].splines,&refs->bb);
2531 sc->ticked = false;
2532 pr = refs;
2533 } else {
2534 /* In some mal-formed postscript fonts we can have a reference */
2535 /* to a character that is not actually in the font. I even */
2536 /* generated one by mistake once... */
2537 if ( pr==NULL )
2538 sc->layers[layer].refs = next;
2539 else
2540 pr->next = next;
2541 refs->next = NULL;
2542 RefCharsFree(refs);
2543 }
2544 }
2545 }
2546 }
2547 }
2548
2549 /* Also handles type3s */
_SplineFontFromType1(SplineFont * sf,FontDict * fd,struct pscontext * pscontext)2550 static void _SplineFontFromType1(SplineFont *sf, FontDict *fd, struct pscontext *pscontext) {
2551 int i, j, notdefpos;
2552 RefChar *refs, *next;
2553 int istype2 = fd->fonttype==2; /* Easy enough to deal with even though it will never happen... */
2554 int istype3 = fd->charprocs->next!=0;
2555 EncMap *map;
2556
2557 if ( istype2 )
2558 fd->private->subrs->bias = fd->private->subrs->cnt<1240 ? 107 :
2559 fd->private->subrs->cnt<33900 ? 1131 : 32768;
2560 sf->glyphmax = sf->glyphcnt = istype3 ? fd->charprocs->next : fd->chars->next;
2561 if ( sf->map==NULL ) {
2562 sf->map = map = EncMapNew(256+CharsNotInEncoding(fd),sf->glyphcnt,fd->encoding_name);
2563 } else
2564 map = sf->map;
2565 sf->glyphs = calloc(map->backmax,sizeof(SplineChar *));
2566 if ( istype3 ) /* We read a type3 */
2567 sf->multilayer = true;
2568 if ( istype3 )
2569 notdefpos = LookupCharString(".notdef",(struct pschars *) (fd->charprocs));
2570 else
2571 notdefpos = LookupCharString(".notdef",fd->chars);
2572 for ( i=0; i<256; ++i ) {
2573 int k;
2574 if ( istype3 ) {
2575 k = LookupCharString(fd->encoding[i],(struct pschars *) (fd->charprocs));
2576 } else {
2577 k = LookupCharString(fd->encoding[i],fd->chars);
2578 }
2579 if ( k==-1 ) k = notdefpos;
2580 map->map[i] = k;
2581 if ( k!=-1 && map->backmap[k]==-1 )
2582 map->backmap[k] = i;
2583 }
2584 if ( map->enccount>256 ) {
2585 int k, j;
2586 for ( k=0; k<fd->chars->cnt; ++k ) {
2587 if ( fd->chars->keys[k]!=NULL ) {
2588 for ( j=0; j<256; ++j )
2589 if ( fd->encoding[j]!=NULL &&
2590 strcmp(fd->encoding[j],fd->chars->keys[k])==0 )
2591 break;
2592 if ( j==256 ) {
2593 map->map[i] = k;
2594 if ( map->backmap[k]==-1 )
2595 map->backmap[k] = i;
2596 ++i;
2597 }
2598 }
2599 }
2600 /* And for type3s */
2601 for ( k=0; k<fd->charprocs->cnt; ++k ) {
2602 if ( fd->charprocs->keys[k]!=NULL ) {
2603 for ( j=0; j<256; ++j )
2604 if ( fd->encoding[j]!=NULL &&
2605 strcmp(fd->encoding[j],fd->charprocs->keys[k])==0 )
2606 break;
2607 if ( j==256 ) {
2608 map->map[i] = k;
2609 if ( map->backmap[k]==-1 )
2610 map->backmap[k] = i;
2611 ++i;
2612 }
2613 }
2614 }
2615 }
2616 for ( i=0; i<map->enccount; ++i ) if ( map->map[i]==-1 )
2617 map->map[i] = notdefpos;
2618
2619 for ( i=0; i<sf->glyphcnt; ++i ) {
2620 if ( !istype3 )
2621 sf->glyphs[i] = PSCharStringToSplines(fd->chars->values[i],fd->chars->lens[i],
2622 pscontext,fd->private->subrs,NULL,fd->chars->keys[i]);
2623 else
2624 sf->glyphs[i] = fd->charprocs->values[i];
2625 if ( sf->glyphs[i]!=NULL ) {
2626 sf->glyphs[i]->orig_pos = i;
2627 sf->glyphs[i]->vwidth = sf->ascent+sf->descent;
2628 sf->glyphs[i]->unicodeenc = UniFromName(sf->glyphs[i]->name,sf->uni_interp,map->enc);
2629 sf->glyphs[i]->parent = sf;
2630 /* SCLigDefault(sf->glyphs[i]);*/ /* Also reads from AFM file, but it probably doesn't exist */
2631 }
2632 ff_progress_next();
2633 }
2634 SFInstanciateRefs(sf);
2635 if ( fd->metrics!=NULL ) {
2636 for ( i=0; i<fd->metrics->next; ++i ) {
2637 int width = strtol(fd->metrics->values[i],NULL,10);
2638 for ( j=sf->glyphcnt-1; j>=0; --j ) {
2639 if ( sf->glyphs[j]!=NULL && sf->glyphs[j]->name!=NULL &&
2640 strcmp(fd->metrics->keys[i],sf->glyphs[j]->name)==0 ) {
2641 sf->glyphs[j]->width = width;
2642 break;
2643 }
2644 }
2645 }
2646 }
2647 for ( i=0; i<sf->glyphcnt; ++i ) if ( sf->glyphs[i]!=NULL )
2648 for ( refs = sf->glyphs[i]->layers[ly_fore].refs; refs!=NULL; refs=next ) {
2649 next = refs->next;
2650 if ( refs->adobe_enc==' ' && refs->layers[0].splines==NULL ) {
2651 /* When I have a link to a single character I will save out a */
2652 /* seac to that character and a space (since I can only make */
2653 /* real char links), so if we find a space link, get rid of*/
2654 /* it. It's an artifact */
2655 SCRefToSplines(sf->glyphs[i],refs,ly_fore);
2656 }
2657 }
2658 /* sometimes (some apple oblique fonts) the fontmatrix is not just a */
2659 /* formality, it acutally contains a skew. So be ready */
2660 if ( fd->fontmatrix[0]!=0 )
2661 TransByFontMatrix(sf,fd->fontmatrix);
2662 AltUniFigure(sf,sf->map,true);
2663 }
2664
SplineFontFromType1(SplineFont * sf,FontDict * fd,struct pscontext * pscontext)2665 static void SplineFontFromType1(SplineFont *sf, FontDict *fd, struct pscontext *pscontext) {
2666 int i;
2667 SplineChar *sc;
2668
2669 _SplineFontFromType1(sf,fd,pscontext);
2670
2671 /* Clean up the hint masks, We create an initial hintmask whether we need */
2672 /* it or not */
2673 for ( i=0; i<sf->glyphcnt; ++i ) {
2674 if ( (sc = sf->glyphs[i])!=NULL && !sc->hconflicts && !sc->vconflicts &&
2675 sc->layers[ly_fore].splines!=NULL ) {
2676 chunkfree( sc->layers[ly_fore].splines->first->hintmask,sizeof(HintMask) );
2677 sc->layers[ly_fore].splines->first->hintmask = NULL;
2678 }
2679 }
2680 }
2681
SplineFontFromMMType1(SplineFont * sf,FontDict * fd,struct pscontext * pscontext)2682 static SplineFont *SplineFontFromMMType1(SplineFont *sf, FontDict *fd, struct pscontext *pscontext) {
2683 char *pt, *end, *origweight;
2684 MMSet *mm;
2685 int ipos, apos, ppos, item, i;
2686 real blends[12]; /* At most twelve points/axis in a blenddesignmap */
2687 real designs[12];
2688 EncMap *map;
2689
2690 if ( fd->weightvector==NULL || fd->fontinfo->blenddesignpositions==NULL ||
2691 fd->fontinfo->blenddesignmap==NULL || fd->fontinfo->blendaxistypes==NULL ) {
2692 ff_post_error(_("Bad Multiple Master Font"),_("Bad Multiple Master Font"));
2693 SplineFontFree(sf);
2694 return( NULL );
2695 }
2696
2697 mm = chunkalloc(sizeof(MMSet));
2698
2699 pt = fd->weightvector;
2700 while ( *pt==' ' || *pt=='[' ) ++pt;
2701 while ( *pt!=']' && *pt!='\0' ) {
2702 pscontext->blend_values[ pscontext->instance_count ] =
2703 g_ascii_strtod(pt,&end);
2704 if ( pt==end )
2705 break;
2706 ++(pscontext->instance_count);
2707 if ( pscontext->instance_count>=sizeof(pscontext->blend_values)/sizeof(pscontext->blend_values[0])) {
2708 LogError( _("Multiple master font with more than 16 instances\n") );
2709 break;
2710 }
2711 for ( pt = end; *pt==' '; ++pt );
2712 }
2713
2714 mm->instance_count = pscontext->instance_count;
2715 mm->instances = malloc(pscontext->instance_count*sizeof(SplineFont *));
2716 mm->defweights = malloc(mm->instance_count*sizeof(real));
2717 memcpy(mm->defweights,pscontext->blend_values,mm->instance_count*sizeof(real));
2718 mm->normal = sf;
2719 _SplineFontFromType1(mm->normal,fd,pscontext);
2720 map = sf->map;
2721 for ( i=0; i<sf->glyphcnt; ++i ) if ( sf->glyphs[i]!=NULL )
2722 sf->glyphs[i]->blended = true;
2723 sf->mm = mm;
2724
2725 pt = fd->fontinfo->blendaxistypes;
2726 while ( *pt==' ' || *pt=='[' ) ++pt;
2727 while ( *pt!=']' && *pt!='\0' ) {
2728 if ( *pt=='/' ) ++pt;
2729 for ( end=pt; *end!=' ' && *end!=']' && *end!='\0'; ++end );
2730 if ( pt==end )
2731 break;
2732 if ( mm->axis_count>=sizeof(mm->axes)/sizeof(mm->axes[0])) {
2733 LogError( _("Multiple master font with more than 4 axes\n") );
2734 break;
2735 }
2736 mm->axes[ mm->axis_count++ ] = copyn( pt,end-pt );
2737 for ( pt = end; *pt==' '; ++pt );
2738 }
2739
2740 if ( mm->instance_count < (1<<mm->axis_count) )
2741 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);
2742 else if ( mm->instance_count > (1<<mm->axis_count) )
2743 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);
2744 mm->positions = calloc(mm->axis_count*mm->instance_count,sizeof(real));
2745 pt = fd->fontinfo->blenddesignpositions;
2746 while ( *pt==' ' ) ++pt;
2747 if ( *pt=='[' ) ++pt;
2748 ipos = 0;
2749 while ( *pt!=']' && *pt!='\0' ) {
2750 while ( *pt==' ' ) ++pt;
2751 if ( *pt==']' || *pt=='\0' )
2752 break;
2753 if ( ipos>=mm->instance_count )
2754 break;
2755 if ( *pt=='[' ) {
2756 ++pt;
2757 apos=0;
2758 while ( *pt!=']' && *pt!='\0' ) {
2759 if ( apos>=mm->axis_count ) {
2760 LogError( _("Too many axis positions specified in /BlendDesignPositions.\n") );
2761 break;
2762 }
2763 mm->positions[ipos*mm->axis_count+apos] =
2764 g_ascii_strtod(pt,&end);
2765 if ( pt==end )
2766 break;
2767 ++apos;
2768 for ( pt = end; *pt==' '; ++pt );
2769 }
2770 if ( *pt==']' ) ++pt;
2771 ++ipos;
2772 } else
2773 ++pt;
2774 }
2775
2776 mm->axismaps = calloc(mm->axis_count,sizeof(struct axismap));
2777 pt = fd->fontinfo->blenddesignmap;
2778 while ( *pt==' ' ) ++pt;
2779 if ( *pt=='[' ) ++pt;
2780 apos = 0;
2781 while ( *pt!=']' && *pt!='\0' ) {
2782 while ( *pt==' ' ) ++pt;
2783 if ( *pt==']' || *pt=='\0' )
2784 break;
2785 if ( apos>=mm->axis_count )
2786 break;
2787 if ( *pt=='[' ) {
2788 ++pt;
2789 ppos=0;
2790 while ( *pt!=']' && *pt!='\0' ) {
2791 if ( ppos>=12 ) {
2792 LogError( _("Too many mapping data points specified in /BlendDesignMap for axis %s.\n"), mm->axes[apos] );
2793 break;
2794 }
2795 while ( *pt==' ' ) ++pt;
2796 if ( *pt=='[' ) {
2797 ++pt;
2798 designs[ppos] = g_ascii_strtod(pt,&end);
2799 blends[ppos] = g_ascii_strtod(end,&end);
2800 if ( blends[ppos]<0 || blends[ppos]>1 ) {
2801 LogError( _("Bad value for blend in /BlendDesignMap for axis %s.\n"), mm->axes[apos] );
2802 if ( blends[ppos]<0 ) blends[ppos] = 0;
2803 if ( blends[ppos]>1 ) blends[ppos] = 1;
2804 }
2805 pt = end;
2806 while ( *pt!=']' && *pt!='\0' ) ++pt;
2807 ppos ++;
2808 }
2809 ++pt;
2810 while ( *pt==' ' ) ++pt;
2811 }
2812 if ( *pt==']' ) ++pt;
2813 if ( ppos<2 )
2814 LogError( _("Bad few values in /BlendDesignMap for axis %s.\n"), mm->axes[apos] );
2815 mm->axismaps[apos].points = ppos;
2816 mm->axismaps[apos].blends = malloc(ppos*sizeof(real));
2817 mm->axismaps[apos].designs = malloc(ppos*sizeof(real));
2818 memcpy(mm->axismaps[apos].blends,blends,ppos*sizeof(real));
2819 memcpy(mm->axismaps[apos].designs,designs,ppos*sizeof(real));
2820 ++apos;
2821 } else
2822 ++pt;
2823 }
2824
2825 mm->cdv = copy(fd->cdv);
2826 mm->ndv = copy(fd->ndv);
2827
2828 origweight = fd->fontinfo->weight;
2829
2830 /* Now figure out the master designs, being careful to interpolate */
2831 /* BlueValues, ForceBold, UnderlinePosition etc. We need to copy private */
2832 /* generate a font name */
2833 for ( ipos = 0; ipos<mm->instance_count; ++ipos ) {
2834 free(fd->fontname);
2835 free(fd->fontinfo->fullname);
2836 fd->fontname = MMMakeMasterFontname(mm,ipos,&fd->fontinfo->fullname);
2837 fd->fontinfo->weight = MMGuessWeight(mm,ipos,copy(origweight));
2838 if ( fd->blendfontinfo!=NULL ) {
2839 for ( item=0; item<3; ++item ) {
2840 static char *names[] = { "ItalicAngle", "UnderlinePosition", "UnderlineThickness" };
2841 pt = PSDictHasEntry(fd->blendfontinfo,names[item]);
2842 if ( pt!=NULL ) {
2843 pt = MMExtractNth(pt,ipos);
2844 if ( pt!=NULL ) {
2845 bigreal val = g_ascii_strtod(pt,NULL);
2846 free(pt);
2847 switch ( item ) {
2848 case 0: fd->fontinfo->italicangle = val; break;
2849 case 1: fd->fontinfo->underlineposition = val; break;
2850 case 2: fd->fontinfo->underlinethickness = val; break;
2851 }
2852 }
2853 }
2854 }
2855 }
2856 fd->private->private = PSDictCopy(sf->private);
2857 if ( fd->blendprivate!=NULL ) {
2858 static char *arrnames[] = { "BlueValues", "OtherBlues", "FamilyBlues", "FamilyOtherBlues", "StdHW", "StdVW", "StemSnapH", "StemSnapV", NULL };
2859 static char *scalarnames[] = { "ForceBold", "BlueFuzz", "BlueScale", "BlueShift", NULL };
2860 for ( item=0; scalarnames[item]!=NULL; ++item ) {
2861 pt = PSDictHasEntry(fd->blendprivate,scalarnames[item]);
2862 if ( pt!=NULL ) {
2863 pt = MMExtractNth(pt,ipos);
2864 PSDictChangeEntry(fd->private->private,scalarnames[item],pt);
2865 free(pt);
2866 }
2867 }
2868 for ( item=0; arrnames[item]!=NULL; ++item ) {
2869 pt = PSDictHasEntry(fd->blendprivate,arrnames[item]);
2870 if ( pt!=NULL ) {
2871 pt = MMExtractArrayNth(pt,ipos);
2872 PSDictChangeEntry(fd->private->private,arrnames[item],pt);
2873 free(pt);
2874 }
2875 }
2876 }
2877 for ( item=0; item<mm->instance_count; ++item )
2878 pscontext->blend_values[item] = 0;
2879 pscontext->blend_values[ipos] = 1;
2880
2881 mm->instances[ipos] = SplineFontEmpty();
2882 SplineFontMetaData(mm->instances[ipos],fd);
2883 free(fd->fontinfo->weight);
2884 mm->instances[ipos]->map = map;
2885 _SplineFontFromType1(mm->instances[ipos],fd,pscontext);
2886 mm->instances[ipos]->mm = mm;
2887 }
2888 fd->fontinfo->weight = origweight;
2889
2890 /* Clean up hintmasks. We always create a hintmask on the first point */
2891 /* only keep them if we actually have conflicts. */
2892 for ( i=0; i<mm->normal->glyphcnt; ++i )
2893 if ( mm->normal->glyphs[i]!=NULL &&
2894 mm->normal->glyphs[i]->layers[ly_fore].splines != NULL ) {
2895 for ( item=0; item<mm->instance_count; ++item )
2896 if ( mm->instances[item]->glyphs[i]->vconflicts ||
2897 mm->instances[item]->glyphs[i]->hconflicts )
2898 break;
2899 if ( item==mm->instance_count ) { /* No conflicts */
2900 for ( item=0; item<mm->instance_count; ++item ) {
2901 chunkfree( mm->instances[item]->glyphs[i]->layers[ly_fore].splines->first->hintmask, sizeof(HintMask) );
2902 mm->instances[item]->glyphs[i]->layers[ly_fore].splines->first->hintmask = NULL;
2903 }
2904 chunkfree( mm->normal->glyphs[i]->layers[ly_fore].splines->first->hintmask, sizeof(HintMask) );
2905 mm->normal->glyphs[i]->layers[ly_fore].splines->first->hintmask = NULL;
2906 }
2907 }
2908
2909 return( sf );
2910 }
2911
SplineFontFromCIDType1(SplineFont * sf,FontDict * fd,struct pscontext * pscontext)2912 static SplineFont *SplineFontFromCIDType1(SplineFont *sf, FontDict *fd,
2913 struct pscontext *pscontext) {
2914 int i,j,k, bad, uni;
2915 SplineChar **chars;
2916 char buffer[100];
2917 struct cidmap *map;
2918 SplineFont *_sf;
2919 SplineChar *sc;
2920 EncMap *encmap;
2921
2922 bad = 0x80000000;
2923 for ( i=0; i<fd->fdcnt; ++i )
2924 if ( fd->fds[i]->fonttype!=1 && fd->fds[i]->fonttype!=2 )
2925 bad = fd->fds[i]->fonttype;
2926 if ( bad!=0x80000000 || fd->cidfonttype!=0 ) {
2927 LogError( _("Could not parse a CID font, %sCIDFontType %d, %sfonttype %d\n"),
2928 ( fd->cidfonttype!=0 ) ? "unexpected " : "",
2929 ( bad!=0x80000000 ) ? "unexpected " : "",
2930 fd->cidfonttype, bad );
2931 SplineFontFree(sf);
2932 return( NULL );
2933 }
2934 if ( fd->cidstrs==NULL || fd->cidcnt==0 ) {
2935 LogError( _("CID format doesn't contain what we expected it to.\n") );
2936 SplineFontFree(sf);
2937 return( NULL );
2938 }
2939
2940 encmap = EncMap1to1(fd->cidcnt);
2941
2942 sf->subfontcnt = fd->fdcnt;
2943 sf->subfonts = malloc((sf->subfontcnt+1)*sizeof(SplineFont *));
2944 for ( i=0; i<fd->fdcnt; ++i ) {
2945 if ( fd->fontmatrix[0]!=0 ) {
2946 MatMultiply(fd->fontmatrix,fd->fds[i]->fontmatrix,fd->fds[i]->fontmatrix);
2947 }
2948 sf->subfonts[i] = SplineFontEmpty();
2949 SplineFontMetaData(sf->subfonts[i],fd->fds[i]);
2950 sf->subfonts[i]->cidmaster = sf;
2951 sf->subfonts[i]->uni_interp = sf->uni_interp;
2952 sf->subfonts[i]->map = encmap;
2953 if ( fd->fds[i]->fonttype==2 )
2954 fd->fds[i]->private->subrs->bias =
2955 fd->fds[i]->private->subrs->cnt<1240 ? 107 :
2956 fd->fds[i]->private->subrs->cnt<33900 ? 1131 : 32768;
2957 }
2958
2959 map = FindCidMap(sf->cidregistry,sf->ordering,sf->supplement,sf);
2960
2961 chars = calloc(fd->cidcnt,sizeof(SplineChar *));
2962 for ( i=0; i<fd->cidcnt; ++i ) if ( fd->cidlens[i]>0 ) {
2963 j = fd->cidfds[i]; /* We get font indexes of 255 for non-existant chars */
2964 uni = CID2NameUni(map,i,buffer,sizeof(buffer));
2965 pscontext->is_type2 = fd->fds[j]->fonttype==2;
2966 chars[i] = PSCharStringToSplines(fd->cidstrs[i],fd->cidlens[i],
2967 pscontext,fd->fds[j]->private->subrs,
2968 NULL,buffer);
2969 chars[i]->vwidth = sf->subfonts[j]->ascent+sf->subfonts[j]->descent;
2970 chars[i]->unicodeenc = uni;
2971 chars[i]->orig_pos = i;
2972 chars[i]->altuni = CIDSetAltUnis(map,i);
2973 /* There better not be any references (seac's) because we have no */
2974 /* encoding on which to base any fixups */
2975 if ( chars[i]->layers[ly_fore].refs!=NULL )
2976 IError( "Reference found in CID font. Can't fix it up");
2977 sf->subfonts[j]->glyphcnt = sf->subfonts[j]->glyphmax = i+1;
2978 ff_progress_next();
2979 }
2980 for ( i=0; i<fd->fdcnt; ++i )
2981 sf->subfonts[i]->glyphs = calloc(sf->subfonts[i]->glyphcnt,sizeof(SplineChar *));
2982 for ( i=0; i<fd->cidcnt; ++i ) if ( chars[i]!=NULL ) {
2983 j = fd->cidfds[i];
2984 if ( j<sf->subfontcnt ) {
2985 sf->subfonts[j]->glyphs[i] = chars[i];
2986 chars[i]->parent = sf->subfonts[j];
2987 }
2988 }
2989 free(chars);
2990
2991 /* Clean up the hint masks, We create an initial hintmask whether we */
2992 /* need it or not */
2993 k=0;
2994 do {
2995 _sf = k<sf->subfontcnt?sf->subfonts[k]:sf;
2996 for ( i=0; i<_sf->glyphcnt; ++i ) {
2997 if ( (sc = _sf->glyphs[i])!=NULL && !sc->hconflicts && !sc->vconflicts &&
2998 sc->layers[ly_fore].splines!=NULL ) {
2999 chunkfree( sc->layers[ly_fore].splines->first->hintmask,sizeof(HintMask) );
3000 sc->layers[ly_fore].splines->first->hintmask = NULL;
3001 }
3002 }
3003 ++k;
3004 } while ( k<sf->subfontcnt );
3005 return( sf );
3006 }
3007
SplineFontFromPSFont(FontDict * fd)3008 SplineFont *SplineFontFromPSFont(FontDict *fd) {
3009 SplineFont *sf;
3010 struct pscontext pscontext;
3011
3012 if ( fd->sf!=NULL )
3013 sf = fd->sf;
3014 else {
3015 memset(&pscontext,0,sizeof(pscontext));
3016 pscontext.is_type2 = fd->fonttype==2;
3017 pscontext.painttype = fd->painttype;
3018
3019 sf = SplineFontEmpty();
3020 SplineFontMetaData(sf,fd);
3021 if ( fd->wascff ) {
3022 SplineFontFree(sf);
3023 sf = fd->sf;
3024 } else if ( fd->fdcnt!=0 )
3025 sf = SplineFontFromCIDType1(sf,fd,&pscontext);
3026 else if ( fd->weightvector!=NULL )
3027 SplineFontFromMMType1(sf,fd,&pscontext);
3028 else
3029 SplineFontFromType1(sf,fd,&pscontext);
3030 if ( loaded_fonts_same_as_new && new_fonts_are_order2 &&
3031 fd->weightvector==NULL )
3032 SFConvertToOrder2(sf);
3033 }
3034 if ( sf->multilayer )
3035 SFCheckPSBitmap(sf);
3036 return( sf );
3037 }
3038
LayerToRefLayer(struct reflayer * rl,Layer * layer,real transform[6])3039 static void LayerToRefLayer(struct reflayer *rl,Layer *layer, real transform[6]) {
3040 BrushCopy(&rl->fill_brush, &layer->fill_brush,transform);
3041 PenCopy(&rl->stroke_pen, &layer->stroke_pen,transform);
3042 rl->dofill = layer->dofill;
3043 rl->dostroke = layer->dostroke;
3044 rl->fillfirst = layer->fillfirst;
3045 }
3046
RefLayerFindBaseLayerIndex(RefChar * rf,int layer)3047 static int RefLayerFindBaseLayerIndex(RefChar *rf, int layer) {
3048 // Note that most of the logic below is copied and lightly modified from SCReinstanciateRefChar.
3049 SplineChar *rsc = rf->sc;
3050 int i = 0, j = 0, cnt = 0;
3051 RefChar *subref;
3052 for ( i=ly_fore; i<rsc->layer_cnt; ++i ) {
3053 if ( rsc->layers[i].splines!=NULL || rsc->layers[i].images!=NULL ) {
3054 if (cnt == layer) return i;
3055 ++cnt;
3056 }
3057 for ( subref=rsc->layers[i].refs; subref!=NULL; subref=subref->next ) {
3058 for ( j=0; j<subref->layer_cnt; ++j ) if ( subref->layers[j].images!=NULL || subref->layers[j].splines!=NULL ) {
3059 if (cnt == layer) return i;
3060 ++cnt;
3061 }
3062 }
3063 }
3064 return -1;
3065 }
3066
RefCharFindBounds(RefChar * rf)3067 void RefCharFindBounds(RefChar *rf) {
3068 int i;
3069 SplineChar *rsc = rf->sc;
3070 real extra=0,e;
3071
3072 memset(&rf->bb,'\0',sizeof(rf->bb));
3073 rf->top.y = -1e10;
3074 for ( i=0; i<rf->layer_cnt; ++i ) {
3075 _SplineSetFindBounds(rf->layers[i].splines,&rf->bb);
3076 _SplineSetFindTop(rf->layers[i].splines,&rf->top);
3077 int baselayer = RefLayerFindBaseLayerIndex(rf, i);
3078 if ( baselayer >= 0 && rsc->layers[baselayer].dostroke ) {
3079 if ( rf->layers[i].stroke_pen.width!=WIDTH_INHERITED )
3080 e = rf->layers[i].stroke_pen.width*rf->layers[i].stroke_pen.trans[0];
3081 else
3082 e = rf->layers[i].stroke_pen.trans[0];
3083 if ( e>extra ) extra = e;
3084 }
3085 }
3086 if ( rf->top.y < -65536 ) rf->top.y = rf->top.x = 0;
3087 rf->bb.minx -= extra; rf->bb.miny -= extra;
3088 rf->bb.maxx += extra; rf->bb.maxy += extra;
3089 }
3090
SCReinstanciateRefChar(SplineChar * sc,RefChar * rf,int layer)3091 void SCReinstanciateRefChar(SplineChar *sc,RefChar *rf,int layer) {
3092 SplinePointList *new, *last;
3093 RefChar *refs;
3094 int i,j;
3095 SplineChar *rsc = rf->sc;
3096 real extra=0,e;
3097
3098 for ( i=0; i<rf->layer_cnt; ++i ) {
3099 SplinePointListsFree(rf->layers[i].splines);
3100 GradientFree(rf->layers[i].fill_brush.gradient);
3101 PatternFree(rf->layers[i].fill_brush.pattern);
3102 GradientFree(rf->layers[i].stroke_pen.brush.gradient);
3103 PatternFree(rf->layers[i].stroke_pen.brush.pattern);
3104 }
3105 free( rf->layers );
3106 rf->layers = NULL;
3107 rf->layer_cnt = 0;
3108 if ( rsc==NULL )
3109 return;
3110 /* Can be called before sc->parent is set, but only when reading a ttf */
3111 /* file which won't be multilayer */
3112 if ( sc->parent!=NULL && sc->parent->multilayer ) {
3113 int cnt = 0;
3114 RefChar *subref;
3115 for ( i=ly_fore; i<rsc->layer_cnt; ++i ) {
3116 if ( rsc->layers[i].splines!=NULL || rsc->layers[i].images!=NULL )
3117 ++cnt;
3118 for ( subref=rsc->layers[i].refs; subref!=NULL; subref=subref->next )
3119 cnt += subref->layer_cnt;
3120 }
3121
3122 rf->layer_cnt = cnt;
3123 rf->layers = calloc(cnt,sizeof(struct reflayer));
3124 cnt = 0;
3125 for ( i=ly_fore; i<rsc->layer_cnt; ++i ) {
3126 if ( rsc->layers[i].splines!=NULL || rsc->layers[i].images!=NULL ) {
3127 rf->layers[cnt].splines =
3128 SplinePointListTransform(
3129 SplinePointListCopy(rsc->layers[i].splines),rf->transform,tpt_AllPoints);
3130 rf->layers[cnt].images =
3131 ImageListTransform(
3132 ImageListCopy(rsc->layers[i].images),rf->transform,true);
3133 LayerToRefLayer(&rf->layers[cnt],&rsc->layers[i],rf->transform);
3134 ++cnt;
3135 }
3136 for ( subref=rsc->layers[i].refs; subref!=NULL; subref=subref->next ) {
3137 for ( j=0; j<subref->layer_cnt; ++j ) if ( subref->layers[j].images!=NULL || subref->layers[j].splines!=NULL ) {
3138 rf->layers[cnt] = subref->layers[j];
3139 rf->layers[cnt].splines =
3140 SplinePointListTransform(
3141 SplinePointListCopy(subref->layers[j].splines),rf->transform,tpt_AllPoints);
3142 rf->layers[cnt].images =
3143 ImageListTransform(
3144 ImageListCopy(subref->layers[j].images),rf->transform,true);
3145 ++cnt;
3146 }
3147 }
3148 }
3149
3150 memset(&rf->bb,'\0',sizeof(rf->bb));
3151 rf->top.y = -1e10;
3152 for ( i=0; i<rf->layer_cnt; ++i ) {
3153 _SplineSetFindBounds(rf->layers[i].splines,&rf->bb);
3154 _SplineSetFindTop(rf->layers[i].splines,&rf->top);
3155 int baselayer = RefLayerFindBaseLayerIndex(rf, i);
3156 if ( baselayer >= 0 && rsc->layers[baselayer].dostroke ) {
3157 if ( rf->layers[i].stroke_pen.width!=WIDTH_INHERITED )
3158 e = rf->layers[i].stroke_pen.width*rf->layers[i].stroke_pen.trans[0];
3159 else
3160 e = rf->layers[i].stroke_pen.trans[0];
3161 if ( e>extra ) extra = e;
3162 }
3163 }
3164 if ( rf->top.y < -65536 ) rf->top.y = rf->top.x = 0;
3165 rf->bb.minx -= extra; rf->bb.miny -= extra;
3166 rf->bb.maxx += extra; rf->bb.maxy += extra;
3167 } else {
3168 if ( rf->layer_cnt>0 ) {
3169 SplinePointListsFree(rf->layers[0].splines);
3170 rf->layers[0].splines = NULL;
3171 }
3172 rf->layers = calloc(1,sizeof(struct reflayer));
3173 rf->layer_cnt = 1;
3174 rf->layers[0].dofill = true;
3175 new = SplinePointListTransform(SplinePointListCopy(rf->sc->layers[layer].splines),rf->transform,tpt_AllPoints);
3176 rf->layers[0].splines = new;
3177 last = NULL;
3178 if ( new!=NULL )
3179 for ( last = new; last->next!=NULL; last = last->next );
3180 for ( refs = rf->sc->layers[layer].refs; refs!=NULL; refs = refs->next ) {
3181 new = SplinePointListTransform(SplinePointListCopy(refs->layers[0].splines),rf->transform,tpt_AllPoints);
3182 if ( last!=NULL )
3183 last->next = new;
3184 else
3185 rf->layers[0].splines = new;
3186 if ( new!=NULL )
3187 for ( last = new; last->next!=NULL; last = last->next );
3188 }
3189 }
3190 RefCharFindBounds(rf);
3191 }
3192
_SFReinstanciateRefs(SplineFont * sf)3193 static void _SFReinstanciateRefs(SplineFont *sf) {
3194 int i, undone, undoable, j, cnt;
3195 RefChar *ref;
3196
3197 for ( i=0; i<sf->glyphcnt; ++i ) if ( sf->glyphs[i]!=NULL )
3198 sf->glyphs[i]->ticked = false;
3199
3200 undone = true;
3201 cnt = 0;
3202 while ( undone && cnt<200) {
3203 undone = false;
3204 for ( i=0; i<sf->glyphcnt; ++i ) if ( sf->glyphs[i]!=NULL && !sf->glyphs[i]->ticked ) {
3205 undoable = false;
3206 for ( j=0; j<sf->glyphs[i]->layer_cnt; ++j ) {
3207 for ( ref=sf->glyphs[i]->layers[j].refs; ref!=NULL; ref=ref->next ) {
3208 if ( !ref->sc->ticked )
3209 undoable = true;
3210 }
3211 }
3212 if ( undoable )
3213 undone = true;
3214 else {
3215 for ( j=0; j<sf->glyphs[i]->layer_cnt; ++j ) {
3216 for ( ref=sf->glyphs[i]->layers[j].refs; ref!=NULL; ref=ref->next )
3217 SCReinstanciateRefChar(sf->glyphs[i],ref,j);
3218 }
3219 sf->glyphs[i]->ticked = true;
3220 }
3221 }
3222 ++cnt;
3223 }
3224 }
3225
SFReinstanciateRefs(SplineFont * sf)3226 void SFReinstanciateRefs(SplineFont *sf) {
3227 int i;
3228
3229 if ( sf->cidmaster!=NULL || sf->subfontcnt!=0 ) {
3230 if ( sf->cidmaster!=NULL ) sf = sf->cidmaster;
3231 for ( i=0; i<sf->subfontcnt; ++i )
3232 _SFReinstanciateRefs(sf->subfonts[i]);
3233 } else
3234 _SFReinstanciateRefs(sf);
3235 }
3236
SCReinstanciateRef(SplineChar * sc,SplineChar * rsc,int layer)3237 void SCReinstanciateRef(SplineChar *sc,SplineChar *rsc,int layer) {
3238 RefChar *rf;
3239
3240 for ( rf=sc->layers[layer].refs; rf!=NULL; rf=rf->next ) if ( rf->sc==rsc ) {
3241 SCReinstanciateRefChar(sc,rf,layer);
3242 }
3243 }
3244
SCRemoveDependent(SplineChar * dependent,RefChar * rf,int layer)3245 void SCRemoveDependent(SplineChar *dependent,RefChar *rf,int layer) {
3246 struct splinecharlist *dlist, *pd;
3247 RefChar *prev;
3248 int i;
3249
3250 if ( dependent->layers[layer].refs==rf )
3251 dependent->layers[layer].refs = rf->next;
3252 else {
3253 for ( prev = dependent->layers[layer].refs; prev->next!=rf; prev=prev->next );
3254 prev->next = rf->next;
3255 }
3256 /* Check for multiple dependencies (colon has two refs to period) */
3257 /* Also check other layers (they may include references to the same glyph as well */
3258 /* if there are none, then remove dependent from ref->sc's dependents list */
3259 for ( i=0; i<dependent->layer_cnt; i++ ) {
3260 for ( prev = dependent->layers[i].refs; prev!=NULL && (prev==rf || prev->sc!=rf->sc); prev = prev->next );
3261 }
3262 if ( prev==NULL ) {
3263 dlist = rf->sc->dependents;
3264 if ( dlist==NULL )
3265 /* Do nothing */;
3266 else if ( dlist->sc==dependent ) {
3267 rf->sc->dependents = dlist->next;
3268 } else {
3269 for ( pd=dlist, dlist = pd->next; dlist!=NULL && dlist->sc!=dependent; pd=dlist, dlist = pd->next );
3270 if ( dlist!=NULL )
3271 pd->next = dlist->next;
3272 }
3273 chunkfree(dlist,sizeof(struct splinecharlist));
3274 }
3275 RefCharFree(rf);
3276 }
3277
SCRemoveLayerDependents(SplineChar * dependent,int layer)3278 void SCRemoveLayerDependents(SplineChar *dependent,int layer) {
3279 RefChar *rf, *next;
3280
3281 for ( rf=dependent->layers[layer].refs; rf!=NULL; rf=next ) {
3282 next = rf->next;
3283 SCRemoveDependent(dependent,rf,layer);
3284 }
3285 dependent->layers[layer].refs = NULL;
3286 }
3287
SCRemoveDependents(SplineChar * dependent)3288 void SCRemoveDependents(SplineChar *dependent) {
3289 int layer;
3290
3291 for ( layer=ly_fore; layer<dependent->layer_cnt; ++layer )
3292 SCRemoveLayerDependents(dependent,layer);
3293 }
3294
SCRefToSplines(SplineChar * sc,RefChar * rf,int layer)3295 void SCRefToSplines(SplineChar *sc,RefChar *rf,int layer) {
3296 SplineSet *spl;
3297 int rlayer;
3298
3299 if ( sc->parent->multilayer ) {
3300 Layer *old = sc->layers;
3301 sc->layers = realloc(sc->layers,(sc->layer_cnt+rf->layer_cnt)*sizeof(Layer));
3302 for ( rlayer = 0; rlayer<rf->layer_cnt; ++rlayer ) {
3303 LayerDefault(&sc->layers[sc->layer_cnt+rlayer]);
3304 sc->layers[sc->layer_cnt+rlayer].splines = rf->layers[rlayer].splines;
3305 rf->layers[rlayer].splines = NULL;
3306 sc->layers[sc->layer_cnt+rlayer].images = rf->layers[rlayer].images;
3307 rf->layers[rlayer].images = NULL;
3308 sc->layers[sc->layer_cnt+rlayer].refs = NULL;
3309 sc->layers[sc->layer_cnt+rlayer].undoes = NULL;
3310 sc->layers[sc->layer_cnt+rlayer].redoes = NULL;
3311 BrushCopy(&sc->layers[sc->layer_cnt+rlayer].fill_brush, &rf->layers[rlayer].fill_brush,rf->transform);
3312 PenCopy(&sc->layers[sc->layer_cnt+rlayer].stroke_pen, &rf->layers[rlayer].stroke_pen,rf->transform);
3313 sc->layers[sc->layer_cnt+rlayer].dofill = rf->layers[rlayer].dofill;
3314 sc->layers[sc->layer_cnt+rlayer].dostroke = rf->layers[rlayer].dostroke;
3315 sc->layers[sc->layer_cnt+rlayer].fillfirst = rf->layers[rlayer].fillfirst;
3316 }
3317 sc->layer_cnt += rf->layer_cnt;
3318 SCMoreLayers(sc,old);
3319 } else {
3320 if ( (spl = rf->layers[0].splines)!=NULL ) {
3321 while ( spl->next!=NULL )
3322 spl = spl->next;
3323 spl->next = sc->layers[layer].splines;
3324 sc->layers[layer].splines = rf->layers[0].splines;
3325 rf->layers[0].splines = NULL;
3326 if ( sc->layers[layer].order2 && !sc->layers[layer].background )
3327 SCClearInstrsOrMark(sc,layer,true);
3328 }
3329 }
3330 SCRemoveDependent(sc,rf,layer);
3331 }
3332
3333 /* This returns all real solutions, even those out of bounds */
3334 /* I use -999999 as an error flag, since we're really only interested in */
3335 /* solns near 0 and 1 that should be ok. -1 is perhaps a little too close */
3336 /* Sigh. When solutions are near 0, the rounding errors are appalling. */
_CubicSolve(const Spline1D * sp,bigreal sought,extended ts[3])3337 int _CubicSolve(const Spline1D *sp,bigreal sought, extended ts[3]) {
3338 extended d, xN, yN, delta2, temp, delta, h, t2, t3, theta;
3339 extended sa=sp->a, sb=sp->b, sc=sp->c, sd=sp->d-sought;
3340 int i=0;
3341
3342 ts[0] = ts[1] = ts[2] = -999999;
3343 if ( sd==0 && sa!=0 ) {
3344 /* one of the roots is 0, the other two are the soln of a quadratic */
3345 ts[0] = 0;
3346 if ( sc==0 ) {
3347 ts[1] = -sb/(extended) sa; /* two zero roots */
3348 } else {
3349 temp = sb*(extended) sb-4*(extended) sa*sc;
3350 if ( RealNear(temp,0))
3351 ts[1] = -sb/(2*(extended) sa);
3352 else if ( temp>=0 ) {
3353 temp = sqrt(temp);
3354 ts[1] = (-sb+temp)/(2*(extended) sa);
3355 ts[2] = (-sb-temp)/(2*(extended) sa);
3356 }
3357 }
3358 } else if ( sa!=0 ) {
3359 /* http://www.m-a.org.uk/eb/mg/mg077ch.pdf */
3360 /* this nifty solution to the cubic neatly avoids complex arithmatic */
3361 xN = -sb/(3*(extended) sa);
3362 yN = ((sa*xN + sb)*xN+sc)*xN + sd;
3363
3364 delta2 = (sb*(extended) sb-3*(extended) sa*sc)/(9*(extended) sa*sa);
3365 /*if ( RealWithin(delta2,0,.00000001) ) delta2 = 0;*/
3366
3367 /* the descriminant is yN^2-h^2, but delta might be <0 so avoid using h */
3368 d = yN*yN - 4*sa*sa*delta2*delta2*delta2;
3369 if ( ((yN>.01 || yN<-.01) && RealNear(d/yN,0)) || ((yN<=.01 && yN>=-.01) && RealNear(d,0)) )
3370 d = 0;
3371 if ( d>0 ) {
3372 temp = sqrt(d);
3373 t2 = (-yN-temp)/(2*sa);
3374 t2 = (t2==0) ? 0 : (t2<0) ? -pow(-t2,1./3.) : pow(t2,1./3.);
3375 t3 = (-yN+temp)/(2*sa);
3376 t3 = t3==0 ? 0 : (t3<0) ? -pow(-t3,1./3.) : pow(t3,1./3.);
3377 ts[0] = xN + t2 + t3;
3378 } else if ( d<0 ) {
3379 if ( delta2>=0 ) {
3380 delta = sqrt(delta2);
3381 h = 2*sa*delta2*delta;
3382 temp = -yN/h;
3383 if ( temp>=-1.0001 && temp<=1.0001 ) {
3384 if ( temp<-1 ) temp = -1; else if ( temp>1 ) temp = 1;
3385 theta = acos(temp)/3;
3386 ts[i++] = xN+2*delta*cos(theta);
3387 ts[i++] = xN+2*delta*cos(2.0943951+theta); /* 2*pi/3 */
3388 ts[i++] = xN+2*delta*cos(4.1887902+theta); /* 4*pi/3 */
3389 }
3390 }
3391 } else if ( /* d==0 && */ delta2!=0 ) {
3392 delta = yN/(2*sa);
3393 delta = delta==0 ? 0 : delta>0 ? pow(delta,1./3.) : -pow(-delta,1./3.);
3394 ts[i++] = xN + delta; /* this root twice, but that's irrelevant to me */
3395 ts[i++] = xN - 2*delta;
3396 } else if ( /* d==0 && */ delta2==0 ) {
3397 if ( xN>=-0.0001 && xN<=1.0001 ) ts[0] = xN;
3398 }
3399 } else if ( sb!=0 ) {
3400 extended d = sc*(extended) sc-4*(extended) sb*sd;
3401 if ( d<0 && RealNear(d,0)) d=0;
3402 if ( d<0 )
3403 return(false); /* All roots imaginary */
3404 d = sqrt(d);
3405 ts[0] = (-sc-d)/(2*(extended) sb);
3406 ts[1] = (-sc+d)/(2*(extended) sb);
3407 } else if ( sc!=0 ) {
3408 ts[0] = -sd/(extended) sc;
3409 } else {
3410 /* If it's a point then either everything is a solution, or nothing */
3411 }
3412 return( ts[0]!=-999999 );
3413 }
3414
CubicSolve(const Spline1D * sp,bigreal sought,extended ts[3])3415 int CubicSolve(const Spline1D *sp,bigreal sought, extended ts[3]) {
3416 extended t;
3417 extended ts2[3];
3418 int i,j;
3419 /* This routine gives us all solutions between [0,1] with -1 as an error flag */
3420 /* http://mathforum.org/dr.math/faq/faq.cubic.equations.html */
3421
3422 ts[0] = ts[1] = ts[2] = -1;
3423 if ( !_CubicSolve(sp,sought,ts2)) {
3424 return( false );
3425 }
3426
3427 for ( i=j=0; i<3; ++i ) {
3428 if ( ts2[i]>-.0001 && ts2[i]<1.0001 ) {
3429 if ( ts2[i]<0 ) ts[j++] = 0;
3430 else if ( ts2[i]>1 ) ts[j++] = 1;
3431 else
3432 ts[j++] = ts2[i];
3433 }
3434 }
3435 if ( j==0 )
3436 return( false );
3437
3438 if ( ts[0]>ts[2] && ts[2]!=-1 ) {
3439 t = ts[0]; ts[0] = ts[2]; ts[2] = t;
3440 }
3441 if ( ts[0]>ts[1] && ts[1]!=-1 ) {
3442 t = ts[0]; ts[0] = ts[1]; ts[1] = t;
3443 }
3444 if ( ts[1]>ts[2] && ts[2]!=-1 ) {
3445 t = ts[1]; ts[1] = ts[2]; ts[2] = t;
3446 }
3447 return( true );
3448 }
3449
_QuarticSolve(Quartic * q,extended ts[4])3450 static int _QuarticSolve(Quartic *q,extended ts[4]) {
3451 extended extrema[5];
3452 Spline1D sp;
3453 int ecnt = 0, i, zcnt;
3454
3455 /* Two special cases */
3456 if ( q->a==0 ) { /* It's really a cubic */
3457 sp.a = q->b;
3458 sp.b = q->c;
3459 sp.c = q->d;
3460 sp.d = q->e;
3461 ts[3] = -999999;
3462 return( _CubicSolve(&sp,0,ts));
3463 } else if ( q->e==0 ) { /* we can factor out a zero root */
3464 sp.a = q->a;
3465 sp.b = q->b;
3466 sp.c = q->c;
3467 sp.d = q->d;
3468 ts[0] = 0;
3469 return( _CubicSolve(&sp,0,ts+1)+1);
3470 }
3471
3472 sp.a = 4*q->a;
3473 sp.b = 3*q->b;
3474 sp.c = 2*q->c;
3475 sp.d = q->d;
3476 if ( _CubicSolve(&sp,0,extrema)) {
3477 ecnt = 1;
3478 if ( extrema[1]!=-999999 ) {
3479 ecnt = 2;
3480 if ( extrema[1]<extrema[0] ) {
3481 extended temp = extrema[1]; extrema[1] = extrema[0]; extrema[0]=temp;
3482 }
3483 if ( extrema[2]!=-999999 ) {
3484 ecnt = 3;
3485 if ( extrema[2]<extrema[0] ) {
3486 extended temp = extrema[2]; extrema[2] = extrema[0]; extrema[0]=temp;
3487 }
3488 if ( extrema[2]<extrema[1] ) {
3489 extended temp = extrema[2]; extrema[2] = extrema[1]; extrema[1]=temp;
3490 }
3491 }
3492 }
3493 }
3494 for ( i=ecnt-1; i>=0 ; --i )
3495 extrema[i+1] = extrema[i];
3496 /* Upper and lower bounds within which we'll search */
3497 extrema[0] = -999;
3498 extrema[ecnt+1] = 999;
3499 ecnt += 2;
3500 /* divide into monotonic sections & use binary search to find zeroes */
3501 for ( i=zcnt=0; i<ecnt-1; ++i ) {
3502 extended top, bottom, val;
3503 extended topt, bottomt, t;
3504 topt = extrema[i+1];
3505 bottomt = extrema[i];
3506 top = (((q->a*topt+q->b)*topt+q->c)*topt+q->d)*topt+q->e;
3507 bottom = (((q->a*bottomt+q->b)*bottomt+q->c)*bottomt+q->d)*bottomt+q->e;
3508 if ( top<bottom ) {
3509 extended temp = top; top = bottom; bottom = temp;
3510 temp = topt; topt = bottomt; bottomt = temp;
3511 }
3512 if ( bottom>.001 ) /* this monotonic is all above 0 */
3513 continue;
3514 if ( top<-.001 ) /* this monotonic is all below 0 */
3515 continue;
3516 if ( bottom>0 ) {
3517 ts[zcnt++] = bottomt;
3518 continue;
3519 }
3520 if ( top<0 ) {
3521 ts[zcnt++] = topt;
3522 continue;
3523 }
3524 for (;;) {
3525 t = (topt+bottomt)/2;
3526 if ( t==topt || t==bottomt ) {
3527 ts[zcnt++] = t;
3528 break;
3529 }
3530
3531 val = (((q->a*t+q->b)*t+q->c)*t+q->d)*t+q->e;
3532 if ( val>-.0001 && val<.0001 ) {
3533 ts[zcnt++] = t;
3534 break;
3535 } else if ( val>0 ) {
3536 top = val;
3537 topt = t;
3538 } else {
3539 bottom = val;
3540 bottomt = t;
3541 }
3542 }
3543 }
3544 for ( i=zcnt; i<4; ++i )
3545 ts[i] = -999999;
3546 return( zcnt );
3547 }
3548
SplineSolve(const Spline1D * sp,real tmin,real tmax,extended sought)3549 extended SplineSolve(const Spline1D *sp, real tmin, real tmax, extended sought) {
3550 /* We want to find t so that spline(t) = sought */
3551 /* the curve must be monotonic */
3552 /* returns t which is near sought or -1 */
3553 extended ts[3];
3554 int i;
3555 extended t;
3556
3557 CubicSolve(sp,sought,ts);
3558 if ( tmax<tmin ) { t = tmax; tmax = tmin; tmin = t; }
3559 for ( i=0; i<3; ++i )
3560 if ( ts[i]>=tmin && ts[i]<=tmax )
3561 return( ts[i] );
3562
3563 return( -1 );
3564 }
3565
3566 /* An IEEE double has 52 bits of precision. So one unit of rounding error will be */
3567 /* the number divided by 2^51 */
3568 # define D_RE_Factor (1024.0*1024.0*1024.0*1024.0*1024.0*2.0)
3569 /* But that's not going to work near 0, so, since the t values we care about */
3570 /* are [0,1], let's use 1.0/D_RE_Factor */
3571
SplineSolveFixup(const Spline1D * sp,real tmin,real tmax,extended sought)3572 extended SplineSolveFixup(const Spline1D *sp, real tmin, real tmax, extended sought) {
3573 extended ts[3];
3574 int i;
3575 bigreal factor;
3576 extended t;
3577 extended val, valp, valm;
3578
3579 CubicSolve(sp,sought,ts);
3580 if ( tmax<tmin ) { t = tmax; tmax = tmin; tmin = t; }
3581 for ( i=0; i<3; ++i )
3582 if ( ts[i]>=tmin && ts[i]<=tmax )
3583 break;
3584 if ( i==3 ) {
3585 /* nothing in range, but ... */
3586 /* did a rounding error take a solution just outside the bounds? */
3587 extended bestd = .0001; int besti = -1;
3588 extended off;
3589 for ( i=0; i<3 && ts[i]!=-1; ++i ) {
3590 if ( ts[i]<tmin )
3591 off = tmin-ts[i];
3592 else
3593 off = ts[i]-tmax;
3594 if ( off<bestd ) {
3595 bestd = off;
3596 besti = i;
3597 }
3598 }
3599 if ( besti==-1 )
3600 return( -1 );
3601 i = besti;
3602 }
3603 t = ts[i];
3604
3605 if ((val = (((sp->a*t+sp->b)*t+sp->c)*t+sp->d) - sought)<0 )
3606 val=-val;
3607 if ( val!=0 ) {
3608 for ( factor=1024.0*1024.0*1024.0*1024.0*1024.0; factor>.5; factor/=2.0 ) {
3609 extended tp = t + (factor*t)/D_RE_Factor;
3610 extended tm = t - (factor*t)/D_RE_Factor;
3611 if ( (valp = (((sp->a*tp+sp->b)*tp+sp->c)*tp+sp->d) - sought)<0 )
3612 valp = -valp;
3613 if ( (valm = (((sp->a*tm+sp->b)*tm+sp->c)*tm+sp->d) - sought)<0 )
3614 valm = -valm;
3615 if ( valp<val && valp<valm ) {
3616 if ( factor==1024.0*1024.0*1024.0*1024*1024 ) {
3617 bigreal it = IterateSplineSolve(sp,tmin,tmax,sought);
3618 printf( "Used %g: orig-t: %g, new-t: %g iter-t: %g\n", (double) factor, (double) t, (double) tp, (double) it );
3619 }
3620 t = tp;
3621 val = valp;
3622 } else if ( valm<val ) {
3623 if ( factor==1024.0*1024.0*1024.0*1024*1024 ) {
3624 bigreal it = IterateSplineSolve(sp,tmin,tmax,sought);
3625 printf( "Used -%g: orig-t: %g, new-t: %g iter-t: %g\n", (double) factor, (double) t, (double) tm, (double) it );
3626 }
3627 t = tm;
3628 val = valm;
3629 }
3630 }
3631 }
3632 if ( t>=tmin && t<=tmax )
3633 return( t );
3634
3635 return( -1 );
3636 }
3637
IterateSplineSolve(const Spline1D * sp,extended tmin,extended tmax,extended sought)3638 extended IterateSplineSolve(const Spline1D *sp, extended tmin, extended tmax,
3639 extended sought) {
3640 extended t, low, high, test;
3641 Spline1D temp;
3642 /* Now the closed form CubicSolver can have rounding errors so if we know */
3643 /* the spline to be monotonic, an iterative approach is more accurate */
3644
3645 if ( tmin>tmax ) {
3646 t=tmin; tmin=tmax; tmax=t;
3647 }
3648
3649 temp = *sp;
3650 temp.d -= sought;
3651
3652 if ( temp.a==0 && temp.b==0 && temp.c!=0 ) {
3653 t = -temp.d/(extended) temp.c;
3654 if ( t<tmin || t>tmax )
3655 return( -1 );
3656 return( t );
3657 }
3658
3659 low = ((temp.a*tmin+temp.b)*tmin+temp.c)*tmin+temp.d;
3660 high = ((temp.a*tmax+temp.b)*tmax+temp.c)*tmax+temp.d;
3661 if ( low==0 )
3662 return(tmin);
3663 if ( high==0 )
3664 return(tmax);
3665 if (( low<0 && high>0 ) ||
3666 ( low>0 && high<0 )) {
3667
3668 for (;;) {
3669 t = (tmax+tmin)/2;
3670 if ( t==tmax || t==tmin )
3671 return( t );
3672 test = ((temp.a*t+temp.b)*t+temp.c)*t+temp.d;
3673 if ( test==0 ) /* someone complained that this test relied on exact arithmetic. In fact this test will almost never be hit, the real exit test is the line above, when tmin/tmax are so close that there is no space between them in the floating representation */
3674 return( t );
3675 if ( (low<0 && test<0) || (low>0 && test>0) )
3676 tmin=t;
3677 else
3678 tmax = t;
3679 }
3680 } else if ( low<.0001 && low>-.0001 )
3681 return( tmin ); /* Rounding errors */
3682 else if ( high<.0001 && high>-.0001 )
3683 return( tmax );
3684
3685 return( -1 );
3686 }
3687
IterateSplineSolveFixup(const Spline1D * sp,extended tmin,extended tmax,extended sought)3688 extended IterateSplineSolveFixup(const Spline1D *sp, extended tmin, extended tmax,
3689 extended sought) {
3690 // Search between tmin and tmax for a t-value at which the spline outputs sought.
3691 extended t;
3692 bigreal factor;
3693 extended val, valp, valm;
3694
3695 if ( tmin>tmax ) {
3696 t=tmin; tmin=tmax; tmax=t;
3697 }
3698
3699 t = IterateSplineSolve(sp,tmin,tmax,sought);
3700
3701 if ( t==-1 )
3702 return( -1 );
3703
3704 if ((val = (((sp->a*t+sp->b)*t+sp->c)*t+sp->d) - sought)<0 )
3705 val=-val;
3706 if ( val!=0 ) {
3707 for ( factor=1024.0*1024.0*1024.0*1024.0*1024.0; factor>.5; factor/=2.0 ) {
3708 extended tp = t + (factor*t)/D_RE_Factor;
3709 extended tm = t - (factor*t)/D_RE_Factor;
3710 if ( tp>tmax ) tp=tmax;
3711 if ( tm<tmin ) tm=tmin;
3712 if ( (valp = (((sp->a*tp+sp->b)*tp+sp->c)*tp+sp->d) - sought)<0 )
3713 valp = -valp;
3714 if ( (valm = (((sp->a*tm+sp->b)*tm+sp->c)*tm+sp->d) - sought)<0 )
3715 valm = -valm;
3716 if ( valp<val && valp<valm ) {
3717 t = tp;
3718 val = valp;
3719 } else if ( valm<val ) {
3720 t = tm;
3721 val = valm;
3722 }
3723 }
3724 }
3725 if ( t==0 && !Within16RoundingErrors(sought,sought+val))
3726 return( -1 );
3727 /* if t!=0 then we we get the chance of far worse rounding errors */
3728 else if ( t==tmax || t==tmin ) {
3729 if ( Within16RoundingErrors(sought,sought+val) ||
3730 Within16RoundingErrors(sp->a,sp->a+val) ||
3731 Within16RoundingErrors(sp->b,sp->b+val) ||
3732 Within16RoundingErrors(sp->c,sp->c+val) ||
3733 Within16RoundingErrors(sp->c,sp->c+val) ||
3734 Within16RoundingErrors(sp->d,sp->d+val))
3735 return( t );
3736 else
3737 return( -1 );
3738 }
3739
3740 if ( t>=tmin && t<=tmax )
3741 return( t );
3742
3743 /* I don't think this can happen... */
3744 return( -1 );
3745 }
3746
CheckExtremaForSingleBitErrors(const Spline1D * sp,double t,double othert)3747 double CheckExtremaForSingleBitErrors(const Spline1D *sp, double t, double othert) {
3748 double u1, um1;
3749 double slope, slope1, slopem1;
3750 int err;
3751 double diff, factor;
3752
3753 if ( t<0 || t>1 )
3754 return( t );
3755
3756 factor = t*0x40000/D_RE_Factor;
3757 if ( (diff = t-othert)<0 ) diff= -diff;
3758 if ( factor>diff/4 && diff!=0 ) /* This little check is to insure we don't skip beyond the well of this extremum into the next */
3759 factor = diff/4;
3760
3761 slope = (3*(double) sp->a*t+2*sp->b)*t+sp->c;
3762 if ( slope<0 ) slope = -slope;
3763
3764 for ( err = 0x40000; err!=0; err>>=1 ) {
3765 u1 = t+factor;
3766 slope1 = (3*(double) sp->a*u1+2*sp->b)*u1+sp->c;
3767 if ( slope1<0 ) slope1 = -slope1;
3768
3769 um1 = t-factor;
3770 slopem1 = (3*(double) sp->a*um1+2*sp->b)*um1+sp->c;
3771 if ( slopem1<0 ) slopem1 = -slopem1;
3772
3773 if ( slope1<slope && slope1<=slopem1 && u1<=1.0 ) {
3774 t = u1;
3775 } else if ( slopem1<slope && slopem1<=slope1 && um1>=0.0 ) {
3776 t = um1;
3777 }
3778 factor /= 2.0;
3779 }
3780 /* that seems as good as it gets */
3781
3782 return( t );
3783 }
3784
_SplineFindExtrema(const Spline1D * sp,extended * _t1,extended * _t2)3785 static void _SplineFindExtrema(const Spline1D *sp, extended *_t1, extended *_t2 ) {
3786 extended t1= -1, t2= -1;
3787 extended b2_fourac;
3788
3789 /* Find the extreme points on the curve */
3790 /* Set to -1 if there are none or if they are outside the range [0,1] */
3791 /* Order them so that t1<t2 */
3792 /* If only one valid extremum it will be t1 */
3793 /* (Does not check the end points unless they have derivative==0) */
3794 /* (Does not check to see if d/dt==0 points are inflection points (rather than extrema) */
3795 if ( sp->a!=0 ) {
3796 /* cubic, possibly 2 extrema (possibly none) */
3797 b2_fourac = 4*(extended)sp->b*sp->b - 12*(extended)sp->a*sp->c;
3798 if ( b2_fourac>=0 ) {
3799 b2_fourac = sqrt(b2_fourac);
3800 t1 = (-2*sp->b - b2_fourac) / (6*sp->a);
3801 t2 = (-2*sp->b + b2_fourac) / (6*sp->a);
3802 t1 = CheckExtremaForSingleBitErrors(sp,t1,t2);
3803 t2 = CheckExtremaForSingleBitErrors(sp,t2,t1);
3804 if ( t1>t2 ) { extended temp = t1; t1 = t2; t2 = temp; }
3805 else if ( t1==t2 ) t2 = -1;
3806 if ( RealNear(t1,0)) t1=0; else if ( RealNear(t1,1)) t1=1;
3807 if ( RealNear(t2,0)) t2=0; else if ( RealNear(t2,1)) t2=1;
3808 }
3809 } else if ( sp->b!=0 ) {
3810 /* Quadratic, at most one extremum */
3811 t1 = -sp->c/(2.0*(extended) sp->b);
3812 } else /*if ( sp->c!=0 )*/ {
3813 /* linear, no extrema */
3814 }
3815 *_t1 = t1; *_t2 = t2;
3816 }
3817
SplineFindExtrema(const Spline1D * sp,extended * _t1,extended * _t2)3818 void SplineFindExtrema(const Spline1D *sp, extended *_t1, extended *_t2 ) {
3819 extended t1= -1, t2= -1;
3820 extended b2_fourac;
3821
3822 /* Find the extreme points on the curve */
3823 /* Set to -1 if there are none or if they are outside the range [0,1] */
3824 /* Order them so that t1<t2 */
3825 /* If only one valid extremum it will be t1 */
3826 /* (Does not check the end points unless they have derivative==0) */
3827 /* (Does not check to see if d/dt==0 points are inflection points (rather than extrema) */
3828 if ( sp->a!=0 ) {
3829 /* cubic, possibly 2 extrema (possibly none) */
3830 b2_fourac = 4*(extended) sp->b*sp->b - 12*(extended) sp->a*sp->c;
3831 if ( b2_fourac>=0 ) {
3832 b2_fourac = sqrt(b2_fourac);
3833 t1 = (-2*sp->b - b2_fourac) / (6*sp->a);
3834 t2 = (-2*sp->b + b2_fourac) / (6*sp->a);
3835 t1 = CheckExtremaForSingleBitErrors(sp,t1,t2);
3836 t2 = CheckExtremaForSingleBitErrors(sp,t2,t1);
3837 if ( t1>t2 ) { extended temp = t1; t1 = t2; t2 = temp; }
3838 else if ( t1==t2 ) t2 = -1;
3839 if ( RealNear(t1,0)) t1=0; else if ( RealNear(t1,1)) t1=1;
3840 if ( RealNear(t2,0)) t2=0; else if ( RealNear(t2,1)) t2=1;
3841 if ( t2<=0 || t2>=1 ) t2 = -1;
3842 if ( t1<=0 || t1>=1 ) { t1 = t2; t2 = -1; }
3843 }
3844 } else if ( sp->b!=0 ) {
3845 /* Quadratic, at most one extremum */
3846 t1 = -sp->c/(2.0*(extended) sp->b);
3847 if ( t1<=0 || t1>=1 ) t1 = -1;
3848 } else /*if ( sp->c!=0 )*/ {
3849 /* linear, no extrema */
3850 }
3851 *_t1 = t1; *_t2 = t2;
3852 }
3853
SplineCurvature(Spline * s,bigreal t)3854 bigreal SplineCurvature(Spline *s, bigreal t) {
3855 /* Kappa = (x'y'' - y'x'') / (x'^2 + y'^2)^(3/2) */
3856 bigreal dxdt, dydt, d2xdt2, d2ydt2, denom, numer;
3857
3858 if ( s==NULL )
3859 return( CURVATURE_ERROR );
3860
3861 dxdt = (3*s->splines[0].a*t+2*s->splines[0].b)*t+s->splines[0].c;
3862 dydt = (3*s->splines[1].a*t+2*s->splines[1].b)*t+s->splines[1].c;
3863 d2xdt2 = 6*s->splines[0].a*t + 2*s->splines[0].b;
3864 d2ydt2 = 6*s->splines[1].a*t + 2*s->splines[1].b;
3865 denom = pow( dxdt*dxdt + dydt*dydt, 3.0/2.0 );
3866 numer = dxdt*d2ydt2 - dydt*d2xdt2;
3867
3868 if ( numer==0 )
3869 return( 0 );
3870 if ( denom==0 )
3871 return( CURVATURE_ERROR );
3872
3873 return( numer/denom );
3874 }
3875
SplineAtInflection(Spline1D * sp,bigreal t)3876 int SplineAtInflection(Spline1D *sp, bigreal t ) {
3877 /* It's a point of inflection if d sp/dt==0 and d2 sp/dt^2==0 */
3878 return ( RealNear( (3*sp->a*t + 2*sp->b)*t + sp->c,0) &&
3879 RealNear( 6*sp->a*t + 2*sp->b, 0));
3880 }
3881
SplineAtMinMax(Spline1D * sp,bigreal t)3882 int SplineAtMinMax(Spline1D *sp, bigreal t ) {
3883 /* It's a point of inflection if d sp/dt==0 and d2 sp/dt^2!=0 */
3884 return ( RealNear( (3*sp->a*t + 2*sp->b)*t + sp->c,0) &&
3885 !RealNear( 6*sp->a*t + 2*sp->b, 0));
3886 }
3887
Spline2DFindExtrema(const Spline * sp,extended extrema[4])3888 int Spline2DFindExtrema(const Spline *sp, extended extrema[4] ) {
3889 int i,j;
3890 BasePoint last, cur, mid;
3891
3892 /* If the control points are at the end-points then this (1D) spline is */
3893 /* basically a line. But rounding errors can give us very faint extrema */
3894 /* if we look for them */
3895 if ( !Spline1DCantExtremeX(sp) )
3896 SplineFindExtrema(&sp->splines[0],&extrema[0],&extrema[1]);
3897 else
3898 extrema[0] = extrema[1] = -1;
3899 if ( !Spline1DCantExtremeY(sp) )
3900 SplineFindExtrema(&sp->splines[1],&extrema[2],&extrema[3]);
3901 else
3902 extrema[2] = extrema[3] = -1;
3903
3904 for ( i=0; i<3; ++i ) for ( j=i+1; j<4; ++j ) {
3905 if ( (extrema[i]==-1 && extrema[j]!=-1) || (extrema[i]>extrema[j] && extrema[j]!=-1) ) {
3906 extended temp = extrema[i];
3907 extrema[i] = extrema[j];
3908 extrema[j] = temp;
3909 }
3910 }
3911 for ( i=j=0; i<3 && extrema[i]!=-1; ++i ) {
3912 if ( extrema[i]==extrema[i+1] ) {
3913 for ( j=i+1; j<3; ++j )
3914 extrema[j] = extrema[j+1];
3915 extrema[3] = -1;
3916 }
3917 }
3918
3919 /* Extrema which are too close together are not interesting */
3920 last = sp->from->me;
3921 for ( i=0; i<4 && extrema[i]!=-1; ++i ) {
3922 cur.x = ((sp->splines[0].a*extrema[i]+sp->splines[0].b)*extrema[i]+
3923 sp->splines[0].c)*extrema[i]+sp->splines[0].d;
3924 cur.y = ((sp->splines[1].a*extrema[i]+sp->splines[1].b)*extrema[i]+
3925 sp->splines[1].c)*extrema[i]+sp->splines[1].d;
3926 mid.x = (last.x+cur.x)/2; mid.y = (last.y+cur.y)/2;
3927 if ( (mid.x==last.x || mid.x==cur.x) &&
3928 (mid.y==last.y || mid.y==cur.y)) {
3929 for ( j=i; j<3; ++j )
3930 extrema[j] = extrema[j+1];
3931 extrema[3] = -1;
3932 --i;
3933 } else
3934 last = cur;
3935 }
3936 if ( extrema[0]!=-1 ) {
3937 mid.x = (last.x+sp->to->me.x)/2; mid.y = (last.y+sp->to->me.y)/2;
3938 if ( (mid.x==last.x || mid.x==cur.x) &&
3939 (mid.y==last.y || mid.y==cur.y))
3940 extrema[i-1] = -1;
3941 }
3942 for ( i=0; i<4 && extrema[i]!=-1; ++i );
3943 if ( i!=0 ) {
3944 cur = sp->to->me;
3945 mid.x = (last.x+cur.x)/2; mid.y = (last.y+cur.y)/2;
3946 if ( (mid.x==last.x || mid.x==cur.x) &&
3947 (mid.y==last.y || mid.y==cur.y))
3948 extrema[--i] = -1;
3949 }
3950
3951 return( i );
3952 }
3953
Spline2DFindPointsOfInflection(const Spline * sp,extended poi[2])3954 int Spline2DFindPointsOfInflection(const Spline *sp, extended poi[2] ) {
3955 int cnt=0;
3956 extended a, b, c, b2_fourac, t;
3957 /* A POI happens when d2 y/dx2 is zero. This is not the same as d2y/dt2 / d2x/dt2 */
3958 /* d2 y/dx^2 = d/dt ( dy/dt / dx/dt ) / dx/dt */
3959 /* = ( (dx/dt) * d2 y/dt2 - ((dy/dt) * d2 x/dt2) )/ (dx/dt)^3 */
3960 /* (3ax*t^2+2bx*t+cx) * (6ay*t+2by) - (3ay*t^2+2by*t+cy) * (6ax*t+2bx) == 0 */
3961 /* (3ax*t^2+2bx*t+cx) * (3ay*t+by) - (3ay*t^2+2by*t+cy) * (3ax*t+bx) == 0 */
3962 /* 9*ax*ay*t^3 + (3ax*by+6bx*ay)*t^2 + (2bx*by+3cx*ay)*t + cx*by */
3963 /* -(9*ax*ay*t^3 + (3ay*bx+6by*ax)*t^2 + (2by*bx+3cy*ax)*t + cy*bx)==0 */
3964 /* 3*(ax*by-ay*bx)*t^2 + 3*(cx*ay-cy*ax)*t+ (cx*by-cy*bx) == 0 */
3965
3966 a = 3*((extended) sp->splines[1].a*sp->splines[0].b-(extended) sp->splines[0].a*sp->splines[1].b);
3967 b = 3*((extended) sp->splines[0].c*sp->splines[1].a - (extended) sp->splines[1].c*sp->splines[0].a);
3968 c = (extended) sp->splines[0].c*sp->splines[1].b-(extended) sp->splines[1].c*sp->splines[0].b;
3969 if ( !RealNear(a,0) ) {
3970 b2_fourac = b*b - 4*a*c;
3971 poi[0] = poi[1] = -1;
3972 if ( b2_fourac<0 )
3973 return( 0 );
3974 b2_fourac = sqrt( b2_fourac );
3975 t = (-b+b2_fourac)/(2*a);
3976 if ( t>=0 && t<=1.0 )
3977 poi[cnt++] = t;
3978 t = (-b-b2_fourac)/(2*a);
3979 if ( t>=0 && t<=1.0 ) {
3980 if ( cnt==1 && poi[0]>t ) {
3981 poi[1] = poi[0];
3982 poi[0] = t;
3983 ++cnt;
3984 } else
3985 poi[cnt++] = t;
3986 }
3987 } else if ( !RealNear(b,0) ) {
3988 t = -c/b;
3989 if ( t>=0 && t<=1.0 )
3990 poi[cnt++] = t;
3991 }
3992 if ( cnt<2 )
3993 poi[cnt] = -1;
3994
3995 return( cnt );
3996 }
3997
3998 /* Ok, if the above routine finds an extremum that less than 1 unit */
3999 /* from an endpoint or another extremum, then many things are */
4000 /* just going to skip over it, and other things will be confused by this */
4001 /* so just remove it. It should be so close the difference won't matter */
SplineRemoveExtremaTooClose(Spline1D * sp,extended * _t1,extended * _t2)4002 void SplineRemoveExtremaTooClose(Spline1D *sp, extended *_t1, extended *_t2 ) {
4003 extended last, test;
4004 extended t1= *_t1, t2 = *_t2;
4005
4006 if ( t1>t2 && t2!=-1 ) {
4007 t1 = t2;
4008 t2 = *_t1;
4009 }
4010 last = sp->d;
4011 if ( t1!=-1 ) {
4012 test = ((sp->a*t1+sp->b)*t1+sp->c)*t1+sp->d;
4013 if ( (test-last)*(test-last)<1 )
4014 t1 = -1;
4015 else
4016 last = test;
4017 }
4018 if ( t2!=-1 ) {
4019 test = ((sp->a*t2+sp->b)*t2+sp->c)*t2+sp->d;
4020 if ( (test-last)*(test-last)<1 )
4021 t2 = -1;
4022 else
4023 last = test;
4024 }
4025 test = sp->a+sp->b+sp->c+sp->d;
4026 if ( (test-last)*(test-last)<1 ) {
4027 if ( t2!=-1 )
4028 t2 = -1;
4029 else if ( t1!=-1 )
4030 t1 = -1;
4031 else {
4032 /* Well we should just remove the whole spline? */
4033 ;
4034 }
4035 }
4036 *_t1 = t1; *_t2 = t2;
4037 }
4038
IntersectLines(BasePoint * inter,BasePoint * line1_1,BasePoint * line1_2,BasePoint * line2_1,BasePoint * line2_2)4039 int IntersectLines(BasePoint *inter,
4040 BasePoint *line1_1, BasePoint *line1_2,
4041 BasePoint *line2_1, BasePoint *line2_2) {
4042 // A lot of functions call this with the same address as an input and the output.
4043 // In order to avoid unexpected behavior, we delay writing to the output until the end.
4044 bigreal s1, s2;
4045 BasePoint _output;
4046 BasePoint * output = &_output;
4047 if ( line1_1->x == line1_2->x ) {
4048 // Line 1 is vertical.
4049 output->x = line1_1->x;
4050 if ( line2_1->x == line2_2->x ) {
4051 // Line 2 is vertical.
4052 if ( line2_1->x!=line1_1->x )
4053 return( false ); /* Parallel vertical lines */
4054 output->y = (line1_1->y+line2_1->y)/2;
4055 } else {
4056 output->y = line2_1->y + (output->x-line2_1->x) * (line2_2->y - line2_1->y)/(line2_2->x - line2_1->x);
4057 }
4058 *inter = *output;
4059 return( true );
4060 } else if ( line2_1->x == line2_2->x ) {
4061 // Line 2 is vertical, but we know that line 1 is not.
4062 output->x = line2_1->x;
4063 output->y = line1_1->y + (output->x-line1_1->x) * (line1_2->y - line1_1->y)/(line1_2->x - line1_1->x);
4064 *inter = *output;
4065 return( true );
4066 } else {
4067 // Both lines are oblique.
4068 s1 = (line1_2->y - line1_1->y)/(line1_2->x - line1_1->x);
4069 s2 = (line2_2->y - line2_1->y)/(line2_2->x - line2_1->x);
4070 if ( RealNear(s1,s2)) {
4071 if ( !RealNear(line1_1->y + (line2_1->x-line1_1->x) * s1,line2_1->y))
4072 return( false );
4073 output->x = (line1_2->x+line2_2->x)/2;
4074 output->y = (line1_2->y+line2_2->y)/2;
4075 } else {
4076 output->x = (s1*line1_1->x - s2*line2_1->x - line1_1->y + line2_1->y)/(s1-s2);
4077 output->y = line1_1->y + (output->x-line1_1->x) * s1;
4078 }
4079 *inter = *output;
4080 return( true );
4081 }
4082 }
4083
IntersectLinesClip(BasePoint * inter,BasePoint * line1_1,BasePoint * line1_2,BasePoint * line2_1,BasePoint * line2_2)4084 int IntersectLinesClip(BasePoint *inter,
4085 BasePoint *line1_1, BasePoint *line1_2,
4086 BasePoint *line2_1, BasePoint *line2_2) {
4087 BasePoint old = *inter, unit;
4088 bigreal len, val;
4089
4090 if ( !IntersectLines(inter,line1_1,line1_2,line2_1,line2_2))
4091 return( false );
4092 else {
4093 unit.x = line2_2->x-line1_2->x;
4094 unit.y = line2_2->y-line1_2->y;
4095 len = sqrt(unit.x*unit.x + unit.y*unit.y);
4096 if ( len==0 )
4097 return( false );
4098 else {
4099 unit.x /= len; unit.y /= len;
4100 val = unit.x*(inter->x-line1_2->x) + unit.y*(inter->y-line1_2->y);
4101 if ( val<=0 || val>=len ) {
4102 *inter = old;
4103 return( false );
4104 }
4105 }
4106 }
4107 return( true );
4108 }
4109
IntersectLinesSlopes(BasePoint * inter,BasePoint * line1,BasePoint * slope1,BasePoint * line2,BasePoint * slope2)4110 int IntersectLinesSlopes(BasePoint *inter,
4111 BasePoint *line1, BasePoint *slope1,
4112 BasePoint *line2, BasePoint *slope2) {
4113 bigreal denom = slope1->y*(bigreal) slope2->x - slope1->x*(bigreal) slope2->y;
4114 bigreal x,y;
4115
4116 if ( denom == 0 )
4117 return( false ); /* Lines are colinear, no intersection */
4118 if ( line1->x==line2->x && line1->y==line2->y ) {
4119 *inter = *line1;
4120 return( true );
4121 }
4122
4123 x = (slope1->y*(bigreal) slope2->x*line1->x -
4124 slope2->y*(bigreal) slope1->x*line2->x +
4125 slope2->x*(bigreal) slope1->x*(line2->y - line1->y)) / denom;
4126 if ( slope1->x==0 )
4127 y = slope2->y*(x-line2->x)/slope2->x + line2->y;
4128 else
4129 y = slope1->y*(x-line1->x)/slope1->x + line1->y;
4130 if ( x<-16000 || x>16000 || y<-16000 || y>16000 )
4131 return( false ); /* Effectively parallel */
4132
4133 inter->x = x;
4134 inter->y = y;
4135 return( true );
4136 }
4137
AddPoint(extended x,extended y,extended t,extended s,BasePoint * pts,extended t1s[3],extended t2s[3],int soln)4138 static int AddPoint(extended x,extended y,extended t,extended s,BasePoint *pts,
4139 extended t1s[3],extended t2s[3], int soln) {
4140 int i;
4141
4142 for ( i=0; i<soln; ++i )
4143 if ( x==pts[i].x && y==pts[i].y )
4144 return( soln );
4145 if ( soln>=9 )
4146 IError( "Too many solutions!\n" );
4147 t1s[soln] = t;
4148 t2s[soln] = s;
4149 pts[soln].x = x;
4150 pts[soln].y = y;
4151 return( soln+1 );
4152 }
4153
IterateSolve(const Spline1D * sp,extended ts[3])4154 static void IterateSolve(const Spline1D *sp,extended ts[3]) {
4155 /* The closed form solution has too many rounding errors for my taste... */
4156 int i,j;
4157
4158 ts[0] = ts[1] = ts[2] = -1;
4159
4160 if ( sp->a!=0 ) {
4161 extended e[4];
4162 e[0] = 0; e[1] = e[2] = e[3] = 1.0;
4163 SplineFindExtrema(sp,&e[1],&e[2]);
4164 if ( e[1]==-1 ) e[1] = 1;
4165 if ( e[2]==-1 ) e[2] = 1;
4166 for ( i=j=0; i<3; ++i ) {
4167 ts[j] = IterateSplineSolve(sp,e[i],e[i+1],0);
4168 if ( ts[j]!=-1 ) ++j;
4169 if ( e[i+1]==1.0 )
4170 break;
4171 }
4172 } else if ( sp->b!=0 ) {
4173 extended b2_4ac = sp->c*(extended) sp->c - 4*sp->b*(extended) sp->d;
4174 if ( b2_4ac>=0 ) {
4175 b2_4ac = sqrt(b2_4ac);
4176 ts[0] = (-sp->c-b2_4ac)/(2*sp->b);
4177 ts[1] = (-sp->c+b2_4ac)/(2*sp->b);
4178 if ( ts[0]>ts[1] ) { bigreal t = ts[0]; ts[0] = ts[1]; ts[1] = t; }
4179 }
4180 } else if ( sp->c!=0 ) {
4181 ts[0] = -sp->d/(extended) sp->c;
4182 } else {
4183 /* No solutions, or all solutions */
4184 ;
4185 }
4186
4187 for ( i=j=0; i<3; ++i )
4188 if ( ts[i]>=0 && ts[i]<=1 )
4189 ts[j++] = ts[i];
4190 for ( i=0; i<j-1; ++i )
4191 if ( ts[i]+.0000001>ts[i+1]) {
4192 ts[i] = (ts[i]+ts[i+1])/2;
4193 --j;
4194 for ( ++i; i<j; ++i )
4195 ts[i] = ts[i+1];
4196 }
4197 if ( j!=0 ) {
4198 if ( ts[0]!=0 ) {
4199 extended d0 = sp->d;
4200 extended dt = ((sp->a*ts[0]+sp->b)*ts[0]+sp->c)*ts[0]+sp->d;
4201 if ( d0<0 ) d0=-d0;
4202 if ( dt<0 ) dt=-dt;
4203 if ( d0<dt )
4204 ts[0] = 0;
4205 }
4206 if ( ts[j-1]!=1.0 ) {
4207 extended d1 = sp->a+(extended) sp->b+sp->c+sp->d;
4208 extended dt = ((sp->a*ts[j-1]+sp->b)*ts[j-1]+sp->c)*ts[j-1]+sp->d;
4209 if ( d1<0 ) d1=-d1;
4210 if ( dt<0 ) dt=-dt;
4211 if ( d1<dt )
4212 ts[j-1] = 1;
4213 }
4214 }
4215 for ( ; j<3; ++j )
4216 ts[j] = -1;
4217 }
4218
ISolveWithin(const Spline * spline,int major,extended val,extended tlow,extended thigh)4219 static extended ISolveWithin(const Spline *spline,int major,
4220 extended val,extended tlow, extended thigh) {
4221 Spline1D temp;
4222 extended ts[3];
4223 const Spline1D *sp = &spline->splines[major];
4224 int i;
4225
4226 /* Calculation for t=1 can yield rounding errors. Insist on the endpoints */
4227 /* (the Spline1D is not a perfectly accurate description of the spline, */
4228 /* but the control points are right -- at least that's my defn.) */
4229 if ( tlow==0 && val==(&spline->from->me.x)[major] )
4230 return( 0 );
4231 if ( thigh==1.0 && val==(&spline->to->me.x)[major] )
4232 return( 1.0 );
4233
4234 temp = *sp;
4235 temp.d -= val;
4236 IterateSolve(&temp,ts);
4237 if ( tlow<thigh ) {
4238 for ( i=0; i<3; ++i )
4239 if ( ts[i]>=tlow && ts[i]<=thigh )
4240 return( ts[i] );
4241 for ( i=0; i<3; ++i ) {
4242 if ( ts[i]>=tlow-1./1024. && ts[i]<=tlow )
4243 return( tlow );
4244 if ( ts[i]>=thigh && ts[i]<=thigh+1./1024 )
4245 return( thigh );
4246 }
4247 } else {
4248 for ( i=0; i<3; ++i )
4249 if ( ts[i]>=thigh && ts[i]<=tlow )
4250 return( ts[i] );
4251 for ( i=0; i<3; ++i ) {
4252 if ( ts[i]>=thigh-1./1024. && ts[i]<=thigh )
4253 return( thigh );
4254 if ( ts[i]>=tlow && ts[i]<=tlow+1./1024 )
4255 return( tlow );
4256 }
4257 }
4258 return( -1 );
4259 }
4260
ICAddInter(int cnt,BasePoint * foundpos,extended * foundt1,extended * foundt2,const Spline * s1,const Spline * s2,extended t1,extended t2,int maxcnt)4261 static int ICAddInter(int cnt,BasePoint *foundpos,extended *foundt1,extended *foundt2,
4262 const Spline *s1,const Spline *s2,extended t1,extended t2, int maxcnt) {
4263
4264 if ( cnt>=maxcnt )
4265 return( cnt );
4266
4267 foundt1[cnt] = t1;
4268 foundt2[cnt] = t2;
4269 foundpos[cnt].x = ((s1->splines[0].a*t1+s1->splines[0].b)*t1+
4270 s1->splines[0].c)*t1+s1->splines[0].d;
4271 foundpos[cnt].y = ((s1->splines[1].a*t1+s1->splines[1].b)*t1+
4272 s1->splines[1].c)*t1+s1->splines[1].d;
4273 return( cnt+1 );
4274 }
4275
ICBinarySearch(int cnt,BasePoint * foundpos,extended * foundt1,extended * foundt2,int other,const Spline * s1,const Spline * s2,extended t1low,extended t1high,extended t2low,extended t2high,int maxcnt)4276 static int ICBinarySearch(int cnt,BasePoint *foundpos,extended *foundt1,extended *foundt2,
4277 int other,
4278 const Spline *s1,const Spline *s2,extended t1low,extended t1high,extended t2low,extended t2high,
4279 int maxcnt) {
4280 int major;
4281 extended t1, t2;
4282 extended o1o, o2o, o1n, o2n, m;
4283
4284 major = !other;
4285 o1o = ((s1->splines[other].a*t1low+s1->splines[other].b)*t1low+
4286 s1->splines[other].c)*t1low+s1->splines[other].d;
4287 o2o = ((s2->splines[other].a*t2low+s2->splines[other].b)*t2low+
4288 s2->splines[other].c)*t2low+s2->splines[other].d;
4289 for (;;) {
4290 t1 = (t1low+t1high)/2;
4291 m = ((s1->splines[major].a*t1+s1->splines[major].b)*t1+
4292 s1->splines[major].c)*t1+s1->splines[major].d;
4293 t2 = ISolveWithin(s2,major,m,t2low,t2high);
4294 if ( t2==-1 )
4295 return( cnt );
4296
4297 o1n = ((s1->splines[other].a*t1+s1->splines[other].b)*t1+
4298 s1->splines[other].c)*t1+s1->splines[other].d;
4299 o2n = ((s2->splines[other].a*t2+s2->splines[other].b)*t2+
4300 s2->splines[other].c)*t2+s2->splines[other].d;
4301 if (( o1n-o2n<.001 && o1n-o2n>-.001) ||
4302 (t1-t1low<.0001 && t1-t1low>-.0001))
4303 return( ICAddInter(cnt,foundpos,foundt1,foundt2,s1,s2,t1,t2,maxcnt));
4304 if ( (o1o>o2o && o1n<o2n) || (o1o<o2o && o1n>o2n)) {
4305 t1high = t1;
4306 t2high = t2;
4307 } else {
4308 t1low = t1;
4309 t2low = t2;
4310 }
4311 }
4312 }
4313
CubicsIntersect(const Spline * s1,extended lowt1,extended hight1,BasePoint * min1,BasePoint * max1,const Spline * s2,extended lowt2,extended hight2,BasePoint * min2,BasePoint * max2,BasePoint * foundpos,extended * foundt1,extended * foundt2,int maxcnt)4314 static int CubicsIntersect(const Spline *s1,extended lowt1,extended hight1,BasePoint *min1,BasePoint *max1,
4315 const Spline *s2,extended lowt2,extended hight2,BasePoint *min2,BasePoint *max2,
4316 BasePoint *foundpos,extended *foundt1,extended *foundt2,
4317 int maxcnt) {
4318 int major, other;
4319 BasePoint max, min;
4320 extended t1max, t1min, t2max, t2min, t1, t2, t1diff, oldt2;
4321 extended o1o, o2o, o1n, o2n, m;
4322 int cnt=0;
4323
4324 if ( (min.x = min1->x)<min2->x ) min.x = min2->x;
4325 if ( (min.y = min1->y)<min2->y ) min.y = min2->y;
4326 if ( (max.x = max1->x)>max2->x ) max.x = max2->x;
4327 if ( (max.y = max1->y)>max2->y ) max.y = max2->y;
4328 if ( max.x<min.x || max.y<min.y )
4329 return( 0 );
4330 if ( max.x-min.x > max.y-min.y )
4331 major = 0;
4332 else
4333 major = 1;
4334 other = 1-major;
4335
4336 t1max = ISolveWithin(s1,major,(&max.x)[major],lowt1,hight1);
4337 t1min = ISolveWithin(s1,major,(&min.x)[major],lowt1,hight1);
4338 t2max = ISolveWithin(s2,major,(&max.x)[major],lowt2,hight2);
4339 t2min = ISolveWithin(s2,major,(&min.x)[major],lowt2,hight2);
4340 if ( t1max==-1 || t1min==-1 || t2max==-1 || t2min==-1 )
4341 return( 0 );
4342 t1diff = (t1max-t1min)/64.0;
4343 if (RealNear(t1diff,0))
4344 return( 0 );
4345
4346 t1 = t1min; t2 = t2min;
4347 o1o = t1==0 ? (&s1->from->me.x)[other] :
4348 t1==1.0 ? (&s1->to->me.x)[other] :
4349 ((s1->splines[other].a*t1+s1->splines[other].b)*t1+
4350 s1->splines[other].c)*t1+s1->splines[other].d;
4351 o2o = t2==0 ? (&s2->from->me.x)[other] :
4352 t2==1.0 ? (&s2->to->me.x)[other] :
4353 ((s2->splines[other].a*t2+s2->splines[other].b)*t2+
4354 s2->splines[other].c)*t2+s2->splines[other].d;
4355 if ( o1o==o2o )
4356 cnt = ICAddInter(cnt,foundpos,foundt1,foundt2,s1,s2,t1,t2,maxcnt);
4357 for (;;) {
4358 if ( cnt>=maxcnt )
4359 break;
4360 t1 += t1diff;
4361 if (( t1max>t1min && t1>t1max ) || (t1max<t1min && t1<t1max) || cnt>3 )
4362 break;
4363 m = t1==0 ? (&s1->from->me.x)[major] :
4364 t1==1.0 ? (&s1->to->me.x)[major] :
4365 ((s1->splines[major].a*t1+s1->splines[major].b)*t1+
4366 s1->splines[major].c)*t1+s1->splines[major].d;
4367 oldt2 = t2;
4368 t2 = ISolveWithin(s2,major,m,lowt2,hight2);
4369 if ( t2==-1 )
4370 continue;
4371
4372 o1n = t1==0 ? (&s1->from->me.x)[other] :
4373 t1==1.0 ? (&s1->to->me.x)[other] :
4374 ((s1->splines[other].a*t1+s1->splines[other].b)*t1+
4375 s1->splines[other].c)*t1+s1->splines[other].d;
4376 o2n = t2==0 ? (&s2->from->me.x)[other] :
4377 t2==1.0 ? (&s2->to->me.x)[other] :
4378 ((s2->splines[other].a*t2+s2->splines[other].b)*t2+
4379 s2->splines[other].c)*t2+s2->splines[other].d;
4380 if ( o1n==o2n )
4381 cnt = ICAddInter(cnt,foundpos,foundt1,foundt2,s1,s2,t1,t2,maxcnt);
4382 if ( (o1o>o2o && o1n<o2n) || (o1o<o2o && o1n>o2n))
4383 cnt = ICBinarySearch(cnt,foundpos,foundt1,foundt2,other,
4384 s1,s2,t1-t1diff,t1,oldt2,t2,maxcnt);
4385 o1o = o1n; o2o = o2n;
4386 }
4387 return( cnt );
4388 }
4389
Closer(const Spline * s1,const Spline * s2,extended t1,extended t2,extended t1p,extended t2p)4390 static int Closer(const Spline *s1,const Spline *s2,extended t1,extended t2,extended t1p,extended t2p) {
4391 bigreal x1 = ((s1->splines[0].a*t1+s1->splines[0].b)*t1+s1->splines[0].c)*t1+s1->splines[0].d;
4392 bigreal y1 = ((s1->splines[1].a*t1+s1->splines[1].b)*t1+s1->splines[1].c)*t1+s1->splines[1].d;
4393 bigreal x2 = ((s2->splines[0].a*t2+s2->splines[0].b)*t2+s2->splines[0].c)*t2+s2->splines[0].d;
4394 bigreal y2 = ((s2->splines[1].a*t2+s2->splines[1].b)*t2+s2->splines[1].c)*t2+s2->splines[1].d;
4395 bigreal diff = (x1-x2)*(x1-x2) + (y1-y2)*(y1-y2);
4396 bigreal x1p = ((s1->splines[0].a*t1p+s1->splines[0].b)*t1p+s1->splines[0].c)*t1p+s1->splines[0].d;
4397 bigreal y1p = ((s1->splines[1].a*t1p+s1->splines[1].b)*t1p+s1->splines[1].c)*t1p+s1->splines[1].d;
4398 bigreal x2p = ((s2->splines[0].a*t2p+s2->splines[0].b)*t2p+s2->splines[0].c)*t2p+s2->splines[0].d;
4399 bigreal y2p = ((s2->splines[1].a*t2p+s2->splines[1].b)*t2p+s2->splines[1].c)*t2p+s2->splines[1].d;
4400 bigreal diffp = (x1p-x2p)*(x1p-x2p) + (y1p-y2p)*(y1p-y2p);
4401
4402 if ( diff<diffp )
4403 return( false );
4404
4405 return( true );
4406 }
4407
4408 /* returns 0=>no intersection, 1=>at least one, location in pts, t1s, t2s */
4409 /* -1 => We couldn't figure it out in a closed form, have to do a numerical */
4410 /* approximation */
SplinesIntersect(const Spline * s1,const Spline * s2,BasePoint pts[9],extended t1s[10],extended t2s[10])4411 int SplinesIntersect(const Spline *s1, const Spline *s2, BasePoint pts[9],
4412 extended t1s[10], extended t2s[10]) { /* One extra for a trailing -1 */
4413 BasePoint min1, max1, min2, max2;
4414 int soln = 0;
4415 extended x,y,t, ac0, ac1;
4416 int i,j,found;
4417 Spline1D spline;
4418 extended tempts[4]; /* 3 solns for cubics, 4 for quartics */
4419 extended extrema1[6], extrema2[6];
4420 int ecnt1, ecnt2;
4421
4422 t1s[0] = t1s[1] = t1s[2] = t1s[3] = -1;
4423 t2s[0] = t2s[1] = t2s[2] = t2s[3] = -1;
4424
4425 if ( s1==s2 && !s1->knownlinear && !s1->isquadratic )
4426 /* Special case see if it doubles back on itself anywhere */;
4427 else if ( s1==s2 )
4428 return( 0 ); /* Linear and quadratics can't double back, can't self-intersect */
4429 else if ( s1->splines[0].a == s2->splines[0].a &&
4430 s1->splines[0].b == s2->splines[0].b &&
4431 s1->splines[0].c == s2->splines[0].c &&
4432 s1->splines[0].d == s2->splines[0].d &&
4433 s1->splines[1].a == s2->splines[1].a &&
4434 s1->splines[1].b == s2->splines[1].b &&
4435 s1->splines[1].c == s2->splines[1].c &&
4436 s1->splines[1].d == s2->splines[1].d )
4437 return( -1 ); /* Same spline. Intersects everywhere */
4438
4439 /* Ignore splines which are just a point */
4440 if ( s1->knownlinear && s1->splines[0].c==0 && s1->splines[1].c==0 )
4441 return( 0 );
4442 if ( s2->knownlinear && s2->splines[0].c==0 && s2->splines[1].c==0 )
4443 return( 0 );
4444
4445 if ( s1->knownlinear )
4446 /* Do Nothing */;
4447 else if ( s2->knownlinear || (!s1->isquadratic && s2->isquadratic)) {
4448 const Spline *stemp = s1;
4449 extended *ts = t1s;
4450 t1s = t2s; t2s = ts;
4451 s1 = s2; s2 = stemp;
4452 }
4453
4454 min1 = s1->from->me; max1 = min1;
4455 min2 = s2->from->me; max2 = min2;
4456 if ( s1->from->nextcp.x>max1.x ) max1.x = s1->from->nextcp.x;
4457 else if ( s1->from->nextcp.x<min1.x ) min1.x = s1->from->nextcp.x;
4458 if ( s1->from->nextcp.y>max1.y ) max1.y = s1->from->nextcp.y;
4459 else if ( s1->from->nextcp.y<min1.y ) min1.y = s1->from->nextcp.y;
4460 if ( s1->to->prevcp.x>max1.x ) max1.x = s1->to->prevcp.x;
4461 else if ( s1->to->prevcp.x<min1.x ) min1.x = s1->to->prevcp.x;
4462 if ( s1->to->prevcp.y>max1.y ) max1.y = s1->to->prevcp.y;
4463 else if ( s1->to->prevcp.y<min1.y ) min1.y = s1->to->prevcp.y;
4464 if ( s1->to->me.x>max1.x ) max1.x = s1->to->me.x;
4465 else if ( s1->to->me.x<min1.x ) min1.x = s1->to->me.x;
4466 if ( s1->to->me.y>max1.y ) max1.y = s1->to->me.y;
4467 else if ( s1->to->me.y<min1.y ) min1.y = s1->to->me.y;
4468
4469 if ( s2->from->nextcp.x>max2.x ) max2.x = s2->from->nextcp.x;
4470 else if ( s2->from->nextcp.x<min2.x ) min2.x = s2->from->nextcp.x;
4471 if ( s2->from->nextcp.y>max2.y ) max2.y = s2->from->nextcp.y;
4472 else if ( s2->from->nextcp.y<min2.y ) min2.y = s2->from->nextcp.y;
4473 if ( s2->to->prevcp.x>max2.x ) max2.x = s2->to->prevcp.x;
4474 else if ( s2->to->prevcp.x<min2.x ) min2.x = s2->to->prevcp.x;
4475 if ( s2->to->prevcp.y>max2.y ) max2.y = s2->to->prevcp.y;
4476 else if ( s2->to->prevcp.y<min2.y ) min2.y = s2->to->prevcp.y;
4477 if ( s2->to->me.x>max2.x ) max2.x = s2->to->me.x;
4478 else if ( s2->to->me.x<min2.x ) min2.x = s2->to->me.x;
4479 if ( s2->to->me.y>max2.y ) max2.y = s2->to->me.y;
4480 else if ( s2->to->me.y<min2.y ) min2.y = s2->to->me.y;
4481 if ( min1.x>max2.x || min2.x>max1.x || min1.y>max2.y || min2.y>max1.y )
4482 return( false ); /* no intersection of bounding boxes */
4483
4484 if ( s1->knownlinear ) {
4485 spline.d = s1->splines[1].c*((bigreal) s2->splines[0].d-(bigreal) s1->splines[0].d)-
4486 s1->splines[0].c*((bigreal) s2->splines[1].d-(bigreal) s1->splines[1].d);
4487 spline.c = s1->splines[1].c*(bigreal) s2->splines[0].c - s1->splines[0].c*(bigreal) s2->splines[1].c;
4488 spline.b = s1->splines[1].c*(bigreal) s2->splines[0].b - s1->splines[0].c*(bigreal) s2->splines[1].b;
4489 spline.a = s1->splines[1].c*(bigreal) s2->splines[0].a - s1->splines[0].c*(bigreal) s2->splines[1].a;
4490 IterateSolve(&spline,tempts);
4491 if ( tempts[0]==-1 )
4492 return( false );
4493 for ( i = 0; i<3 && tempts[i]!=-1; ++i ) {
4494 x = ((s2->splines[0].a*tempts[i]+s2->splines[0].b)*tempts[i]+
4495 s2->splines[0].c)*tempts[i]+s2->splines[0].d;
4496 y = ((s2->splines[1].a*tempts[i]+s2->splines[1].b)*tempts[i]+
4497 s2->splines[1].c)*tempts[i]+s2->splines[1].d;
4498 if ( s1->splines[0].c==0 )
4499 x = s1->splines[0].d;
4500 if ( s1->splines[1].c==0 )
4501 y = s1->splines[1].d;
4502 if ( (ac0 = s1->splines[0].c)<0 ) ac0 = -ac0;
4503 if ( (ac1 = s1->splines[1].c)<0 ) ac1 = -ac1;
4504 if ( ac0>ac1 )
4505 t = (x-s1->splines[0].d)/s1->splines[0].c;
4506 else
4507 t = (y-s1->splines[1].d)/s1->splines[1].c;
4508 if ( tempts[i]>.99996 && Closer(s1,s2,t,tempts[i],t,1)) {
4509 tempts[i] = 1;
4510 x = s2->to->me.x; y = s2->to->me.y;
4511 } else if ( tempts[i]<.00001 && Closer(s1,s2,t,tempts[i],t,0)) {
4512 tempts[i] = 0;
4513 x = s2->from->me.x; y = s2->from->me.y;
4514 }
4515 /* I know we just did this, but we might have changed x,y so redo */
4516 if ( ac0>ac1 )
4517 t = (x-s1->splines[0].d)/s1->splines[0].c;
4518 else
4519 t = (y-s1->splines[1].d)/s1->splines[1].c;
4520 if ( t>.99996 && t<1.001 && Closer(s1,s2,t,tempts[i],1,tempts[i])) {
4521 t = 1;
4522 x = s1->to->me.x; y = s1->to->me.y;
4523 } else if ( t<.00001 && t>-.001 && Closer(s1,s2,t,tempts[i],0,tempts[i])) {
4524 t = 0;
4525 x = s1->from->me.x; y = s1->from->me.y;
4526 }
4527 if ( t<-.001 || t>1.001 || x<min1.x-.01 || y<min1.y-.01 || x>max1.x+.01 || y>max1.y+.01 )
4528 continue;
4529 if ( t<=0 ) {t=0; x=s1->from->me.x; y = s1->from->me.y; }
4530 else if ( t>=1 ) { t=1; x=s1->to->me.x; y = s1->to->me.y; }
4531 if ( s1->from->me.x==s1->to->me.x ) /* Avoid rounding errors */
4532 x = s1->from->me.x; /* on hor/vert lines */
4533 else if ( s1->from->me.y==s1->to->me.y )
4534 y = s1->from->me.y;
4535 if ( s2->knownlinear ) {
4536 if ( s2->from->me.x==s2->to->me.x )
4537 x = s2->from->me.x;
4538 else if ( s2->from->me.y==s2->to->me.y )
4539 y = s2->from->me.y;
4540 }
4541 soln = AddPoint(x,y,t,tempts[i],pts,t1s,t2s,soln);
4542 }
4543 return( soln!=0 );
4544 }
4545 /* if one of the splines is quadratic then we can get an expression */
4546 /* relating c*t+d to poly(s^3), and substituting this back we get */
4547 /* a poly of degree 6 in s which could be solved iteratively */
4548 /* however mixed quadratics and cubics are unlikely */
4549
4550 /* but if both splines are degree 3, the t is expressed as the sqrt of */
4551 /* a third degree poly, which must be substituted into a cubic, and */
4552 /* then squared to get rid of the sqrts leaving us with an ?18? degree */
4553 /* poly. Ick. */
4554
4555 /* So let's do it the hard way... we break the splines into little bits */
4556 /* where they are monotonic in both dimensions, then check these for */
4557 /* possible intersections */
4558 extrema1[0] = extrema2[0] = 0;
4559 ecnt1 = Spline2DFindExtrema(s1,extrema1+1);
4560 ecnt2 = Spline2DFindExtrema(s2,extrema2+1);
4561 extrema1[++ecnt1] = 1.0;
4562 extrema2[++ecnt2] = 1.0;
4563 found=0;
4564 for ( i=0; i<ecnt1; ++i ) {
4565 min1.x = ((s1->splines[0].a*extrema1[i]+s1->splines[0].b)*extrema1[i]+
4566 s1->splines[0].c)*extrema1[i]+s1->splines[0].d;
4567 min1.y = ((s1->splines[1].a*extrema1[i]+s1->splines[1].b)*extrema1[i]+
4568 s1->splines[1].c)*extrema1[i]+s1->splines[1].d;
4569 max1.x = ((s1->splines[0].a*extrema1[i+1]+s1->splines[0].b)*extrema1[i+1]+
4570 s1->splines[0].c)*extrema1[i+1]+s1->splines[0].d;
4571 max1.y = ((s1->splines[1].a*extrema1[i+1]+s1->splines[1].b)*extrema1[i+1]+
4572 s1->splines[1].c)*extrema1[i+1]+s1->splines[1].d;
4573 if ( max1.x<min1.x ) { extended temp = max1.x; max1.x = min1.x; min1.x = temp; }
4574 if ( max1.y<min1.y ) { extended temp = max1.y; max1.y = min1.y; min1.y = temp; }
4575 for ( j=(s1==s2)?i+1:0; j<ecnt2; ++j ) {
4576 min2.x = ((s2->splines[0].a*extrema2[j]+s2->splines[0].b)*extrema2[j]+
4577 s2->splines[0].c)*extrema2[j]+s2->splines[0].d;
4578 min2.y = ((s2->splines[1].a*extrema2[j]+s2->splines[1].b)*extrema2[j]+
4579 s2->splines[1].c)*extrema2[j]+s2->splines[1].d;
4580 max2.x = ((s2->splines[0].a*extrema2[j+1]+s2->splines[0].b)*extrema2[j+1]+
4581 s2->splines[0].c)*extrema2[j+1]+s2->splines[0].d;
4582 max2.y = ((s2->splines[1].a*extrema2[j+1]+s2->splines[1].b)*extrema2[j+1]+
4583 s2->splines[1].c)*extrema2[j+1]+s2->splines[1].d;
4584 if ( max2.x<min2.x ) { extended temp = max2.x; max2.x = min2.x; min2.x = temp; }
4585 if ( max2.y<min2.y ) { extended temp = max2.y; max2.y = min2.y; min2.y = temp; }
4586 if ( min1.x>max2.x || min2.x>max1.x || min1.y>max2.y || min2.y>max1.y )
4587 /* No possible intersection */;
4588 else if ( s1!=s2 )
4589 found += CubicsIntersect(s1,extrema1[i],extrema1[i+1],&min1,&max1,
4590 s2,extrema2[j],extrema2[j+1],&min2,&max2,
4591 &pts[found],&t1s[found],&t2s[found],9-found);
4592 else {
4593 int k,l;
4594 int cnt = CubicsIntersect(s1,extrema1[i],extrema1[i+1],&min1,&max1,
4595 s2,extrema2[j],extrema2[j+1],&min2,&max2,
4596 &pts[found],&t1s[found],&t2s[found],9-found);
4597 for ( k=0; k<cnt; ++k ) {
4598 if ( RealNear(t1s[found+k],t2s[found+k]) ) {
4599 for ( l=k+1; l<cnt; ++l ) {
4600 pts[found+l-1] = pts[found+l];
4601 t1s[found+l-1] = t1s[found+l];
4602 t2s[found+l-1] = t2s[found+l];
4603 }
4604 --cnt; --k;
4605 }
4606 }
4607 found += cnt;
4608 }
4609 if ( found>=8 ) {
4610 /* If the splines are colinear then we might get an unbounded */
4611 /* number of intersections */
4612 break;
4613 }
4614 }
4615 }
4616 t1s[found] = t2s[found] = -1;
4617 return( found!=0 );
4618 }
4619
4620 /* Puts all the contours of the glyph together. Next routine undoes this */
LayerAllSplines(Layer * layer)4621 SplineSet *LayerAllSplines(Layer *layer) {
4622 SplineSet *head=NULL, *last=NULL;
4623 RefChar *r;
4624
4625 head = layer->splines;
4626 if ( head!=NULL )
4627 for ( last=head; last->next!=NULL; last = last->next );
4628 for ( r=layer->refs; r!=NULL; r=r->next ) {
4629 if ( last!=NULL ) {
4630 last->next = r->layers[0].splines;
4631 for ( ; last->next!=NULL; last=last->next );
4632 } else {
4633 head = r->layers[0].splines;
4634 if ( head!=NULL )
4635 for ( last=head; last->next!=NULL; last = last->next );
4636 }
4637 }
4638 return( head );
4639 }
4640
LayerUnAllSplines(Layer * layer)4641 SplineSet *LayerUnAllSplines(Layer *layer) {
4642 SplineSet *spl = layer->splines;
4643 RefChar *r = layer->refs;
4644
4645 if ( spl==NULL ) {
4646 while ( r!=NULL && r->layers[0].splines==NULL )
4647 r = r->next;
4648 if ( r==NULL )
4649 return( NULL );
4650 spl = r->layers[0].splines;
4651 do { r = r->next; } while ( r!=NULL && r->layers[0].splines==NULL );
4652 }
4653 while ( r!=NULL ) {
4654 while ( spl!=NULL && spl->next!=r->layers[0].splines )
4655 spl = spl->next;
4656 spl->next = NULL;
4657 spl = r->layers[0].splines;
4658 do { r = r->next; } while ( r!=NULL && r->layers[0].splines==NULL );
4659 }
4660 return( layer->splines );
4661 }
4662
SplineSetIntersect(SplineSet * spl,Spline ** _spline,Spline ** _spline2)4663 int SplineSetIntersect(SplineSet *spl, Spline **_spline, Spline **_spline2) {
4664 BasePoint pts[9];
4665 extended t1s[10], t2s[10];
4666 int found = false,i;
4667 SplineSet *test, *test2;
4668 Spline *spline, *spline2, *first, *first2;
4669
4670 for ( test=spl; test!=NULL ; test=test->next ) {
4671 first = NULL;
4672 for ( spline = test->first->next; spline!=NULL && spline!=first; spline=spline->to->next ) {
4673 if ( first==NULL ) first = spline;
4674 for ( test2=test; test2!=NULL; test2=test2->next ) {
4675 first2 = test2==test && first!=spline ? first : NULL;
4676 for ( spline2=(test2==test)?spline : test2->first->next;
4677 spline2!=NULL && spline2!=first2; spline2 = spline2->to->next ) {
4678 if ( first2==NULL ) first2 = spline2;
4679 if ( SplinesIntersect(spline,spline2,pts,t1s,t2s)) {
4680 if ( spline->to->next!=spline2 && spline->from->prev!=spline2 )
4681 found = true;
4682 else for ( i=0; i<10 && t1s[i]!=-1; ++i ) {
4683 if ( (t1s[i]<.999 && t1s[i]>.001) || (t2s[i]<.999 && t2s[i]>.001)) {
4684 found = true;
4685 break;
4686 }
4687 }
4688 if ( found )
4689 break;
4690 }
4691 }
4692 if ( found )
4693 break;
4694 }
4695 if ( found )
4696 break;
4697 }
4698 if ( found )
4699 break;
4700 }
4701 if ( found ) {
4702 *_spline = spline;
4703 *_spline2 = spline2;
4704 }
4705 return( found );
4706 }
4707
LineTangentToSplineThroughPt(Spline * s,BasePoint * pt,extended ts[4],extended tmin,extended tmax)4708 int LineTangentToSplineThroughPt(Spline *s, BasePoint *pt, extended ts[4],
4709 extended tmin, extended tmax) {
4710 /* attempt to find a line though the point pt which is tangent to the spline */
4711 /* we return t of the tangent point on the spline (if any) */
4712 /* So the slope of the line through pt&tangent point must match slope */
4713 /* at the tangent point on the spline. Or... */
4714 /* (pt.x-xt)/(pt.y-yt) = (dx/dt)/(dy/dt) */
4715 /* (pt.x-xt)*(dy/dt) = (pt.y-yt)*(dx/dt) */
4716 /* (pt.x - ax*t^3 - bx*t^2 - cx*t - dx)(3ay*t^2 + 2by*t + cy) = */
4717 /* (pt.y - ay*t^3 - by*t^2 - cy*t^2 - dy)(3ax*t^2 + 2bx*t + cx) */
4718 /* (-ax*3ay + ay*3ax) * t^5 + */
4719 /* (-ax*2by - bx*3ay + ay*2bx + by*3ax) * t^4 + */
4720 /* (-ax*cy - bx*2by - cx*3ay + ay*cx + by*2bx + cy*3ax) * t^3 + */
4721 /* (pt.x*3ay - bx*cy - cx*2by - dx*3ay - pt.y*3ax + by*cx + cy*2bx + dy*3ax) * t^2 + */
4722 /* (pt.x*2by - cx*cy - dx*2by - pt.y*2bx + cy*cx + dy*2bx) * t + */
4723 /* (pt.x*cy - dx*cy - pt.y*cx + dy*cx) = 0 */
4724 /* Yeah! The order 5 terms cancel out */
4725 /* (ax*by - bx*ay) * t^4 + */
4726 /* (2*ax*cy - 2*cx*ay) * t^3 + */
4727 /* (3*pt.x*ay + bx*cy - cx*by - 3*dx*ay - 3*pt.y*ax + 3*dy*ax) * t^2 + */
4728 /* (2*pt.x*by - 2*dx*by - 2*pt.y*bx + 2*dy*bx) * t + */
4729 /* (pt.x*cy - dx*cy - pt.y*cx + dy*cx) = 0 */
4730 Quartic quad;
4731 int i,j,k;
4732
4733 if ( !isfinite(pt->x) || !isfinite(pt->y) ) {
4734 IError( "Non-finite arguments passed to LineTangentToSplineThroughPt");
4735 return( -1 );
4736 }
4737
4738 quad.a = s->splines[0].a*s->splines[1].b - s->splines[0].b*s->splines[1].a;
4739 quad.b = 2*s->splines[0].a*s->splines[1].c - 2*s->splines[0].c*s->splines[1].a;
4740 quad.c = 3*pt->x*s->splines[1].a + s->splines[0].b*s->splines[1].c - s->splines[0].c*s->splines[1].b - 3*s->splines[0].d*s->splines[1].a - 3*pt->y*s->splines[0].a + 3*s->splines[1].d*s->splines[0].a;
4741 quad.d = 2*pt->x*s->splines[1].b - 2*s->splines[0].d*s->splines[1].b - 2*pt->y*s->splines[0].b + 2*s->splines[1].d*s->splines[0].b;
4742 quad.e = pt->x*s->splines[1].c - s->splines[0].d*s->splines[1].c - pt->y*s->splines[0].c + s->splines[1].d*s->splines[0].c;
4743
4744 if ( _QuarticSolve(&quad,ts)==-1 )
4745 return( -1 );
4746
4747 for ( i=0; i<4 && ts[i]!=-999999; ++i ) {
4748 if ( ts[i]>tmin-.0001 && ts[i]<tmin ) ts[i] = tmin;
4749 if ( ts[i]>tmax && ts[i]<tmax+.001 ) ts[i] = tmax;
4750 if ( ts[i]>tmax || ts[i]<tmin ) ts[i] = -999999;
4751 }
4752 for ( i=3; i>=0 && ts[i]==-999999; --i );
4753 if ( i==-1 )
4754 return( -1 );
4755 for ( j=i ; j>=0 ; --j ) {
4756 if ( ts[j]<0 ) {
4757 for ( k=j+1; k<=i; ++k )
4758 ts[k-1] = ts[k];
4759 ts[i--] = -999999;
4760 }
4761 }
4762 return(i+1);
4763 }
4764
XSolve(Spline * spline,real tmin,real tmax,FindSel * fs)4765 static int XSolve(Spline *spline,real tmin, real tmax,FindSel *fs) {
4766 Spline1D *yspline = &spline->splines[1], *xspline = &spline->splines[0];
4767 bigreal t,x,y;
4768
4769 fs->p->t = t = SplineSolve(xspline,tmin,tmax,fs->p->cx);
4770 if ( t>=0 && t<=1 ) {
4771 y = ((yspline->a*t+yspline->b)*t+yspline->c)*t + yspline->d;
4772 if ( fs->yl<y && fs->yh>y )
4773 return( true );
4774 }
4775 /* Although we know that globaly there's more x change, locally there */
4776 /* maybe more y change */
4777 fs->p->t = t = SplineSolve(yspline,tmin,tmax,fs->p->cy);
4778 if ( t>=0 && t<=1 ) {
4779 x = ((xspline->a*t+xspline->b)*t+xspline->c)*t + xspline->d;
4780 if ( fs->xl<x && fs->xh>x )
4781 return( true );
4782 }
4783 return( false );
4784 }
4785
YSolve(Spline * spline,real tmin,real tmax,FindSel * fs)4786 static int YSolve(Spline *spline,real tmin, real tmax,FindSel *fs) {
4787 Spline1D *yspline = &spline->splines[1], *xspline = &spline->splines[0];
4788 bigreal t,x,y;
4789
4790 fs->p->t = t = SplineSolve(yspline,tmin,tmax,fs->p->cy);
4791 if ( t>=0 && t<=1 ) {
4792 x = ((xspline->a*t+xspline->b)*t+xspline->c)*t + xspline->d;
4793 if ( fs->xl<x && fs->xh>x )
4794 return( true );
4795 }
4796 /* Although we know that globaly there's more y change, locally there */
4797 /* maybe more x change */
4798 fs->p->t = t = SplineSolve(xspline,tmin,tmax,fs->p->cx);
4799 if ( t>=0 && t<=1 ) {
4800 y = ((yspline->a*t+yspline->b)*t+yspline->c)*t + yspline->d;
4801 if ( fs->yl<y && fs->yh>y )
4802 return( true );
4803 }
4804 return( false );
4805 }
4806
NearXSpline(FindSel * fs,Spline * spline)4807 static int NearXSpline(FindSel *fs, Spline *spline) {
4808 /* If we get here we've checked the bounding box and we're in it */
4809 /* the y spline is a horizontal line */
4810 /* the x spline is not linear */
4811 bigreal t,y;
4812 Spline1D *yspline = &spline->splines[1], *xspline = &spline->splines[0];
4813
4814 if ( xspline->a!=0 ) {
4815 extended t1, t2, tbase;
4816 SplineFindExtrema(xspline,&t1,&t2);
4817 tbase = 0;
4818 if ( t1!=-1 ) {
4819 if ( XSolve(spline,0,t1,fs))
4820 return( true );
4821 tbase = t1;
4822 }
4823 if ( t2!=-1 ) {
4824 if ( XSolve(spline,tbase,t2,fs))
4825 return( true );
4826 tbase = t2;
4827 }
4828 if ( XSolve(spline,tbase,1.0,fs))
4829 return( true );
4830 } else if ( xspline->b!=0 ) {
4831 bigreal root = xspline->c*xspline->c - 4*xspline->b*(xspline->d-fs->p->cx);
4832 if ( root < 0 )
4833 return( false );
4834 root = sqrt(root);
4835 fs->p->t = t = (-xspline->c + root)/(2*xspline->b);
4836 if ( t>=0 && t<=1 ) {
4837 y = ((yspline->a*t+yspline->b)*t+yspline->c)*t + yspline->d;
4838 if ( fs->yl<y && fs->yh>y )
4839 return( true );
4840 }
4841 fs->p->t = t = (-xspline->c - root)/(2*xspline->b);
4842 if ( t>=0 && t<=1 ) {
4843 y = ((yspline->a*t+yspline->b)*t+yspline->c)*t + yspline->d;
4844 if ( fs->yl<y && fs->yh>y )
4845 return( true );
4846 }
4847 } else /* xspline->c can't be 0 because dx>dy => dx!=0 => xspline->c!=0 */ {
4848 fs->p->t = t = (fs->p->cx-xspline->d)/xspline->c;
4849 y = ((yspline->a*t+yspline->b)*t+yspline->c)*t + yspline->d;
4850 if ( fs->yl<y && fs->yh>y )
4851 return( true );
4852 }
4853 return( false );
4854 }
4855
NearSpline(FindSel * fs,Spline * spline)4856 int NearSpline(FindSel *fs, Spline *spline) {
4857 bigreal t,x,y;
4858 Spline1D *yspline = &spline->splines[1], *xspline = &spline->splines[0];
4859 bigreal dx, dy;
4860
4861 if (( dx = spline->to->me.x-spline->from->me.x)<0 ) dx = -dx;
4862 if (( dy = spline->to->me.y-spline->from->me.y)<0 ) dy = -dy;
4863
4864 if ( spline->knownlinear ) {
4865 if ( fs->xl > spline->from->me.x && fs->xl > spline->to->me.x )
4866 return( false );
4867 if ( fs->xh < spline->from->me.x && fs->xh < spline->to->me.x )
4868 return( false );
4869 if ( fs->yl > spline->from->me.y && fs->yl > spline->to->me.y )
4870 return( false );
4871 if ( fs->yh < spline->from->me.y && fs->yh < spline->to->me.y )
4872 return( false );
4873 if ( xspline->c==0 && yspline->c==0 ) /* It's a point. */
4874 return( true );
4875 if ( dy>dx ) {
4876 t = (fs->p->cy-yspline->d)/yspline->c;
4877 fs->p->t = t;
4878 x = xspline->c*t + xspline->d;
4879 if ( fs->xl<x && fs->xh>x && t>=0 && t<=1 )
4880 return( true );
4881 } else {
4882 t = (fs->p->cx-xspline->d)/xspline->c;
4883 fs->p->t = t;
4884 y = yspline->c*t + yspline->d;
4885 if ( fs->yl<y && fs->yh>y && t>=0 && t<=1 )
4886 return( true );
4887 }
4888 return( false );
4889 } else {
4890 if ( fs->xl > spline->from->me.x && fs->xl > spline->to->me.x &&
4891 fs->xl > spline->from->nextcp.x && fs->xl > spline->to->prevcp.x )
4892 return( false );
4893 if ( fs->xh < spline->from->me.x && fs->xh < spline->to->me.x &&
4894 fs->xh < spline->from->nextcp.x && fs->xh < spline->to->prevcp.x )
4895 return( false );
4896 if ( fs->yl > spline->from->me.y && fs->yl > spline->to->me.y &&
4897 fs->yl > spline->from->nextcp.y && fs->yl > spline->to->prevcp.y )
4898 return( false );
4899 if ( fs->yh < spline->from->me.y && fs->yh < spline->to->me.y &&
4900 fs->yh < spline->from->nextcp.y && fs->yh < spline->to->prevcp.y )
4901 return( false );
4902
4903 if ( dx>dy )
4904 return( NearXSpline(fs,spline));
4905 else if ( yspline->a == 0 && yspline->b == 0 ) {
4906 fs->p->t = t = (fs->p->cy-yspline->d)/yspline->c;
4907 x = ((xspline->a*t+xspline->b)*t+xspline->c)*t + xspline->d;
4908 if ( fs->xl<x && fs->xh>x && t>=0 && t<=1 )
4909 return( true );
4910 } else if ( yspline->a==0 ) {
4911 bigreal root = yspline->c*yspline->c - 4*yspline->b*(yspline->d-fs->p->cy);
4912 if ( root < 0 )
4913 return( false );
4914 root = sqrt(root);
4915 fs->p->t = t = (-yspline->c + root)/(2*yspline->b);
4916 x = ((xspline->a*t+xspline->b)*t+xspline->c)*t + xspline->d;
4917 if ( fs->xl<x && fs->xh>x && t>0 && t<1 )
4918 return( true );
4919 fs->p->t = t = (-yspline->c - root)/(2*yspline->b);
4920 x = ((xspline->a*t+xspline->b)*t+xspline->c)*t + xspline->d;
4921 if ( fs->xl<x && fs->xh>x && t>=0 && t<=1 )
4922 return( true );
4923 } else {
4924 extended t1, t2, tbase;
4925 SplineFindExtrema(yspline,&t1,&t2);
4926 tbase = 0;
4927 if ( t1!=-1 ) {
4928 if ( YSolve(spline,0,t1,fs))
4929 return( true );
4930 tbase = t1;
4931 }
4932 if ( t2!=-1 ) {
4933 if ( YSolve(spline,tbase,t2,fs))
4934 return( true );
4935 tbase = t2;
4936 }
4937 if ( YSolve(spline,tbase,1.0,fs))
4938 return( true );
4939 }
4940 }
4941 return( false );
4942 }
4943
SplineNearPoint(Spline * spline,BasePoint * bp,real fudge)4944 real SplineNearPoint(Spline *spline, BasePoint *bp, real fudge) {
4945 PressedOn p;
4946 FindSel fs;
4947
4948 memset(&fs,'\0',sizeof(fs));
4949 memset(&p,'\0',sizeof(p));
4950 fs.p = &p;
4951 p.cx = bp->x;
4952 p.cy = bp->y;
4953 fs.fudge = fudge;
4954 fs.xl = p.cx-fudge;
4955 fs.xh = p.cx+fudge;
4956 fs.yl = p.cy-fudge;
4957 fs.yh = p.cy+fudge;
4958 if ( !NearSpline(&fs,spline))
4959 return( -1 );
4960
4961 return( p.t );
4962 }
4963
SplineT2SpiroIndex(Spline * spline,bigreal t,SplineSet * spl)4964 int SplineT2SpiroIndex(Spline *spline,bigreal t,SplineSet *spl) {
4965 /* User clicked on a spline. Now, where in the spiro array was that? */
4966 /* I shall assume that the first time we hit a spiro point that corresponds */
4967 /* to the point. In some really gnarly spiro tangles that might not be */
4968 /* true, but in a well behaved contour I think (hope) it will be ok */
4969
4970 /* It appears that each spiro cp has a corresponding splinepoint, but */
4971 /* I don't want to rely on that because it won't be true after a simplify*/
4972 Spline *sp, *lastsp=spl->first->next;
4973 bigreal test;
4974 int i;
4975 BasePoint bp;
4976
4977 for ( i=1; i<spl->spiro_cnt; ++i ) { /* For once I do mean spiro count, that loops back to the start for close contours */
4978 if ( i<spl->spiro_cnt-1 ) {
4979 bp.x = spl->spiros[i].x;
4980 bp.y = spl->spiros[i].y;
4981 } else if ( SPIRO_SPL_OPEN(spl))
4982 return( -1 );
4983 else {
4984 bp.x = spl->spiros[0].x;
4985 bp.y = spl->spiros[0].y;
4986 }
4987 for ( sp=lastsp; ; ) {
4988 test = SplineNearPoint(sp,&bp,.001);
4989 if ( test==-1 ) {
4990 if ( sp==spline )
4991 return( i-1 );
4992 } else {
4993 if ( sp==spline && t<test )
4994 return( i-1 );
4995 lastsp = sp;
4996 break;
4997 }
4998 if ( sp->to->next==NULL || sp->to==spl->first )
4999 return( -1 );
5000 sp = sp->to->next;
5001 }
5002 }
5003 return( -1 );
5004 }
5005
SplinePrevMinMax(Spline * s,int up)5006 static int SplinePrevMinMax(Spline *s,int up) {
5007 const bigreal t = .9999;
5008 bigreal y;
5009 int pup;
5010
5011 s = s->from->prev;
5012 while ( s->from->me.y==s->to->me.y && s->islinear )
5013 s = s->from->prev;
5014 y = ((s->splines[1].a*t + s->splines[1].b)*t + s->splines[1].c)*t + s->splines[1].d;
5015 pup = s->to->me.y > y;
5016 return( pup!=up );
5017 }
5018
SplineNextMinMax(Spline * s,int up)5019 static int SplineNextMinMax(Spline *s,int up) {
5020 const bigreal t = .0001;
5021 bigreal y;
5022 int nup;
5023
5024 s = s->to->next;
5025 while ( s->from->me.y==s->to->me.y && s->islinear )
5026 s = s->to->next;
5027 y = ((s->splines[1].a*t + s->splines[1].b)*t + s->splines[1].c)*t + s->splines[1].d;
5028 nup = y > s->from->me.y;
5029 return( nup!=up );
5030 }
5031
Crossings(Spline * s,BasePoint * pt)5032 static int Crossings(Spline *s,BasePoint *pt) {
5033 extended ext[4];
5034 int i, cnt=0;
5035 bigreal yi, yi1, t, x;
5036
5037 ext[0] = 0; ext[3] = 1.0;
5038 SplineFindExtrema(&s->splines[1],&ext[1],&ext[2]);
5039 if ( ext[2]!=-1 && SplineAtInflection(&s->splines[1],ext[2])) ext[2]=-1;
5040 if ( ext[1]!=-1 && SplineAtInflection(&s->splines[1],ext[1])) {ext[1] = ext[2]; ext[2]=-1;}
5041 if ( ext[1]==-1 ) ext[1] = 1.0;
5042 else if ( ext[2]==-1 ) ext[2] = 1.0;
5043 yi = s->splines[1].d;
5044 for ( i=0; ext[i]!=1.0; ++i, yi=yi1 ) {
5045 yi1 = ((s->splines[1].a*ext[i+1]+s->splines[1].b)*ext[i+1]+s->splines[1].c)*ext[i+1]+s->splines[1].d;
5046 if ( yi==yi1 )
5047 continue; /* Ignore horizontal lines */
5048 if ( (yi>yi1 && (pt->y<yi1 || pt->y>yi)) ||
5049 (yi<yi1 && (pt->y<yi || pt->y>yi1)) )
5050 continue;
5051 t = IterateSplineSolve(&s->splines[1],ext[i],ext[i+1],pt->y);
5052 if ( t==-1 )
5053 continue;
5054 x = ((s->splines[0].a*t+s->splines[0].b)*t+s->splines[0].c)*t+s->splines[0].d;
5055 if ( x>=pt->x ) /* Things on the edge are not inside */
5056 continue;
5057 if (( ext[i]!=0 && RealApprox(t,ext[i]) && SplineAtMinMax(&s->splines[1],ext[i]) ) ||
5058 ( ext[i+1]!=1 && RealApprox(t,ext[i+1]) && SplineAtMinMax(&s->splines[1],ext[i+1]) ))
5059 continue; /* Min/Max points don't add to count */
5060 if (( RealApprox(t,0) && SplinePrevMinMax(s,yi1>yi) ) ||
5061 ( RealApprox(t,1) && SplineNextMinMax(s,yi1>yi) ))
5062 continue; /* ditto */
5063 if ( pt->y==yi1 ) /* Not a min/max. prev/next spline continues same direction */
5064 continue; /* If it's at an endpoint we don't want to count it twice */
5065 /* So only add to count at start endpoint, never at final */
5066 if ( yi1>yi )
5067 ++cnt;
5068 else
5069 --cnt;
5070 }
5071 return( cnt );
5072 }
5073
5074 /* Return whether this point is within the set of contours in spl */
5075 /* Draw a line from [-infinity,pt.y] to [pt.x,pt.y] and count contour crossings */
SSPointWithin(SplineSet * spl,BasePoint * pt)5076 int SSPointWithin(SplineSet *spl,BasePoint *pt) {
5077 int cnt=0;
5078 Spline *s, *first;
5079
5080 while ( spl!=NULL ) {
5081 if ( spl->first->prev!=NULL ) {
5082 first = NULL;
5083 for ( s = spl->first->next; s!=first; s=s->to->next ) {
5084 if ( first==NULL ) first = s;
5085 if (( s->from->me.x>pt->x && s->from->nextcp.x>pt->x &&
5086 s->to->me.x>pt->x && s->to->prevcp.x>pt->x) ||
5087 ( s->from->me.y>pt->y && s->from->nextcp.y>pt->y &&
5088 s->to->me.y>pt->y && s->to->prevcp.y>pt->y) ||
5089 ( s->from->me.y<pt->y && s->from->nextcp.y<pt->y &&
5090 s->to->me.y<pt->y && s->to->prevcp.y<pt->y))
5091 continue;
5092 cnt += Crossings(s,pt);
5093 }
5094 }
5095 spl = spl->next;
5096 }
5097 return( cnt!=0 );
5098 }
5099
StemInfoFree(StemInfo * h)5100 void StemInfoFree(StemInfo *h) {
5101 HintInstance *hi, *n;
5102
5103 for ( hi=h->where; hi!=NULL; hi=n ) {
5104 n = hi->next;
5105 chunkfree(hi,sizeof(HintInstance));
5106 }
5107 chunkfree(h,sizeof(StemInfo));
5108 }
5109
StemInfosFree(StemInfo * h)5110 void StemInfosFree(StemInfo *h) {
5111 StemInfo *hnext;
5112 HintInstance *hi, *n;
5113
5114 for ( ; h!=NULL; h = hnext ) {
5115 for ( hi=h->where; hi!=NULL; hi=n ) {
5116 n = hi->next;
5117 chunkfree(hi,sizeof(HintInstance));
5118 }
5119 hnext = h->next;
5120 chunkfree(h,sizeof(StemInfo));
5121 }
5122 }
5123
DStemInfoFree(DStemInfo * h)5124 void DStemInfoFree(DStemInfo *h) {
5125 HintInstance *hi, *n;
5126
5127 for ( hi=h->where; hi!=NULL; hi=n ) {
5128 n = hi->next;
5129 chunkfree(hi,sizeof(HintInstance));
5130 }
5131 chunkfree(h,sizeof(DStemInfo));
5132 }
5133
DStemInfosFree(DStemInfo * h)5134 void DStemInfosFree(DStemInfo *h) {
5135 DStemInfo *hnext;
5136 HintInstance *hi, *n;
5137
5138 for ( ; h!=NULL; h = hnext ) {
5139 for ( hi=h->where; hi!=NULL; hi=n ) {
5140 n = hi->next;
5141 chunkfree(hi,sizeof(HintInstance));
5142 }
5143 hnext = h->next;
5144 chunkfree(h,sizeof(DStemInfo));
5145 }
5146 }
5147
StemInfoCopy(StemInfo * h)5148 StemInfo *StemInfoCopy(StemInfo *h) {
5149 StemInfo *head=NULL, *last=NULL, *cur;
5150 HintInstance *hilast, *hicur, *hi;
5151
5152 for ( ; h!=NULL; h = h->next ) {
5153 cur = chunkalloc(sizeof(StemInfo));
5154 *cur = *h;
5155 cur->next = NULL;
5156 if ( head==NULL )
5157 head = last = cur;
5158 else {
5159 last->next = cur;
5160 last = cur;
5161 }
5162 cur->where = hilast = NULL;
5163 for ( hi=h->where; hi!=NULL; hi=hi->next ) {
5164 hicur = chunkalloc(sizeof(StemInfo));
5165 *hicur = *hi;
5166 hicur->next = NULL;
5167 if ( hilast==NULL )
5168 cur->where = hilast = hicur;
5169 else {
5170 hilast->next = hicur;
5171 hilast = hicur;
5172 }
5173 }
5174 }
5175 return( head );
5176 }
5177
DStemInfoCopy(DStemInfo * h)5178 DStemInfo *DStemInfoCopy(DStemInfo *h) {
5179 DStemInfo *head=NULL, *last=NULL, *cur;
5180 HintInstance *hilast, *hicur, *hi;
5181
5182 for ( ; h!=NULL; h = h->next ) {
5183 cur = chunkalloc(sizeof(DStemInfo));
5184 *cur = *h;
5185 cur->next = NULL;
5186 if ( head==NULL )
5187 head = last = cur;
5188 else {
5189 last->next = cur;
5190 last = cur;
5191 }
5192 cur->where = hilast = NULL;
5193 for ( hi=h->where; hi!=NULL; hi=hi->next ) {
5194 hicur = chunkalloc(sizeof(StemInfo));
5195 *hicur = *hi;
5196 hicur->next = NULL;
5197 if ( hilast==NULL )
5198 cur->where = hilast = hicur;
5199 else {
5200 hilast->next = hicur;
5201 hilast = hicur;
5202 }
5203 }
5204 }
5205 return( head );
5206 }
5207
MinimumDistanceCopy(MinimumDistance * md)5208 MinimumDistance *MinimumDistanceCopy(MinimumDistance *md) {
5209 MinimumDistance *head=NULL, *last=NULL, *cur;
5210
5211 for ( ; md!=NULL; md = md->next ) {
5212 cur = chunkalloc(sizeof(MinimumDistance));
5213 *cur = *md;
5214 cur->next = NULL;
5215 if ( head==NULL )
5216 head = last = cur;
5217 else {
5218 last->next = cur;
5219 last = cur;
5220 }
5221 }
5222 return( head );
5223 }
5224
KernPairsFree(KernPair * kp)5225 void KernPairsFree(KernPair *kp) {
5226 KernPair *knext;
5227 for ( ; kp!=NULL; kp = knext ) {
5228 knext = kp->next;
5229 if ( kp->adjust!=NULL ) {
5230 free(kp->adjust->corrections);
5231 chunkfree(kp->adjust,sizeof(DeviceTable));
5232 }
5233 chunkfree(kp,sizeof(KernPair));
5234 }
5235 }
5236
AnchorPointsRemoveName(AnchorPoint * alist,AnchorClass * an)5237 static AnchorPoint *AnchorPointsRemoveName(AnchorPoint *alist,AnchorClass *an) {
5238 AnchorPoint *prev=NULL, *ap, *next;
5239
5240 for ( ap=alist; ap!=NULL; ap=next ) {
5241 next = ap->next;
5242 if ( ap->anchor == an ) {
5243 if ( prev==NULL )
5244 alist = next;
5245 else
5246 prev->next = next;
5247 ap->next = NULL;
5248 if ( an->type == act_mark || (an->type==act_mklg && ap->type==at_mark))
5249 next = NULL; /* Only one instance of an anchor class in a glyph for mark to base anchors */
5250 /* Or for the mark glyphs of ligature classes */
5251 /* Mark to mark & cursive will (probably) have 2 occurances */
5252 /* and ligatures may have lots */
5253 AnchorPointsFree(ap);
5254 } else
5255 prev = ap;
5256 }
5257 return( alist );
5258 }
5259
5260 /* Finds or adds an AnchorClass of the given name. Resets it to have the given subtable if not NULL */
SFFindOrAddAnchorClass(SplineFont * sf,char * name,struct lookup_subtable * sub)5261 AnchorClass *SFFindOrAddAnchorClass(SplineFont *sf,char *name,struct lookup_subtable *sub) {
5262 AnchorClass *ac;
5263 int actype = act_unknown;
5264
5265 for ( ac=sf->anchor; ac!=NULL; ac=ac->next )
5266 if (strcmp(name,ac->name)==0)
5267 break;
5268 if ( ac!=NULL && ( sub==NULL || ac->subtable==sub ) )
5269 return( ac );
5270
5271 if ( sub!=NULL )
5272 actype = sub->lookup->lookup_type==gpos_cursive ? act_curs :
5273 sub->lookup->lookup_type==gpos_mark2base ? act_mark :
5274 sub->lookup->lookup_type==gpos_mark2ligature ? act_mklg :
5275 sub->lookup->lookup_type==gpos_mark2mark ? act_mkmk :
5276 act_unknown;
5277 if ( ac==NULL ) {
5278 ac = chunkalloc(sizeof(AnchorClass));
5279 ac->subtable = sub;
5280 ac->type = actype;
5281 ac->name = copy( name );
5282 ac->next = sf->anchor;
5283 sf->anchor = ac;
5284 }
5285 else if ( sub!=NULL && ac->subtable!=sub ) {
5286 ac->subtable = sub;
5287 ac->type = actype;
5288 }
5289 return( ac );
5290 }
5291
SCRemoveAnchorClass(SplineChar * sc,AnchorClass * an)5292 static void SCRemoveAnchorClass(SplineChar *sc,AnchorClass *an) {
5293 Undoes *test;
5294
5295 if ( sc==NULL )
5296 return;
5297 sc->anchor = AnchorPointsRemoveName(sc->anchor,an);
5298 for ( test = sc->layers[ly_fore].undoes; test!=NULL; test=test->next )
5299 if ( test->undotype==ut_state || test->undotype==ut_tstate ||
5300 test->undotype==ut_statehint || test->undotype==ut_statename )
5301 test->u.state.anchor = AnchorPointsRemoveName(test->u.state.anchor,an);
5302 for ( test = sc->layers[ly_fore].redoes; test!=NULL; test=test->next )
5303 if ( test->undotype==ut_state || test->undotype==ut_tstate ||
5304 test->undotype==ut_statehint || test->undotype==ut_statename )
5305 test->u.state.anchor = AnchorPointsRemoveName(test->u.state.anchor,an);
5306 }
5307
SFRemoveAnchorClass(SplineFont * sf,AnchorClass * an)5308 void SFRemoveAnchorClass(SplineFont *sf,AnchorClass *an) {
5309 int i;
5310 AnchorClass *prev, *test;
5311
5312 PasteRemoveAnchorClass(sf,an);
5313
5314 for ( i=0; i<sf->glyphcnt; ++i )
5315 SCRemoveAnchorClass(sf->glyphs[i],an);
5316 prev = NULL;
5317 for ( test=sf->anchor; test!=NULL; test=test->next ) {
5318 if ( test==an ) {
5319 if ( prev==NULL )
5320 sf->anchor = test->next;
5321 else
5322 prev->next = test->next;
5323 chunkfree(test,sizeof(AnchorClass));
5324 break;
5325 } else
5326 prev = test;
5327 }
5328 }
5329
APAnchorClassMerge(AnchorPoint * anchors,AnchorClass * into,AnchorClass * from)5330 AnchorPoint *APAnchorClassMerge(AnchorPoint *anchors,AnchorClass *into,AnchorClass *from) {
5331 AnchorPoint *api=NULL, *prev, *ap, *next;
5332
5333 prev = NULL;
5334 for ( ap=anchors; ap!=NULL; ap=next ) {
5335 next = ap->next;
5336 if ( ap->anchor==from ) {
5337 for ( api=anchors; api!=NULL; api=api->next ) {
5338 if ( api->anchor==into &&
5339 (api->type!=at_baselig || ap->type!=at_baselig || api->lig_index==ap->lig_index))
5340 break;
5341 }
5342 if ( api==NULL && into!=NULL ) {
5343 ap->anchor = into;
5344 prev = ap;
5345 } else {
5346 if ( prev==NULL )
5347 anchors = next;
5348 else
5349 prev->next = next;
5350 ap->next = NULL;
5351 AnchorPointsFree(ap);
5352 }
5353 } else
5354 prev = ap;
5355 }
5356 return( anchors );
5357 }
5358
AnchorClassMerge(SplineFont * sf,AnchorClass * into,AnchorClass * from)5359 void AnchorClassMerge(SplineFont *sf,AnchorClass *into,AnchorClass *from) {
5360 int i;
5361
5362 if ( into==from )
5363 return;
5364 PasteAnchorClassMerge(sf,into,from);
5365 for ( i=0; i<sf->glyphcnt; ++i ) if ( sf->glyphs[i]!=NULL ) {
5366 SplineChar *sc = sf->glyphs[i];
5367
5368 sc->anchor = APAnchorClassMerge(sc->anchor,into,from);
5369 }
5370 }
5371
AnchorPointsCopy(AnchorPoint * alist)5372 AnchorPoint *AnchorPointsCopy(AnchorPoint *alist) {
5373 AnchorPoint *head=NULL, *last, *ap;
5374
5375 while ( alist!=NULL ) {
5376 ap = chunkalloc(sizeof(AnchorPoint));
5377 *ap = *alist;
5378 if ( ap->xadjust.corrections!=NULL ) {
5379 int len = ap->xadjust.last_pixel_size-ap->xadjust.first_pixel_size+1;
5380 ap->xadjust.corrections = malloc(len);
5381 memcpy(ap->xadjust.corrections,alist->xadjust.corrections,len);
5382 }
5383 if ( ap->yadjust.corrections!=NULL ) {
5384 int len = ap->yadjust.last_pixel_size-ap->yadjust.first_pixel_size+1;
5385 ap->yadjust.corrections = malloc(len);
5386 memcpy(ap->yadjust.corrections,alist->yadjust.corrections,len);
5387 }
5388 if ( head==NULL )
5389 head = ap;
5390 else
5391 last->next = ap;
5392 last = ap;
5393 alist = alist->next;
5394 }
5395 return( head );
5396 }
5397
AnchorPointsFree(AnchorPoint * ap)5398 void AnchorPointsFree(AnchorPoint *ap) {
5399 AnchorPoint *anext;
5400 for ( ; ap!=NULL; ap = anext ) {
5401 anext = ap->next;
5402 free(ap->xadjust.corrections);
5403 free(ap->yadjust.corrections);
5404 chunkfree(ap,sizeof(AnchorPoint));
5405 }
5406 }
5407
GuidelineSetFree(GuidelineSet * gl)5408 void GuidelineSetFree(GuidelineSet *gl) {
5409 GuidelineSet *glnext;
5410 for ( ; gl!=NULL; gl = glnext ) {
5411 glnext = gl->next;
5412 if (gl->name != NULL) {
5413 free(gl->name);
5414 gl->name = NULL;
5415 }
5416 if (gl->identifier != NULL) {
5417 free(gl->identifier);
5418 gl->identifier = NULL;
5419 }
5420 chunkfree(gl,sizeof(GuidelineSet));
5421 }
5422 }
5423
ValDevFree(ValDevTab * adjust)5424 void ValDevFree(ValDevTab *adjust) {
5425 if ( adjust==NULL )
5426 return;
5427 free( adjust->xadjust.corrections );
5428 free( adjust->yadjust.corrections );
5429 free( adjust->xadv.corrections );
5430 free( adjust->yadv.corrections );
5431 chunkfree(adjust,sizeof(ValDevTab));
5432 }
5433
ValDevTabCopy(ValDevTab * orig)5434 ValDevTab *ValDevTabCopy(ValDevTab *orig) {
5435 ValDevTab *new;
5436 int i;
5437
5438 if ( orig==NULL )
5439 return( NULL );
5440 new = chunkalloc(sizeof(ValDevTab));
5441 for ( i=0; i<4; ++i ) {
5442 if ( (&orig->xadjust)[i].corrections!=NULL ) {
5443 int len = (&orig->xadjust)[i].last_pixel_size - (&orig->xadjust)[i].first_pixel_size + 1;
5444 (&new->xadjust)[i] = (&orig->xadjust)[i];
5445 (&new->xadjust)[i].corrections = malloc(len);
5446 memcpy((&new->xadjust)[i].corrections,(&orig->xadjust)[i].corrections,len);
5447 }
5448 }
5449 return( new );
5450 }
5451
DeviceTableFree(DeviceTable * dt)5452 void DeviceTableFree(DeviceTable *dt) {
5453
5454 if ( dt==NULL )
5455 return;
5456
5457 free(dt->corrections);
5458 chunkfree(dt,sizeof(DeviceTable));
5459 }
5460
DeviceTableCopy(DeviceTable * orig)5461 DeviceTable *DeviceTableCopy(DeviceTable *orig) {
5462 DeviceTable *new;
5463 int len;
5464
5465 if ( orig==NULL )
5466 return( NULL );
5467 new = chunkalloc(sizeof(DeviceTable));
5468 *new = *orig;
5469 len = orig->last_pixel_size - orig->first_pixel_size + 1;
5470 new->corrections = malloc(len);
5471 memcpy(new->corrections,orig->corrections,len);
5472 return( new );
5473 }
5474
DeviceTableSet(DeviceTable * adjust,int size,int correction)5475 void DeviceTableSet(DeviceTable *adjust, int size, int correction) {
5476 int len, i, j;
5477
5478 len = adjust->last_pixel_size-adjust->first_pixel_size + 1;
5479 if ( correction==0 ) {
5480 if ( adjust->corrections==NULL ||
5481 size<adjust->first_pixel_size ||
5482 size>adjust->last_pixel_size )
5483 return;
5484 adjust->corrections[size-adjust->first_pixel_size] = 0;
5485 for ( i=0; i<len; ++i )
5486 if ( adjust->corrections[i]!=0 )
5487 break;
5488 if ( i==len ) {
5489 free(adjust->corrections);
5490 memset(adjust,0,sizeof(DeviceTable));
5491 } else {
5492 if ( i!=0 ) {
5493 for ( j=0; j<len-i; ++j )
5494 adjust->corrections[j] = adjust->corrections[j+i];
5495 adjust->first_pixel_size += i;
5496 len -= i;
5497 }
5498 for ( i=len-1; i>=0; --i )
5499 if ( adjust->corrections[i]!=0 )
5500 break;
5501 adjust->last_pixel_size = adjust->first_pixel_size+i;
5502 }
5503 } else {
5504 if ( adjust->corrections==NULL ) {
5505 adjust->first_pixel_size = adjust->last_pixel_size = size;
5506 adjust->corrections = malloc(1);
5507 } else if ( size>=adjust->first_pixel_size &&
5508 size<=adjust->last_pixel_size ) {
5509 } else if ( size>adjust->last_pixel_size ) {
5510 adjust->corrections = realloc(adjust->corrections,
5511 size-adjust->first_pixel_size);
5512 for ( i=len; i<size-adjust->first_pixel_size; ++i )
5513 adjust->corrections[i] = 0;
5514 adjust->last_pixel_size = size;
5515 } else {
5516 int8 *new = malloc(adjust->last_pixel_size-size+1);
5517 memset(new,0,adjust->first_pixel_size-size);
5518 memcpy(new+adjust->first_pixel_size-size,
5519 adjust->corrections, len);
5520 adjust->first_pixel_size = size;
5521 free(adjust->corrections);
5522 adjust->corrections = new;
5523 }
5524 adjust->corrections[size-adjust->first_pixel_size] = correction;
5525 }
5526 }
5527
PSTFree(PST * pst)5528 void PSTFree(PST *pst) {
5529 PST *pnext;
5530 for ( ; pst!=NULL; pst = pnext ) {
5531 pnext = pst->next;
5532 if ( pst->type==pst_lcaret )
5533 free(pst->u.lcaret.carets);
5534 else if ( pst->type==pst_pair ) {
5535 free(pst->u.pair.paired);
5536 ValDevFree(pst->u.pair.vr[0].adjust);
5537 ValDevFree(pst->u.pair.vr[1].adjust);
5538 chunkfree(pst->u.pair.vr,sizeof(struct vr [2]));
5539 } else if ( pst->type!=pst_position ) {
5540 free(pst->u.subs.variant);
5541 } else if ( pst->type==pst_position ) {
5542 ValDevFree(pst->u.pos.adjust);
5543 }
5544 chunkfree(pst,sizeof(PST));
5545 }
5546 }
5547
FPSTRuleContentsFree(struct fpst_rule * r,enum fpossub_format format)5548 void FPSTRuleContentsFree(struct fpst_rule *r, enum fpossub_format format) {
5549 int j;
5550
5551 switch ( format ) {
5552 case pst_glyphs:
5553 free(r->u.glyph.names);
5554 free(r->u.glyph.back);
5555 free(r->u.glyph.fore);
5556 break;
5557 case pst_class:
5558 free(r->u.class.nclasses);
5559 free(r->u.class.bclasses);
5560 free(r->u.class.fclasses);
5561 break;
5562 case pst_reversecoverage:
5563 free(r->u.rcoverage.replacements);
5564 case pst_coverage:
5565 for ( j=0 ; j<r->u.coverage.ncnt ; ++j )
5566 free(r->u.coverage.ncovers[j]);
5567 free(r->u.coverage.ncovers);
5568 for ( j=0 ; j<r->u.coverage.bcnt ; ++j )
5569 free(r->u.coverage.bcovers[j]);
5570 free(r->u.coverage.bcovers);
5571 for ( j=0 ; j<r->u.coverage.fcnt ; ++j )
5572 free(r->u.coverage.fcovers[j]);
5573 free(r->u.coverage.fcovers);
5574 break;
5575 }
5576 free(r->lookups);
5577 }
5578
FPSTRulesFree(struct fpst_rule * r,enum fpossub_format format,int rcnt)5579 void FPSTRulesFree(struct fpst_rule *r, enum fpossub_format format, int rcnt) {
5580 int i;
5581 for ( i=0; i<rcnt; ++i )
5582 FPSTRuleContentsFree(&r[i],format);
5583 free(r);
5584 }
5585
RulesCopy(struct fpst_rule * from,int cnt,enum fpossub_format format)5586 static struct fpst_rule *RulesCopy(struct fpst_rule *from, int cnt,
5587 enum fpossub_format format ) {
5588 int i, j;
5589 struct fpst_rule *to, *f, *t;
5590
5591 if ( cnt==0 )
5592 return( NULL );
5593
5594 to = calloc(cnt,sizeof(struct fpst_rule));
5595 for ( i=0; i<cnt; ++i ) {
5596 f = from+i; t = to+i;
5597 switch ( format ) {
5598 case pst_glyphs:
5599 t->u.glyph.names = copy(f->u.glyph.names);
5600 t->u.glyph.back = copy(f->u.glyph.back);
5601 t->u.glyph.fore = copy(f->u.glyph.fore);
5602 break;
5603 case pst_class:
5604 t->u.class.ncnt = f->u.class.ncnt;
5605 t->u.class.bcnt = f->u.class.bcnt;
5606 t->u.class.fcnt = f->u.class.fcnt;
5607 t->u.class.nclasses = malloc( f->u.class.ncnt*sizeof(uint16));
5608 memcpy(t->u.class.nclasses,f->u.class.nclasses,
5609 f->u.class.ncnt*sizeof(uint16));
5610 if ( t->u.class.bcnt!=0 ) {
5611 t->u.class.bclasses = malloc( f->u.class.bcnt*sizeof(uint16));
5612 memcpy(t->u.class.bclasses,f->u.class.bclasses,
5613 f->u.class.bcnt*sizeof(uint16));
5614 }
5615 if ( t->u.class.fcnt!=0 ) {
5616 t->u.class.fclasses = malloc( f->u.class.fcnt*sizeof(uint16));
5617 memcpy(t->u.class.fclasses,f->u.class.fclasses,
5618 f->u.class.fcnt*sizeof(uint16));
5619 }
5620 break;
5621 case pst_reversecoverage:
5622 t->u.rcoverage.replacements = copy(f->u.rcoverage.replacements);
5623 case pst_coverage:
5624 t->u.coverage.ncnt = f->u.coverage.ncnt;
5625 t->u.coverage.bcnt = f->u.coverage.bcnt;
5626 t->u.coverage.fcnt = f->u.coverage.fcnt;
5627 t->u.coverage.ncovers = malloc( f->u.coverage.ncnt*sizeof(char *));
5628 for ( j=0; j<t->u.coverage.ncnt; ++j )
5629 t->u.coverage.ncovers[j] = copy(f->u.coverage.ncovers[j]);
5630 if ( t->u.coverage.bcnt!=0 ) {
5631 t->u.coverage.bcovers = malloc( f->u.coverage.bcnt*sizeof(char *));
5632 for ( j=0; j<t->u.coverage.bcnt; ++j )
5633 t->u.coverage.bcovers[j] = copy(f->u.coverage.bcovers[j]);
5634 }
5635 if ( t->u.coverage.fcnt!=0 ) {
5636 t->u.coverage.fcovers = malloc( f->u.coverage.fcnt*sizeof(char *));
5637 for ( j=0; j<t->u.coverage.fcnt; ++j )
5638 t->u.coverage.fcovers[j] = copy(f->u.coverage.fcovers[j]);
5639 }
5640 break;
5641 }
5642 if ( f->lookup_cnt!=0 ) {
5643 t->lookup_cnt = f->lookup_cnt;
5644 t->lookups = malloc(t->lookup_cnt*sizeof(struct seqlookup));
5645 memcpy(t->lookups,f->lookups,t->lookup_cnt*sizeof(struct seqlookup));
5646 }
5647 }
5648 return( to );
5649 }
5650
FPSTCopy(FPST * fpst)5651 FPST *FPSTCopy(FPST *fpst) {
5652 FPST *nfpst;
5653 int i;
5654
5655 nfpst = chunkalloc(sizeof(FPST));
5656 *nfpst = *fpst;
5657 nfpst->next = NULL;
5658 if ( nfpst->nccnt!=0 ) {
5659 nfpst->nclass = malloc(nfpst->nccnt*sizeof(char *));
5660 nfpst->nclassnames = malloc(nfpst->nccnt*sizeof(char *));
5661 for ( i=0; i<nfpst->nccnt; ++i ) {
5662 nfpst->nclass[i] = copy(fpst->nclass[i]);
5663 nfpst->nclassnames[i] = copy(fpst->nclassnames[i]);
5664 }
5665 }
5666 if ( nfpst->bccnt!=0 ) {
5667 nfpst->bclass = malloc(nfpst->bccnt*sizeof(char *));
5668 nfpst->bclassnames = malloc(nfpst->bccnt*sizeof(char *));
5669 for ( i=0; i<nfpst->bccnt; ++i ) {
5670 nfpst->bclass[i] = copy(fpst->bclass[i]);
5671 nfpst->bclassnames[i] = copy(fpst->bclassnames[i]);
5672 }
5673 }
5674 if ( nfpst->fccnt!=0 ) {
5675 nfpst->fclass = malloc(nfpst->fccnt*sizeof(char *));
5676 nfpst->fclassnames = malloc(nfpst->fccnt*sizeof(char *));
5677 for ( i=0; i<nfpst->fccnt; ++i ) {
5678 nfpst->fclass[i] = copy(fpst->fclass[i]);
5679 nfpst->fclassnames[i] = copy(fpst->fclassnames[i]);
5680 }
5681 }
5682 nfpst->rules = RulesCopy(fpst->rules,fpst->rule_cnt,fpst->format);
5683 return( nfpst );
5684 }
5685
FPSTClassesFree(FPST * fpst)5686 void FPSTClassesFree(FPST *fpst) {
5687 int i;
5688
5689 for ( i=0; i<fpst->nccnt; ++i ) {
5690 free(fpst->nclass[i]);
5691 free(fpst->nclassnames[i]);
5692 }
5693 for ( i=0; i<fpst->bccnt; ++i ) {
5694 free(fpst->bclass[i]);
5695 free(fpst->bclassnames[i]);
5696 }
5697 for ( i=0; i<fpst->fccnt; ++i ) {
5698 free(fpst->fclass[i]);
5699 free(fpst->fclassnames[i]);
5700 }
5701 free(fpst->nclass); free(fpst->bclass); free(fpst->fclass);
5702 free(fpst->nclassnames); free(fpst->bclassnames); free(fpst->fclassnames);
5703
5704 fpst->nccnt = fpst->bccnt = fpst->fccnt = 0;
5705 fpst->nclass = fpst->bclass = fpst->fclass = NULL;
5706 fpst->nclassnames = fpst->bclassnames = fpst->fclassnames = NULL;
5707 }
5708
FPSTFree(FPST * fpst)5709 void FPSTFree(FPST *fpst) {
5710 FPST *next;
5711 int i;
5712
5713 while ( fpst!=NULL ) {
5714 next = fpst->next;
5715 FPSTClassesFree(fpst);
5716 for ( i=0; i<fpst->rule_cnt; ++i ) {
5717 FPSTRuleContentsFree( &fpst->rules[i],fpst->format );
5718 }
5719 free(fpst->rules);
5720 chunkfree(fpst,sizeof(FPST));
5721 fpst = next;
5722 }
5723 }
5724
MinimumDistancesFree(MinimumDistance * md)5725 void MinimumDistancesFree(MinimumDistance *md) {
5726 MinimumDistance *next;
5727
5728 while ( md!=NULL ) {
5729 next = md->next;
5730 chunkfree(md,sizeof(MinimumDistance));
5731 md = next;
5732 }
5733 }
5734
TTFLangNamesFree(struct ttflangname * l)5735 void TTFLangNamesFree(struct ttflangname *l) {
5736 struct ttflangname *next;
5737 int i;
5738
5739 while ( l!=NULL ) {
5740 next = l->next;
5741 for ( i=0; i<ttf_namemax; ++i )
5742 free(l->names[i]);
5743 chunkfree(l,sizeof(*l));
5744 l = next;
5745 }
5746 }
5747
AltUniFree(struct altuni * altuni)5748 void AltUniFree(struct altuni *altuni) {
5749 struct altuni *next;
5750
5751 while ( altuni ) {
5752 next = altuni->next;
5753 chunkfree(altuni,sizeof(struct altuni));
5754 altuni = next;
5755 }
5756 }
5757
LayerDefault(Layer * layer)5758 void LayerDefault(Layer *layer) {
5759 memset(layer,0,sizeof(Layer));
5760 layer->fill_brush.opacity = layer->stroke_pen.brush.opacity = 1.0;
5761 layer->fill_brush.col = layer->stroke_pen.brush.col = COLOR_INHERITED;
5762 layer->stroke_pen.width = 10;
5763 layer->stroke_pen.linecap = lc_round;
5764 layer->stroke_pen.linejoin = lj_round;
5765 layer->dofill = true;
5766 layer->fillfirst = true;
5767 layer->stroke_pen.trans[0] = layer->stroke_pen.trans[3] = 1.0;
5768 layer->stroke_pen.trans[1] = layer->stroke_pen.trans[2] = 0.0;
5769 /* Dashes default to an unbroken line */
5770 }
5771
SplineCharCreate(int layer_cnt)5772 SplineChar *SplineCharCreate(int layer_cnt) {
5773 SplineChar *sc = chunkalloc(sizeof(SplineChar));
5774 int i;
5775
5776 sc->color = COLOR_DEFAULT;
5777 sc->orig_pos = 0xffff;
5778 sc->unicodeenc = -1;
5779 sc->layer_cnt = layer_cnt;
5780 sc->layers = calloc(layer_cnt,sizeof(Layer));
5781 for ( i=0; i<layer_cnt; ++i )
5782 LayerDefault(&sc->layers[i]);
5783 sc->tex_height = sc->tex_depth = sc->italic_correction = sc->top_accent_horiz =
5784 TEX_UNDEF;
5785 return( sc );
5786 }
5787
SFSplineCharCreate(SplineFont * sf)5788 SplineChar *SFSplineCharCreate(SplineFont *sf) {
5789 SplineChar *sc = SplineCharCreate(sf==NULL?2:sf->layer_cnt);
5790 int i;
5791
5792 if ( sf==NULL ) {
5793 sc->layers[ly_back].background = true;
5794 sc->layers[ly_fore].background = false;
5795 } else {
5796 for ( i=0; i<sf->layer_cnt; ++i ) {
5797 sc->layers[i].background = sf->layers[i].background;
5798 sc->layers[i].order2 = sf->layers[i].order2;
5799 }
5800 sc->parent = sf;
5801 }
5802 return( sc );
5803 }
5804
GlyphVariantsFree(struct glyphvariants * gv)5805 void GlyphVariantsFree(struct glyphvariants *gv) {
5806 int i;
5807
5808 if ( gv==NULL )
5809 return;
5810 free(gv->variants);
5811 DeviceTableFree(gv->italic_adjusts);
5812 for ( i=0; i<gv->part_cnt; ++i )
5813 free( gv->parts[i].component );
5814 free(gv->parts);
5815 chunkfree(gv,sizeof(*gv));
5816 }
5817
GlyphVariantsCopy(struct glyphvariants * gv)5818 struct glyphvariants *GlyphVariantsCopy(struct glyphvariants *gv) {
5819 struct glyphvariants *newgv;
5820 int i;
5821
5822 if ( gv==NULL )
5823 return( NULL );
5824 newgv = chunkalloc(sizeof(struct glyphvariants));
5825 newgv->variants = copy(gv->variants);
5826 newgv->italic_adjusts = DeviceTableCopy(gv->italic_adjusts);
5827 newgv->part_cnt = gv->part_cnt;
5828 if ( gv->part_cnt!=0 ) {
5829 newgv->parts = calloc(gv->part_cnt,sizeof(struct gv_part));
5830 memcpy(newgv->parts,gv->parts,gv->part_cnt*sizeof(struct gv_part));
5831 for ( i=0; i<gv->part_cnt; ++i )
5832 newgv->parts[i].component = copy(gv->parts[i].component);
5833 }
5834 return( newgv );
5835 }
5836
MathKernCopy(struct mathkern * mk)5837 struct mathkern *MathKernCopy(struct mathkern *mk) {
5838 int i,j;
5839 struct mathkern *mknew;
5840
5841 if ( mk==NULL )
5842 return( NULL );
5843 mknew = chunkalloc(sizeof(*mknew));
5844 for ( i=0; i<4; ++i ) {
5845 struct mathkernvertex *mkv = &(&mk->top_right)[i];
5846 struct mathkernvertex *mknewv = &(&mknew->top_right)[i];
5847 mknewv->cnt = mkv->cnt;
5848 if ( mknewv->cnt!=0 ) {
5849 mknewv->mkd = calloc(mkv->cnt,sizeof(struct mathkerndata));
5850 for ( j=0; j<mkv->cnt; ++j ) {
5851 mknewv->mkd[j].height = mkv->mkd[j].height;
5852 mknewv->mkd[j].kern = mkv->mkd[j].kern;
5853 mknewv->mkd[j].height_adjusts = DeviceTableCopy( mkv->mkd[j].height_adjusts );
5854 mknewv->mkd[j].kern_adjusts = DeviceTableCopy( mkv->mkd[j].kern_adjusts );
5855 }
5856 }
5857 }
5858 return( mknew );
5859 }
5860
MathKernVContentsFree(struct mathkernvertex * mk)5861 void MathKernVContentsFree(struct mathkernvertex *mk) {
5862 int i;
5863 for ( i=0; i<mk->cnt; ++i ) {
5864 DeviceTableFree(mk->mkd[i].height_adjusts);
5865 DeviceTableFree(mk->mkd[i].kern_adjusts);
5866 }
5867 free(mk->mkd);
5868 }
5869
MathKernFree(struct mathkern * mk)5870 void MathKernFree(struct mathkern *mk) {
5871 int i;
5872
5873 if ( mk==NULL )
5874 return;
5875 for ( i=0; i<4; ++i )
5876 MathKernVContentsFree( &(&mk->top_right)[i] );
5877 chunkfree(mk,sizeof(*mk));
5878 }
5879
SplineCharListsFree(struct splinecharlist * dlist)5880 void SplineCharListsFree(struct splinecharlist *dlist) {
5881 struct splinecharlist *dnext;
5882 for ( ; dlist!=NULL; dlist = dnext ) {
5883 dnext = dlist->next;
5884 chunkfree(dlist,sizeof(struct splinecharlist));
5885 }
5886 }
5887
PatternCopy(struct pattern * old,real transform[6])5888 struct pattern *PatternCopy(struct pattern *old, real transform[6]) {
5889 struct pattern *pat;
5890
5891 if ( old==NULL )
5892 return( NULL );
5893
5894 pat = chunkalloc(sizeof(struct pattern));
5895
5896 *pat = *old;
5897 pat->pattern = copy( old->pattern );
5898 if ( transform!=NULL )
5899 MatMultiply(pat->transform,transform,pat->transform);
5900 return( pat );
5901 }
5902
PatternFree(struct pattern * pat)5903 void PatternFree(struct pattern *pat) {
5904 if ( pat==NULL )
5905 return;
5906 free(pat->pattern);
5907 chunkfree(pat,sizeof(struct pattern));
5908 }
5909
GradientCopy(struct gradient * old,real transform[6])5910 struct gradient *GradientCopy(struct gradient *old,real transform[6]) {
5911 struct gradient *grad;
5912
5913 if ( old==NULL )
5914 return( NULL );
5915
5916 grad = chunkalloc(sizeof(struct gradient));
5917
5918 *grad = *old;
5919 grad->grad_stops = malloc(old->stop_cnt*sizeof(struct grad_stops));
5920 memcpy(grad->grad_stops,old->grad_stops,old->stop_cnt*sizeof(struct grad_stops));
5921 if ( transform!=NULL ) {
5922 BpTransform(&grad->start,&grad->start,transform);
5923 BpTransform(&grad->stop,&grad->stop,transform);
5924 }
5925 return( grad );
5926 }
5927
GradientFree(struct gradient * grad)5928 void GradientFree(struct gradient *grad) {
5929 if ( grad==NULL )
5930 return;
5931 free(grad->grad_stops);
5932 chunkfree(grad,sizeof(struct gradient));
5933 }
5934
BrushCopy(struct brush * into,struct brush * from,real transform[6])5935 void BrushCopy(struct brush *into, struct brush *from, real transform[6]) {
5936 *into = *from;
5937 into->gradient = GradientCopy(from->gradient,transform);
5938 into->pattern = PatternCopy(from->pattern,transform);
5939 }
5940
PenCopy(struct pen * into,struct pen * from,real transform[6])5941 void PenCopy(struct pen *into, struct pen *from,real transform[6]) {
5942 *into = *from;
5943 into->brush.gradient = GradientCopy(from->brush.gradient,transform);
5944 into->brush.pattern = PatternCopy(from->brush.pattern,transform);
5945 }
5946
LayerFreeContents(SplineChar * sc,int layer)5947 void LayerFreeContents(SplineChar *sc,int layer) {
5948 SplinePointListsFree(sc->layers[layer].splines);
5949 GradientFree(sc->layers[layer].fill_brush.gradient);
5950 PatternFree(sc->layers[layer].fill_brush.pattern);
5951 GradientFree(sc->layers[layer].stroke_pen.brush.gradient);
5952 PatternFree(sc->layers[layer].stroke_pen.brush.pattern);
5953 RefCharsFree(sc->layers[layer].refs);
5954 GuidelineSetFree(sc->layers[layer].guidelines);
5955 ImageListsFree(sc->layers[layer].images);
5956 /* image garbage collection????!!!! */
5957 UndoesFree(sc->layers[layer].undoes);
5958 UndoesFree(sc->layers[layer].redoes);
5959 }
5960
SplineCharFreeContents(SplineChar * sc)5961 void SplineCharFreeContents(SplineChar *sc) {
5962 int i;
5963
5964 if ( sc==NULL )
5965 return;
5966 if (sc->name != NULL) free(sc->name);
5967 if (sc->comment != NULL) free(sc->comment);
5968 if (sc->user_decomp != NULL) free(sc->user_decomp);
5969 for ( i=0; i<sc->layer_cnt; ++i ) {
5970 #if defined(_NO_PYTHON)
5971 if (sc->layers[i].python_persistent != NULL) free( sc->layers[i].python_persistent ); /* It's a string of pickled data which we leave as a string */
5972 #else
5973 PyFF_FreeSCLayer(sc, i);
5974 #endif
5975 LayerFreeContents(sc,i);
5976 }
5977 StemInfosFree(sc->hstem);
5978 StemInfosFree(sc->vstem);
5979 DStemInfosFree(sc->dstem);
5980 MinimumDistancesFree(sc->md);
5981 KernPairsFree(sc->kerns);
5982 KernPairsFree(sc->vkerns);
5983 AnchorPointsFree(sc->anchor);
5984 SplineCharListsFree(sc->dependents);
5985 PSTFree(sc->possub);
5986 if (sc->ttf_instrs != NULL) free(sc->ttf_instrs);
5987 if (sc->countermasks != NULL) free(sc->countermasks);
5988 if (sc->layers != NULL) free(sc->layers);
5989 AltUniFree(sc->altuni);
5990 GlyphVariantsFree(sc->horiz_variants);
5991 GlyphVariantsFree(sc->vert_variants);
5992 DeviceTableFree(sc->italic_adjusts);
5993 DeviceTableFree(sc->top_accent_adjusts);
5994 MathKernFree(sc->mathkern);
5995 if (sc->glif_name != NULL) { free(sc->glif_name); sc->glif_name = NULL; }
5996 }
5997
SplineCharFree(SplineChar * sc)5998 void SplineCharFree(SplineChar *sc) {
5999
6000 if ( sc==NULL )
6001 return;
6002 SplineCharFreeContents(sc);
6003 chunkfree(sc,sizeof(SplineChar));
6004 }
6005
AnchorClassesFree(AnchorClass * an)6006 void AnchorClassesFree(AnchorClass *an) {
6007 AnchorClass *anext;
6008 for ( ; an!=NULL; an = anext ) {
6009 anext = an->next;
6010 free(an->name);
6011 chunkfree(an,sizeof(AnchorClass));
6012 }
6013 }
6014
TtfTablesFree(struct ttf_table * tab)6015 void TtfTablesFree(struct ttf_table *tab) {
6016 struct ttf_table *next;
6017
6018 for ( ; tab!=NULL; tab = next ) {
6019 next = tab->next;
6020 free(tab->data);
6021 chunkfree(tab,sizeof(struct ttf_table));
6022 }
6023 }
6024
SFRemoveSavedTable(SplineFont * sf,uint32 tag)6025 void SFRemoveSavedTable(SplineFont *sf, uint32 tag) {
6026 struct ttf_table *tab, *prev;
6027
6028 for ( prev=NULL, tab=sf->ttf_tables; tab!=NULL && tab->tag!=tag; prev=tab, tab=tab->next );
6029 if ( tab!=NULL ) {
6030 if ( prev==NULL )
6031 sf->ttf_tables = tab->next;
6032 else
6033 prev->next = tab->next;
6034 } else {
6035 for ( prev=NULL, tab=sf->ttf_tab_saved; tab!=NULL && tab->tag!=tag; prev=tab, tab=tab->next );
6036 if ( tab==NULL )
6037 return;
6038 if ( prev==NULL )
6039 sf->ttf_tab_saved = tab->next;
6040 else
6041 prev->next = tab->next;
6042 }
6043 tab->next = NULL;
6044 TtfTablesFree(tab);
6045 if ( !sf->changed ) {
6046 sf->changed = true;
6047 FVSetTitles(sf);
6048 }
6049 }
6050
ScriptLangListFree(struct scriptlanglist * sl)6051 void ScriptLangListFree(struct scriptlanglist *sl) {
6052 struct scriptlanglist *next;
6053
6054 while ( sl!=NULL ) {
6055 next = sl->next;
6056 free(sl->morelangs);
6057 chunkfree(sl,sizeof(*sl));
6058 sl = next;
6059 }
6060 }
6061
FeatureScriptLangListFree(FeatureScriptLangList * fl)6062 void FeatureScriptLangListFree(FeatureScriptLangList *fl) {
6063 FeatureScriptLangList *next;
6064
6065 while ( fl!=NULL ) {
6066 next = fl->next;
6067 ScriptLangListFree(fl->scripts);
6068 chunkfree(fl,sizeof(*fl));
6069 fl = next;
6070 }
6071 }
6072
OTLookupFree(OTLookup * lookup)6073 void OTLookupFree(OTLookup *lookup) {
6074 struct lookup_subtable *st, *stnext;
6075
6076 free(lookup->lookup_name);
6077 FeatureScriptLangListFree(lookup->features);
6078 for ( st=lookup->subtables; st!=NULL; st=stnext ) {
6079 stnext = st->next;
6080 free(st->subtable_name);
6081 free(st->suffix);
6082 chunkfree(st,sizeof(struct lookup_subtable));
6083 }
6084 chunkfree( lookup,sizeof(OTLookup) );
6085 }
6086
OTLookupListFree(OTLookup * lookup)6087 void OTLookupListFree(OTLookup *lookup ) {
6088 OTLookup *next;
6089
6090 for ( ; lookup!=NULL; lookup = next ) {
6091 next = lookup->next;
6092 OTLookupFree(lookup);
6093 }
6094 }
6095
KernClassCopy(KernClass * kc)6096 KernClass *KernClassCopy(KernClass *kc) {
6097 KernClass *new;
6098 int i;
6099 if ( kc==NULL )
6100 return( NULL );
6101 new = chunkalloc(sizeof(KernClass));
6102 *new = *kc;
6103 new->firsts = malloc(new->first_cnt*sizeof(char *));
6104 new->seconds = malloc(new->second_cnt*sizeof(char *));
6105 new->offsets = malloc(new->first_cnt*new->second_cnt*sizeof(int16));
6106 memcpy(new->offsets,kc->offsets, new->first_cnt*new->second_cnt*sizeof(int16));
6107 // Group kerning.
6108 if (kc->firsts_names) new->firsts_names = calloc(new->first_cnt,sizeof(char *));
6109 if (kc->seconds_names) new->seconds_names = calloc(new->second_cnt,sizeof(char *));
6110 if (kc->firsts_flags) {
6111 new->firsts_flags = calloc(new->first_cnt,sizeof(int));
6112 memcpy(new->firsts_flags, kc->firsts_flags, new->first_cnt*sizeof(int));
6113 }
6114 if (kc->seconds_flags) {
6115 new->seconds_flags = calloc(new->second_cnt,sizeof(int));
6116 memcpy(new->seconds_flags, kc->seconds_flags, new->second_cnt*sizeof(int));
6117 }
6118 if (kc->offsets_flags) {
6119 new->offsets_flags = calloc(new->first_cnt*new->second_cnt,sizeof(int));
6120 memcpy(new->offsets_flags, kc->offsets_flags, new->first_cnt*new->second_cnt*sizeof(int));
6121 }
6122 for ( i=0; i<new->first_cnt; ++i ) {
6123 new->firsts[i] = copy(kc->firsts[i]);
6124 if (kc->firsts_names && kc->firsts_names[i]) new->firsts_names[i] = copy(kc->firsts_names[i]);
6125 }
6126 for ( i=0; i<new->second_cnt; ++i ) {
6127 new->seconds[i] = copy(kc->seconds[i]);
6128 if (kc->seconds_names && kc->seconds_names[i]) new->seconds_names[i] = copy(kc->seconds_names[i]);
6129 }
6130 new->adjusts = calloc(new->first_cnt*new->second_cnt,sizeof(DeviceTable));
6131 memcpy(new->adjusts,kc->adjusts, new->first_cnt*new->second_cnt*sizeof(DeviceTable));
6132 for ( i=new->first_cnt*new->second_cnt-1; i>=0 ; --i ) {
6133 if ( new->adjusts[i].corrections!=NULL ) {
6134 int8 *old = new->adjusts[i].corrections;
6135 int len = new->adjusts[i].last_pixel_size - new->adjusts[i].first_pixel_size + 1;
6136 new->adjusts[i].corrections = malloc(len);
6137 memcpy(new->adjusts[i].corrections,old,len);
6138 }
6139 }
6140
6141
6142
6143 new->next = NULL;
6144 return( new );
6145 }
6146
KernClassFreeContents(KernClass * kc)6147 void KernClassFreeContents(KernClass *kc) {
6148 int i;
6149 for ( i=1; i<kc->first_cnt; ++i )
6150 free(kc->firsts[i]);
6151 for ( i=1; i<kc->second_cnt; ++i )
6152 free(kc->seconds[i]);
6153 free(kc->firsts);
6154 free(kc->seconds);
6155 free(kc->offsets);
6156 for ( i=kc->first_cnt*kc->second_cnt-1; i>=0 ; --i )
6157 free(kc->adjusts[i].corrections);
6158 free(kc->adjusts);
6159 if (kc->firsts_flags) free(kc->firsts_flags);
6160 if (kc->seconds_flags) free(kc->seconds_flags);
6161 if (kc->offsets_flags) free(kc->offsets_flags);
6162 if (kc->firsts_names) {
6163 for ( i=kc->first_cnt-1; i>=0 ; --i )
6164 free(kc->firsts_names[i]);
6165 free(kc->firsts_names);
6166 }
6167 if (kc->seconds_names) {
6168 for ( i=kc->second_cnt-1; i>=0 ; --i )
6169 free(kc->seconds_names[i]);
6170 free(kc->seconds_names);
6171 }
6172 }
6173
KernClassClearSpecialContents(KernClass * kc)6174 void KernClassClearSpecialContents(KernClass *kc) {
6175 // This frees and zeros special data not handled by the FontForge GUI,
6176 // most of which comes from U. F. O..
6177 int i;
6178 if (kc->firsts_flags) { free(kc->firsts_flags); kc->firsts_flags = NULL; }
6179 if (kc->seconds_flags) { free(kc->seconds_flags); kc->seconds_flags = NULL; }
6180 if (kc->offsets_flags) { free(kc->offsets_flags); kc->offsets_flags = NULL; }
6181 if (kc->firsts_names) {
6182 for ( i=kc->first_cnt-1; i>=0 ; --i )
6183 free(kc->firsts_names[i]);
6184 free(kc->firsts_names);
6185 kc->firsts_names = NULL;
6186 }
6187 if (kc->seconds_names) {
6188 for ( i=kc->second_cnt-1; i>=0 ; --i )
6189 free(kc->seconds_names[i]);
6190 free(kc->seconds_names);
6191 kc->seconds_names = NULL;
6192 }
6193 }
6194
KernClassListFree(KernClass * kc)6195 void KernClassListFree(KernClass *kc) {
6196 KernClass *n;
6197
6198 while ( kc ) {
6199 KernClassFreeContents(kc);
6200 n = kc->next;
6201 chunkfree(kc,sizeof(KernClass));
6202 kc = n;
6203 }
6204 }
6205
KernClassListClearSpecialContents(KernClass * kc)6206 void KernClassListClearSpecialContents(KernClass *kc) {
6207 KernClass *n;
6208
6209 while ( kc ) {
6210 KernClassClearSpecialContents(kc);
6211 n = kc->next;
6212 kc = n;
6213 }
6214 }
6215
MacNameListFree(struct macname * mn)6216 void MacNameListFree(struct macname *mn) {
6217 struct macname *next;
6218
6219 while ( mn!=NULL ) {
6220 next = mn->next;
6221 free(mn->name);
6222 chunkfree(mn,sizeof(struct macname));
6223 mn = next;
6224 }
6225 }
6226
MacSettingListFree(struct macsetting * ms)6227 void MacSettingListFree(struct macsetting *ms) {
6228 struct macsetting *next;
6229
6230 while ( ms!=NULL ) {
6231 next = ms->next;
6232 MacNameListFree(ms->setname);
6233 chunkfree(ms,sizeof(struct macsetting));
6234 ms = next;
6235 }
6236 }
6237
MacFeatListFree(MacFeat * mf)6238 void MacFeatListFree(MacFeat *mf) {
6239 MacFeat *next;
6240
6241 while ( mf!=NULL ) {
6242 next = mf->next;
6243 MacNameListFree(mf->featname);
6244 MacSettingListFree(mf->settings);
6245 chunkfree(mf,sizeof(MacFeat));
6246 mf = next;
6247 }
6248 }
6249
ASMFree(ASM * sm)6250 void ASMFree(ASM *sm) {
6251 ASM *next;
6252 int i;
6253
6254 while ( sm!=NULL ) {
6255 next = sm->next;
6256 if ( sm->type==asm_insert ) {
6257 for ( i=0; i<sm->class_cnt*sm->state_cnt; ++i ) {
6258 free( sm->state[i].u.insert.mark_ins );
6259 free( sm->state[i].u.insert.cur_ins );
6260 }
6261 } else if ( sm->type==asm_kern ) {
6262 for ( i=0; i<sm->class_cnt*sm->state_cnt; ++i ) {
6263 free( sm->state[i].u.kern.kerns );
6264 }
6265 }
6266 for ( i=4; i<sm->class_cnt; ++i )
6267 free(sm->classes[i]);
6268 free(sm->state);
6269 free(sm->classes);
6270 chunkfree(sm,sizeof(ASM));
6271 sm = next;
6272 }
6273 }
6274
OtfNameListFree(struct otfname * on)6275 void OtfNameListFree(struct otfname *on) {
6276 struct otfname *on_next;
6277
6278 for ( ; on!=NULL; on = on_next ) {
6279 on_next = on->next;
6280 free(on->name);
6281 chunkfree(on,sizeof(*on));
6282 }
6283 }
6284
OtfFeatNameListFree(struct otffeatname * fn)6285 void OtfFeatNameListFree(struct otffeatname *fn) {
6286 struct otffeatname *fn_next;
6287
6288 for ( ; fn!=NULL; fn = fn_next ) {
6289 fn_next = fn->next;
6290 OtfNameListFree(fn->names);
6291 chunkfree(fn,sizeof(*fn));
6292 }
6293 }
6294
EncMapNew(int enccount,int backmax,Encoding * enc)6295 EncMap *EncMapNew(int enccount,int backmax,Encoding *enc) {
6296 /* NOTE: 'enccount' and 'backmax' can sometimes be different map sizes */
6297 EncMap *map;
6298
6299 /* Ensure all memory available, otherwise cleanup and exit as NULL */
6300 if ( (map=chunkalloc(sizeof(EncMap)))!=NULL ) {
6301 if ( (map->map=malloc(enccount*sizeof(int32)))!=NULL ) {
6302 if ( (map->backmap=malloc(backmax*sizeof(int32)))!=NULL ) {
6303 map->enccount = map->encmax = enccount;
6304 map->backmax = backmax;
6305 memset(map->map,-1,enccount*sizeof(int32));
6306 memset(map->backmap,-1,backmax*sizeof(int32));
6307 map->enc = enc;
6308 return( map );
6309 }
6310 free(map->map);
6311 }
6312 free(map);
6313 }
6314 return( NULL );
6315 }
6316
EncMap1to1(int enccount)6317 EncMap *EncMap1to1(int enccount) {
6318 /* Used for CID fonts where CID is same as orig_pos */
6319 /* NOTE: map-enc point to a global variable custom. */
6320 /* TODO: avoid global custom and use passed pointer */
6321 EncMap *map;
6322 int i;
6323
6324 if ( (map=EncMapNew(enccount,enccount,&custom))!=NULL ) {
6325 for ( i=0; i<enccount; ++i )
6326 map->map[i] = map->backmap[i] = i;
6327 }
6328 return( map );
6329 }
6330
EncMapFree(EncMap * map)6331 void EncMapFree(EncMap *map) {
6332 if ( map==NULL )
6333 return;
6334
6335 if ( map->enc->is_temporary )
6336 EncodingFree(map->enc);
6337 free(map->map);
6338 free(map->backmap);
6339 free(map->remap);
6340 chunkfree(map,sizeof(EncMap));
6341 }
6342
EncMapCopy(EncMap * map)6343 EncMap *EncMapCopy(EncMap *map) {
6344 /* Make a duplicate 'new' copy of EncMap 'map', Return a NULL if error */
6345 /* NOTE: new-enc also shares map->enc, so be careful if freeing either */
6346 EncMap *new;
6347 int n;
6348
6349 /* Ensure all memory available, otherwise cleanup and exit as NULL */
6350 if ( (new=chunkalloc(sizeof(EncMap)))!=NULL ) {
6351 *new = *map;
6352 if ( (new->map=malloc(map->encmax*sizeof(int32)))!=NULL ) {
6353 if ( (new->backmap=malloc(map->backmax*sizeof(int32)))!=NULL ) {
6354 memcpy(new->map,map->map,map->enccount*sizeof(int32));
6355 memcpy(new->backmap,map->backmap,map->backmax*sizeof(int32));
6356 /* NOTE: This new->enc 'also' points to same map->enc. */
6357 if ( map->remap==NULL )
6358 return( new );
6359 for ( n=0; map->remap[n].infont!=-1; ++n );
6360 if ( (new->remap=malloc(n*sizeof(struct remap)))!=NULL ) {
6361 memcpy(new->remap,map->remap,n*sizeof(struct remap));
6362 return( new );
6363 }
6364 free(new->backmap);
6365 }
6366 free(new->map);
6367 }
6368 free(new);
6369 }
6370 return( NULL );
6371 }
6372
MarkClassFree(int cnt,char ** classes,char ** names)6373 void MarkClassFree(int cnt,char **classes,char **names) {
6374 int i;
6375
6376 for ( i=1; i<cnt; ++i ) {
6377 free( classes[i] );
6378 free( names[i] );
6379 }
6380 free( classes );
6381 free( names );
6382 }
6383
MarkSetFree(int cnt,char ** classes,char ** names)6384 void MarkSetFree(int cnt,char **classes,char **names) {
6385 int i;
6386
6387 for ( i=0; i<cnt; ++i ) {
6388 free( classes[i] );
6389 free( names[i] );
6390 }
6391 free( classes );
6392 free( names );
6393 }
6394
BaseLangCopy(struct baselangextent * extent)6395 struct baselangextent *BaseLangCopy(struct baselangextent *extent) {
6396 struct baselangextent *head, *last, *cur;
6397
6398 last = head = NULL;
6399 for ( ; extent!=NULL; extent = extent->next ) {
6400 cur = chunkalloc(sizeof(struct baselangextent));
6401 *cur = *extent;
6402 cur->features = BaseLangCopy(cur->features);
6403 if ( head==NULL )
6404 head = cur;
6405 else
6406 last->next = cur;
6407 last = cur;
6408 }
6409 return( head );
6410 }
6411
BaseLangFree(struct baselangextent * extent)6412 void BaseLangFree(struct baselangextent *extent) {
6413 struct baselangextent *next;
6414
6415 while ( extent!=NULL ) {
6416 next = extent->next;
6417 BaseLangFree(extent->features);
6418 chunkfree(extent,sizeof(struct baselangextent));
6419 extent = next;
6420 }
6421 }
6422
BaseScriptFree(struct basescript * bs)6423 void BaseScriptFree(struct basescript *bs) {
6424 struct basescript *next;
6425
6426 while ( bs!=NULL ) {
6427 next = bs->next;
6428 if ( bs->baseline_pos )
6429 free(bs->baseline_pos);
6430 BaseLangFree(bs->langs);
6431 chunkfree(bs,sizeof(struct basescript));
6432 bs = next;
6433 }
6434 }
6435
BaseFree(struct Base * base)6436 void BaseFree(struct Base *base) {
6437 if ( base==NULL )
6438 return;
6439
6440 free(base->baseline_tags);
6441 BaseScriptFree(base->scripts);
6442 chunkfree(base,sizeof(struct Base));
6443 }
6444
OTLListCopy(OTLookup ** str)6445 static OTLookup **OTLListCopy(OTLookup **str) {
6446 OTLookup **ret;
6447 int i;
6448
6449 if ( str == NULL )
6450 return( NULL );
6451 for ( i=0 ; str[i]!=NULL; ++i );
6452 ret = malloc((i+1)*sizeof( OTLookup *));
6453 for ( i=0 ; str[i]!=NULL; ++i )
6454 ret[i] = str[i];
6455 ret[i] = NULL;
6456 return( ret );
6457 }
6458
JstfLangsCopy(struct jstf_lang * jl)6459 struct jstf_lang *JstfLangsCopy(struct jstf_lang *jl) {
6460 struct jstf_lang *head=NULL, *last=NULL, *cur;
6461 int i;
6462
6463 while ( jl!=NULL ) {
6464 cur = chunkalloc(sizeof(*cur));
6465 cur->lang = jl->lang;
6466 cur->cnt = jl->cnt;
6467 cur->prios = calloc(cur->cnt,sizeof(struct jstf_prio));
6468 for ( i=0; i<cur->cnt; ++i ) {
6469 cur->prios[i].enableShrink = OTLListCopy( jl->prios[i].enableShrink );
6470 cur->prios[i].disableShrink = OTLListCopy( jl->prios[i].disableShrink );
6471 cur->prios[i].maxShrink = OTLListCopy( jl->prios[i].maxShrink );
6472 cur->prios[i].enableExtend = OTLListCopy( jl->prios[i].enableExtend );
6473 cur->prios[i].disableExtend = OTLListCopy( jl->prios[i].disableExtend );
6474 cur->prios[i].maxExtend = OTLListCopy( jl->prios[i].maxExtend );
6475 }
6476 if ( head==NULL )
6477 head = cur;
6478 else
6479 last->next = cur;
6480 last = cur;
6481 jl = jl->next;
6482 }
6483 return( head );
6484 }
6485
JstfLangFree(struct jstf_lang * jl)6486 void JstfLangFree(struct jstf_lang *jl) {
6487 struct jstf_lang *next;
6488 int i;
6489
6490 while ( jl!=NULL ) {
6491 next = jl->next;
6492 for ( i=0; i<jl->cnt; ++i ) {
6493 struct jstf_prio *jp = &jl->prios[i];
6494 free(jp->enableShrink);
6495 free(jp->disableShrink);
6496 free(jp->maxShrink);
6497 free(jp->enableExtend);
6498 free(jp->disableExtend);
6499 free(jp->maxExtend);
6500 }
6501 free(jl->prios);
6502 chunkfree(jl,sizeof(*jl));
6503 jl = next;
6504 }
6505 }
6506
JustifyFree(Justify * just)6507 void JustifyFree(Justify *just) {
6508 Justify *next;
6509
6510 while ( just!=NULL ) {
6511 next = just->next;
6512 free(just->extenders);
6513 JstfLangFree(just->langs);
6514 chunkfree(just,sizeof(*just));
6515 just = next;
6516 }
6517 }
6518
SplineFontFree(SplineFont * sf)6519 void SplineFontFree(SplineFont *sf) {
6520 int i;
6521 BDFFont *bdf, *bnext;
6522
6523 if ( sf==NULL )
6524 return;
6525 if ( sf->mm!=NULL ) {
6526 MMSetFree(sf->mm);
6527 return;
6528 }
6529 CopyBufferClearCopiedFrom(sf);
6530 PasteRemoveSFAnchors(sf);
6531 if ( sf->sfd_version>0 && sf->sfd_version<2 ) {
6532 // Free special data.
6533 SplineFont1* oldsf = (SplineFont1*)sf;
6534 // First the script language lists.
6535 if (oldsf->script_lang != NULL) {
6536 int scripti;
6537 for (scripti = 0; oldsf->script_lang[scripti] != NULL; scripti ++) {
6538 int scriptj;
6539 for (scriptj = 0; oldsf->script_lang[scripti][scriptj].script != 0; scriptj ++) {
6540 if (oldsf->script_lang[scripti][scriptj].langs != NULL) free(oldsf->script_lang[scripti][scriptj].langs);
6541 }
6542 free(oldsf->script_lang[scripti]); oldsf->script_lang[scripti] = NULL;
6543 }
6544 free(oldsf->script_lang); oldsf->script_lang = NULL;
6545 }
6546 // Then the table orderings.
6547 {
6548 struct table_ordering *ord = oldsf->orders;
6549 while (ord != NULL) {
6550 struct table_ordering *ordtofree = ord;
6551 if (ord->ordered_features != NULL) free(ord->ordered_features);
6552 ord = ord->next;
6553 chunkfree(ordtofree, sizeof(struct table_ordering));
6554 }
6555 oldsf->orders = NULL;
6556 }
6557 }
6558 for ( bdf = sf->bitmaps; bdf!=NULL; bdf = bnext ) {
6559 bnext = bdf->next;
6560 BDFFontFree(bdf);
6561 }
6562 for ( i=0; i<sf->glyphcnt; ++i ) if ( sf->glyphs[i]!=NULL )
6563 SplineCharFree(sf->glyphs[i]);
6564 free(sf->glyphs);
6565 free(sf->fontname);
6566 free(sf->fullname);
6567 free(sf->familyname);
6568 free(sf->weight);
6569 free(sf->copyright);
6570 free(sf->comments);
6571 free(sf->filename);
6572 free(sf->origname);
6573 free(sf->autosavename);
6574 free(sf->version);
6575 free(sf->xuid);
6576 free(sf->cidregistry);
6577 free(sf->ordering);
6578 if ( sf->styleMapFamilyName && sf->styleMapFamilyName[0]!='\0' ) { free(sf->styleMapFamilyName); sf->styleMapFamilyName = NULL; }
6579 MacFeatListFree(sf->features);
6580 /* We don't free the EncMap. That field is only a temporary pointer. Let the FontViewBase free it, that's where it really lives */
6581 // TODO: But that doesn't always get freed. The statement below causes double-frees, so we need to come up with better conditions.
6582 #if 0
6583 if (sf->cidmaster == NULL || sf->cidmaster == sf)
6584 if (sf->map != NULL) { free(sf->map); sf->map = NULL; }
6585 #endif // 0
6586 SplinePointListsFree(sf->grid.splines);
6587 AnchorClassesFree(sf->anchor);
6588 TtfTablesFree(sf->ttf_tables);
6589 TtfTablesFree(sf->ttf_tab_saved);
6590 UndoesFree(sf->grid.undoes);
6591 UndoesFree(sf->grid.redoes);
6592 PSDictFree(sf->private);
6593 TTFLangNamesFree(sf->names);
6594 for ( i=0; i<sf->subfontcnt; ++i )
6595 SplineFontFree(sf->subfonts[i]);
6596 free(sf->subfonts);
6597 GlyphHashFree(sf);
6598 OTLookupListFree(sf->gpos_lookups);
6599 OTLookupListFree(sf->gsub_lookups);
6600 KernClassListFree(sf->kerns);
6601 KernClassListFree(sf->vkerns);
6602 FPSTFree(sf->possub);
6603 ASMFree(sf->sm);
6604 OtfNameListFree(sf->fontstyle_name);
6605 OtfFeatNameListFree(sf->feat_names);
6606 MarkClassFree(sf->mark_class_cnt,sf->mark_classes,sf->mark_class_names);
6607 MarkSetFree(sf->mark_set_cnt,sf->mark_sets,sf->mark_set_names);
6608 GlyphGroupsFree(sf->groups);
6609 GlyphGroupKernsFree(sf->groupkerns);
6610 GlyphGroupKernsFree(sf->groupvkerns);
6611 free( sf->gasp );
6612 #if defined(_NO_PYTHON)
6613 free( sf->python_persistent ); /* It's a string of pickled data which we leave as a string */
6614 #else
6615 PyFF_FreeSF(sf);
6616 #endif
6617 BaseFree(sf->horiz_base);
6618 BaseFree(sf->vert_base);
6619 JustifyFree(sf->justify);
6620 if (sf->layers != NULL) {
6621 int layer;
6622 for (layer = 0; layer < sf->layer_cnt; layer ++) {
6623 if (sf->layers[layer].name != NULL) {
6624 free(sf->layers[layer].name);
6625 sf->layers[layer].name = NULL;
6626 }
6627 if (sf->layers[layer].ufo_path != NULL) {
6628 free(sf->layers[layer].ufo_path);
6629 sf->layers[layer].ufo_path = NULL;
6630 }
6631 }
6632 free(sf->layers); sf->layers = NULL;
6633 }
6634 free(sf);
6635 }
6636
SplineFontClearSpecial(SplineFont * sf)6637 void SplineFontClearSpecial(SplineFont *sf) {
6638 int i;
6639
6640 if ( sf==NULL )
6641 return;
6642 if ( sf->mm!=NULL ) {
6643 MMSetClearSpecial(sf->mm);
6644 return;
6645 }
6646 for ( i=0; i<sf->glyphcnt; ++i ) if ( sf->glyphs[i]!=NULL ) {
6647 struct splinechar *sc = sf->glyphs[i];
6648 if (sc->glif_name != NULL) { free(sc->glif_name); sc->glif_name = NULL; }
6649 // Go through layers.
6650 int lyi;
6651 for ( lyi=0; lyi<sc->layer_cnt; ++lyi ) {
6652 // Free guidelines.
6653 GuidelineSetFree(sc->layers[lyi].guidelines);
6654 sc->layers[lyi].guidelines = NULL;
6655 }
6656 }
6657 for ( i=0; i<sf->subfontcnt; ++i )
6658 SplineFontClearSpecial(sf->subfonts[i]);
6659 KernClassListClearSpecialContents(sf->kerns);
6660 KernClassListClearSpecialContents(sf->vkerns);
6661 if (sf->groups) { GlyphGroupsFree(sf->groups); sf->groups = NULL; }
6662 if (sf->groupkerns) { GlyphGroupKernsFree(sf->groupkerns); sf->groupkerns = NULL; }
6663 if (sf->groupvkerns) { GlyphGroupKernsFree(sf->groupvkerns); sf->groupvkerns = NULL; }
6664 if (sf->python_persistent) {
6665 #if defined(_NO_PYTHON)
6666 free( sf->python_persistent ); /* It's a string of pickled data which we leave as a string */
6667 #else
6668 PyFF_FreeSF(sf);
6669 #endif
6670 sf->python_persistent = NULL;
6671 }
6672 if (sf->layers != NULL) {
6673 int layer;
6674 for (layer = 0; layer < sf->layer_cnt; layer ++) {
6675 if (sf->layers[layer].ufo_path != NULL) {
6676 free(sf->layers[layer].ufo_path);
6677 sf->layers[layer].ufo_path = NULL;
6678 }
6679 }
6680 }
6681 }
6682
6683 #if 0
6684 // These are in splinefont.h.
6685 #define GROUP_NAME_KERNING_UFO 1
6686 #define GROUP_NAME_KERNING_FEATURE 2
6687 #define GROUP_NAME_VERTICAL 4 // Otherwise horizontal.
6688 #define GROUP_NAME_RIGHT 8 // Otherwise left (or above).
6689 #endif // 0
6690
6691
GlyphGroupFree(struct ff_glyphclasses * group)6692 void GlyphGroupFree(struct ff_glyphclasses* group) {
6693 if (group->classname != NULL) free(group->classname);
6694 if (group->glyphs != NULL) free(group->glyphs);
6695 free(group);
6696 }
6697
GlyphGroupsFree(struct ff_glyphclasses * root)6698 void GlyphGroupsFree(struct ff_glyphclasses* root) {
6699 struct ff_glyphclasses* current = root;
6700 struct ff_glyphclasses* next;
6701 while (current != NULL) {
6702 next = current->next;
6703 GlyphGroupFree(current);
6704 current = next;
6705 }
6706 }
6707
GroupNameType(const char * input)6708 int GroupNameType(const char *input) {
6709 int kerning_type = 0; // 1 for U. F. O., 2 for feature file.
6710 int kerning_vert = 0;
6711 int kerning_side = 0; // 1 for left, 2 for right.
6712 if (strchr(input, ' ') || strchr(input, '\n')) return -1;
6713 if (strncmp(input, "public.kern", strlen("public.kern")) == 0) {
6714 int off1 = strlen("public.kern");
6715 char nextc = *(input+off1);
6716 if (nextc == '1') kerning_side = 1;
6717 if (nextc == '2') kerning_side = 2;
6718 if (kerning_side != 0 && *(input+off1+1) == '.' && *(input+off1+2) != '\0')
6719 kerning_type = 1;
6720 else return -1;
6721 } else if (strncmp(input, "public.vkern", strlen("public.vkern")) == 0) {
6722 kerning_vert = 1;
6723 int off1 = strlen("public.vkern");
6724 char nextc = *(input+off1);
6725 if (nextc == '1') kerning_side = 1;
6726 if (nextc == '2') kerning_side = 2;
6727 if (kerning_side != 0 && *(input+off1+1) == '.' && *(input+off1+2) != '\0')
6728 kerning_type = 1;
6729 else return -1;
6730 } else if (strncmp(input, "@MMK_", strlen("@MMK_")) == 0) {
6731 int off1 = strlen("@MMK_");
6732 char nextc = *(input+off1);
6733 if (nextc == 'L') kerning_side = 1;
6734 else if (nextc == 'R') kerning_side = 2;
6735 else if (nextc == 'A') { kerning_side = 1; kerning_vert = 1; }
6736 else if (nextc == 'B') { kerning_side = 2; kerning_vert = 1; }
6737 if (kerning_side != 0 && *(input+off1+1) == '_' && *(input+off1+2) != '\0')
6738 kerning_type = 2;
6739 else return -1;
6740 }
6741 return kerning_type | ((kerning_side == 2) ? GROUP_NAME_RIGHT : 0) | (kerning_vert * GROUP_NAME_VERTICAL);
6742 }
6743
GlyphGroupKernFree(struct ff_rawoffsets * groupkern)6744 void GlyphGroupKernFree(struct ff_rawoffsets* groupkern) {
6745 if (groupkern->left != NULL) free(groupkern->left);
6746 if (groupkern->right != NULL) free(groupkern->right);
6747 free(groupkern);
6748 }
6749
GlyphGroupKernsFree(struct ff_rawoffsets * root)6750 void GlyphGroupKernsFree(struct ff_rawoffsets* root) {
6751 struct ff_rawoffsets* current = root;
6752 struct ff_rawoffsets* next;
6753 while (current != NULL) {
6754 next = current->next;
6755 GlyphGroupKernFree(current);
6756 current = next;
6757 }
6758 }
6759
CountKerningClasses(SplineFont * sf)6760 int CountKerningClasses(SplineFont *sf) {
6761 struct kernclass *current_kernclass;
6762 int isv;
6763 int isr;
6764 int i;
6765 int absolute_index = 0; // This gives us a unique index for each kerning class.
6766 // First we catch the existing names.
6767 absolute_index = 0;
6768 for (isv = 0; isv < 2; isv++)
6769 for (current_kernclass = (isv ? sf->vkerns : sf->kerns); current_kernclass != NULL; current_kernclass = current_kernclass->next)
6770 for (isr = 0; isr < 2; isr++) {
6771 // for ( i=0; i< (isr ? current_kernclass->second_cnt : current_kernclass->first_cnt); ++i );
6772 // absolute_index +=i;
6773 absolute_index += (isr ? current_kernclass->second_cnt : current_kernclass->first_cnt);
6774 }
6775 return absolute_index;
6776 }
6777
count_caps(const char * input)6778 size_t count_caps(const char * input) {
6779 size_t count = 0;
6780 for (int i = 0; input[i] != '\0'; i++) {
6781 if ((input[i] >= 'A') && (input[i] <= 'Z')) count ++;
6782 }
6783 return count;
6784 }
6785
upper_case(const char * input)6786 char * upper_case(const char * input) {
6787 size_t output_length = strlen(input);
6788 char * output = malloc(output_length + 1);
6789 off_t pos = 0;
6790 if (output == NULL) return NULL;
6791 while (pos < output_length) {
6792 if ((input[pos] >= 'a') && (input[pos] <= 'z')) {
6793 output[pos] = (char)(((unsigned char) input[pos]) - 0x20U);
6794 } else {
6795 output[pos] = input[pos];
6796 }
6797 pos++;
6798 }
6799 output[pos] = '\0';
6800 return output;
6801 }
6802
same_case(const char * input)6803 char * same_case(const char * input) {
6804 size_t output_length = strlen(input);
6805 char * output = malloc(output_length + 1);
6806 off_t pos = 0;
6807 if (output == NULL) return NULL;
6808 while (pos < output_length) {
6809 output[pos] = input[pos];
6810 pos++;
6811 }
6812 output[pos] = '\0';
6813 return output;
6814 }
6815
delimit_null(const char * input,char delimiter)6816 char * delimit_null(const char * input, char delimiter) {
6817 size_t output_length = strlen(input);
6818 char * output = malloc(output_length + 1);
6819 if (output == NULL) return NULL;
6820 off_t pos = 0;
6821 while (pos < output_length) {
6822 if (input[pos] == delimiter) {
6823 output[pos] = '\0';
6824 } else {
6825 output[pos] = input[pos];
6826 }
6827 pos++;
6828 }
6829 return output;
6830 }
6831
HashKerningClassNamesFlex(SplineFont * sf,struct glif_name_index * class_name_hash,int capitalize)6832 int HashKerningClassNamesFlex(SplineFont *sf, struct glif_name_index * class_name_hash, int capitalize) {
6833 struct kernclass *current_kernclass;
6834 int isv;
6835 int isr;
6836 int i;
6837 int absolute_index = 0; // This gives us a unique index for each kerning class.
6838 // First we catch the existing names.
6839 absolute_index = 0;
6840 for (isv = 0; isv < 2; isv++)
6841 for (current_kernclass = (isv ? sf->vkerns : sf->kerns); current_kernclass != NULL; current_kernclass = current_kernclass->next)
6842 for (isr = 0; isr < 2; isr++) if ( (isr ? current_kernclass->seconds_names : current_kernclass->firsts_names) != NULL ) {
6843 for ( i=0; i < (isr ? current_kernclass->second_cnt : current_kernclass->first_cnt); ++i )
6844 if ( (isr ? current_kernclass->seconds_names[i] : current_kernclass->firsts_names[i]) != NULL ) {
6845 // Add it to the hash table with its index.
6846 if (capitalize) {
6847 char * cap_name = upper_case(isr ? current_kernclass->seconds_names[i] : current_kernclass->firsts_names[i]);
6848 glif_name_track_new(class_name_hash, absolute_index + i, cap_name);
6849 free(cap_name); cap_name = NULL;
6850 } else {
6851 glif_name_track_new(class_name_hash, absolute_index + i, (isr ? current_kernclass->seconds_names[i] : current_kernclass->firsts_names[i]));
6852 }
6853 }
6854 absolute_index +=i;
6855 }
6856 return absolute_index;
6857 }
HashKerningClassNames(SplineFont * sf,struct glif_name_index * class_name_hash)6858 int HashKerningClassNames(SplineFont *sf, struct glif_name_index * class_name_hash) {
6859 return HashKerningClassNamesFlex(sf, class_name_hash, 0);
6860 }
HashKerningClassNamesCaps(SplineFont * sf,struct glif_name_index * class_name_hash)6861 int HashKerningClassNamesCaps(SplineFont *sf, struct glif_name_index * class_name_hash) {
6862 return HashKerningClassNamesFlex(sf, class_name_hash, 1);
6863 }
6864
KerningClassSeekByAbsoluteIndex(const struct splinefont * sf,int seek_index,struct kernclass ** okc,int * oisv,int * oisr,int * ooffset)6865 int KerningClassSeekByAbsoluteIndex(const struct splinefont *sf, int seek_index, struct kernclass **okc, int *oisv, int *oisr, int *ooffset) {
6866 int current = 0;
6867 struct kernclass *current_kernclass;
6868 int isv;
6869 int isr;
6870 int absolute_index = 0; // This gives us a unique index for each kerning class.
6871 // First we catch the existing names.
6872 absolute_index = 0;
6873 for (isv = 0; isv < 2; isv++)
6874 for (current_kernclass = (isv ? sf->vkerns : sf->kerns); current_kernclass != NULL; current_kernclass = current_kernclass->next)
6875 for (isr = 0; isr < 2; isr++) {
6876 if (seek_index < absolute_index + (isr ? current_kernclass->second_cnt : current_kernclass->first_cnt)) {
6877 *okc = current_kernclass;
6878 *oisv = isv;
6879 *oisr = isr;
6880 *ooffset = seek_index - absolute_index;
6881 return 1;
6882 }
6883 absolute_index += (isr ? current_kernclass->second_cnt : current_kernclass->first_cnt);
6884 }
6885 return 0;
6886 }
6887
SFGetGroup(const struct splinefont * sf,int index,const char * name)6888 struct ff_glyphclasses *SFGetGroup(const struct splinefont *sf, int index, const char *name) {
6889 if (sf == NULL) return NULL;
6890 struct ff_glyphclasses *ret = sf->groups;
6891 while (ret != NULL && (ret->classname == NULL || strcmp(ret->classname, name) != 0)) ret = ret->next;
6892 return ret;
6893 }
6894
StringInStrings(char const * const * space,int length,const char * target)6895 int StringInStrings(char const* const* space, int length, const char *target) {
6896 int pos;
6897 for (pos = 0; pos < length; pos++) if (strcmp(space[pos], target) == 0) break;
6898 return pos;
6899 }
6900
StringExplode(const char * input,char delimiter)6901 char **StringExplode(const char *input, char delimiter) {
6902 if (input == NULL) return NULL;
6903 const char *pstart = input;
6904 const char *pend = input;
6905 int entry_count = 0;
6906 while (*pend != '\0') {
6907 while (*pstart == delimiter) pstart++;
6908 pend = pstart;
6909 while (*pend != delimiter && *pend != '\0') pend++;
6910 if (pend > pstart) entry_count++;
6911 pstart = pend;
6912 }
6913 char **output = calloc(entry_count + 1, sizeof(char*));
6914 pstart = input;
6915 pend = input;
6916 entry_count = 0;
6917 while (*pend != '\0') {
6918 while (*pstart == delimiter) pstart++;
6919 pend = pstart;
6920 while (*pend != delimiter && *pend != '\0') pend++;
6921 if (pend > pstart) output[entry_count++] = copyn(pstart, pend-pstart);
6922 pstart = pend;
6923 }
6924 return output;
6925 }
6926
ExplodedStringFree(char ** input)6927 void ExplodedStringFree(char **input) {
6928 int index = 0;
6929 while (input[index] != NULL) free(input[index++]);
6930 free(input);
6931 }
6932
SFKerningGroupExistsSpecific(const struct splinefont * sf,const char * groupname,int isv,int isr)6933 int SFKerningGroupExistsSpecific(const struct splinefont *sf, const char *groupname, int isv, int isr) {
6934 if (sf == NULL) return 0;
6935 if (isv) {
6936 if (sf->vkerns == NULL) return 0;
6937 if (isr) return (StringInStrings((const char * const *)sf->vkerns->seconds_names, sf->vkerns->second_cnt, groupname) < sf->vkerns->second_cnt);
6938 else return (StringInStrings((const char * const *)sf->vkerns->firsts_names, sf->vkerns->first_cnt, groupname) < sf->vkerns->first_cnt);
6939 } else {
6940 if (sf->kerns == NULL) return 0;
6941 if (isr) return (StringInStrings((const char * const *)sf->kerns->seconds_names, sf->kerns->second_cnt, groupname) < sf->kerns->second_cnt);
6942 else return (StringInStrings((const char * const *)sf->kerns->firsts_names, sf->kerns->first_cnt, groupname) < sf->kerns->first_cnt);
6943 }
6944 return 0;
6945 }
6946
MMSetFreeContents(MMSet * mm)6947 void MMSetFreeContents(MMSet *mm) {
6948 int i;
6949
6950 free(mm->instances);
6951
6952 free(mm->positions);
6953 free(mm->defweights);
6954
6955 for ( i=0; i<mm->axis_count; ++i ) {
6956 free(mm->axes[i]);
6957 free(mm->axismaps[i].blends);
6958 free(mm->axismaps[i].designs);
6959 MacNameListFree(mm->axismaps[i].axisnames);
6960 }
6961 free(mm->axismaps);
6962 free(mm->cdv);
6963 free(mm->ndv);
6964 for ( i=0; i<mm->named_instance_count; ++i ) {
6965 free(mm->named_instances[i].coords);
6966 MacNameListFree(mm->named_instances[i].names);
6967 }
6968 free(mm->named_instances);
6969 }
6970
MMSetFree(MMSet * mm)6971 void MMSetFree(MMSet *mm) {
6972 int i;
6973
6974 for ( i=0; i<mm->instance_count; ++i ) {
6975 mm->instances[i]->mm = NULL;
6976 mm->instances[i]->map = NULL;
6977 SplineFontFree(mm->instances[i]);
6978 }
6979 mm->normal->mm = NULL;
6980 SplineFontFree(mm->normal); /* EncMap gets freed here */
6981 MMSetFreeContents(mm);
6982
6983 chunkfree(mm,sizeof(*mm));
6984 }
6985
MMSetClearSpecial(MMSet * mm)6986 void MMSetClearSpecial(MMSet *mm) {
6987 int i;
6988
6989 for ( i=0; i<mm->instance_count; ++i ) {
6990 SplineFontClearSpecial(mm->instances[i]);
6991 }
6992 SplineFontClearSpecial(mm->normal);
6993 }
6994
xcmp(const void * _p1,const void * _p2)6995 static int xcmp(const void *_p1, const void *_p2) {
6996 const SplinePoint * const *_spt1 = _p1, * const *_spt2 = _p2;
6997 const SplinePoint *sp1 = *_spt1, *sp2 = *_spt2;
6998
6999 if ( sp1->me.x>sp2->me.x )
7000 return( 1 );
7001 else if ( sp1->me.x<sp2->me.x )
7002 return( -1 );
7003
7004 return( 0 );
7005 }
7006
ycmp(const void * _p1,const void * _p2)7007 static int ycmp(const void *_p1, const void *_p2) {
7008 const SplinePoint * const *_spt1 = _p1, * const *_spt2 = _p2;
7009 const SplinePoint *sp1 = *_spt1, *sp2 = *_spt2;
7010
7011 if ( sp1->me.y>sp2->me.y )
7012 return( 1 );
7013 else if ( sp1->me.y<sp2->me.y )
7014 return( -1 );
7015
7016 return( 0 );
7017 }
7018
7019 struct cluster {
7020 int cnt;
7021 int first, last;
7022 };
7023
countcluster(SplinePoint ** ptspace,struct cluster * cspace,int ptcnt,int is_y,int i,bigreal within,bigreal max)7024 static void countcluster(SplinePoint **ptspace, struct cluster *cspace,
7025 int ptcnt, int is_y, int i, bigreal within, bigreal max) {
7026 int j;
7027
7028 cspace[i].cnt = 1; /* current point is always within its own cluster */
7029 cspace[i].first = cspace[i].last = i;
7030 for ( j=i-1; j>=0; --j ) {
7031 if ( cspace[j].cnt==0 ) /* Already allocated to a different cluster */
7032 break;
7033 if ( (&ptspace[j+1]->me.x)[is_y]-(&ptspace[j]->me.x)[is_y]<within &&
7034 (&ptspace[i]->me.x)[is_y]-(&ptspace[j]->me.x)[is_y]<max ) {
7035 ++cspace[i].cnt;
7036 cspace[i].first = j;
7037 } else
7038 break;
7039 }
7040 for ( j=i+1; j<ptcnt; ++j ) {
7041 if ( cspace[j].cnt==0 ) /* Already allocated to a different cluster */
7042 break;
7043 if ( (&ptspace[j]->me.x)[is_y]-(&ptspace[j-1]->me.x)[is_y]<within &&
7044 (&ptspace[j]->me.x)[is_y]-(&ptspace[i]->me.x)[is_y]<max ) {
7045 ++cspace[i].cnt;
7046 cspace[i].last = j;
7047 } else
7048 break;
7049 }
7050 }
7051
_SplineCharRoundToCluster(SplineChar * sc,SplinePoint ** ptspace,struct cluster * cspace,int ptcnt,int is_y,int dohints,int layer,int changed,bigreal within,bigreal max)7052 static int _SplineCharRoundToCluster(SplineChar *sc,SplinePoint **ptspace,
7053 struct cluster *cspace,int ptcnt,int is_y,int dohints,
7054 int layer, int changed,
7055 bigreal within, bigreal max ) {
7056 int i,j,best;
7057 bigreal low,high,cur;
7058
7059 for ( i=0; i<ptcnt; ++i )
7060 cspace[i].cnt = 1; /* Initialize to non-zero */
7061 for ( i=0; i<ptcnt; ++i )
7062 countcluster(ptspace,cspace,ptcnt,is_y,i,within,max);
7063
7064 for (;;) {
7065 j=0; best = cspace[0].cnt;
7066 for ( i=1; i<ptcnt; ++i ) {
7067 if ( cspace[i].cnt>best ) {
7068 j=i;
7069 best = cspace[i].cnt;
7070 }
7071 }
7072 if ( best<=1 ) /* No more clusters */
7073 return( changed );
7074 for ( i=j+1; i<=cspace[j].last && cspace[i].cnt==cspace[j].cnt; ++i );
7075 j = (j+i-1)/2; /* There are probably several points with the */
7076 /* same values for cspace. Pick one in the */
7077 /* middle, so that when round we round to the */
7078 /* middle rather than to an edge */
7079 low = (&ptspace[cspace[j].first]->me.x)[is_y];
7080 high = (&ptspace[cspace[j].last]->me.x)[is_y];
7081 cur = (&ptspace[j]->me.x)[is_y];
7082 if ( low==high ) {
7083 for ( i=cspace[j].first; i<=cspace[j].last; ++i )
7084 cspace[i].cnt = 0;
7085 continue;
7086 }
7087 if ( !changed ) {
7088 if ( layer==ly_all )
7089 SCPreserveState(sc,dohints);
7090 else if ( layer!=ly_grid )
7091 SCPreserveLayer(sc,layer,dohints);
7092 changed = true;
7093 }
7094 for ( i=cspace[j].first; i<=cspace[j].last; ++i ) {
7095 bigreal off = (&ptspace[i]->me.x)[is_y] - cur;
7096 (&ptspace[i]->nextcp.x)[is_y] -= off;
7097 (&ptspace[i]->prevcp.x)[is_y] -= off;
7098 (&ptspace[i]->me.x)[is_y] -= off;
7099 if ( (&ptspace[i]->prevcp.x)[is_y]-cur>-within &&
7100 (&ptspace[i]->prevcp.x)[is_y]-cur<within ) {
7101 (&ptspace[i]->prevcp.x)[is_y] = cur;
7102 if ( (&ptspace[i]->prevcp.x)[!is_y]==(&ptspace[i]->me.x)[!is_y] )
7103 ptspace[i]->noprevcp = true;
7104 }
7105 if ( (&ptspace[i]->nextcp.x)[is_y]-cur>-within &&
7106 (&ptspace[i]->nextcp.x)[is_y]-cur<within ) {
7107 (&ptspace[i]->nextcp.x)[is_y] = cur;
7108 if ( (&ptspace[i]->nextcp.x)[!is_y]==(&ptspace[i]->me.x)[!is_y] )
7109 ptspace[i]->nonextcp = true;
7110 }
7111 cspace[i].cnt = 0;
7112 }
7113 if ( dohints ) {
7114 StemInfo *h = is_y ? sc->hstem : sc->vstem;
7115 while ( h!=NULL && h->start<=high ) {
7116 if ( h->start>=low ) {
7117 h->width -= (h->start-cur);
7118 h->start = cur;
7119 }
7120 if ( h->start+h->width>=low && h->start+h->width<=high )
7121 h->width = cur-h->start;
7122 h = h->next;
7123 }
7124 }
7125 /* Ok, surrounding points can no longer use the ones allocated to */
7126 /* this cluster. So refigure them */
7127 for ( i=cspace[j].first-1; i>=0 &&
7128 ( (&ptspace[i]->me.x)[is_y]-cur>-max && (&ptspace[i]->me.x)[is_y]-cur<max ); --i )
7129 countcluster(ptspace,cspace,ptcnt,is_y,i,within,max);
7130 for ( i=cspace[j].last+1; i<ptcnt &&
7131 ( (&ptspace[i]->me.x)[is_y]-cur>-max && (&ptspace[i]->me.x)[is_y]-cur<max ); ++i )
7132 countcluster(ptspace,cspace,ptcnt,is_y,i,within,max);
7133 }
7134 }
7135
SCRoundToCluster(SplineChar * sc,int layer,int sel,bigreal within,bigreal max)7136 int SCRoundToCluster(SplineChar *sc,int layer,int sel,bigreal within,bigreal max) {
7137 /* Do a cluster analysis on the points in this character. Look at each */
7138 /* axis in turn. Order all points in char along this axis. For each pt: */
7139 /* look at the two points before & after it. If those to pts are within */
7140 /* the error bound (within) then continue until we reach a point that */
7141 /* is further from its nearest point than "within" or is further from */
7142 /* the center point than "max". Count all the points we have found. */
7143 /* These points make up the cluster centered on this point. */
7144 /* Then find the largest cluster & round everything to the center point */
7145 /* (shift each point & its cps to center point. Then if cps are "within" */
7146 /* set the cps to the center point too) */
7147 /* Refigure all clusters within "max" of this one, Find the next largest */
7148 /* cluster, and continue. We stop when the largest cluster has only one */
7149 /* point in it */
7150 /* if "sel" is true then we are only interested in selected points */
7151 /* (if there are no selected points then all points in the current layer) */
7152 /* if "layer"==ly_grid then use sf->grid. if layer==ly_all then all foreground layers*/
7153 /* if "layer"==ly_fore or ly_all then round hints that fall in our clusters too*/
7154 int ptcnt, selcnt;
7155 int l,k,changed;
7156 SplineSet *spl;
7157 SplinePoint *sp;
7158 SplinePoint **ptspace = NULL;
7159 struct cluster *cspace;
7160 Spline *s, *first;
7161
7162 /* First figure out what points we will need */
7163 for ( k=0; k<2; ++k ) {
7164 ptcnt = selcnt = 0;
7165 if ( layer==ly_all ) {
7166 for ( l=ly_fore; l<sc->layer_cnt; ++l ) {
7167 for ( spl = sc->layers[l].splines; spl!=NULL; spl=spl->next ) {
7168 for ( sp = spl->first; ; ) {
7169 if ( k && (!sel || (sel && sp->selected)) )
7170 ptspace[ptcnt++] = sp;
7171 else if ( !k )
7172 ++ptcnt;
7173 if ( sp->selected ) ++selcnt;
7174 if ( sp->next==NULL )
7175 break;
7176 sp = sp->next->to;
7177 if ( sp==spl->first )
7178 break;
7179 }
7180 SplineSetSpirosClear(spl);
7181 }
7182 }
7183 } else {
7184 if ( layer==ly_grid )
7185 spl = sc->parent->grid.splines;
7186 else
7187 spl = sc->layers[layer].splines;
7188 for ( ; spl!=NULL; spl=spl->next ) {
7189 for ( sp = spl->first; ; ) {
7190 if ( k && (!sel || (sel && sp->selected)) )
7191 ptspace[ptcnt++] = sp;
7192 else if ( !k )
7193 ++ptcnt;
7194 if ( sp->selected ) ++selcnt;
7195 if ( sp->next==NULL )
7196 break;
7197 sp = sp->next->to;
7198 if ( sp==spl->first )
7199 break;
7200 }
7201 }
7202 }
7203 if ( sel && selcnt==0 )
7204 sel = false;
7205 if ( sel ) ptcnt = selcnt;
7206 if ( ptcnt<=1 ) {
7207 free(ptspace);
7208 return(false); /* Can't be any clusters */
7209 }
7210 if ( k==0 )
7211 ptspace = malloc((ptcnt+1)*sizeof(SplinePoint *));
7212 else
7213 ptspace[ptcnt] = NULL;
7214 }
7215
7216 cspace = malloc(ptcnt*sizeof(struct cluster));
7217
7218 qsort(ptspace,ptcnt,sizeof(SplinePoint *),xcmp);
7219 changed = _SplineCharRoundToCluster(sc,ptspace,cspace,ptcnt,false,
7220 (layer==ly_all || layer==ly_fore) && !sel,layer,false,within,max);
7221
7222 qsort(ptspace,ptcnt,sizeof(SplinePoint *),ycmp);
7223 changed = _SplineCharRoundToCluster(sc,ptspace,cspace,ptcnt,true,
7224 (layer==ly_all || layer==ly_fore) && !sel,layer,changed,within,max);
7225
7226 free(ptspace);
7227 free(cspace);
7228
7229 if ( changed ) {
7230 if ( layer==ly_all ) {
7231 for ( l=ly_fore; l<sc->layer_cnt; ++l ) {
7232 for ( spl = sc->layers[l].splines; spl!=NULL; spl=spl->next ) {
7233 first = NULL;
7234 SplineSetSpirosClear(spl);
7235 for ( s=spl->first->next; s!=NULL && s!=first; s=s->to->next ) {
7236 SplineRefigure(s);
7237 if ( first==NULL ) first = s;
7238 }
7239 }
7240 }
7241 } else {
7242 if ( layer==ly_grid )
7243 spl = sc->parent->grid.splines;
7244 else
7245 spl = sc->layers[layer].splines;
7246 for ( ; spl!=NULL; spl=spl->next ) {
7247 first = NULL;
7248 for ( s=spl->first->next; s!=NULL && s!=first; s=s->to->next ) {
7249 SplineRefigure(s);
7250 if ( first==NULL ) first = s;
7251 }
7252 }
7253 }
7254 SCCharChangedUpdate(sc,layer);
7255 }
7256 return( changed );
7257 }
7258
SplineRemoveAnnoyingExtrema1(Spline * s,int which,bigreal err_sq)7259 static int SplineRemoveAnnoyingExtrema1(Spline *s,int which,bigreal err_sq) {
7260 /* Remove extrema which are very close to one of the spline end-points */
7261 /* and which are in the oposite direction (along the normal of the */
7262 /* close end-point's cp) from the other end-point */
7263 extended ts[2], t1, t2;
7264 bigreal df, dt;
7265 bigreal dp, d_o;
7266 int i;
7267 BasePoint pos, norm;
7268 SplinePoint *close, *other;
7269 BasePoint *ccp;
7270 bigreal c_, b_, nextcp, prevcp, prop;
7271 int changed = false;
7272
7273 SplineFindExtrema(&s->splines[which],&ts[0],&ts[1]);
7274
7275 for ( i=0; i<2; ++i ) if ( ts[i]!=-1 && ts[i]!=0 && ts[i]!=1 ) {
7276 pos.x = ((s->splines[0].a*ts[i]+s->splines[0].b)*ts[i]+s->splines[0].c)*ts[i]+s->splines[0].d;
7277 pos.y = ((s->splines[1].a*ts[i]+s->splines[1].b)*ts[i]+s->splines[1].c)*ts[i]+s->splines[1].d;
7278 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);
7279 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);
7280 if ( df<dt && df<err_sq ) {
7281 close = s->from;
7282 ccp = &s->from->nextcp;
7283 other = s->to;
7284 } else if ( dt<df && dt<err_sq ) {
7285 close = s->to;
7286 ccp = &s->to->prevcp;
7287 other = s->from;
7288 } else
7289 continue;
7290 if ( ccp->x==close->me.x && ccp->y==close->me.y )
7291 continue;
7292
7293 norm.x = (ccp->y-close->me.y);
7294 norm.y = -(ccp->x-close->me.x);
7295 dp = (pos.x-close->me.x)*norm.x + (pos.y-close->me.y)*norm.y;
7296 d_o = (other->me.x-close->me.x)*norm.x + (other->me.y-close->me.y)*norm.y;
7297 if ( dp!=0 && dp*d_o>=0 )
7298 continue;
7299
7300 _SplineFindExtrema(&s->splines[which],&t1,&t2);
7301 if ( t1==ts[i] ) {
7302 if ( close==s->from ) t1=0;
7303 else t1 = 1;
7304 } else if ( t2==ts[i] ) {
7305 if ( close==s->from ) t2=0;
7306 else t2 = 1;
7307 } else
7308 continue;
7309
7310 if ( t2==-1 ) /* quadratic */
7311 continue; /* Can't happen in a quadratic */
7312
7313 /* The roots of the "slope" quadratic were t1, t2. We have shifted one*/
7314 /* root so that that extremum is exactly on an end point */
7315 /* Figure out the new slope quadratic, from that what the cubic must */
7316 /* be, and from that what the control points must be */
7317 /* Quad = 3at^2 + 2bt + c */
7318 /* New quad = 3a * (t^2 -(t1+t2)t + t1*t2) */
7319 /* a' = a, b' = -(t1+t2)/6a, c' = t1*t2/3a, d' = d */
7320 /* nextcp = from + c'/3, prevcp = nextcp + (b' + c')/3 */
7321 /* Then for each cp figure what percentage of the original cp vector */
7322 /* (or at least this one dimension of that vector) this represents */
7323 /* and scale both dimens by this amount */
7324 b_ = -(t1+t2)*3*s->splines[which].a/2;
7325 c_ = (t1*t2)*3*s->splines[which].a;
7326 nextcp = (&s->from->me.x)[which] + c_/3;
7327 prevcp = nextcp + (b_ + c_)/3;
7328
7329 if ( (&s->from->nextcp.x)[which] != (&s->from->me.x)[which] ) {
7330 prop = (c_/3) / ( (&s->from->nextcp.x)[which] - (&s->from->me.x)[which] );
7331 if ( prop<0 && (c_/3 < .1 && c_/3 > -.1))
7332 (&s->to->prevcp.x)[which] = nextcp;
7333 else if ( prop>=0 && prop<=10 ) {
7334 s->from->nextcp.x = s->from->me.x + prop*(s->from->nextcp.x-s->from->me.x);
7335 s->from->nextcp.y = s->from->me.y + prop*(s->from->nextcp.y-s->from->me.y);
7336 s->from->nonextcp = (prop == 0);
7337 }
7338 }
7339
7340 if ( (&s->to->prevcp.x)[which] != (&s->to->me.x)[which] ) {
7341 prop = ( prevcp - (&s->to->me.x)[which]) /
7342 ( (&s->to->prevcp.x)[which] - (&s->to->me.x)[which] );
7343 if ( prop<0 && (prevcp - (&s->to->me.x)[which] < .1 && prevcp - (&s->to->me.x)[which] > -.1))
7344 (&s->to->prevcp.x)[which] = prevcp;
7345 else if ( prop>=0 && prop<=10 ) {
7346 s->to->prevcp.x = s->to->me.x + prop*(s->to->prevcp.x-s->to->me.x);
7347 s->to->prevcp.y = s->to->me.y + prop*(s->to->prevcp.y-s->to->me.y);
7348 s->to->noprevcp = (prop == 0);
7349 }
7350 }
7351 SplineRefigure(s);
7352 changed = true;
7353 }
7354 return( changed );
7355 }
7356
SplineRemoveAnnoyingExtrema(Spline * s,bigreal err_sq)7357 static int SplineRemoveAnnoyingExtrema(Spline *s,bigreal err_sq) {
7358 int changed;
7359
7360 changed = SplineRemoveAnnoyingExtrema1(s,0,err_sq);
7361 if ( SplineRemoveAnnoyingExtrema1(s,1,err_sq) )
7362 changed = true;
7363 return( changed );
7364 }
7365
SplineSetsRemoveAnnoyingExtrema(SplineSet * ss,bigreal err)7366 int SplineSetsRemoveAnnoyingExtrema(SplineSet *ss,bigreal err) {
7367 int changed = false;
7368 bigreal err_sq = err*err;
7369 Spline *s, *first;
7370
7371
7372 while ( ss!=NULL ) {
7373 first = NULL;
7374 for ( s = ss->first->next; s!=NULL && s!=first; s = s->to->next ) {
7375 if ( first == NULL ) first = s;
7376 if ( SplineRemoveAnnoyingExtrema(s,err_sq))
7377 changed = true;
7378 }
7379 ss = ss->next;
7380 }
7381 return( changed );
7382 }
7383
SplineRemoveWildControlPoints(Spline * s,bigreal distratio)7384 int SplineRemoveWildControlPoints(Spline *s, bigreal distratio) {
7385 // If the distance between the control point and its base
7386 // exceeds the the distance between the base points
7387 // by a great factor,
7388 // it is likely erroneous and is likely to cause problems.
7389 // So we remove it.
7390 if (s->from == NULL || s->to == NULL)
7391 return 0;
7392 int changed;
7393 bigreal pdisplacement = DistanceBetweenPoints(&s->from->me, &s->to->me);
7394 bigreal bcdisplacement0 = 0.0;
7395 bigreal bcdisplacement1 = 0.0;
7396 if (!s->from->nonextcp)
7397 bcdisplacement0 = DistanceBetweenPoints(&s->from->me, &s->from->nextcp);
7398 if (!s->to->noprevcp)
7399 bcdisplacement1 = DistanceBetweenPoints(&s->to->me, &s->to->prevcp);
7400 if (pdisplacement == 0 || MAX(bcdisplacement0, bcdisplacement1) / pdisplacement > distratio) {
7401 changed = s->islinear = s->from->nonextcp = s->to->noprevcp = true;
7402 s->from->nextcp = s->from->me;
7403 s->to->prevcp = s->to->me;
7404 SplineRefigure(s);
7405 }
7406 return changed;
7407 }
7408
SplineSetsRemoveWildControlPoints(SplineSet * ss,bigreal distratio)7409 int SplineSetsRemoveWildControlPoints(SplineSet *ss, bigreal distratio) {
7410 int changed = false;
7411 Spline *s, *first;
7412
7413
7414 while ( ss!=NULL ) {
7415 first = NULL;
7416 for ( s = ss->first->next; s!=NULL && s!=first; s = s->to->next ) {
7417 if ( first == NULL ) first = s;
7418 if ( SplineRemoveWildControlPoints(s,distratio))
7419 changed = true;
7420 }
7421 ss = ss->next;
7422 }
7423 return( changed );
7424 }
7425
SplineBisect(Spline * spline,extended t)7426 SplinePoint *SplineBisect(Spline *spline, extended t) {
7427 Spline1 xstart, xend;
7428 Spline1 ystart, yend;
7429 Spline *spline1, *spline2;
7430 SplinePoint *mid;
7431 SplinePoint *old0, *old1;
7432 Spline1D *xsp = &spline->splines[0], *ysp = &spline->splines[1];
7433 int order2 = spline->order2;
7434
7435 #ifdef DEBUG
7436 if ( t<=1e-3 || t>=1-1e-3 )
7437 IError("Bisection to create a zero length spline");
7438 #endif
7439 xstart.s0 = xsp->d; ystart.s0 = ysp->d;
7440 xend.s1 = (extended) xsp->a+xsp->b+xsp->c+xsp->d;
7441 yend.s1 = (extended) ysp->a+ysp->b+ysp->c+ysp->d;
7442 xstart.s1 = xend.s0 = ((xsp->a*t+xsp->b)*t+xsp->c)*t + xsp->d;
7443 ystart.s1 = yend.s0 = ((ysp->a*t+ysp->b)*t+ysp->c)*t + ysp->d;
7444 FigureSpline1(&xstart,0,t,xsp);
7445 FigureSpline1(&xend,t,1,xsp);
7446 FigureSpline1(&ystart,0,t,ysp);
7447 FigureSpline1(¥d,t,1,ysp);
7448
7449 mid = chunkalloc(sizeof(SplinePoint));
7450 mid->me.x = xstart.s1; mid->me.y = ystart.s1;
7451 if ( order2 ) {
7452 mid->nextcp.x = xend.sp.d + xend.sp.c/2;
7453 mid->nextcp.y = yend.sp.d + yend.sp.c/2;
7454 mid->prevcp.x = xstart.sp.d + xstart.sp.c/2;
7455 mid->prevcp.y = ystart.sp.d + ystart.sp.c/2;
7456 } else {
7457 mid->nextcp.x = xend.c0; mid->nextcp.y = yend.c0;
7458 mid->prevcp.x = xstart.c1; mid->prevcp.y = ystart.c1;
7459 }
7460 if ( mid->me.x==mid->nextcp.x && mid->me.y==mid->nextcp.y )
7461 mid->nonextcp = true;
7462 if ( mid->me.x==mid->prevcp.x && mid->me.y==mid->prevcp.y )
7463 mid->noprevcp = true;
7464
7465 old0 = spline->from; old1 = spline->to;
7466 if ( order2 ) {
7467 old0->nextcp = mid->prevcp;
7468 old1->prevcp = mid->nextcp;
7469 } else {
7470 old0->nextcp.x = xstart.c0; old0->nextcp.y = ystart.c0;
7471 old1->prevcp.x = xend.c1; old1->prevcp.y = yend.c1;
7472 }
7473 old0->nonextcp = (old0->nextcp.x==old0->me.x && old0->nextcp.y==old0->me.y);
7474 old1->noprevcp = (old1->prevcp.x==old1->me.x && old1->prevcp.y==old1->me.y);
7475 old0->nextcpdef = false;
7476 old1->prevcpdef = false;
7477 SplineFree(spline);
7478
7479 spline1 = chunkalloc(sizeof(Spline));
7480 spline1->splines[0] = xstart.sp; spline1->splines[1] = ystart.sp;
7481 spline1->from = old0;
7482 spline1->to = mid;
7483 spline1->order2 = order2;
7484 old0->next = spline1;
7485 mid->prev = spline1;
7486 if ( SplineIsLinear(spline1)) {
7487 spline1->islinear = spline1->from->nonextcp = spline1->to->noprevcp = true;
7488 spline1->from->nextcp = spline1->from->me;
7489 spline1->to->prevcp = spline1->to->me;
7490 }
7491 SplineRefigure(spline1);
7492
7493 spline2 = chunkalloc(sizeof(Spline));
7494 spline2->splines[0] = xend.sp; spline2->splines[1] = xend.sp;
7495 spline2->from = mid;
7496 spline2->to = old1;
7497 spline2->order2 = order2;
7498 mid->next = spline2;
7499 old1->prev = spline2;
7500 if ( SplineIsLinear(spline2)) {
7501 spline2->islinear = spline2->from->nonextcp = spline2->to->noprevcp = true;
7502 spline2->from->nextcp = spline2->from->me;
7503 spline2->to->prevcp = spline2->to->me;
7504 }
7505 SplineRefigure(spline2);
7506 return( mid );
7507 }
7508
SplineSplit(Spline * spline,extended ts[3])7509 Spline *SplineSplit(Spline *spline, extended ts[3]) {
7510 /* Split the current spline in up to 3 places */
7511 Spline1 splines[2][4];
7512 int i,cnt;
7513 bigreal base;
7514 SplinePoint *last, *sp;
7515 Spline *new;
7516 int order2 = spline->order2;
7517
7518 memset(splines,0,sizeof(splines));
7519 base=0;
7520 for ( i=cnt=0; i<3 && ts[i]!=-1; ++i ) {
7521 if ( base>1-1e-3 ) /* Avoid tiny splines */
7522 break;
7523 else if ( base<ts[i]-1e-3 ) {
7524 FigureSpline1(&splines[0][cnt],base,ts[i],&spline->splines[0]);
7525 FigureSpline1(&splines[1][cnt++],base,ts[i],&spline->splines[1]);
7526 base = ts[i];
7527 }
7528 }
7529 if ( base==0 )
7530 return( spline );
7531
7532 FigureSpline1(&splines[0][cnt],base,1.0,&spline->splines[0]);
7533 FigureSpline1(&splines[1][cnt],base,1.0,&spline->splines[1]);
7534
7535 last = spline->from;
7536 for ( i=0; i<=cnt; ++i ) {
7537 if ( order2 ) {
7538 last->nextcp.x = splines[0][i].sp.d+splines[0][i].sp.c/2;
7539 last->nextcp.y = splines[1][i].sp.d+splines[1][i].sp.c/2;
7540 } else {
7541 last->nextcp.x = splines[0][i].c0;
7542 last->nextcp.y = splines[1][i].c0;
7543 }
7544 if ( i==cnt )
7545 sp = spline->to;
7546 else {
7547 sp = chunkalloc(sizeof(SplinePoint));
7548 sp->me.x = splines[0][i+1].sp.d;
7549 sp->me.y = splines[1][i+1].sp.d;
7550 }
7551 if ( order2 ) {
7552 sp->prevcp = last->nextcp;
7553 SplineMake2(last,sp);
7554 } else {
7555 sp->prevcp.x = splines[0][i].c1;
7556 sp->prevcp.y = splines[1][i].c1;
7557 SplineMake3(last,sp);
7558 }
7559 last = sp;
7560 }
7561
7562 new = spline->from->next;
7563 SplineFree(spline);
7564 return( new );
7565 }
7566
SSExistsInLayer(SplineSet * ss,SplineSet * lots)7567 int SSExistsInLayer(SplineSet *ss,SplineSet *lots ) {
7568 /* In Find Problems we hold some state while we allow the user to go off */
7569 /* and do stuff. It is perfectly possible for the user to delete the */
7570 /* state we hold pointers to. Do a rough check that the thing hasn't */
7571 /* been deleted */
7572 while ( lots!=NULL ) {
7573 if ( lots==ss )
7574 return( true );
7575 lots = lots->next;
7576 }
7577 return( false );
7578 }
7579
SplineExistsInSS(Spline * s,SplineSet * ss)7580 int SplineExistsInSS(Spline *s,SplineSet *ss) {
7581 /* In Find Problems we hold some state while we allow the user to go off */
7582 /* and do stuff. It is perfectly possible for the user to delete the */
7583 /* state we hold pointers to. Do a rough check that the thing hasn't */
7584 /* been deleted */
7585 Spline *spline, *first;
7586
7587 first = NULL;
7588 for ( spline = ss->first->next; spline!=NULL && spline!=first; spline=spline->to->next ) {
7589 if ( first==NULL ) first = spline;
7590 if ( spline==s )
7591 return( true );
7592 }
7593 return( false );
7594 }
7595
SpExistsInSS(SplinePoint * sp,SplineSet * ss)7596 int SpExistsInSS(SplinePoint *sp,SplineSet *ss) {
7597 /* In Find Problems we hold some state while we allow the user to go off */
7598 /* and do stuff. It is perfectly possible for the user to delete the */
7599 /* state we hold pointers to. Do a rough check that the thing hasn't */
7600 /* been deleted */
7601 SplinePoint *sp2;
7602
7603 for ( sp2 = ss->first; ; ) {
7604 if ( sp==sp2 )
7605 return( true );
7606 if ( sp2->next==NULL )
7607 return( false );
7608 sp2 = sp2->next->to;
7609 if ( sp2==ss->first )
7610 return( false );
7611 }
7612 }
7613
SSHasClip(SplineSet * ss)7614 int SSHasClip(SplineSet *ss) {
7615 while ( ss!=NULL ) {
7616 if ( ss->is_clip_path )
7617 return( true );
7618 ss = ss->next;
7619 }
7620 return( false );
7621 }
7622
SSHasDrawn(SplineSet * ss)7623 int SSHasDrawn(SplineSet *ss) {
7624 while ( ss!=NULL ) {
7625 if ( !ss->is_clip_path )
7626 return( true );
7627 ss = ss->next;
7628 }
7629 return( false );
7630 }
7631
SSBoundsWithin(SplineSet * ss,bigreal z1,bigreal z2,bigreal * wmin,bigreal * wmax,int major)7632 int SSBoundsWithin(SplineSet *ss,bigreal z1, bigreal z2, bigreal *wmin, bigreal *wmax, int major ) {
7633 /* if major==0 then find y values when x between z1, z2 */
7634 /* if major==1 then find x values when y between z1, z2 */
7635 bigreal w0= 1e23, w1= -1e23;
7636 int any=0;
7637 Spline *s, *first;
7638 Spline1D *ws, *zs;
7639 extended ts[3];
7640 bigreal w, z;
7641 int i;
7642 int other = !major;
7643
7644 if ( z1>z2 ) {
7645 bigreal temp = z1;
7646 z1 = z2;
7647 z2 = temp;
7648 }
7649
7650 while ( ss!=NULL ) {
7651 first = NULL;
7652 for ( s=ss->first->next; s!=first; s=s->to->next ) {
7653 if ( first==NULL ) first = s;
7654 ws = &s->splines[other];
7655 zs = &s->splines[major];
7656 if ( major ) {
7657 if ( s->from->me.y<z1 && s->from->nextcp.y<z1 && s->to->prevcp.y<z1 && s->to->me.y<z1 )
7658 continue;
7659 else if ( s->from->me.y>z2 && s->from->nextcp.y>z2 && s->to->prevcp.y>z2 && s->to->me.y>z2 )
7660 continue;
7661 } else {
7662 if ( s->from->me.x<z1 && s->from->nextcp.x<z1 && s->to->prevcp.x<z1 && s->to->me.x<z1 )
7663 continue;
7664 else if ( s->from->me.x>z2 && s->from->nextcp.x>z2 && s->to->prevcp.x>z2 && s->to->me.x>z2 )
7665 continue;
7666 }
7667 if ( CubicSolve(zs,z1,ts)) {
7668 for ( i=0; i<2 && ts[i]!=-1; ++i ) {
7669 w = ((ws->a*ts[i]+ws->b)*ts[i]+ws->c)*ts[i]+ws->d;
7670 if ( w<w0 ) w0=w;
7671 if ( w>w1 ) w1=w;
7672 any = true;
7673 }
7674 }
7675 if ( CubicSolve(zs,z2,ts)) {
7676 for ( i=0; i<2 && ts[i]!=-1; ++i ) {
7677 w = ((ws->a*ts[i]+ws->b)*ts[i]+ws->c)*ts[i]+ws->d;
7678 if ( w<w0 ) w0=w;
7679 if ( w>w1 ) w1=w;
7680 any = true;
7681 }
7682 }
7683 ts[0]=0; ts[1]=1.0;
7684 for ( i=0; i<2; ++i ) {
7685 w = ((ws->a*ts[i]+ws->b)*ts[i]+ws->c)*ts[i]+ws->d;
7686 z = ((zs->a*ts[i]+zs->b)*ts[i]+zs->c)*ts[i]+zs->d;
7687 if ( z>=z1 && z<=z2 ) {
7688 if ( w<w0 ) w0=w;
7689 if ( w>w1 ) w1=w;
7690 any = true;
7691 }
7692 }
7693 SplineFindExtrema(ws,&ts[0],&ts[1]);
7694 for ( i=0; i<2 && ts[i]!=-1; ++i ) {
7695 w = ((ws->a*ts[i]+ws->b)*ts[i]+ws->c)*ts[i]+ws->d;
7696 z = ((zs->a*ts[i]+zs->b)*ts[i]+zs->c)*ts[i]+zs->d;
7697 if ( z>=z1 && z<=z2 ) {
7698 if ( w<w0 ) w0=w;
7699 if ( w>w1 ) w1=w;
7700 any = true;
7701 }
7702 }
7703 }
7704 ss = ss->next;
7705 }
7706
7707 *wmin = w0; *wmax = w1;
7708 return( any );
7709 }
7710
FindZero5(bigreal w[7],bigreal tlow,bigreal thigh)7711 static bigreal FindZero5(bigreal w[7],bigreal tlow, bigreal thigh) {
7712 /* Somewhere between tlow and thigh there is a value of t where w(t)==0 */
7713 /* It is conceiveable that there might be 3 such ts if there are some high frequency effects */
7714 /* but I ignore that for now */
7715 bigreal t, test;
7716 int bot_negative;
7717
7718 t = tlow;
7719 test = ((((w[5]*t+w[4])*t+w[3])*t+w[2])*t+w[1])*t + w[0];
7720 bot_negative = test<0;
7721
7722 for (;;) {
7723 t = (thigh+tlow)/2;
7724 if ( thigh==t || tlow==t )
7725 return( t ); /* close as we can get */
7726 test = ((((w[5]*t+w[4])*t+w[3])*t+w[2])*t+w[1])*t + w[0];
7727 if ( test==0 )
7728 return( t );
7729 if ( bot_negative ) {
7730 if ( test<0 )
7731 tlow = t;
7732 else
7733 thigh = t;
7734 } else {
7735 if ( test<0 )
7736 thigh = t;
7737 else
7738 tlow = t;
7739 }
7740 }
7741 }
7742
FindZero3(bigreal w[7],bigreal tlow,bigreal thigh)7743 static bigreal FindZero3(bigreal w[7],bigreal tlow, bigreal thigh) {
7744 /* Somewhere between tlow and thigh there is a value of t where w(t)==0 */
7745 /* It is conceiveable that there might be 3 such ts if there are some high frequency effects */
7746 /* but I ignore that for now */
7747 bigreal t, test;
7748 int bot_negative;
7749
7750 t = tlow;
7751 test = ((w[3]*t+w[2])*t+w[1])*t + w[0];
7752 bot_negative = test<0;
7753
7754 for (;;) {
7755 t = (thigh+tlow)/2;
7756 if ( thigh==t || tlow==t )
7757 return( t ); /* close as we can get */
7758 test = ((w[3]*t+w[2])*t+w[1])*t + w[0];
7759 if ( test==0 )
7760 return( t );
7761 if ( bot_negative ) {
7762 if ( test<0 )
7763 tlow = t;
7764 else
7765 thigh = t;
7766 } else {
7767 if ( test<0 )
7768 thigh = t;
7769 else
7770 tlow = t;
7771 }
7772 }
7773 }
7774
SplineMinDistanceToPoint(Spline * s,BasePoint * p)7775 bigreal SplineMinDistanceToPoint(Spline *s, BasePoint *p) {
7776 /* So to find the minimum distance we want the sqrt( (sx(t)-px)^2 + (sy(t)-py)^2 ) */
7777 /* Same minima as (sx(t)-px)^2 + (sy(t)-py)^2, which is easier to deal with */
7778 bigreal w[7];
7779 Spline1D *x = &s->splines[0], *y = &s->splines[1];
7780 bigreal off[2], best;
7781
7782 off[0] = (x->d-p->x); off[1] = (y->d-p->y);
7783
7784 w[6] = (x->a*x->a) + (y->a*y->a);
7785 w[5] = 2*(x->a*x->b + y->a*y->b);
7786 w[4] = (x->b*x->b) + 2*(x->a*x->c) + (y->b*y->b) + 2*(y->a*y->c);
7787 w[3] = 2* (x->b*x->c + x->a*off[0] + y->b*y->c + y->a*off[1]);
7788 w[2] = (x->c*x->c) + 2*(x->b*off[0]) + (y->c*y->c) + 2*y->b*off[1];
7789 w[1] = 2*(x->c*off[0] + y->c*off[1]);
7790 w[0] = off[0]*off[0] + off[1]*off[1];
7791
7792 /* Take derivative */
7793 w[0] = w[1];
7794 w[1] = 2*w[2];
7795 w[2] = 3*w[3];
7796 w[3] = 4*w[4];
7797 w[4] = 5*w[5];
7798 w[5] = 6*w[6];
7799 w[6] = 0;
7800
7801 if ( w[5]!=0 ) {
7802 bigreal tzeros[8], t, incr, test, lasttest, zerot;
7803 int i, zcnt=0;
7804 /* Well, we've got a 5th degree poly and no way to play cute tricks. */
7805 /* brute force it */
7806 incr = 1.0/1024;
7807 lasttest = w[0];
7808 for ( t = incr; t<=1.0; t += incr ) {
7809 test = ((((w[5]*t+w[4])*t+w[3])*t+w[2])*t+w[1])*t + w[0];
7810 if ( test==0 )
7811 tzeros[zcnt++] = t;
7812 else {
7813 if ( lasttest!=0 && (test>0) != (lasttest>0) ) {
7814 zerot = FindZero5(w,t-incr,t);
7815 if ( zerot>0 )
7816 tzeros[zcnt++] = zerot;
7817 }
7818 }
7819 lasttest = test;
7820 }
7821 best = off[0]*off[0] + off[1]*off[1]; /* t==0 */
7822 test = (x->a+x->b+x->c+off[0])*(x->a+x->b+x->c+off[0]) +
7823 (y->a+y->b+y->c+off[1])*(y->a+y->b+y->c+off[1]); /* t==1 */
7824 if ( best>test ) best = test;
7825 for ( i=0; i<zcnt; ++i ) {
7826 bigreal tx, ty;
7827 tx = ((x->a*tzeros[i]+x->b)*tzeros[i]+x->c)*tzeros[i] + off[0];
7828 ty = ((y->a*tzeros[i]+y->b)*tzeros[i]+y->c)*tzeros[i] + off[1];
7829 test = tx*tx + ty*ty;
7830 if ( best>test ) best = test;
7831 }
7832 return( sqrt(best));
7833 } else if ( w[4]==0 && w[3]!=0 ) {
7834 /* Started with a quadratic -- now, find 0s of a cubic */
7835 /* We could find the extrema, so we have a bunch of monotonics */
7836 /* Or we could brute force it as above */
7837 bigreal tzeros[8], test, zerot;
7838 bigreal quad[3], disc, e[5], t1, t2;
7839 int i, zcnt=0, ecnt;
7840
7841 quad[2] = 3*w[3]; quad[1] = 2*w[2]; quad[0] = w[1];
7842 disc = (-quad[1]*quad[1] - 4*quad[2]*quad[0]);
7843 e[0] = 0;
7844 if ( disc<0 ) {
7845 e[1] = 1.0;
7846 ecnt = 2;
7847 } else
7848 disc = sqrt(disc);
7849 t1 = (-w[1] - disc) / (2*w[2]);
7850 t2 = (-w[1] + disc) / (2*w[2]);
7851 if ( t1>t2 ) {
7852 bigreal temp = t1;
7853 t1 = t2;
7854 t2 = temp;
7855 }
7856 ecnt=1;
7857 if ( t1>0 && t1<1 )
7858 e[ecnt++] = t1;
7859 if ( t2>0 && t2<1 && t1!=t2 )
7860 e[ecnt++] = t2;
7861 e[ecnt++] = 1.0;
7862 for ( i=1; i<ecnt; ++i ) {
7863 zerot = FindZero3(w,e[i-1],e[i]);
7864 if ( zerot>0 )
7865 tzeros[zcnt++] = zerot;
7866 }
7867 best = off[0]*off[0] + off[1]*off[1]; /* t==0 */
7868 test = (x->b+x->c+off[0])*(x->b+x->c+off[0]) +
7869 (y->b+y->c+off[1])*(y->b+y->c+off[1]); /* t==1 */
7870 if ( best>test ) best = test;
7871 for ( i=0; i<zcnt; ++i ) {
7872 bigreal tx, ty;
7873 tx = (x->b*tzeros[i]+x->c)*tzeros[i] + off[0];
7874 ty = (y->b*tzeros[i]+y->c)*tzeros[i] + off[1];
7875 test = tx*tx + ty*ty;
7876 if ( best>test ) best = test;
7877 }
7878 return( sqrt(best));
7879 } else if ( w[2]==0 && w[1]!=0 ) {
7880 /* Started with a line */
7881 bigreal t = -w[0]/w[1], test, best;
7882 best = off[0]*off[0] + off[1]*off[1]; /* t==0 */
7883 test = (x->c+off[0])*(x->c+off[0]) + (y->c+off[1])*(y->c+off[1]); /* t==1 */
7884 if ( best>test ) best = test;
7885 if ( t>0 && t<1 ) {
7886 test = (x->c*t+off[0])*(x->c*t+off[0]) + (y->c*t+off[1])*(y->c*t+off[1]);
7887 if ( best>test ) best = test;
7888 }
7889 return(sqrt(best));
7890 } else if ( w[4]!=0 && w[3]!=0 && w[2]!=0 && w[1]!=0 ) {
7891 IError( "Impossible condition in SplineMinDistanceToPoint");
7892 } else {
7893 /* It's a point, minimum distance is the only distance */
7894 return( sqrt(off[0]*off[0] + off[1]*off[1]) );
7895 }
7896 return( -1 );
7897 }
7898
GrowBuffer(GrowBuf * gb)7899 void GrowBuffer(GrowBuf *gb) {
7900 if ( gb->base==NULL ) {
7901 gb->base = gb->pt = malloc(200);
7902 gb->end = gb->base + 200;
7903 } else {
7904 int len = (gb->end-gb->base) + 400;
7905 int off = gb->pt-gb->base;
7906 gb->base = realloc(gb->base,len);
7907 gb->end = gb->base + len;
7908 gb->pt = gb->base+off;
7909 }
7910 }
7911
GrowBufferAdd(GrowBuf * gb,int ch)7912 void GrowBufferAdd(GrowBuf *gb,int ch) {
7913 if ( gb->base==NULL ) {
7914 gb->base = gb->pt = malloc(200);
7915 gb->end = gb->base + 200;
7916 } else if ( gb->pt>=gb->end ) {
7917 int len = (gb->end-gb->base) + 400;
7918 int off = gb->pt-gb->base;
7919 gb->base = realloc(gb->base,len);
7920 gb->end = gb->base + len;
7921 gb->pt = gb->base+off;
7922 }
7923 *gb->pt++ = ch;
7924 }
7925
GrowBufferAddStr(GrowBuf * gb,char * str)7926 void GrowBufferAddStr(GrowBuf *gb,char *str) {
7927 int n;
7928
7929 if ( str==NULL )
7930 return;
7931 n = strlen(str);
7932
7933 if ( gb->base==NULL ) {
7934 gb->base = gb->pt = malloc(200+n);
7935 gb->end = gb->base + 200+n;
7936 } else if ( gb->pt+n+1>=gb->end ) {
7937 int len = (gb->end-gb->base) + n+200;
7938 int off = gb->pt-gb->base;
7939 gb->base = realloc(gb->base,len);
7940 gb->end = gb->base + len;
7941 gb->pt = gb->base+off;
7942 }
7943 strcpy((char *)gb->pt, str);
7944 gb->pt += n;
7945 }
7946
DistanceBetweenPoints(BasePoint * p1,BasePoint * p2)7947 bigreal DistanceBetweenPoints( BasePoint *p1, BasePoint *p2 )
7948 {
7949 bigreal t = pow(p1->x - p2->x,2) + pow(p1->y - p2->y,2);
7950 if( !t )
7951 return t;
7952
7953 t = sqrt( t );
7954 return t;
7955 }
7956