shithub: fnt

Download patch

ref: d792b270044c33bfb8cf6d9541a78357d8577957
parent: 65d1d12a2188d0e3424ed7d696d896967165eb98
author: Sigrid Solveig Haflínudóttir <sigrid@ftrv.se>
date: Thu Jul 18 16:39:00 EDT 2024

make rasterizer a bit faster; special-case obligatory gap to just ε

--- a/otf.h.in
+++ b/otf.h.in
@@ -106,7 +106,7 @@
 typedef struct Glyf Glyf;
 Glyf *otfglyf(Otf *o, int index);
 int otfglyfnum(Otf *o);
-int otfdrawglyf(Otf *o, Glyf *g, double ppem, int gap, GlyfImage *im);
+int otfdrawglyf(Otf *o, Glyf *g, double ppem, double gap, GlyfImage *im);
 int otfupem(Otf *o);
 int otfrune2glyph(Otf *o, Rune r);
 Rune otfglyph2rune(Otf *o, int g);
--- a/plan9/otf.c
+++ b/plan9/otf.c
@@ -709,7 +709,7 @@
 				x += 65536;
 			return x;
 		}else{
-			x = i + sc->idRangeOffset[i]/2 + (r - sc->startCode[i]);
+			x = i + sc->idRangeOffset[i]/2 + (r - sc->startCode[i]) - segC;
 			n = (sc->length-((8*2)+(sc->segCountX2*4)))/2;
 			if(x < 0 || x >= n)
 				break;
--- a/plan9/otf.h
+++ b/plan9/otf.h
@@ -107,7 +107,7 @@
 typedef struct Glyf Glyf;
 Glyf *otfglyf(Otf *o, int index);
 int otfglyfnum(Otf *o);
-int otfdrawglyf(Otf *o, Glyf *g, double ppem, int gap, GlyfImage *im);
+int otfdrawglyf(Otf *o, Glyf *g, double ppem, double gap, GlyfImage *im);
 int otfupem(Otf *o);
 int otfrune2glyph(Otf *o, Rune r);
 Rune otfglyph2rune(Otf *o, int g);
--- a/rast.c
+++ b/rast.c
@@ -457,12 +457,16 @@
 }
 
 static SegQ *
-addpoints(SegQ *s, Spt *pts₀, int max, Glyf *g)
+addpoints(SegQ *s, Spt *pts₀, Glyf *g, Sval dx, Sval dy, Sval sx, Sval sy, Sval *bb)
 {
+	int k, npts, xMin, yMin, xMax, yMax;
 	Point *p₀, *p, *prev;
 	Spt *e, *pts;
-	int k, npts;
+	Sval v;
 
+	xMin = yMin = 99999;
+	xMax = yMax = -99999;
+
 	for(k = 0; k < g->numberOfContours; k++){
 		npts = g->simple->endPtsOfContours[k]+1;
 		if(k > 0)
@@ -475,36 +479,33 @@
 		prev = p₀+npts-1;
 		if(!p->onCurve){
 			/* fun stuff */
-			if(max-- < 1)
-				goto noplace;
 			if(prev->onCurve)
-				*e = (Spt){prev->x, prev->y};
+				*e = (Spt){dx+sx*prev->x, dy+sy*prev->y};
 			else
-				*e = (Spt){(Sval)(p->x + prev->x)/2, (Sval)(p->y + prev->y)/2};
+				*e = (Spt){dx+sx/2*(p->x+prev->x), dy+sy/2*(p->y+prev->y)};
 			e++;
 		}
 		for(prev = nil; p < p₀+npts; prev = p, p++, e++){
 			if(prev != nil && p->onCurve == prev->onCurve){
 				/* more fun stuff */
-				if(max-- < 1)
-					goto noplace;
 				if(p->onCurve) /* straight line */
-					*e = (Spt){p->x, p->y};
+					*e = (Spt){dx+sx*p->x, dy+sy*p->y};
 				else /* a point in the middle */
-					*e = (Spt){(Sval)(p->x + prev->x)/2, (Sval)(p->y + prev->y)/2};
+					*e = (Spt){dx+sx/2*(p->x+prev->x), dy+sy/2*(p->y+prev->y)};
 				e++;
 			}
-			if(max-- < 1)
-				goto noplace;
-			*e = (Spt){p->x, p->y};
+			*e = (Spt){dx+sx*p->x, dy+sy*p->y};
+
+			if(bb != nil){
+				if(xMin > p->x) xMin = p->x;
+				if(yMin > p->y) yMin = p->y;
+				if(xMax < p->x) xMax = p->x;
+				if(yMax < p->y) yMax = p->y;
+			}
 		}
-		if(p[-1].onCurve){ /* close with a straight line */
-			if(max-- < 1)
-				goto noplace;
+		/* close with a straight line */
+		if(p[-1].onCurve)
 			*e++ = *pts;
-		}
-		if(max-- < 1)
-			goto noplace;
 		*e++ = *pts;
 
 		for(; pts <= e-3; pts += 2, s++){
@@ -516,10 +517,15 @@
 			s->v2[1] = pts[2].y;
 		}
 	}
+
+	if(bb != nil){
+		if(bb[0] > (v = dx+sx*xMin)) bb[0] = v;
+		if(bb[1] > (v = dy+sy*yMin)) bb[1] = v;
+		if(bb[2] < (v = dx+sx*xMax)) bb[2] = v;
+		if(bb[3] < (v = dy+sy*yMax)) bb[3] = v;
+	}
+
 	return s;
-noplace:
-	werrstr("points don't fit");
-	return nil;
 }
 
 static int
