diff options
Diffstat (limited to 'Build/source/texk/dvisvgm/dvisvgm-src/libs/ff-woff/fontforge/splineutil.c')
-rw-r--r-- | Build/source/texk/dvisvgm/dvisvgm-src/libs/ff-woff/fontforge/splineutil.c | 3579 |
1 files changed, 0 insertions, 3579 deletions
diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/libs/ff-woff/fontforge/splineutil.c b/Build/source/texk/dvisvgm/dvisvgm-src/libs/ff-woff/fontforge/splineutil.c deleted file mode 100644 index 4f96e87a30b..00000000000 --- a/Build/source/texk/dvisvgm/dvisvgm-src/libs/ff-woff/fontforge/splineutil.c +++ /dev/null @@ -1,3579 +0,0 @@ -/* Copyright (C) 2000-2012 by George Williams */ -/* - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - - * The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -#include "fontforgevw.h" -#include "encoding.h" -#include <math.h> - -#ifdef HAVE_IEEEFP_H -# include <ieeefp.h> /* Solaris defines isnan in ieeefp rather than math.h */ -#endif - -#include "sfd1.h" // This has the extended SplineFont type SplineFont1 for old file versions. -#ifdef FF_UTHASH_GLIF_NAMES -# include "glif_name_hash.h" -#endif - - -/*#define DEBUG 1*/ - -typedef struct quartic { - bigreal a,b,c,d,e; -} Quartic; - -/* In an attempt to make allocation more efficient I just keep preallocated */ -/* lists of certain common sizes. It doesn't seem to make much difference */ -/* when allocating stuff, but does when freeing. If the extra complexity */ -/* is bad then put: */ -/* #define chunkalloc(size) calloc(1,size) */ -/* #define chunkfree(item,size) free(item) */ -/* into splinefont.h after (or instead of) the definition of chunkalloc()*/ - -#define ALLOC_CHUNK 100 /* Number of small chunks to malloc at a time */ -#ifndef FONTFORGE_CONFIG_USE_DOUBLE -# define CHUNK_MAX 100 /* Maximum size (in chunk units) that we are prepared to allocate */ - /* The size of our data structures */ -#else -# define CHUNK_MAX 129 -#endif -# define CHUNK_UNIT sizeof(void *) /* will vary with the word size of */ - /* the machine. if pointers are 64 bits*/ - /* we may need twice as much space as for 32 bits */ - -#ifdef FLAG -#undef FLAG -#define FLAG 0xbadcafe -#endif - -#ifdef CHUNKDEBUG -static int chunkdebug = 0; /* When this is set we never free anything, insuring that each chunk is unique */ -#endif - -#if ALLOC_CHUNK>1 -struct chunk { struct chunk *next; }; -struct chunk2 { struct chunk2 *next; int flag; }; -#endif - -#if defined(FLAG) && ALLOC_CHUNK>1 -void chunktest(void) { - int i; - struct chunk2 *c; - - for ( i=2; i<CHUNK_MAX; ++i ) - for ( c=(struct chunk2 *) chunklists[i]; c!=NULL; c=c->next ) - if ( c->flag!=FLAG ) { - fprintf( stderr, "Chunk memory list has been corrupted\n" ); - abort(); - } -} -#endif - -void LineListFree(LineList *ll) { - LineList *next; - - while ( ll!=NULL ) { - next = ll->next; - chunkfree(ll,sizeof(LineList)); - ll = next; - } -} - -void LinearApproxFree(LinearApprox *la) { - LinearApprox *next; - - while ( la!=NULL ) { - next = la->next; - LineListFree(la->lines); - chunkfree(la,sizeof(LinearApprox)); - la = next; - } -} - -void SplineFree(Spline *spline) { - LinearApproxFree(spline->approx); - chunkfree(spline,sizeof(Spline)); -} - -SplinePoint *SplinePointCreate(real x, real y) { - SplinePoint *sp; - if ( (sp=chunkalloc(sizeof(SplinePoint)))!=NULL ) { - sp->me.x = x; sp->me.y = y; - sp->nextcp = sp->prevcp = sp->me; - sp->nonextcp = sp->noprevcp = true; - sp->nextcpdef = sp->prevcpdef = false; - sp->ttfindex = sp->nextcpindex = 0xfffe; - sp->name = NULL; - } - return( sp ); -} - -Spline *SplineMake3(SplinePoint *from, SplinePoint *to) { - Spline *spline = chunkalloc(sizeof(Spline)); - - spline->from = from; spline->to = to; - from->next = to->prev = spline; - SplineRefigure3(spline); -return( spline ); -} - -void SplinePointFree(SplinePoint *sp) { - chunkfree(sp->hintmask,sizeof(HintMask)); - free(sp->name); - chunkfree(sp,sizeof(SplinePoint)); -} - -void SplinePointsFree(SplinePointList *spl) { - Spline *first, *spline, *next; - int nonext; - - if ( spl==NULL ) - return; - if ( spl->first!=NULL ) { - nonext = spl->first->next==NULL; // If there is no spline, we set a flag. - first = NULL; - // We start on the first spline if it exists. - for ( spline = spl->first->next; spline!=NULL && spline!=first; spline = next ) { - next = spline->to->next; // Cache the location of the next spline. - SplinePointFree(spline->to); // Free the destination point. - SplineFree(spline); // Free the spline. - if ( first==NULL ) first = spline; // We want to avoid repeating the circuit. - } - // If the path is open or has no splines, free the starting point. - if ( spl->last!=spl->first || nonext ) - SplinePointFree(spl->first); - } -} - -void SplinePointListFree(SplinePointList *spl) { - - if ( spl==NULL ) return; - SplinePointsFree(spl); - free(spl->spiros); - free(spl->contour_name); - chunkfree(spl,sizeof(SplinePointList)); -} - -void SplinePointListsFree(SplinePointList *spl) { - SplinePointList *next; - - while ( spl!=NULL ) { - next = spl->next; - SplinePointListFree(spl); - spl = next; - } -} - -void SplineSetSpirosClear(SplineSet *spl) { - free(spl->spiros); - spl->spiros = NULL; - spl->spiro_cnt = spl->spiro_max = 0; -} - - -void RefCharFree(RefChar *ref) { - int i; - - if ( ref==NULL ) -return; - for ( i=0; i<ref->layer_cnt; ++i ) { - SplinePointListsFree(ref->layers[i].splines); - GradientFree(ref->layers[i].fill_brush.gradient); - GradientFree(ref->layers[i].stroke_pen.brush.gradient); - PatternFree(ref->layers[i].fill_brush.pattern); - PatternFree(ref->layers[i].stroke_pen.brush.pattern); - } - free(ref->layers); - chunkfree(ref,sizeof(RefChar)); -} - -RefChar *RefCharCreate(void) { - RefChar *ref = chunkalloc(sizeof(RefChar)); - ref->layer_cnt = 1; - ref->layers = calloc(1,sizeof(struct reflayer)); - ref->layers[0].fill_brush.opacity = ref->layers[0].stroke_pen.brush.opacity = 1.0; - ref->layers[0].fill_brush.col = ref->layers[0].stroke_pen.brush.col = COLOR_INHERITED; - ref->layers[0].stroke_pen.width = WIDTH_INHERITED; - ref->layers[0].stroke_pen.linecap = lc_inherited; - ref->layers[0].stroke_pen.linejoin = lj_inherited; - ref->layers[0].dofill = true; - ref->round_translation_to_grid = true; -return( ref ); -} - -void RefCharsFree(RefChar *ref) { - RefChar *rnext; - - while ( ref!=NULL ) { - rnext = ref->next; - RefCharFree(ref); - ref = rnext; - } -} - -typedef struct spline1 { - Spline1D sp; - real s0, s1; - real c0, c1; -} Spline1; - -static void FigureSpline1(Spline1 *sp1,bigreal t0, bigreal t1, Spline1D *sp ) { - bigreal s = (t1-t0); - if ( sp->a==0 && sp->b==0 ) { - sp1->sp.d = sp->d + t0*sp->c; - sp1->sp.c = s*sp->c; - sp1->sp.b = sp1->sp.a = 0; - } else { - sp1->sp.d = sp->d + t0*(sp->c + t0*(sp->b + t0*sp->a)); - sp1->sp.c = s*(sp->c + t0*(2*sp->b + 3*sp->a*t0)); - sp1->sp.b = s*s*(sp->b+3*sp->a*t0); - sp1->sp.a = s*s*s*sp->a; - } - sp1->c0 = sp1->sp.c/3 + sp1->sp.d; - sp1->c1 = sp1->c0 + (sp1->sp.b+sp1->sp.c)/3; -} - -static void SplineFindBounds(const Spline *sp, DBounds *bounds) { - real t, b2_fourac, v; - real min, max; - const Spline1D *sp1; - int i; - - /* first try the end points */ - for ( i=0; i<2; ++i ) { - sp1 = &sp->splines[i]; - if ( i==0 ) { - if ( sp->to->me.x<bounds->minx ) bounds->minx = sp->to->me.x; - if ( sp->to->me.x>bounds->maxx ) bounds->maxx = sp->to->me.x; - min = bounds->minx; max = bounds->maxx; - } else { - if ( sp->to->me.y<bounds->miny ) bounds->miny = sp->to->me.y; - if ( sp->to->me.y>bounds->maxy ) bounds->maxy = sp->to->me.y; - min = bounds->miny; max = bounds->maxy; - } - - /* then try the extrema of the spline (assuming they are between t=(0,1) */ - /* (I don't bother fixing up for tiny rounding errors here. they don't matter */ - /* But we could call CheckExtremaForSingleBitErrors */ - if ( sp1->a!=0 ) { - b2_fourac = 4*sp1->b*sp1->b - 12*sp1->a*sp1->c; - if ( b2_fourac>=0 ) { - b2_fourac = sqrt(b2_fourac); - t = (-2*sp1->b + b2_fourac) / (6*sp1->a); - if ( t>0 && t<1 ) { - v = ((sp1->a*t+sp1->b)*t+sp1->c)*t + sp1->d; - if ( v<min ) min = v; - if ( v>max ) max = v; - } - t = (-2*sp1->b - b2_fourac) / (6*sp1->a); - if ( t>0 && t<1 ) { - v = ((sp1->a*t+sp1->b)*t+sp1->c)*t + sp1->d; - if ( v<min ) min = v; - if ( v>max ) max = v; - } - } - } else if ( sp1->b!=0 ) { - t = -sp1->c/(2.0*sp1->b); - if ( t>0 && t<1 ) { - v = (sp1->b*t+sp1->c)*t + sp1->d; - if ( v<min ) min = v; - if ( v>max ) max = v; - } - } - if ( i==0 ) { - bounds->minx = min; bounds->maxx = max; - } else { - bounds->miny = min; bounds->maxy = max; - } - } -} - -static void _SplineSetFindBounds(const SplinePointList *spl, DBounds *bounds) { - Spline *spline, *first; - /* Ignore contours consisting of a single point (used for hinting, anchors */ - /* for mark to base, etc. */ - - for ( ; spl!=NULL; spl = spl->next ) if ( spl->first->next!=NULL && spl->first->next->to != spl->first ) { - first = NULL; - if ( bounds->minx==0 && bounds->maxx==0 && bounds->miny==0 && bounds->maxy == 0 ) { - bounds->minx = bounds->maxx = spl->first->me.x; - bounds->miny = bounds->maxy = spl->first->me.y; - } else { - if ( spl->first->me.x<bounds->minx ) bounds->minx = spl->first->me.x; - if ( spl->first->me.x>bounds->maxx ) bounds->maxx = spl->first->me.x; - if ( spl->first->me.y<bounds->miny ) bounds->miny = spl->first->me.y; - if ( spl->first->me.y>bounds->maxy ) bounds->maxy = spl->first->me.y; - } - for ( spline = spl->first->next; spline!=NULL && spline!=first; spline=spline->to->next ) { - SplineFindBounds(spline,bounds); - if ( first==NULL ) first = spline; - } - } -} - -static void _SplineSetFindClippedBounds(const SplinePointList *spl, DBounds *bounds,DBounds *clipb) { - Spline *spline, *first; - /* Ignore contours consisting of a single point (used for hinting, anchors */ - /* for mark to base, etc. */ - - for ( ; spl!=NULL; spl = spl->next ) if ( spl->first->next!=NULL && spl->first->next->to != spl->first ) { - first = NULL; - if ( !spl->is_clip_path ) { - if ( bounds->minx==0 && bounds->maxx==0 && bounds->miny==0 && bounds->maxy == 0 ) { - bounds->minx = bounds->maxx = spl->first->me.x; - bounds->miny = bounds->maxy = spl->first->me.y; - } else { - if ( spl->first->me.x<bounds->minx ) bounds->minx = spl->first->me.x; - if ( spl->first->me.x>bounds->maxx ) bounds->maxx = spl->first->me.x; - if ( spl->first->me.y<bounds->miny ) bounds->miny = spl->first->me.y; - if ( spl->first->me.y>bounds->maxy ) bounds->maxy = spl->first->me.y; - } - for ( spline = spl->first->next; spline!=NULL && spline!=first; spline=spline->to->next ) { - SplineFindBounds(spline,bounds); - if ( first==NULL ) first = spline; - } - } else { - if ( clipb->minx==0 && clipb->maxx==0 && clipb->miny==0 && clipb->maxy == 0 ) { - clipb->minx = clipb->maxx = spl->first->me.x; - clipb->miny = clipb->maxy = spl->first->me.y; - } else { - if ( spl->first->me.x<clipb->minx ) clipb->minx = spl->first->me.x; - if ( spl->first->me.x>clipb->maxx ) clipb->maxx = spl->first->me.x; - if ( spl->first->me.y<clipb->miny ) clipb->miny = spl->first->me.y; - if ( spl->first->me.y>clipb->maxy ) clipb->maxy = spl->first->me.y; - } - for ( spline = spl->first->next; spline!=NULL && spline!=first; spline=spline->to->next ) { - SplineFindBounds(spline,clipb); - if ( first==NULL ) first = spline; - } - } - } -} - -static void _SplineCharLayerFindBounds(SplineChar *sc,int layer, DBounds *bounds) { - RefChar *rf; - real e; - DBounds b, clipb; - - for ( rf=sc->layers[layer].refs; rf!=NULL; rf = rf->next ) { - if ( bounds->minx==0 && bounds->maxx==0 && bounds->miny==0 && bounds->maxy == 0 ) - *bounds = rf->bb; - else if ( rf->bb.minx!=0 || rf->bb.maxx != 0 || rf->bb.maxy != 0 || rf->bb.miny!=0 ) { - if ( rf->bb.minx < bounds->minx ) bounds->minx = rf->bb.minx; - if ( rf->bb.miny < bounds->miny ) bounds->miny = rf->bb.miny; - if ( rf->bb.maxx > bounds->maxx ) bounds->maxx = rf->bb.maxx; - if ( rf->bb.maxy > bounds->maxy ) bounds->maxy = rf->bb.maxy; - } - } - memset(&b,0,sizeof(b)); - memset(&clipb,0,sizeof(clipb)); - _SplineSetFindClippedBounds(sc->layers[layer].splines,&b,&clipb); - if ( sc->layers[layer].dostroke ) { - if ( sc->layers[layer].stroke_pen.width!=WIDTH_INHERITED ) - e = sc->layers[layer].stroke_pen.width*sc->layers[layer].stroke_pen.trans[0]; - else - e = sc->layers[layer].stroke_pen.trans[0]; - b.minx -= e; b.maxx += e; - b.miny -= e; b.maxy += e; - } - if ( clipb.minx!=0 || clipb.miny!=0 || clipb.maxx!=0 || clipb.maxy!=0 ) { - if ( b.minx<clipb.minx ) b.minx = clipb.minx; - if ( b.miny<clipb.miny ) b.miny = clipb.miny; - if ( b.maxx>clipb.maxx ) b.maxx = clipb.maxx; - if ( b.maxy>clipb.maxy ) b.maxy = clipb.maxy; - } - if ( bounds->minx==0 && bounds->maxx==0 && bounds->miny==0 && bounds->maxy == 0 ) - *bounds = b; - else if ( b.minx!=0 || b.maxx != 0 || b.maxy != 0 || b.miny!=0 ) { - if ( b.minx < bounds->minx ) bounds->minx = b.minx; - if ( b.miny < bounds->miny ) bounds->miny = b.miny; - if ( b.maxx > bounds->maxx ) bounds->maxx = b.maxx; - if ( b.maxy > bounds->maxy ) bounds->maxy = b.maxy; - } - - if ( sc->parent!=NULL && sc->parent->strokedfont && - (bounds->minx!=bounds->maxx || bounds->miny!=bounds->maxy)) { - real sw = sc->parent->strokewidth; - bounds->minx -= sw; bounds->miny -= sw; - bounds->maxx += sw; bounds->maxy += sw; - } -} - -void SplineCharLayerFindBounds(SplineChar *sc,int layer,DBounds *bounds) { - - if ( sc->parent!=NULL && sc->parent->multilayer ) { - SplineCharFindBounds(sc,bounds); -return; - } - - /* a char with no splines (ie. a space) must have an lbearing of 0 */ - bounds->minx = bounds->maxx = 0; - bounds->miny = bounds->maxy = 0; - - _SplineCharLayerFindBounds(sc,layer,bounds); -} - -void SplineCharFindBounds(SplineChar *sc,DBounds *bounds) { - int i; - int first,last; - - /* a char with no splines (ie. a space) must have an lbearing of 0 */ - bounds->minx = bounds->maxx = 0; - bounds->miny = bounds->maxy = 0; - - first = last = ly_fore; - if ( sc->parent!=NULL && sc->parent->multilayer ) - last = sc->layer_cnt-1; - for ( i=first; i<=last; ++i ) - _SplineCharLayerFindBounds(sc,i,bounds); -} - -void SplineFontLayerFindBounds(SplineFont *sf,int layer,DBounds *bounds) { - int i, k, first, last; - - if ( sf->multilayer ) { - SplineFontFindBounds(sf,bounds); -return; - } - - bounds->minx = bounds->maxx = 0; - bounds->miny = bounds->maxy = 0; - - for ( i = 0; i<sf->glyphcnt; ++i ) { - SplineChar *sc = sf->glyphs[i]; - if ( sc!=NULL ) { - first = last = ly_fore; - if ( sc->parent != NULL && sc->parent->multilayer ) - last = sc->layer_cnt-1; - for ( k=first; k<=last; ++k ) - _SplineCharLayerFindBounds(sc,k,bounds); - } - } -} - -void SplineFontFindBounds(SplineFont *sf,DBounds *bounds) { - int i, k, first, last; - - bounds->minx = bounds->maxx = 0; - bounds->miny = bounds->maxy = 0; - - for ( i = 0; i<sf->glyphcnt; ++i ) { - SplineChar *sc = sf->glyphs[i]; - if ( sc!=NULL ) { - first = last = ly_fore; - if ( sf->multilayer ) - last = sc->layer_cnt-1; - for ( k=first; k<=last; ++k ) - _SplineCharLayerFindBounds(sc,k,bounds); - } - } -} - -void CIDLayerFindBounds(SplineFont *cidmaster,int layer,DBounds *bounds) { - SplineFont *sf; - int i; - DBounds b; - real factor; - - if ( cidmaster->cidmaster ) - cidmaster = cidmaster->cidmaster; - if ( cidmaster->subfonts==NULL ) { - SplineFontLayerFindBounds(cidmaster,layer,bounds); -return; - } - - sf = cidmaster->subfonts[0]; - SplineFontLayerFindBounds(sf,layer,bounds); - factor = 1000.0/(sf->ascent+sf->descent); - bounds->maxx *= factor; bounds->minx *= factor; bounds->miny *= factor; bounds->maxy *= factor; - for ( i=1; i<cidmaster->subfontcnt; ++i ) { - sf = cidmaster->subfonts[i]; - SplineFontLayerFindBounds(sf,layer,&b); - factor = 1000.0/(sf->ascent+sf->descent); - b.maxx *= factor; b.minx *= factor; b.miny *= factor; b.maxy *= factor; - if ( b.maxx>bounds->maxx ) bounds->maxx = b.maxx; - if ( b.maxy>bounds->maxy ) bounds->maxy = b.maxy; - if ( b.miny<bounds->miny ) bounds->miny = b.miny; - if ( b.minx<bounds->minx ) bounds->minx = b.minx; - } -} - -static void _SplineSetFindTop(SplineSet *ss,BasePoint *top) { - SplinePoint *sp; - - for ( ; ss!=NULL; ss=ss->next ) { - for ( sp=ss->first; ; ) { - if ( sp->me.y > top->y ) *top = sp->me; - if ( sp->next==NULL ) - break; - sp = sp->next->to; - if ( sp==ss->first ) - break; - } - } -} - -void SplineSetQuickBounds(SplineSet *ss,DBounds *b) { - SplinePoint *sp; - - b->minx = b->miny = 1e10; - b->maxx = b->maxy = -1e10; - for ( ; ss!=NULL; ss=ss->next ) { - for ( sp=ss->first; ; ) { - if ( sp->me.y < b->miny ) b->miny = sp->me.y; - if ( sp->me.x < b->minx ) b->minx = sp->me.x; - if ( sp->me.y > b->maxy ) b->maxy = sp->me.y; - if ( sp->me.x > b->maxx ) b->maxx = sp->me.x; - // Frank added the control points to the calculation since, - // according to Adam Twardoch, - // the OpenType values that rely upon this function - // expect control points to be included. - if ( !sp->noprevcp ) { - if ( sp->prevcp.y < b->miny ) b->miny = sp->prevcp.y; - if ( sp->prevcp.x < b->minx ) b->minx = sp->prevcp.x; - if ( sp->prevcp.y > b->maxy ) b->maxy = sp->prevcp.y; - if ( sp->prevcp.x > b->maxx ) b->maxx = sp->prevcp.x; - } - if ( !sp->nonextcp ) { - if ( sp->nextcp.y < b->miny ) b->miny = sp->nextcp.y; - if ( sp->nextcp.x < b->minx ) b->minx = sp->nextcp.x; - if ( sp->nextcp.y > b->maxy ) b->maxy = sp->nextcp.y; - if ( sp->nextcp.x > b->maxx ) b->maxx = sp->nextcp.x; - } - if ( sp->next==NULL ) - break; - sp = sp->next->to; - if ( sp==ss->first ) - break; - } - } - if ( b->minx>65536 ) b->minx = 0; - if ( b->miny>65536 ) b->miny = 0; - if ( b->maxx<-65536 ) b->maxx = 0; - if ( b->maxy<-65536 ) b->maxy = 0; -} - -void SplineCharQuickBounds(SplineChar *sc, DBounds *b) { - RefChar *ref; - int i,first, last; - DBounds temp; - real e; - - b->minx = b->miny = 1e10; - b->maxx = b->maxy = -1e10; - first = last = ly_fore; - if ( sc->parent!=NULL && sc->parent->multilayer ) - last = sc->layer_cnt-1; - for ( i=first; i<=last; ++i ) { - SplineSetQuickBounds(sc->layers[i].splines,&temp); - if ( sc->layers[i].dostroke && sc->layers[i].splines!=NULL ) { - if ( sc->layers[i].stroke_pen.width!=WIDTH_INHERITED ) - e = sc->layers[i].stroke_pen.width*sc->layers[i].stroke_pen.trans[0]; - else - e = sc->layers[i].stroke_pen.trans[0]; - temp.minx -= e; temp.maxx += e; - temp.miny -= e; temp.maxy += e; - } - if ( temp.minx!=0 || temp.maxx != 0 || temp.maxy != 0 || temp.miny!=0 ) { - if ( temp.minx < b->minx ) b->minx = temp.minx; - if ( temp.miny < b->miny ) b->miny = temp.miny; - if ( temp.maxx > b->maxx ) b->maxx = temp.maxx; - if ( temp.maxy > b->maxy ) b->maxy = temp.maxy; - } - for ( ref = sc->layers[i].refs; ref!=NULL; ref = ref->next ) { - /*SplineSetQuickBounds(ref->layers[0].splines,&temp);*/ - if ( b->minx==0 && b->maxx==0 && b->miny==0 && b->maxy == 0 ) - *b = ref->bb; - else if ( ref->bb.minx!=0 || ref->bb.maxx != 0 || ref->bb.maxy != 0 || ref->bb.miny!=0 ) { - if ( ref->bb.minx < b->minx ) b->minx = ref->bb.minx; - if ( ref->bb.miny < b->miny ) b->miny = ref->bb.miny; - if ( ref->bb.maxx > b->maxx ) b->maxx = ref->bb.maxx; - if ( ref->bb.maxy > b->maxy ) b->maxy = ref->bb.maxy; - } - } - } - if ( sc->parent!=NULL && sc->parent->strokedfont && - (b->minx!=b->maxx || b->miny!=b->maxy)) { - real sw = sc->parent->strokewidth; - b->minx -= sw; b->miny -= sw; - b->maxx += sw; b->maxy += sw; - } - if ( b->minx>1e9 ) - memset(b,0,sizeof(*b)); -} - -void SplineCharLayerQuickBounds(SplineChar *sc,int layer,DBounds *bounds) { - RefChar *ref; - DBounds temp; - - if ( sc->parent!=NULL && sc->parent->multilayer ) { - SplineCharQuickBounds(sc,bounds); -return; - } - - bounds->minx = bounds->miny = 1e10; - bounds->maxx = bounds->maxy = -1e10; - - SplineSetQuickBounds(sc->layers[layer].splines,bounds); - - for ( ref = sc->layers[layer].refs; ref!=NULL; ref = ref->next ) { - SplineSetQuickBounds(ref->layers[0].splines,&temp); - if ( bounds->minx==0 && bounds->maxx==0 && bounds->miny==0 && bounds->maxy == 0 ) - *bounds = temp; - else if ( temp.minx!=0 || temp.maxx != 0 || temp.maxy != 0 || temp.miny!=0 ) { - if ( temp.minx < bounds->minx ) bounds->minx = temp.minx; - if ( temp.miny < bounds->miny ) bounds->miny = temp.miny; - if ( temp.maxx > bounds->maxx ) bounds->maxx = temp.maxx; - if ( temp.maxy > bounds->maxy ) bounds->maxy = temp.maxy; - } - } - /* a char with no splines (ie. a space) must have an lbearing of 0 */ - if ( bounds->minx>1e9 ) - memset(bounds,0,sizeof(*bounds)); -} - -void SplinePointCategorize(SplinePoint *sp) { - int oldpointtype = sp->pointtype; - - sp->pointtype = pt_corner; - if ( sp->next==NULL && sp->prev==NULL ) - ; - else if ( (sp->next!=NULL && sp->next->to->me.x==sp->me.x && sp->next->to->me.y==sp->me.y) || - (sp->prev!=NULL && sp->prev->from->me.x==sp->me.x && sp->prev->from->me.y==sp->me.y )) - ; - else if ( sp->next==NULL ) { - sp->pointtype = sp->noprevcp ? pt_corner : pt_curve; - } else if ( sp->prev==NULL ) { - sp->pointtype = sp->nonextcp ? pt_corner : pt_curve; - } else if ( sp->nonextcp && sp->noprevcp ) { - ; - } else { - BasePoint ndir, ncdir, ncunit, pdir, pcdir, pcunit; - bigreal nlen, nclen, plen, pclen; - bigreal cross, bounds; - - ncdir.x = sp->nextcp.x - sp->me.x; ncdir.y = sp->nextcp.y - sp->me.y; - pcdir.x = sp->prevcp.x - sp->me.x; pcdir.y = sp->prevcp.y - sp->me.y; - ndir.x = ndir.y = pdir.x = pdir.y = 0; - if ( sp->next!=NULL ) { - ndir.x = sp->next->to->me.x - sp->me.x; ndir.y = sp->next->to->me.y - sp->me.y; - } - if ( sp->prev!=NULL ) { - pdir.x = sp->prev->from->me.x - sp->me.x; pdir.y = sp->prev->from->me.y - sp->me.y; - } - nclen = sqrt(ncdir.x*ncdir.x + ncdir.y*ncdir.y); - pclen = sqrt(pcdir.x*pcdir.x + pcdir.y*pcdir.y); - nlen = sqrt(ndir.x*ndir.x + ndir.y*ndir.y); - plen = sqrt(pdir.x*pdir.x + pdir.y*pdir.y); - ncunit = ncdir; pcunit = pcdir; - if ( nclen!=0 ) { ncunit.x /= nclen; ncunit.y /= nclen; } - if ( pclen!=0 ) { pcunit.x /= pclen; pcunit.y /= pclen; } - if ( nlen!=0 ) { ndir.x /= nlen; ndir.y /= nlen; } - if ( plen!=0 ) { pdir.x /= plen; pdir.y /= plen; } - - /* find out which side has the shorter control vector. Cross that vector */ - /* with the normal of the unit vector on the other side. If the */ - /* result is less than 1 em-unit then we've got colinear control points */ - /* (within the resolution of the integer grid) */ - /* Not quite... they could point in the same direction */ - if ( oldpointtype==pt_curve ) - bounds = 4.0; - else - bounds = 1.0; - if ( nclen!=0 && pclen!=0 && - ((nclen>=pclen && (cross = pcdir.x*ncunit.y - pcdir.y*ncunit.x)<bounds && cross>-bounds ) || - (pclen>nclen && (cross = ncdir.x*pcunit.y - ncdir.y*pcunit.x)<bounds && cross>-bounds )) && - ncdir.x*pcdir.x + ncdir.y*pcdir.y < 0 ) - sp->pointtype = pt_curve; - /* Cross product of control point with unit vector normal to line in */ - /* opposite direction should be less than an em-unit for a tangent */ - else if (( nclen==0 && pclen!=0 && (cross = pcdir.x*ndir.y-pcdir.y*ndir.x)<bounds && cross>-bounds ) || - ( pclen==0 && nclen!=0 && (cross = ncdir.x*pdir.y-ncdir.y*pdir.x)<bounds && cross>-bounds )) - sp->pointtype = pt_tangent; - - /* If a point started out hv, and could still be hv, them make it so */ - /* but don't make hv points de novo, Alexey doesn't like change */ - /* (this only works because hv isn't a default setting, so if it's */ - /* there it was done intentionally) */ - if ( sp->pointtype == pt_curve && oldpointtype == pt_hvcurve && - ((sp->nextcp.x==sp->me.x && sp->prevcp.x==sp->me.x && sp->nextcp.y!=sp->me.y) || - (sp->nextcp.y==sp->me.y && sp->prevcp.y==sp->me.y && sp->nextcp.x!=sp->me.x))) - sp->pointtype = pt_hvcurve; - } -} - -void SPLCategorizePoints(SplinePointList *spl) { - Spline *spline, *first, *last=NULL; - - for ( ; spl!=NULL; spl = spl->next ) { - first = NULL; - for ( spline = spl->first->next; spline!=NULL && spline!=first; spline=spline->to->next ) { - SplinePointCategorize(spline->from); - last = spline; - if ( first==NULL ) first = spline; - } - if ( spline==NULL && last!=NULL ) - SplinePointCategorize(last->to); - } -} - -SplinePointList *SplinePointListCopy1(const SplinePointList *spl) { - SplinePointList *cur; - const SplinePoint *pt; SplinePoint *cpt; - Spline *spline; - - cur = chunkalloc(sizeof(SplinePointList)); - cur->is_clip_path = spl->is_clip_path; - cur->spiro_cnt = cur->spiro_max = 0; - cur->spiros = 0; - if (spl->contour_name != NULL) cur->contour_name = copy(spl->contour_name); - for ( pt=spl->first; ; ) { - cpt = SplinePointCreate( 0, 0 ); - *cpt = *pt; - if ( pt->hintmask!=NULL ) { - cpt->hintmask = chunkalloc(sizeof(HintMask)); - memcpy(cpt->hintmask,pt->hintmask,sizeof(HintMask)); - } - if ( pt->name!=NULL ) { - cpt->name = copy(pt->name); - } - cpt->next = cpt->prev = NULL; - if ( cur->first==NULL ) { - cur->first = cur->last = cpt; - cur->start_offset = 0; - } else { - spline = chunkalloc(sizeof(Spline)); - *spline = *pt->prev; - spline->from = cur->last; - cur->last->next = spline; - cpt->prev = spline; - spline->to = cpt; - spline->approx = NULL; - cur->last = cpt; - } - if ( pt->next==NULL ) - break; - pt = pt->next->to; - if ( pt==spl->first ) - break; - } - if ( spl->first->prev!=NULL ) { - cpt = cur->first; - spline = chunkalloc(sizeof(Spline)); - *spline = *pt->prev; - spline->from = cur->last; - cur->last->next = spline; - cpt->prev = spline; - spline->to = cpt; - spline->approx = NULL; - cur->last = cpt; - } - if ( spl->spiro_cnt!=0 ) { - cur->spiro_cnt = cur->spiro_max = spl->spiro_cnt; - cur->spiros = malloc(cur->spiro_cnt*sizeof(spiro_cp)); - memcpy(cur->spiros,spl->spiros,cur->spiro_cnt*sizeof(spiro_cp)); - } -return( cur ); -} - -SplinePointList *SplinePointListCopy(const SplinePointList *base) { - SplinePointList *head=NULL, *last=NULL, *cur; - - for ( ; base!=NULL; base = base->next ) { - cur = SplinePointListCopy1(base); - if ( head==NULL ) - head = cur; - else - last->next = cur; - last = cur; - } -return( head ); -} - -void BpTransform(BasePoint *to, BasePoint *from, real transform[6]) { - BasePoint p; - p.x = transform[0]*from->x + transform[2]*from->y + transform[4]; - p.y = transform[1]*from->x + transform[3]*from->y + transform[5]; - to->x = rint(1024*p.x)/1024; - to->y = rint(1024*p.y)/1024; -} - -static void TransformPointExtended(SplinePoint *sp, real transform[6], enum transformPointMask tpmask ) -{ - /** - * If we are to transform selected BCP instead of their base splinepoint - * then lets do that. - */ - if( tpmask & tpmask_operateOnSelectedBCP - && (sp->nextcpselected || sp->prevcpselected )) - { - if( sp->nextcpselected ) - { - int order2 = sp->next ? sp->next->order2 : 0; - BpTransform(&sp->nextcp,&sp->nextcp,transform); - SPTouchControl( sp, &sp->nextcp, order2 ); - } - else if( sp->prevcpselected ) - { - int order2 = sp->next ? sp->next->order2 : 0; - BpTransform(&sp->prevcp,&sp->prevcp,transform); - SPTouchControl( sp, &sp->prevcp, order2 ); - } - } - else - { - /** - * Transform the base splinepoints. - */ - BpTransform(&sp->me,&sp->me,transform); - - if ( !sp->nonextcp ) - { - BpTransform(&sp->nextcp,&sp->nextcp,transform); - } - else - { - sp->nextcp = sp->me; - } - - if ( !sp->noprevcp ) - { - BpTransform(&sp->prevcp,&sp->prevcp,transform); - } - else - { - sp->prevcp = sp->me; - } - } - - - - if ( sp->pointtype == pt_hvcurve ) - { - if( - ((sp->nextcp.x==sp->me.x && sp->prevcp.x==sp->me.x && sp->nextcp.y!=sp->me.y) || - (sp->nextcp.y==sp->me.y && sp->prevcp.y==sp->me.y && sp->nextcp.x!=sp->me.x))) - { - /* Do Nothing */; - } - else - { - sp->pointtype = pt_curve; - } - } -} - -static void TransformPoint(SplinePoint *sp, real transform[6]) -{ - TransformPointExtended( sp, transform, 0 ); -} - -static void TransformSpiro(spiro_cp *cp, real transform[6]) { - bigreal x; - - x = transform[0]*cp->x + transform[2]*cp->y + transform[4]; - cp->y = transform[1]*cp->x + transform[3]*cp->y + transform[5]; - cp->x = x; -} - -static void TransformPTsInterpolateCPs(BasePoint *fromorig,Spline *spline, - BasePoint *toorig,real transform[6] ) { - BasePoint totrans, temp; - bigreal fraction; - - /* Normally the "from" point will already have been translated, and the "to" */ - /* point will need to be. But if we have a closed contour then on the */ - /* last spline both from and to will have been transform. We can detect */ - /* this because toorig will be different from &spline->to->me */ - if ( spline->to->selected && toorig==&spline->to->me ) - BpTransform(&totrans,&spline->to->me,transform); - else - totrans = spline->to->me; - - /* None of the control points will have been transformed yet */ - if ( fromorig->x!=toorig->x ) { - fraction = (spline->from->nextcp.x-fromorig->x)/( toorig->x-fromorig->x ); - spline->from->nextcp.x = spline->from->me.x + fraction*( totrans.x-spline->from->me.x ); - fraction = (spline->to->prevcp.x-fromorig->x)/( toorig->x-fromorig->x ); - spline->to->prevcp.x = spline->from->me.x + fraction*( totrans.x-spline->from->me.x ); - } else { - BpTransform(&temp,&spline->from->nextcp,transform); - spline->from->nextcp.x = temp.x; - BpTransform(&temp,&spline->to->prevcp,transform); - spline->to->prevcp.x = temp.x; - } - if ( fromorig->y!=toorig->y ) { - fraction = (spline->from->nextcp.y-fromorig->y)/( toorig->y-fromorig->y ); - spline->from->nextcp.y = spline->from->me.y + fraction*( totrans.y-spline->from->me.y ); - fraction = (spline->to->prevcp.y-fromorig->y)/( toorig->y-fromorig->y ); - spline->to->prevcp.y = spline->from->me.y + fraction*( totrans.y-spline->from->me.y ); - } else { - BpTransform(&temp,&spline->from->nextcp,transform); - spline->from->nextcp.y = temp.y; - BpTransform(&temp,&spline->to->prevcp,transform); - spline->to->prevcp.y = temp.y; - } - - if ( spline->to->selected ) - spline->to->me = totrans; -} - - -SplinePointList *SplinePointListTransformExtended(SplinePointList *base, real transform[6], - enum transformPointType tpt, enum transformPointMask tpmask ) { - Spline *spline, *first; - SplinePointList *spl; - SplinePoint *spt, *pfirst; - int allsel, anysel, alldone=true; - BasePoint lastpointorig, firstpointorig, orig; - - for ( spl = base; spl!=NULL; spl = spl->next ) { - pfirst = NULL; first = NULL; - allsel = true; anysel=false; - if ( tpt==tpt_OnlySelectedInterpCPs && spl->first->next!=NULL && !spl->first->next->order2 ) { - lastpointorig = firstpointorig = spl->first->me; - printf("SplinePointListTransformExtended() spl->first->selected %d\n", spl->first->selected ); - if ( spl->first->selected ) { - anysel = true; - BpTransform(&spl->first->me,&spl->first->me,transform); - } else - allsel = false; - for ( spline = spl->first->next; spline!=NULL && spline!=first; spline=spline->to->next ) { - if ( first==NULL ) first = spline; - orig = spline->to->me; - if ( spline->from->selected || spline->to->selected ) - { - TransformPTsInterpolateCPs( &lastpointorig, spline, - spl->first==spline->to? &firstpointorig : &spline->to->me, - transform ); - } - lastpointorig = orig; - if ( spline->to->selected ) anysel = true; else allsel = false; - } - - } else { - for ( spt = spl->first ; spt!=pfirst; spt = spt->next->to ) { - if ( pfirst==NULL ) pfirst = spt; - if ( tpt==tpt_AllPoints || spt->selected ) { - TransformPointExtended(spt,transform,tpmask); - if ( tpt!=tpt_AllPoints ) { - if ( spt->next!=NULL && spt->next->order2 && !spt->next->to->selected && spt->next->to->ttfindex==0xffff ) { - SplinePoint *to = spt->next->to; - to->prevcp = spt->nextcp; - to->me.x = (to->prevcp.x+to->nextcp.x)/2; - to->me.y = (to->prevcp.y+to->nextcp.y)/2; - } - if ( spt->prev!=NULL && spt->prev->order2 && !spt->prev->from->selected && spt->prev->from->ttfindex==0xffff ) { - SplinePoint *from = spt->prev->from; - from->nextcp = spt->prevcp; - from->me.x = (from->prevcp.x+from->nextcp.x)/2; - from->me.y = (from->prevcp.y+from->nextcp.y)/2; - } - } - anysel = true; - } else - allsel = alldone = false; - if ( spt->next==NULL ) - break; - } - } - if ( !anysel ) /* This splineset had no selected points it's unchanged */ - continue; - - /* If we changed all the points, then transform the spiro version too */ - /* otherwise if we just changed some points, throw away the spiro */ - if ( allsel ) { - int i; - for ( i=0; i<spl->spiro_cnt-1; ++i ) - TransformSpiro(&spl->spiros[i], transform); - } else - SplineSetSpirosClear(spl); - - /* if we changed all the points then the control points are right */ - /* otherwise those near the edges may be wonky, fix 'em up */ - /* Figuring out where the edges of the selection are is difficult */ - /* so let's just tweak all points, it shouldn't matter */ - /* It does matter. Let's tweak all default points */ - if( !(tpmask & tpmask_dontFixControlPoints)) - { - if ( tpt!=tpt_AllPoints && !allsel && spl->first->next!=NULL && !spl->first->next->order2 ) - { - pfirst = NULL; - for ( spt = spl->first ; spt!=pfirst; spt = spt->next->to ) - { - if ( pfirst==NULL ) pfirst = spt; - if ( spt->selected && spt->prev!=NULL && !spt->prev->from->selected && - spt->prev->from->pointtype == pt_tangent ) - SplineCharTangentPrevCP(spt->prev->from); - if ( spt->selected && spt->next!=NULL && !spt->next->to->selected && - spt->next->to->pointtype == pt_tangent ) - SplineCharTangentNextCP(spt->next->to); - if ( spt->prev!=NULL && spt->prevcpdef && tpt==tpt_OnlySelected ) - SplineCharDefaultPrevCP(spt); - if ( spt->next==NULL ) - break; - if ( spt->nextcpdef && tpt==tpt_OnlySelected ) - SplineCharDefaultNextCP(spt); - } - } - } - first = NULL; - for ( spline = spl->first->next; spline!=NULL && spline!=first; spline=spline->to->next ) { - if ( !alldone ) SplineRefigureFixup(spline); else SplineRefigure(spline); - if ( first==NULL ) first = spline; - } - } -return( base ); -} - -SplinePointList *SplinePointListTransform( SplinePointList *base, real transform[6], - enum transformPointType tpt ) -{ - enum transformPointMask tpmask = 0; - return SplinePointListTransformExtended( base, transform, tpt, tpmask ); -} - -HintMask *HintMaskFromTransformedRef(RefChar *ref,BasePoint *trans, - SplineChar *basesc,HintMask *hm) { - StemInfo *st, *st2; - int hst_cnt, bcnt; - real start, width; - int i; - - if ( ref->transform[1]!=0 || ref->transform[2]!=0 ) -return(NULL); - - memset(hm,0,sizeof(HintMask)); - for ( st = ref->sc->hstem; st!=NULL; st=st->next ) { - start = st->start*ref->transform[3] + ref->transform[5] + trans->y; - width = st->width*ref->transform[3]; - for ( st2=basesc->hstem,bcnt=0; st2!=NULL; st2=st2->next, bcnt++ ) - if ( st2->start == start && st2->width == width ) - break; - if ( st2!=NULL ) - (*hm)[bcnt>>3] |= (0x80>>(bcnt&7)); - } - for ( st2=basesc->hstem,hst_cnt=0; st2!=NULL; st2=st2->next, hst_cnt++ ); - - for ( st = ref->sc->vstem; st!=NULL; st=st->next ) { - start = st->start*ref->transform[0] + ref->transform[4] + trans->x; - width = st->width*ref->transform[0]; - for ( st2=basesc->vstem,bcnt=hst_cnt; st2!=NULL; st2=st2->next, bcnt++ ) - if ( st2->start == start && st2->width == width ) - break; - if ( st2!=NULL ) - (*hm)[bcnt>>3] |= (0x80>>(bcnt&7)); - } - for ( i=0; i<HntMax/8; ++i ) - if ( (*hm)[i]!=0 ) -return( hm ); - -return( NULL ); -} - -static HintMask *HintMaskTransform(HintMask *oldhm,real transform[6], - SplineChar *basesc,SplineChar *subsc) { - HintMask *newhm; - StemInfo *st, *st2; - int cnt, hst_cnt, bcnt; - real start, width; - - if ( transform[1]!=0 || transform[2]!=0 ) -return( NULL ); - - newhm = chunkalloc(sizeof(HintMask)); - for ( st = subsc->hstem,cnt = 0; st!=NULL; st=st->next, cnt++ ) { - if ( (*oldhm)[cnt>>3]&(0x80>>(cnt&7)) ) { - start = st->start*transform[3] + transform[5]; - width = st->width*transform[3]; - for ( st2=basesc->hstem,bcnt=0; st2!=NULL; st2=st2->next, bcnt++ ) - if ( st2->start == start && st2->width == width ) - break; - if ( st2!=NULL ) - (*newhm)[bcnt>>3] |= (0x80>>(bcnt&7)); - } - } - for ( st2=basesc->hstem,hst_cnt=0; st2!=NULL; st2=st2->next, hst_cnt++ ); - - for ( st = subsc->vstem; st!=NULL; st=st->next, cnt++ ) { - if ( (*oldhm)[cnt>>3]&(0x80>>(cnt&7)) ) { - start = st->start*transform[0] + transform[4]; - width = st->width*transform[0]; - for ( st2=basesc->vstem,bcnt=hst_cnt; st2!=NULL; st2=st2->next, bcnt++ ) - if ( st2->start == start && st2->width == width ) - break; - if ( st2!=NULL ) - (*newhm)[bcnt>>3] |= (0x80>>(bcnt&7)); - } - } -return( newhm ); -} - -SplinePointList *SPLCopyTranslatedHintMasks(SplinePointList *base, - SplineChar *basesc, SplineChar *subsc, BasePoint *trans ) { - SplinePointList *spl, *spl2, *head; - SplinePoint *spt, *spt2, *pfirst; - real transform[6]; - Spline *s, *first; - - head = SplinePointListCopy(base); - - transform[0] = transform[3] = 1; transform[1] = transform[2] = 0; - transform[4] = trans->x; transform[5] = trans->y; - - for ( spl = head, spl2=base; spl!=NULL; spl = spl->next, spl2 = spl2->next ) { - pfirst = NULL; - for ( spt = spl->first, spt2 = spl2->first ; spt!=pfirst; spt = spt->next->to, spt2 = spt2->next->to ) { - if ( pfirst==NULL ) pfirst = spt; - TransformPoint(spt,transform); - if ( spt2->hintmask ) { - chunkfree(spt->hintmask,sizeof(HintMask)); - spt->hintmask = HintMaskTransform(spt2->hintmask,transform,basesc,subsc); - } - if ( spt->next==NULL ) - break; - } - first = NULL; - for ( s = spl->first->next; s!=NULL && s!=first; s=s->to->next ) { - SplineRefigure(s); - if ( first==NULL ) first = s; - } - } -return( head ); -} - -static SplinePointList *_SPLCopyTransformedHintMasks(SplineChar *subsc,int layer, - real transform[6], SplineChar *basesc ) { - SplinePointList *spl, *spl2, *head, *last=NULL, *cur, *base; - SplinePoint *spt, *spt2, *pfirst; - Spline *s, *first; - real trans[6]; - RefChar *rf; - - base = subsc->layers[layer].splines; - head = SplinePointListCopy(base); - if ( head!=NULL ) - for ( last = head; last->next!=NULL; last=last->next ); - - for ( spl = head, spl2=base; spl!=NULL; spl = spl->next, spl2=spl2->next ) { - pfirst = NULL; - for ( spt = spl->first, spt2 = spl2->first ; spt!=pfirst; spt = spt->next->to, spt2 = spt2->next->to ) { - if ( pfirst==NULL ) pfirst = spt; - TransformPoint(spt,transform); - if ( spt2->hintmask ) { - chunkfree(spt->hintmask,sizeof(HintMask)); - spt->hintmask = HintMaskTransform(spt2->hintmask,transform,basesc,subsc); - } - if ( spt->next==NULL ) - break; - } - first = NULL; - for ( s = spl->first->next; s!=NULL && s!=first; s=s->to->next ) { - SplineRefigure(s); - if ( first==NULL ) first = s; - } - } - for ( rf=subsc->layers[layer].refs; rf!=NULL; rf=rf->next ) { - trans[0] = rf->transform[0]*transform[0] + - rf->transform[1]*transform[2]; - trans[1] = rf->transform[0]*transform[1] + - rf->transform[1]*transform[3]; - trans[2] = rf->transform[2]*transform[0] + - rf->transform[3]*transform[2]; - trans[3] = rf->transform[2]*transform[1] + - rf->transform[3]*transform[3]; - trans[4] = rf->transform[4]*transform[0] + - rf->transform[5]*transform[2] + - transform[4]; - trans[5] = rf->transform[4]*transform[1] + - rf->transform[5]*transform[3] + - transform[5]; - cur = _SPLCopyTransformedHintMasks(rf->sc,layer,trans,basesc); - if ( head==NULL ) - head = cur; - else - last->next = cur; - if ( cur!=NULL ) { - while ( cur->next!=NULL ) cur = cur->next; - last = cur; - } - } -return( head ); -} - -SplinePointList *SPLCopyTransformedHintMasks(RefChar *r, - SplineChar *basesc, BasePoint *trans,int layer ) { - real transform[6]; - - memcpy(transform,r->transform,sizeof(transform)); - transform[4] += trans->x; transform[5] += trans->y; -return( _SPLCopyTransformedHintMasks(r->sc,layer,transform,basesc)); -} - -void SCMakeDependent(SplineChar *dependent,SplineChar *base) { - struct splinecharlist *dlist; - - if ( dependent->searcherdummy ) -return; - - for ( dlist=base->dependents; dlist!=NULL && dlist->sc!=dependent; dlist = dlist->next); - if ( dlist==NULL ) { - dlist = chunkalloc(sizeof(struct splinecharlist)); - dlist->sc = dependent; - dlist->next = base->dependents; - base->dependents = dlist; - } -} - -static void LayerToRefLayer(struct reflayer *rl,Layer *layer, real transform[6]) { - BrushCopy(&rl->fill_brush, &layer->fill_brush,transform); - PenCopy(&rl->stroke_pen, &layer->stroke_pen,transform); - rl->dofill = layer->dofill; - rl->dostroke = layer->dostroke; - rl->fillfirst = layer->fillfirst; -} - -int RefLayerFindBaseLayerIndex(RefChar *rf, int layer) { - // Note that most of the logic below is copied and lightly modified from SCReinstanciateRefChar. - SplineChar *rsc = rf->sc; - int i = 0, j = 0, cnt = 0; - RefChar *subref; - for ( i=ly_fore; i<rsc->layer_cnt; ++i ) { - if ( rsc->layers[i].splines!=NULL) { - if (cnt == layer) return i; - ++cnt; - } - for ( subref=rsc->layers[i].refs; subref!=NULL; subref=subref->next ) { - for ( j=0; j<subref->layer_cnt; ++j ) if ( subref->layers[j].splines!=NULL ) { - if (cnt == layer) return i; - ++cnt; - } - } - } - return -1; -} - -void RefCharFindBounds(RefChar *rf) { - int i; - SplineChar *rsc = rf->sc; - real extra=0,e; - - memset(&rf->bb,'\0',sizeof(rf->bb)); - rf->top.y = -1e10; - for ( i=0; i<rf->layer_cnt; ++i ) { - _SplineSetFindBounds(rf->layers[i].splines,&rf->bb); - _SplineSetFindTop(rf->layers[i].splines,&rf->top); - int baselayer = RefLayerFindBaseLayerIndex(rf, i); - if ( baselayer >= 0 && rsc->layers[baselayer].dostroke ) { - if ( rf->layers[i].stroke_pen.width!=WIDTH_INHERITED ) - e = rf->layers[i].stroke_pen.width*rf->layers[i].stroke_pen.trans[0]; - else - e = rf->layers[i].stroke_pen.trans[0]; - if ( e>extra ) extra = e; - } - } - if ( rf->top.y < -65536 ) rf->top.y = rf->top.x = 0; - rf->bb.minx -= extra; rf->bb.miny -= extra; - rf->bb.maxx += extra; rf->bb.maxy += extra; -} - -void SCReinstanciateRefChar(SplineChar *sc,RefChar *rf,int layer) { - SplinePointList *new, *last; - RefChar *refs; - int i,j; - SplineChar *rsc = rf->sc; - real extra=0,e; - - for ( i=0; i<rf->layer_cnt; ++i ) { - SplinePointListsFree(rf->layers[i].splines); - GradientFree(rf->layers[i].fill_brush.gradient); - PatternFree(rf->layers[i].fill_brush.pattern); - GradientFree(rf->layers[i].stroke_pen.brush.gradient); - PatternFree(rf->layers[i].stroke_pen.brush.pattern); - } - free( rf->layers ); - rf->layers = NULL; - rf->layer_cnt = 0; - if ( rsc==NULL ) -return; - /* Can be called before sc->parent is set, but only when reading a ttf */ - /* file which won't be multilayer */ - if ( sc->parent!=NULL && sc->parent->multilayer ) { - int cnt = 0; - RefChar *subref; - for ( i=ly_fore; i<rsc->layer_cnt; ++i ) { - if ( rsc->layers[i].splines!=NULL) - ++cnt; - for ( subref=rsc->layers[i].refs; subref!=NULL; subref=subref->next ) - cnt += subref->layer_cnt; - } - - rf->layer_cnt = cnt; - rf->layers = calloc(cnt,sizeof(struct reflayer)); - cnt = 0; - for ( i=ly_fore; i<rsc->layer_cnt; ++i ) { - if ( rsc->layers[i].splines!=NULL ) { - rf->layers[cnt].splines = - SplinePointListTransform( - SplinePointListCopy(rsc->layers[i].splines),rf->transform,tpt_AllPoints); - LayerToRefLayer(&rf->layers[cnt],&rsc->layers[i],rf->transform); - ++cnt; - } - for ( subref=rsc->layers[i].refs; subref!=NULL; subref=subref->next ) { - for ( j=0; j<subref->layer_cnt; ++j ) if ( subref->layers[j].splines!=NULL ) { - rf->layers[cnt] = subref->layers[j]; - rf->layers[cnt].splines = - SplinePointListTransform( - SplinePointListCopy(subref->layers[j].splines),rf->transform,tpt_AllPoints); - ++cnt; - } - } - } - - memset(&rf->bb,'\0',sizeof(rf->bb)); - rf->top.y = -1e10; - for ( i=0; i<rf->layer_cnt; ++i ) { - _SplineSetFindBounds(rf->layers[i].splines,&rf->bb); - _SplineSetFindTop(rf->layers[i].splines,&rf->top); - int baselayer = RefLayerFindBaseLayerIndex(rf, i); - if ( baselayer >= 0 && rsc->layers[baselayer].dostroke ) { - if ( rf->layers[i].stroke_pen.width!=WIDTH_INHERITED ) - e = rf->layers[i].stroke_pen.width*rf->layers[i].stroke_pen.trans[0]; - else - e = rf->layers[i].stroke_pen.trans[0]; - if ( e>extra ) extra = e; - } - } - if ( rf->top.y < -65536 ) rf->top.y = rf->top.x = 0; - rf->bb.minx -= extra; rf->bb.miny -= extra; - rf->bb.maxx += extra; rf->bb.maxy += extra; - } else { - if ( rf->layer_cnt>0 ) { - SplinePointListsFree(rf->layers[0].splines); - rf->layers[0].splines = NULL; - } - rf->layers = calloc(1,sizeof(struct reflayer)); - rf->layer_cnt = 1; - rf->layers[0].dofill = true; - new = SplinePointListTransform(SplinePointListCopy(rf->sc->layers[layer].splines),rf->transform,tpt_AllPoints); - rf->layers[0].splines = new; - last = NULL; - if ( new!=NULL ) - for ( last = new; last->next!=NULL; last = last->next ); - for ( refs = rf->sc->layers[layer].refs; refs!=NULL; refs = refs->next ) { - new = SplinePointListTransform(SplinePointListCopy(refs->layers[0].splines),rf->transform,tpt_AllPoints); - if ( last!=NULL ) - last->next = new; - else - rf->layers[0].splines = new; - if ( new!=NULL ) - for ( last = new; last->next!=NULL; last = last->next ); - } - } - RefCharFindBounds(rf); -} - -/* This returns all real solutions, even those out of bounds */ -/* I use -999999 as an error flag, since we're really only interested in */ -/* solns near 0 and 1 that should be ok. -1 is perhaps a little too close */ -/* Sigh. When solutions are near 0, the rounding errors are appalling. */ -int _CubicSolve(const Spline1D *sp,bigreal sought, extended ts[3]) { - extended d, xN, yN, delta2, temp, delta, h, t2, t3, theta; - extended sa=sp->a, sb=sp->b, sc=sp->c, sd=sp->d-sought; - int i=0; - - ts[0] = ts[1] = ts[2] = -999999; - if ( sd==0 && sa!=0 ) { - /* one of the roots is 0, the other two are the soln of a quadratic */ - ts[0] = 0; - if ( sc==0 ) { - ts[1] = -sb/(extended) sa; /* two zero roots */ - } else { - temp = sb*(extended) sb-4*(extended) sa*sc; - if ( RealNear(temp,0)) - ts[1] = -sb/(2*(extended) sa); - else if ( temp>=0 ) { - temp = sqrt(temp); - ts[1] = (-sb+temp)/(2*(extended) sa); - ts[2] = (-sb-temp)/(2*(extended) sa); - } - } - } else if ( sa!=0 ) { - /* http://www.m-a.org.uk/eb/mg/mg077ch.pdf */ - /* this nifty solution to the cubic neatly avoids complex arithmatic */ - xN = -sb/(3*(extended) sa); - yN = ((sa*xN + sb)*xN+sc)*xN + sd; - - delta2 = (sb*(extended) sb-3*(extended) sa*sc)/(9*(extended) sa*sa); - /*if ( RealWithin(delta2,0,.00000001) ) delta2 = 0;*/ - - /* the descriminant is yN^2-h^2, but delta might be <0 so avoid using h */ - d = yN*yN - 4*sa*sa*delta2*delta2*delta2; - if ( ((yN>.01 || yN<-.01) && RealNear(d/yN,0)) || ((yN<=.01 && yN>=-.01) && RealNear(d,0)) ) - d = 0; - if ( d>0 ) { - temp = sqrt(d); - t2 = (-yN-temp)/(2*sa); - t2 = (t2==0) ? 0 : (t2<0) ? -pow(-t2,1./3.) : pow(t2,1./3.); - t3 = (-yN+temp)/(2*sa); - t3 = t3==0 ? 0 : (t3<0) ? -pow(-t3,1./3.) : pow(t3,1./3.); - ts[0] = xN + t2 + t3; - } else if ( d<0 ) { - if ( delta2>=0 ) { - delta = sqrt(delta2); - h = 2*sa*delta2*delta; - temp = -yN/h; - if ( temp>=-1.0001 && temp<=1.0001 ) { - if ( temp<-1 ) temp = -1; else if ( temp>1 ) temp = 1; - theta = acos(temp)/3; - ts[i++] = xN+2*delta*cos(theta); - ts[i++] = xN+2*delta*cos(2.0943951+theta); /* 2*pi/3 */ - ts[i++] = xN+2*delta*cos(4.1887902+theta); /* 4*pi/3 */ - } - } - } else if ( /* d==0 && */ delta2!=0 ) { - delta = yN/(2*sa); - delta = delta==0 ? 0 : delta>0 ? pow(delta,1./3.) : -pow(-delta,1./3.); - ts[i++] = xN + delta; /* this root twice, but that's irrelevant to me */ - ts[i++] = xN - 2*delta; - } else if ( /* d==0 && */ delta2==0 ) { - if ( xN>=-0.0001 && xN<=1.0001 ) ts[0] = xN; - } - } else if ( sb!=0 ) { - extended d = sc*(extended) sc-4*(extended) sb*sd; - if ( d<0 && RealNear(d,0)) d=0; - if ( d<0 ) -return(false); /* All roots imaginary */ - d = sqrt(d); - ts[0] = (-sc-d)/(2*(extended) sb); - ts[1] = (-sc+d)/(2*(extended) sb); - } else if ( sc!=0 ) { - ts[0] = -sd/(extended) sc; - } else { - /* If it's a point then either everything is a solution, or nothing */ - } -return( ts[0]!=-999999 ); -} - -int CubicSolve(const Spline1D *sp,bigreal sought, extended ts[3]) { - extended t; - extended ts2[3]; - int i,j; - /* This routine gives us all solutions between [0,1] with -1 as an error flag */ - /* http://mathforum.org/dr.math/faq/faq.cubic.equations.html */ - - ts[0] = ts[1] = ts[2] = -1; - if ( !_CubicSolve(sp,sought,ts2)) { -return( false ); - } - - for ( i=j=0; i<3; ++i ) { - if ( ts2[i]>-.0001 && ts2[i]<1.0001 ) { - if ( ts2[i]<0 ) ts[j++] = 0; - else if ( ts2[i]>1 ) ts[j++] = 1; - else - ts[j++] = ts2[i]; - } - } - if ( j==0 ) -return( false ); - - if ( ts[0]>ts[2] && ts[2]!=-1 ) { - t = ts[0]; ts[0] = ts[2]; ts[2] = t; - } - if ( ts[0]>ts[1] && ts[1]!=-1 ) { - t = ts[0]; ts[0] = ts[1]; ts[1] = t; - } - if ( ts[1]>ts[2] && ts[2]!=-1 ) { - t = ts[1]; ts[1] = ts[2]; ts[2] = t; - } -return( true ); -} - -/* An IEEE double has 52 bits of precision. So one unit of rounding error will be */ -/* the number divided by 2^51 */ -# define D_RE_Factor (1024.0*1024.0*1024.0*1024.0*1024.0*2.0) -/* But that's not going to work near 0, so, since the t values we care about */ -/* are [0,1], let's use 1.0/D_RE_Factor */ - -extended IterateSplineSolve(const Spline1D *sp, extended tmin, extended tmax, - extended sought) { - extended t, low, high, test; - Spline1D temp; - /* Now the closed form CubicSolver can have rounding errors so if we know */ - /* the spline to be monotonic, an iterative approach is more accurate */ - - if ( tmin>tmax ) { - t=tmin; tmin=tmax; tmax=t; - } - - temp = *sp; - temp.d -= sought; - - if ( temp.a==0 && temp.b==0 && temp.c!=0 ) { - t = -temp.d/(extended) temp.c; - if ( t<tmin || t>tmax ) -return( -1 ); -return( t ); - } - - low = ((temp.a*tmin+temp.b)*tmin+temp.c)*tmin+temp.d; - high = ((temp.a*tmax+temp.b)*tmax+temp.c)*tmax+temp.d; - if ( low==0 ) -return(tmin); - if ( high==0 ) -return(tmax); - if (( low<0 && high>0 ) || - ( low>0 && high<0 )) { - - for (;;) { - t = (tmax+tmin)/2; - if ( t==tmax || t==tmin ) -return( t ); - test = ((temp.a*t+temp.b)*t+temp.c)*t+temp.d; - if ( test==0 ) /* someone complained that this test relied on exact arithmetic. In fact this test will almost never be hit, the real exit test is the line above, when tmin/tmax are so close that there is no space between them in the floating representation */ -return( t ); - if ( (low<0 && test<0) || (low>0 && test>0) ) - tmin=t; - else - tmax = t; - } - } else if ( low<.0001 && low>-.0001 ) -return( tmin ); /* Rounding errors */ - else if ( high<.0001 && high>-.0001 ) -return( tmax ); - -return( -1 ); -} - -extended IterateSplineSolveFixup(const Spline1D *sp, extended tmin, extended tmax, - extended sought) { - // Search between tmin and tmax for a t-value at which the spline outputs sought. - extended t; - bigreal factor; - extended val, valp, valm; - - if ( tmin>tmax ) { - t=tmin; tmin=tmax; tmax=t; - } - - t = IterateSplineSolve(sp,tmin,tmax,sought); - - if ( t==-1 ) -return( -1 ); - - if ((val = (((sp->a*t+sp->b)*t+sp->c)*t+sp->d) - sought)<0 ) - val=-val; - if ( val!=0 ) { - for ( factor=1024.0*1024.0*1024.0*1024.0*1024.0; factor>.5; factor/=2.0 ) { - extended tp = t + (factor*t)/D_RE_Factor; - extended tm = t - (factor*t)/D_RE_Factor; - if ( tp>tmax ) tp=tmax; - if ( tm<tmin ) tm=tmin; - if ( (valp = (((sp->a*tp+sp->b)*tp+sp->c)*tp+sp->d) - sought)<0 ) - valp = -valp; - if ( (valm = (((sp->a*tm+sp->b)*tm+sp->c)*tm+sp->d) - sought)<0 ) - valm = -valm; - if ( valp<val && valp<valm ) { - t = tp; - val = valp; - } else if ( valm<val ) { - t = tm; - val = valm; - } - } - } - if ( t==0 && !Within16RoundingErrors(sought,sought+val)) -return( -1 ); - /* if t!=0 then we we get the chance of far worse rounding errors */ - else if ( t==tmax || t==tmin ) { - if ( Within16RoundingErrors(sought,sought+val) || - Within16RoundingErrors(sp->a,sp->a+val) || - Within16RoundingErrors(sp->b,sp->b+val) || - Within16RoundingErrors(sp->c,sp->c+val) || - Within16RoundingErrors(sp->c,sp->c+val) || - Within16RoundingErrors(sp->d,sp->d+val)) -return( t ); - else -return( -1 ); - } - - if ( t>=tmin && t<=tmax ) -return( t ); - - /* I don't think this can happen... */ -return( -1 ); -} - -double CheckExtremaForSingleBitErrors(const Spline1D *sp, double t, double othert) { - double u1, um1; - double slope, slope1, slopem1; - int err; - double diff, factor; - - if ( t<0 || t>1 ) -return( t ); - - factor = t*0x40000/D_RE_Factor; - if ( (diff = t-othert)<0 ) diff= -diff; - if ( factor>diff/4 && diff!=0 ) /* This little check is to insure we don't skip beyond the well of this extremum into the next */ - factor = diff/4; - - slope = (3*(double) sp->a*t+2*sp->b)*t+sp->c; - if ( slope<0 ) slope = -slope; - - for ( err = 0x40000; err!=0; err>>=1 ) { - u1 = t+factor; - slope1 = (3*(double) sp->a*u1+2*sp->b)*u1+sp->c; - if ( slope1<0 ) slope1 = -slope1; - - um1 = t-factor; - slopem1 = (3*(double) sp->a*um1+2*sp->b)*um1+sp->c; - if ( slopem1<0 ) slopem1 = -slopem1; - - if ( slope1<slope && slope1<=slopem1 && u1<=1.0 ) { - t = u1; - } else if ( slopem1<slope && slopem1<=slope1 && um1>=0.0 ) { - t = um1; - } - factor /= 2.0; - } - /* that seems as good as it gets */ - -return( t ); -} - -void SplineFindExtrema(const Spline1D *sp, extended *_t1, extended *_t2 ) { - extended t1= -1, t2= -1; - extended b2_fourac; - - /* Find the extreme points on the curve */ - /* Set to -1 if there are none or if they are outside the range [0,1] */ - /* Order them so that t1<t2 */ - /* If only one valid extremum it will be t1 */ - /* (Does not check the end points unless they have derivative==0) */ - /* (Does not check to see if d/dt==0 points are inflection points (rather than extrema) */ - if ( sp->a!=0 ) { - /* cubic, possibly 2 extrema (possibly none) */ - b2_fourac = 4*(extended) sp->b*sp->b - 12*(extended) sp->a*sp->c; - if ( b2_fourac>=0 ) { - b2_fourac = sqrt(b2_fourac); - t1 = (-2*sp->b - b2_fourac) / (6*sp->a); - t2 = (-2*sp->b + b2_fourac) / (6*sp->a); - t1 = CheckExtremaForSingleBitErrors(sp,t1,t2); - t2 = CheckExtremaForSingleBitErrors(sp,t2,t1); - if ( t1>t2 ) { extended temp = t1; t1 = t2; t2 = temp; } - else if ( t1==t2 ) t2 = -1; - if ( RealNear(t1,0)) t1=0; else if ( RealNear(t1,1)) t1=1; - if ( RealNear(t2,0)) t2=0; else if ( RealNear(t2,1)) t2=1; - if ( t2<=0 || t2>=1 ) t2 = -1; - if ( t1<=0 || t1>=1 ) { t1 = t2; t2 = -1; } - } - } else if ( sp->b!=0 ) { - /* Quadratic, at most one extremum */ - t1 = -sp->c/(2.0*(extended) sp->b); - if ( t1<=0 || t1>=1 ) t1 = -1; - } else /*if ( sp->c!=0 )*/ { - /* linear, no extrema */ - } - *_t1 = t1; *_t2 = t2; -} - -bigreal SplineCurvature(Spline *s, bigreal t) { - /* Kappa = (x'y'' - y'x'') / (x'^2 + y'^2)^(3/2) */ - bigreal dxdt, dydt, d2xdt2, d2ydt2, denom, numer; - - if ( s==NULL ) -return( CURVATURE_ERROR ); - - dxdt = (3*s->splines[0].a*t+2*s->splines[0].b)*t+s->splines[0].c; - dydt = (3*s->splines[1].a*t+2*s->splines[1].b)*t+s->splines[1].c; - d2xdt2 = 6*s->splines[0].a*t + 2*s->splines[0].b; - d2ydt2 = 6*s->splines[1].a*t + 2*s->splines[1].b; - denom = pow( dxdt*dxdt + dydt*dydt, 3.0/2.0 ); - numer = dxdt*d2ydt2 - dydt*d2xdt2; - - if ( numer==0 ) -return( 0 ); - if ( denom==0 ) -return( CURVATURE_ERROR ); - -return( numer/denom ); -} - -int Spline2DFindExtrema(const Spline *sp, extended extrema[4] ) { - int i,j; - BasePoint last, cur, mid; - - /* If the control points are at the end-points then this (1D) spline is */ - /* basically a line. But rounding errors can give us very faint extrema */ - /* if we look for them */ - if ( !Spline1DCantExtremeX(sp) ) - SplineFindExtrema(&sp->splines[0],&extrema[0],&extrema[1]); - else - extrema[0] = extrema[1] = -1; - if ( !Spline1DCantExtremeY(sp) ) - SplineFindExtrema(&sp->splines[1],&extrema[2],&extrema[3]); - else - extrema[2] = extrema[3] = -1; - - for ( i=0; i<3; ++i ) for ( j=i+1; j<4; ++j ) { - if ( (extrema[i]==-1 && extrema[j]!=-1) || (extrema[i]>extrema[j] && extrema[j]!=-1) ) { - extended temp = extrema[i]; - extrema[i] = extrema[j]; - extrema[j] = temp; - } - } - for ( i=j=0; i<3 && extrema[i]!=-1; ++i ) { - if ( extrema[i]==extrema[i+1] ) { - for ( j=i+1; j<3; ++j ) - extrema[j] = extrema[j+1]; - extrema[3] = -1; - } - } - - /* Extrema which are too close together are not interesting */ - last = sp->from->me; - for ( i=0; i<4 && extrema[i]!=-1; ++i ) { - cur.x = ((sp->splines[0].a*extrema[i]+sp->splines[0].b)*extrema[i]+ - sp->splines[0].c)*extrema[i]+sp->splines[0].d; - cur.y = ((sp->splines[1].a*extrema[i]+sp->splines[1].b)*extrema[i]+ - sp->splines[1].c)*extrema[i]+sp->splines[1].d; - mid.x = (last.x+cur.x)/2; mid.y = (last.y+cur.y)/2; - if ( (mid.x==last.x || mid.x==cur.x) && - (mid.y==last.y || mid.y==cur.y)) { - for ( j=i; j<3; ++j ) - extrema[j] = extrema[j+1]; - extrema[3] = -1; - --i; - } else - last = cur; - } - if ( extrema[0]!=-1 ) { - mid.x = (last.x+sp->to->me.x)/2; mid.y = (last.y+sp->to->me.y)/2; - if ( (mid.x==last.x || mid.x==cur.x) && - (mid.y==last.y || mid.y==cur.y)) - extrema[i-1] = -1; - } - for ( i=0; i<4 && extrema[i]!=-1; ++i ); - if ( i!=0 ) { - cur = sp->to->me; - mid.x = (last.x+cur.x)/2; mid.y = (last.y+cur.y)/2; - if ( (mid.x==last.x || mid.x==cur.x) && - (mid.y==last.y || mid.y==cur.y)) - extrema[--i] = -1; - } - -return( i ); -} - -int Spline2DFindPointsOfInflection(const Spline *sp, extended poi[2] ) { - int cnt=0; - extended a, b, c, b2_fourac, t; - /* A POI happens when d2 y/dx2 is zero. This is not the same as d2y/dt2 / d2x/dt2 */ - /* d2 y/dx^2 = d/dt ( dy/dt / dx/dt ) / dx/dt */ - /* = ( (dx/dt) * d2 y/dt2 - ((dy/dt) * d2 x/dt2) )/ (dx/dt)^3 */ - /* (3ax*t^2+2bx*t+cx) * (6ay*t+2by) - (3ay*t^2+2by*t+cy) * (6ax*t+2bx) == 0 */ - /* (3ax*t^2+2bx*t+cx) * (3ay*t+by) - (3ay*t^2+2by*t+cy) * (3ax*t+bx) == 0 */ - /* 9*ax*ay*t^3 + (3ax*by+6bx*ay)*t^2 + (2bx*by+3cx*ay)*t + cx*by */ - /* -(9*ax*ay*t^3 + (3ay*bx+6by*ax)*t^2 + (2by*bx+3cy*ax)*t + cy*bx)==0 */ - /* 3*(ax*by-ay*bx)*t^2 + 3*(cx*ay-cy*ax)*t+ (cx*by-cy*bx) == 0 */ - - a = 3*((extended) sp->splines[1].a*sp->splines[0].b-(extended) sp->splines[0].a*sp->splines[1].b); - b = 3*((extended) sp->splines[0].c*sp->splines[1].a - (extended) sp->splines[1].c*sp->splines[0].a); - c = (extended) sp->splines[0].c*sp->splines[1].b-(extended) sp->splines[1].c*sp->splines[0].b; - if ( !RealNear(a,0) ) { - b2_fourac = b*b - 4*a*c; - poi[0] = poi[1] = -1; - if ( b2_fourac<0 ) -return( 0 ); - b2_fourac = sqrt( b2_fourac ); - t = (-b+b2_fourac)/(2*a); - if ( t>=0 && t<=1.0 ) - poi[cnt++] = t; - t = (-b-b2_fourac)/(2*a); - if ( t>=0 && t<=1.0 ) { - if ( cnt==1 && poi[0]>t ) { - poi[1] = poi[0]; - poi[0] = t; - ++cnt; - } else - poi[cnt++] = t; - } - } else if ( !RealNear(b,0) ) { - t = -c/b; - if ( t>=0 && t<=1.0 ) - poi[cnt++] = t; - } - if ( cnt<2 ) - poi[cnt] = -1; - -return( cnt ); -} - -/* Ok, if the above routine finds an extremum that less than 1 unit */ -/* from an endpoint or another extremum, then many things are */ -/* just going to skip over it, and other things will be confused by this */ -/* so just remove it. It should be so close the difference won't matter */ -void SplineRemoveExtremaTooClose(Spline1D *sp, extended *_t1, extended *_t2 ) { - extended last, test; - extended t1= *_t1, t2 = *_t2; - - if ( t1>t2 && t2!=-1 ) { - t1 = t2; - t2 = *_t1; - } - last = sp->d; - if ( t1!=-1 ) { - test = ((sp->a*t1+sp->b)*t1+sp->c)*t1+sp->d; - if ( (test-last)*(test-last)<1 ) - t1 = -1; - else - last = test; - } - if ( t2!=-1 ) { - test = ((sp->a*t2+sp->b)*t2+sp->c)*t2+sp->d; - if ( (test-last)*(test-last)<1 ) - t2 = -1; - else - last = test; - } - test = sp->a+sp->b+sp->c+sp->d; - if ( (test-last)*(test-last)<1 ) { - if ( t2!=-1 ) - t2 = -1; - else if ( t1!=-1 ) - t1 = -1; - else { - /* Well we should just remove the whole spline? */ - ; - } - } - *_t1 = t1; *_t2 = t2; -} - -int IntersectLines(BasePoint *inter, - BasePoint *line1_1, BasePoint *line1_2, - BasePoint *line2_1, BasePoint *line2_2) { - // A lot of functions call this with the same address as an input and the output. - // In order to avoid unexpected behavior, we delay writing to the output until the end. - bigreal s1, s2; - BasePoint _output; - BasePoint * output = &_output; - if ( line1_1->x == line1_2->x ) { - // Line 1 is vertical. - output->x = line1_1->x; - if ( line2_1->x == line2_2->x ) { - // Line 2 is vertical. - if ( line2_1->x!=line1_1->x ) - return( false ); /* Parallel vertical lines */ - output->y = (line1_1->y+line2_1->y)/2; - } else { - output->y = line2_1->y + (output->x-line2_1->x) * (line2_2->y - line2_1->y)/(line2_2->x - line2_1->x); - } - *inter = *output; - return( true ); - } else if ( line2_1->x == line2_2->x ) { - // Line 2 is vertical, but we know that line 1 is not. - output->x = line2_1->x; - output->y = line1_1->y + (output->x-line1_1->x) * (line1_2->y - line1_1->y)/(line1_2->x - line1_1->x); - *inter = *output; - return( true ); - } else { - // Both lines are oblique. - s1 = (line1_2->y - line1_1->y)/(line1_2->x - line1_1->x); - s2 = (line2_2->y - line2_1->y)/(line2_2->x - line2_1->x); - if ( RealNear(s1,s2)) { - if ( !RealNear(line1_1->y + (line2_1->x-line1_1->x) * s1,line2_1->y)) - return( false ); - output->x = (line1_2->x+line2_2->x)/2; - output->y = (line1_2->y+line2_2->y)/2; - } else { - output->x = (s1*line1_1->x - s2*line2_1->x - line1_1->y + line2_1->y)/(s1-s2); - output->y = line1_1->y + (output->x-line1_1->x) * s1; - } - *inter = *output; - return( true ); - } -} - -int IntersectLinesClip(BasePoint *inter, - BasePoint *line1_1, BasePoint *line1_2, - BasePoint *line2_1, BasePoint *line2_2) { - BasePoint old = *inter, unit; - bigreal len, val; - - if ( !IntersectLines(inter,line1_1,line1_2,line2_1,line2_2)) -return( false ); - else { - unit.x = line2_2->x-line1_2->x; - unit.y = line2_2->y-line1_2->y; - len = sqrt(unit.x*unit.x + unit.y*unit.y); - if ( len==0 ) -return( false ); - else { - unit.x /= len; unit.y /= len; - val = unit.x*(inter->x-line1_2->x) + unit.y*(inter->y-line1_2->y); - if ( val<=0 || val>=len ) { - *inter = old; -return( false ); - } - } - } -return( true ); -} - -static int AddPoint(extended x,extended y,extended t,extended s,BasePoint *pts, - extended t1s[3],extended t2s[3], int soln) { - int i; - - for ( i=0; i<soln; ++i ) - if ( x==pts[i].x && y==pts[i].y ) -return( soln ); - if ( soln>=9 ) - IError( "Too many solutions!\n" ); - t1s[soln] = t; - t2s[soln] = s; - pts[soln].x = x; - pts[soln].y = y; -return( soln+1 ); -} - -static void IterateSolve(const Spline1D *sp,extended ts[3]) { - /* The closed form solution has too many rounding errors for my taste... */ - int i,j; - - ts[0] = ts[1] = ts[2] = -1; - - if ( sp->a!=0 ) { - extended e[4]; - e[0] = 0; e[1] = e[2] = e[3] = 1.0; - SplineFindExtrema(sp,&e[1],&e[2]); - if ( e[1]==-1 ) e[1] = 1; - if ( e[2]==-1 ) e[2] = 1; - for ( i=j=0; i<3; ++i ) { - ts[j] = IterateSplineSolve(sp,e[i],e[i+1],0); - if ( ts[j]!=-1 ) ++j; - if ( e[i+1]==1.0 ) - break; - } - } else if ( sp->b!=0 ) { - extended b2_4ac = sp->c*(extended) sp->c - 4*sp->b*(extended) sp->d; - if ( b2_4ac>=0 ) { - b2_4ac = sqrt(b2_4ac); - ts[0] = (-sp->c-b2_4ac)/(2*sp->b); - ts[1] = (-sp->c+b2_4ac)/(2*sp->b); - if ( ts[0]>ts[1] ) { bigreal t = ts[0]; ts[0] = ts[1]; ts[1] = t; } - } - } else if ( sp->c!=0 ) { - ts[0] = -sp->d/(extended) sp->c; - } else { - /* No solutions, or all solutions */ - ; - } - - for ( i=j=0; i<3; ++i ) - if ( ts[i]>=0 && ts[i]<=1 ) - ts[j++] = ts[i]; - for ( i=0; i<j-1; ++i ) - if ( ts[i]+.0000001>ts[i+1]) { - ts[i] = (ts[i]+ts[i+1])/2; - --j; - for ( ++i; i<j; ++i ) - ts[i] = ts[i+1]; - } - if ( j!=0 ) { - if ( ts[0]!=0 ) { - extended d0 = sp->d; - extended dt = ((sp->a*ts[0]+sp->b)*ts[0]+sp->c)*ts[0]+sp->d; - if ( d0<0 ) d0=-d0; - if ( dt<0 ) dt=-dt; - if ( d0<dt ) - ts[0] = 0; - } - if ( ts[j-1]!=1.0 ) { - extended d1 = sp->a+(extended) sp->b+sp->c+sp->d; - extended dt = ((sp->a*ts[j-1]+sp->b)*ts[j-1]+sp->c)*ts[j-1]+sp->d; - if ( d1<0 ) d1=-d1; - if ( dt<0 ) dt=-dt; - if ( d1<dt ) - ts[j-1] = 1; - } - } - for ( ; j<3; ++j ) - ts[j] = -1; -} - -static extended ISolveWithin(const Spline *spline,int major, - extended val,extended tlow, extended thigh) { - Spline1D temp; - extended ts[3]; - const Spline1D *sp = &spline->splines[major]; - int i; - - /* Calculation for t=1 can yield rounding errors. Insist on the endpoints */ - /* (the Spline1D is not a perfectly accurate description of the spline, */ - /* but the control points are right -- at least that's my defn.) */ - if ( tlow==0 && val==(&spline->from->me.x)[major] ) -return( 0 ); - if ( thigh==1.0 && val==(&spline->to->me.x)[major] ) -return( 1.0 ); - - temp = *sp; - temp.d -= val; - IterateSolve(&temp,ts); - if ( tlow<thigh ) { - for ( i=0; i<3; ++i ) - if ( ts[i]>=tlow && ts[i]<=thigh ) -return( ts[i] ); - for ( i=0; i<3; ++i ) { - if ( ts[i]>=tlow-1./1024. && ts[i]<=tlow ) -return( tlow ); - if ( ts[i]>=thigh && ts[i]<=thigh+1./1024 ) -return( thigh ); - } - } else { - for ( i=0; i<3; ++i ) - if ( ts[i]>=thigh && ts[i]<=tlow ) -return( ts[i] ); - for ( i=0; i<3; ++i ) { - if ( ts[i]>=thigh-1./1024. && ts[i]<=thigh ) -return( thigh ); - if ( ts[i]>=tlow && ts[i]<=tlow+1./1024 ) -return( tlow ); - } - } -return( -1 ); -} - -static int ICAddInter(int cnt,BasePoint *foundpos,extended *foundt1,extended *foundt2, - const Spline *s1,const Spline *s2,extended t1,extended t2, int maxcnt) { - - if ( cnt>=maxcnt ) -return( cnt ); - - foundt1[cnt] = t1; - foundt2[cnt] = t2; - foundpos[cnt].x = ((s1->splines[0].a*t1+s1->splines[0].b)*t1+ - s1->splines[0].c)*t1+s1->splines[0].d; - foundpos[cnt].y = ((s1->splines[1].a*t1+s1->splines[1].b)*t1+ - s1->splines[1].c)*t1+s1->splines[1].d; -return( cnt+1 ); -} - -static int ICBinarySearch(int cnt,BasePoint *foundpos,extended *foundt1,extended *foundt2, - int other, - const Spline *s1,const Spline *s2,extended t1low,extended t1high,extended t2low,extended t2high, - int maxcnt) { - int major; - extended t1, t2; - extended o1o, o2o, o1n, o2n, m; - - major = !other; - o1o = ((s1->splines[other].a*t1low+s1->splines[other].b)*t1low+ - s1->splines[other].c)*t1low+s1->splines[other].d; - o2o = ((s2->splines[other].a*t2low+s2->splines[other].b)*t2low+ - s2->splines[other].c)*t2low+s2->splines[other].d; - for (;;) { - t1 = (t1low+t1high)/2; - m = ((s1->splines[major].a*t1+s1->splines[major].b)*t1+ - s1->splines[major].c)*t1+s1->splines[major].d; - t2 = ISolveWithin(s2,major,m,t2low,t2high); - if ( t2==-1 ) -return( cnt ); - - o1n = ((s1->splines[other].a*t1+s1->splines[other].b)*t1+ - s1->splines[other].c)*t1+s1->splines[other].d; - o2n = ((s2->splines[other].a*t2+s2->splines[other].b)*t2+ - s2->splines[other].c)*t2+s2->splines[other].d; - if (( o1n-o2n<.001 && o1n-o2n>-.001) || - (t1-t1low<.0001 && t1-t1low>-.0001)) -return( ICAddInter(cnt,foundpos,foundt1,foundt2,s1,s2,t1,t2,maxcnt)); - if ( (o1o>o2o && o1n<o2n) || (o1o<o2o && o1n>o2n)) { - t1high = t1; - t2high = t2; - } else { - t1low = t1; - t2low = t2; - } - } -} - -static int CubicsIntersect(const Spline *s1,extended lowt1,extended hight1,BasePoint *min1,BasePoint *max1, - const Spline *s2,extended lowt2,extended hight2,BasePoint *min2,BasePoint *max2, - BasePoint *foundpos,extended *foundt1,extended *foundt2, - int maxcnt) { - int major, other; - BasePoint max, min; - extended t1max, t1min, t2max, t2min, t1, t2, t1diff, oldt2; - extended o1o, o2o, o1n, o2n, m; - int cnt=0; - - if ( (min.x = min1->x)<min2->x ) min.x = min2->x; - if ( (min.y = min1->y)<min2->y ) min.y = min2->y; - if ( (max.x = max1->x)>max2->x ) max.x = max2->x; - if ( (max.y = max1->y)>max2->y ) max.y = max2->y; - if ( max.x<min.x || max.y<min.y ) -return( 0 ); - if ( max.x-min.x > max.y-min.y ) - major = 0; - else - major = 1; - other = 1-major; - - t1max = ISolveWithin(s1,major,(&max.x)[major],lowt1,hight1); - t1min = ISolveWithin(s1,major,(&min.x)[major],lowt1,hight1); - t2max = ISolveWithin(s2,major,(&max.x)[major],lowt2,hight2); - t2min = ISolveWithin(s2,major,(&min.x)[major],lowt2,hight2); - if ( t1max==-1 || t1min==-1 || t2max==-1 || t2min==-1 ) -return( 0 ); - t1diff = (t1max-t1min)/64.0; - if (RealNear(t1diff,0)) -return( 0 ); - - t1 = t1min; t2 = t2min; - o1o = t1==0 ? (&s1->from->me.x)[other] : - t1==1.0 ? (&s1->to->me.x)[other] : - ((s1->splines[other].a*t1+s1->splines[other].b)*t1+ - s1->splines[other].c)*t1+s1->splines[other].d; - o2o = t2==0 ? (&s2->from->me.x)[other] : - t2==1.0 ? (&s2->to->me.x)[other] : - ((s2->splines[other].a*t2+s2->splines[other].b)*t2+ - s2->splines[other].c)*t2+s2->splines[other].d; - if ( o1o==o2o ) - cnt = ICAddInter(cnt,foundpos,foundt1,foundt2,s1,s2,t1,t2,maxcnt); - for (;;) { - if ( cnt>=maxcnt ) - break; - t1 += t1diff; - if (( t1max>t1min && t1>t1max ) || (t1max<t1min && t1<t1max) || cnt>3 ) - break; - m = t1==0 ? (&s1->from->me.x)[major] : - t1==1.0 ? (&s1->to->me.x)[major] : - ((s1->splines[major].a*t1+s1->splines[major].b)*t1+ - s1->splines[major].c)*t1+s1->splines[major].d; - oldt2 = t2; - t2 = ISolveWithin(s2,major,m,lowt2,hight2); - if ( t2==-1 ) - continue; - - o1n = t1==0 ? (&s1->from->me.x)[other] : - t1==1.0 ? (&s1->to->me.x)[other] : - ((s1->splines[other].a*t1+s1->splines[other].b)*t1+ - s1->splines[other].c)*t1+s1->splines[other].d; - o2n = t2==0 ? (&s2->from->me.x)[other] : - t2==1.0 ? (&s2->to->me.x)[other] : - ((s2->splines[other].a*t2+s2->splines[other].b)*t2+ - s2->splines[other].c)*t2+s2->splines[other].d; - if ( o1n==o2n ) - cnt = ICAddInter(cnt,foundpos,foundt1,foundt2,s1,s2,t1,t2,maxcnt); - if ( (o1o>o2o && o1n<o2n) || (o1o<o2o && o1n>o2n)) - cnt = ICBinarySearch(cnt,foundpos,foundt1,foundt2,other, - s1,s2,t1-t1diff,t1,oldt2,t2,maxcnt); - o1o = o1n; o2o = o2n; - } -return( cnt ); -} - -static int Closer(const Spline *s1,const Spline *s2,extended t1,extended t2,extended t1p,extended t2p) { - bigreal x1 = ((s1->splines[0].a*t1+s1->splines[0].b)*t1+s1->splines[0].c)*t1+s1->splines[0].d; - bigreal y1 = ((s1->splines[1].a*t1+s1->splines[1].b)*t1+s1->splines[1].c)*t1+s1->splines[1].d; - bigreal x2 = ((s2->splines[0].a*t2+s2->splines[0].b)*t2+s2->splines[0].c)*t2+s2->splines[0].d; - bigreal y2 = ((s2->splines[1].a*t2+s2->splines[1].b)*t2+s2->splines[1].c)*t2+s2->splines[1].d; - bigreal diff = (x1-x2)*(x1-x2) + (y1-y2)*(y1-y2); - bigreal x1p = ((s1->splines[0].a*t1p+s1->splines[0].b)*t1p+s1->splines[0].c)*t1p+s1->splines[0].d; - bigreal y1p = ((s1->splines[1].a*t1p+s1->splines[1].b)*t1p+s1->splines[1].c)*t1p+s1->splines[1].d; - bigreal x2p = ((s2->splines[0].a*t2p+s2->splines[0].b)*t2p+s2->splines[0].c)*t2p+s2->splines[0].d; - bigreal y2p = ((s2->splines[1].a*t2p+s2->splines[1].b)*t2p+s2->splines[1].c)*t2p+s2->splines[1].d; - bigreal diffp = (x1p-x2p)*(x1p-x2p) + (y1p-y2p)*(y1p-y2p); - - if ( diff<diffp ) -return( false ); - -return( true ); -} - -/* returns 0=>no intersection, 1=>at least one, location in pts, t1s, t2s */ -/* -1 => We couldn't figure it out in a closed form, have to do a numerical */ -/* approximation */ -int SplinesIntersect(const Spline *s1, const Spline *s2, BasePoint pts[9], - extended t1s[10], extended t2s[10]) { /* One extra for a trailing -1 */ - BasePoint min1, max1, min2, max2; - int soln = 0; - extended x,y,t, ac0, ac1; - int i,j,found; - Spline1D spline; - extended tempts[4]; /* 3 solns for cubics, 4 for quartics */ - extended extrema1[6], extrema2[6]; - int ecnt1, ecnt2; - - t1s[0] = t1s[1] = t1s[2] = t1s[3] = -1; - t2s[0] = t2s[1] = t2s[2] = t2s[3] = -1; - - if ( s1==s2 && !s1->knownlinear && !s1->isquadratic ) - /* Special case see if it doubles back on itself anywhere */; - else if ( s1==s2 ) -return( 0 ); /* Linear and quadratics can't double back, can't self-intersect */ - else if ( s1->splines[0].a == s2->splines[0].a && - s1->splines[0].b == s2->splines[0].b && - s1->splines[0].c == s2->splines[0].c && - s1->splines[0].d == s2->splines[0].d && - s1->splines[1].a == s2->splines[1].a && - s1->splines[1].b == s2->splines[1].b && - s1->splines[1].c == s2->splines[1].c && - s1->splines[1].d == s2->splines[1].d ) -return( -1 ); /* Same spline. Intersects everywhere */ - - /* Ignore splines which are just a point */ - if ( s1->knownlinear && s1->splines[0].c==0 && s1->splines[1].c==0 ) -return( 0 ); - if ( s2->knownlinear && s2->splines[0].c==0 && s2->splines[1].c==0 ) -return( 0 ); - - if ( s1->knownlinear ) - /* Do Nothing */; - else if ( s2->knownlinear || (!s1->isquadratic && s2->isquadratic)) { - const Spline *stemp = s1; - extended *ts = t1s; - t1s = t2s; t2s = ts; - s1 = s2; s2 = stemp; - } - - min1 = s1->from->me; max1 = min1; - min2 = s2->from->me; max2 = min2; - if ( s1->from->nextcp.x>max1.x ) max1.x = s1->from->nextcp.x; - else if ( s1->from->nextcp.x<min1.x ) min1.x = s1->from->nextcp.x; - if ( s1->from->nextcp.y>max1.y ) max1.y = s1->from->nextcp.y; - else if ( s1->from->nextcp.y<min1.y ) min1.y = s1->from->nextcp.y; - if ( s1->to->prevcp.x>max1.x ) max1.x = s1->to->prevcp.x; - else if ( s1->to->prevcp.x<min1.x ) min1.x = s1->to->prevcp.x; - if ( s1->to->prevcp.y>max1.y ) max1.y = s1->to->prevcp.y; - else if ( s1->to->prevcp.y<min1.y ) min1.y = s1->to->prevcp.y; - if ( s1->to->me.x>max1.x ) max1.x = s1->to->me.x; - else if ( s1->to->me.x<min1.x ) min1.x = s1->to->me.x; - if ( s1->to->me.y>max1.y ) max1.y = s1->to->me.y; - else if ( s1->to->me.y<min1.y ) min1.y = s1->to->me.y; - - if ( s2->from->nextcp.x>max2.x ) max2.x = s2->from->nextcp.x; - else if ( s2->from->nextcp.x<min2.x ) min2.x = s2->from->nextcp.x; - if ( s2->from->nextcp.y>max2.y ) max2.y = s2->from->nextcp.y; - else if ( s2->from->nextcp.y<min2.y ) min2.y = s2->from->nextcp.y; - if ( s2->to->prevcp.x>max2.x ) max2.x = s2->to->prevcp.x; - else if ( s2->to->prevcp.x<min2.x ) min2.x = s2->to->prevcp.x; - if ( s2->to->prevcp.y>max2.y ) max2.y = s2->to->prevcp.y; - else if ( s2->to->prevcp.y<min2.y ) min2.y = s2->to->prevcp.y; - if ( s2->to->me.x>max2.x ) max2.x = s2->to->me.x; - else if ( s2->to->me.x<min2.x ) min2.x = s2->to->me.x; - if ( s2->to->me.y>max2.y ) max2.y = s2->to->me.y; - else if ( s2->to->me.y<min2.y ) min2.y = s2->to->me.y; - if ( min1.x>max2.x || min2.x>max1.x || min1.y>max2.y || min2.y>max1.y ) -return( false ); /* no intersection of bounding boxes */ - - if ( s1->knownlinear ) { - spline.d = s1->splines[1].c*((bigreal) s2->splines[0].d-(bigreal) s1->splines[0].d)- - s1->splines[0].c*((bigreal) s2->splines[1].d-(bigreal) s1->splines[1].d); - spline.c = s1->splines[1].c*(bigreal) s2->splines[0].c - s1->splines[0].c*(bigreal) s2->splines[1].c; - spline.b = s1->splines[1].c*(bigreal) s2->splines[0].b - s1->splines[0].c*(bigreal) s2->splines[1].b; - spline.a = s1->splines[1].c*(bigreal) s2->splines[0].a - s1->splines[0].c*(bigreal) s2->splines[1].a; - IterateSolve(&spline,tempts); - if ( tempts[0]==-1 ) -return( false ); - for ( i = 0; i<3 && tempts[i]!=-1; ++i ) { - x = ((s2->splines[0].a*tempts[i]+s2->splines[0].b)*tempts[i]+ - s2->splines[0].c)*tempts[i]+s2->splines[0].d; - y = ((s2->splines[1].a*tempts[i]+s2->splines[1].b)*tempts[i]+ - s2->splines[1].c)*tempts[i]+s2->splines[1].d; - if ( s1->splines[0].c==0 ) - x = s1->splines[0].d; - if ( s1->splines[1].c==0 ) - y = s1->splines[1].d; - if ( (ac0 = s1->splines[0].c)<0 ) ac0 = -ac0; - if ( (ac1 = s1->splines[1].c)<0 ) ac1 = -ac1; - if ( ac0>ac1 ) - t = (x-s1->splines[0].d)/s1->splines[0].c; - else - t = (y-s1->splines[1].d)/s1->splines[1].c; - if ( tempts[i]>.99996 && Closer(s1,s2,t,tempts[i],t,1)) { - tempts[i] = 1; - x = s2->to->me.x; y = s2->to->me.y; - } else if ( tempts[i]<.00001 && Closer(s1,s2,t,tempts[i],t,0)) { - tempts[i] = 0; - x = s2->from->me.x; y = s2->from->me.y; - } - /* I know we just did this, but we might have changed x,y so redo */ - if ( ac0>ac1 ) - t = (x-s1->splines[0].d)/s1->splines[0].c; - else - t = (y-s1->splines[1].d)/s1->splines[1].c; - if ( t>.99996 && t<1.001 && Closer(s1,s2,t,tempts[i],1,tempts[i])) { - t = 1; - x = s1->to->me.x; y = s1->to->me.y; - } else if ( t<.00001 && t>-.001 && Closer(s1,s2,t,tempts[i],0,tempts[i])) { - t = 0; - x = s1->from->me.x; y = s1->from->me.y; - } - if ( t<-.001 || t>1.001 || x<min1.x-.01 || y<min1.y-.01 || x>max1.x+.01 || y>max1.y+.01 ) - continue; - if ( t<=0 ) {t=0; x=s1->from->me.x; y = s1->from->me.y; } - else if ( t>=1 ) { t=1; x=s1->to->me.x; y = s1->to->me.y; } - if ( s1->from->me.x==s1->to->me.x ) /* Avoid rounding errors */ - x = s1->from->me.x; /* on hor/vert lines */ - else if ( s1->from->me.y==s1->to->me.y ) - y = s1->from->me.y; - if ( s2->knownlinear ) { - if ( s2->from->me.x==s2->to->me.x ) - x = s2->from->me.x; - else if ( s2->from->me.y==s2->to->me.y ) - y = s2->from->me.y; - } - soln = AddPoint(x,y,t,tempts[i],pts,t1s,t2s,soln); - } -return( soln!=0 ); - } - /* if one of the splines is quadratic then we can get an expression */ - /* relating c*t+d to poly(s^3), and substituting this back we get */ - /* a poly of degree 6 in s which could be solved iteratively */ - /* however mixed quadratics and cubics are unlikely */ - - /* but if both splines are degree 3, the t is expressed as the sqrt of */ - /* a third degree poly, which must be substituted into a cubic, and */ - /* then squared to get rid of the sqrts leaving us with an ?18? degree */ - /* poly. Ick. */ - - /* So let's do it the hard way... we break the splines into little bits */ - /* where they are monotonic in both dimensions, then check these for */ - /* possible intersections */ - extrema1[0] = extrema2[0] = 0; - ecnt1 = Spline2DFindExtrema(s1,extrema1+1); - ecnt2 = Spline2DFindExtrema(s2,extrema2+1); - extrema1[++ecnt1] = 1.0; - extrema2[++ecnt2] = 1.0; - found=0; - for ( i=0; i<ecnt1; ++i ) { - min1.x = ((s1->splines[0].a*extrema1[i]+s1->splines[0].b)*extrema1[i]+ - s1->splines[0].c)*extrema1[i]+s1->splines[0].d; - min1.y = ((s1->splines[1].a*extrema1[i]+s1->splines[1].b)*extrema1[i]+ - s1->splines[1].c)*extrema1[i]+s1->splines[1].d; - max1.x = ((s1->splines[0].a*extrema1[i+1]+s1->splines[0].b)*extrema1[i+1]+ - s1->splines[0].c)*extrema1[i+1]+s1->splines[0].d; - max1.y = ((s1->splines[1].a*extrema1[i+1]+s1->splines[1].b)*extrema1[i+1]+ - s1->splines[1].c)*extrema1[i+1]+s1->splines[1].d; - if ( max1.x<min1.x ) { extended temp = max1.x; max1.x = min1.x; min1.x = temp; } - if ( max1.y<min1.y ) { extended temp = max1.y; max1.y = min1.y; min1.y = temp; } - for ( j=(s1==s2)?i+1:0; j<ecnt2; ++j ) { - min2.x = ((s2->splines[0].a*extrema2[j]+s2->splines[0].b)*extrema2[j]+ - s2->splines[0].c)*extrema2[j]+s2->splines[0].d; - min2.y = ((s2->splines[1].a*extrema2[j]+s2->splines[1].b)*extrema2[j]+ - s2->splines[1].c)*extrema2[j]+s2->splines[1].d; - max2.x = ((s2->splines[0].a*extrema2[j+1]+s2->splines[0].b)*extrema2[j+1]+ - s2->splines[0].c)*extrema2[j+1]+s2->splines[0].d; - max2.y = ((s2->splines[1].a*extrema2[j+1]+s2->splines[1].b)*extrema2[j+1]+ - s2->splines[1].c)*extrema2[j+1]+s2->splines[1].d; - if ( max2.x<min2.x ) { extended temp = max2.x; max2.x = min2.x; min2.x = temp; } - if ( max2.y<min2.y ) { extended temp = max2.y; max2.y = min2.y; min2.y = temp; } - if ( min1.x>max2.x || min2.x>max1.x || min1.y>max2.y || min2.y>max1.y ) - /* No possible intersection */; - else if ( s1!=s2 ) - found += CubicsIntersect(s1,extrema1[i],extrema1[i+1],&min1,&max1, - s2,extrema2[j],extrema2[j+1],&min2,&max2, - &pts[found],&t1s[found],&t2s[found],9-found); - else { - int k,l; - int cnt = CubicsIntersect(s1,extrema1[i],extrema1[i+1],&min1,&max1, - s2,extrema2[j],extrema2[j+1],&min2,&max2, - &pts[found],&t1s[found],&t2s[found],9-found); - for ( k=0; k<cnt; ++k ) { - if ( RealNear(t1s[found+k],t2s[found+k]) ) { - for ( l=k+1; l<cnt; ++l ) { - pts[found+l-1] = pts[found+l]; - t1s[found+l-1] = t1s[found+l]; - t2s[found+l-1] = t2s[found+l]; - } - --cnt; --k; - } - } - found += cnt; - } - if ( found>=8 ) { - /* If the splines are colinear then we might get an unbounded */ - /* number of intersections */ - break; - } - } - } - t1s[found] = t2s[found] = -1; -return( found!=0 ); -} - -void StemInfoFree(StemInfo *h) { - HintInstance *hi, *n; - - for ( hi=h->where; hi!=NULL; hi=n ) { - n = hi->next; - chunkfree(hi,sizeof(HintInstance)); - } - chunkfree(h,sizeof(StemInfo)); -} - -void StemInfosFree(StemInfo *h) { - StemInfo *hnext; - HintInstance *hi, *n; - - for ( ; h!=NULL; h = hnext ) { - for ( hi=h->where; hi!=NULL; hi=n ) { - n = hi->next; - chunkfree(hi,sizeof(HintInstance)); - } - hnext = h->next; - chunkfree(h,sizeof(StemInfo)); - } -} - -void DStemInfoFree(DStemInfo *h) { - HintInstance *hi, *n; - - for ( hi=h->where; hi!=NULL; hi=n ) { - n = hi->next; - chunkfree(hi,sizeof(HintInstance)); - } - chunkfree(h,sizeof(DStemInfo)); -} - -void DStemInfosFree(DStemInfo *h) { - DStemInfo *hnext; - HintInstance *hi, *n; - - for ( ; h!=NULL; h = hnext ) { - for ( hi=h->where; hi!=NULL; hi=n ) { - n = hi->next; - chunkfree(hi,sizeof(HintInstance)); - } - hnext = h->next; - chunkfree(h,sizeof(DStemInfo)); - } -} - -void KernPairsFree(KernPair *kp) { - KernPair *knext; - for ( ; kp!=NULL; kp = knext ) { - knext = kp->next; - if ( kp->adjust!=NULL ) { - free(kp->adjust->corrections); - chunkfree(kp->adjust,sizeof(DeviceTable)); - } - chunkfree(kp,sizeof(KernPair)); - } -} - -void AnchorPointsFree(AnchorPoint *ap) { - AnchorPoint *anext; - for ( ; ap!=NULL; ap = anext ) { - anext = ap->next; - free(ap->xadjust.corrections); - free(ap->yadjust.corrections); - chunkfree(ap,sizeof(AnchorPoint)); - } -} - -void ValDevFree(ValDevTab *adjust) { - if ( adjust==NULL ) -return; - free( adjust->xadjust.corrections ); - free( adjust->yadjust.corrections ); - free( adjust->xadv.corrections ); - free( adjust->yadv.corrections ); - chunkfree(adjust,sizeof(ValDevTab)); -} - -void DeviceTableFree(DeviceTable *dt) { - - if ( dt==NULL ) -return; - - free(dt->corrections); - chunkfree(dt,sizeof(DeviceTable)); -} - -void PSTFree(PST *pst) { - PST *pnext; - for ( ; pst!=NULL; pst = pnext ) { - pnext = pst->next; - if ( pst->type==pst_lcaret ) - free(pst->u.lcaret.carets); - else if ( pst->type==pst_pair ) { - free(pst->u.pair.paired); - ValDevFree(pst->u.pair.vr[0].adjust); - ValDevFree(pst->u.pair.vr[1].adjust); - chunkfree(pst->u.pair.vr,sizeof(struct vr [2])); - } else if ( pst->type!=pst_position ) { - free(pst->u.subs.variant); - } else if ( pst->type==pst_position ) { - ValDevFree(pst->u.pos.adjust); - } - chunkfree(pst,sizeof(PST)); - } -} - -void FPSTRuleContentsFree(struct fpst_rule *r, enum fpossub_format format) { - int j; - - switch ( format ) { - case pst_glyphs: - free(r->u.glyph.names); - free(r->u.glyph.back); - free(r->u.glyph.fore); - break; - case pst_class: - free(r->u.class.nclasses); - free(r->u.class.bclasses); - free(r->u.class.fclasses); - break; - case pst_reversecoverage: - free(r->u.rcoverage.replacements); - case pst_coverage: - for ( j=0 ; j<r->u.coverage.ncnt ; ++j ) - free(r->u.coverage.ncovers[j]); - free(r->u.coverage.ncovers); - for ( j=0 ; j<r->u.coverage.bcnt ; ++j ) - free(r->u.coverage.bcovers[j]); - free(r->u.coverage.bcovers); - for ( j=0 ; j<r->u.coverage.fcnt ; ++j ) - free(r->u.coverage.fcovers[j]); - free(r->u.coverage.fcovers); - break; - default:; - } - free(r->lookups); -} - -void FPSTClassesFree(FPST *fpst) { - int i; - - for ( i=0; i<fpst->nccnt; ++i ) { - free(fpst->nclass[i]); - free(fpst->nclassnames[i]); - } - for ( i=0; i<fpst->bccnt; ++i ) { - free(fpst->bclass[i]); - free(fpst->bclassnames[i]); - } - for ( i=0; i<fpst->fccnt; ++i ) { - free(fpst->fclass[i]); - free(fpst->fclassnames[i]); - } - free(fpst->nclass); free(fpst->bclass); free(fpst->fclass); - free(fpst->nclassnames); free(fpst->bclassnames); free(fpst->fclassnames); - - fpst->nccnt = fpst->bccnt = fpst->fccnt = 0; - fpst->nclass = fpst->bclass = fpst->fclass = NULL; - fpst->nclassnames = fpst->bclassnames = fpst->fclassnames = NULL; -} - -void FPSTFree(FPST *fpst) { - FPST *next; - int i; - - while ( fpst!=NULL ) { - next = fpst->next; - FPSTClassesFree(fpst); - for ( i=0; i<fpst->rule_cnt; ++i ) { - FPSTRuleContentsFree( &fpst->rules[i],fpst->format ); - } - free(fpst->rules); - chunkfree(fpst,sizeof(FPST)); - fpst = next; - } -} - -void MinimumDistancesFree(MinimumDistance *md) { - MinimumDistance *next; - - while ( md!=NULL ) { - next = md->next; - chunkfree(md,sizeof(MinimumDistance)); - md = next; - } -} - -void TTFLangNamesFree(struct ttflangname *l) { - struct ttflangname *next; - int i; - - while ( l!=NULL ) { - next = l->next; - for ( i=0; i<ttf_namemax; ++i ) - free(l->names[i]); - chunkfree(l,sizeof(*l)); - l = next; - } -} - -void AltUniFree(struct altuni *altuni) { - struct altuni *next; - - while ( altuni ) { - next = altuni->next; - chunkfree(altuni,sizeof(struct altuni)); - altuni = next; - } -} - -void LayerDefault(Layer *layer) { - memset(layer,0,sizeof(Layer)); - layer->fill_brush.opacity = layer->stroke_pen.brush.opacity = 1.0; - layer->fill_brush.col = layer->stroke_pen.brush.col = COLOR_INHERITED; - layer->stroke_pen.width = 10; - layer->stroke_pen.linecap = lc_round; - layer->stroke_pen.linejoin = lj_round; - layer->dofill = true; - layer->fillfirst = true; - layer->stroke_pen.trans[0] = layer->stroke_pen.trans[3] = 1.0; - layer->stroke_pen.trans[1] = layer->stroke_pen.trans[2] = 0.0; - /* Dashes default to an unbroken line */ -} - -SplineChar *SplineCharCreate(int layer_cnt) { - SplineChar *sc = chunkalloc(sizeof(SplineChar)); - int i; - - sc->color = COLOR_DEFAULT; - sc->orig_pos = 0xffff; - sc->unicodeenc = -1; - sc->layer_cnt = layer_cnt; - sc->layers = calloc(layer_cnt,sizeof(Layer)); - for ( i=0; i<layer_cnt; ++i ) - LayerDefault(&sc->layers[i]); - sc->tex_height = sc->tex_depth = sc->italic_correction = sc->top_accent_horiz = - TEX_UNDEF; -return( sc ); -} - -SplineChar *SFSplineCharCreate(SplineFont *sf) { - SplineChar *sc = SplineCharCreate(sf==NULL?2:sf->layer_cnt); - int i; - - if ( sf==NULL ) { - sc->layers[ly_back].background = true; - sc->layers[ly_fore].background = false; - } else { - for ( i=0; i<sf->layer_cnt; ++i ) { - sc->layers[i].background = sf->layers[i].background; - sc->layers[i].order2 = sf->layers[i].order2; - } - sc->parent = sf; - } -return( sc ); -} - -void GlyphVariantsFree(struct glyphvariants *gv) { - int i; - - if ( gv==NULL ) -return; - free(gv->variants); - DeviceTableFree(gv->italic_adjusts); - for ( i=0; i<gv->part_cnt; ++i ) - free( gv->parts[i].component ); - free(gv->parts); - chunkfree(gv,sizeof(*gv)); -} - -void MathKernVContentsFree(struct mathkernvertex *mk) { - int i; - for ( i=0; i<mk->cnt; ++i ) { - DeviceTableFree(mk->mkd[i].height_adjusts); - DeviceTableFree(mk->mkd[i].kern_adjusts); - } - free(mk->mkd); -} - -void MathKernFree(struct mathkern *mk) { - int i; - - if ( mk==NULL ) -return; - for ( i=0; i<4; ++i ) - MathKernVContentsFree( &(&mk->top_right)[i] ); - chunkfree(mk,sizeof(*mk)); -} - -void SplineCharListsFree(struct splinecharlist *dlist) { - struct splinecharlist *dnext; - for ( ; dlist!=NULL; dlist = dnext ) { - dnext = dlist->next; - chunkfree(dlist,sizeof(struct splinecharlist)); - } -} - -struct pattern *PatternCopy(struct pattern *old, real transform[6]) { - struct pattern *pat; - - if ( old==NULL ) -return( NULL ); - - pat = chunkalloc(sizeof(struct pattern)); - - *pat = *old; - pat->pattern = copy( old->pattern ); - if ( transform!=NULL ) - MatMultiply(pat->transform,transform,pat->transform); -return( pat ); -} - -void PatternFree(struct pattern *pat) { - if ( pat==NULL ) -return; - free(pat->pattern); - chunkfree(pat,sizeof(struct pattern)); -} - -struct gradient *GradientCopy(struct gradient *old,real transform[6]) { - struct gradient *grad; - - if ( old==NULL ) -return( NULL ); - - grad = chunkalloc(sizeof(struct gradient)); - - *grad = *old; - grad->grad_stops = malloc(old->stop_cnt*sizeof(struct grad_stops)); - memcpy(grad->grad_stops,old->grad_stops,old->stop_cnt*sizeof(struct grad_stops)); - if ( transform!=NULL ) { - BpTransform(&grad->start,&grad->start,transform); - BpTransform(&grad->stop,&grad->stop,transform); - } -return( grad ); -} - -void GradientFree(struct gradient *grad) { - if ( grad==NULL ) -return; - free(grad->grad_stops); - chunkfree(grad,sizeof(struct gradient)); -} - -void BrushCopy(struct brush *into, struct brush *from, real transform[6]) { - *into = *from; - into->gradient = GradientCopy(from->gradient,transform); - into->pattern = PatternCopy(from->pattern,transform); -} - -void PenCopy(struct pen *into, struct pen *from,real transform[6]) { - *into = *from; - into->brush.gradient = GradientCopy(from->brush.gradient,transform); - into->brush.pattern = PatternCopy(from->brush.pattern,transform); -} - -void LayerFreeContents(SplineChar *sc,int layer) { - SplinePointListsFree(sc->layers[layer].splines); - GradientFree(sc->layers[layer].fill_brush.gradient); - PatternFree(sc->layers[layer].fill_brush.pattern); - GradientFree(sc->layers[layer].stroke_pen.brush.gradient); - PatternFree(sc->layers[layer].stroke_pen.brush.pattern); - RefCharsFree(sc->layers[layer].refs); - /* image garbage collection????!!!! */ -} - -void SplineCharFreeContents(SplineChar *sc) { - int i; - - if ( sc==NULL ) -return; - if (sc->name != NULL) free(sc->name); - if (sc->comment != NULL) free(sc->comment); - for ( i=0; i<sc->layer_cnt; ++i ) { -#if defined(_NO_PYTHON) - if (sc->layers[i].python_persistent != NULL) free( sc->layers[i].python_persistent ); /* It's a string of pickled data which we leave as a string */ -#else - PyFF_FreeSCLayer(sc, i); -#endif - LayerFreeContents(sc,i); - } - StemInfosFree(sc->hstem); - StemInfosFree(sc->vstem); - DStemInfosFree(sc->dstem); - MinimumDistancesFree(sc->md); - KernPairsFree(sc->kerns); - KernPairsFree(sc->vkerns); - AnchorPointsFree(sc->anchor); - SplineCharListsFree(sc->dependents); - PSTFree(sc->possub); - if (sc->ttf_instrs != NULL) free(sc->ttf_instrs); - if (sc->countermasks != NULL) free(sc->countermasks); - if (sc->layers != NULL) free(sc->layers); - AltUniFree(sc->altuni); - GlyphVariantsFree(sc->horiz_variants); - GlyphVariantsFree(sc->vert_variants); - DeviceTableFree(sc->italic_adjusts); - DeviceTableFree(sc->top_accent_adjusts); - MathKernFree(sc->mathkern); - if (sc->glif_name != NULL) { free(sc->glif_name); sc->glif_name = NULL; } -} - -void SplineCharFree(SplineChar *sc) { - - if ( sc==NULL ) -return; - SplineCharFreeContents(sc); - chunkfree(sc,sizeof(SplineChar)); -} - -void AnchorClassesFree(AnchorClass *an) { - AnchorClass *anext; - for ( ; an!=NULL; an = anext ) { - anext = an->next; - free(an->name); - chunkfree(an,sizeof(AnchorClass)); - } -} - -void TtfTablesFree(struct ttf_table *tab) { - struct ttf_table *next; - - for ( ; tab!=NULL; tab = next ) { - next = tab->next; - free(tab->data); - chunkfree(tab,sizeof(struct ttf_table)); - } -} - -void ScriptLangListFree(struct scriptlanglist *sl) { - struct scriptlanglist *next; - - while ( sl!=NULL ) { - next = sl->next; - free(sl->morelangs); - chunkfree(sl,sizeof(*sl)); - sl = next; - } -} - -void FeatureScriptLangListFree(FeatureScriptLangList *fl) { - FeatureScriptLangList *next; - - while ( fl!=NULL ) { - next = fl->next; - ScriptLangListFree(fl->scripts); - chunkfree(fl,sizeof(*fl)); - fl = next; - } -} - -void OTLookupFree(OTLookup *lookup) { - struct lookup_subtable *st, *stnext; - - free(lookup->lookup_name); - FeatureScriptLangListFree(lookup->features); - for ( st=lookup->subtables; st!=NULL; st=stnext ) { - stnext = st->next; - free(st->subtable_name); - free(st->suffix); - chunkfree(st,sizeof(struct lookup_subtable)); - } - chunkfree( lookup,sizeof(OTLookup) ); -} - -void OTLookupListFree(OTLookup *lookup ) { - OTLookup *next; - - for ( ; lookup!=NULL; lookup = next ) { - next = lookup->next; - OTLookupFree(lookup); - } -} - -void KernClassFreeContents(KernClass *kc) { - int i; - for ( i=1; i<kc->first_cnt; ++i ) - free(kc->firsts[i]); - for ( i=1; i<kc->second_cnt; ++i ) - free(kc->seconds[i]); - free(kc->firsts); - free(kc->seconds); - free(kc->offsets); - for ( i=kc->first_cnt*kc->second_cnt-1; i>=0 ; --i ) - free(kc->adjusts[i].corrections); - free(kc->adjusts); - if (kc->firsts_flags) free(kc->firsts_flags); - if (kc->seconds_flags) free(kc->seconds_flags); - if (kc->offsets_flags) free(kc->offsets_flags); - if (kc->firsts_names) { - for ( i=kc->first_cnt-1; i>=0 ; --i ) - free(kc->firsts_names[i]); - free(kc->firsts_names); - } - if (kc->seconds_names) { - for ( i=kc->second_cnt-1; i>=0 ; --i ) - free(kc->seconds_names[i]); - free(kc->seconds_names); - } -} - -void KernClassClearSpecialContents(KernClass *kc) { - // This frees and zeros special data not handled by the FontForge GUI, - // most of which comes from U. F. O.. - int i; - if (kc->firsts_flags) { free(kc->firsts_flags); kc->firsts_flags = NULL; } - if (kc->seconds_flags) { free(kc->seconds_flags); kc->seconds_flags = NULL; } - if (kc->offsets_flags) { free(kc->offsets_flags); kc->offsets_flags = NULL; } - if (kc->firsts_names) { - for ( i=kc->first_cnt-1; i>=0 ; --i ) - free(kc->firsts_names[i]); - free(kc->firsts_names); - kc->firsts_names = NULL; - } - if (kc->seconds_names) { - for ( i=kc->second_cnt-1; i>=0 ; --i ) - free(kc->seconds_names[i]); - free(kc->seconds_names); - kc->seconds_names = NULL; - } -} - -void KernClassListFree(KernClass *kc) { - KernClass *n; - - while ( kc ) { - KernClassFreeContents(kc); - n = kc->next; - chunkfree(kc,sizeof(KernClass)); - kc = n; - } -} - -void KernClassListClearSpecialContents(KernClass *kc) { - KernClass *n; - - while ( kc ) { - KernClassClearSpecialContents(kc); - n = kc->next; - kc = n; - } -} - -void MacNameListFree(struct macname *mn) { - struct macname *next; - - while ( mn!=NULL ) { - next = mn->next; - free(mn->name); - chunkfree(mn,sizeof(struct macname)); - mn = next; - } -} - -void MacSettingListFree(struct macsetting *ms) { - struct macsetting *next; - - while ( ms!=NULL ) { - next = ms->next; - MacNameListFree(ms->setname); - chunkfree(ms,sizeof(struct macsetting)); - ms = next; - } -} - -void MacFeatListFree(MacFeat *mf) { - MacFeat *next; - - while ( mf!=NULL ) { - next = mf->next; - MacNameListFree(mf->featname); - MacSettingListFree(mf->settings); - chunkfree(mf,sizeof(MacFeat)); - mf = next; - } -} - -void ASMFree(ASM *sm) { - ASM *next; - int i; - - while ( sm!=NULL ) { - next = sm->next; - if ( sm->type==asm_insert ) { - for ( i=0; i<sm->class_cnt*sm->state_cnt; ++i ) { - free( sm->state[i].u.insert.mark_ins ); - free( sm->state[i].u.insert.cur_ins ); - } - } else if ( sm->type==asm_kern ) { - for ( i=0; i<sm->class_cnt*sm->state_cnt; ++i ) { - free( sm->state[i].u.kern.kerns ); - } - } - for ( i=4; i<sm->class_cnt; ++i ) - free(sm->classes[i]); - free(sm->state); - free(sm->classes); - chunkfree(sm,sizeof(ASM)); - sm = next; - } -} - -void OtfNameListFree(struct otfname *on) { - struct otfname *on_next; - - for ( ; on!=NULL; on = on_next ) { - on_next = on->next; - free(on->name); - chunkfree(on,sizeof(*on)); - } -} - -void OtfFeatNameListFree(struct otffeatname *fn) { - struct otffeatname *fn_next; - - for ( ; fn!=NULL; fn = fn_next ) { - fn_next = fn->next; - OtfNameListFree(fn->names); - chunkfree(fn,sizeof(*fn)); - } -} - -EncMap *EncMapNew(int enccount,int backmax,Encoding *enc) { -/* NOTE: 'enccount' and 'backmax' can sometimes be different map sizes */ - EncMap *map; - - /* Ensure all memory available, otherwise cleanup and exit as NULL */ - if ( (map=chunkalloc(sizeof(EncMap)))!=NULL ) { - if ( (map->map=malloc(enccount*sizeof(int32)))!=NULL ) { - if ( (map->backmap=malloc(backmax*sizeof(int32)))!=NULL ) { - map->enccount = map->encmax = enccount; - map->backmax = backmax; - memset(map->map,-1,enccount*sizeof(int32)); - memset(map->backmap,-1,backmax*sizeof(int32)); - map->enc = enc; - return( map ); - } - free(map->map); - } - free(map); - } - return( NULL ); -} - -EncMap *EncMap1to1(int enccount) { -/* Used for CID fonts where CID is same as orig_pos */ -/* NOTE: map-enc point to a global variable custom. */ -/* TODO: avoid global custom and use passed pointer */ - EncMap *map; - int i; - - if ( (map=EncMapNew(enccount,enccount,&custom))!=NULL ) { - for ( i=0; i<enccount; ++i ) - map->map[i] = map->backmap[i] = i; - } - return( map ); -} - -void EncMapFree(EncMap *map) { - if ( map==NULL ) -return; - - if ( map->enc->is_temporary ) - EncodingFree(map->enc); - free(map->map); - free(map->backmap); - free(map->remap); - chunkfree(map,sizeof(EncMap)); -} - -void MarkClassFree(int cnt,char **classes,char **names) { - int i; - - for ( i=1; i<cnt; ++i ) { - free( classes[i] ); - free( names[i] ); - } - free( classes ); - free( names ); -} - -void MarkSetFree(int cnt,char **classes,char **names) { - int i; - - for ( i=0; i<cnt; ++i ) { - free( classes[i] ); - free( names[i] ); - } - free( classes ); - free( names ); -} - -struct baselangextent *BaseLangCopy(struct baselangextent *extent) { - struct baselangextent *head, *last, *cur; - - last = head = NULL; - for ( ; extent!=NULL; extent = extent->next ) { - cur = chunkalloc(sizeof(struct baselangextent)); - *cur = *extent; - cur->features = BaseLangCopy(cur->features); - if ( head==NULL ) - head = cur; - else - last->next = cur; - last = cur; - } -return( head ); -} - -void BaseLangFree(struct baselangextent *extent) { - struct baselangextent *next; - - while ( extent!=NULL ) { - next = extent->next; - BaseLangFree(extent->features); - chunkfree(extent,sizeof(struct baselangextent)); - extent = next; - } -} - -void BaseScriptFree(struct basescript *bs) { - struct basescript *next; - - while ( bs!=NULL ) { - next = bs->next; - if ( bs->baseline_pos ) - free(bs->baseline_pos); - BaseLangFree(bs->langs); - chunkfree(bs,sizeof(struct basescript)); - bs = next; - } -} - -void BaseFree(struct Base *base) { - if ( base==NULL ) -return; - - free(base->baseline_tags); - BaseScriptFree(base->scripts); - chunkfree(base,sizeof(struct Base)); -} - -void JstfLangFree(struct jstf_lang *jl) { - struct jstf_lang *next; - int i; - - while ( jl!=NULL ) { - next = jl->next; - for ( i=0; i<jl->cnt; ++i ) { - struct jstf_prio *jp = &jl->prios[i]; - free(jp->enableShrink); - free(jp->disableShrink); - free(jp->maxShrink); - free(jp->enableExtend); - free(jp->disableExtend); - free(jp->maxExtend); - } - free(jl->prios); - chunkfree(jl,sizeof(*jl)); - jl = next; - } -} - -void JustifyFree(Justify *just) { - Justify *next; - - while ( just!=NULL ) { - next = just->next; - free(just->extenders); - JstfLangFree(just->langs); - chunkfree(just,sizeof(*just)); - just = next; - } -} - -void SplineFontFree(SplineFont *sf) { - int i; - - if ( sf==NULL ) -return; - if ( sf->mm!=NULL ) { - MMSetFree(sf->mm); -return; - } - if ( sf->sfd_version>0 && sf->sfd_version<2 ) { - // Free special data. - SplineFont1* oldsf = (SplineFont1*)sf; - // First the script language lists. - if (oldsf->script_lang != NULL) { - int scripti; - for (scripti = 0; oldsf->script_lang[scripti] != NULL; scripti ++) { - int scriptj; - for (scriptj = 0; oldsf->script_lang[scripti][scriptj].script != 0; scriptj ++) { - if (oldsf->script_lang[scripti][scriptj].langs != NULL) free(oldsf->script_lang[scripti][scriptj].langs); - } - free(oldsf->script_lang[scripti]); oldsf->script_lang[scripti] = NULL; - } - free(oldsf->script_lang); oldsf->script_lang = NULL; - } - // Then the table orderings. - { - struct table_ordering *ord = oldsf->orders; - while (ord != NULL) { - struct table_ordering *ordtofree = ord; - if (ord->ordered_features != NULL) free(ord->ordered_features); - ord = ord->next; - chunkfree(ordtofree, sizeof(struct table_ordering)); - } - oldsf->orders = NULL; - } - } - for ( i=0; i<sf->glyphcnt; ++i ) if ( sf->glyphs[i]!=NULL ) - SplineCharFree(sf->glyphs[i]); - free(sf->glyphs); - free(sf->fontname); - free(sf->fullname); - free(sf->familyname); - free(sf->weight); - free(sf->copyright); - free(sf->comments); - free(sf->filename); - free(sf->origname); - free(sf->autosavename); - free(sf->version); - free(sf->xuid); - free(sf->cidregistry); - free(sf->ordering); - if (sf->map != 0) - EncMapFree(sf->map); - if (sf->MATH) - free(sf->MATH); - if ( sf->styleMapFamilyName && sf->styleMapFamilyName[0]!='\0' ) { free(sf->styleMapFamilyName); sf->styleMapFamilyName = NULL; } - MacFeatListFree(sf->features); - /* We don't free the EncMap. That field is only a temporary pointer. Let the FontViewBase free it, that's where it really lives */ - // TODO: But that doesn't always get freed. The statement below causes double-frees, so we need to come up with better conditions. - #if 0 - if (sf->cidmaster == NULL || sf->cidmaster == sf) - if (sf->map != NULL) { free(sf->map); sf->map = NULL; } - #endif // 0 - SplinePointListsFree(sf->grid.splines); - AnchorClassesFree(sf->anchor); - TtfTablesFree(sf->ttf_tables); - TtfTablesFree(sf->ttf_tab_saved); - PSDictFree(sf->private); - TTFLangNamesFree(sf->names); - for ( i=0; i<sf->subfontcnt; ++i ) - SplineFontFree(sf->subfonts[i]); - free(sf->subfonts); - GlyphHashFree(sf); - OTLookupListFree(sf->gpos_lookups); - OTLookupListFree(sf->gsub_lookups); - KernClassListFree(sf->kerns); - KernClassListFree(sf->vkerns); - FPSTFree(sf->possub); - ASMFree(sf->sm); - OtfNameListFree(sf->fontstyle_name); - OtfFeatNameListFree(sf->feat_names); - MarkClassFree(sf->mark_class_cnt,sf->mark_classes,sf->mark_class_names); - MarkSetFree(sf->mark_set_cnt,sf->mark_sets,sf->mark_set_names); - GlyphGroupsFree(sf->groups); - GlyphGroupKernsFree(sf->groupkerns); - GlyphGroupKernsFree(sf->groupvkerns); - free( sf->gasp ); -#if defined(_NO_PYTHON) - free( sf->python_persistent ); /* It's a string of pickled data which we leave as a string */ -#else - PyFF_FreeSF(sf); -#endif - BaseFree(sf->horiz_base); - BaseFree(sf->vert_base); - JustifyFree(sf->justify); - if (sf->layers != NULL) { - int layer; - for (layer = 0; layer < sf->layer_cnt; layer ++) { - if (sf->layers[layer].name != NULL) { - free(sf->layers[layer].name); - sf->layers[layer].name = NULL; - } - if (sf->layers[layer].ufo_path != NULL) { - free(sf->layers[layer].ufo_path); - sf->layers[layer].ufo_path = NULL; - } - } - free(sf->layers); sf->layers = NULL; - } - free(sf); -} - -void SplineFontClearSpecial(SplineFont *sf) { - int i; - - if ( sf==NULL ) -return; - if ( sf->mm!=NULL ) { - MMSetClearSpecial(sf->mm); -return; - } - for ( i=0; i<sf->glyphcnt; ++i ) if ( sf->glyphs[i]!=NULL ) { - struct splinechar *sc = sf->glyphs[i]; - if (sc->glif_name != NULL) { free(sc->glif_name); sc->glif_name = NULL; } - } - for ( i=0; i<sf->subfontcnt; ++i ) - SplineFontClearSpecial(sf->subfonts[i]); - KernClassListClearSpecialContents(sf->kerns); - KernClassListClearSpecialContents(sf->vkerns); - if (sf->groups) { GlyphGroupsFree(sf->groups); sf->groups = NULL; } - if (sf->groupkerns) { GlyphGroupKernsFree(sf->groupkerns); sf->groupkerns = NULL; } - if (sf->groupvkerns) { GlyphGroupKernsFree(sf->groupvkerns); sf->groupvkerns = NULL; } - if (sf->python_persistent) { -#if defined(_NO_PYTHON) - free( sf->python_persistent ); /* It's a string of pickled data which we leave as a string */ -#else - PyFF_FreeSF(sf); -#endif - sf->python_persistent = NULL; - } - if (sf->layers != NULL) { - int layer; - for (layer = 0; layer < sf->layer_cnt; layer ++) { - if (sf->layers[layer].ufo_path != NULL) { - free(sf->layers[layer].ufo_path); - sf->layers[layer].ufo_path = NULL; - } - } - } -} - -#if 0 -// These are in splinefont.h. -#define GROUP_NAME_KERNING_UFO 1 -#define GROUP_NAME_KERNING_FEATURE 2 -#define GROUP_NAME_VERTICAL 4 // Otherwise horizontal. -#define GROUP_NAME_RIGHT 8 // Otherwise left (or above). -#endif // 0 - - -void GlyphGroupFree(struct ff_glyphclasses* group) { - if (group->classname != NULL) free(group->classname); - if (group->glyphs != NULL) free(group->glyphs); - free(group); -} - -void GlyphGroupsFree(struct ff_glyphclasses* root) { - struct ff_glyphclasses* current = root; - struct ff_glyphclasses* next; - while (current != NULL) { - next = current->next; - GlyphGroupFree(current); - current = next; - } -} - -void GlyphGroupKernFree(struct ff_rawoffsets* groupkern) { - if (groupkern->left != NULL) free(groupkern->left); - if (groupkern->right != NULL) free(groupkern->right); - free(groupkern); -} - -void GlyphGroupKernsFree(struct ff_rawoffsets* root) { - struct ff_rawoffsets* current = root; - struct ff_rawoffsets* next; - while (current != NULL) { - next = current->next; - GlyphGroupKernFree(current); - current = next; - } -} - - -#ifdef FF_UTHASH_GLIF_NAMES -int HashKerningClassNamesFlex(SplineFont *sf, struct glif_name_index * class_name_hash, int capitalize) { - struct kernclass *current_kernclass; - int isv; - int isr; - int i; - int absolute_index = 0; // This gives us a unique index for each kerning class. - // First we catch the existing names. - absolute_index = 0; - for (isv = 0; isv < 2; isv++) - for (current_kernclass = (isv ? sf->vkerns : sf->kerns); current_kernclass != NULL; current_kernclass = current_kernclass->next) - for (isr = 0; isr < 2; isr++) if ( (isr ? current_kernclass->seconds_names : current_kernclass->firsts_names) != NULL ) { - for ( i=0; i < (isr ? current_kernclass->second_cnt : current_kernclass->first_cnt); ++i ) - if ( (isr ? current_kernclass->seconds_names[i] : current_kernclass->firsts_names[i]) != NULL ) { - // Add it to the hash table with its index. - if (capitalize) { - char * cap_name = upper_case(isr ? current_kernclass->seconds_names[i] : current_kernclass->firsts_names[i]); - glif_name_track_new(class_name_hash, absolute_index + i, cap_name); - free(cap_name); cap_name = NULL; - } else { - glif_name_track_new(class_name_hash, absolute_index + i, (isr ? current_kernclass->seconds_names[i] : current_kernclass->firsts_names[i])); - } - } - absolute_index +=i; - } - return absolute_index; -} -int HashKerningClassNames(SplineFont *sf, struct glif_name_index * class_name_hash) { - return HashKerningClassNamesFlex(sf, class_name_hash, 0); -} -int HashKerningClassNamesCaps(SplineFont *sf, struct glif_name_index * class_name_hash) { - return HashKerningClassNamesFlex(sf, class_name_hash, 1); -} -#endif - -void MMSetFreeContents(MMSet *mm) { - int i; - - free(mm->instances); - - free(mm->positions); - free(mm->defweights); - - for ( i=0; i<mm->axis_count; ++i ) { - free(mm->axes[i]); - free(mm->axismaps[i].blends); - free(mm->axismaps[i].designs); - MacNameListFree(mm->axismaps[i].axisnames); - } - free(mm->axismaps); - free(mm->cdv); - free(mm->ndv); - for ( i=0; i<mm->named_instance_count; ++i ) { - free(mm->named_instances[i].coords); - MacNameListFree(mm->named_instances[i].names); - } - free(mm->named_instances); -} - -void MMSetFree(MMSet *mm) { - int i; - - for ( i=0; i<mm->instance_count; ++i ) { - mm->instances[i]->mm = NULL; - mm->instances[i]->map = NULL; - SplineFontFree(mm->instances[i]); - } - mm->normal->mm = NULL; - SplineFontFree(mm->normal); /* EncMap gets freed here */ - MMSetFreeContents(mm); - - chunkfree(mm,sizeof(*mm)); -} - -void MMSetClearSpecial(MMSet *mm) { - int i; - - for ( i=0; i<mm->instance_count; ++i ) { - SplineFontClearSpecial(mm->instances[i]); - } - SplineFontClearSpecial(mm->normal); -} - -SplinePoint *SplineBisect(Spline *spline, extended t) { - Spline1 xstart, xend; - Spline1 ystart, yend; - Spline *spline1, *spline2; - SplinePoint *mid; - SplinePoint *old0, *old1; - Spline1D *xsp = &spline->splines[0], *ysp = &spline->splines[1]; - int order2 = spline->order2; - -#ifdef DEBUG - if ( t<=1e-3 || t>=1-1e-3 ) - IError("Bisection to create a zero length spline"); -#endif - xstart.s0 = xsp->d; ystart.s0 = ysp->d; - xend.s1 = (extended) xsp->a+xsp->b+xsp->c+xsp->d; - yend.s1 = (extended) ysp->a+ysp->b+ysp->c+ysp->d; - xstart.s1 = xend.s0 = ((xsp->a*t+xsp->b)*t+xsp->c)*t + xsp->d; - ystart.s1 = yend.s0 = ((ysp->a*t+ysp->b)*t+ysp->c)*t + ysp->d; - FigureSpline1(&xstart,0,t,xsp); - FigureSpline1(&xend,t,1,xsp); - FigureSpline1(&ystart,0,t,ysp); - FigureSpline1(¥d,t,1,ysp); - - mid = chunkalloc(sizeof(SplinePoint)); - mid->me.x = xstart.s1; mid->me.y = ystart.s1; - if ( order2 ) { - mid->nextcp.x = xend.sp.d + xend.sp.c/2; - mid->nextcp.y = yend.sp.d + yend.sp.c/2; - mid->prevcp.x = xstart.sp.d + xstart.sp.c/2; - mid->prevcp.y = ystart.sp.d + ystart.sp.c/2; - } else { - mid->nextcp.x = xend.c0; mid->nextcp.y = yend.c0; - mid->prevcp.x = xstart.c1; mid->prevcp.y = ystart.c1; - } - if ( mid->me.x==mid->nextcp.x && mid->me.y==mid->nextcp.y ) - mid->nonextcp = true; - if ( mid->me.x==mid->prevcp.x && mid->me.y==mid->prevcp.y ) - mid->noprevcp = true; - - old0 = spline->from; old1 = spline->to; - if ( order2 ) { - old0->nextcp = mid->prevcp; - old1->prevcp = mid->nextcp; - } else { - old0->nextcp.x = xstart.c0; old0->nextcp.y = ystart.c0; - old1->prevcp.x = xend.c1; old1->prevcp.y = yend.c1; - } - old0->nonextcp = (old0->nextcp.x==old0->me.x && old0->nextcp.y==old0->me.y); - old1->noprevcp = (old1->prevcp.x==old1->me.x && old1->prevcp.y==old1->me.y); - old0->nextcpdef = false; - old1->prevcpdef = false; - SplineFree(spline); - - spline1 = chunkalloc(sizeof(Spline)); - spline1->splines[0] = xstart.sp; spline1->splines[1] = ystart.sp; - spline1->from = old0; - spline1->to = mid; - spline1->order2 = order2; - old0->next = spline1; - mid->prev = spline1; - if ( SplineIsLinear(spline1)) { - spline1->islinear = spline1->from->nonextcp = spline1->to->noprevcp = true; - spline1->from->nextcp = spline1->from->me; - spline1->to->prevcp = spline1->to->me; - } - SplineRefigure(spline1); - - spline2 = chunkalloc(sizeof(Spline)); - spline2->splines[0] = xend.sp; spline2->splines[1] = xend.sp; - spline2->from = mid; - spline2->to = old1; - spline2->order2 = order2; - mid->next = spline2; - old1->prev = spline2; - if ( SplineIsLinear(spline2)) { - spline2->islinear = spline2->from->nonextcp = spline2->to->noprevcp = true; - spline2->from->nextcp = spline2->from->me; - spline2->to->prevcp = spline2->to->me; - } - SplineRefigure(spline2); -return( mid ); -} - -void GrowBuffer(GrowBuf *gb) { - if ( gb->base==NULL ) { - gb->base = gb->pt = malloc(200); - gb->end = gb->base + 200; - } else { - int len = (gb->end-gb->base) + 400; - int off = gb->pt-gb->base; - gb->base = realloc(gb->base,len); - gb->end = gb->base + len; - gb->pt = gb->base+off; - } -} |