diff options
Diffstat (limited to 'appl/ebook/cssfont.b')
| -rw-r--r-- | appl/ebook/cssfont.b | 179 |
1 files changed, 179 insertions, 0 deletions
diff --git a/appl/ebook/cssfont.b b/appl/ebook/cssfont.b new file mode 100644 index 00000000..6fbd18db --- /dev/null +++ b/appl/ebook/cssfont.b @@ -0,0 +1,179 @@ +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; + } +} |