@@ -539,7 +545,7 @@
 }
 
 int
-otfdrawglyf(Otf *o, Glyf *g, double ppem, int gap, GlyfImage *im)
+otfdrawglyf(Otf *o, Glyf *g, double ppem, double gap, GlyfImage *im)
 {
 	int i, j, maxptstotal, maxpts, ngs, w, h, r, npx, baseline;
 	Glyf *gs[MAXCOMPONENTS];
@@ -580,10 +586,10 @@
 	}
 */
 
-	Sval xMin = 99999, yMin = 99999, xMax = -99999, yMax = -99999;
 	scale = ppem / otfupem(o);
+	Sval bb[4] = {g->xMin*scale, g->yMin*scale, g->xMax*scale, g->yMax*scale};
 	pts = calloc(1, maxpts*sizeof(*pts) + maxptstotal/2*sizeof(*s));
-	p = s = s₀ = (SegQ*)(pts + maxpts);
+	s = s₀ = (SegQ*)(pts + maxpts);
 	cg = g->component;
 	for(i = 0; i < ngs; i++){
 		Sval dx = 0, dy = 0, gscaleX = scale, gscaleY = scale;
@@ -613,28 +619,9 @@
 */
 			cg = cg->next;
 		}
-		if((s = addpoints(s, pts, maxpts, gs[i])) == nil)
+
+		if((s = addpoints(s, pts, gs[i], dx, dy, gscaleX, gscaleY, ngs > 1 ? bb : nil)) == nil)
 			goto done;
-		for(; p < s; p++){
-			p->p0.x = p->p0.x*gscaleX + dx;
-			xMin = min(xMin, p->p0.x);
-			xMax = max(xMax, p->p0.x);
-			p->p0.y = p->p0.y*gscaleY + dy;
-			yMin = min(yMin, p->p0.y);
-			yMax = max(yMax, p->p0.y);
-			p->p1.x = p->p1.x*gscaleX + dx;
-			xMin = min(xMin, p->p1.x);
-			xMax = max(xMax, p->p1.x);
-			p->p1.y = p->p1.y*gscaleY + dy;
-			yMin = min(yMin, p->p1.y);
-			yMax = max(yMax, p->p1.y);
-			p->p2.x = p->p2.x*gscaleX + dx;
-			xMin = min(xMin, p->p2.x);
-			xMax = max(xMax, p->p2.x);
-			p->p2.y = p->p2.y*gscaleY + dy;
-			yMin = min(yMin, p->p2.y);
-			yMax = max(yMax, p->p2.y);
-		}
 	}
 
 	if(s == s₀){
@@ -641,29 +628,31 @@
 		w = h = 1;
 		baseline = 0;
 	}else{
-		/*
-		 * very rarely a glyph will have one of its segments
-		 * go over the edge because of imprecise arithmetic.
-		 * it's much easier to solve this by always having a small gap.
-		 */
-		if(gap < 1)
-			gap = 1;
-		xMin -= gap;
-		yMin -= gap;
-		xMax += gap;
-		yMax += gap;
+		bb[0] -= gap;
+		bb[1] -= gap;
+		bb[2] += gap;
+		bb[3] += gap;
 
 		/* height+baseline is where it is in the image */
-		baseline = floor(yMin);
+		baseline = floor(bb[1]);
 		offY = -baseline;
-		yMax += offY;
-		w = ceil(xMax - xMin);
-		h = ceil(yMax);
+		if(offY == -bb[1]){
+			/*
+			 * very rarely a glyph will have one of its segments
+			 * go over the edge because of imprecise arithmetic.
+			 * it's much easier to solve this by always having a small gap.
+			 */
+			offY += ε;
+			bb[3] += ε;
+		}
+		bb[3] += offY;
+		w = ceil(bb[2] - bb[0]);
+		h = ceil(bb[3]);
 
 		for(p = s₀; p != s; p++){
-			p->p0.x -= xMin;
-			p->p1.x -= xMin;
-			p->p2.x -= xMin;
+			p->p0.x -= bb[0];
+			p->p1.x -= bb[0];
+			p->p2.x -= bb[0];
 			p->p0.y += offY;
 			p->p1.y += offY;
 			p->p2.y += offY;