ref: 38c0cf0737de03906729054ad7b7b011dd1ca475
dir: /appl/ebook/cssfont.b/
implement CSSfont; include "sys.m"; sys: Sys; include "draw.m"; draw: Draw; Font: import draw; include "units.m"; units: Units; include "cssfont.m"; # locally available font styles BOLD, CW, ITALIC, PLAIN, NSTYLES: con iota; NSIZES: con 5; # number of locally available font sizes fonts := array[] of { PLAIN => array[] of { "/fonts/charon/plain.tiny.font", "/fonts/charon/plain.small.font", "/fonts/charon/plain.normal.font", "/fonts/charon/plain.large.font", "/fonts/charon/plain.vlarge.font", }, BOLD => array[] of { "/fonts/charon/bold.tiny.font", "/fonts/charon/bold.small.font", "/fonts/charon/bold.normal.font", "/fonts/charon/bold.large.font", "/fonts/charon/bold.vlarge.font", }, CW => array[] of { "/fonts/charon/cw.tiny.font", "/fonts/charon/cw.small.font", "/fonts/charon/cw.normal.font", "/fonts/charon/cw.large.font", "/fonts/charon/cw.vlarge.font", }, ITALIC => array[] of { "/fonts/charon/italic.tiny.font", "/fonts/charon/italic.small.font", "/fonts/charon/italic.normal.font", "/fonts/charon/italic.large.font", "/fonts/charon/italic.vlarge.font", }, }; fontinfo := array[NSTYLES] of array of ref Font; sizechoice := array[NSTYLES] of array of byte; init(displ: ref Draw->Display) { sys = load Sys Sys->PATH; draw = load Draw Draw->PATH; units = load Units Units->PATH; if (units == nil) { sys->fprint(sys->fildes(2), "cssfont: cannot load %s: %r\n", Units->PATH); raise "fail:bad module"; } units->init(); for (i := 0; i < len fonts; i++) { fpaths := fonts[i]; fontinfo[i] = array[len fpaths] of ref Font; # could make this process lazier, only computing sizes # when a font of a particular class was asked for. maxheight := 0; for (j := 0; j < len fpaths; j++) { if ((fontinfo[i][j] = f := Font.open(displ, fpaths[j])) == nil) { sys->fprint(sys->fildes(2), "cssfont: font %s unavailable: %r\n", fpaths[j]); raise "fail:font unavailable"; } if (f.height > maxheight) maxheight = f.height; } sizechoice[i] = array[maxheight + 1] of byte; for (j = 0; j < maxheight + 1; j++) sizechoice[i][j] = byte matchheight(j, fontinfo[i]); } # for (i = 0; i < NSTYLES; i++) { # sys->print("class %d\n", i); # for (j := 0; j < NSIZES; j++) { # sys->print(" height %d; translates to %d [%d]\n", # fontinfo[i][j].height, # int sizechoice[i][fontinfo[i][j].height], # fontinfo[i][int sizechoice[i][fontinfo[i][j].height]].height); # } # } } # find the closest match to a given desired height from the choices given. matchheight(desired: int, choices: array of ref Font): int { n := len choices; if (desired <= choices[0].height) return 0; if (desired >= choices[n - 1].height) return n - 1; for (i := 1; i < n; i++) { if (desired >= choices[i - 1].height && desired <= choices[i].height) { if (desired - choices[i - 1].height < choices[i].height - desired) return i - 1; else return i; } } sys->fprint(sys->fildes(2), "cssfont: can't happen!\n"); raise "error"; return -1; # should never happen } # get an appropriate font given the css specification. getfont(spec: Spec, parentem, parentex: int): (string, int, int) { #sys->print("getfont size:%s family:%s; style:%s; weight:%s -> ", # spec.size, spec.family, spec.style, spec.weight); class := getclass(spec); i := choosesize(class, spec.size, parentem, parentex); #sys->print("%s (height:%d)\n", fonts[class][i], fontinfo[class][i].height); # XXX i suppose we should really find out what height(widgth?) the 'x' is. return (fonts[class][i], fontinfo[class][i].height, fontinfo[class][i].height); } getclass(spec: Spec): int { if (spec.family == "monospace") return CW; if (spec.style == "italic") return ITALIC; if (spec.weight == "bold") return BOLD; return PLAIN; } choosesize(class: int, size: string, parentem, parentex: int): int { if (size != nil && (size[0] >= '0' && size[0] <= '9')) { (height, nil) := units->length(size, parentem, parentex, nil); choices := sizechoice[class]; if (height > len choices) height = len choices - 1; return int choices[height]; } case size { "xx-small" or "x-small" => return 0; "small" => return 1; "medium" => return 2; "large" => return 3; "x-large" or "xx-large" => return 4; "larger" or "smaller" => choice := sizechoice[class]; if (parentem >= len choice) parentem = len choice - 1; i := int choice[parentem]; if (size[0] == 's') { if (i > 0) i--; } else { if (i < len fonts[class] - 1) i++; } return i; * => sys->fprint(sys->fildes(2), "cssfont: unknown font size spec '%s'\n", size); return 2; } }