1 /* Copyright (C) 2000-2008 by George Williams */
3 * Redistribution and use in source and binary forms, with or without
4 * modification, are permitted provided that the following conditions are met:
6 * Redistributions of source code must retain the above copyright notice, this
7 * list of conditions and the following disclaimer.
9 * Redistributions in binary form must reproduce the above copyright notice,
10 * this list of conditions and the following disclaimer in the documentation
11 * and/or other materials provided with the distribution.
13 * The name of the author may not be used to endorse or promote products
14 * derived from this software without specific prior written permission.
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
19 * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 #include "fontforgevw.h"
33 # include <ieeefp.h> /* Solaris defines isnan in ieeefp rather than math.h */
38 typedef struct quartic
{
42 /* In an attempt to make allocation more efficient I just keep preallocated */
43 /* lists of certain common sizes. It doesn't seem to make much difference */
44 /* when allocating stuff, but does when freeing. If the extra complexity */
45 /* is bad then put: */
46 /* #define chunkalloc(size) gcalloc(1,size) */
47 /* #define chunkfree(item,size) free(item) */
48 /* into splinefont.h after (or instead of) the definition of chunkalloc()*/
51 #define ALLOC_CHUNK 100 /* Number of small chunks to malloc at a time */
52 #if !defined(FONTFORGE_CONFIG_USE_LONGDOUBLE) && !defined(FONTFORGE_CONFIG_USE_DOUBLE)
53 # define CHUNK_MAX 100 /* Maximum size (in chunk units) that we are prepared to allocate */
54 /* The size of our data structures */
56 # define CHUNK_MAX 129
58 # define CHUNK_UNIT sizeof(void *) /* will vary with the word size of */
59 /* the machine. if pointers are 64 bits*/
60 /* we may need twice as much space as for 32 bits */
64 #define FLAG 0xbadcafe
68 static int chunkdebug
= 0; /* When this is set we never free anything, insuring that each chunk is unique */
72 struct chunk
{ struct chunk
*next
; };
73 struct chunk2
{ struct chunk2
*next
; int flag
; };
74 static struct chunk
*chunklists
[CHUNK_MAX
] = { 0 };
77 #if defined(FLAG) && ALLOC_CHUNK>1
78 void chunktest(void) {
82 for ( i
=2; i
<CHUNK_MAX
; ++i
)
83 for ( c
=(struct chunk2
*) chunklists
[i
]; c
!=NULL
; c
=c
->next
)
84 if ( c
->flag
!=FLAG
) {
85 fprintf( stderr
, "Chunk memory list has been corrupted\n" );
91 void *chunkalloc(int size
) {
93 return( gcalloc(1,size
));
98 if ( size
&(CHUNK_UNIT
-1) )
99 size
= (size
+CHUNK_UNIT
-1)&~(CHUNK_UNIT
-1);
101 if ( (size
&(CHUNK_UNIT
-1)) || size
>=(int)(CHUNK_MAX
*CHUNK_UNIT
) || size
<=(int)sizeof(struct chunk
)) {
102 fprintf( stderr
, "Attempt to allocate something of size %d\n", size
);
103 return( gcalloc(1,size
));
108 index
= (size
+CHUNK_UNIT
-1)/CHUNK_UNIT
;
109 if ( chunklists
[index
]==NULL
) {
111 pt
= galloc(ALLOC_CHUNK
*size
);
112 chunklists
[index
] = (struct chunk
*) pt
;
113 end
= pt
+(ALLOC_CHUNK
-1)*size
;
115 ((struct chunk
*) pt
)->next
= (struct chunk
*) (pt
+ size
);
117 ((struct chunk2
*) pt
)->flag
= FLAG
;
121 ((struct chunk
*) pt
)->next
= NULL
;
123 ((struct chunk2
*) pt
)->flag
= FLAG
;
126 item
= chunklists
[index
];
127 chunklists
[index
] = item
->next
;
128 memset(item
,'\0',size
);
133 void chunkfree(void *item
,int size
) {
134 int index
= (size
+CHUNK_UNIT
-1)/CHUNK_UNIT
;
145 if ( size
&(CHUNK_UNIT
-1) )
146 size
= (size
+CHUNK_UNIT
-1)&~(CHUNK_UNIT
-1);
148 if ( (size
&(CHUNK_UNIT
-1)) || size
>=(int)(CHUNK_MAX
*CHUNK_UNIT
) || size
<=(int)sizeof(struct chunk
)) {
149 fprintf( stderr
, "Attempt to free something of size %d\n", size
);
153 if ( (char *) (chunklists
[index
]) == (char *) item
||
154 ( ((char *) (chunklists
[index
]))<(char *) item
&&
155 ((char *) (chunklists
[index
]))+size
>(char *) item
) ||
156 ( ((char *) (chunklists
[index
]))>(char *) item
&&
157 ((char *) (chunklists
[index
]))<((char *) item
)+size
))
158 IError( "Memory mixup. Chunk list is wrong!!!" );
160 ((struct chunk
*) item
)->next
= chunklists
[index
];
162 if ( size
>=sizeof(struct chunk2
))
163 ((struct chunk2
*) item
)->flag
= FLAG
;
165 chunklists
[index
] = (struct chunk
*) item
;
174 char *strconcat(const char *str1
,const char *str2
) {
175 int len1
= strlen(str1
);
176 char *ret
= galloc(len1
+strlen(str2
)+1);
178 strcpy(ret
+len1
,str2
);
182 char *strconcat3(const char *str1
,const char *str2
, const char *str3
) {
183 int len1
= strlen(str1
), len2
= strlen(str2
);
184 char *ret
= galloc(len1
+len2
+strlen(str3
)+1);
186 strcpy(ret
+len1
,str2
);
187 strcpy(ret
+len1
+len2
,str3
);
191 void LineListFree(LineList
*ll
) {
196 chunkfree(ll
,sizeof(LineList
));
201 void LinearApproxFree(LinearApprox
*la
) {
206 LineListFree(la
->lines
);
207 chunkfree(la
,sizeof(LinearApprox
));
212 void SplineFree(Spline
*spline
) {
213 LinearApproxFree(spline
->approx
);
214 chunkfree(spline
,sizeof(Spline
));
217 SplinePoint
*SplinePointCreate(real x
, real y
) {
218 SplinePoint
*sp
= chunkalloc(sizeof(SplinePoint
));
219 sp
->me
.x
= x
; sp
->me
.y
= y
;
220 sp
->nextcp
= sp
->prevcp
= sp
->me
;
221 sp
->nonextcp
= sp
->noprevcp
= true;
222 sp
->nextcpdef
= sp
->prevcpdef
= false;
223 sp
->ttfindex
= sp
->nextcpindex
= 0xfffe;
227 Spline
*SplineMake3(SplinePoint
*from
, SplinePoint
*to
) {
228 Spline
*spline
= chunkalloc(sizeof(Spline
));
230 spline
->from
= from
; spline
->to
= to
;
231 from
->next
= to
->prev
= spline
;
232 SplineRefigure3(spline
);
236 void SplinePointFree(SplinePoint
*sp
) {
237 chunkfree(sp
->hintmask
,sizeof(HintMask
));
238 chunkfree(sp
,sizeof(SplinePoint
));
241 void SplinePointMDFree(SplineChar
*sc
, SplinePoint
*sp
) {
242 MinimumDistance
*md
, *prev
, *next
;
246 for ( md
= sc
->md
; md
!=NULL
; md
= next
) {
248 if ( md
->sp1
==sp
|| md
->sp2
==sp
) {
253 chunkfree(md
,sizeof(MinimumDistance
));
259 chunkfree(sp
->hintmask
,sizeof(HintMask
));
260 chunkfree(sp
,sizeof(SplinePoint
));
263 void SplinePointsFree(SplinePointList
*spl
) {
264 Spline
*first
, *spline
, *next
;
269 nonext
= spl
->first
->next
==NULL
;
270 if ( spl
->first
!=NULL
) {
272 for ( spline
= spl
->first
->next
; spline
!=NULL
&& spline
!=first
; spline
= next
) {
273 next
= spline
->to
->next
;
274 SplinePointFree(spline
->to
);
276 if ( first
==NULL
) first
= spline
;
278 if ( spl
->last
!=spl
->first
|| nonext
)
279 SplinePointFree(spl
->first
);
283 void SplineSetBeziersClear(SplinePointList
*spl
) {
284 Spline
*first
, *spline
, *next
;
289 if ( spl
->first
!=NULL
) {
290 nonext
= spl
->first
->next
==NULL
;
292 for ( spline
= spl
->first
->next
; spline
!=NULL
&& spline
!=first
; spline
= next
) {
293 next
= spline
->to
->next
;
294 SplinePointFree(spline
->to
);
296 if ( first
==NULL
) first
= spline
;
298 if ( spl
->last
!=spl
->first
|| nonext
)
299 SplinePointFree(spl
->first
);
301 spl
->first
= spl
->last
= NULL
;
304 void SplinePointListFree(SplinePointList
*spl
) {
305 Spline
*first
, *spline
, *next
;
310 if ( spl
->first
!=NULL
) {
311 nonext
= spl
->first
->next
==NULL
;
313 for ( spline
= spl
->first
->next
; spline
!=NULL
&& spline
!=first
; spline
= next
) {
314 next
= spline
->to
->next
;
315 SplinePointFree(spline
->to
);
317 if ( first
==NULL
) first
= spline
;
319 if ( spl
->last
!=spl
->first
|| nonext
)
320 SplinePointFree(spl
->first
);
322 free(spl
->contour_name
);
323 chunkfree(spl
,sizeof(SplinePointList
));
326 void SplinePointListMDFree(SplineChar
*sc
,SplinePointList
*spl
) {
327 Spline
*first
, *spline
, *next
;
332 if ( spl
->first
!=NULL
) {
334 freefirst
= ( spl
->last
!=spl
->first
|| spl
->first
->next
==NULL
);
335 for ( spline
= spl
->first
->next
; spline
!=NULL
&& spline
!=first
; spline
= next
) {
336 next
= spline
->to
->next
;
337 SplinePointMDFree(sc
,spline
->to
);
339 if ( first
==NULL
) first
= spline
;
342 SplinePointMDFree(sc
,spl
->first
);
344 free(spl
->contour_name
);
345 chunkfree(spl
,sizeof(SplinePointList
));
348 void SplinePointListsMDFree(SplineChar
*sc
,SplinePointList
*spl
) {
349 SplinePointList
*next
;
351 while ( spl
!=NULL
) {
353 SplinePointListMDFree(sc
,spl
);
358 void SplinePointListsFree(SplinePointList
*head
) {
359 SplinePointList
*spl
, *next
;
361 for ( spl
=head
; spl
!=NULL
; spl
=next
) {
363 SplinePointListFree(spl
);
367 void ImageListsFree(ImageList
*imgs
) {
370 while ( imgs
!=NULL
) {
372 chunkfree(imgs
,sizeof(ImageList
));
377 void RefCharFree(RefChar
*ref
) {
382 for ( i
=0; i
<ref
->layer_cnt
; ++i
) {
383 SplinePointListsFree(ref
->layers
[i
].splines
);
384 ImageListsFree(ref
->layers
[i
].images
);
387 chunkfree(ref
,sizeof(RefChar
));
390 RefChar
*RefCharCreate(void) {
391 RefChar
*ref
= chunkalloc(sizeof(RefChar
));
393 ref
->layers
= gcalloc(1,sizeof(struct reflayer
));
394 ref
->round_translation_to_grid
= true;
398 void RefCharsFree(RefChar
*ref
) {
401 while ( ref
!=NULL
) {
409 typedef struct spline1
{
415 static void FigureSpline1(Spline1
*sp1
,bigreal t0
, bigreal t1
, Spline1D
*sp
) {
417 if ( sp
->a
==0 && sp
->b
==0 ) {
418 sp1
->sp
.d
= sp
->d
+ t0
*sp
->c
;
420 sp1
->sp
.b
= sp1
->sp
.a
= 0;
422 sp1
->sp
.d
= sp
->d
+ t0
*(sp
->c
+ t0
*(sp
->b
+ t0
*sp
->a
));
423 sp1
->sp
.c
= s
*(sp
->c
+ t0
*(2*sp
->b
+ 3*sp
->a
*t0
));
424 sp1
->sp
.b
= s
*s
*(sp
->b
+3*sp
->a
*t0
);
425 sp1
->sp
.a
= s
*s
*s
*sp
->a
;
426 #if 0 /* Got invoked once on a perfectly good spline */
427 sp1
->s1
= sp1
->sp
.a
+sp1
->sp
.b
+sp1
->sp
.c
+sp1
->sp
.d
;
428 if ( ((sp1
->s1
>.001 || sp1
->s1
<-.001) && !RealNear((double) sp1
->sp
.a
+sp1
->sp
.b
+sp1
->sp
.c
+sp1
->sp
.d
,sp1
->s1
)) ||
429 !RealNear(sp1
->sp
.d
,sp1
->s0
))
430 IError( "Created spline does not work in FigureSpline1");
433 sp1
->c0
= sp1
->sp
.c
/3 + sp1
->sp
.d
;
434 sp1
->c1
= sp1
->c0
+ (sp1
->sp
.b
+sp1
->sp
.c
)/3;
438 static void SplineFindBounds(const Spline
*sp
, DBounds
*bounds
) {
439 real t
, b2_fourac
, v
;
444 /* first try the end points */
445 for ( i
=0; i
<2; ++i
) {
446 sp1
= &sp
->splines
[i
];
448 if ( sp
->to
->me
.x
<bounds
->minx
) bounds
->minx
= sp
->to
->me
.x
;
449 if ( sp
->to
->me
.x
>bounds
->maxx
) bounds
->maxx
= sp
->to
->me
.x
;
450 min
= bounds
->minx
; max
= bounds
->maxx
;
452 if ( sp
->to
->me
.y
<bounds
->miny
) bounds
->miny
= sp
->to
->me
.y
;
453 if ( sp
->to
->me
.y
>bounds
->maxy
) bounds
->maxy
= sp
->to
->me
.y
;
454 min
= bounds
->miny
; max
= bounds
->maxy
;
457 /* then try the extrema of the spline (assuming they are between t=(0,1) */
458 /* (I don't bother fixing up for tiny rounding errors here. they don't matter */
459 /* But we could call CheckExtremaForSingleBitErrors */
461 b2_fourac
= 4*sp1
->b
*sp1
->b
- 12*sp1
->a
*sp1
->c
;
462 if ( b2_fourac
>=0 ) {
463 b2_fourac
= sqrt(b2_fourac
);
464 t
= (-2*sp1
->b
+ b2_fourac
) / (6*sp1
->a
);
466 v
= ((sp1
->a
*t
+sp1
->b
)*t
+sp1
->c
)*t
+ sp1
->d
;
467 if ( v
<min
) min
= v
;
468 if ( v
>max
) max
= v
;
470 t
= (-2*sp1
->b
- b2_fourac
) / (6*sp1
->a
);
472 v
= ((sp1
->a
*t
+sp1
->b
)*t
+sp1
->c
)*t
+ sp1
->d
;
473 if ( v
<min
) min
= v
;
474 if ( v
>max
) max
= v
;
477 } else if ( sp1
->b
!=0 ) {
478 t
= -sp1
->c
/(2.0*sp1
->b
);
480 v
= (sp1
->b
*t
+sp1
->c
)*t
+ sp1
->d
;
481 if ( v
<min
) min
= v
;
482 if ( v
>max
) max
= v
;
486 bounds
->minx
= min
; bounds
->maxx
= max
;
488 bounds
->miny
= min
; bounds
->maxy
= max
;
493 static void _SplineSetFindBounds(const SplinePointList
*spl
, DBounds
*bounds
) {
494 Spline
*spline
, *first
;
495 /* Ignore contours consisting of a single point (used for hinting, anchors */
496 /* for mark to base, etc. */
498 for ( ; spl
!=NULL
; spl
= spl
->next
) if ( spl
->first
->next
!=NULL
&& spl
->first
->next
->to
!= spl
->first
) {
500 if ( bounds
->minx
==0 && bounds
->maxx
==0 && bounds
->miny
==0 && bounds
->maxy
== 0 ) {
501 bounds
->minx
= bounds
->maxx
= spl
->first
->me
.x
;
502 bounds
->miny
= bounds
->maxy
= spl
->first
->me
.y
;
504 if ( spl
->first
->me
.x
<bounds
->minx
) bounds
->minx
= spl
->first
->me
.x
;
505 if ( spl
->first
->me
.x
>bounds
->maxx
) bounds
->maxx
= spl
->first
->me
.x
;
506 if ( spl
->first
->me
.y
<bounds
->miny
) bounds
->miny
= spl
->first
->me
.y
;
507 if ( spl
->first
->me
.y
>bounds
->maxy
) bounds
->maxy
= spl
->first
->me
.y
;
509 for ( spline
= spl
->first
->next
; spline
!=NULL
&& spline
!=first
; spline
=spline
->to
->next
) {
510 SplineFindBounds(spline
,bounds
);
511 if ( first
==NULL
) first
= spline
;
517 void SplineSetFindBounds(const SplinePointList
*spl
, DBounds
*bounds
) {
518 memset(bounds
,'\0',sizeof(*bounds
));
519 _SplineSetFindBounds(spl
,bounds
);
522 static void _SplineCharLayerFindBounds(SplineChar
*sc
,int layer
, DBounds
*bounds
) {
525 for ( rf
=sc
->layers
[layer
].refs
; rf
!=NULL
; rf
= rf
->next
) {
526 if ( bounds
->minx
==0 && bounds
->maxx
==0 && bounds
->miny
==0 && bounds
->maxy
== 0 )
528 else if ( rf
->bb
.minx
!=0 || rf
->bb
.maxx
!= 0 || rf
->bb
.maxy
!= 0 || rf
->bb
.miny
!=0 ) {
529 if ( rf
->bb
.minx
< bounds
->minx
) bounds
->minx
= rf
->bb
.minx
;
530 if ( rf
->bb
.miny
< bounds
->miny
) bounds
->miny
= rf
->bb
.miny
;
531 if ( rf
->bb
.maxx
> bounds
->maxx
) bounds
->maxx
= rf
->bb
.maxx
;
532 if ( rf
->bb
.maxy
> bounds
->maxy
) bounds
->maxy
= rf
->bb
.maxy
;
535 _SplineSetFindBounds(sc
->layers
[layer
].splines
,bounds
);
537 if ( sc
->parent
!=NULL
&& sc
->parent
->strokedfont
&&
538 (bounds
->minx
!=bounds
->maxx
|| bounds
->miny
!=bounds
->maxy
)) {
539 real sw
= sc
->parent
->strokewidth
;
540 bounds
->minx
-= sw
; bounds
->miny
-= sw
;
541 bounds
->maxx
+= sw
; bounds
->maxy
+= sw
;
545 void SplineCharLayerFindBounds(SplineChar
*sc
,int layer
,DBounds
*bounds
) {
547 if ( sc
->parent
!=NULL
&& sc
->parent
->multilayer
) {
548 SplineCharFindBounds(sc
,bounds
);
552 /* a char with no splines (ie. a space) must have an lbearing of 0 */
553 bounds
->minx
= bounds
->maxx
= 0;
554 bounds
->miny
= bounds
->maxy
= 0;
556 _SplineCharLayerFindBounds(sc
,layer
,bounds
);
559 void SplineCharFindBounds(SplineChar
*sc
,DBounds
*bounds
) {
563 /* a char with no splines (ie. a space) must have an lbearing of 0 */
564 bounds
->minx
= bounds
->maxx
= 0;
565 bounds
->miny
= bounds
->maxy
= 0;
567 first
= last
= ly_fore
;
568 if ( sc
->parent
!=NULL
&& sc
->parent
->multilayer
)
569 last
= sc
->layer_cnt
-1;
570 for ( i
=first
; i
<=last
; ++i
)
571 _SplineCharLayerFindBounds(sc
,i
,bounds
);
574 void SplineFontLayerFindBounds(SplineFont
*sf
,int layer
,DBounds
*bounds
) {
575 int i
, k
, first
, last
;
577 if ( sf
->multilayer
) {
578 SplineFontFindBounds(sf
,bounds
);
582 bounds
->minx
= bounds
->maxx
= 0;
583 bounds
->miny
= bounds
->maxy
= 0;
585 for ( i
= 0; i
<sf
->glyphcnt
; ++i
) {
586 SplineChar
*sc
= sf
->glyphs
[i
];
588 first
= last
= ly_fore
;
589 if ( sc
->parent
!= NULL
&& sc
->parent
->multilayer
)
590 last
= sc
->layer_cnt
-1;
591 for ( k
=first
; k
<=last
; ++k
)
592 _SplineCharLayerFindBounds(sc
,k
,bounds
);
597 void SplineFontFindBounds(SplineFont
*sf
,DBounds
*bounds
) {
598 int i
, k
, first
, last
;
600 bounds
->minx
= bounds
->maxx
= 0;
601 bounds
->miny
= bounds
->maxy
= 0;
603 for ( i
= 0; i
<sf
->glyphcnt
; ++i
) {
604 SplineChar
*sc
= sf
->glyphs
[i
];
606 first
= last
= ly_fore
;
607 if ( sf
->multilayer
)
608 last
= sc
->layer_cnt
-1;
609 for ( k
=first
; k
<=last
; ++k
)
610 _SplineCharLayerFindBounds(sc
,k
,bounds
);
615 void CIDLayerFindBounds(SplineFont
*cidmaster
,int layer
,DBounds
*bounds
) {
621 if ( cidmaster
->cidmaster
)
622 cidmaster
= cidmaster
->cidmaster
;
623 if ( cidmaster
->subfonts
==NULL
) {
624 SplineFontLayerFindBounds(cidmaster
,layer
,bounds
);
628 sf
= cidmaster
->subfonts
[0];
629 SplineFontLayerFindBounds(sf
,layer
,bounds
);
630 factor
= 1000.0/(sf
->ascent
+sf
->descent
);
631 bounds
->maxx
*= factor
; bounds
->minx
*= factor
; bounds
->miny
*= factor
; bounds
->maxy
*= factor
;
632 for ( i
=1; i
<cidmaster
->subfontcnt
; ++i
) {
633 sf
= cidmaster
->subfonts
[i
];
634 SplineFontLayerFindBounds(sf
,layer
,&b
);
635 factor
= 1000.0/(sf
->ascent
+sf
->descent
);
636 b
.maxx
*= factor
; b
.minx
*= factor
; b
.miny
*= factor
; b
.maxy
*= factor
;
637 if ( b
.maxx
>bounds
->maxx
) bounds
->maxx
= b
.maxx
;
638 if ( b
.maxy
>bounds
->maxy
) bounds
->maxy
= b
.maxy
;
639 if ( b
.miny
<bounds
->miny
) bounds
->miny
= b
.miny
;
640 if ( b
.minx
<bounds
->minx
) bounds
->minx
= b
.minx
;
644 static void _SplineSetFindTop(SplineSet
*ss
,BasePoint
*top
) {
647 for ( ; ss
!=NULL
; ss
=ss
->next
) {
648 for ( sp
=ss
->first
; ; ) {
649 if ( sp
->me
.y
> top
->y
) *top
= sp
->me
;
650 if ( sp
->next
==NULL
)
659 static void SplineSetFindTop(SplineSet
*ss
,BasePoint
*top
) {
662 _SplineSetFindTop(ss
,top
);
663 if ( top
->y
< -65536 ) top
->y
= top
->x
= 0;
666 void SplineSetQuickBounds(SplineSet
*ss
,DBounds
*b
) {
669 b
->minx
= b
->miny
= 1e10
;
670 b
->maxx
= b
->maxy
= -1e10
;
671 for ( ; ss
!=NULL
; ss
=ss
->next
) {
672 for ( sp
=ss
->first
; ; ) {
673 if ( sp
->me
.y
< b
->miny
) b
->miny
= sp
->me
.y
;
674 if ( sp
->me
.x
< b
->minx
) b
->minx
= sp
->me
.x
;
675 if ( sp
->me
.y
> b
->maxy
) b
->maxy
= sp
->me
.y
;
676 if ( sp
->me
.x
> b
->maxx
) b
->maxx
= sp
->me
.x
;
677 if ( sp
->next
==NULL
)
684 if ( b
->minx
>65536 ) b
->minx
= 0;
685 if ( b
->miny
>65536 ) b
->miny
= 0;
686 if ( b
->maxx
<-65536 ) b
->maxx
= 0;
687 if ( b
->maxy
<-65536 ) b
->maxy
= 0;
690 void SplineCharQuickBounds(SplineChar
*sc
, DBounds
*b
) {
695 memset(b
,0,sizeof(*b
));
696 first
= last
= ly_fore
;
697 if ( sc
->parent
!=NULL
&& sc
->parent
->multilayer
)
698 last
= sc
->layer_cnt
-1;
699 for ( i
=first
; i
<=last
; ++i
) {
700 SplineSetQuickBounds(sc
->layers
[i
].splines
,&temp
);
701 if ( temp
.minx
!=0 || temp
.maxx
!= 0 || temp
.maxy
!= 0 || temp
.miny
!=0 ) {
702 if ( temp
.minx
< b
->minx
) b
->minx
= temp
.minx
;
703 if ( temp
.miny
< b
->miny
) b
->miny
= temp
.miny
;
704 if ( temp
.maxx
> b
->maxx
) b
->maxx
= temp
.maxx
;
705 if ( temp
.maxy
> b
->maxy
) b
->maxy
= temp
.maxy
;
707 for ( ref
= sc
->layers
[i
].refs
; ref
!=NULL
; ref
= ref
->next
) {
708 /*SplineSetQuickBounds(ref->layers[0].splines,&temp);*/
709 if ( b
->minx
==0 && b
->maxx
==0 && b
->miny
==0 && b
->maxy
== 0 )
711 else if ( ref
->bb
.minx
!=0 || ref
->bb
.maxx
!= 0 || ref
->bb
.maxy
!= 0 || ref
->bb
.miny
!=0 ) {
712 if ( ref
->bb
.minx
< b
->minx
) b
->minx
= ref
->bb
.minx
;
713 if ( ref
->bb
.miny
< b
->miny
) b
->miny
= ref
->bb
.miny
;
714 if ( ref
->bb
.maxx
> b
->maxx
) b
->maxx
= ref
->bb
.maxx
;
715 if ( ref
->bb
.maxy
> b
->maxy
) b
->maxy
= ref
->bb
.maxy
;
719 if ( sc
->parent
!=NULL
&& sc
->parent
->strokedfont
&&
720 (b
->minx
!=b
->maxx
|| b
->miny
!=b
->maxy
)) {
721 real sw
= sc
->parent
->strokewidth
;
722 b
->minx
-= sw
; b
->miny
-= sw
;
723 b
->maxx
+= sw
; b
->maxy
+= sw
;
727 void SplineSetQuickConservativeBounds(SplineSet
*ss
,DBounds
*b
) {
730 b
->minx
= b
->miny
= 1e10
;
731 b
->maxx
= b
->maxy
= -1e10
;
732 for ( ; ss
!=NULL
; ss
=ss
->next
) {
733 for ( sp
=ss
->first
; ; ) {
734 if ( sp
->me
.y
< b
->miny
) b
->miny
= sp
->me
.y
;
735 if ( sp
->me
.x
< b
->minx
) b
->minx
= sp
->me
.x
;
736 if ( sp
->me
.y
> b
->maxy
) b
->maxy
= sp
->me
.y
;
737 if ( sp
->me
.x
> b
->maxx
) b
->maxx
= sp
->me
.x
;
738 if ( sp
->nextcp
.y
< b
->miny
) b
->miny
= sp
->nextcp
.y
;
739 if ( sp
->nextcp
.x
< b
->minx
) b
->minx
= sp
->nextcp
.x
;
740 if ( sp
->nextcp
.y
> b
->maxy
) b
->maxy
= sp
->nextcp
.y
;
741 if ( sp
->nextcp
.x
> b
->maxx
) b
->maxx
= sp
->nextcp
.x
;
742 if ( sp
->prevcp
.y
< b
->miny
) b
->miny
= sp
->prevcp
.y
;
743 if ( sp
->prevcp
.x
< b
->minx
) b
->minx
= sp
->prevcp
.x
;
744 if ( sp
->prevcp
.y
> b
->maxy
) b
->maxy
= sp
->prevcp
.y
;
745 if ( sp
->prevcp
.x
> b
->maxx
) b
->maxx
= sp
->prevcp
.x
;
746 if ( sp
->next
==NULL
)
753 if ( b
->minx
>65536 ) b
->minx
= 0;
754 if ( b
->miny
>65536 ) b
->miny
= 0;
755 if ( b
->maxx
<-65536 ) b
->maxx
= 0;
756 if ( b
->maxy
<-65536 ) b
->maxy
= 0;
759 void SplineCharQuickConservativeBounds(SplineChar
*sc
, DBounds
*b
) {
764 memset(b
,0,sizeof(*b
));
765 first
= last
= ly_fore
;
766 if ( sc
->parent
!=NULL
&& sc
->parent
->multilayer
)
767 last
= sc
->layer_cnt
-1;
768 for ( i
=first
; i
<=last
; ++i
) {
769 SplineSetQuickConservativeBounds(sc
->layers
[i
].splines
,&temp
);
770 if ( temp
.minx
!=0 || temp
.maxx
!= 0 || temp
.maxy
!= 0 || temp
.miny
!=0 ) {
771 if ( temp
.minx
< b
->minx
) b
->minx
= temp
.minx
;
772 if ( temp
.miny
< b
->miny
) b
->miny
= temp
.miny
;
773 if ( temp
.maxx
> b
->maxx
) b
->maxx
= temp
.maxx
;
774 if ( temp
.maxy
> b
->maxy
) b
->maxy
= temp
.maxy
;
776 for ( ref
= sc
->layers
[i
].refs
; ref
!=NULL
; ref
= ref
->next
) {
777 /*SplineSetQuickConservativeBounds(ref->layers[0].splines,&temp);*/
778 if ( b
->minx
==0 && b
->maxx
==0 && b
->miny
==0 && b
->maxy
== 0 )
780 else if ( ref
->bb
.minx
!=0 || ref
->bb
.maxx
!= 0 || ref
->bb
.maxy
!= 0 || ref
->bb
.miny
!=0 ) {
781 if ( ref
->bb
.minx
< b
->minx
) b
->minx
= ref
->bb
.minx
;
782 if ( ref
->bb
.miny
< b
->miny
) b
->miny
= ref
->bb
.miny
;
783 if ( ref
->bb
.maxx
> b
->maxx
) b
->maxx
= ref
->bb
.maxx
;
784 if ( ref
->bb
.maxy
> b
->maxy
) b
->maxy
= ref
->bb
.maxy
;
788 if ( sc
->parent
->strokedfont
&& (b
->minx
!=b
->maxx
|| b
->miny
!=b
->maxy
)) {
789 real sw
= sc
->parent
->strokewidth
;
790 b
->minx
-= sw
; b
->miny
-= sw
;
791 b
->maxx
+= sw
; b
->maxy
+= sw
;
795 void SplineFontQuickConservativeBounds(SplineFont
*sf
,DBounds
*b
) {
799 b
->minx
= b
->miny
= 1e10
;
800 b
->maxx
= b
->maxy
= -1e10
;
801 for ( i
=0; i
<sf
->glyphcnt
; ++i
) if ( sf
->glyphs
[i
]!=NULL
) {
802 SplineCharQuickConservativeBounds(sf
->glyphs
[i
],&bb
);
803 if ( bb
.minx
< b
->minx
) b
->minx
= bb
.minx
;
804 if ( bb
.miny
< b
->miny
) b
->miny
= bb
.miny
;
805 if ( bb
.maxx
> b
->maxx
) b
->maxx
= bb
.maxx
;
806 if ( bb
.maxy
> b
->maxy
) b
->maxy
= bb
.maxy
;
808 if ( b
->minx
>65536 ) b
->minx
= 0;
809 if ( b
->miny
>65536 ) b
->miny
= 0;
810 if ( b
->maxx
<-65536 ) b
->maxx
= 0;
811 if ( b
->maxy
<-65536 ) b
->maxy
= 0;
814 void SplinePointCatagorize(SplinePoint
*sp
) {
815 int oldpointtype
= sp
->pointtype
;
817 sp
->pointtype
= pt_corner
;
818 if ( sp
->next
==NULL
&& sp
->prev
==NULL
)
820 else if ( (sp
->next
!=NULL
&& sp
->next
->to
->me
.x
==sp
->me
.x
&& sp
->next
->to
->me
.y
==sp
->me
.y
) ||
821 (sp
->prev
!=NULL
&& sp
->prev
->from
->me
.x
==sp
->me
.x
&& sp
->prev
->from
->me
.y
==sp
->me
.y
))
823 else if ( sp
->next
==NULL
) {
824 sp
->pointtype
= sp
->noprevcp
? pt_corner
: pt_curve
;
825 } else if ( sp
->prev
==NULL
) {
826 sp
->pointtype
= sp
->nonextcp
? pt_corner
: pt_curve
;
827 } else if ( sp
->nonextcp
&& sp
->noprevcp
) {
830 BasePoint ndir
, ncdir
, ncunit
, pdir
, pcdir
, pcunit
;
831 double nlen
, nclen
, plen
, pclen
;
834 ncdir
.x
= sp
->nextcp
.x
- sp
->me
.x
; ncdir
.y
= sp
->nextcp
.y
- sp
->me
.y
;
835 pcdir
.x
= sp
->prevcp
.x
- sp
->me
.x
; pcdir
.y
= sp
->prevcp
.y
- sp
->me
.y
;
836 ndir
.x
= ndir
.y
= pdir
.x
= pdir
.y
= 0;
837 if ( sp
->next
!=NULL
) {
838 ndir
.x
= sp
->next
->to
->me
.x
- sp
->me
.x
; ndir
.y
= sp
->next
->to
->me
.y
- sp
->me
.y
;
840 if ( sp
->prev
!=NULL
) {
841 pdir
.x
= sp
->prev
->from
->me
.x
- sp
->me
.x
; pdir
.y
= sp
->prev
->from
->me
.y
- sp
->me
.y
;
843 nclen
= sqrt(ncdir
.x
*ncdir
.x
+ ncdir
.y
*ncdir
.y
);
844 pclen
= sqrt(pcdir
.x
*pcdir
.x
+ pcdir
.y
*pcdir
.y
);
845 nlen
= sqrt(ndir
.x
*ndir
.x
+ ndir
.y
*ndir
.y
);
846 plen
= sqrt(pdir
.x
*pdir
.x
+ pdir
.y
*pdir
.y
);
847 ncunit
= ncdir
; pcunit
= pcdir
;
848 if ( nclen
!=0 ) { ncunit
.x
/= nclen
; ncunit
.y
/= nclen
; }
849 if ( pclen
!=0 ) { pcunit
.x
/= pclen
; pcunit
.y
/= pclen
; }
850 if ( nlen
!=0 ) { ndir
.x
/= nlen
; ndir
.y
/= nlen
; }
851 if ( plen
!=0 ) { pdir
.x
/= plen
; pdir
.y
/= plen
; }
853 /* find out which side has the shorter control vector. Dot that vector */
854 /* with the normal of the unit vector on the other side. If the */
855 /* result is less than 1 em-unit then we've got colinear control points */
856 /* (within the resolution of the integer grid) */
857 if ( nclen
!=0 && pclen
!=0 &&
858 ((nclen
>=pclen
&& (dot
= pcdir
.x
*ncunit
.y
- pcdir
.y
*ncunit
.x
)<1.0 && dot
>-1.0 ) ||
859 (pclen
>nclen
&& (dot
= ncdir
.x
*pcunit
.y
- ncdir
.y
*pcunit
.x
)<1.0 && dot
>-1.0 )))
860 sp
->pointtype
= pt_curve
;
861 /* Dot product of control point with unit vector normal to line in */
862 /* opposite direction should be less than an em-unit for a tangent */
863 else if (( nclen
==0 && pclen
!=0 && (dot
= pcdir
.x
*ndir
.y
-pcdir
.y
*ndir
.x
)<1.0 && dot
>-1.0 ) ||
864 ( pclen
==0 && nclen
!=0 && (dot
= ncdir
.x
*pdir
.y
-ncdir
.y
*pdir
.x
)<1.0 && dot
>-1.0 ))
865 sp
->pointtype
= pt_tangent
;
867 /* If a point started out hv, and could still be hv, them make it so */
868 /* but don't make hv points de novo, Alexey doesn't like change */
869 /* (this only works because hv isn't a default setting, so if it's */
870 /* there it was done intentionally) */
871 if ( sp
->pointtype
== pt_curve
&& oldpointtype
== pt_hvcurve
&&
872 ((sp
->nextcp
.x
==sp
->me
.x
&& sp
->prevcp
.x
==sp
->me
.x
&& sp
->nextcp
.y
!=sp
->me
.y
) ||
873 (sp
->nextcp
.y
==sp
->me
.y
&& sp
->prevcp
.y
==sp
->me
.y
&& sp
->nextcp
.x
!=sp
->me
.x
)))
874 sp
->pointtype
= pt_hvcurve
;
878 int SplinePointIsACorner(SplinePoint
*sp
) {
879 enum pointtype old
= sp
->pointtype
, new;
881 SplinePointCatagorize(sp
);
884 return( new==pt_corner
);
887 void SPLCatagorizePoints(SplinePointList
*spl
) {
888 Spline
*spline
, *first
, *last
=NULL
;
890 for ( ; spl
!=NULL
; spl
= spl
->next
) {
892 for ( spline
= spl
->first
->next
; spline
!=NULL
&& spline
!=first
; spline
=spline
->to
->next
) {
893 SplinePointCatagorize(spline
->from
);
895 if ( first
==NULL
) first
= spline
;
897 if ( spline
==NULL
&& last
!=NULL
)
898 SplinePointCatagorize(last
->to
);
902 void SCCatagorizePoints(SplineChar
*sc
) {
903 SPLCatagorizePoints(sc
->layers
[ly_fore
].splines
);
906 static int CharsNotInEncoding(FontDict
*fd
) {
909 for ( i
=cnt
=0; i
<fd
->chars
->cnt
; ++i
) {
910 if ( fd
->chars
->keys
[i
]!=NULL
) {
911 for ( j
=0; j
<256; ++j
)
912 if ( fd
->encoding
[j
]!=NULL
&&
913 strcmp(fd
->encoding
[j
],fd
->chars
->keys
[i
])==0 )
919 /* And for type 3 fonts... */
920 if ( fd
->charprocs
!=NULL
) for ( i
=0; i
<fd
->charprocs
->cnt
; ++i
) {
921 if ( fd
->charprocs
->keys
[i
]!=NULL
) {
922 for ( j
=0; j
<256; ++j
)
923 if ( fd
->encoding
[j
]!=NULL
&&
924 strcmp(fd
->encoding
[j
],fd
->charprocs
->keys
[i
])==0 )
933 static int LookupCharString(char *encname
,struct pschars
*chars
) {
936 if ( encname
==NULL
) encname
= ".notdef"; /* In case of an incomplete encoding array */
938 for ( k
=0; k
<chars
->cnt
; ++k
) {
939 if ( chars
->keys
[k
]!=NULL
)
940 if ( strcmp(encname
,chars
->keys
[k
])==0 )
946 SplinePointList
*SplinePointListCopy1(const SplinePointList
*spl
) {
947 SplinePointList
*cur
;
948 const SplinePoint
*pt
; SplinePoint
*cpt
;
951 cur
= chunkalloc(sizeof(SplinePointList
));
952 cur
->is_clip_path
= spl
->is_clip_path
;
954 for ( pt
=spl
->first
; ; ) {
955 cpt
= chunkalloc(sizeof(SplinePoint
));
957 if ( pt
->hintmask
!=NULL
) {
958 cpt
->hintmask
= chunkalloc(sizeof(HintMask
));
959 memcpy(cpt
->hintmask
,pt
->hintmask
,sizeof(HintMask
));
961 cpt
->next
= cpt
->prev
= NULL
;
962 if ( cur
->first
==NULL
)
963 cur
->first
= cur
->last
= cpt
;
965 spline
= chunkalloc(sizeof(Spline
));
967 spline
->from
= cur
->last
;
968 cur
->last
->next
= spline
;
971 spline
->approx
= NULL
;
974 if ( pt
->next
==NULL
)
977 if ( pt
==spl
->first
)
980 if ( spl
->first
->prev
!=NULL
) {
982 spline
= chunkalloc(sizeof(Spline
));
984 spline
->from
= cur
->last
;
985 cur
->last
->next
= spline
;
988 spline
->approx
= NULL
;
994 /* If this routine is called we are guarenteed that:
995 at least one point on the splineset is selected
996 not all points on the splineset are selected
998 static SplinePointList
*SplinePointListCopySelected1(SplinePointList
*spl
) {
999 SplinePointList
*head
=NULL
, *last
=NULL
, *cur
;
1000 SplinePoint
*cpt
, *first
, *start
;
1004 if ( spl
->first
==spl
->last
) {
1005 /* If it's a closed contour and the start point is selected then we */
1006 /* don't know where that selection began (and we have to keep it with */
1007 /* the things that precede it when we make the new splinesets), so */
1008 /* loop until we find something unselected */
1009 while ( start
->selected
)
1010 start
= start
->next
->to
;
1013 while ( start
!= NULL
&& start
!=first
) {
1014 while ( start
!=NULL
&& start
!=first
&& !start
->selected
) {
1015 if ( first
==NULL
) first
= start
;
1016 if ( start
->next
==NULL
) {
1020 start
= start
->next
->to
;
1022 if ( start
==NULL
|| start
==first
)
1024 cur
= chunkalloc(sizeof(SplinePointList
));
1031 while ( start
!=NULL
&& start
->selected
&& start
!=first
) {
1032 cpt
= chunkalloc(sizeof(SplinePoint
));
1034 cpt
->hintmask
= NULL
;
1035 cpt
->next
= cpt
->prev
= NULL
;
1036 if ( cur
->first
==NULL
)
1037 cur
->first
= cur
->last
= cpt
;
1039 spline
= chunkalloc(sizeof(Spline
));
1040 *spline
= *start
->prev
;
1041 spline
->from
= cur
->last
;
1042 cur
->last
->next
= spline
;
1045 spline
->approx
= NULL
;
1048 if ( first
==NULL
) first
= start
;
1049 if ( start
->next
==NULL
) {
1053 start
= start
->next
->to
;
1060 SplinePointList
*SplinePointListCopy(const SplinePointList
*base
) {
1061 SplinePointList
*head
=NULL
, *last
=NULL
, *cur
;
1063 for ( ; base
!=NULL
; base
= base
->next
) {
1064 cur
= SplinePointListCopy1(base
);
1074 SplinePointList
*SplinePointListCopySelected(SplinePointList
*base
) {
1075 SplinePointList
*head
=NULL
, *last
=NULL
, *cur
=NULL
;
1076 SplinePoint
*pt
, *first
;
1079 for ( ; base
!=NULL
; base
= base
->next
) {
1080 anysel
= false; allsel
= true;
1082 for ( pt
=base
->first
; pt
!=NULL
&& pt
!=first
; pt
= pt
->next
->to
) {
1083 if ( pt
->selected
) anysel
= true;
1084 else allsel
= false;
1085 if ( first
==NULL
) first
= pt
;
1086 if ( pt
->next
==NULL
)
1090 cur
= SplinePointListCopy1(base
);
1092 cur
= SplinePointListCopySelected1(base
);
1098 for ( last
= cur
; last
->next
; last
= last
->next
);
1106 static SplinePointList
*SplinePointListSplit(SplineChar
*sc
,SplinePointList
*spl
) {
1107 SplinePointList
*head
=NULL
, *last
=NULL
, *cur
;
1108 SplinePoint
*first
, *start
, *next
;
1111 if ( spl
->first
==spl
->last
) {
1112 /* If it's a closed contour and the start point is selected then we */
1113 /* don't know where that selection began (and we have to keep it with */
1114 /* the things that precede it when we make the new splinesets), so */
1115 /* loop until we find something unselected */
1116 while ( !start
->selected
)
1117 start
= start
->next
->to
;
1120 while ( start
!= NULL
&& start
!=first
) {
1121 while ( start
!=NULL
&& start
!=first
&& start
->selected
) {
1122 if ( first
==NULL
) first
= start
;
1123 if ( start
->prev
!=NULL
) {
1124 start
->prev
->from
->next
= NULL
;
1125 SplineFree(start
->prev
);
1127 if ( start
->next
!=NULL
) {
1128 next
= start
->next
->to
;
1130 SplineFree(start
->next
);
1133 SplinePointMDFree(sc
,start
);
1136 if ( start
==NULL
|| start
==first
)
1140 spl
->first
= spl
->last
= NULL
;
1142 cur
= chunkalloc(sizeof(SplinePointList
));
1147 while ( start
!=NULL
&& !start
->selected
&& start
!=first
) {
1148 if ( cur
->first
==NULL
)
1151 if ( start
->next
!=NULL
) {
1152 next
= start
->next
->to
;
1153 if ( next
->selected
) {
1154 SplineFree(start
->next
);
1160 if ( first
==NULL
) first
= start
;
1167 SplinePointList
*SplinePointListRemoveSelected(SplineChar
*sc
,SplinePointList
*base
) {
1168 SplinePointList
*head
=NULL
, *last
=NULL
, *next
;
1169 SplinePoint
*pt
, *first
;
1172 for ( ; base
!=NULL
; base
= next
) {
1174 anysel
= false; allsel
= true;
1176 for ( pt
=base
->first
; pt
!=NULL
&& pt
!=first
; pt
= pt
->next
->to
) {
1177 if ( pt
->selected
) anysel
= true;
1178 else allsel
= false;
1179 if ( first
==NULL
) first
= pt
;
1180 if ( pt
->next
==NULL
)
1184 SplinePointListMDFree(sc
,base
);
1194 last
= SplinePointListSplit(sc
,base
);
1197 if ( last
!=NULL
) last
->next
= NULL
;
1201 ImageList
*ImageListCopy(ImageList
*cimg
) {
1202 ImageList
*head
=NULL
, *last
=NULL
, *new;
1204 for ( ; cimg
!=NULL
; cimg
=cimg
->next
) {
1205 new = chunkalloc(sizeof(ImageList
));
1219 void ApTransform(AnchorPoint
*ap
, real transform
[6]) {
1221 p
.x
= transform
[0]*ap
->me
.x
+ transform
[2]*ap
->me
.y
+ transform
[4];
1222 p
.y
= transform
[1]*ap
->me
.x
+ transform
[3]*ap
->me
.y
+ transform
[5];
1223 ap
->me
.x
= rint(1024*p
.x
)/1024;
1224 ap
->me
.y
= rint(1024*p
.y
)/1024;
1227 static void TransformPoint(SplinePoint
*sp
, real transform
[6]) {
1229 p
.x
= transform
[0]*sp
->me
.x
+ transform
[2]*sp
->me
.y
+ transform
[4];
1230 p
.y
= transform
[1]*sp
->me
.x
+ transform
[3]*sp
->me
.y
+ transform
[5];
1231 p
.x
= rint(1024*p
.x
)/1024;
1232 p
.y
= rint(1024*p
.y
)/1024;
1234 if ( !sp
->nonextcp
) {
1235 p
.x
= transform
[0]*sp
->nextcp
.x
+ transform
[2]*sp
->nextcp
.y
+ transform
[4];
1236 p
.y
= transform
[1]*sp
->nextcp
.x
+ transform
[3]*sp
->nextcp
.y
+ transform
[5];
1237 p
.x
= rint(1024*p
.x
)/1024;
1238 p
.y
= rint(1024*p
.y
)/1024;
1241 sp
->nextcp
= sp
->me
;
1242 if ( !sp
->noprevcp
) {
1243 p
.x
= transform
[0]*sp
->prevcp
.x
+ transform
[2]*sp
->prevcp
.y
+ transform
[4];
1244 p
.y
= transform
[1]*sp
->prevcp
.x
+ transform
[3]*sp
->prevcp
.y
+ transform
[5];
1245 p
.x
= rint(1024*p
.x
)/1024;
1246 p
.y
= rint(1024*p
.y
)/1024;
1249 sp
->prevcp
= sp
->me
;
1250 if ( sp
->pointtype
== pt_hvcurve
) {
1252 ((sp
->nextcp
.x
==sp
->me
.x
&& sp
->prevcp
.x
==sp
->me
.x
&& sp
->nextcp
.y
!=sp
->me
.y
) ||
1253 (sp
->nextcp
.y
==sp
->me
.y
&& sp
->prevcp
.y
==sp
->me
.y
&& sp
->nextcp
.x
!=sp
->me
.x
)))
1256 sp
->pointtype
= pt_curve
;
1260 SplinePointList
*SplinePointListTransform(SplinePointList
*base
, real transform
[6], int allpoints
) {
1261 Spline
*spline
, *first
;
1262 SplinePointList
*spl
;
1263 SplinePoint
*spt
, *pfirst
;
1264 int allsel
, anysel
, alldone
=true;
1266 for ( spl
= base
; spl
!=NULL
; spl
= spl
->next
) {
1268 allsel
= true; anysel
=false;
1269 for ( spt
= spl
->first
; spt
!=pfirst
; spt
= spt
->next
->to
) {
1270 if ( pfirst
==NULL
) pfirst
= spt
;
1271 if ( allpoints
|| spt
->selected
) {
1272 TransformPoint(spt
,transform
);
1274 if ( spt
->next
!=NULL
&& spt
->next
->order2
&& !spt
->next
->to
->selected
&& spt
->next
->to
->ttfindex
==0xffff ) {
1275 SplinePoint
*to
= spt
->next
->to
;
1276 to
->prevcp
= spt
->nextcp
;
1277 to
->me
.x
= (to
->prevcp
.x
+to
->nextcp
.x
)/2;
1278 to
->me
.y
= (to
->prevcp
.y
+to
->nextcp
.y
)/2;
1280 if ( spt
->prev
!=NULL
&& spt
->prev
->order2
&& !spt
->prev
->from
->selected
&& spt
->prev
->from
->ttfindex
==0xffff ) {
1281 SplinePoint
*from
= spt
->prev
->from
;
1282 from
->nextcp
= spt
->prevcp
;
1283 from
->me
.x
= (from
->prevcp
.x
+from
->nextcp
.x
)/2;
1284 from
->me
.y
= (from
->prevcp
.y
+from
->nextcp
.y
)/2;
1289 allsel
= alldone
= false;
1290 if ( spt
->next
==NULL
)
1293 if ( !anysel
) /* This splineset had no selected points it's unchanged */
1296 /* if we changed all the points then the control points are right */
1297 /* otherwise those near the edges may be wonky, fix 'em up */
1298 /* Figuring out where the edges of the selection are is difficult */
1299 /* so let's just tweak all points, it shouldn't matter */
1300 /* It does matter. Let's tweak all default points */
1301 if ( !allpoints
&& !allsel
&& spl
->first
->next
!=NULL
&& !spl
->first
->next
->order2
) {
1303 for ( spt
= spl
->first
; spt
!=pfirst
; spt
= spt
->next
->to
) {
1304 if ( pfirst
==NULL
) pfirst
= spt
;
1305 if ( spt
->selected
&& spt
->prev
!=NULL
&& !spt
->prev
->from
->selected
&&
1306 spt
->prev
->from
->pointtype
== pt_tangent
)
1307 SplineCharTangentPrevCP(spt
->prev
->from
);
1308 if ( spt
->selected
&& spt
->next
!=NULL
&& !spt
->next
->to
->selected
&&
1309 spt
->next
->to
->pointtype
== pt_tangent
)
1310 SplineCharTangentNextCP(spt
->next
->to
);
1311 if ( spt
->prev
!=NULL
&& spt
->prevcpdef
)
1312 SplineCharDefaultPrevCP(spt
);
1313 if ( spt
->next
==NULL
)
1315 if ( spt
->nextcpdef
)
1316 SplineCharDefaultNextCP(spt
);
1320 for ( spline
= spl
->first
->next
; spline
!=NULL
&& spline
!=first
; spline
=spline
->to
->next
) {
1321 if ( !alldone
) SplineRefigureFixup(spline
); else SplineRefigure(spline
);
1322 if ( first
==NULL
) first
= spline
;
1329 SplinePointList
*SplinePointListShift(SplinePointList
*base
,real xoff
,int allpoints
) {
1333 transform
[0] = transform
[3] = 1;
1334 transform
[1] = transform
[2] = transform
[5] = 0;
1335 transform
[4] = xoff
;
1336 return( SplinePointListTransform(base
,transform
,allpoints
));
1339 HintMask
*HintMaskFromTransformedRef(RefChar
*ref
,BasePoint
*trans
,
1340 SplineChar
*basesc
,HintMask
*hm
) {
1346 if ( ref
->transform
[1]!=0 || ref
->transform
[2]!=0 )
1349 memset(hm
,0,sizeof(HintMask
));
1350 for ( st
= ref
->sc
->hstem
; st
!=NULL
; st
=st
->next
) {
1351 start
= st
->start
*ref
->transform
[3] + ref
->transform
[5] + trans
->y
;
1352 width
= st
->width
*ref
->transform
[3];
1353 for ( st2
=basesc
->hstem
,bcnt
=0; st2
!=NULL
; st2
=st2
->next
, bcnt
++ )
1354 if ( st2
->start
== start
&& st2
->width
== width
)
1357 (*hm
)[bcnt
>>3] |= (0x80>>(bcnt
&7));
1359 for ( st2
=basesc
->hstem
,hst_cnt
=0; st2
!=NULL
; st2
=st2
->next
, hst_cnt
++ );
1361 for ( st
= ref
->sc
->vstem
; st
!=NULL
; st
=st
->next
) {
1362 start
= st
->start
*ref
->transform
[0] + ref
->transform
[4] + trans
->x
;
1363 width
= st
->width
*ref
->transform
[0];
1364 for ( st2
=basesc
->vstem
,bcnt
=hst_cnt
; st2
!=NULL
; st2
=st2
->next
, bcnt
++ )
1365 if ( st2
->start
== start
&& st2
->width
== width
)
1368 (*hm
)[bcnt
>>3] |= (0x80>>(bcnt
&7));
1370 for ( i
=0; i
<HntMax
/8; ++i
)
1377 static HintMask
*HintMaskTransform(HintMask
*oldhm
,real transform
[6],
1378 SplineChar
*basesc
,SplineChar
*subsc
) {
1381 int cnt
, hst_cnt
, bcnt
;
1384 if ( transform
[1]!=0 || transform
[2]!=0 )
1387 newhm
= chunkalloc(sizeof(HintMask
));
1388 for ( st
= subsc
->hstem
,cnt
= 0; st
!=NULL
; st
=st
->next
, cnt
++ ) {
1389 if ( (*oldhm
)[cnt
>>3]&(0x80>>(cnt
&7)) ) {
1390 start
= st
->start
*transform
[3] + transform
[5];
1391 width
= st
->width
*transform
[3];
1392 for ( st2
=basesc
->hstem
,bcnt
=0; st2
!=NULL
; st2
=st2
->next
, bcnt
++ )
1393 if ( st2
->start
== start
&& st2
->width
== width
)
1396 (*newhm
)[bcnt
>>3] |= (0x80>>(bcnt
&7));
1399 for ( st2
=basesc
->hstem
,hst_cnt
=0; st2
!=NULL
; st2
=st2
->next
, hst_cnt
++ );
1401 for ( st
= subsc
->vstem
; st
!=NULL
; st
=st
->next
, cnt
++ ) {
1402 if ( (*oldhm
)[cnt
>>3]&(0x80>>(cnt
&7)) ) {
1403 start
= st
->start
*transform
[0] + transform
[4];
1404 width
= st
->width
*transform
[0];
1405 for ( st2
=basesc
->vstem
,bcnt
=hst_cnt
; st2
!=NULL
; st2
=st2
->next
, bcnt
++ )
1406 if ( st2
->start
== start
&& st2
->width
== width
)
1409 (*newhm
)[bcnt
>>3] |= (0x80>>(bcnt
&7));
1415 SplinePointList
*SPLCopyTranslatedHintMasks(SplinePointList
*base
,
1416 SplineChar
*basesc
, SplineChar
*subsc
, BasePoint
*trans
) {
1417 SplinePointList
*spl
, *spl2
, *head
;
1418 SplinePoint
*spt
, *spt2
, *pfirst
;
1422 head
= SplinePointListCopy(base
);
1424 transform
[0] = transform
[3] = 1; transform
[1] = transform
[2] = 0;
1425 transform
[4] = trans
->x
; transform
[5] = trans
->y
;
1427 for ( spl
= head
, spl2
=base
; spl
!=NULL
; spl
= spl
->next
, spl2
= spl2
->next
) {
1429 for ( spt
= spl
->first
, spt2
= spl2
->first
; spt
!=pfirst
; spt
= spt
->next
->to
, spt2
= spt2
->next
->to
) {
1430 if ( pfirst
==NULL
) pfirst
= spt
;
1431 TransformPoint(spt
,transform
);
1432 if ( spt2
->hintmask
) {
1433 chunkfree(spt
->hintmask
,sizeof(HintMask
));
1434 spt
->hintmask
= HintMaskTransform(spt2
->hintmask
,transform
,basesc
,subsc
);
1436 if ( spt
->next
==NULL
)
1440 for ( s
= spl
->first
->next
; s
!=NULL
&& s
!=first
; s
=s
->to
->next
) {
1442 if ( first
==NULL
) first
= s
;
1448 static SplinePointList
*_SPLCopyTransformedHintMasks(SplineChar
*subsc
,int layer
,
1449 real transform
[6], SplineChar
*basesc
) {
1450 SplinePointList
*spl
, *spl2
, *head
, *last
=NULL
, *cur
, *base
;
1451 SplinePoint
*spt
, *spt2
, *pfirst
;
1456 base
= subsc
->layers
[layer
].splines
;
1457 head
= SplinePointListCopy(base
);
1459 for ( last
= head
; last
->next
!=NULL
; last
=last
->next
);
1461 for ( spl
= head
, spl2
=base
; spl
!=NULL
; spl
= spl
->next
, spl2
=spl2
->next
) {
1463 for ( spt
= spl
->first
, spt2
= spl2
->first
; spt
!=pfirst
; spt
= spt
->next
->to
, spt2
= spt2
->next
->to
) {
1464 if ( pfirst
==NULL
) pfirst
= spt
;
1465 TransformPoint(spt
,transform
);
1466 if ( spt2
->hintmask
) {
1467 chunkfree(spt
->hintmask
,sizeof(HintMask
));
1468 spt
->hintmask
= HintMaskTransform(spt2
->hintmask
,transform
,basesc
,subsc
);
1470 if ( spt
->next
==NULL
)
1474 for ( s
= spl
->first
->next
; s
!=NULL
&& s
!=first
; s
=s
->to
->next
) {
1476 if ( first
==NULL
) first
= s
;
1479 for ( rf
=subsc
->layers
[layer
].refs
; rf
!=NULL
; rf
=rf
->next
) {
1480 trans
[0] = rf
->transform
[0]*transform
[0] +
1481 rf
->transform
[1]*transform
[2];
1482 trans
[1] = rf
->transform
[0]*transform
[1] +
1483 rf
->transform
[1]*transform
[3];
1484 trans
[2] = rf
->transform
[2]*transform
[0] +
1485 rf
->transform
[3]*transform
[2];
1486 trans
[3] = rf
->transform
[2]*transform
[1] +
1487 rf
->transform
[3]*transform
[3];
1488 trans
[4] = rf
->transform
[4]*transform
[0] +
1489 rf
->transform
[5]*transform
[2] +
1491 trans
[5] = rf
->transform
[4]*transform
[1] +
1492 rf
->transform
[5]*transform
[3] +
1494 cur
= _SPLCopyTransformedHintMasks(rf
->sc
,layer
,trans
,basesc
);
1500 while ( cur
->next
!=NULL
) cur
= cur
->next
;
1507 SplinePointList
*SPLCopyTransformedHintMasks(RefChar
*r
,
1508 SplineChar
*basesc
, BasePoint
*trans
,int layer
) {
1511 memcpy(transform
,r
->transform
,sizeof(transform
));
1512 transform
[4] += trans
->x
; transform
[5] += trans
->y
;
1513 return( _SPLCopyTransformedHintMasks(r
->sc
,layer
,transform
,basesc
));
1516 void SplinePointListSelect(SplinePointList
*spl
,int sel
) {
1517 Spline
*spline
, *first
;
1519 for ( ; spl
!=NULL
; spl
= spl
->next
) {
1521 spl
->first
->selected
= sel
;
1522 for ( spline
= spl
->first
->next
; spline
!=NULL
&& spline
!=first
; spline
=spline
->to
->next
) {
1523 spline
->to
->selected
= sel
;
1524 if ( first
==NULL
) first
= spline
;
1529 void SCMakeDependent(SplineChar
*dependent
,SplineChar
*base
) {
1530 struct splinecharlist
*dlist
;
1532 if ( dependent
->searcherdummy
)
1535 for ( dlist
=base
->dependents
; dlist
!=NULL
&& dlist
->sc
!=dependent
; dlist
= dlist
->next
);
1536 if ( dlist
==NULL
) {
1537 dlist
= chunkalloc(sizeof(struct splinecharlist
));
1538 dlist
->sc
= dependent
;
1539 dlist
->next
= base
->dependents
;
1540 base
->dependents
= dlist
;
1544 static void InstanciateReference(SplineFont
*sf
, RefChar
*topref
, RefChar
*refs
,
1545 real transform
[6], SplineChar
*dsc
, int layer
) {
1549 SplinePointList
*spl
, *new;
1552 if ( !refs
->checked
) {
1553 if ( refs
->sc
!=NULL
)
1554 i
= refs
->sc
->orig_pos
; /* Can happen in type3 fonts */
1555 else for ( i
=0; i
<sf
->glyphcnt
; ++i
) if ( sf
->glyphs
[i
]!=NULL
)
1556 if ( strcmp(sf
->glyphs
[i
]->name
,AdobeStandardEncoding
[refs
->adobe_enc
])==0 )
1558 if ( i
!=sf
->glyphcnt
&& !sf
->glyphs
[i
]->ticked
) {
1559 refs
->checked
= true;
1560 refs
->sc
= rsc
= sf
->glyphs
[i
];
1561 refs
->orig_pos
= rsc
->orig_pos
;
1562 refs
->unicode_enc
= rsc
->unicodeenc
;
1563 SCMakeDependent(dsc
,rsc
);
1565 LogError( _("Couldn't find referenced character \"%s\" in %s\n"),
1566 AdobeStandardEncoding
[refs
->adobe_enc
], dsc
->name
);
1569 } else if ( refs
->sc
->ticked
)
1575 for ( rf
=rsc
->layers
[ly_fore
].refs
; rf
!=NULL
; rf
= rf
->next
) {
1576 trans
[0] = rf
->transform
[0]*transform
[0] +
1577 rf
->transform
[1]*transform
[2];
1578 trans
[1] = rf
->transform
[0]*transform
[1] +
1579 rf
->transform
[1]*transform
[3];
1580 trans
[2] = rf
->transform
[2]*transform
[0] +
1581 rf
->transform
[3]*transform
[2];
1582 trans
[3] = rf
->transform
[2]*transform
[1] +
1583 rf
->transform
[3]*transform
[3];
1584 trans
[4] = rf
->transform
[4]*transform
[0] +
1585 rf
->transform
[5]*transform
[2] +
1587 trans
[5] = rf
->transform
[4]*transform
[1] +
1588 rf
->transform
[5]*transform
[3] +
1590 InstanciateReference(sf
,topref
,rf
,trans
,rsc
,layer
);
1592 rsc
->ticked
= false;
1595 new = SplinePointListTransform(SplinePointListCopy(rsc
->layers
[layer
].splines
),transform
,true);
1597 for ( spl
= new; spl
->next
!=NULL
; spl
= spl
->next
);
1598 spl
->next
= topref
->layers
[0].splines
;
1599 topref
->layers
[0].splines
= new;
1604 static char *copyparse(char *str
) {
1611 rpt
=ret
=galloc(strlen(str
)+1);
1615 if ( *str
=='n' ) ch
= '\n';
1616 else if ( *str
=='r' ) ch
= '\r';
1617 else if ( *str
=='t' ) ch
= '\t';
1618 else if ( *str
=='b' ) ch
= '\b';
1619 else if ( *str
=='f' ) ch
= '\f';
1620 else if ( *str
=='\\' ) ch
= '\\';
1621 else if ( *str
=='(' ) ch
= '(';
1622 else if ( *str
==')' ) ch
= ')';
1623 else if ( *str
>='0' && *str
<='7' ) {
1624 for ( i
=ch
= 0; i
<3 && *str
>='0' && *str
<='7'; ++i
)
1625 ch
= (ch
<<3) + *str
++-'0';
1635 if ( !utf8_valid(ret
)) {
1636 /* Assume latin1, convert to utf8 */
1637 rpt
= latin1_2_utf8_copy(ret
);
1644 char *XUIDFromFD(int xuid
[20]) {
1648 for ( i
=19; i
>=0 && xuid
[i
]==0; --i
);
1651 ret
= galloc(2+20*(i
+1));
1654 for ( j
=0; j
<=i
; ++j
) {
1655 sprintf(pt
,"%d ", xuid
[j
]);
1663 static void SplineFontMetaData(SplineFont
*sf
,struct fontdict
*fd
) {
1666 sf
->fontname
= utf8_verify_copy(fd
->cidfontname
?fd
->cidfontname
:fd
->fontname
);
1667 sf
->display_size
= -default_fv_font_size
;
1668 sf
->display_antialias
= default_fv_antialias
;
1669 if ( fd
->fontinfo
!=NULL
) {
1670 if ( sf
->fontname
==NULL
&& fd
->fontinfo
->fullname
!=NULL
) {
1671 sf
->fontname
= EnforcePostScriptName(fd
->fontinfo
->fullname
);
1673 if ( sf
->fontname
==NULL
) sf
->fontname
= EnforcePostScriptName(fd
->fontinfo
->familyname
);
1674 sf
->fullname
= copyparse(fd
->fontinfo
->fullname
);
1675 sf
->familyname
= copyparse(fd
->fontinfo
->familyname
);
1676 sf
->weight
= copyparse(fd
->fontinfo
->weight
);
1677 sf
->version
= copyparse(fd
->fontinfo
->version
);
1678 sf
->copyright
= copyparse(fd
->fontinfo
->notice
);
1679 sf
->italicangle
= fd
->fontinfo
->italicangle
;
1680 sf
->upos
= fd
->fontinfo
->underlineposition
;
1681 sf
->uwidth
= fd
->fontinfo
->underlinethickness
;
1682 sf
->strokedfont
= fd
->painttype
==2;
1683 sf
->strokewidth
= fd
->strokewidth
;
1684 sf
->ascent
= fd
->fontinfo
->ascent
;
1685 sf
->descent
= fd
->fontinfo
->descent
;
1687 if ( sf
->uniqueid
==0 ) sf
->uniqueid
= fd
->uniqueid
;
1688 if ( sf
->fontname
==NULL
) sf
->fontname
= GetNextUntitledName();
1689 if ( sf
->fullname
==NULL
) sf
->fullname
= copy(sf
->fontname
);
1690 if ( sf
->familyname
==NULL
) sf
->familyname
= copy(sf
->fontname
);
1691 if ( sf
->weight
==NULL
) sf
->weight
= copy("");
1692 if ( fd
->modificationtime
!=0 ) {
1693 sf
->modificationtime
= fd
->modificationtime
;
1694 sf
->creationtime
= fd
->creationtime
;
1696 sf
->cidversion
= fd
->cidversion
;
1697 sf
->xuid
= XUIDFromFD(fd
->xuid
);
1698 /*sf->wasbinary = fd->wasbinary;*/
1699 if ( fd
->fontmatrix
[0]==0 )
1702 em
= rint(1/fd
->fontmatrix
[0]);
1703 if ( sf
->ascent
==0 && sf
->descent
!=0 )
1704 sf
->ascent
= em
-sf
->descent
;
1705 else if ( fd
->fontbb
[3]-fd
->fontbb
[1]==em
) {
1706 if ( sf
->ascent
==0 ) sf
->ascent
= fd
->fontbb
[3];
1707 if ( sf
->descent
==0 ) sf
->descent
= fd
->fontbb
[1];
1708 } else if ( sf
->ascent
==0 )
1709 sf
->ascent
= 8*em
/10;
1710 sf
->descent
= em
-sf
->ascent
;
1712 sf
->private = fd
->private->private; fd
->private->private = NULL
;
1713 PSDictRemoveEntry(sf
->private, "OtherSubrs");
1715 sf
->cidregistry
= copy(fd
->registry
);
1716 sf
->ordering
= copy(fd
->ordering
);
1717 sf
->supplement
= fd
->supplement
;
1718 sf
->pfminfo
.fstype
= fd
->fontinfo
->fstype
;
1719 if ( sf
->ordering
!=NULL
) {
1720 if ( strnmatch(sf
->ordering
,"Japan",5)==0 )
1721 sf
->uni_interp
= ui_japanese
;
1722 else if ( strnmatch(sf
->ordering
,"Korea",5)==0 )
1723 sf
->uni_interp
= ui_korean
;
1724 else if ( strnmatch(sf
->ordering
,"CNS",3)==0 )
1725 sf
->uni_interp
= ui_trad_chinese
;
1726 else if ( strnmatch(sf
->ordering
,"GB",2)==0 )
1727 sf
->uni_interp
= ui_simp_chinese
;
1731 static void TransByFontMatrix(SplineFont
*sf
,real fontmatrix
[6]) {
1733 int em
= sf
->ascent
+sf
->descent
, i
;
1737 if ( fontmatrix
[0]==fontmatrix
[3] &&
1738 fontmatrix
[1]==0 && fontmatrix
[2]==0 &&
1739 fontmatrix
[4]==0 && fontmatrix
[5]==0 )
1740 return; /* It's just the expected matrix */
1743 if ( fontmatrix
[0]==fontmatrix
[3] ) trans
[3] = 1;
1744 else trans
[3] = rint(fontmatrix
[3]*em
);
1745 trans
[1] = fontmatrix
[1]*em
;
1746 trans
[2] = fontmatrix
[2]*em
;
1747 trans
[4] = rint(fontmatrix
[4]*em
);
1748 trans
[5] = rint(fontmatrix
[5]*em
);
1750 for ( i
=0; i
<sf
->glyphcnt
; ++i
) if ( (sc
=sf
->glyphs
[i
])!=NULL
) {
1751 SplinePointListTransform(sc
->layers
[ly_fore
].splines
,trans
,true);
1752 for ( refs
=sc
->layers
[ly_fore
].refs
; refs
!=NULL
; refs
=refs
->next
) {
1753 /* Just scale the offsets. we'll do all the base characters */
1754 real temp
= refs
->transform
[4]*trans
[0] +
1755 refs
->transform
[5]*trans
[2] +
1757 refs
->transform
[5] = refs
->transform
[4]*trans
[1] +
1758 refs
->transform
[5]*trans
[3] +
1760 refs
->transform
[4] = temp
;
1762 sc
->changedsincelasthinted
= true;
1763 sc
->manualhints
= false;
1765 for ( i
=0; i
<sf
->glyphcnt
; ++i
) if ( (sc
=sf
->glyphs
[i
])!=NULL
) {
1766 for ( refs
=sc
->layers
[ly_fore
].refs
; refs
!=NULL
; refs
=refs
->next
)
1767 SCReinstanciateRefChar(sc
,refs
,ly_fore
);
1771 void SFInstanciateRefs(SplineFont
*sf
) {
1773 RefChar
*refs
, *next
, *pr
;
1775 for ( i
=0; i
<sf
->glyphcnt
; ++i
) if ( sf
->glyphs
[i
]!=NULL
)
1776 sf
->glyphs
[i
]->ticked
= false;
1778 for ( i
=0; i
<sf
->glyphcnt
; ++i
) if ( sf
->glyphs
[i
]!=NULL
) {
1779 SplineChar
*sc
= sf
->glyphs
[i
];
1781 for ( layer
=ly_back
; layer
<sc
->layer_cnt
; ++layer
) {
1782 for ( pr
=NULL
, refs
= sc
->layers
[layer
].refs
; refs
!=NULL
; refs
=next
) {
1785 InstanciateReference(sf
, refs
, refs
, refs
->transform
,sc
,layer
);
1786 if ( refs
->sc
!=NULL
) {
1787 SplineSetFindBounds(refs
->layers
[0].splines
,&refs
->bb
);
1791 /* In some mal-formed postscript fonts we can have a reference */
1792 /* to a character that is not actually in the font. I even */
1793 /* generated one by mistake once... */
1795 sc
->layers
[layer
].refs
= next
;
1806 /* Also handles type3s */
1807 static void _SplineFontFromType1(SplineFont
*sf
, FontDict
*fd
, struct pscontext
*pscontext
) {
1808 int i
, j
, notdefpos
;
1809 RefChar
*refs
, *next
;
1810 int istype2
= fd
->fonttype
==2; /* Easy enough to deal with even though it will never happen... */
1811 int istype3
= fd
->charprocs
->next
!=0;
1815 fd
->private->subrs
->bias
= fd
->private->subrs
->cnt
<1240 ? 107 :
1816 fd
->private->subrs
->cnt
<33900 ? 1131 : 32768;
1817 sf
->glyphmax
= sf
->glyphcnt
= istype3
? fd
->charprocs
->next
: fd
->chars
->next
;
1818 if ( sf
->map
==NULL
) {
1819 sf
->map
= map
= EncMapNew(256+CharsNotInEncoding(fd
),sf
->glyphcnt
,fd
->encoding_name
);
1822 sf
->glyphs
= gcalloc(map
->backmax
,sizeof(SplineChar
*));
1824 notdefpos
= LookupCharString(".notdef",(struct pschars
*) (fd
->charprocs
));
1826 notdefpos
= LookupCharString(".notdef",fd
->chars
);
1827 for ( i
=0; i
<256; ++i
) {
1830 k
= LookupCharString(fd
->encoding
[i
],(struct pschars
*) (fd
->charprocs
));
1832 k
= LookupCharString(fd
->encoding
[i
],fd
->chars
);
1834 if ( k
==-1 ) k
= notdefpos
;
1836 if ( k
!=-1 && map
->backmap
[k
]==-1 )
1837 map
->backmap
[k
] = i
;
1839 if ( map
->enccount
>256 ) {
1841 for ( k
=0; k
<fd
->chars
->cnt
; ++k
) {
1842 if ( fd
->chars
->keys
[k
]!=NULL
) {
1843 for ( j
=0; j
<256; ++j
)
1844 if ( fd
->encoding
[j
]!=NULL
&&
1845 strcmp(fd
->encoding
[j
],fd
->chars
->keys
[k
])==0 )
1849 if ( map
->backmap
[k
]==-1 )
1850 map
->backmap
[k
] = i
;
1855 /* And for type3s */
1856 for ( k
=0; k
<fd
->charprocs
->cnt
; ++k
) {
1857 if ( fd
->charprocs
->keys
[k
]!=NULL
) {
1858 for ( j
=0; j
<256; ++j
)
1859 if ( fd
->encoding
[j
]!=NULL
&&
1860 strcmp(fd
->encoding
[j
],fd
->charprocs
->keys
[k
])==0 )
1864 if ( map
->backmap
[k
]==-1 )
1865 map
->backmap
[k
] = i
;
1871 for ( i
=0; i
<map
->enccount
; ++i
) if ( map
->map
[i
]==-1 )
1872 map
->map
[i
] = notdefpos
;
1874 for ( i
=0; i
<sf
->glyphcnt
; ++i
) {
1876 sf
->glyphs
[i
] = PSCharStringToSplines(fd
->chars
->values
[i
],fd
->chars
->lens
[i
],
1877 pscontext
,fd
->private->subrs
,NULL
,fd
->chars
->keys
[i
]);
1879 sf
->glyphs
[i
] = fd
->charprocs
->values
[i
];
1880 if ( sf
->glyphs
[i
]!=NULL
) {
1881 sf
->glyphs
[i
]->orig_pos
= i
;
1882 sf
->glyphs
[i
]->vwidth
= sf
->ascent
+sf
->descent
;
1883 sf
->glyphs
[i
]->unicodeenc
= UniFromName(sf
->glyphs
[i
]->name
,sf
->uni_interp
,map
->enc
);
1884 sf
->glyphs
[i
]->parent
= sf
;
1885 /* SCLigDefault(sf->glyphs[i]);*/ /* Also reads from AFM file, but it probably doesn't exist */
1889 SFInstanciateRefs(sf
);
1890 if ( fd
->metrics
!=NULL
) {
1891 for ( i
=0; i
<fd
->metrics
->next
; ++i
) {
1892 int width
= strtol(fd
->metrics
->values
[i
],NULL
,10);
1893 for ( j
=sf
->glyphcnt
-1; j
>=0; --j
) {
1894 if ( sf
->glyphs
[j
]!=NULL
&& sf
->glyphs
[j
]->name
!=NULL
&&
1895 strcmp(fd
->metrics
->keys
[i
],sf
->glyphs
[j
]->name
)==0 ) {
1896 sf
->glyphs
[j
]->width
= width
;
1902 for ( i
=0; i
<sf
->glyphcnt
; ++i
) if ( sf
->glyphs
[i
]!=NULL
)
1903 for ( refs
= sf
->glyphs
[i
]->layers
[ly_fore
].refs
; refs
!=NULL
; refs
=next
) {
1905 if ( refs
->adobe_enc
==' ' && refs
->layers
[0].splines
==NULL
) {
1906 /* When I have a link to a single character I will save out a */
1907 /* seac to that character and a space (since I can only make */
1908 /* real char links), so if we find a space link, get rid of*/
1909 /* it. It's an artifact */
1910 SCRefToSplines(sf
->glyphs
[i
],refs
,ly_fore
);
1913 /* sometimes (some apple oblique fonts) the fontmatrix is not just a */
1914 /* formality, it acutally contains a skew. So be ready */
1915 if ( fd
->fontmatrix
[0]!=0 )
1916 TransByFontMatrix(sf
,fd
->fontmatrix
);
1919 static void SplineFontFromType1(SplineFont
*sf
, FontDict
*fd
, struct pscontext
*pscontext
) {
1923 _SplineFontFromType1(sf
,fd
,pscontext
);
1925 /* Clean up the hint masks, We create an initial hintmask whether we need */
1927 for ( i
=0; i
<sf
->glyphcnt
; ++i
) {
1928 if ( (sc
= sf
->glyphs
[i
])!=NULL
&& !sc
->hconflicts
&& !sc
->vconflicts
&&
1929 sc
->layers
[ly_fore
].splines
!=NULL
) {
1930 chunkfree( sc
->layers
[ly_fore
].splines
->first
->hintmask
,sizeof(HintMask
) );
1931 sc
->layers
[ly_fore
].splines
->first
->hintmask
= NULL
;
1936 static SplineFont
*SplineFontFromMMType1(SplineFont
*sf
, FontDict
*fd
, struct pscontext
*pscontext
) {
1937 char *pt
, *end
, *origweight
;
1939 int ipos
, apos
, ppos
, item
, i
;
1940 real blends
[12]; /* At most twelve points/axis in a blenddesignmap */
1944 if ( fd
->weightvector
==NULL
|| fd
->fontinfo
->blenddesignpositions
==NULL
||
1945 fd
->fontinfo
->blenddesignmap
==NULL
|| fd
->fontinfo
->blendaxistypes
==NULL
) {
1946 ff_post_error(_("Bad Multiple Master Font"),_("Bad Multiple Master Font"));
1951 mm
= chunkalloc(sizeof(MMSet
));
1953 pt
= fd
->weightvector
;
1954 while ( *pt
==' ' || *pt
=='[' ) ++pt
;
1955 while ( *pt
!=']' && *pt
!='\0' ) {
1956 pscontext
->blend_values
[ pscontext
->instance_count
] =
1960 ++(pscontext
->instance_count
);
1961 if ( pscontext
->instance_count
>=(int)(sizeof(pscontext
->blend_values
)/sizeof(pscontext
->blend_values
[0]))) {
1962 LogError( _("Multiple master font with more than 16 instances\n") );
1965 for ( pt
= end
; *pt
==' '; ++pt
);
1968 mm
->instance_count
= pscontext
->instance_count
;
1969 mm
->instances
= galloc(pscontext
->instance_count
*sizeof(SplineFont
*));
1970 mm
->defweights
= galloc(mm
->instance_count
*sizeof(real
));
1971 memcpy(mm
->defweights
,pscontext
->blend_values
,mm
->instance_count
*sizeof(real
));
1973 _SplineFontFromType1(mm
->normal
,fd
,pscontext
);
1975 for ( i
=0; i
<sf
->glyphcnt
; ++i
) if ( sf
->glyphs
[i
]!=NULL
)
1976 sf
->glyphs
[i
]->blended
= true;
1979 pt
= fd
->fontinfo
->blendaxistypes
;
1980 while ( *pt
==' ' || *pt
=='[' ) ++pt
;
1981 while ( *pt
!=']' && *pt
!='\0' ) {
1982 if ( *pt
=='/' ) ++pt
;
1983 for ( end
=pt
; *end
!=' ' && *end
!=']' && *end
!='\0'; ++end
);
1986 if ( mm
->axis_count
>=(int)(sizeof(mm
->axes
)/sizeof(mm
->axes
[0]))) {
1987 LogError( _("Multiple master font with more than 4 axes\n") );
1990 mm
->axes
[ mm
->axis_count
++ ] = copyn( pt
,end
-pt
);
1991 for ( pt
= end
; *pt
==' '; ++pt
);
1994 if ( mm
->instance_count
< (1<<mm
->axis_count
) )
1995 ff_post_error(_("Bad Multiple Master Font"),_("This multiple master font has %1$d instance fonts, but it needs at least %2$d master fonts for %3$d axes. FontForge will not be able to edit this correctly"),mm
->instance_count
,1<<mm
->axis_count
,mm
->axis_count
);
1996 else if ( mm
->instance_count
> (1<<mm
->axis_count
) )
1997 ff_post_error(_("Bad Multiple Master Font"),_("This multiple master font has %1$d instance fonts, but FontForge can only handle %2$d master fonts for %3$d axes. FontForge will not be able to edit this correctly"),mm
->instance_count
,1<<mm
->axis_count
,mm
->axis_count
);
1998 mm
->positions
= gcalloc(mm
->axis_count
*mm
->instance_count
,sizeof(real
));
1999 pt
= fd
->fontinfo
->blenddesignpositions
;
2000 while ( *pt
==' ' ) ++pt
;
2001 if ( *pt
=='[' ) ++pt
;
2003 while ( *pt
!=']' && *pt
!='\0' ) {
2004 while ( *pt
==' ' ) ++pt
;
2005 if ( *pt
==']' || *pt
=='\0' )
2007 if ( ipos
>=mm
->instance_count
)
2012 while ( *pt
!=']' && *pt
!='\0' ) {
2013 if ( apos
>=mm
->axis_count
) {
2014 LogError( _("Too many axis positions specified in /BlendDesignPositions.\n") );
2017 mm
->positions
[ipos
*mm
->axis_count
+apos
] =
2022 for ( pt
= end
; *pt
==' '; ++pt
);
2024 if ( *pt
==']' ) ++pt
;
2030 mm
->axismaps
= gcalloc(mm
->axis_count
,sizeof(struct axismap
));
2031 pt
= fd
->fontinfo
->blenddesignmap
;
2032 while ( *pt
==' ' ) ++pt
;
2033 if ( *pt
=='[' ) ++pt
;
2035 while ( *pt
!=']' && *pt
!='\0' ) {
2036 while ( *pt
==' ' ) ++pt
;
2037 if ( *pt
==']' || *pt
=='\0' )
2039 if ( apos
>=mm
->axis_count
)
2044 while ( *pt
!=']' && *pt
!='\0' ) {
2046 LogError( _("Too many mapping data points specified in /BlendDesignMap for axis %s.\n"), mm
->axes
[apos
] );
2049 while ( *pt
==' ' ) ++pt
;
2052 designs
[ppos
] = strtod(pt
,&end
);
2053 blends
[ppos
] = strtod(end
,&end
);
2054 if ( blends
[ppos
]<0 || blends
[ppos
]>1 ) {
2055 LogError( _("Bad value for blend in /BlendDesignMap for axis %s.\n"), mm
->axes
[apos
] );
2056 if ( blends
[ppos
]<0 ) blends
[ppos
] = 0;
2057 if ( blends
[ppos
]>1 ) blends
[ppos
] = 1;
2060 while ( *pt
!=']' && *pt
!='\0' ) ++pt
;
2064 while ( *pt
==' ' ) ++pt
;
2066 if ( *pt
==']' ) ++pt
;
2068 LogError( _("Bad few values in /BlendDesignMap for axis %s.\n"), mm
->axes
[apos
] );
2069 mm
->axismaps
[apos
].points
= ppos
;
2070 mm
->axismaps
[apos
].blends
= galloc(ppos
*sizeof(real
));
2071 mm
->axismaps
[apos
].designs
= galloc(ppos
*sizeof(real
));
2072 memcpy(mm
->axismaps
[apos
].blends
,blends
,ppos
*sizeof(real
));
2073 memcpy(mm
->axismaps
[apos
].designs
,designs
,ppos
*sizeof(real
));
2079 mm
->cdv
= copy(fd
->cdv
);
2080 mm
->ndv
= copy(fd
->ndv
);
2082 origweight
= fd
->fontinfo
->weight
;
2084 /* Now figure out the master designs, being careful to interpolate */
2085 /* BlueValues, ForceBold, UnderlinePosition etc. We need to copy private */
2086 /* generate a font name */
2087 for ( ipos
= 0; ipos
<mm
->instance_count
; ++ipos
) {
2089 free(fd
->fontinfo
->fullname
);
2090 fd
->fontname
= MMMakeMasterFontname(mm
,ipos
,&fd
->fontinfo
->fullname
);
2091 fd
->fontinfo
->weight
= MMGuessWeight(mm
,ipos
,copy(origweight
));
2092 if ( fd
->blendfontinfo
!=NULL
) {
2093 for ( item
=0; item
<3; ++item
) {
2094 static char *names
[] = { "ItalicAngle", "UnderlinePosition", "UnderlineThickness" };
2095 pt
= PSDictHasEntry(fd
->blendfontinfo
,names
[item
]);
2097 pt
= MMExtractNth(pt
,ipos
);
2099 double val
= strtod(pt
,NULL
);
2102 case 0: fd
->fontinfo
->italicangle
= val
; break;
2103 case 1: fd
->fontinfo
->underlineposition
= val
; break;
2104 case 2: fd
->fontinfo
->underlinethickness
= val
; break;
2110 fd
->private->private = PSDictCopy(sf
->private);
2111 if ( fd
->blendprivate
!=NULL
) {
2112 static char *arrnames
[] = { "BlueValues", "OtherBlues", "FamilyBlues", "FamilyOtherBlues", "StdHW", "StdVW", "StemSnapH", "StemSnapV", NULL
};
2113 static char *scalarnames
[] = { "ForceBold", "BlueFuzz", "BlueScale", "BlueShift", NULL
};
2114 for ( item
=0; scalarnames
[item
]!=NULL
; ++item
) {
2115 pt
= PSDictHasEntry(fd
->blendprivate
,scalarnames
[item
]);
2117 pt
= MMExtractNth(pt
,ipos
);
2118 PSDictChangeEntry(fd
->private->private,scalarnames
[item
],pt
);
2122 for ( item
=0; arrnames
[item
]!=NULL
; ++item
) {
2123 pt
= PSDictHasEntry(fd
->blendprivate
,arrnames
[item
]);
2125 pt
= MMExtractArrayNth(pt
,ipos
);
2126 PSDictChangeEntry(fd
->private->private,arrnames
[item
],pt
);
2131 for ( item
=0; item
<mm
->instance_count
; ++item
)
2132 pscontext
->blend_values
[item
] = 0;
2133 pscontext
->blend_values
[ipos
] = 1;
2135 mm
->instances
[ipos
] = SplineFontEmpty();
2136 SplineFontMetaData(mm
->instances
[ipos
],fd
);
2137 free(fd
->fontinfo
->weight
);
2138 mm
->instances
[ipos
]->map
= map
;
2139 _SplineFontFromType1(mm
->instances
[ipos
],fd
,pscontext
);
2140 mm
->instances
[ipos
]->mm
= mm
;
2142 fd
->fontinfo
->weight
= origweight
;
2144 /* Clean up hintmasks. We always create a hintmask on the first point */
2145 /* only keep them if we actually have conflicts. */
2146 for ( i
=0; i
<mm
->normal
->glyphcnt
; ++i
)
2147 if ( mm
->normal
->glyphs
[i
]!=NULL
&&
2148 mm
->normal
->glyphs
[i
]->layers
[ly_fore
].splines
!= NULL
) {
2149 for ( item
=0; item
<mm
->instance_count
; ++item
)
2150 if ( mm
->instances
[item
]->glyphs
[i
]->vconflicts
||
2151 mm
->instances
[item
]->glyphs
[i
]->hconflicts
)
2153 if ( item
==mm
->instance_count
) { /* No conflicts */
2154 for ( item
=0; item
<mm
->instance_count
; ++item
) {
2155 chunkfree( mm
->instances
[item
]->glyphs
[i
]->layers
[ly_fore
].splines
->first
->hintmask
, sizeof(HintMask
) );
2156 mm
->instances
[item
]->glyphs
[i
]->layers
[ly_fore
].splines
->first
->hintmask
= NULL
;
2158 chunkfree( mm
->normal
->glyphs
[i
]->layers
[ly_fore
].splines
->first
->hintmask
, sizeof(HintMask
) );
2159 mm
->normal
->glyphs
[i
]->layers
[ly_fore
].splines
->first
->hintmask
= NULL
;
2166 static SplineFont
*SplineFontFromCIDType1(SplineFont
*sf
, FontDict
*fd
,
2167 struct pscontext
*pscontext
) {
2178 for ( i
=0; i
<fd
->fdcnt
; ++i
)
2179 if ( fd
->fds
[i
]->fonttype
!=1 && fd
->fds
[i
]->fonttype
!=2 )
2180 bad
= fd
->fds
[i
]->fonttype
;
2181 if ( bad
!=0x80000000 || fd
->cidfonttype
!=0 ) {
2182 LogError( _("Could not parse a CID font, %sCIDFontType %d, %sfonttype %d\n"),
2183 ( fd
->cidfonttype
!=0 ) ? "unexpected " : "",
2184 ( bad
!=0x80000000 ) ? "unexpected " : "",
2185 fd
->cidfonttype
, bad
);
2189 if ( fd
->cidstrs
==NULL
|| fd
->cidcnt
==0 ) {
2190 LogError( _("CID format doesn't contain what we expected it to.\n") );
2195 encmap
= EncMap1to1(fd
->cidcnt
);
2197 sf
->subfontcnt
= fd
->fdcnt
;
2198 sf
->subfonts
= galloc((sf
->subfontcnt
+1)*sizeof(SplineFont
*));
2199 for ( i
=0; i
<fd
->fdcnt
; ++i
) {
2200 if ( fd
->fontmatrix
[0]!=0 ) {
2201 MatMultiply(fd
->fontmatrix
,fd
->fds
[i
]->fontmatrix
,fd
->fds
[i
]->fontmatrix
);
2203 sf
->subfonts
[i
] = SplineFontEmpty();
2204 SplineFontMetaData(sf
->subfonts
[i
],fd
->fds
[i
]);
2205 sf
->subfonts
[i
]->cidmaster
= sf
;
2206 sf
->subfonts
[i
]->uni_interp
= sf
->uni_interp
;
2207 sf
->subfonts
[i
]->map
= encmap
;
2208 if ( fd
->fds
[i
]->fonttype
==2 )
2209 fd
->fds
[i
]->private->subrs
->bias
=
2210 fd
->fds
[i
]->private->subrs
->cnt
<1240 ? 107 :
2211 fd
->fds
[i
]->private->subrs
->cnt
<33900 ? 1131 : 32768;
2214 map
= FindCidMap(sf
->cidregistry
,sf
->ordering
,sf
->supplement
,sf
);
2216 chars
= gcalloc(fd
->cidcnt
,sizeof(SplineChar
*));
2217 for ( i
=0; i
<fd
->cidcnt
; ++i
) if ( fd
->cidlens
[i
]>0 ) {
2218 j
= fd
->cidfds
[i
]; /* We get font indexes of 255 for non-existant chars */
2219 uni
= CID2NameUni(map
,i
,buffer
,sizeof(buffer
));
2220 pscontext
->is_type2
= fd
->fds
[j
]->fonttype
==2;
2221 chars
[i
] = PSCharStringToSplines(fd
->cidstrs
[i
],fd
->cidlens
[i
],
2222 pscontext
,fd
->fds
[j
]->private->subrs
,
2224 chars
[i
]->vwidth
= sf
->subfonts
[j
]->ascent
+sf
->subfonts
[j
]->descent
;
2225 chars
[i
]->unicodeenc
= uni
;
2226 chars
[i
]->orig_pos
= i
;
2227 /* There better not be any references (seac's) because we have no */
2228 /* encoding on which to base any fixups */
2229 if ( chars
[i
]->layers
[ly_fore
].refs
!=NULL
)
2230 IError( "Reference found in CID font. Can't fix it up");
2231 sf
->subfonts
[j
]->glyphcnt
= sf
->subfonts
[j
]->glyphmax
= i
+1;
2234 for ( i
=0; i
<fd
->fdcnt
; ++i
)
2235 sf
->subfonts
[i
]->glyphs
= gcalloc(sf
->subfonts
[i
]->glyphcnt
,sizeof(SplineChar
*));
2236 for ( i
=0; i
<fd
->cidcnt
; ++i
) if ( chars
[i
]!=NULL
) {
2238 if ( j
<sf
->subfontcnt
) {
2239 sf
->subfonts
[j
]->glyphs
[i
] = chars
[i
];
2240 chars
[i
]->parent
= sf
->subfonts
[j
];
2245 /* Clean up the hint masks, We create an initial hintmask whether we */
2246 /* need it or not */
2249 _sf
= k
<sf
->subfontcnt
?sf
->subfonts
[k
]:sf
;
2250 for ( i
=0; i
<_sf
->glyphcnt
; ++i
) {
2251 if ( (sc
= _sf
->glyphs
[i
])!=NULL
&& !sc
->hconflicts
&& !sc
->vconflicts
&&
2252 sc
->layers
[ly_fore
].splines
!=NULL
) {
2253 chunkfree( sc
->layers
[ly_fore
].splines
->first
->hintmask
,sizeof(HintMask
) );
2254 sc
->layers
[ly_fore
].splines
->first
->hintmask
= NULL
;
2258 } while ( k
<sf
->subfontcnt
);
2262 SplineFont
*SplineFontFromPSFont(FontDict
*fd
) {
2264 struct pscontext pscontext
;
2269 memset(&pscontext
,0,sizeof(pscontext
));
2270 pscontext
.is_type2
= fd
->fonttype
==2;
2271 pscontext
.painttype
= fd
->painttype
;
2273 sf
= SplineFontEmpty();
2274 SplineFontMetaData(sf
,fd
);
2278 } else if ( fd
->fdcnt
!=0 )
2279 sf
= SplineFontFromCIDType1(sf
,fd
,&pscontext
);
2280 else if ( fd
->weightvector
!=NULL
)
2281 SplineFontFromMMType1(sf
,fd
,&pscontext
);
2283 SplineFontFromType1(sf
,fd
,&pscontext
);
2288 void RefCharFindBounds(RefChar
*rf
) {
2289 SplineSetFindBounds(rf
->layers
[0].splines
,&rf
->bb
);
2290 SplineSetFindTop(rf
->layers
[0].splines
,&rf
->top
);
2293 void SCReinstanciateRefChar(SplineChar
*sc
,RefChar
*rf
,int layer
) {
2294 SplinePointList
*new, *last
;
2298 if ( rf
->layer_cnt
>0 ) {
2299 SplinePointListsFree(rf
->layers
[0].splines
);
2300 rf
->layers
[0].splines
= NULL
;
2302 rf
->layers
= gcalloc(1,sizeof(struct reflayer
));
2304 new = SplinePointListTransform(SplinePointListCopy(rf
->sc
->layers
[layer
].splines
),rf
->transform
,true);
2305 rf
->layers
[0].splines
= new;
2308 for ( last
= new; last
->next
!=NULL
; last
= last
->next
);
2309 for ( refs
= rf
->sc
->layers
[layer
].refs
; refs
!=NULL
; refs
= refs
->next
) {
2310 new = SplinePointListTransform(SplinePointListCopy(refs
->layers
[0].splines
),rf
->transform
,true);
2314 rf
->layers
[0].splines
= new;
2316 for ( last
= new; last
->next
!=NULL
; last
= last
->next
);
2319 RefCharFindBounds(rf
);
2322 static void _SFReinstanciateRefs(SplineFont
*sf
) {
2323 int i
, undone
, undoable
, j
, cnt
;
2326 for ( i
=0; i
<sf
->glyphcnt
; ++i
) if ( sf
->glyphs
[i
]!=NULL
)
2327 sf
->glyphs
[i
]->ticked
= false;
2331 while ( undone
&& cnt
<200) {
2333 for ( i
=0; i
<sf
->glyphcnt
; ++i
) if ( sf
->glyphs
[i
]!=NULL
&& !sf
->glyphs
[i
]->ticked
) {
2335 for ( j
=0; j
<sf
->glyphs
[i
]->layer_cnt
; ++j
) {
2336 for ( ref
=sf
->glyphs
[i
]->layers
[j
].refs
; ref
!=NULL
; ref
=ref
->next
) {
2337 if ( !ref
->sc
->ticked
)
2344 for ( j
=0; j
<sf
->glyphs
[i
]->layer_cnt
; ++j
) {
2345 for ( ref
=sf
->glyphs
[i
]->layers
[j
].refs
; ref
!=NULL
; ref
=ref
->next
)
2346 SCReinstanciateRefChar(sf
->glyphs
[i
],ref
,j
);
2348 sf
->glyphs
[i
]->ticked
= true;
2355 void SFReinstanciateRefs(SplineFont
*sf
) {
2358 if ( sf
->cidmaster
!=NULL
|| sf
->subfontcnt
!=0 ) {
2359 if ( sf
->cidmaster
!=NULL
) sf
= sf
->cidmaster
;
2360 for ( i
=0; i
<sf
->subfontcnt
; ++i
)
2361 _SFReinstanciateRefs(sf
->subfonts
[i
]);
2363 _SFReinstanciateRefs(sf
);
2366 void SCReinstanciateRef(SplineChar
*sc
,SplineChar
*rsc
,int layer
) {
2369 for ( rf
=sc
->layers
[layer
].refs
; rf
!=NULL
; rf
=rf
->next
) if ( rf
->sc
==rsc
) {
2370 SCReinstanciateRefChar(sc
,rf
,layer
);
2374 void SCRemoveDependent(SplineChar
*dependent
,RefChar
*rf
,int layer
) {
2375 struct splinecharlist
*dlist
, *pd
;
2378 if ( dependent
->layers
[layer
].refs
==rf
)
2379 dependent
->layers
[layer
].refs
= rf
->next
;
2381 for ( prev
= dependent
->layers
[layer
].refs
; prev
->next
!=rf
; prev
=prev
->next
);
2382 prev
->next
= rf
->next
;
2384 /* Check for multiple dependencies (colon has two refs to period) */
2385 /* if there are none, then remove dependent from ref->sc's dependents list */
2386 for ( prev
= dependent
->layers
[ly_fore
].refs
; prev
!=NULL
&& (prev
==rf
|| prev
->sc
!=rf
->sc
); prev
= prev
->next
);
2388 dlist
= rf
->sc
->dependents
;
2391 else if ( dlist
->sc
==dependent
) {
2392 rf
->sc
->dependents
= dlist
->next
;
2394 for ( pd
=dlist
, dlist
= pd
->next
; dlist
!=NULL
&& dlist
->sc
!=dependent
; pd
=dlist
, dlist
= pd
->next
);
2396 pd
->next
= dlist
->next
;
2398 chunkfree(dlist
,sizeof(struct splinecharlist
));
2403 void SCRemoveLayerDependents(SplineChar
*dependent
,int layer
) {
2406 for ( rf
=dependent
->layers
[layer
].refs
; rf
!=NULL
; rf
=next
) {
2408 SCRemoveDependent(dependent
,rf
,layer
);
2410 dependent
->layers
[layer
].refs
= NULL
;
2413 void SCRemoveDependents(SplineChar
*dependent
) {
2416 for ( layer
=ly_fore
; layer
<dependent
->layer_cnt
; ++layer
)
2417 SCRemoveLayerDependents(dependent
,layer
);
2420 void SCRefToSplines(SplineChar
*sc
,RefChar
*rf
,int layer
) {
2423 if ( (spl
= rf
->layers
[0].splines
)!=NULL
) {
2424 while ( spl
->next
!=NULL
)
2426 spl
->next
= sc
->layers
[layer
].splines
;
2427 sc
->layers
[layer
].splines
= rf
->layers
[0].splines
;
2428 rf
->layers
[0].splines
= NULL
;
2431 SCRemoveDependent(sc
,rf
,layer
);
2434 /* This returns all real solutions, even those out of bounds */
2435 /* I use -999999 as an error flag, since we're really only interested in */
2436 /* solns near 0 and 1 that should be ok. -1 is perhaps a little too close */
2437 static int _CubicSolve(const Spline1D
*sp
,extended ts
[3]) {
2438 extended d
, xN
, yN
, delta2
, temp
, delta
, h
, t2
, t3
, theta
;
2441 ts
[0] = ts
[1] = ts
[2] = -999999;
2442 if ( sp
->d
==0 && sp
->a
!=0 ) {
2443 /* one of the roots is 0, the other two are the soln of a quadratic */
2446 ts
[1] = -sp
->b
/(extended
) sp
->a
; /* two zero roots */
2448 temp
= sp
->b
*(extended
) sp
->b
-4*(extended
) sp
->a
*sp
->c
;
2449 if ( RealNear(temp
,0))
2450 ts
[1] = -sp
->b
/(2*(extended
) sp
->a
);
2451 else if ( temp
>=0 ) {
2453 ts
[1] = (-sp
->b
+temp
)/(2*(extended
) sp
->a
);
2454 ts
[2] = (-sp
->b
-temp
)/(2*(extended
) sp
->a
);
2457 } else if ( sp
->a
!=0 ) {
2458 /* http://www.m-a.org.uk/eb/mg/mg077ch.pdf */
2459 /* this nifty solution to the cubic neatly avoids complex arithmatic */
2460 xN
= -sp
->b
/(3*(extended
) sp
->a
);
2461 yN
= ((sp
->a
*xN
+ sp
->b
)*xN
+sp
->c
)*xN
+ sp
->d
;
2463 delta2
= (sp
->b
*(extended
) sp
->b
-3*(extended
) sp
->a
*sp
->c
)/(9*(extended
) sp
->a
*sp
->a
);
2464 if ( RealNear(delta2
,0) ) delta2
= 0;
2466 /* the descriminant is yN^2-h^2, but delta might be <0 so avoid using h */
2467 d
= yN
*yN
- 4*sp
->a
*sp
->a
*delta2
*delta2
*delta2
;
2468 if ( ((yN
>.01 || yN
<-.01) && RealNear(d
/yN
,0)) || ((yN
<=.01 && yN
>=-.01) && RealNear(d
,0)) )
2472 t2
= (-yN
-temp
)/(2*sp
->a
);
2473 t2
= (t2
==0) ? 0 : (t2
<0) ? -pow(-t2
,1./3.) : pow(t2
,1./3.);
2474 t3
= (-yN
+temp
)/(2*sp
->a
);
2475 t3
= t3
==0 ? 0 : (t3
<0) ? -pow(-t3
,1./3.) : pow(t3
,1./3.);
2476 ts
[0] = xN
+ t2
+ t3
;
2479 delta
= sqrt(delta2
);
2480 h
= 2*sp
->a
*delta2
*delta
;
2482 if ( temp
>=-1.0001 && temp
<=1.0001 ) {
2483 if ( temp
<-1 ) temp
= -1; else if ( temp
>1 ) temp
= 1;
2484 theta
= acos(temp
)/3;
2485 ts
[i
++] = xN
+2*delta
*cos(theta
);
2486 ts
[i
++] = xN
+2*delta
*cos(2.0943951+theta
);
2487 ts
[i
++] = xN
+2*delta
*cos(4.1887902+theta
);
2490 } else if ( /* d==0 && */ delta2
!=0 ) {
2491 delta
= yN
/(2*sp
->a
);
2492 delta
= delta
==0 ? 0 : delta
>0 ? pow(delta
,1./3.) : -pow(-delta
,1./3.);
2493 ts
[i
++] = xN
+ delta
; /* this root twice, but that's irrelevant to me */
2494 ts
[i
++] = xN
- 2*delta
;
2495 } else if ( /* d==0 && */ delta2
==0 ) {
2496 if ( xN
>=-0.0001 && xN
<=1.0001 ) ts
[0] = xN
;
2498 } else if ( sp
->b
!=0 ) {
2499 extended d
= sp
->c
*(extended
) sp
->c
-4*(extended
) sp
->b
*sp
->d
;
2500 if ( RealNear(d
,0)) d
=0;
2502 return(false); /* All roots imaginary */
2504 ts
[0] = (-sp
->c
-d
)/(2*(extended
) sp
->b
);
2505 ts
[1] = (-sp
->c
+d
)/(2*(extended
) sp
->b
);
2506 } else if ( sp
->c
!=0 ) {
2507 ts
[0] = -sp
->d
/(extended
) sp
->c
;
2509 /* If it's a point then either everything is a solution, or nothing */
2511 return( ts
[0]!=-999999 );
2514 int CubicSolve(const Spline1D
*sp
,extended ts
[3]) {
2517 /* This routine gives us all solutions between [0,1] with -1 as an error flag */
2518 /* http://mathforum.org/dr.math/faq/faq.cubic.equations.html */
2520 if ( !_CubicSolve(sp
,ts
)) {
2521 ts
[0] = ts
[1] = ts
[2] = -1;
2525 for ( i
=0; i
<3; ++i
)
2526 if ( ts
[i
]==-999999 ) ts
[i
] = -1;
2527 if (ts
[0]>1.0001 || ts
[0]<-.0001 ) ts
[0] = -1;
2528 else if ( ts
[0]<0 ) ts
[0] = 0; else if ( ts
[0]>1 ) ts
[0] = 1;
2529 if (ts
[1]>1.0001 || ts
[1]<-.0001 ) ts
[1] = -1;
2530 else if ( ts
[1]<0 ) ts
[1] = 0; else if ( ts
[1]>1 ) ts
[1] = 1;
2531 if (ts
[2]>1.0001 || ts
[2]<-.0001 ) ts
[2] = -1;
2532 else if ( ts
[2]<0 ) ts
[2] = 0; else if ( ts
[2]>1 ) ts
[2] = 1;
2533 if ( ts
[1]==-1 ) { ts
[1] = ts
[2]; ts
[2] = -1;}
2534 if ( ts
[0]==-1 ) { ts
[0] = ts
[1]; ts
[1] = ts
[2]; ts
[2] = -1; }
2537 if ( ts
[0]>ts
[2] && ts
[2]!=-1 ) {
2538 t
= ts
[0]; ts
[0] = ts
[2]; ts
[2] = t
;
2540 if ( ts
[0]>ts
[1] && ts
[1]!=-1 ) {
2541 t
= ts
[0]; ts
[0] = ts
[1]; ts
[1] = t
;
2543 if ( ts
[1]>ts
[2] && ts
[2]!=-1 ) {
2544 t
= ts
[1]; ts
[1] = ts
[2]; ts
[2] = t
;
2550 extended
SplineSolve(const Spline1D
*sp
, real tmin
, real tmax
, extended sought
,real err
) {
2551 /* We want to find t so that spline(t) = sought */
2552 /* the curve must be monotonic */
2553 /* returns t which is near sought or -1 */
2561 CubicSolve(&temp
,ts
);
2562 if ( tmax
<tmin
) { t
= tmax
; tmax
= tmin
; tmin
= t
; }
2563 for ( i
=0; i
<3; ++i
)
2564 if ( ts
[i
]>=tmin
&& ts
[i
]<=tmax
)
2570 #ifndef EXTENDED_IS_LONG_DOUBLE
2571 double CheckExtremaForSingleBitErrors(const Spline1D
*sp
, double t
) {
2572 union { double dval
; int32 ival
[2]; } u1
, um1
, temp
;
2573 double slope
, slope1
, slopem1
;
2574 #ifdef WORDS_BIGENDIAN
2575 const int index
= 1;
2577 const int index
= 0;
2580 slope
= (3*(double) sp
->a
*t
+2*sp
->b
)*t
+sp
->c
;
2583 u1
.ival
[index
] += 1;
2584 slope1
= (3*(double) sp
->a
*u1
.dval
+2*sp
->b
)*u1
.dval
+sp
->c
;
2587 um1
.ival
[index
] -= 1;
2588 slopem1
= (3*(double) sp
->a
*um1
.dval
+2*sp
->b
)*um1
.dval
+sp
->c
;
2590 if ( slope
<0 ) slope
= -slope
;
2591 if ( slope1
<0 ) slope1
= -slope1
;
2592 if ( slopem1
<0 ) slopem1
= -slopem1
;
2594 if ( slope1
<slope
&& slope1
<=slopem1
) {
2595 /* Ok, things got better when we added 1. */
2596 /* Do they improve further if we add 1 more? */
2598 temp
.ival
[index
] += 1;
2599 slope
= (3*(double) sp
->a
*temp
.dval
+2*sp
->b
)*temp
.dval
+sp
->c
;
2600 if ( slope
<0 ) slope
= -slope
;
2602 return( temp
.dval
);
2605 } else if ( slopem1
<slope
&& slopem1
<=slope
) {
2606 /* Ok, things got better when we subtracted 1. */
2607 /* Do they improve further if we subtract 1 more? */
2609 temp
.ival
[index
] -= 1;
2610 slope
= (3*(double) sp
->a
*temp
.dval
+2*sp
->b
)*temp
.dval
+sp
->c
;
2611 if ( slope
<0 ) slope
= -slope
;
2612 if ( slope
<slopem1
)
2613 return( temp
.dval
);
2617 /* that seems as good as it gets */
2622 extended
esqrt(extended e
) {
2625 rt
= sqrt( (double) e
);
2637 static void _SplineFindExtrema(const Spline1D
*sp
, extended
*_t1
, extended
*_t2
) {
2638 extended t1
= -1, t2
= -1;
2641 /* Find the extreme points on the curve */
2642 /* Set to -1 if there are none or if they are outside the range [0,1] */
2643 /* Order them so that t1<t2 */
2644 /* If only one valid extremum it will be t1 */
2645 /* (Does not check the end points unless they have derivative==0) */
2646 /* (Does not check to see if d/dt==0 points are inflection points (rather than extrema) */
2648 /* cubic, possibly 2 extrema (possibly none) */
2649 b2_fourac
= 4*(extended
)sp
->b
*sp
->b
- 12*(extended
)sp
->a
*sp
->c
;
2650 if ( b2_fourac
>=0 ) {
2651 b2_fourac
= esqrt(b2_fourac
);
2652 t1
= (-2*sp
->b
- b2_fourac
) / (6*sp
->a
);
2653 t2
= (-2*sp
->b
+ b2_fourac
) / (6*sp
->a
);
2654 t1
= CheckExtremaForSingleBitErrors(sp
,t1
);
2655 t2
= CheckExtremaForSingleBitErrors(sp
,t2
);
2656 if ( t1
>t2
) { extended temp
= t1
; t1
= t2
; t2
= temp
; }
2657 else if ( t1
==t2
) t2
= -1;
2658 if ( RealNear(t1
,0)) t1
=0; else if ( RealNear(t1
,1)) t1
=1;
2659 if ( RealNear(t2
,0)) t2
=0; else if ( RealNear(t2
,1)) t2
=1;
2661 } else if ( sp
->b
!=0 ) {
2662 /* Quadratic, at most one extremum */
2663 t1
= -sp
->c
/(2.0*(extended
) sp
->b
);
2664 } else /*if ( sp->c!=0 )*/ {
2665 /* linear, no extrema */
2667 *_t1
= t1
; *_t2
= t2
;
2670 void SplineFindExtrema(const Spline1D
*sp
, extended
*_t1
, extended
*_t2
) {
2671 extended t1
= -1, t2
= -1;
2674 /* Find the extreme points on the curve */
2675 /* Set to -1 if there are none or if they are outside the range [0,1] */
2676 /* Order them so that t1<t2 */
2677 /* If only one valid extremum it will be t1 */
2678 /* (Does not check the end points unless they have derivative==0) */
2679 /* (Does not check to see if d/dt==0 points are inflection points (rather than extrema) */
2681 /* cubic, possibly 2 extrema (possibly none) */
2682 b2_fourac
= 4*(extended
) sp
->b
*sp
->b
- 12*(extended
) sp
->a
*sp
->c
;
2683 if ( b2_fourac
>=0 ) {
2684 b2_fourac
= esqrt(b2_fourac
);
2685 t1
= (-2*sp
->b
- b2_fourac
) / (6*sp
->a
);
2686 t2
= (-2*sp
->b
+ b2_fourac
) / (6*sp
->a
);
2687 t1
= CheckExtremaForSingleBitErrors(sp
,t1
);
2688 t2
= CheckExtremaForSingleBitErrors(sp
,t2
);
2689 if ( t1
>t2
) { extended temp
= t1
; t1
= t2
; t2
= temp
; }
2690 else if ( t1
==t2
) t2
= -1;
2691 if ( RealNear(t1
,0)) t1
=0; else if ( RealNear(t1
,1)) t1
=1;
2692 if ( RealNear(t2
,0)) t2
=0; else if ( RealNear(t2
,1)) t2
=1;
2693 if ( t2
<=0 || t2
>=1 ) t2
= -1;
2694 if ( t1
<=0 || t1
>=1 ) { t1
= t2
; t2
= -1; }
2696 } else if ( sp
->b
!=0 ) {
2697 /* Quadratic, at most one extremum */
2698 t1
= -sp
->c
/(2.0*(extended
) sp
->b
);
2699 if ( t1
<=0 || t1
>=1 ) t1
= -1;
2700 } else /*if ( sp->c!=0 )*/ {
2701 /* linear, no extrema */
2703 *_t1
= t1
; *_t2
= t2
;
2706 double SplineCurvature(Spline
*s
, double t
) {
2707 /* Kappa = (x'y'' - y'x'') / (x'^2 + y'^2)^(3/2) */
2708 double dxdt
, dydt
, d2xdt2
, d2ydt2
, denom
, numer
;
2711 return( CURVATURE_ERROR
);
2713 dxdt
= (3*s
->splines
[0].a
*t
+2*s
->splines
[0].b
)*t
+s
->splines
[0].c
;
2714 dydt
= (3*s
->splines
[1].a
*t
+2*s
->splines
[1].b
)*t
+s
->splines
[1].c
;
2715 d2xdt2
= 6*s
->splines
[0].a
*t
+ 2*s
->splines
[0].b
;
2716 d2ydt2
= 6*s
->splines
[1].a
*t
+ 2*s
->splines
[1].b
;
2717 denom
= pow( dxdt
*dxdt
+ dydt
*dydt
, 3.0/2.0 );
2718 numer
= dxdt
*d2ydt2
- dydt
*d2xdt2
;
2723 return( CURVATURE_ERROR
);
2725 return( numer
/denom
);
2728 int SplineAtInflection(Spline1D
*sp
, double t
) {
2729 /* It's a point of inflection if d sp/dt==0 and d2 sp/dt^2==0 */
2730 return ( RealNear( (3*sp
->a
*t
+ 2*sp
->b
)*t
+ sp
->c
,0) &&
2731 RealNear( 6*sp
->a
*t
+ 2*sp
->b
, 0));
2734 int SplineAtMinMax(Spline1D
*sp
, double t
) {
2735 /* It's a point of inflection if d sp/dt==0 and d2 sp/dt^2!=0 */
2736 return ( RealNear( (3*sp
->a
*t
+ 2*sp
->b
)*t
+ sp
->c
,0) &&
2737 !RealNear( 6*sp
->a
*t
+ 2*sp
->b
, 0));
2740 int Spline2DFindExtrema(const Spline
*sp
, extended extrema
[4] ) {
2742 BasePoint last
, cur
, mid
;
2744 SplineFindExtrema(&sp
->splines
[0],&extrema
[0],&extrema
[1]);
2745 SplineFindExtrema(&sp
->splines
[1],&extrema
[2],&extrema
[3]);
2747 for ( i
=0; i
<3; ++i
) for ( j
=i
+1; j
<4; ++j
) {
2748 if ( (extrema
[i
]==-1 && extrema
[j
]!=-1) || (extrema
[i
]>extrema
[j
] && extrema
[j
]!=-1) ) {
2749 extended temp
= extrema
[i
];
2750 extrema
[i
] = extrema
[j
];
2754 for ( i
=j
=0; i
<3 && extrema
[i
]!=-1; ++i
) {
2755 if ( extrema
[i
]==extrema
[i
+1] ) {
2756 for ( j
=i
+1; j
<3; ++j
)
2757 extrema
[j
] = extrema
[j
+1];
2762 /* Extrema which are too close together are not interesting */
2763 last
= sp
->from
->me
;
2764 for ( i
=0; i
<4 && extrema
[i
]!=-1; ++i
) {
2765 cur
.x
= ((sp
->splines
[0].a
*extrema
[i
]+sp
->splines
[0].b
)*extrema
[i
]+
2766 sp
->splines
[0].c
)*extrema
[i
]+sp
->splines
[0].d
;
2767 cur
.y
= ((sp
->splines
[1].a
*extrema
[i
]+sp
->splines
[1].b
)*extrema
[i
]+
2768 sp
->splines
[1].c
)*extrema
[i
]+sp
->splines
[1].d
;
2769 mid
.x
= (last
.x
+cur
.x
)/2; mid
.y
= (last
.y
+cur
.y
)/2;
2770 if ( (mid
.x
==last
.x
|| mid
.x
==cur
.x
) &&
2771 (mid
.y
==last
.y
|| mid
.y
==cur
.y
)) {
2772 for ( j
=i
+1; j
<3; ++j
)
2773 extrema
[j
] = extrema
[j
+1];
2777 for ( i
=0; i
<4 && extrema
[i
]!=-1; ++i
);
2780 mid
.x
= (last
.x
+cur
.x
)/2; mid
.y
= (last
.y
+cur
.y
)/2;
2781 if ( (mid
.x
==last
.x
|| mid
.x
==cur
.x
) &&
2782 (mid
.y
==last
.y
|| mid
.y
==cur
.y
))
2789 int Spline2DFindPointsOfInflection(const Spline
*sp
, extended poi
[2] ) {
2791 extended a
, b
, c
, b2_fourac
, t
;
2792 /* A POI happens when d2 y/dx2 is zero. This is not the same as d2y/dt2 / d2x/dt2 */
2793 /* d2 y/dx^2 = d/dt ( dy/dt / dx/dt ) / dx/dt */
2794 /* = ( (dx/dt) * d2 y/dt2 - ((dy/dt) * d2 x/dt2) )/ (dx/dt)^3 */
2795 /* (3ax*t^2+2bx*t+cx) * (6ay*t+2by) - (3ay*t^2+2by*t+cy) * (6ax*t+2bx) == 0 */
2796 /* (3ax*t^2+2bx*t+cx) * (3ay*t+by) - (3ay*t^2+2by*t+cy) * (3ax*t+bx) == 0 */
2797 /* 9*ax*ay*t^3 + (3ax*by+6bx*ay)*t^2 + (2bx*by+3cx*ay)*t + cx*by */
2798 /* -(9*ax*ay*t^3 + (3ay*bx+6by*ax)*t^2 + (2by*bx+3cy*ax)*t + cy*bx)==0 */
2799 /* 3*(ax*by-ay*bx)*t^2 + 3*(cx*ay-cy*ax)*t+ (cx*by-cy*bx) == 0 */
2801 a
= 3*((extended
) sp
->splines
[1].a
*sp
->splines
[0].b
-(extended
) sp
->splines
[0].a
*sp
->splines
[1].b
);
2802 b
= 3*((extended
) sp
->splines
[0].c
*sp
->splines
[1].a
- (extended
) sp
->splines
[1].c
*sp
->splines
[0].a
);
2803 c
= (extended
) sp
->splines
[0].c
*sp
->splines
[1].b
-(extended
) sp
->splines
[1].c
*sp
->splines
[0].b
;
2804 if ( !RealNear(a
,0) ) {
2805 b2_fourac
= b
*b
- 4*a
*c
;
2806 poi
[0] = poi
[1] = -1;
2809 b2_fourac
= esqrt( b2_fourac
);
2810 t
= (-b
+b2_fourac
)/(2*a
);
2811 if ( t
>=0 && t
<=1.0 )
2813 t
= (-b
-b2_fourac
)/(2*a
);
2814 if ( t
>=0 && t
<=1.0 ) {
2815 if ( cnt
==1 && poi
[0]>t
) {
2822 } else if ( !RealNear(b
,0) ) {
2824 if ( t
>=0 && t
<=1.0 )
2833 /* Ok, if the above routine finds an extremum that less than 1 unit */
2834 /* from an endpoint or another extremum, then many things are */
2835 /* just going to skip over it, and other things will be confused by this */
2836 /* so just remove it. It should be so close the difference won't matter */
2837 void SplineRemoveExtremaTooClose(Spline1D
*sp
, extended
*_t1
, extended
*_t2
) {
2838 extended last
, test
;
2839 extended t1
= *_t1
, t2
= *_t2
;
2841 if ( t1
>t2
&& t2
!=-1 ) {
2847 test
= ((sp
->a
*t1
+sp
->b
)*t1
+sp
->c
)*t1
+sp
->d
;
2848 if ( (test
-last
)*(test
-last
)<1 )
2854 test
= ((sp
->a
*t2
+sp
->b
)*t2
+sp
->c
)*t2
+sp
->d
;
2855 if ( (test
-last
)*(test
-last
)<1 )
2860 test
= sp
->a
+sp
->b
+sp
->c
+sp
->d
;
2861 if ( (test
-last
)*(test
-last
)<1 ) {
2867 /* Well we should just remove the whole spline? */;
2870 *_t1
= t1
; *_t2
= t2
;
2873 int SplineSolveFull(const Spline1D
*sp
,extended val
, extended ts
[3]) {
2878 CubicSolve(&temp
,ts
);
2879 return( ts
[0]!=-1 );
2882 static int AddPoint(extended x
,extended y
,extended t
,extended s
,BasePoint
*pts
,
2883 extended t1s
[3],extended t2s
[3], int soln
) {
2886 for ( i
=0; i
<soln
; ++i
)
2887 if ( x
==pts
[i
].x
&& y
==pts
[i
].y
)
2890 IError( "Too many solutions!\n" );
2898 static void IterateSolve(const Spline1D
*sp
,extended ts
[3]) {
2899 /* The closed form solution has too many rounding errors for my taste... */
2902 ts
[0] = ts
[1] = ts
[2] = -1;
2906 e
[0] = 0; e
[1] = e
[2] = e
[3] = 1.0;
2907 SplineFindExtrema(sp
,&e
[1],&e
[2]);
2908 if ( e
[1]==-1 ) e
[1] = 1;
2909 if ( e
[2]==-1 ) e
[2] = 1;
2910 for ( i
=j
=0; i
<3; ++i
) {
2911 ts
[j
] = IterateSplineSolve(sp
,e
[i
],e
[i
+1],0,.0001);
2912 if ( ts
[j
]!=-1 ) ++j
;
2916 } else if ( sp
->b
!=0 ) {
2917 extended b2_4ac
= sp
->c
*(extended
) sp
->c
- 4*sp
->b
*(extended
) sp
->d
;
2919 b2_4ac
= esqrt(b2_4ac
);
2920 ts
[0] = (-sp
->c
-b2_4ac
)/(2*sp
->b
);
2921 ts
[1] = (-sp
->c
+b2_4ac
)/(2*sp
->b
);
2922 if ( ts
[0]>ts
[1] ) { bigreal t
= ts
[0]; ts
[0] = ts
[1]; ts
[1] = t
; }
2924 } else if ( sp
->c
!=0 ) {
2925 ts
[0] = -sp
->d
/(extended
) sp
->c
;
2927 /* No solutions, or all solutions */;
2929 for ( i
=j
=0; i
<3; ++i
)
2930 if ( ts
[i
]>=0 && ts
[i
]<=1 )
2932 for ( i
=0; i
<j
-1; ++i
)
2933 if ( ts
[i
]+.0000001>ts
[i
+1]) {
2934 ts
[i
] = (ts
[i
]+ts
[i
+1])/2;
2936 for ( ++i
; i
<j
; ++i
)
2941 extended d0
= sp
->d
;
2942 extended dt
= ((sp
->a
*ts
[0]+sp
->b
)*ts
[0]+sp
->c
)*ts
[0]+sp
->d
;
2948 if ( ts
[j
-1]!=1.0 ) {
2949 extended d1
= sp
->a
+(extended
) sp
->b
+sp
->c
+sp
->d
;
2950 extended dt
= ((sp
->a
*ts
[j
-1]+sp
->b
)*ts
[j
-1]+sp
->c
)*ts
[j
-1]+sp
->d
;
2961 static extended
ISolveWithin(const Spline1D
*sp
,extended val
,extended tlow
, extended thigh
) {
2968 IterateSolve(&temp
,ts
);
2970 for ( i
=0; i
<3; ++i
)
2971 if ( ts
[i
]>=tlow
&& ts
[i
]<=thigh
)
2973 for ( i
=0; i
<3; ++i
) {
2974 if ( ts
[i
]>=tlow
-1./1024. && ts
[i
]<=tlow
)
2976 if ( ts
[i
]>=thigh
&& ts
[i
]<=thigh
+1./1024 )
2980 for ( i
=0; i
<3; ++i
)
2981 if ( ts
[i
]>=thigh
&& ts
[i
]<=tlow
)
2983 for ( i
=0; i
<3; ++i
) {
2984 if ( ts
[i
]>=thigh
-1./1024. && ts
[i
]<=thigh
)
2986 if ( ts
[i
]>=tlow
&& ts
[i
]<=tlow
+1./1024 )
2993 static int ICAddInter(int cnt
,BasePoint
*foundpos
,extended
*foundt1
,extended
*foundt2
,
2994 const Spline
*s1
,const Spline
*s2
,extended t1
,extended t2
, int maxcnt
) {
3001 foundpos
[cnt
].x
= ((s1
->splines
[0].a
*t1
+s1
->splines
[0].b
)*t1
+
3002 s1
->splines
[0].c
)*t1
+s1
->splines
[0].d
;
3003 foundpos
[cnt
].y
= ((s1
->splines
[1].a
*t1
+s1
->splines
[1].b
)*t1
+
3004 s1
->splines
[1].c
)*t1
+s1
->splines
[1].d
;
3008 static int ICBinarySearch(int cnt
,BasePoint
*foundpos
,extended
*foundt1
,extended
*foundt2
,
3010 const Spline
*s1
,const Spline
*s2
,extended t1low
,extended t1high
,extended t2low
,extended t2high
,
3014 extended o1o
, o2o
, o1n
, o2n
, m
;
3017 o1o
= ((s1
->splines
[other
].a
*t1low
+s1
->splines
[other
].b
)*t1low
+
3018 s1
->splines
[other
].c
)*t1low
+s1
->splines
[other
].d
;
3019 o2o
= ((s2
->splines
[other
].a
*t2low
+s2
->splines
[other
].b
)*t2low
+
3020 s2
->splines
[other
].c
)*t2low
+s2
->splines
[other
].d
;
3022 t1
= (t1low
+t1high
)/2;
3023 m
= ((s1
->splines
[major
].a
*t1
+s1
->splines
[major
].b
)*t1
+
3024 s1
->splines
[major
].c
)*t1
+s1
->splines
[major
].d
;
3025 t2
= ISolveWithin(&s2
->splines
[major
],m
,t2low
,t2high
);
3029 o1n
= ((s1
->splines
[other
].a
*t1
+s1
->splines
[other
].b
)*t1
+
3030 s1
->splines
[other
].c
)*t1
+s1
->splines
[other
].d
;
3031 o2n
= ((s2
->splines
[other
].a
*t2
+s2
->splines
[other
].b
)*t2
+
3032 s2
->splines
[other
].c
)*t2
+s2
->splines
[other
].d
;
3033 if (( o1n
-o2n
<.001 && o1n
-o2n
>-.001) ||
3034 (t1
-t1low
<.0001 && t1
-t1low
>-.0001))
3035 return( ICAddInter(cnt
,foundpos
,foundt1
,foundt2
,s1
,s2
,t1
,t2
,maxcnt
));
3036 if ( (o1o
>o2o
&& o1n
<o2n
) || (o1o
<o2o
&& o1n
>o2n
)) {
3046 static int CubicsIntersect(const Spline
*s1
,extended lowt1
,extended hight1
,BasePoint
*min1
,BasePoint
*max1
,
3047 const Spline
*s2
,extended lowt2
,extended hight2
,BasePoint
*min2
,BasePoint
*max2
,
3048 BasePoint
*foundpos
,extended
*foundt1
,extended
*foundt2
,
3052 extended t1max
, t1min
, t2max
, t2min
, t1
, t2
, t1diff
, oldt2
;
3053 extended o1o
, o2o
, o1n
, o2n
, m
;
3056 if ( (min
.x
= min1
->x
)<min2
->x
) min
.x
= min2
->x
;
3057 if ( (min
.y
= min1
->y
)<min2
->y
) min
.y
= min2
->y
;
3058 if ( (max
.x
= max1
->x
)>max2
->x
) max
.x
= max2
->x
;
3059 if ( (max
.y
= max1
->y
)>max2
->y
) max
.y
= max2
->y
;
3060 if ( max
.x
<min
.x
|| max
.y
<min
.y
)
3062 if ( max
.x
-min
.x
> max
.y
-min
.y
)
3068 t1max
= ISolveWithin(&s1
->splines
[major
],(&max
.x
)[major
],lowt1
,hight1
);
3069 t1min
= ISolveWithin(&s1
->splines
[major
],(&min
.x
)[major
],lowt1
,hight1
);
3070 t2max
= ISolveWithin(&s2
->splines
[major
],(&max
.x
)[major
],lowt2
,hight2
);
3071 t2min
= ISolveWithin(&s2
->splines
[major
],(&min
.x
)[major
],lowt2
,hight2
);
3072 if ( t1max
==-1 || t1min
==-1 || t2max
==-1 || t1min
==-1 )
3074 t1diff
= (t1max
-t1min
)/64.0;
3078 t1
= t1min
; t2
= t2min
;
3079 o1o
= ((s1
->splines
[other
].a
*t1
+s1
->splines
[other
].b
)*t1
+
3080 s1
->splines
[other
].c
)*t1
+s1
->splines
[other
].d
;
3081 o2o
= ((s2
->splines
[other
].a
*t2
+s2
->splines
[other
].b
)*t2
+
3082 s2
->splines
[other
].c
)*t2
+s2
->splines
[other
].d
;
3084 cnt
= ICAddInter(cnt
,foundpos
,foundt1
,foundt2
,s1
,s2
,t1
,t2
,maxcnt
);
3089 if (( t1max
>t1min
&& t1
>t1max
) || (t1max
<t1min
&& t1
<t1max
) || cnt
>3 )
3091 m
= ((s1
->splines
[major
].a
*t1
+s1
->splines
[major
].b
)*t1
+
3092 s1
->splines
[major
].c
)*t1
+s1
->splines
[major
].d
;
3094 t2
= ISolveWithin(&s2
->splines
[major
],m
,lowt2
,hight2
);
3098 o1n
= ((s1
->splines
[other
].a
*t1
+s1
->splines
[other
].b
)*t1
+
3099 s1
->splines
[other
].c
)*t1
+s1
->splines
[other
].d
;
3100 o2n
= ((s2
->splines
[other
].a
*t2
+s2
->splines
[other
].b
)*t2
+
3101 s2
->splines
[other
].c
)*t2
+s2
->splines
[other
].d
;
3103 cnt
= ICAddInter(cnt
,foundpos
,foundt1
,foundt2
,s1
,s2
,t1
,t2
,maxcnt
);
3104 if ( (o1o
>o2o
&& o1n
<o2n
) || (o1o
<o2o
&& o1n
>o2n
))
3105 cnt
= ICBinarySearch(cnt
,foundpos
,foundt1
,foundt2
,other
,
3106 s1
,s2
,t1
-t1diff
,t1
,oldt2
,t2
,maxcnt
);
3107 o1o
= o1n
; o2o
= o2n
;
3112 static int Closer(const Spline
*s1
,const Spline
*s2
,extended t1
,extended t2
,extended t1p
,extended t2p
) {
3113 double x1
= ((s1
->splines
[0].a
*t1
+s1
->splines
[0].b
)*t1
+s1
->splines
[0].c
)*t1
+s1
->splines
[0].c
;
3114 double y1
= ((s1
->splines
[1].a
*t1
+s1
->splines
[1].b
)*t1
+s1
->splines
[1].c
)*t1
+s1
->splines
[1].c
;
3115 double x2
= ((s2
->splines
[0].a
*t2
+s2
->splines
[0].b
)*t2
+s2
->splines
[0].c
)*t2
+s2
->splines
[0].c
;
3116 double y2
= ((s2
->splines
[1].a
*t2
+s2
->splines
[1].b
)*t2
+s2
->splines
[1].c
)*t2
+s2
->splines
[1].c
;
3117 double diff
= abs(x1
-x2
) + abs(y1
-y2
);
3118 double x1p
= ((s1
->splines
[0].a
*t1p
+s1
->splines
[0].b
)*t1p
+s1
->splines
[0].c
)*t1p
+s1
->splines
[0].c
;
3119 double y1p
= ((s1
->splines
[1].a
*t1p
+s1
->splines
[1].b
)*t1p
+s1
->splines
[1].c
)*t1p
+s1
->splines
[1].c
;
3120 double x2p
= ((s2
->splines
[0].a
*t2p
+s2
->splines
[0].b
)*t2p
+s2
->splines
[0].c
)*t2p
+s2
->splines
[0].c
;
3121 double y2p
= ((s2
->splines
[1].a
*t2p
+s2
->splines
[1].b
)*t2p
+s2
->splines
[1].c
)*t2p
+s2
->splines
[1].c
;
3122 double diffp
= abs(x1p
-x2p
) + abs(y1p
-y2p
);
3130 /* returns 0=>no intersection, 1=>at least one, location in pts, t1s, t2s */
3131 /* -1 => We couldn't figure it out in a closed form, have to do a numerical */
3133 int SplinesIntersect(const Spline
*s1
, const Spline
*s2
, BasePoint pts
[9],
3134 extended t1s
[10], extended t2s
[10]) { /* One extra for a trailing -1 */
3135 BasePoint min1
, max1
, min2
, max2
;
3137 extended x
,y
,t
, ac0
, ac1
;
3140 extended tempts
[4]; /* 3 solns for cubics, 4 for quartics */
3141 extended extrema1
[6], extrema2
[6];
3144 t1s
[0] = t1s
[1] = t1s
[2] = t1s
[3] = -1;
3145 t2s
[0] = t2s
[1] = t2s
[2] = t2s
[3] = -1;
3147 if ( s1
==s2
&& !s1
->knownlinear
&& !s1
->isquadratic
)
3148 /* Special case see if it doubles back on itself anywhere */;
3150 return( 0 ); /* Linear and quadratics can't double back, can't self-intersect */
3151 else if ( s1
->splines
[0].a
== s2
->splines
[0].a
&&
3152 s1
->splines
[0].b
== s2
->splines
[0].b
&&
3153 s1
->splines
[0].c
== s2
->splines
[0].c
&&
3154 s1
->splines
[0].d
== s2
->splines
[0].d
&&
3155 s1
->splines
[1].a
== s2
->splines
[1].a
&&
3156 s1
->splines
[1].b
== s2
->splines
[1].b
&&
3157 s1
->splines
[1].c
== s2
->splines
[1].c
&&
3158 s1
->splines
[1].d
== s2
->splines
[1].d
)
3159 return( -1 ); /* Same spline. Intersects everywhere */
3161 /* Ignore splines which are just a point */
3162 if ( s1
->knownlinear
&& s1
->splines
[0].c
==0 && s1
->splines
[1].c
==0 )
3164 if ( s2
->knownlinear
&& s2
->splines
[0].c
==0 && s2
->splines
[1].c
==0 )
3167 if ( s1
->knownlinear
)
3169 else if ( s2
->knownlinear
|| (!s1
->isquadratic
&& s2
->isquadratic
)) {
3170 const Spline
*stemp
= s1
;
3172 t1s
= t2s
; t2s
= ts
;
3173 s1
= s2
; s2
= stemp
;
3176 min1
= s1
->from
->me
; max1
= min1
;
3177 min2
= s2
->from
->me
; max2
= min2
;
3178 if ( s1
->from
->nextcp
.x
>max1
.x
) max1
.x
= s1
->from
->nextcp
.x
;
3179 else if ( s1
->from
->nextcp
.x
<min1
.x
) min1
.x
= s1
->from
->nextcp
.x
;
3180 if ( s1
->from
->nextcp
.y
>max1
.y
) max1
.y
= s1
->from
->nextcp
.y
;
3181 else if ( s1
->from
->nextcp
.y
<min1
.y
) min1
.y
= s1
->from
->nextcp
.y
;
3182 if ( s1
->to
->prevcp
.x
>max1
.x
) max1
.x
= s1
->to
->prevcp
.x
;
3183 else if ( s1
->to
->prevcp
.x
<min1
.x
) min1
.x
= s1
->to
->prevcp
.x
;
3184 if ( s1
->to
->prevcp
.y
>max1
.y
) max1
.y
= s1
->to
->prevcp
.y
;
3185 else if ( s1
->to
->prevcp
.y
<min1
.y
) min1
.y
= s1
->to
->prevcp
.y
;
3186 if ( s1
->to
->me
.x
>max1
.x
) max1
.x
= s1
->to
->me
.x
;
3187 else if ( s1
->to
->me
.x
<min1
.x
) min1
.x
= s1
->to
->me
.x
;
3188 if ( s1
->to
->me
.y
>max1
.y
) max1
.y
= s1
->to
->me
.y
;
3189 else if ( s1
->to
->me
.y
<min1
.y
) min1
.y
= s1
->to
->me
.y
;
3191 if ( s2
->from
->nextcp
.x
>max2
.x
) max2
.x
= s2
->from
->nextcp
.x
;
3192 else if ( s2
->from
->nextcp
.x
<min2
.x
) min2
.x
= s2
->from
->nextcp
.x
;
3193 if ( s2
->from
->nextcp
.y
>max2
.y
) max2
.y
= s2
->from
->nextcp
.y
;
3194 else if ( s2
->from
->nextcp
.y
<min2
.y
) min2
.y
= s2
->from
->nextcp
.y
;
3195 if ( s2
->to
->prevcp
.x
>max2
.x
) max2
.x
= s2
->to
->prevcp
.x
;
3196 else if ( s2
->to
->prevcp
.x
<min2
.x
) min2
.x
= s2
->to
->prevcp
.x
;
3197 if ( s2
->to
->prevcp
.y
>max2
.y
) max2
.y
= s2
->to
->prevcp
.y
;
3198 else if ( s2
->to
->prevcp
.y
<min2
.y
) min2
.y
= s2
->to
->prevcp
.y
;
3199 if ( s2
->to
->me
.x
>max2
.x
) max2
.x
= s2
->to
->me
.x
;
3200 else if ( s2
->to
->me
.x
<min2
.x
) min2
.x
= s2
->to
->me
.x
;
3201 if ( s2
->to
->me
.y
>max2
.y
) max2
.y
= s2
->to
->me
.y
;
3202 else if ( s2
->to
->me
.y
<min2
.y
) min2
.y
= s2
->to
->me
.y
;
3203 if ( min1
.x
>max2
.x
|| min2
.x
>max1
.x
|| min1
.y
>max2
.y
|| min2
.y
>max1
.y
)
3204 return( false ); /* no intersection of bounding boxes */
3207 soln
= CheckEndpoint(&s1
->from
->me
,s2
,0,pts
,t1s
,t2s
,soln
);
3208 soln
= CheckEndpoint(&s1
->to
->me
,s2
,1,pts
,t1s
,t2s
,soln
);
3209 soln
= CheckEndpoint(&s2
->from
->me
,s1
,0,pts
,t2s
,t1s
,soln
);
3210 soln
= CheckEndpoint(&s2
->to
->me
,s1
,1,pts
,t2s
,t1s
,soln
);
3213 if ( s1
->knownlinear
) {
3214 spline
.d
= s1
->splines
[1].c
*((bigreal
) s2
->splines
[0].d
-(bigreal
) s1
->splines
[0].d
)-
3215 s1
->splines
[0].c
*((bigreal
) s2
->splines
[1].d
-(bigreal
) s1
->splines
[1].d
);
3216 spline
.c
= s1
->splines
[1].c
*(bigreal
) s2
->splines
[0].c
- s1
->splines
[0].c
*(bigreal
) s2
->splines
[1].c
;
3217 spline
.b
= s1
->splines
[1].c
*(bigreal
) s2
->splines
[0].b
- s1
->splines
[0].c
*(bigreal
) s2
->splines
[1].b
;
3218 spline
.a
= s1
->splines
[1].c
*(bigreal
) s2
->splines
[0].a
- s1
->splines
[0].c
*(bigreal
) s2
->splines
[1].a
;
3219 IterateSolve(&spline
,tempts
);
3220 if ( tempts
[0]==-1 )
3222 for ( i
= 0; i
<3 && tempts
[i
]!=-1; ++i
) {
3223 x
= ((s2
->splines
[0].a
*tempts
[i
]+s2
->splines
[0].b
)*tempts
[i
]+
3224 s2
->splines
[0].c
)*tempts
[i
]+s2
->splines
[0].d
;
3225 y
= ((s2
->splines
[1].a
*tempts
[i
]+s2
->splines
[1].b
)*tempts
[i
]+
3226 s2
->splines
[1].c
)*tempts
[i
]+s2
->splines
[1].d
;
3227 if ( (ac0
= s1
->splines
[0].c
)<0 ) ac0
= -ac0
;
3228 if ( (ac1
= s1
->splines
[1].c
)<0 ) ac1
= -ac1
;
3230 t
= (x
-s1
->splines
[0].d
)/s1
->splines
[0].c
;
3232 t
= (y
-s1
->splines
[1].d
)/s1
->splines
[1].c
;
3233 if ( tempts
[i
]>.999 && Closer(s1
,s2
,tempts
[i
],t
,1,t
))
3235 else if ( tempts
[i
]<.001 && Closer(s1
,s2
,tempts
[i
],t
,0,t
))
3237 if ( t
>.999 && Closer(s1
,s2
,tempts
[i
],t
,tempts
[i
],1))
3239 else if ( t
<.001 && Closer(s1
,s2
,tempts
[i
],t
,tempts
[i
],0))
3241 if ( t
<-.001 || t
>1.001 || x
<min1
.x
-.01 || y
<min1
.y
-.01 || x
>max1
.x
+.01 || y
>max1
.y
+.01 )
3243 if ( t
<=0 ) {t
=0; x
=s1
->from
->me
.x
; y
= s1
->from
->me
.y
; }
3244 else if ( t
>=1 ) { t
=1; x
=s1
->to
->me
.x
; y
= s1
->to
->me
.y
; }
3245 if ( s1
->from
->me
.x
==s1
->to
->me
.x
) /* Avoid rounding errors */
3246 x
= s1
->from
->me
.x
; /* on hor/vert lines */
3247 else if ( s1
->from
->me
.y
==s1
->to
->me
.y
)
3249 if ( s2
->knownlinear
) {
3250 if ( s2
->from
->me
.x
==s2
->to
->me
.x
)
3252 else if ( s2
->from
->me
.y
==s2
->to
->me
.y
)
3255 soln
= AddPoint(x
,y
,t
,tempts
[i
],pts
,t1s
,t2s
,soln
);
3258 #if 0 /* This doesn't work. */
3259 } else if ( s1
->isquadratic
&& s2
->isquadratic
) {
3261 temp
.b
= s1
->splines
[1].b
*s2
->splines
[0].b
- s1
->splines
[0].b
*s2
->splines
[1].b
;
3262 temp
.c
= s1
->splines
[1].b
*s2
->splines
[0].c
- s1
->splines
[0].b
*s2
->splines
[1].c
;
3263 temp
.d
= s1
->splines
[1].b
*(s2
->splines
[0].d
-s1
->splines
[0].d
) -
3264 s1
->splines
[0].b
*(s2
->splines
[1].d
-s1
->splines
[1].d
);
3265 d
= s1
->splines
[1].b
*s1
->splines
[0].c
- s1
->splines
[0].b
*s1
->splines
[1].c
;
3266 if ( RealNear(d
,0)) d
=0;
3268 temp
.b
/= d
; temp
.c
/= d
; temp
.d
/= d
;
3269 /* At this point t= temp.b*s^2 + temp.c*s + temp.d */
3270 /* We substitute this back into one of our equations and get a */
3272 quad
.a
= s1
->splines
[0].b
*temp
.b
*temp
.b
;
3273 quad
.b
= s1
->splines
[0].b
*2*temp
.b
*temp
.c
;
3274 quad
.c
= s1
->splines
[0].b
*(2*temp
.b
*temp
.d
+temp
.c
*temp
.c
);
3275 quad
.d
= s1
->splines
[0].b
*2*temp
.d
*temp
.c
;
3276 quad
.e
= s1
->splines
[0].b
*temp
.d
*temp
.d
;
3277 quad
.b
+= s1
->splines
[0].c
*temp
.b
;
3278 quad
.c
+= s1
->splines
[0].c
*temp
.c
;
3279 quad
.d
+= s1
->splines
[0].c
*temp
.d
;
3280 quad
.e
+= s1
->splines
[0].d
;
3281 quad
.e
-= s2
->splines
[0].d
;
3282 quad
.d
-= s2
->splines
[0].c
;
3283 quad
.c
-= s2
->splines
[0].b
;
3284 if ( QuarticSolve(&quad
,tempts
)==-1 )
3286 for ( i
=0; i
<4 && tempts
[i
]!=-999999; ++i
)
3287 soln
= AddQuadraticSoln(tempts
[i
],s1
,s2
,pts
,t1s
,t2s
,soln
);
3289 d
= temp
.c
*temp
.c
-4*temp
.b
*temp
.c
;
3290 if ( RealNear(d
,0)) d
= 0;
3294 s
= (-temp
.c
-d
)/(2*temp
.b
);
3295 soln
= AddQuadraticSoln(s
,s1
,s2
,pts
,t1s
,t2s
,soln
);
3296 s
= (-temp
.c
+d
)/(2*temp
.b
);
3297 soln
= AddQuadraticSoln(s
,s1
,s2
,pts
,t1s
,t2s
,soln
);
3302 /* if one of the splines is quadratic then we can get an expression */
3303 /* relating c*t+d to poly(s^3), and substituting this back we get */
3304 /* a poly of degree 6 in s which could be solved iteratively */
3305 /* however mixed quadratics and cubics are unlikely */
3307 /* but if both splines are degree 3, the t is expressed as the sqrt of */
3308 /* a third degree poly, which must be substituted into a cubic, and */
3309 /* then squared to get rid of the sqrts leaving us with an ?18? degree */
3312 /* So let's do it the hard way... we break the splines into little bits */
3313 /* where they are monotonic in both dimensions, then check these for */
3314 /* possible intersections */
3315 extrema1
[0] = extrema2
[0] = 0;
3316 ecnt1
= Spline2DFindExtrema(s1
,extrema1
+1);
3317 ecnt2
= Spline2DFindExtrema(s2
,extrema2
+1);
3318 extrema1
[++ecnt1
] = 1.0;
3319 extrema2
[++ecnt2
] = 1.0;
3321 for ( i
=0; i
<ecnt1
; ++i
) {
3322 min1
.x
= ((s1
->splines
[0].a
*extrema1
[i
]+s1
->splines
[0].b
)*extrema1
[i
]+
3323 s1
->splines
[0].c
)*extrema1
[i
]+s1
->splines
[0].d
;
3324 min1
.y
= ((s1
->splines
[1].a
*extrema1
[i
]+s1
->splines
[1].b
)*extrema1
[i
]+
3325 s1
->splines
[1].c
)*extrema1
[i
]+s1
->splines
[1].d
;
3326 max1
.x
= ((s1
->splines
[0].a
*extrema1
[i
+1]+s1
->splines
[0].b
)*extrema1
[i
+1]+
3327 s1
->splines
[0].c
)*extrema1
[i
+1]+s1
->splines
[0].d
;
3328 max1
.y
= ((s1
->splines
[1].a
*extrema1
[i
+1]+s1
->splines
[1].b
)*extrema1
[i
+1]+
3329 s1
->splines
[1].c
)*extrema1
[i
+1]+s1
->splines
[1].d
;
3330 if ( max1
.x
<min1
.x
) { extended temp
= max1
.x
; max1
.x
= min1
.x
; min1
.x
= temp
; }
3331 if ( max1
.y
<min1
.y
) { extended temp
= max1
.y
; max1
.y
= min1
.y
; min1
.y
= temp
; }
3332 for ( j
=(s1
==s2
)?i
+1:0; j
<ecnt2
; ++j
) {
3333 min2
.x
= ((s2
->splines
[0].a
*extrema2
[j
]+s2
->splines
[0].b
)*extrema2
[j
]+
3334 s2
->splines
[0].c
)*extrema2
[j
]+s2
->splines
[0].d
;
3335 min2
.y
= ((s2
->splines
[1].a
*extrema2
[j
]+s2
->splines
[1].b
)*extrema2
[j
]+
3336 s2
->splines
[1].c
)*extrema2
[j
]+s2
->splines
[1].d
;
3337 max2
.x
= ((s2
->splines
[0].a
*extrema2
[j
+1]+s2
->splines
[0].b
)*extrema2
[j
+1]+
3338 s2
->splines
[0].c
)*extrema2
[j
+1]+s2
->splines
[0].d
;
3339 max2
.y
= ((s2
->splines
[1].a
*extrema2
[j
+1]+s2
->splines
[1].b
)*extrema2
[j
+1]+
3340 s2
->splines
[1].c
)*extrema2
[j
+1]+s2
->splines
[1].d
;
3341 if ( max2
.x
<min2
.x
) { extended temp
= max2
.x
; max2
.x
= min2
.x
; min2
.x
= temp
; }
3342 if ( max2
.y
<min2
.y
) { extended temp
= max2
.y
; max2
.y
= min2
.y
; min2
.y
= temp
; }
3343 if ( min1
.x
>max2
.x
|| min2
.x
>max1
.x
|| min1
.y
>max2
.y
|| min2
.y
>max1
.y
)
3344 /* No possible intersection */;
3346 found
+= CubicsIntersect(s1
,extrema1
[i
],extrema1
[i
+1],&min1
,&max1
,
3347 s2
,extrema2
[j
],extrema2
[j
+1],&min2
,&max2
,
3348 &pts
[found
],&t1s
[found
],&t2s
[found
],9-found
);
3351 int cnt
= CubicsIntersect(s1
,extrema1
[i
],extrema1
[i
+1],&min1
,&max1
,
3352 s2
,extrema2
[j
],extrema2
[j
+1],&min2
,&max2
,
3353 &pts
[found
],&t1s
[found
],&t2s
[found
],9-found
);
3354 for ( k
=0; k
<cnt
; ++k
) {
3355 if ( RealNear(t1s
[found
+k
],t2s
[found
+k
]) ) {
3356 for ( l
=k
+1; l
<cnt
; ++l
) {
3357 pts
[found
+l
-1] = pts
[found
+l
];
3358 t1s
[found
+l
-1] = t1s
[found
+l
];
3359 t2s
[found
+l
-1] = t2s
[found
+l
];
3367 /* If the splines are colinear then we might get an unbounded */
3368 /* number of intersections */
3373 t1s
[found
] = t2s
[found
] = -1;
3377 int SplineSetIntersect(SplineSet
*spl
, Spline
**_spline
, Spline
**_spline2
) {
3379 extended t1s
[10], t2s
[10];
3380 int found
= false,i
;
3381 SplineSet
*test
, *test2
;
3382 Spline
*spline
, *spline2
, *first
, *first2
;
3384 for ( test
=spl
; test
!=NULL
; test
=test
->next
) {
3386 for ( spline
= test
->first
->next
; spline
!=NULL
&& spline
!=first
; spline
=spline
->to
->next
) {
3387 if ( first
==NULL
) first
= spline
;
3388 for ( test2
=test
; test2
!=NULL
; test2
=test2
->next
) {
3389 first2
= test2
==test
&& first
!=spline
? first
: NULL
;
3390 for ( spline2
=(test2
==test
)?spline
: test2
->first
->next
;
3391 spline2
!=NULL
&& spline2
!=first2
; spline2
= spline2
->to
->next
) {
3392 if ( first2
==NULL
) first2
= spline2
;
3393 if ( SplinesIntersect(spline
,spline2
,pts
,t1s
,t2s
)) {
3394 if ( spline
->to
->next
!=spline2
&& spline
->from
->prev
!=spline2
)
3396 else for ( i
=0; i
<10 && t1s
[i
]!=-1; ++i
) {
3397 if ( (t1s
[i
]<.9 && t1s
[i
]>.1) || (t2s
[i
]<.9 && t2s
[i
]>.1)) {
3417 *_spline2
= spline2
;
3422 void StemInfoFree(StemInfo
*h
) {
3423 HintInstance
*hi
, *n
;
3425 for ( hi
=h
->where
; hi
!=NULL
; hi
=n
) {
3427 chunkfree(hi
,sizeof(HintInstance
));
3429 chunkfree(h
,sizeof(StemInfo
));
3432 void StemInfosFree(StemInfo
*h
) {
3434 HintInstance
*hi
, *n
;
3436 for ( ; h
!=NULL
; h
= hnext
) {
3437 for ( hi
=h
->where
; hi
!=NULL
; hi
=n
) {
3439 chunkfree(hi
,sizeof(HintInstance
));
3442 chunkfree(h
,sizeof(StemInfo
));
3446 void DStemInfoFree(DStemInfo
*h
) {
3447 HintInstance
*hi
, *n
;
3449 for ( hi
=h
->where
; hi
!=NULL
; hi
=n
) {
3451 chunkfree(hi
,sizeof(HintInstance
));
3453 chunkfree(h
,sizeof(DStemInfo
));
3456 void DStemInfosFree(DStemInfo
*h
) {
3458 HintInstance
*hi
, *n
;
3460 for ( ; h
!=NULL
; h
= hnext
) {
3461 for ( hi
=h
->where
; hi
!=NULL
; hi
=n
) {
3463 chunkfree(hi
,sizeof(HintInstance
));
3466 chunkfree(h
,sizeof(DStemInfo
));
3470 StemInfo
*StemInfoCopy(StemInfo
*h
) {
3471 StemInfo
*head
=NULL
, *last
=NULL
, *cur
;
3472 HintInstance
*hilast
, *hicur
, *hi
;
3474 for ( ; h
!=NULL
; h
= h
->next
) {
3475 cur
= chunkalloc(sizeof(StemInfo
));
3484 cur
->where
= hilast
= NULL
;
3485 for ( hi
=h
->where
; hi
!=NULL
; hi
=hi
->next
) {
3486 hicur
= chunkalloc(sizeof(StemInfo
));
3490 cur
->where
= hilast
= hicur
;
3492 hilast
->next
= hicur
;
3500 DStemInfo
*DStemInfoCopy(DStemInfo
*h
) {
3501 DStemInfo
*head
=NULL
, *last
=NULL
, *cur
;
3502 HintInstance
*hilast
, *hicur
, *hi
;
3504 for ( ; h
!=NULL
; h
= h
->next
) {
3505 cur
= chunkalloc(sizeof(DStemInfo
));
3514 cur
->where
= hilast
= NULL
;
3515 for ( hi
=h
->where
; hi
!=NULL
; hi
=hi
->next
) {
3516 hicur
= chunkalloc(sizeof(StemInfo
));
3520 cur
->where
= hilast
= hicur
;
3522 hilast
->next
= hicur
;
3530 MinimumDistance
*MinimumDistanceCopy(MinimumDistance
*md
) {
3531 MinimumDistance
*head
=NULL
, *last
=NULL
, *cur
;
3533 for ( ; md
!=NULL
; md
= md
->next
) {
3534 cur
= chunkalloc(sizeof(DStemInfo
));
3547 void KernPairsFree(KernPair
*kp
) {
3549 for ( ; kp
!=NULL
; kp
= knext
) {
3551 chunkfree(kp
,sizeof(KernPair
));
3555 static AnchorPoint
*AnchorPointsRemoveName(AnchorPoint
*alist
,AnchorClass
*an
) {
3556 AnchorPoint
*prev
=NULL
, *ap
, *next
;
3558 for ( ap
=alist
; ap
!=NULL
; ap
=next
) {
3560 if ( ap
->anchor
== an
) {
3566 AnchorPointsFree(ap
);
3567 if ( an
->type
== act_mark
|| (an
->type
==act_mklg
&& ap
->type
==at_mark
))
3568 next
= NULL
; /* Only one instance of an anchor class in a glyph for mark to base anchors */
3569 /* Or for the mark glyphs of ligature classes */
3570 /* Mark to mark & cursive will (probably) have 2 occurances */
3571 /* and ligatures may have lots */
3578 static void SCRemoveAnchorClass(SplineChar
*sc
,AnchorClass
*an
) {
3583 sc
->anchor
= AnchorPointsRemoveName(sc
->anchor
,an
);
3584 for ( test
= sc
->layers
[ly_fore
].undoes
; test
!=NULL
; test
=test
->next
)
3585 if ( test
->undotype
==ut_state
|| test
->undotype
==ut_tstate
||
3586 test
->undotype
==ut_statehint
|| test
->undotype
==ut_statename
)
3587 test
->u
.state
.anchor
= AnchorPointsRemoveName(test
->u
.state
.anchor
,an
);
3588 for ( test
= sc
->layers
[ly_fore
].redoes
; test
!=NULL
; test
=test
->next
)
3589 if ( test
->undotype
==ut_state
|| test
->undotype
==ut_tstate
||
3590 test
->undotype
==ut_statehint
|| test
->undotype
==ut_statename
)
3591 test
->u
.state
.anchor
= AnchorPointsRemoveName(test
->u
.state
.anchor
,an
);
3594 void SFRemoveAnchorClass(SplineFont
*sf
,AnchorClass
*an
) {
3596 AnchorClass
*prev
, *test
;
3598 for ( i
=0; i
<sf
->glyphcnt
; ++i
)
3599 SCRemoveAnchorClass(sf
->glyphs
[i
],an
);
3601 for ( test
=sf
->anchor
; test
!=NULL
; test
=test
->next
) {
3604 sf
->anchor
= test
->next
;
3606 prev
->next
= test
->next
;
3607 chunkfree(test
,sizeof(AnchorClass
));
3614 AnchorPoint
*APAnchorClassMerge(AnchorPoint
*anchors
,AnchorClass
*into
,AnchorClass
*from
) {
3615 AnchorPoint
*api
=NULL
, *prev
, *ap
, *next
;
3618 for ( ap
=anchors
; ap
!=NULL
; ap
=next
) {
3620 if ( ap
->anchor
==from
) {
3621 for ( api
=anchors
; api
!=NULL
; api
=api
->next
) {
3622 if ( api
->anchor
==into
&&
3623 (api
->type
!=at_baselig
|| ap
->type
!=at_baselig
|| api
->lig_index
==ap
->lig_index
))
3626 if ( api
==NULL
&& into
!=NULL
) {
3635 AnchorPointsFree(ap
);
3643 AnchorPoint
*AnchorPointsCopy(AnchorPoint
*alist
) {
3644 AnchorPoint
*head
=NULL
, *last
=NULL
, *ap
;
3646 while ( alist
!=NULL
) {
3647 ap
= chunkalloc(sizeof(AnchorPoint
));
3654 alist
= alist
->next
;
3659 void AnchorPointsFree(AnchorPoint
*ap
) {
3661 for ( ; ap
!=NULL
; ap
= anext
) {
3663 chunkfree(ap
,sizeof(AnchorPoint
));
3668 void PSTFree(PST
*pst
) {
3670 for ( ; pst
!=NULL
; pst
= pnext
) {
3672 if ( pst
->type
==pst_lcaret
)
3673 free(pst
->u
.lcaret
.carets
);
3674 else if ( pst
->type
==pst_pair
) {
3675 free(pst
->u
.pair
.paired
);
3676 chunkfree(pst
->u
.pair
.vr
,sizeof(struct vr
[2]));
3677 } else if ( pst
->type
!=pst_position
) {
3678 free(pst
->u
.subs
.variant
);
3679 } else if ( pst
->type
==pst_position
) {
3681 chunkfree(pst
,sizeof(PST
));
3685 void FPSTRuleContentsFree(struct fpst_rule
*r
, enum fpossub_format format
) {
3690 free(r
->u
.glyph
.names
);
3691 free(r
->u
.glyph
.back
);
3692 free(r
->u
.glyph
.fore
);
3695 free(r
->u
.class.nclasses
);
3696 free(r
->u
.class.bclasses
);
3697 free(r
->u
.class.fclasses
);
3699 case pst_reversecoverage
:
3700 free(r
->u
.rcoverage
.replacements
);
3702 for ( j
=0 ; j
<r
->u
.coverage
.ncnt
; ++j
)
3703 free(r
->u
.coverage
.ncovers
[j
]);
3704 free(r
->u
.coverage
.ncovers
);
3705 for ( j
=0 ; j
<r
->u
.coverage
.bcnt
; ++j
)
3706 free(r
->u
.coverage
.bcovers
[j
]);
3707 free(r
->u
.coverage
.bcovers
);
3708 for ( j
=0 ; j
<r
->u
.coverage
.fcnt
; ++j
)
3709 free(r
->u
.coverage
.fcovers
[j
]);
3710 free(r
->u
.coverage
.fcovers
);
3718 void FPSTRulesFree(struct fpst_rule
*r
, enum fpossub_format format
, int rcnt
) {
3720 for ( i
=0; i
<rcnt
; ++i
)
3721 FPSTRuleContentsFree(&r
[i
],format
);
3725 static struct fpst_rule
*RulesCopy(struct fpst_rule
*from
, int cnt
,
3726 enum fpossub_format format
) {
3728 struct fpst_rule
*to
, *f
, *t
;
3733 to
= gcalloc(cnt
,sizeof(struct fpst_rule
));
3734 for ( i
=0; i
<cnt
; ++i
) {
3735 f
= from
+i
; t
= to
+i
;
3738 t
->u
.glyph
.names
= copy(f
->u
.glyph
.names
);
3739 t
->u
.glyph
.back
= copy(f
->u
.glyph
.back
);
3740 t
->u
.glyph
.fore
= copy(f
->u
.glyph
.fore
);
3743 t
->u
.class.ncnt
= f
->u
.class.ncnt
;
3744 t
->u
.class.bcnt
= f
->u
.class.bcnt
;
3745 t
->u
.class.fcnt
= f
->u
.class.fcnt
;
3746 t
->u
.class.nclasses
= galloc( f
->u
.class.ncnt
*sizeof(uint16
));
3747 memcpy(t
->u
.class.nclasses
,f
->u
.class.nclasses
,
3748 f
->u
.class.ncnt
*sizeof(uint16
));
3749 if ( t
->u
.class.bcnt
!=0 ) {
3750 t
->u
.class.bclasses
= galloc( f
->u
.class.bcnt
*sizeof(uint16
));
3751 memcpy(t
->u
.class.bclasses
,f
->u
.class.bclasses
,
3752 f
->u
.class.bcnt
*sizeof(uint16
));
3754 if ( t
->u
.class.fcnt
!=0 ) {
3755 t
->u
.class.fclasses
= galloc( f
->u
.class.fcnt
*sizeof(uint16
));
3756 memcpy(t
->u
.class.fclasses
,f
->u
.class.fclasses
,
3757 f
->u
.class.fcnt
*sizeof(uint16
));
3760 case pst_reversecoverage
:
3761 t
->u
.rcoverage
.replacements
= copy(f
->u
.rcoverage
.replacements
);
3763 t
->u
.coverage
.ncnt
= f
->u
.coverage
.ncnt
;
3764 t
->u
.coverage
.bcnt
= f
->u
.coverage
.bcnt
;
3765 t
->u
.coverage
.fcnt
= f
->u
.coverage
.fcnt
;
3766 t
->u
.coverage
.ncovers
= galloc( f
->u
.coverage
.ncnt
*sizeof(char *));
3767 for ( j
=0; j
<t
->u
.coverage
.ncnt
; ++j
)
3768 t
->u
.coverage
.ncovers
[j
] = copy(f
->u
.coverage
.ncovers
[j
]);
3769 if ( t
->u
.coverage
.bcnt
!=0 ) {
3770 t
->u
.coverage
.bcovers
= galloc( f
->u
.coverage
.bcnt
*sizeof(char *));
3771 for ( j
=0; j
<t
->u
.coverage
.bcnt
; ++j
)
3772 t
->u
.coverage
.bcovers
[j
] = copy(f
->u
.coverage
.bcovers
[j
]);
3774 if ( t
->u
.coverage
.fcnt
!=0 ) {
3775 t
->u
.coverage
.fcovers
= galloc( f
->u
.coverage
.fcnt
*sizeof(char *));
3776 for ( j
=0; j
<t
->u
.coverage
.fcnt
; ++j
)
3777 t
->u
.coverage
.fcovers
[j
] = copy(f
->u
.coverage
.fcovers
[j
]);
3783 if ( f
->lookup_cnt
!=0 ) {
3784 t
->lookup_cnt
= f
->lookup_cnt
;
3785 t
->lookups
= galloc(t
->lookup_cnt
*sizeof(struct seqlookup
));
3786 memcpy(t
->lookups
,f
->lookups
,t
->lookup_cnt
*sizeof(struct seqlookup
));
3792 FPST
*FPSTCopy(FPST
*fpst
) {
3796 nfpst
= chunkalloc(sizeof(FPST
));
3799 if ( nfpst
->nccnt
!=0 ) {
3800 nfpst
->nclass
= galloc(nfpst
->nccnt
*sizeof(char *));
3801 for ( i
=0; i
<nfpst
->nccnt
; ++i
)
3802 nfpst
->nclass
[i
] = copy(fpst
->nclass
[i
]);
3804 if ( nfpst
->bccnt
!=0 ) {
3805 nfpst
->bclass
= galloc(nfpst
->bccnt
*sizeof(char *));
3806 for ( i
=0; i
<nfpst
->bccnt
; ++i
)
3807 nfpst
->bclass
[i
] = copy(fpst
->bclass
[i
]);
3809 if ( nfpst
->fccnt
!=0 ) {
3810 nfpst
->fclass
= galloc(nfpst
->fccnt
*sizeof(char *));
3811 for ( i
=0; i
<nfpst
->fccnt
; ++i
)
3812 nfpst
->fclass
[i
] = copy(fpst
->fclass
[i
]);
3814 nfpst
->rules
= RulesCopy(fpst
->rules
,fpst
->rule_cnt
,fpst
->format
);
3818 void FPSTFree(FPST
*fpst
) {
3822 while ( fpst
!=NULL
) {
3824 for ( i
=0; i
<fpst
->nccnt
; ++i
)
3825 free(fpst
->nclass
[i
]);
3826 for ( i
=0; i
<fpst
->bccnt
; ++i
)
3827 free(fpst
->bclass
[i
]);
3828 for ( i
=0; i
<fpst
->fccnt
; ++i
)
3829 free(fpst
->fclass
[i
]);
3830 free(fpst
->nclass
); free(fpst
->bclass
); free(fpst
->fclass
);
3831 for ( i
=0; i
<fpst
->rule_cnt
; ++i
) {
3832 FPSTRuleContentsFree( &fpst
->rules
[i
],fpst
->format
);
3835 chunkfree(fpst
,sizeof(FPST
));
3840 void MinimumDistancesFree(MinimumDistance
*md
) {
3841 MinimumDistance
*next
;
3843 while ( md
!=NULL
) {
3845 chunkfree(md
,sizeof(MinimumDistance
));
3850 void TTFLangNamesFree(struct ttflangname
*l
) {
3851 struct ttflangname
*next
;
3856 for ( i
=0; i
<ttf_namemax
; ++i
)
3858 chunkfree(l
,sizeof(*l
));
3863 void AltUniFree(struct altuni
*altuni
) {
3864 struct altuni
*next
;
3867 next
= altuni
->next
;
3868 chunkfree(altuni
,sizeof(struct altuni
));
3873 void LayerDefault(Layer
*layer
) {
3874 memset(layer
,0,sizeof(Layer
));
3877 SplineChar
*SplineCharCreate(int layer_cnt
) {
3878 SplineChar
*sc
= chunkalloc(sizeof(SplineChar
));
3881 sc
->color
= COLOR_DEFAULT
;
3882 sc
->orig_pos
= 0xffff;
3883 sc
->unicodeenc
= -1;
3884 sc
->layer_cnt
= layer_cnt
;
3885 sc
->layers
= gcalloc(layer_cnt
,sizeof(Layer
));
3886 for ( i
=0; i
<layer_cnt
; ++i
)
3887 LayerDefault(&sc
->layers
[i
]);
3888 sc
->tex_height
= sc
->tex_depth
= sc
->italic_correction
= sc
->top_accent_horiz
=
3893 SplineChar
*SFSplineCharCreate(SplineFont
*sf
) {
3894 SplineChar
*sc
= SplineCharCreate(sf
->layer_cnt
);
3897 for ( i
=0; i
<sf
->layer_cnt
; ++i
) {
3898 sc
->layers
[i
].background
= sf
->layers
[i
].background
;
3899 sc
->layers
[i
].order2
= sf
->layers
[i
].order2
;
3905 void GlyphVariantsFree(struct glyphvariants
*gv
) {
3911 for ( i
=0; i
<gv
->part_cnt
; ++i
)
3912 free( gv
->parts
[i
].component
);
3914 chunkfree(gv
,sizeof(*gv
));
3917 struct mathkern
*MathKernCopy(struct mathkern
*mk
) {
3919 struct mathkern
*mknew
;
3923 mknew
= chunkalloc(sizeof(*mknew
));
3924 for ( i
=0; i
<4; ++i
) {
3925 struct mathkernvertex
*mkv
= &(&mk
->top_right
)[i
];
3926 struct mathkernvertex
*mknewv
= &(&mknew
->top_right
)[i
];
3927 mknewv
->cnt
= mkv
->cnt
;
3928 if ( mknewv
->cnt
!=0 ) {
3929 mknewv
->mkd
= gcalloc(mkv
->cnt
,sizeof(struct mathkerndata
));
3930 for ( j
=0; j
<mkv
->cnt
; ++j
) {
3931 mknewv
->mkd
[j
].height
= mkv
->mkd
[j
].height
;
3932 mknewv
->mkd
[j
].kern
= mkv
->mkd
[j
].kern
;
3939 void MathKernVContentsFree(struct mathkernvertex
*mk
) {
3943 void MathKernFree(struct mathkern
*mk
) {
3948 for ( i
=0; i
<4; ++i
)
3949 MathKernVContentsFree( &(&mk
->top_right
)[i
] );
3950 chunkfree(mk
,sizeof(*mk
));
3953 void SplineCharListsFree(struct splinecharlist
*dlist
) {
3954 struct splinecharlist
*dnext
;
3955 for ( ; dlist
!=NULL
; dlist
= dnext
) {
3956 dnext
= dlist
->next
;
3957 chunkfree(dlist
,sizeof(struct splinecharlist
));
3961 void LayerFreeContents(SplineChar
*sc
,int layer
) {
3962 SplinePointListsFree(sc
->layers
[layer
].splines
);
3963 RefCharsFree(sc
->layers
[layer
].refs
);
3964 ImageListsFree(sc
->layers
[layer
].images
);
3965 /* image garbage collection????!!!! */
3966 UndoesFree(sc
->layers
[layer
].undoes
);
3967 UndoesFree(sc
->layers
[layer
].redoes
);
3970 void SplineCharFreeContents(SplineChar
*sc
) {
3977 for ( i
=0; i
<sc
->layer_cnt
; ++i
)
3978 LayerFreeContents(sc
,i
);
3979 StemInfosFree(sc
->hstem
);
3980 StemInfosFree(sc
->vstem
);
3981 DStemInfosFree(sc
->dstem
);
3982 MinimumDistancesFree(sc
->md
);
3983 KernPairsFree(sc
->kerns
);
3984 KernPairsFree(sc
->vkerns
);
3985 AnchorPointsFree(sc
->anchor
);
3986 SplineCharListsFree(sc
->dependents
);
3987 PSTFree(sc
->possub
);
3988 free(sc
->ttf_instrs
);
3989 free(sc
->countermasks
);
3991 AltUniFree(sc
->altuni
);
3992 GlyphVariantsFree(sc
->horiz_variants
);
3993 GlyphVariantsFree(sc
->vert_variants
);
3994 MathKernFree(sc
->mathkern
);
3995 #if defined(_NO_PYTHON)
3996 free( sc
->python_persistent
); /* It's a string of pickled data which we leave as a string */
4002 void SplineCharFree(SplineChar
*sc
) {
4006 SplineCharFreeContents(sc
);
4007 chunkfree(sc
,sizeof(SplineChar
));
4010 void AnchorClassesFree(AnchorClass
*an
) {
4012 for ( ; an
!=NULL
; an
= anext
) {
4015 chunkfree(an
,sizeof(AnchorClass
));
4019 void TtfTablesFree(struct ttf_table
*tab
) {
4020 struct ttf_table
*next
;
4022 for ( ; tab
!=NULL
; tab
= next
) {
4025 chunkfree(tab
,sizeof(struct ttf_table
));
4029 void ScriptLangListFree(struct scriptlanglist
*sl
) {
4030 struct scriptlanglist
*next
;
4032 while ( sl
!=NULL
) {
4034 free(sl
->morelangs
);
4035 chunkfree(sl
,sizeof(*sl
));
4040 void FeatureScriptLangListFree(FeatureScriptLangList
*fl
) {
4041 FeatureScriptLangList
*next
;
4043 while ( fl
!=NULL
) {
4045 ScriptLangListFree(fl
->scripts
);
4046 chunkfree(fl
,sizeof(*fl
));
4051 void OTLookupFree(OTLookup
*lookup
) {
4052 struct lookup_subtable
*st
, *stnext
;
4054 free(lookup
->lookup_name
);
4055 FeatureScriptLangListFree(lookup
->features
);
4056 for ( st
=lookup
->subtables
; st
!=NULL
; st
=stnext
) {
4058 free(st
->subtable_name
);
4060 chunkfree(st
,sizeof(struct lookup_subtable
));
4062 chunkfree( lookup
,sizeof(OTLookup
) );
4065 void OTLookupListFree(OTLookup
*lookup
) {
4068 for ( ; lookup
!=NULL
; lookup
= next
) {
4069 next
= lookup
->next
;
4070 OTLookupFree(lookup
);
4074 KernClass
*KernClassCopy(KernClass
*kc
) {
4080 new = chunkalloc(sizeof(KernClass
));
4082 new->firsts
= galloc(new->first_cnt
*sizeof(char *));
4083 new->seconds
= galloc(new->second_cnt
*sizeof(char *));
4084 new->offsets
= galloc(new->first_cnt
*new->second_cnt
*sizeof(int16
));
4085 memcpy(new->offsets
,kc
->offsets
, new->first_cnt
*new->second_cnt
*sizeof(int16
));
4086 for ( i
=0; i
<new->first_cnt
; ++i
)
4087 new->firsts
[i
] = copy(kc
->firsts
[i
]);
4088 for ( i
=0; i
<new->second_cnt
; ++i
)
4089 new->seconds
[i
] = copy(kc
->seconds
[i
]);
4094 void KernClassFreeContents(KernClass
*kc
) {
4097 for ( i
=0; i
<kc
->first_cnt
; ++i
)
4098 free(kc
->firsts
[i
]);
4099 for ( i
=0; i
<kc
->second_cnt
; ++i
)
4100 free(kc
->seconds
[i
]);
4106 void KernClassListFree(KernClass
*kc
) {
4110 KernClassFreeContents(kc
);
4112 chunkfree(kc
,sizeof(KernClass
));
4117 void OtfNameListFree(struct otfname
*on
) {
4118 struct otfname
*on_next
;
4120 for ( ; on
!=NULL
; on
= on_next
) {
4123 chunkfree(on
,sizeof(*on
));
4127 EncMap
*EncMapNew(int enccount
,int backmax
,Encoding
*enc
) {
4128 EncMap
*map
= chunkalloc(sizeof(EncMap
));
4130 map
->enccount
= map
->encmax
= enccount
;
4131 map
->backmax
= backmax
;
4132 map
->map
= galloc(enccount
*sizeof(int));
4133 memset(map
->map
,-1,enccount
*sizeof(int));
4134 map
->backmap
= galloc(backmax
*sizeof(int));
4135 memset(map
->backmap
,-1,backmax
*sizeof(int));
4140 EncMap
*EncMap1to1(int enccount
) {
4141 EncMap
*map
= chunkalloc(sizeof(EncMap
));
4142 /* Used for CID fonts where CID is same as orig_pos */
4145 map
->enccount
= map
->encmax
= map
->backmax
= enccount
;
4146 map
->map
= galloc(enccount
*sizeof(int));
4147 map
->backmap
= galloc(enccount
*sizeof(int));
4148 for ( i
=0; i
<enccount
; ++i
)
4149 map
->map
[i
] = map
->backmap
[i
] = i
;
4154 static void EncodingFree(Encoding
*enc
) {
4159 free(enc
->enc_name
);
4161 if ( enc
->psnames
!=NULL
) {
4162 for ( i
=0; i
<enc
->char_cnt
; ++i
)
4163 free(enc
->psnames
[i
]);
4169 void EncMapFree(EncMap
*map
) {
4173 if ( map
->enc
->is_temporary
)
4174 EncodingFree(map
->enc
);
4178 chunkfree(map
,sizeof(EncMap
));
4181 EncMap
*EncMapCopy(EncMap
*map
) {
4184 new = chunkalloc(sizeof(EncMap
));
4186 new->map
= galloc(new->encmax
*sizeof(int));
4187 new->backmap
= galloc(new->backmax
*sizeof(int));
4188 memcpy(new->map
,map
->map
,new->enccount
*sizeof(int));
4189 memcpy(new->backmap
,map
->backmap
,new->backmax
*sizeof(int));
4192 for ( n
=0; map
->remap
[n
].infont
!=-1; ++n
);
4193 new->remap
= galloc(n
*sizeof(struct remap
));
4194 memcpy(new->remap
,map
->remap
,n
*sizeof(struct remap
));
4199 void MarkClassFree(int cnt
,char **classes
,char **names
) {
4202 for ( i
=1; i
<cnt
; ++i
) {
4210 struct baselangextent
*BaseLangCopy(struct baselangextent
*extent
) {
4211 struct baselangextent
*head
, *last
, *cur
;
4214 for ( ; extent
!=NULL
; extent
= extent
->next
) {
4215 cur
= chunkalloc(sizeof(struct baselangextent
));
4217 cur
->features
= BaseLangCopy(cur
->features
);
4227 void BaseLangFree(struct baselangextent
*extent
) {
4228 struct baselangextent
*next
;
4230 while ( extent
!=NULL
) {
4231 next
= extent
->next
;
4232 BaseLangFree(extent
->features
);
4233 chunkfree(extent
,sizeof(struct baselangextent
));
4238 void BaseScriptFree(struct basescript
*bs
) {
4239 struct basescript
*next
;
4241 while ( bs
!=NULL
) {
4243 free(bs
->baseline_pos
);
4244 BaseLangFree(bs
->langs
);
4245 chunkfree(bs
,sizeof(struct basescript
));
4250 void BaseFree(struct Base
*base
) {
4254 free(base
->baseline_tags
);
4255 BaseScriptFree(base
->scripts
);
4256 chunkfree(base
,sizeof(struct Base
));
4259 void SplineFontFree(SplineFont
*sf
) {
4264 if ( sf
->mm
!=NULL
) {
4268 for ( i
=0; i
<sf
->glyphcnt
; ++i
) if ( sf
->glyphs
[i
]!=NULL
)
4269 SplineCharFree(sf
->glyphs
[i
]);
4273 free(sf
->familyname
);
4275 free(sf
->copyright
);
4279 free(sf
->autosavename
);
4282 free(sf
->cidregistry
);
4284 /* We don't free the EncMap. That field is only a temporary pointer. Let the FontViewBase free it, that's where it really lives */
4285 SplinePointListsFree(sf
->grid
.splines
);
4286 AnchorClassesFree(sf
->anchor
);
4287 TtfTablesFree(sf
->ttf_tables
);
4288 TtfTablesFree(sf
->ttf_tab_saved
);
4289 UndoesFree(sf
->grid
.undoes
);
4290 UndoesFree(sf
->grid
.redoes
);
4291 PSDictFree(sf
->private);
4292 TTFLangNamesFree(sf
->names
);
4293 for ( i
=0; i
<sf
->subfontcnt
; ++i
)
4294 SplineFontFree(sf
->subfonts
[i
]);
4297 OTLookupListFree(sf
->gpos_lookups
);
4298 OTLookupListFree(sf
->gsub_lookups
);
4299 KernClassListFree(sf
->kerns
);
4300 KernClassListFree(sf
->vkerns
);
4301 FPSTFree(sf
->possub
);
4302 OtfNameListFree(sf
->fontstyle_name
);
4303 MarkClassFree(sf
->mark_class_cnt
,sf
->mark_classes
,sf
->mark_class_names
);
4305 #if defined(_NO_PYTHON)
4306 free( sf
->python_persistent
); /* It's a string of pickled data which we leave as a string */
4310 BaseFree(sf
->horiz_base
);
4311 BaseFree(sf
->vert_base
);
4313 for ( i
=0; i
< sf
->layer_cnt
; ++i
)
4314 free (sf
->layers
[i
].name
);
4320 void MMSetFreeContents(MMSet
*mm
) {
4323 free(mm
->instances
);
4325 free(mm
->positions
);
4326 free(mm
->defweights
);
4328 for ( i
=0; i
<mm
->axis_count
; ++i
) {
4330 free(mm
->axismaps
[i
].blends
);
4331 free(mm
->axismaps
[i
].designs
);
4338 void MMSetFree(MMSet
*mm
) {
4341 for ( i
=0; i
<mm
->instance_count
; ++i
) {
4342 mm
->instances
[i
]->mm
= NULL
;
4343 mm
->instances
[i
]->map
= NULL
;
4344 SplineFontFree(mm
->instances
[i
]);
4346 mm
->normal
->mm
= NULL
;
4347 SplineFontFree(mm
->normal
); /* EncMap gets freed here */
4348 MMSetFreeContents(mm
);
4350 chunkfree(mm
,sizeof(*mm
));
4353 static int SplineRemoveAnnoyingExtrema1(Spline
*s
,int which
,double err_sq
) {
4354 /* Remove extrema which are very close to one of the spline end-points */
4355 /* and which are in the oposite direction (along the normal of the */
4356 /* close end-point's cp) from the other end-point */
4357 extended ts
[2], t1
, t2
;
4361 BasePoint pos
, norm
;
4362 SplinePoint
*close
, *other
;
4364 bigreal c_
, b_
, nextcp
, prevcp
, prop
;
4365 int changed
= false;
4367 SplineFindExtrema(&s
->splines
[which
],&ts
[0],&ts
[1]);
4369 for ( i
=0; i
<2; ++i
) if ( ts
[i
]!=-1 && ts
[i
]!=0 && ts
[i
]!=1 ) {
4370 pos
.x
= ((s
->splines
[0].a
*ts
[i
]+s
->splines
[0].b
)*ts
[i
]+s
->splines
[0].c
)*ts
[i
]+s
->splines
[0].d
;
4371 pos
.y
= ((s
->splines
[1].a
*ts
[i
]+s
->splines
[1].b
)*ts
[i
]+s
->splines
[1].c
)*ts
[i
]+s
->splines
[1].d
;
4372 df
= (pos
.x
-s
->from
->me
.x
)*(pos
.x
-s
->from
->me
.x
) + (pos
.y
-s
->from
->me
.y
)*(pos
.y
-s
->from
->me
.y
);
4373 dt
= (pos
.x
-s
->to
->me
.x
)*(pos
.x
-s
->to
->me
.x
) + (pos
.y
-s
->to
->me
.y
)*(pos
.y
-s
->to
->me
.y
);
4374 if ( df
<dt
&& df
<err_sq
) {
4376 ccp
= &s
->from
->nextcp
;
4378 } else if ( dt
<df
&& dt
<err_sq
) {
4380 ccp
= &s
->to
->prevcp
;
4384 if ( ccp
->x
==close
->me
.x
&& ccp
->y
==close
->me
.y
)
4387 norm
.x
= (ccp
->y
-close
->me
.y
);
4388 norm
.y
= -(ccp
->x
-close
->me
.x
);
4389 dp
= (pos
.x
-close
->me
.x
)*norm
.x
+ (pos
.y
-close
->me
.y
)*norm
.y
;
4390 d_o
= (other
->me
.x
-close
->me
.x
)*norm
.x
+ (other
->me
.y
-close
->me
.y
)*norm
.y
;
4391 if ( dp
!=0 && dp
*d_o
>=0 )
4394 _SplineFindExtrema(&s
->splines
[which
],&t1
,&t2
);
4396 if ( close
==s
->from
) t1
=0;
4398 } else if ( t2
==ts
[i
] ) {
4399 if ( close
==s
->from
) t2
=0;
4404 if ( t2
==-1 ) /* quadratic */
4405 continue; /* Can't happen in a quadratic */
4407 /* The roots of the "slope" quadratic were t1, t2. We have shifted one*/
4408 /* root so that that extremum is exactly on an end point */
4409 /* Figure out the new slope quadratic, from that what the cubic must */
4410 /* be, and from that what the control points must be */
4411 /* Quad = 3at^2 + 2bt + c */
4412 /* New quad = 3a * (t^2 -(t1+t2)t + t1*t2) */
4413 /* a' = a, b' = -(t1+t2)/6a, c' = t1*t2/3a, d' = d */
4414 /* nextcp = from + c'/3, prevcp = nextcp + (b' + c')/3 */
4415 /* Then for each cp figure what percentage of the original cp vector */
4416 /* (or at least this one dimension of that vector) this represents */
4417 /* and scale both dimens by this amount */
4418 b_
= -(t1
+t2
)*3*s
->splines
[which
].a
/2;
4419 c_
= (t1
*t2
)*3*s
->splines
[which
].a
;
4420 nextcp
= (&s
->from
->me
.x
)[which
] + c_
/3;
4421 prevcp
= nextcp
+ (b_
+ c_
)/3;
4423 if ( (&s
->from
->nextcp
.x
)[which
] != (&s
->from
->me
.x
)[which
] ) {
4424 prop
= (c_
/3) / ( (&s
->from
->nextcp
.x
)[which
] - (&s
->from
->me
.x
)[which
] );
4425 if ( prop
<0 && (c_
/3 < .1 && c_
/3 > -.1))
4426 (&s
->to
->prevcp
.x
)[which
] = nextcp
;
4427 else if ( prop
>=0 && prop
<=10 ) {
4428 s
->from
->nextcp
.x
= s
->from
->me
.x
+ prop
*(s
->from
->nextcp
.x
-s
->from
->me
.x
);
4429 s
->from
->nextcp
.y
= s
->from
->me
.y
+ prop
*(s
->from
->nextcp
.y
-s
->from
->me
.y
);
4430 s
->from
->nonextcp
= (prop
== 0);
4434 if ( (&s
->to
->prevcp
.x
)[which
] != (&s
->to
->me
.x
)[which
] ) {
4435 prop
= ( prevcp
- (&s
->to
->me
.x
)[which
]) /
4436 ( (&s
->to
->prevcp
.x
)[which
] - (&s
->to
->me
.x
)[which
] );
4437 if ( prop
<0 && (prevcp
- (&s
->to
->me
.x
)[which
] < .1 && prevcp
- (&s
->to
->me
.x
)[which
] > -.1))
4438 (&s
->to
->prevcp
.x
)[which
] = prevcp
;
4439 else if ( prop
>=0 && prop
<=10 ) {
4440 s
->to
->prevcp
.x
= s
->to
->me
.x
+ prop
*(s
->to
->prevcp
.x
-s
->to
->me
.x
);
4441 s
->to
->prevcp
.y
= s
->to
->me
.y
+ prop
*(s
->to
->prevcp
.y
-s
->to
->me
.y
);
4442 s
->to
->noprevcp
= (prop
== 0);
4451 static int SplineRemoveAnnoyingExtrema(Spline
*s
,double err_sq
) {
4454 changed
= SplineRemoveAnnoyingExtrema1(s
,0,err_sq
);
4455 if ( SplineRemoveAnnoyingExtrema1(s
,1,err_sq
) )
4460 int SplineSetsRemoveAnnoyingExtrema(SplineSet
*ss
,double err
) {
4461 int changed
= false;
4462 double err_sq
= err
*err
;
4466 while ( ss
!=NULL
) {
4468 for ( s
= ss
->first
->next
; s
!=NULL
&& s
!=first
; s
= s
->to
->next
) {
4469 if ( first
== NULL
) first
= s
;
4470 if ( SplineRemoveAnnoyingExtrema(s
,err_sq
))
4478 SplinePoint
*SplineBisect(Spline
*spline
, extended t
) {
4479 Spline1 xstart
, xend
;
4480 Spline1 ystart
, yend
;
4481 Spline
*spline1
, *spline2
;
4483 SplinePoint
*old0
, *old1
;
4484 Spline1D
*xsp
= &spline
->splines
[0], *ysp
= &spline
->splines
[1];
4485 int order2
= spline
->order2
;
4488 if ( t
<=1e-3 || t
>=1-1e-3 )
4489 IError("Bisection to create a zero length spline");
4491 xstart
.s0
= xsp
->d
; ystart
.s0
= ysp
->d
;
4492 xend
.s1
= (extended
) xsp
->a
+xsp
->b
+xsp
->c
+xsp
->d
;
4493 yend
.s1
= (extended
) ysp
->a
+ysp
->b
+ysp
->c
+ysp
->d
;
4494 xstart
.s1
= xend
.s0
= ((xsp
->a
*t
+xsp
->b
)*t
+xsp
->c
)*t
+ xsp
->d
;
4495 ystart
.s1
= yend
.s0
= ((ysp
->a
*t
+ysp
->b
)*t
+ysp
->c
)*t
+ ysp
->d
;
4496 FigureSpline1(&xstart
,0,t
,xsp
);
4497 FigureSpline1(&xend
,t
,1,xsp
);
4498 FigureSpline1(&ystart
,0,t
,ysp
);
4499 FigureSpline1(¥d
,t
,1,ysp
);
4501 mid
= chunkalloc(sizeof(SplinePoint
));
4502 mid
->me
.x
= xstart
.s1
; mid
->me
.y
= ystart
.s1
;
4504 mid
->nextcp
.x
= xend
.sp
.d
+ xend
.sp
.c
/2;
4505 mid
->nextcp
.y
= yend
.sp
.d
+ yend
.sp
.c
/2;
4506 mid
->prevcp
.x
= xstart
.sp
.d
+ xstart
.sp
.c
/2;
4507 mid
->prevcp
.y
= ystart
.sp
.d
+ ystart
.sp
.c
/2;
4509 mid
->nextcp
.x
= xend
.c0
; mid
->nextcp
.y
= yend
.c0
;
4510 mid
->prevcp
.x
= xstart
.c1
; mid
->prevcp
.y
= ystart
.c1
;
4512 if ( mid
->me
.x
==mid
->nextcp
.x
&& mid
->me
.y
==mid
->nextcp
.y
)
4513 mid
->nonextcp
= true;
4514 if ( mid
->me
.x
==mid
->prevcp
.x
&& mid
->me
.y
==mid
->prevcp
.y
)
4515 mid
->noprevcp
= true;
4517 old0
= spline
->from
; old1
= spline
->to
;
4519 old0
->nextcp
= mid
->prevcp
;
4520 old1
->prevcp
= mid
->nextcp
;
4522 old0
->nextcp
.x
= xstart
.c0
; old0
->nextcp
.y
= ystart
.c0
;
4523 old1
->prevcp
.x
= xend
.c1
; old1
->prevcp
.y
= yend
.c1
;
4525 old0
->nonextcp
= (old0
->nextcp
.x
==old0
->me
.x
&& old0
->nextcp
.y
==old0
->me
.y
);
4526 old1
->noprevcp
= (old1
->prevcp
.x
==old1
->me
.x
&& old1
->prevcp
.y
==old1
->me
.y
);
4527 old0
->nextcpdef
= false;
4528 old1
->prevcpdef
= false;
4531 spline1
= chunkalloc(sizeof(Spline
));
4532 spline1
->splines
[0] = xstart
.sp
; spline1
->splines
[1] = ystart
.sp
;
4533 spline1
->from
= old0
;
4535 spline1
->order2
= order2
;
4536 old0
->next
= spline1
;
4537 mid
->prev
= spline1
;
4538 if ( SplineIsLinear(spline1
)) {
4539 spline1
->islinear
= spline1
->from
->nonextcp
= spline1
->to
->noprevcp
= true;
4540 spline1
->from
->nextcp
= spline1
->from
->me
;
4541 spline1
->to
->prevcp
= spline1
->to
->me
;
4543 SplineRefigure(spline1
);
4545 spline2
= chunkalloc(sizeof(Spline
));
4546 spline2
->splines
[0] = xend
.sp
; spline2
->splines
[1] = xend
.sp
;
4547 spline2
->from
= mid
;
4549 spline2
->order2
= order2
;
4550 mid
->next
= spline2
;
4551 old1
->prev
= spline2
;
4552 if ( SplineIsLinear(spline2
)) {
4553 spline2
->islinear
= spline2
->from
->nonextcp
= spline2
->to
->noprevcp
= true;
4554 spline2
->from
->nextcp
= spline2
->from
->me
;
4555 spline2
->to
->prevcp
= spline2
->to
->me
;
4557 SplineRefigure(spline2
);