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;