Initial commit: Schunix as it stands before the SchOS rename
An x86-64 operating system built from xv6, now largely rewritten: SMP, a copy-on-write root filesystem (SchFS), PCI/USB/virtio drivers, a TTF rasteriser, and a Linux-numbered syscall ABI. No history before this point -- the tree was never under version control. This commit exists so the rename that follows has something to undo to.
This commit is contained in:
commit
d0f7acf9eb
275 changed files with 51417 additions and 0 deletions
81
tools/ttftest.c
Normal file
81
tools/ttftest.c
Normal file
|
|
@ -0,0 +1,81 @@
|
|||
// Host harness for kernel/dev/ttf.c.
|
||||
//
|
||||
// A rasteriser is checked by looking at it. This renders a string with the real
|
||||
// font and writes a PGM, which is the smallest image format that needs no
|
||||
// compression -- the point is the glyphs, not the container.
|
||||
//
|
||||
// build/tools/ttftest <font.ttf> <px> "text" out.pgm
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#define TTF_HOST
|
||||
#include "../kernel/dev/ttf.c"
|
||||
|
||||
int ttf_render(struct ttf *, uint32, struct glyph *, unsigned char *, int, int *, int *);
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
if (argc < 5) { fprintf(stderr, "usage: ttftest font.ttf px \"text\" out.pgm\n"); return 1; }
|
||||
const char *path = argv[1];
|
||||
int px = atoi(argv[2]);
|
||||
const char *text = argv[3];
|
||||
|
||||
FILE *fp = fopen(path, "rb");
|
||||
if (!fp) { perror(path); return 1; }
|
||||
fseek(fp, 0, SEEK_END); long n = ftell(fp); fseek(fp, 0, SEEK_SET);
|
||||
unsigned char *buf = malloc(n);
|
||||
if (fread(buf, 1, n, fp) != (size_t)n) { fprintf(stderr, "short read\n"); return 1; }
|
||||
fclose(fp);
|
||||
|
||||
struct ttf f;
|
||||
if (ttf_open(&f, buf, (uint32)n, px) != 0) {
|
||||
fprintf(stderr, "not a TrueType font this can read\n"); return 1;
|
||||
}
|
||||
printf("unitsPerEm %d, %d glyphs, ascent %d descent %d, %s loca\n",
|
||||
f.units_per_em, f.num_glyphs, f.ascent, f.descent,
|
||||
f.long_loca ? "long" : "short");
|
||||
|
||||
struct font *fo = ttf_font(&f);
|
||||
int H = fo->ops->height(fo) + px; // room for descenders and padding
|
||||
int base = fo->ops->baseline(fo) + px / 2;
|
||||
int W = 16;
|
||||
for (const char *p = text; *p; p++) W += px; // generous
|
||||
|
||||
unsigned char *img = calloc(W * H, 1);
|
||||
int pen = 8, drawn = 0, missing = 0;
|
||||
|
||||
for (const char *p = text; *p; p++) {
|
||||
struct glyph g;
|
||||
// Through the provider, not ttf_render, so the glyph cache is on the
|
||||
// path being tested rather than bypassed by the harness.
|
||||
if (fo->ops->glyph(fo, (unsigned char)*p, &g) != 0) {
|
||||
missing++;
|
||||
pen += px / 2;
|
||||
continue;
|
||||
}
|
||||
for (int gy = 0; gy < g.h; gy++)
|
||||
for (int gx = 0; gx < g.w; gx++) {
|
||||
int X = pen + g.bearing_x + gx;
|
||||
int Y = base - g.bearing_y + gy;
|
||||
if (X < 0 || Y < 0 || X >= W || Y >= H) continue;
|
||||
int v = img[Y * W + X] + g.cov[gy * g.w + gx];
|
||||
img[Y * W + X] = v > 255 ? 255 : v;
|
||||
}
|
||||
pen += g.advance;
|
||||
drawn++;
|
||||
}
|
||||
|
||||
// White on black inverted to black on white, which is how text is read.
|
||||
for (int i = 0; i < W * H; i++) img[i] = 255 - img[i];
|
||||
|
||||
FILE *o = fopen(argv[4], "wb");
|
||||
fprintf(o, "P5\n%d %d\n255\n", W, H);
|
||||
fwrite(img, 1, W * H, o);
|
||||
fclose(o);
|
||||
|
||||
printf("%d glyphs drawn, %d missing, %d px advance, image %dx%d -> %s\n",
|
||||
drawn, missing, pen - 8, W, H, argv[4]);
|
||||
return drawn ? 0 : 1;
|
||||
}
|
||||
Loading…
Reference in a new issue