ref: c609f9639ffd99236a5403a057a5d920244fe3c9
parent: 00f3bc7db52b6ebd414ae354d599cf16a2965df2
author: Sigrid Solveig Haflínudóttir <sigrid@ftrv.se>
date: Sun Jul 14 20:48:50 EDT 2024
initial component glyph rasterizing
--- a/otf.c.in
+++ b/otf.c.in
@@ -599,3 +599,9 @@
{
return o->numGlyphs;
}
+
+int
+otfupem(Otf *o)
+{
+ return o->td.head->unitsPerEm;
+}
--- a/otf.h.in
+++ b/otf.h.in
@@ -43,8 +43,14 @@
struct ComponentGlyph {
u16int flags;
u16int glyphIndex;
- int arg1;
- int arg2;
+ union {
+ int arg1;
+ int dx;
+ };
+ union {
+ int arg2;
+ int dy;
+ };
float scale, scaleX, scale01, scale10, scaleY;
u16int numInstr;
u8int *instr;
@@ -77,8 +83,19 @@
void otfprint(Otf *o, Otfile *out, int indent);
void otfclose(Otf *o);
-/* FIXME these will go, this is for debugging and designing the drawing logic */
+/* FIXME these might go eventually */
+
+typedef struct GlyfImage GlyfImage;
+
+struct GlyfImage {
+ u8int *b;
+ int w;
+ int h;
+ int baseline;
+};
+
typedef struct Glyf Glyf;
Glyf *otfglyf(Otf *o, int index);
int otfglyfnum(Otf *o);
-u8int *otfdrawglyf(Glyf *g, int ppem, int *wo, int *ho);
+int otfdrawglyf(Otf *o, Glyf *g, int ppem, GlyfImage *im);
+int otfupem(Otf *o);
--- a/plan9/otf.c
+++ b/plan9/otf.c
@@ -614,6 +614,12 @@
return o->numGlyphs;
}
+int
+otfupem(Otf *o)
+{
+ return o->td.head->unitsPerEm;
+}
+
int
read_SubHeader(Otf *o, SubHeader *v)
--- a/plan9/otf.h
+++ b/plan9/otf.h
@@ -43,8 +43,14 @@
struct ComponentGlyph {
u16int flags;
u16int glyphIndex;
- int arg1;
- int arg2;
+ union {
+ int arg1;
+ int dx;
+ };
+ union {
+ int arg2;
+ int dy;
+ };
float scale, scaleX, scale01, scale10, scaleY;
u16int numInstr;
u8int *instr;
@@ -77,11 +83,22 @@
void otfprint(Otf *o, Otfile *out, int indent);
void otfclose(Otf *o);
-/* FIXME these will go, this is for debugging and designing the drawing logic */
+/* FIXME these might go eventually */
+
+typedef struct GlyfImage GlyfImage;
+
+struct GlyfImage {
+ u8int *b;
+ int w;
+ int h;
+ int baseline;
+};
+
typedef struct Glyf Glyf;
Glyf *otfglyf(Otf *o, int index);
int otfglyfnum(Otf *o);
-u8int *otfdrawglyf(Glyf *g, int ppem, int *wo, int *ho);
+int otfdrawglyf(Otf *o, Glyf *g, int ppem, GlyfImage *im);
+int otfupem(Otf *o);
typedef struct SubHeader SubHeader;
typedef struct MapGroup MapGroup;
--- a/plan9/test.c
+++ b/plan9/test.c
@@ -3,35 +3,11 @@
#include <bio.h>
#include "otf.h"
-typedef struct Image Image;
-
-struct Image {
- int w;
- int h;
- u8int *b;
-};
-
static void
-fit(u8int *b, int bw, int bh, Image *im, int maxh, int *x, int *y, int gap)
+dumpmap(Biobuf *out, GlyfImage *im, int n)
{
- int d;
-
- if((bw-*x) < im->w+gap){
- *y += maxh + gap;
- *x = gap;
- }
- if((bh-*y) < maxh+gap)
- return;
- for(d = 0; d < im->h; d++)
- memcpy(b + (*y + d)*bw + *x, im->b + d*im->w, im->w);
- *x += im->w + gap;
-}
-
-static void
-dumpmap(Biobuf *out, Image *im, int n)
-{
#define gap 1
- int total, mid, npix, bw, bh, x, y, i, maxh;
+ int total, mid, npix, bw, bh, x, y, i, maxh, d;
u8int *b;
total = 0;
@@ -52,10 +28,19 @@
sysfatal("no memory");
memset(b, 0xff, npix);
x = y = gap;
- for(i = 0; i < n; i++)
- fit(b, bw, bh, im+i, maxh, &x, &y, gap);
- Bprint(out, "%11s %11d %11d %11d %11d ", "k8", 0, 0, bw, y+maxh+gap);
- Bwrite(out, b, bw*(y+maxh+gap));
+ for(i = 0; i < n; i++){
+ if((bw-x) < im[i].w+gap){
+ y += maxh + gap;
+ x = gap;
+ }
+ if((bh-y) < maxh+gap)
+ continue;
+ for(d = 0; d < im[i].h; d++)
+ memcpy(b + (maxh - im[i].h + y + im[i].baseline + d)*bw + x, im[i].b + d*im[i].w, im[i].w);
+ x += im[i].w + gap;
+ }
+ Bprint(out, "%11s %11d %11d %11d %11d ", "k8", 0, 0, bw, y+maxh*2+gap);
+ Bwrite(out, b, bw*(y+maxh*2+gap));
free(b);
}
@@ -119,15 +104,14 @@
Bprint(out.aux, "%s\n", argv[i]);
if(G && gi < 0){
int i, n = otfglyfnum(o);
- Image *im = ppem > 0 ? calloc(n, sizeof(*im)) : nil;
+ GlyfImage *im = ppem > 0 ? calloc(n, sizeof(*im)) : nil;
for(i = 0; i < n; i++){
Glyf *g = otfglyf(o, i);
if(g == nil)
- sysfatal("%r");
- if(ppem > 0 && g->simple != nil && g->numberOfContours > 0){
- im[i].b = otfdrawglyf(g, ppem, &im[i].w, &im[i].h);
- if(im[i].b == nil)
- sysfatal("%r");
+ sysfatal("glyf %d: %r", i);
+ if(ppem > 0 && g->numberOfContours != 0){
+ if(otfdrawglyf(o, g, ppem, &im[i]) != 0)
+ sysfatal("glyf %d: %r", i);
}else if(ppem <= 0){
Bprint(out.aux, "%d (%s):\n", i,
g->simple ? "simple" : (g->component ? "component" : "empty"));
@@ -153,17 +137,12 @@
if(g == nil){
fprint(2, "%d: %r\n", gi);
}else if(ppem > 0){
- if(g->component != nil)
- fprint(2, "%d: component\n", gi);
- else{
- int w, h;
- u8int *b = otfdrawglyf(g, ppem, &w, &h);
- if(b == nil)
- sysfatal("%r");
- fprint(1, "%11s %11d %11d %11d %11d ", "k8", 0, 0, w, h);
- write(1, b, w*h);
- free(b);
- }
+ GlyfImage im;
+ if(otfdrawglyf(o, g, ppem, &im) != 0)
+ sysfatal("%r");
+ fprint(1, "%11s %11d %11d %11d %11d ", "k8", 0, 0, im.w, im.h);
+ write(1, im.b, im.w*im.h);
+ free(im.b);
}else{
Bprint(out.aux, "\n%d:\n", gi);
print_Glyf(&out, indentΔ, o, g);
--- a/rast.c
+++ b/rast.c
@@ -451,21 +451,13 @@
return 0;
}
-u8int *
-otfdrawglyf(Glyf *g, int ppem, int *wo, int *ho)
+static SegQ *
+addpoints(SegQ *s, Spt *pts₀, int max, Glyf *g, int dx, int dy, Sval scale, Sval offY)
{
- int w, h, i, r, k, npts, npx, ns;
Point *p₀, *p, *prev;
- Spt *pts₀, *pts, *e;
- SegQ *s₀, *s;
- Sval *fp;
- u8int *b;
+ Spt *e, *pts;
+ int k, npts;
-#define scale (double)ppem/g->unitsPerEm
-
- ns = 0;
- s₀ = nil;
-
for(k = 0; k < g->numberOfContours; k++){
npts = g->simple->endPtsOfContours[k]+1;
if(k > 0)
@@ -473,11 +465,13 @@
if(npts < 2)
continue;
- pts₀ = e = malloc((npts+2)*3*sizeof(*e));
+ e = pts = pts₀;
p₀ = p = g->simple->points + (k > 0 ? g->simple->endPtsOfContours[k-1]+1 : 0);
prev = p₀+npts-1;
if(!p->onCurve){
/* fun stuff */
+ if(max-- < 1)
+ goto noplace;
if(prev->onCurve)
*e = (Spt){prev->x, prev->y};
else
@@ -487,6 +481,8 @@
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};
else /* a point in the middle */
@@ -493,46 +489,129 @@
*e = (Spt){(Sval)(p->x + prev->x)/2, (Sval)(p->y + prev->y)/2};
e++;
}
+ if(max-- < 1)
+ goto noplace;
*e = (Spt){p->x, p->y};
}
- if(e > pts₀ && (e[-1].x != pts₀->x || e[-1].y != pts₀->y)){
- if(p[-1].onCurve) /* close with a straight line */
- *e++ = *pts₀;
- *e++ = *pts₀;
+ if(e > pts && (e[-1].x != pts->x || e[-1].y != pts->y)){
+ if(p[-1].onCurve){ /* close with a straight line */
+ if(max-- < 1)
+ goto noplace;
+ *e++ = *pts;
+ }
+ if(max-- < 1)
+ goto noplace;
+ *e++ = *pts;
}
- s₀ = realloc(s₀, (ns + (e-pts₀)/2)*sizeof(*s₀));
- s = s₀ + ns;
- pts = e;
- for(e = pts₀; e <= pts-3; e += 2, s++, ns++){
- s->v0[0] = (e[0].x - g->xMin) * scale + GAP;
- s->v0[1] = (e[0].y - g->yMin) * scale + GAP;
- s->v1[0] = (e[1].x - g->xMin) * scale + GAP;
- s->v1[1] = (e[1].y - g->yMin) * scale + GAP;
- s->v2[0] = (e[2].x - g->xMin) * scale + GAP;
- s->v2[1] = (e[2].y - g->yMin) * scale + GAP;
+ for(; pts <= e-3; pts += 2, s++){
+ s->v0[0] = (pts[0].x + dx) * scale;
+ s->v0[1] = (pts[0].y + dy) * scale + offY;
+ s->v1[0] = (pts[1].x + dx) * scale;
+ s->v1[1] = (pts[1].y + dy) * scale + offY;
+ s->v2[0] = (pts[2].x + dx) * scale;
+ s->v2[1] = (pts[2].y + dy) * scale + offY;
}
- free(pts₀);
}
+ return s;
+noplace:
+ werrstr("points don't fit");
+ return nil;
+}
- w = ceil((g->xMax - g->xMin)*scale + 2*GAP);
- h = ceil((g->yMax - g->yMin)*scale + 2*GAP);
+static int
+glyfmaxnpts(Glyf *g)
+{
+ int k, npts, d;
+
+ npts = 0;
+ for(k = 0; k < g->numberOfContours; k++){
+ d = g->simple->endPtsOfContours[k]+1;
+ if(k > 0)
+ d -= g->simple->endPtsOfContours[k-1]+1;
+ if(d > 1)
+ npts += 1+2*d+2; /* two extra to close off the contour */
+ }
+ return npts < 2 ? 0 : npts;
+}
+
+#define MAXCOMPONENTS 16
+
+int
+otfdrawglyf(Otf *o, Glyf *g, int ppem, GlyfImage *im)
+{
+ int i, j, maxptstotal, maxpts, ngs, w, h, r, npx, baseline;
+ Glyf *gs[MAXCOMPONENTS];
+ ComponentGlyph *cg;
+ Sval scale, offY;
+ SegQ *s₀, *s;
+ Spt *pts;
+ Sval *fp;
+ u8int *b;
+
+ r = -1;
+ ngs = 0;
+ pts = nil;
+
+ if(g->simple != nil){
+ gs[ngs++] = g;
+ }else{
+ for(cg = g->component; cg != nil && ngs < nelem(gs); cg = cg->next, ngs++){
+ if((gs[ngs] = otfglyf(o, cg->glyphIndex)) == nil)
+ goto done;
+ }
+ }
+ for(maxptstotal = maxpts = i = 0; i < ngs; i++){
+ j = glyfmaxnpts(gs[i]);
+ maxptstotal += j;
+ if(maxpts < j)
+ maxpts = j;
+ }
+
+ scale = (Sval)ppem / otfupem(o);
+ baseline = g->yMin < 0 ? ceil(scale*-g->yMin) : 0;
+ offY = baseline > 0 ? (Sval)baseline - scale*-g->yMin : 0;
+ w = ceil((g->xMax - g->xMin)*scale);
+ h = ceil((g->yMax - g->yMin)*scale + (baseline ? 1 : 0));
npx = w*h;
- fp = calloc(1, npx*sizeof(*fp));
- r = qbzr(s₀, ns, w, h, fp);
- free(s₀);
- b = nil;
- if(r == 0){
- b = (u8int*)fp;
+ pts = calloc(1, maxpts*sizeof(*pts) + maxptstotal/2*sizeof(*s) + npx*sizeof(*fp));
+ s = s₀ = (SegQ*)(pts + maxptstotal);
+ fp = (Sval*)(s + maxpts/2);
+ cg = g->component;
+ for(i = 0; i < ngs; i++){
+ int dx = -g->xMin, dy = -g->yMin;
+ if(cg != nil){
+ if(cg->flags & CGLYPH_FL_SIGNED_XY){
+ dx += cg->dx;
+ dy += cg->dy;
+ }
+ cg = cg->next;
+ }
+ if((s = addpoints(s, pts, maxpts, gs[i], dx, dy, scale, offY)) == nil)
+ goto done;
+ }
+
+ if((r = qbzr(s₀, s-s₀, w, h, fp)) == 0){
+ b = (u8int*)pts;
for(i = 0; i < npx; i++)
b[i] = 255 - (fp[i] <= 0 ? 0 : (fp[i] >= QBZR_PIX_SCALE ? 255 : fp[i]/QBZR_PIX_SCALE*255));
if((b = realloc(b, npx)) != nil){
- *wo = w;
- *ho = h;
- fp = nil;
+ im->b = b;
+ im->w = w;
+ im->h = h;
+ im->baseline = baseline;
+ pts = nil;
+ }else{
+ r = -1;
}
}
- free(fp);
- return b;
+
+done:
+ for(i = 0; i < ngs; i++){
+ if(gs[i] != g)
+ free(gs[i]);
+ }
+ free(pts);
+ return r;
}
--- a/unix/test.c
+++ b/unix/test.c
@@ -5,35 +5,11 @@
#include <string.h>
#include "otf.h"
-typedef struct Image Image;
-
-struct Image {
- int w;
- int h;
- u8int *b;
-};
-
static void
-fit(u8int *b, int bw, int bh, Image *im, int maxh, int *x, int *y, int gap)
+dumpmap(FILE *out, GlyfImage *im, int n)
{
- int d;
-
- if((bw-*x) < im->w+gap){
- *y += maxh + gap;
- *x = gap;
- }
- if((bh-*y) < maxh+gap)
- return;
- for(d = 0; d < im->h; d++)
- memcpy(b + (*y + d)*bw + *x, im->b + d*im->w, im->w);
- *x += im->w + gap;
-}
-
-static void
-dumpmap(FILE *out, Image *im, int n)
-{
#define gap 1
- int total, mid, npix, bw, bh, x, y, i, maxh;
+ int total, mid, npix, bw, bh, x, y, i, maxh, d;
u8int *b;
total = 0;
@@ -52,11 +28,19 @@
npix += bw*gap;
if((b = malloc(npix)) == NULL)
err(1, NULL);
-
memset(b, 0xff, npix);
x = y = gap;
- for(i = 0; i < n; i++)
- fit(b, bw, bh, im+i, maxh, &x, &y, gap);
+ for(i = 0; i < n; i++){
+ if((bw-x) < im[i].w+gap){
+ y += maxh + gap;
+ x = gap;
+ }
+ if((bh-y) < maxh+gap)
+ continue;
+ for(d = 0; d < im[i].h; d++)
+ memcpy(b + (maxh - im[i].h + y + im[i].baseline + d)*bw + x, im[i].b + d*im[i].w, im[i].w);
+ x += im[i].w + gap;
+ }
fprintf(out, "%11s %11d %11d %11d %11d ", "k8", 0, 0, bw, y+maxh+gap);
fwrite(b, 1, bw*(y+maxh+gap), out);
free(b);
@@ -146,14 +130,13 @@
fprintf(out.aux, "%s\n", argv[i]);
if(G && gi < 0){
int i, n = otfglyfnum(o);
- Image *im = ppem > 0 ? calloc(n, sizeof(*im)) : NULL;
+ GlyfImage *im = ppem > 0 ? calloc(n, sizeof(*im)) : NULL;
for(i = 0; i < n; i++){
Glyf *g = otfglyf(o, i);
if(g == NULL)
errx(1, "glyph %d: %s", i, otferrstr());
- if(ppem > 0 && g->simple != NULL && g->numberOfContours > 0){
- im[i].b = otfdrawglyf(g, ppem, &im[i].w, &im[i].h);
- if(im[i].b == NULL)
+ if(ppem > 0 && g->numberOfContours != 0){
+ if(otfdrawglyf(o, g, ppem, im+i) != 0)
errx(1, "glyph %d: %s", i, otferrstr());
}else if(ppem <= 0){
fprintf(out.aux, "%d (%s):\n", i,
@@ -181,9 +164,8 @@
if(g->component != NULL)
errx(1, "glyph %d: component", gi);
else{
- Image im;
- im.b = otfdrawglyf(g, ppem, &im.w, &im.h);
- if(im.b == NULL)
+ GlyfImage im;
+ if(otfdrawglyf(o, g, ppem, &im) != 0)
errx(1, "glyph %d: %s", gi, otferrstr());
fprintf(out.aux, "%11s %11d %11d %11d %11d ", "k8", 0, 0, im.w, im.h);
fwrite(im.b, 1, im.w*im.h, out.aux);