[arch-commits] Commit in fontforge/trunk (spline-fix.patch)

Gaetan Bisson bisson at archlinux.org
Wed Sep 29 22:43:13 UTC 2010


    Date: Wednesday, September 29, 2010 @ 18:43:12
  Author: bisson
Revision: 92444

missing patch...

Added:
  fontforge/trunk/spline-fix.patch

------------------+
 spline-fix.patch |  954 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 954 insertions(+)

Added: spline-fix.patch
===================================================================
--- spline-fix.patch	                        (rev 0)
+++ spline-fix.patch	2010-09-29 22:43:12 UTC (rev 92444)
@@ -0,0 +1,954 @@
+diff -aur fontforge-20100501/fontforge/splinestroke.c fontforge-SVN-20100929/fontforge/splinestroke.c
+--- fontforge-20100501/fontforge/splinestroke.c	2010-04-29 05:53:21.000000000 +0200
++++ fontforge-SVN-20100929/fontforge/splinestroke.c	2010-09-14 22:08:14.000000000 +0200
+@@ -51,10 +51,25 @@
+     uint8 rt;
+ } StrokePoint;
+ 
++/* Square line caps and miter line joins cover more area than the circular pen*/
++/*  So we need a list of the polygons which represent these guys so we can do */
++/*  an additional hit test on them. */
++/* I'm not sure that these will always be presented to us in a clockwise fashion*/
++/*  We can test that by taking a point which is the average of the vertices */
++/*  and seeing if the hit-test says it is inside (It will be inside because */
++/*  these polies are convex). If the hit test fails then the poly must be */
++/*  drawn counter clockwise */
++struct extrapoly {
++    BasePoint poly[4];
++    int ptcnt;		/* 3 (for miters) or 4 (for square caps) */
++};
++
+ typedef struct strokecontext {
+     enum pentype { pt_circle, pt_square, pt_poly } pentype;
+     int cur, max;
+     StrokePoint *all;
++    struct extrapoly *ep;
++    int ecur, emax;
+     TPoint *tpt;
+     int tmax;
+     double resolution;	/* take samples roughly this many em-units */ /* radius/16.0? */
+@@ -62,6 +77,10 @@
+     double radius2;	/* Squared */
+     enum linejoin join;	/* Only for circles */
+     enum linecap cap;	/* Only for circles */
++    double miterlimit;	/* Only for circles if join==lj_miter */
++	    /* PostScript uses 1/sin( theta/2 ) as their miterlimit */
++	    /*  I use -cos(theta). (where theta is the angle between the slopes*/
++	    /*  same idea, different implementation */
+     int n;		/* For polygon pens */
+     BasePoint *corners;	/* Expressed as an offset from the center of the poly */ /* (Where center could mean center of bounding box, or average or all verteces) */
+     BasePoint *slopes;	/* slope[0] is unitvector corners[1]-corners[0] */
+@@ -70,7 +89,7 @@
+     unsigned int open: 1;	/* Original is an open contour */
+     unsigned int remove_inner: 1;
+     unsigned int remove_outer: 1;
+-    /* unsigned int rotate_relative_to_direction: 1;	/* Rotate the polygon pen so it maintains the same orientation with respect to the contour's slope */
++    /* unsigned int rotate_relative_to_direction: 1; */	/* Rotate the polygon pen so it maintains the same orientation with respect to the contour's slope */
+     /* Um, the above is essentially equivalent to a circular pen. No point in duplicating it */
+     unsigned int leave_users_center: 1;			/* Don't move the pen so its center is at the origin */
+     unsigned int scaled_or_rotated: 1;
+@@ -79,6 +98,8 @@
+     real inverse[6];
+ } StrokeContext;
+ 
++static char *glyphname=NULL;
++
+ /* Basically the idea is we find the spline, and then at each point, project */
+ /*  out normal to the current slope and find a point that is radius units away*/
+ /*  Now that's all well and good but we've also got to handle linecaps and joins */
+@@ -91,6 +112,18 @@
+ /*  and where there is a significant hidden area, and at certain places within*/
+ /*  caps and joins */
+ 
++/* Butt line caps and bevel line joins cause problems because they are going */
++/*  be inside (hidden) by a circle centered on the line end or joint. So we */
++/*  can't do the hit test on these edges using any point on the contour which */
++/*  is within radius of the joint. */
++/* Hmmm. That works for the edge itself, but if some other part of the contour*/
++/*  approaches closely (within radius) to the non-existant area it will be */
++/*  incorrectly hidden. BUG!!!!! */
++/* Square line caps and miter line joins have the opposite problem: They should*/
++/*  hide more points than a circular pen will cover. So we can build up a list*/
++/*  of the polygons which represent these extrusions (rectangle for the cap, */
++/*  and triangle for the miter) and do a polygon hit test with those. */
++
+ /* OK, that's a circular pen. Now by scaling we can turn a circle into an */
+ /*  elipse, and by rotating we can orient the main axis how we like */
+ /*  (we actually scale the splines by a transform that turns the ellipse into */
+@@ -146,7 +179,7 @@
+ /* the pen (and testing that it wasn't concave). */
+ /* For a concave poly, the concavities are only relevant at the joins and caps*/
+ /* (otherwise the concavity will be filled as the pen moves) so we could      */
+-/* simply use the smallest convex poly that contains the convex one, and just */
++/* simply use the smallest convex poly that contains the concave one, and just */
+ /* worry about the concavity at the caps and joins (and maybe in doing the hit*/
+ /* test) But I don't think there is much point in dealing with that, and there*/
+ /* are the same issues on describing the shape as before */
+@@ -169,6 +202,143 @@
+     len += 1.5*(len-distance);
+ return( len );
+ }
++
++enum hittest { ht_Outside, ht_Inside, ht_OnEdge };
++
++static enum hittest PolygonHitTest(BasePoint *poly,BasePoint *polyslopes, int n,BasePoint *test, double *distance) {
++    /* If the poly is drawn clockwise, then a point is inside the poly if it */
++    /*  is on the right side of each edge */
++    /* A point lies on an edge if the dot product of:		  */
++    /*  1. the vector normal to the edge			  */
++    /*  2. the vector from either vertex to the point in question */
++    /* is 0 (and it is otherwise inside)			  */
++    /* Now, if we choose the normal vector which points right, then */
++    /*  the dot product must be positive.			    */
++    /* Note we could modify this code to work with counter-clockwise*/
++    /*  polies. Either all the dots must be positive, or all must be*/
++    /*  negative */
++    /* Sigh. Rounding errors. dot may be off by a very small amount */
++    /*  (the polyslopes need to be unit vectors for this test to work) */
++    int i, zero_cnt=0, outside=false;
++    double dx,dy, dot, bestd= 0;
++
++    for ( i=0; i<n; ++i ) {
++
++	dx = test->x    - poly[i].x;
++	dy = test->y    - poly[i].y;
++	dot = dx*polyslopes[i].y - dy*polyslopes[i].x;
++	if ( dot>=-0.001 && dot<=.001 )
++	    ++zero_cnt;
++	else if ( dot<0 ) {	/* It's on the left, so it can't be inside */
++	    if ( distance==NULL )
++return( ht_Outside );
++	    outside= true;
++	    if ( bestd<-dot )
++		bestd = -dot;
++	}
++    }
++
++    if ( outside ) {
++	*distance = bestd;
++return( ht_Outside );
++    }
++
++    if ( distance!=NULL )
++	*distance = 0;
++    /* zero_cnt==1 => on edge, zero_cnt==2 => on a vertex (on edge), zero_cnt>2 is impossible on a nice poly */
++    if ( zero_cnt>0 ) {
++return( ht_OnEdge );
++    }
++
++return( ht_Inside );
++}
++
++/* Something is a valid polygonal pen if: */
++/*  1. It contains something (not a line, or a single point, something with area) */
++/*  2. It contains ONE contour */
++/*	(Multiple contours can be dealt with as long as each contour follows */
++/*	 requirements 3-n. If we have multiple contours: Find the offset from */
++/*	 the center of each contour to the center of all the contours. Trace  */
++/*	 each contour individually and then translate by this offset) */
++/*  3. All edges must be lines (no control points) */
++/*  4. No more than 255 corners (could extend this number, but why?) */
++/*  5. It must be drawn clockwise (not really an error, if found just invert, but important for later checks). */
++/*  6. It must be convex */
++/*  7. No extranious points on the edges */
++
++enum PolyType PolygonIsConvex(BasePoint *poly,int n, int *badpointindex) {
++    /* For each vertex: */
++    /*  Remove that vertex from the polygon, and then test if the vertex is */
++    /*  inside the resultant poly. If it is inside, then the polygon is not */
++    /*  convex */
++    /* If all verteces are outside then we have a convex poly */
++    /* If one vertex is on an edge, then we have a poly with an unneeded vertex */
++    double nx,ny;
++    int i,j,ni;
++
++    if ( badpointindex!=NULL )
++	*badpointindex = -1;
++    if ( n<3 )
++return( Poly_TooFewPoints );
++    /* All the points might lie on one line. That wouldn't be a polygon */
++    nx = -(poly[1].y-poly[0].y);
++    ny = (poly[1].x-poly[0].x);
++    for ( i=2; i<n; ++i ) {
++	if ( (poly[i].x-poly[0].x)*ny - (poly[i].y-poly[0].y)*nx != 0 )
++    break;
++    }
++    if ( i==n )
++return( Poly_Line );		/* Colinear */
++    if ( n==3 ) {
++	/* Triangles are always convex */
++return( Poly_Convex );
++    }
++
++    for ( j=0; j<n; ++j ) {
++	/* Test to see if poly[j] is inside the polygon poly[0..j-1,j+1..n] */
++	/* Basically the hit test code above modified to ignore poly[j] */
++	int outside = 0, zero_cnt=0, sign=0;
++	double sx, sy, dx,dy, dot;
++
++	for ( i=0; ; ++i ) {
++	    if ( i==j )
++	continue;
++	    ni = i+1;
++	    if ( ni==n ) ni=0;
++	    if ( ni==j ) {
++		++ni;
++		if ( ni==n )
++		    ni=0;		/* Can't be j, because it already was */
++	    }
++
++	    sx = poly[ni].x - poly[i].x;
++	    sy = poly[ni].y - poly[i].y;
++	    dx = poly[j ].x - poly[i].x;
++	    dy = poly[j ].y - poly[i].y;
++	    /* Only care about signs, so I don't need unit vectors */
++	    dot = dx*sy - dy*sx;
++	    if ( dot==0 )
++		++zero_cnt;
++	    else if ( sign==0 )
++		sign= dot;
++	    else if ( (dot<0 && sign>0) || (dot>0 && sign<0)) {
++		outside = true;
++	break;
++	    }
++	    if ( ni==0 )
++	break;
++	}
++	if ( !outside ) {
++	    if ( badpointindex!=NULL )
++		*badpointindex = j;
++	    if ( zero_cnt>0 )
++return( Poly_PointOnEdge );
++	    else
++return( Poly_Concave );
++	}
++    }
++return( Poly_Convex );
++}
+ /******************************************************************************/
+ /* ******************************* Circle Pen ******************************* */
+ /******************************************************************************/
+@@ -240,6 +410,27 @@
+ 	halfleft.y = base2.y + c->radius*done.slope.x;
+ 	halfright.x = base2.x + c->radius*done.slope.y;
+ 	halfright.y = base2.y - c->radius*done.slope.x;
++	{
++	    struct extrapoly *ep;
++	    if ( c->ecur>=c->emax )
++		c->ep = grealloc(c->ep,(c->emax+=40)*sizeof(struct extrapoly));
++	    ep = &c->ep[c->ecur++];
++	    ep->poly[0] = done.left;
++	    ep->poly[1].x = done.left.x + c->radius*slope.x;
++	    ep->poly[1].y = done.left.y + c->radius*slope.y;
++	    ep->poly[2].x = done.right.x + c->radius*slope.x;
++	    ep->poly[2].y = done.right.y + c->radius*slope.y;
++	    ep->poly[3] = done.right;
++	    if ( !isend ) {
++		BasePoint temp;
++		ep->poly[0] = done.right;
++		temp = ep->poly[1];
++		ep->poly[1] = ep->poly[2];
++		ep->poly[2] = temp;
++		ep->poly[3] = done.left;
++	    }
++	    ep->ptcnt = 4;
++	}
+ 	for ( i=start; ; i+=incr ) {
+ 	    p = &c->all[c->cur++];
+ 	    p->sp = done.sp;
+@@ -306,7 +497,8 @@
+     StrokePoint *p, *pp;
+     int pindex;
+     int cnt, cnt1, i, was_neg;
+-    /* atbreak means that we are dealing with a close contour, and we have */
++    int force_bevel;
++    /* atbreak means that we are dealing with a closed contour, and we have*/
+     /*  reached the "end" of the contour (which is only the end because we */
+     /*  had to start somewhere), so the next point on the contour is the   */
+     /*  start (index 0), as opposed to (index+1) */
+@@ -331,6 +523,8 @@
+     dot = (nslope.x*pslope.x + nslope.y*pslope.y);
+     if ( dot>=.999 )
+ return;		/* Essentially colinear */ /* Won't be perfect because control points lie on integers */
++    /* miterlimit of 6, 18 degrees */
++    force_bevel = ( c->join==lj_miter && dot<c->miterlimit );
+ 
+     cnt = ceil(c->radius/c->resolution);
+     if ( cnt<6 ) cnt = 6;
+@@ -353,7 +547,7 @@
+     else
+ 	bends_left = false;	/* So it bends right */
+ 
+-    if ( c->join==lj_bevel ) {
++    if ( c->join==lj_bevel || force_bevel ) {
+ 	/* This is easy, a line between the two end points */
+ 	if ( bends_left ) {
+ 	    /* If it bends left, then the joint is on the right */
+@@ -402,6 +596,20 @@
+ 	if ( !IntersectLinesSlopes(&inter,&base,&c->all[pindex].slope,
+ 				    &final,&done.slope))
+ 	    inter = base;
++	{
++	    struct extrapoly *ep;
++	    if ( c->ecur>=c->emax )
++		c->ep = grealloc(c->ep,(c->emax+=40)*sizeof(struct extrapoly));
++	    ep = &c->ep[c->ecur++];
++	    ep->poly[0] = base;
++	    ep->poly[1] = inter;
++	    ep->poly[2] = final;
++	    if ( bends_left ) {
++		ep->poly[0] = final;
++		ep->poly[2] = base;
++	    }
++	    ep->ptcnt = 3;
++	}
+ 	curslope.x = inter.x - base.x;
+ 	curslope.y = inter.y - base.y;
+ 	len = sqrt(curslope.x*curslope.x + curslope.y*curslope.y);
+@@ -510,8 +718,12 @@
+ 		else
+ 		    p->left = temp;
+ 		if ( rot.x<=0 && !was_neg ) {
+-		    was_neg = true;
++		    was_neg = c->cur-1;
+ 		    p->needs_point_left = p->needs_point_right = true;
++		    if ( diff_angle.y>.1 ) {
++			incr_angle.y = diff_angle.y/20;
++			incr_angle.x = sqrt(1-incr_angle.y*incr_angle.y);
++		    }
+ 		}
+ 		temp.x = rot.x*incr_angle.x - rot.y*incr_angle.y;
+ 		temp.y = rot.x*incr_angle.y + rot.y*incr_angle.x;
+@@ -525,6 +737,8 @@
+ 		rot = temp;
+ 	    }
+ 	}
++	if ( was_neg!=0 && c->cur-was_neg<5 )
++	    c->all[was_neg].needs_point_left = c->all[was_neg].needs_point_right = false;
+     }
+     if ( !atbreak )
+ 	c->all[c->cur++] = done;
+@@ -645,6 +859,32 @@
+ 	    }
+ 	}
+     }
++
++    /* now see if any miter join polygons (or square cap polys) cover anything */
++    for ( j=0; j<c->ecur; ++j ) {
++	BasePoint slopes[4];
++	double len;
++	struct extrapoly *ep = &c->ep[j];
++	for ( i=0; i<ep->ptcnt; ++i ) {
++	    int ni = i+1;
++	    if ( ni==ep->ptcnt ) ni=0;
++	    slopes[i].x = ep->poly[ni].x - ep->poly[i].x;
++	    slopes[i].y = ep->poly[ni].y - ep->poly[i].y;
++	    len = sqrt(slopes[i].x*slopes[i].x + slopes[i].y*slopes[i].y);
++	    if ( len==0 )
++return;
++	    slopes[i].x /= len; slopes[i].y /= len;
++	}
++	for ( i=c->cur-1; i>=0 ; --i ) {
++	    StrokePoint *p = &c->all[i];
++	    if ( !p->left_hidden )
++		if ( PolygonHitTest(ep->poly,slopes,ep->ptcnt,&p->left,NULL)==ht_Inside )
++		    p->left_hidden = true;
++	    if ( !p->right_hidden )
++		if ( PolygonHitTest(ep->poly,slopes,ep->ptcnt,&p->right,NULL)==ht_Inside )
++		    p->right_hidden = true;
++	}
++    }
+ }
+ 
+ static void FindStrokePointsCircle(SplineSet *ss, StrokeContext *c) {
+@@ -704,7 +944,7 @@
+     /* just in case... add an on curve point every time the sample's slopes */
+     /*  move through 90 degrees. (We only do this for circles because for  */
+     /*  squares and polygons this will happen automatically whenever we change */
+-    /*  polygon/squar vertices, which is close enough to the same idea as no */
++    /*  polygon/square vertices, which is close enough to the same idea as no */
+     /*  matter) */
+     { int j,k, skip=10/c->resolution;
+     for ( i=c->cur-1; i>=0; ) {
+@@ -1189,143 +1429,6 @@
+ /* ****************************** Polygon Pen ******************************* */
+ /******************************************************************************/
+ 
+-/* Something is a valid polygonal pen if: */
+-/*  1. It contains something (not a line, or a single point, something with area) */
+-/*  2. It contains ONE contour */
+-/*	(Multiple contours can be dealt with as long as each contour follows */
+-/*	 requirements 3-n. If we have multiple contours: Find the offset from */
+-/*	 the center of each contour to the center of all the contours. Trace  */
+-/*	 each contour individually and then translate by this offset) */
+-/*  3. All edges must be lines (no control points) */
+-/*  4. No more than 255 corners (could extend this number, but why?) */
+-/*  5. It must be drawn clockwise (not really an error, if found just invert, but important for later checks). */
+-/*  6. It must be convex */
+-/*  7. No extranious points on the edges */
+-
+-enum hittest { ht_Outside, ht_Inside, ht_OnEdge };
+-
+-static enum hittest PolygonHitTest(BasePoint *poly,BasePoint *polyslopes, int n,BasePoint *test, double *distance) {
+-    /* If the poly is drawn clockwise, then a point is inside the poly if it */
+-    /*  is on the right side of each edge */
+-    /* A point lies on an edge if the dot product of:		  */
+-    /*  1. the vector normal to the edge			  */
+-    /*  2. the vector from either vertex to the point in question */
+-    /* is 0 (and it is otherwise inside)			  */
+-    /* Now, if we choose the normal vector which points right, then */
+-    /*  the dot product must be positive.			    */
+-    /* Note we could modify this code to work with counter-clockwise*/
+-    /*  polies. Either all the dots must be positive, or all must be*/
+-    /*  negative */
+-    /* Sigh. Rounding errors. dot may be off by a very small amount */
+-    /*  (the polyslopes need to be unit vectors for this test to work) */
+-    int i, zero_cnt=0, outside=false;
+-    double dx,dy, dot, bestd= 0;
+-
+-    for ( i=0; i<n; ++i ) {
+-
+-	dx = test->x    - poly[i].x;
+-	dy = test->y    - poly[i].y;
+-	dot = dx*polyslopes[i].y - dy*polyslopes[i].x;
+-	if ( dot>=-0.001 && dot<=.001 )
+-	    ++zero_cnt;
+-	else if ( dot<0 ) {	/* It's on the left, so it can't be inside */
+-	    if ( distance==NULL )
+-return( ht_Outside );
+-	    outside= true;
+-	    if ( bestd<-dot )
+-		bestd = -dot;
+-	}
+-    }
+-
+-    if ( outside ) {
+-	*distance = bestd;
+-return( ht_Outside );
+-    }
+-
+-    if ( distance!=NULL )
+-	*distance = 0;
+-    /* zero_cnt==1 => on edge, zero_cnt==2 => on a vertex (on edge), zero_cnt>2 is impossible on a nice poly */
+-    if ( zero_cnt>0 ) {
+-return( ht_OnEdge );
+-    }
+-
+-return( ht_Inside );
+-}
+-
+-enum PolyType PolygonIsConvex(BasePoint *poly,int n, int *badpointindex) {
+-    /* For each vertex: */
+-    /*  Remove that vertex from the polygon, and then test if the vertex is */
+-    /*  inside the resultant poly. If it is inside, then the polygon is not */
+-    /*  convex */
+-    /* If all verteces are outside then we have a convex poly */
+-    /* If one vertex is on an edge, then we have a poly with an unneeded vertex */
+-    double nx,ny;
+-    int i,j,ni;
+-
+-    if ( badpointindex!=NULL )
+-	*badpointindex = -1;
+-    if ( n<3 )
+-return( Poly_TooFewPoints );
+-    /* All the points might lie on one line. That wouldn't be a polygon */
+-    nx = -(poly[1].y-poly[0].y);
+-    ny = (poly[1].x-poly[0].x);
+-    for ( i=2; i<n; ++i ) {
+-	if ( (poly[i].x-poly[0].x)*nx + (poly[i].y-poly[0].y)*ny != 0 )
+-    break;
+-    }
+-    if ( i==n )
+-return( Poly_Line );		/* Colinear */
+-    if ( n==3 ) {
+-	/* Triangles are always convex */
+-return( Poly_Convex );
+-    }
+-
+-    for ( j=0; j<n; ++j ) {
+-	/* Test to see if poly[j] is inside the polygon poly[0..j-1,j+1..n] */
+-	/* Basically the hit test code above modified to ignore poly[j] */
+-	int outside = 0, zero_cnt=0, sign=0;
+-	double sx, sy, dx,dy, dot;
+-
+-	for ( i=0; ; ++i ) {
+-	    if ( i==j )
+-	continue;
+-	    ni = i+1;
+-	    if ( ni==n ) ni=0;
+-	    if ( ni==j ) {
+-		++ni;
+-		if ( ni==n )
+-		    ni=0;		/* Can't be j, because it already was */
+-	    }
+-
+-	    sx = poly[ni].x - poly[i].x;
+-	    sy = poly[ni].y - poly[i].y;
+-	    dx = poly[j ].x - poly[i].x;
+-	    dy = poly[j ].y - poly[i].y;
+-	    /* Only care about signs, so I don't need unit vectors */
+-	    dot = dx*sy - dy*sx;
+-	    if ( dot==0 )
+-		++zero_cnt;
+-	    else if ( sign==0 )
+-		sign= dot;
+-	    else if ( (dot<0 && sign>0) || (dot>0 && sign<0)) {
+-		outside = true;
+-	break;
+-	    }
+-	    if ( ni==0 )
+-	break;
+-	}
+-	if ( !outside ) {
+-	    if ( badpointindex!=NULL )
+-		*badpointindex = j;
+-	    if ( zero_cnt>0 )
+-return( Poly_PointOnEdge );
+-	    else
+-return( Poly_Concave );
+-	}
+-    }
+-return( Poly_Convex );
+-}
+-
+ static int WhichPolyCorner(StrokeContext *c, BasePoint *slope, int *right_trace) {
+     /* The corner we are interested in is the corner whose normal distance */
+     /*  from the slope is the greatest. */
+@@ -2424,18 +2527,23 @@
+     if ( startslope.x!=0 || startslope.y!=0 )
+ 	ret->noprevcp = false;
+     if ( !*newcontour ) {
+-	ret->nextcp.x += posslope.x;
+-	ret->nextcp.y += posslope.y;
+-	if ( posslope.x!=0 || posslope.y!=0 )
+-	    ret->nonextcp = false;
+ 	/* the same point will often appear at the end of one spline and the */
+ 	/*  start of the next */
+ 	/* Or a joint may add a lot of points to the other side which show up */
+ 	/*  hidden on this side */
++	int opos = pos;
+ 	while ( pos+1<c->cur &&
+ 		((ret->me.x==c->all[pos+1].right.x && ret->me.y==c->all[pos+1].right.y ) ||
+ 		 c->all[pos+1].right_hidden))
+ 	    ++pos;
++	if ( opos!=pos ) {
++	    RightSlopeAtPos(c,pos,false,&posslope);
++	    ret->pointtype = pt_corner;
++	}
++	ret->nextcp.x += posslope.x;
++	ret->nextcp.y += posslope.y;
++	if ( posslope.x!=0 || posslope.y!=0 )
++	    ret->nonextcp = false;
+ 	len2 = (ret->me.x-c->all[pos].right.x)*(ret->me.x-c->all[pos].right.x) + (ret->me.y-c->all[pos].right.y)*(ret->me.y-c->all[pos].right.y);
+ 	if ( len2>=res_bound )
+ 	    *newcontour = true;
+@@ -2704,7 +2812,7 @@
+ 
+     SplinePointFree(other);
+ }
+-    
++
+ static SplineSet *JoinFragments(SplineSet *fragments,SplineSet **contours,
+ 	double resolution) {
+     double res2 = resolution*resolution;
+@@ -3212,6 +3320,133 @@
+ 
+ #define MAX_TPOINTS	40
+ 
++static int InterpolateTPoints(StrokeContext *c,int start_pos,int end_pos,
++	int isleft) {
++    /* We have a short segment of the contour here. So short that there are */
++    /*  very few points StrokePoints on it. If we've only got 1 StrokePoint */
++    /*  we tend to get singular matrices. 2 StrokePoints just gives a bad */
++    /*  approximation (or might), etc. */
++    /* But we have the original spline. We can add as many points between */
++    /*  start and end as we like */
++    double start_t, end_t, t, diff_t;
++    double start_x, end_x, x, diff_x, start_y, end_y, y, diff_y, r2;
++    BasePoint slope, me;
++    Spline *s;
++    int lt,rt;
++    int i,j;
++    double len;
++
++    if ( start_pos==0 )
++return( end_pos-start_pos );
++
++    if ( 20 >= c->tmax )
++	c->tpt = grealloc(c->tpt,(c->tmax = 20+MAX_TPOINTS)*sizeof(TPoint));
++
++    if ( c->all[start_pos].line ) {
++	me = c->all[start_pos-1].me;
++	if ( isleft ) {
++	    slope.x = (c->all[end_pos].left.x - me.x)/6;
++	    slope.y = (c->all[end_pos].left.y - me.y)/6;
++	} else {
++	    slope.x = (c->all[end_pos].right.x - me.x)/6;
++	    slope.y = (c->all[end_pos].right.y - me.y)/6;
++	}
++	for ( i=0; i<5; ++i ) {
++	    c->tpt[i].x = me.x + slope.x*(i+1);
++	    c->tpt[i].x = me.y + slope.y*(i+1);
++	    c->tpt[i].t = (i+1)/6.0;
++	}
++return( 5 );
++    } else if ( c->all[start_pos].circle ) {
++	me = c->all[start_pos].me;		/* Center */
++	if ( isleft ) {
++	    start_x = c->all[start_pos-1].left.x - me.x;
++	    end_x = c->all[end_pos].left.x - me.x;
++	    start_y = c->all[start_pos-1].left.y - me.y;
++	    end_y = c->all[end_pos].left.y - me.y;
++	} else {
++	    start_x = c->all[start_pos-1].right.x - me.x;
++	    end_x = c->all[end_pos].right.x - me.x;
++	    start_y = c->all[start_pos-1].right.y - me.y;
++	    end_y = c->all[end_pos].right.y - me.y;
++	}
++	if ( (diff_x = end_x-start_x)<0 ) diff_x = -diff_x;
++	if ( (diff_y = end_y-start_y)<0 ) diff_y = -diff_y;
++	/* By choosing the bigger difference, I insure the other coord will */
++	/*  not cross over from negative to positive. Actually this is only */
++	/*  true for small segments of the circle. But that's what we've got*/
++	r2 = c->radius*c->radius;
++	if ( diff_y>diff_x ) {
++	    diff_y = (end_y-start_y)/11.0;
++	    for ( y=start_y+diff_y, i=0; i<10; ++i, y+=diff_y ) {
++		x = sqrt( r2-y*y );
++		if ( start_x<0 ) x=-x;
++		c->tpt[i].x = me.x + x;
++		c->tpt[i].y = me.y + y;
++		c->tpt[i].t = (i+1)/11.0;
++	    }
++	} else {
++	    diff_x = (end_x-start_x)/11.0;
++	    for ( x=start_x+diff_x, i=0; i<10; ++i, x+=diff_x ) {
++		y = sqrt( r2-x*x );
++		if ( start_y<0 ) y=-y;
++		c->tpt[i].x = me.x + x;
++		c->tpt[i].y = me.y + y;
++		c->tpt[i].t = (i+1)/11.0;
++	    }
++	}
++return( 10 );
++    }
++
++    if ( c->all[start_pos-1].t == c->all[end_pos].t ||
++	    c->all[start_pos-1].sp!=c->all[end_pos].sp ||
++	    ( isleft && c->all[start_pos-1].lt!=c->all[end_pos].lt) ||
++	    (!isleft && c->all[start_pos-1].rt!=c->all[end_pos].rt))
++return( end_pos-start_pos );		/* Well, nothing we can do here */
++
++    start_t = c->all[start_pos-1].t; end_t = c->all[end_pos].t;
++    diff_t = (end_t-start_t)/11;
++    s = c->all[start_pos].sp;
++    lt = c->all[start_pos].lt; rt = c->all[start_pos].rt;
++    for ( t=start_t+diff_t, j=i=0; i<10; ++i, t+=diff_t ) {
++	me.x = ((s->splines[0].a*t+s->splines[0].b)*t+s->splines[0].c)*t+s->splines[0].d;
++	me.y = ((s->splines[1].a*t+s->splines[1].b)*t+s->splines[1].c)*t+s->splines[1].d;
++	slope.x = (3*s->splines[0].a*t+2*s->splines[0].b)*t+s->splines[0].c;
++	slope.y = (3*s->splines[1].a*t+2*s->splines[1].b)*t+s->splines[1].c;
++	len = slope.x*slope.x + slope.y*slope.y;
++	if ( len==0 && c->pentype==pt_circle )
++    continue;
++	len = sqrt(len);
++	slope.x /= len; slope.y /= len;
++	if ( isleft ) {
++	    if ( c->pentype==pt_circle ) {
++		c->tpt[j].x = me.x - c->radius*slope.y;
++		c->tpt[j].y = me.y + c->radius*slope.x;
++	    } else if ( c->pentype==pt_square ) {
++		c->tpt[j].x = me.x + c->radius*SquareCorners[lt].x;
++		c->tpt[j].y = me.y + c->radius*SquareCorners[lt].y;
++	    } else {
++		c->tpt[j].x = me.x + c->corners[lt].x;
++		c->tpt[j].y = me.y + c->corners[lt].y;
++	    }
++	    c->tpt[j++].t = (i+1)/11.0;
++	} else {
++	    if ( c->pentype==pt_circle ) {
++		c->tpt[j].x = me.x + c->radius*slope.y;
++		c->tpt[j].y = me.y - c->radius*slope.x;
++	    } else if ( c->pentype==pt_square ) {
++		c->tpt[j].x = me.x + c->radius*SquareCorners[rt].x;
++		c->tpt[j].y = me.y + c->radius*SquareCorners[rt].y;
++	    } else {
++		c->tpt[j].x = me.x + c->corners[rt].x;
++		c->tpt[j].y = me.y + c->corners[rt].y;
++	    }
++	    c->tpt[j++].t = (i+1)/11.0;
++	}
++    }
++return( j );
++}
++
+ static SplineSet *ApproximateStrokeContours(StrokeContext *c) {
+     int end_pos, i, start_pos=0, pos, ipos;
+     SplinePoint *first=NULL, *last=NULL, *cur;
+@@ -3281,7 +3516,7 @@
+ 		    StrokePoint *spt = c->all+ipos;
+ 		    tpt->x = spt->left.x;
+ 		    tpt->y = spt->left.y;
+-		    tpt->t = (ipos-start_pos)/ (double) (end_pos-start_pos+1);
++		    tpt->t = (ipos-start_pos+1)/ (double) (end_pos-start_pos+1);
+ 		    ipos += jump;
+ 		    if ( ++skip_cnt>skip && extras>0 ) {
+ 			++ipos;
+@@ -3291,9 +3526,11 @@
+ 		    if ( ipos>end_pos )
+ 			ipos = end_pos;
+ 		}
+-		if ( end_pos!=start_pos )
++		if ( end_pos<start_pos+3 )
++		    tot = InterpolateTPoints(c,start_pos,end_pos,true);
++		if ( end_pos!=start_pos ) {
+ 		    ApproximateSplineFromPointsSlopes(last,cur,c->tpt,tot,false);
+-		else
++		} else
+ 		    SplineMake3(last,cur);
+ 		last = cur;
+ 		if ( pos<end_pos ) {
+@@ -3357,7 +3594,7 @@
+ 		    StrokePoint *spt = c->all+ipos;
+ 		    tpt->x = spt->right.x;
+ 		    tpt->y = spt->right.y;
+-		    tpt->t = (ipos-start_pos)/ (double) (end_pos-start_pos+1);
++		    tpt->t = (ipos-start_pos+1)/ (double) (end_pos-start_pos+1);
+ 		    ipos += jump;
+ 		    if ( ++skip_cnt>skip && extras>0 ) {
+ 			++ipos;
+@@ -3367,9 +3604,11 @@
+ 		    if ( ipos>end_pos )
+ 			ipos = end_pos;
+ 		}
+-		if ( end_pos!=start_pos )
++		if ( end_pos<start_pos+3 )
++		    tot = InterpolateTPoints(c,start_pos,end_pos,false);
++		if ( end_pos!=start_pos ) {
+ 		    ApproximateSplineFromPointsSlopes(last,cur,c->tpt,tot,false);
+-		else
++		} else
+ 		    SplineMake3(last,cur);
+ 		last = cur;
+ 		if ( last->next!=NULL ) last=last->next->to;
+@@ -3417,7 +3656,7 @@
+     lfragments = EdgeEffects(lfragments,c);
+     lfragments=JoinFragments(lfragments,&contours,c->resolution);
+     if ( lfragments!=NULL ) {
+-	IError("Some fragments did not join");
++	IError(glyphname==NULL?_("Some fragments did not join"):_("Some fragments did not join in %s"),glyphname);
+ 	for ( ret=lfragments; ret->next!=NULL; ret=ret->next );
+ 	ret->next = contours;
+ 	contours = lfragments;
+@@ -3444,6 +3683,7 @@
+ 	if ( c->cur!=0 )
+ 	    memset(c->all,0,c->cur*sizeof(StrokePoint));
+ 	c->cur = 0;
++	c->ecur = 0;
+ 	c->open = base->first->prev==NULL;
+ 	switch ( c->pentype ) {
+ 	  case pt_circle:
+@@ -3508,6 +3748,7 @@
+ 		   pt_poly;
+     c.join = si->join;
+     c.cap  = si->cap;
++    c.miterlimit = /* -cos(theta) */ -.98 /* theta=~11 degrees, PS miterlimit=10 */;
+     c.radius = si->radius;
+     c.radius2 = si->radius*si->radius;
+     c.remove_inner = si->removeinternal;
+@@ -3652,6 +3893,7 @@
+ 	if ( (gid=fv->map->map[i])!=-1 && (sc = fv->sf->glyphs[gid])!=NULL &&
+ 		!sc->ticked && fv->selected[i] ) {
+ 	    sc->ticked = true;
++	    glyphname = sc->name;
+ 	    if ( sc->parent->multilayer ) {
+ 		SCPreserveState(sc,false);
+ 		for ( layer = ly_fore; layer<sc->layer_cnt; ++layer ) {
+@@ -3671,5 +3913,6 @@
+     break;
+ 	}
+     }
++ glyphname = NULL;
+     ff_progress_end_indicator();
+ }
+diff -aur fontforge-20100501/fontforge/splineutil2.c fontforge-SVN-20100929/fontforge/splineutil2.c
+--- fontforge-20100501/fontforge/splineutil2.c	2010-04-29 05:53:22.000000000 +0200
++++ fontforge-SVN-20100929/fontforge/splineutil2.c	2010-09-14 22:08:14.000000000 +0200
+@@ -505,7 +505,7 @@
+ }
+ 
+ /* Find a spline which best approximates the list of intermediate points we */
+-/*  are given. No attempt is made to fix the slopes */
++/*  are given. No attempt is made to use fixed slope angles */
+ /* given a set of points (x,y,t) */
+ /* find the bezier spline which best fits those points */
+ 
+@@ -599,6 +599,56 @@
+ 	}
+     }
+ 
++#if 0
++    /* if we look at (p(t)-pi) = (a*t^3+b*t^2+c*t+d)-pi */
++    /* d = p0, a = (p1-p0-b-c) */
++    /* We find another set of equations we can minimize. */
++    /* As might be expected it has exactly the same singularities */
++    /*  Just a linear transform, after all. But I worked through it hoping... */
++    if ( order2 ) {
++    } else {
++	/* Try a different approach */
++	double xconst[2], yconst[2], b_term[2], c_term[2] /* Same for x and y */;
++	double determinant;
++	BasePoint off;
++	xconst[0] = xconst[1] = yconst[0] = yconst[1] =
++	    b_term[0] = b_term[1] = c_term[0] = c_term[1] =  0;
++	off.x = to->me.x - from->me.x; off.y = to->me.y-from->me.y;
++	for ( i=0; i<cnt; ++i ) {
++	    double t = mid[i].t, t2 = t*t, t3=t*t2;
++	    double bfactor = t2-t3, cfactor=t-t3, bc = bfactor*cfactor;
++
++	    b_term[0] += bfactor*bfactor;
++	    b_term[1] += bc;
++	    /*c_term[0] += bc;*/ /* Same as b_term[1]; */
++	    c_term[1] += cfactor*cfactor;
++	    xconst[0] += (off.x*t3+from->me.x-mid[i].x)*bfactor;
++	    xconst[1] += (off.x*t3+from->me.x-mid[i].x)*cfactor;
++	    yconst[0] += (off.y*t3+from->me.y-mid[i].y)*bfactor;
++	    yconst[1] += (off.y*t3+from->me.y-mid[i].y)*cfactor;
++	}
++	c_term[0] = b_term[1];
++	determinant = b_term[1]*c_term[0] - b_term[0]*c_term[1];
++	if ( determinant!=0 ) {
++	    double bx, by, cx, cy;
++	    cx = -(xconst[0]*b_term[1] - xconst[1]*b_term[0])/determinant;
++	    cy = -(yconst[0]*b_term[1] - yconst[1]*b_term[0])/determinant;
++	    if ( b_term[0]!=0 ) {
++		bx = -(xconst[0]+c_term[0]*cx)/b_term[0];
++		by = -(yconst[0]+c_term[0]*cy)/b_term[0];
++	    } else {
++		bx = -(xconst[1]+c_term[1]*cx)/b_term[1];
++		by = -(yconst[1]+c_term[1]*cy)/b_term[1];
++	    }
++	    from->nextcp.x = from->me.x + cx/3;
++	    from->nextcp.y = from->me.y + cy/3;
++	    to->prevcp.x = from->nextcp.x + (bx+cx)/3;
++	    to->prevcp.y = from->nextcp.y + (by+cy)/3;
++return( SplineMake3(from,to));
++	}
++    }
++#endif
++
+     if ( (spline = IsLinearApprox(from,to,mid,cnt,order2))!=NULL )
+ return( spline );
+ 
+@@ -799,21 +849,21 @@
+ /* p(t) = pf +  [ 3*rf*Δf ]*t  +  3*[pt-pf+rt*Δt-2*rf*Δf] *t^2 +			*/
+ /*		[2*pf-2*pt+3*rf*Δf-3*rt*Δt]*t^3 */
+ 
+-/* So I want 
++/* So I want */
+ /*   d  Σ (p(t(i))-p(i))^2/ d rf  == 0 */
+ /*   d  Σ (p(t(i))-p(i))^2/ d rt  == 0 */
+ /* now... */
+ /*   d  Σ (p(t(i))-p(i))^2/ d rf  == 0 */
+ /* => Σ 3*t*Δf*(1-2*t+t^2)*
+-/*			[pf-pi+ 3*(pt-pf)*t^2 + 2*(pf-pt)*t^3]   +
+-/*			3*[t - 2*t^2 + t^3]*Δf*rf   +
+-/*			3*[t^2-t^3]*Δt*rt   */
++ *			[pf-pi+ 3*(pt-pf)*t^2 + 2*(pf-pt)*t^3]   +
++ *			3*[t - 2*t^2 + t^3]*Δf*rf   +
++ *			3*[t^2-t^3]*Δt*rt   */
+ /* and... */
+ /*   d  Σ (p(t(i))-p(i))^2/ d rt  == 0 */
+ /* => Σ 3*t^2*Δt*(1-t)*
+-*			[pf-pi+ 3*(pt-pf)*t^2 + 2*(pf-pt)*t^3]   +
+-/*			3*[t - 2*t^2 + t^3]*Δf*rf   +
+-/*			3*[t^2-t^3]*Δt*rt   */
++ *			[pf-pi+ 3*(pt-pf)*t^2 + 2*(pf-pt)*t^3]   +
++ *			3*[t - 2*t^2 + t^3]*Δf*rf   +
++ *			3*[t^2-t^3]*Δt*rt   */
+ 
+ /* Now for a long time I looked at that and saw four equations and two unknowns*/
+ /*  That was I was trying to solve for x and y separately, and that doesn't work. */
+@@ -852,6 +902,7 @@
+     double offn_, offp_, finaldiff;
+     double pt_pf_x, pt_pf_y, determinant;
+     double consts[2], rt_terms[2], rf_terms[2];
++ double rfbad=0, rtbad=0;
+ 
+     /* If all the selected points are at the same spot, and one of the */
+     /*  end-points is also at that spot, then just copy the control point */
+@@ -1027,6 +1078,8 @@
+ 	rt_terms[1] += factor_to*( -tounit.x*rt_term_x + -tounit.y*rt_term_y);
+     }
+ 
++ /* I've only seen singular matrices (determinant==0) when cnt==1 */
++ /* but even with cnt==1 the determinant is usually non-0 (16 times out of 17)*/
+     determinant = (rt_terms[0]*rf_terms[1]-rt_terms[1]*rf_terms[0]);
+     if ( determinant!=0 ) {
+ 	double rt, rf;
+@@ -1035,6 +1088,16 @@
+ 	    rf = -(consts[0]+rt*rt_terms[0])/rf_terms[0];
+ 	else /* if ( rf_terms[1]!=0 ) This can't happen, otherwise the determinant would be 0 */
+ 	    rf = -(consts[1]+rt*rt_terms[1])/rf_terms[1];
++	/* If we get bad values (ones that point diametrically opposed to what*/
++	/*  we need), then fix that factor at 0, and see what we get for the */
++	/*  other */
++	if ( rf>=0 && rt>0 && rf_terms[0]!=0 &&
++		(rf = -consts[0]/rf_terms[0])>0 ) {
++	    rt = 0;
++	} else if ( rf<0 && rt<=0 && rt_terms[1]!=0 &&
++		(rt = -consts[1]/rt_terms[1])<0 ) {
++	    rf = 0;
++	}
+ 	if ( rt<=0 && rf>=0 ) {
+ 	    from->nextcp.x = from->me.x + rf*fromunit.x;
+ 	    from->nextcp.y = from->me.y + rf*fromunit.y;
+@@ -1044,7 +1107,12 @@
+ 	    to->noprevcp = rt==0;
+ return( SplineMake3(from,to));
+ 	}
+-    }
++	
++  rfbad = rf; rtbad = -rt;
++    } else
++  rfbad = rtbad = -2;
++
++
+ 
+     trylen = (to->me.x-from->me.x)*fromunit.x + (to->me.y-from->me.y)*fromunit.y;
+     if ( trylen>flen ) flen = trylen;
+@@ -2101,6 +2169,7 @@
+ return( top/(dxdt*dxdt) );
+ }
+     
++
+ /* Does the second derivative change sign around this point? If so we should */
+ /*  retain it for truetype */
+ static int SPisD2Change( SplinePoint *sp ) {
+@@ -3415,8 +3484,10 @@
+ 	    s->to->prevcp = s->to->me;
+ 	} else {
+ 	    s->from->nonextcp = true;
+-	    s->from->nextcp = s->to->me;
++	    s->from->nextcp = s->from->me;
+ 	}
++	end->pointtype = pt_corner;
++	SplineRefigure(s);
+ return( true );	/* We changed the slope */
+     }
+     unitslope.x /= len; unitslope.y /= len;
+@@ -3435,12 +3506,14 @@
+ 	    s->from->nextcp.x = s->from->me.x + mydot*unitslope.x;
+ 	    s->from->nextcp.y = s->from->me.y + mydot*unitslope.y;
+ 	}
++	SplineRefigure(s);
+ return( true );	/* We changed the slope */
+     }
+     
+     if ( (xdiff = cp->x - end->me.x)<0 ) xdiff = -xdiff;
+     if ( (ydiff = cp->y - end->me.y)<0 ) ydiff = -ydiff;
+ 
++    to = *cp;
+     if ( xdiff<ydiff/10.0 && xdiff>0 ) {
+ 	to.x = end->me.x;
+ 	end->pointtype = pt_corner;




More information about the arch-commits mailing list