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
|
implement Units;
include "sys.m";
sys: Sys;
include "units.m";
Dpi: con 100; # pixels per inch on an average display (pinched from tk)
init()
{
sys = load Sys Sys->PATH;
}
# return length in pixels, and string equivalent;
# makes sure that string equiv is specified in absolute units
# (not in terms of percentage or font size)
# XXX give this a proper testing.
length(s: string, emsize, xsize: int, relative: string): (int, string)
{
(n, units) := units(s);
case units {
Uem =>
px := (n * emsize);
return (px / SCALE, n2s(px) + "px");
Uex =>
px := (n * xsize);
return (px / SCALE, n2s(px) + "px");
Upx =>
return (n / SCALE, s);
Uin =>
return ((n * Dpi) / SCALE, s);
Ucm =>
return ((n * Dpi * 100) / (2540 * SCALE), s);
Umm =>
return ((n * Dpi * 10) / (254 * SCALE), s);
Upt =>
return ((n * Dpi) / (72 * SCALE), s);
Upc =>
return ((n * Dpi * 12) / (72 * SCALE), s);
Upercent or
Unone =>
# treat no units as relative factor.
# the only place this is used is for "line_height" in css, i believe;
# otherwise an unadorned number is not legal.
if (relative == nil)
return (0, nil);
(rn, rs) := length(relative, 0, 0, nil);
px := (n * rn) / SCALE;
if (units == Upercent)
px /= 100;
return (px, string px + "px");
}
return (n / SCALE, s);
}
# return non-relative for unadorned numbers, as it's not defined so anything's ok.
isrelative(s: string): int
{
n := len s;
if (n < 2)
return 0;
if (s[n - 1] == '%')
return 1;
case s[n - 2:] {
"em" or
"ex" =>
return 1;
}
return 0;
}
n2s(n: int): string
{
(i, f) := (n / SCALE, n % SCALE);
if (f == 0)
return string i;
if (f < 0)
f = -f;
return string i + "." + sys->sprint("%.3d", f);
}
Uem, Uex, Upx, Uin, Ucm, Umm, Upt, Upc, Upercent, Unone: con iota;
SCALE: con 1000;
units(s: string): (int, int)
{
# XXX what should we do on error?
if (s == nil)
return (0, -1);
i := 0;
# optional leading sign
neg := 0;
if (s[0] == '-' || s[0] == '+') {
neg = s[0] == '-';
i++;
}
n := 0;
for (; i < len s; i++) {
c := s[i];
if (c < '0' || c > '9')
break;
n = (n * 10) + (c - '0');
}
n *= SCALE;
if (i < len s && s[i] == '.') {
i++;
mul := 100;
for (; i < len s; i++) {
c := s[i];
if (c < '0' || c > '9')
break;
n += (c - '0') * mul;
mul /= 10;
}
}
units := Unone;
if (i < len s) {
case s[i:] {
"em" =>
units = Uem;
"ex" =>
units = Uex;
"px" =>
units = Upx;
"in" =>
units = Uin;
"cm" =>
units = Ucm;
"mm" =>
units = Umm;
"pt" =>
units = Upt;
"pc" =>
units = Upc;
"%" =>
units = Upercent;
* =>
return (0, -1);
}
}
if (neg)
n = -n;
return (n, units);
}
|