summaryrefslogtreecommitdiff
path: root/sys/src/libttf/head.c
diff options
context:
space:
mode:
authoraiju <devnull@localhost>2018-06-09 14:33:19 +0000
committeraiju <devnull@localhost>2018-06-09 14:33:19 +0000
commitdb71e19005574388bdc368081848327a5c104e5a (patch)
treedb33f3a6c6aac49dd9d5bd5a04145b3acf1f0cb7 /sys/src/libttf/head.c
parent198f10bb25382882c4abd9081dac4dd74dbdbb9f (diff)
add libttf
Diffstat (limited to 'sys/src/libttf/head.c')
-rw-r--r--sys/src/libttf/head.c344
1 files changed, 344 insertions, 0 deletions
diff --git a/sys/src/libttf/head.c b/sys/src/libttf/head.c
new file mode 100644
index 000000000..9a50c7f16
--- /dev/null
+++ b/sys/src/libttf/head.c
@@ -0,0 +1,344 @@
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+#include <draw.h>
+#include <ctype.h>
+#include <ttf.h>
+#include "impl.h"
+
+void
+ttfunpack(TTFontU *f, char *p, ...)
+{
+ va_list va;
+ int n;
+ uchar *p1;
+ u16int *p2;
+ u32int *p4;
+
+ va_start(va, p);
+ for(; *p != 0; p++)
+ switch(*p){
+ case 'b':
+ p1 = va_arg(va, u8int *);
+ *p1 = Bgetc(f->bin);
+ break;
+ case 'B':
+ p4 = va_arg(va, u32int *);
+ *p4 = Bgetc(f->bin);
+ break;
+ case 'w':
+ p2 = va_arg(va, u16int *);
+ *p2 = Bgetc(f->bin) << 8;
+ *p2 |= Bgetc(f->bin);
+ break;
+ case 'W':
+ p4 = va_arg(va, u32int *);
+ *p4 = Bgetc(f->bin) << 8;
+ *p4 |= Bgetc(f->bin);
+ break;
+ case 'S':
+ p4 = va_arg(va, u32int *);
+ *p4 = (char)Bgetc(f->bin) << 8;
+ *p4 |= Bgetc(f->bin);
+ break;
+ case 'l':
+ p4 = va_arg(va, u32int *);
+ *p4 = Bgetc(f->bin) << 24;
+ *p4 |= Bgetc(f->bin) << 16;
+ *p4 |= Bgetc(f->bin) << 8;
+ *p4 |= Bgetc(f->bin);
+ break;
+ case '.': Bgetc(f->bin); break;
+ case ' ': break;
+ default:
+ if(isdigit(*p)){
+ n = strtol(p, &p, 10);
+ p--;
+ Bseek(f->bin, n, 1);
+ }else abort();
+ break;
+ }
+}
+
+static int
+directory(TTFontU *f)
+{
+ u32int scaler;
+ int i;
+
+ ttfunpack(f, "lw .. .. ..", &scaler, &f->ntab);
+ if(scaler != 0x74727565 && scaler != 0x10000){
+ werrstr("unknown scaler type %#ux", scaler);
+ return -1;
+ }
+ f->tab = mallocz(sizeof(TTTable) * f->ntab, 1);
+ if(f->tab == nil) return -1;
+ for(i = 0; i < f->ntab; i++)
+ ttfunpack(f, "llll", &f->tab[i].tag, &f->tab[i].csum, &f->tab[i].offset, &f->tab[i].len);
+ return 0;
+}
+
+int
+ttfgototable(TTFontU *f, char *str)
+{
+ TTTable *t;
+ u32int tag;
+
+ tag = (u8int)str[0] << 24 | (u8int)str[1] << 16 | (u8int)str[2] << 8 | (u8int)str[3];
+ for(t = f->tab; t < f->tab + f->ntab; t++)
+ if(t->tag == tag){
+ Bseek(f->bin, t->offset, 0);
+ return t->len;
+ }
+ werrstr("no such table '%s'", str);
+ return -1;
+}
+
+static int
+ttfparseloca(TTFontU *f)
+{
+ int len, i;
+ u32int x;
+
+ len = ttfgototable(f, "loca");
+ if(len < 0) return -1;
+ x = 0;
+ if(f->longloca){
+ if(len > (f->numGlyphs + 1) * 4) len = (f->numGlyphs + 1) * 4;
+ for(i = 0; i < len/4; i++){
+ x = Bgetc(f->bin) << 24;
+ x |= Bgetc(f->bin) << 16;
+ x |= Bgetc(f->bin) << 8;
+ x |= Bgetc(f->bin);
+ f->ginfo[i].loca = x;
+ }
+ }else{
+ if(len > (f->numGlyphs + 1) * 2) len = (f->numGlyphs + 1) * 2;
+ for(i = 0; i < len/2; i++){
+ x = Bgetc(f->bin) << 8;
+ x |= Bgetc(f->bin);
+ f->ginfo[i].loca = x * 2;
+ }
+ }
+ for(; i < f->numGlyphs; i++)
+ f->ginfo[i].loca = x;
+ return 0;
+}
+
+static int
+ttfparsehmtx(TTFontU *f)
+{
+ int i;
+ u16int x, y;
+ int len;
+ int maxlsb;
+
+ len = ttfgototable(f, "hmtx");
+ if(len < 0)
+ return -1;
+ if(f->numOfLongHorMetrics > f->numGlyphs){
+ werrstr("nonsensical header: numOfLongHorMetrics > numGlyphs");
+ return -1;
+ }
+ for(i = 0; i < f->numOfLongHorMetrics; i++){
+ ttfunpack(f, "ww", &x, &y);
+ f->ginfo[i].advanceWidth = x;
+ f->ginfo[i].lsb = y;
+ }
+ maxlsb = (len - 2 * f->numOfLongHorMetrics) / 2;
+ if(maxlsb > f->numGlyphs){
+ werrstr("nonsensical header: maxlsb > f->numGlyphs");
+ return -1;
+ }
+ for(; i < maxlsb; i++){
+ ttfunpack(f, "w", &y);
+ f->ginfo[i].advanceWidth = x;
+ f->ginfo[i].lsb = y;
+ }
+ for(; i < f->numGlyphs; i++){
+ f->ginfo[i].advanceWidth = x;
+ f->ginfo[i].lsb = y;
+ }
+ return 0;
+}
+
+int
+ttfparsecvt(TTFontU *f)
+{
+ int len;
+ int i;
+ int x;
+ u8int *p;
+ short *w;
+
+ len = ttfgototable(f, "cvt ");
+ if(len <= 0) return 0;
+ f->cvtu = mallocz(len, 1);
+ if(f->cvtu == 0) return -1;
+ Bread(f->bin, f->cvtu, len);
+ p = (u8int *) f->cvtu;
+ f->ncvtu = len / 2;
+ w = f->cvtu;
+ for(i = 0; i < f->ncvtu; i++){
+ x = (short)(p[0] << 8 | p[1]);
+ p += 2;
+ *w++ = x;
+ }
+ return 0;
+}
+
+static int
+ttfparseos2(TTFontU *f)
+{
+ int len;
+ u16int usWinAscent, usWinDescent;
+
+ len = ttfgototable(f, "OS/2 ");
+ if(len < 0)
+ return -1;
+ if(len < 78){
+ werrstr("OS/2 table too short");
+ return -1;
+ }
+ ttfunpack(f, "68 6 ww", &usWinAscent, &usWinDescent);
+ f->ascent = usWinAscent;
+ f->descent = usWinDescent;
+ return 0;
+}
+
+static void
+ttfcloseu(TTFontU *u)
+{
+ int i;
+
+ if(u == nil) return;
+ Bterm(u->bin);
+ for(i = 0; i < u->ncmap; i++)
+ free(u->cmap[i].tab);
+ free(u->cmap);
+ free(u->ginfo);
+ free(u->tab);
+ free(u->cvtu);
+ free(u);
+}
+
+void
+ttfclose(TTFont *f)
+{
+ int i;
+
+ if(f == nil) return;
+ if(--f->u->ref <= 0)
+ ttfcloseu(f->u);
+ for(i = 0; i < f->u->maxFunctionDefs; i++)
+ free(f->func[i].pgm);
+ free(f->hintstack);
+ free(f->func);
+ free(f->storage);
+ free(f->twilight);
+ free(f->twiorg);
+ free(f->cvt);
+ free(f);
+}
+
+static TTFont *
+ttfscaleu(TTFontU *u, int ppem)
+{
+ TTFont *f;
+ int i;
+
+ f = mallocz(sizeof(TTFont), 1);
+ if(f == nil) return nil;
+ f->u = u;
+ u->ref++;
+ f->ppem = ppem;
+ f->ncvt = u->ncvtu;
+ f->cvt = malloc(sizeof(int) * u->ncvtu);
+ if(f->cvt == nil) goto error;
+ for(i = 0; i < u->ncvtu; i++)
+ f->cvt[i] = ttfrounddiv(u->cvtu[i] * ppem * 64, u->emsize);
+ f->hintstack = mallocz(sizeof(u32int) * u->maxStackElements, 1);
+ f->func = mallocz(sizeof(TTFunction) * u->maxFunctionDefs, 1);
+ f->storage = mallocz(sizeof(u32int) * u->maxStorage, 1);
+ f->twilight = mallocz(sizeof(TTPoint) * u->maxTwilightPoints, 1);
+ f->twiorg = mallocz(sizeof(TTPoint) * u->maxTwilightPoints, 1);
+ if(f->hintstack == nil || f->func == nil || f->storage == nil || f->twilight == nil || f->twiorg == nil) goto error;
+ f->ascentpx = (u->ascent * ppem + u->emsize - 1) / (u->emsize);
+ f->descentpx = (u->descent * ppem + u->emsize - 1) / (u->emsize);
+ if(ttfrunfpgm(f) < 0) goto error;
+ if(ttfruncvt(f) < 0) goto error;
+ return f;
+
+error:
+ ttfclose(f);
+ return nil;
+}
+
+TTFont *
+ttfopen(char *name, int ppem, int)
+{
+ Biobuf *b;
+ TTFontU *u;
+
+ if(ppem < 0){
+ werrstr("invalid ppem argument");
+ return nil;
+ }
+ b = Bopen(name, OREAD);
+ if(b == nil)
+ return nil;
+ u = mallocz(sizeof(TTFontU), 1);
+ if(u == nil)
+ return nil;
+ u->bin = b;
+ u->nkern = -1;
+ directory(u);
+ if(ttfgototable(u, "head") < 0) goto error;
+ ttfunpack(u, "16 w W 16 wwww 6 w", &u->flags, &u->emsize, &u->xmin, &u->ymin, &u->xmax, &u->ymax, &u->longloca);
+ if(ttfgototable(u, "maxp") < 0) goto error;
+ ttfunpack(u, "4 wwwwwwwwwwwwww",
+ &u->numGlyphs, &u->maxPoints, &u->maxCountours, &u->maxComponentPoints, &u->maxComponentCountours,
+ &u->maxZones, &u->maxTwilightPoints, &u->maxStorage, &u->maxFunctionDefs, &u->maxInstructionDefs,
+ &u->maxStackElements, &u->maxSizeOfInstructions, &u->maxComponentElements, &u->maxComponentDepth);
+ u->ginfo = mallocz(sizeof(TTGlyphInfo) * (u->numGlyphs + 1), 1);
+ if(u->ginfo == nil)
+ goto error;
+ if(ttfgototable(u, "hhea") < 0) goto error;
+ ttfunpack(u, "10 wwww 16 w", &u->advanceWidthMax, &u->minLeftSideBearing, &u->minRightSideBearing, &u->xMaxExtent, &u->numOfLongHorMetrics);
+ if(ttfparseloca(u) < 0) goto error;
+ if(ttfparsehmtx(u) < 0) goto error;
+ if(ttfparsecvt(u) < 0) goto error;
+ if(ttfparsecmap(u) < 0) goto error;
+ if(ttfparseos2(u) < 0) goto error;
+ return ttfscaleu(u, ppem);
+
+error:
+ ttfcloseu(u);
+ return nil;
+}
+
+TTFont *
+ttfscale(TTFont *f, int ppem, int)
+{
+ return ttfscaleu(f->u, ppem);
+}
+
+int
+ttfrounddiv(int a, int b)
+{
+ if(b < 0){ a = -a; b = -b; }
+ if(a > 0)
+ return (a + b/2) / b;
+ else
+ return (a - b/2) / b;
+}
+
+int
+ttfvrounddiv(vlong a, int b)
+{
+ if(b < 0){ a = -a; b = -b; }
+ if(a > 0)
+ return (a + b/2) / b;
+ else
+ return (a - b/2) / b;
+}