1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
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;
}
}
|