ref: d180b70c6c69ffe8168cc8571772ad6e15ac6aba
dir: /font.myr/
use std
use bio
use iter
use "types"
use "image"
use "load"
use "pack"
pkg draw =
const openfont : (dpy : display#, name : byte[:] -> std.result(font#, err))
pkglocal const loadsubfont : (dpy : display#, sub : subfont# -> void)
pkglocal const cachechar : (font : font#, c : char -> int16)
;;
const openfont = {dpy, name
var dir
dir = std.dirname(name)
match bio.open(name, bio.Rd)
| `std.Ok f: -> loadfont(dpy, dir, f)
| `std.Err e: -> `std.Err `Efont
;;
}
const cachechar = {ft, c
match std.htget(ft.cache, c)
| `std.Some inf:
inf.hits++
-> inf.idx
| `std.None:
-> loadglyph(ft, c)
;;
}
const loadglyph = {ft, c
var r : rect
var p : point
var g, info
for sub : iter.byref(ft.subf)
if c < sub.lo || c >= sub.hi
continue
;;
if sub.glyph.len == 0
loadsubfont(ft.cimage.dpy, sub)
;;
/*
l cacheid[4] srcid[4] index[2] r[4*4] sp[2*4] left[1]
width[1]
*/
g = &sub.glyph[c - sub.lo]
p = [.x=g.x, .y=0]
r = [.x0=ft.x, .y0=0, .x1=ft.x + g.width, .y1=ft.ascent]
pack(ft.cimage.dpy, "biisrpbb", 0, \
('l' : byte), \
ft.cimage.id, \
sub.image.id, \
ft.nextidx, \
r, \
p, \
g.left, \
g.width)
flush(ft.cimage.dpy)
info.hits = 0
info.idx = ft.nextidx
std.htput(ft.cache, c, info)
ft.x += g.width
ft.nextidx++
-> info.idx
;;
-> -1
}
const loadfont = {dpy, dir, f
var sp : byte[:][3]
var lo, hi, start, n, r
var font
font = std.zalloc()
match bio.readln(f)
| `std.Ok ln:
std.bstrtok(sp[:2], ln)
font.height = std.getv(std.intparse(sp[0]), -1)
font.ascent = std.getv(std.intparse(sp[0]), -1)
| `std.Err `bio.Eof:
| `std.Err e:
;;
for ln : bio.byline(f)
n = 0
start = 0
std.bstrtok(sp[:3], ln)
lo = std.getv(std.intparse(sp[n++]), -1)
hi = std.getv(std.intparse(sp[n++]), -1)
if sp.len == 4
start = std.getv(std.intparse(sp[n++]), -1)
;;
std.slpush(&font.subf, [
.lo=lo,
.hi=hi,
.start=start,
.path=std.pathcat(dir, sp[n]),
])
;;
/* heuristic: probably big enough... */
font.cache = std.mkht()
r = [.x0 = 0, .y0 = 0, .x1 = 1000, .y1 = font.ascent]
font.cimage = genallocimage(dpy, 0, Refnone, Cgrey8, DBlack, false, r, r)
pack(dpy, "biib", 0, \
('i' : byte), \
font.cimage.id, \
128, \
font.ascent)
-> `std.Ok font
}
const loadsubfont = {dpy, subf
var buf
match std.slurp(subf.path)
| `std.Err e: std.fatal("could not open subf {}: {}\n", subf.path, e)
| `std.Ok b: buf = b
;;
match xload(dpy, buf)
| `std.Err e: std.fatal("could not load image {}: {}\n")
| `std.Ok (img, off):
match readglyphs(buf[off:])
| `std.Ok gd:
subf.image = img
subf.glyph = gd
| `std.Err e:
std.fatal("invalid glyph data in subf {}\n", subf.path)
;;
;;
}
const readglyphs = {glyphdata
var sp : byte[:][3]
var n, height, ascent, err
var gd, g
if glyphdata.len < 3*12 || std.bstrtok(sp[:], glyphdata[:3*12]).len != 3
-> `std.Err `Efmt
;;
err = false
n = getint(sp[0], &err)
height = getint(sp[1], &err)
ascent = getint(sp[2], &err)
glyphdata = glyphdata[3*12:]
if err || glyphdata.len < n
-> `std.Err `Efmt
;;
gd = [][:]
for var i = 0; i <= n; i++
g = [
.x=std.getle16(glyphdata[6*i+0 : 6*i+2]),
.top=(glyphdata[6*i + 2] : int),
.bottom=(glyphdata[6*i + 3] : int),
.left=(glyphdata[6*i + 4] : int),
.width=(glyphdata[6*i + 5] : int),
]
std.slpush(&gd, g)
;;
-> `std.Ok gd
}