summaryrefslogtreecommitdiff
path: root/appl/ebook/units.b
diff options
context:
space:
mode:
Diffstat (limited to 'appl/ebook/units.b')
-rw-r--r--appl/ebook/units.b146
1 files changed, 146 insertions, 0 deletions
diff --git a/appl/ebook/units.b b/appl/ebook/units.b
new file mode 100644
index 00000000..0442fc65
--- /dev/null
+++ b/appl/ebook/units.b
@@ -0,0 +1,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);
+}