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 }