File: length.mll

package info (click to toggle)
hevea 2.36-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 3,780 kB
  • sloc: ml: 19,453; sh: 503; makefile: 311; ansic: 132
file content (112 lines) | stat: -rw-r--r-- 3,724 bytes parent folder | download | duplicates (2)
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
(***********************************************************************)
(*                                                                     *)
(*                          HEVEA                                      *)
(*                                                                     *)
(*  Luc Maranget, projet Moscova, INRIA Rocquencourt                   *)
(*                                                                     *)
(*  Copyright 2001 Institut National de Recherche en Informatique et   *)
(*  Automatique.  Distributed only by permission.                      *)
(*                                                                     *)
(*  $Id: length.mll,v 1.16 2012-06-05 14:55:39 maranget Exp $          *)
(***********************************************************************)

{
open Lexing

exception ConversionFailure
;;

let base_font_size = 12 (* Reasonable default: 1em = 12pt; units: pt *)
;;

let base_font_size_float = float base_font_size
;;

(*  [base_font_relative_ex_size_float] is just a heuristic; any value
 *  between 0.42 to 0.54 seems reasonable, i.e. is backed by fonts
 *  actually used in browsers.
 *
 *  W3C: "In the cases where it is impossible or impractical to
 *  determine the x-height, a value of 0.5em should be used." *)
let base_font_relative_ex_size_float = 0.5
;;

let points_per_pixel = 0.75 (* W3C definition: 12pt = 16px; units: pt/px *)
and pixels_per_char = 16 (* units: px/char *)
;;

let pixel_to_char x = (100 * x + 50) / (100 * pixels_per_char)
and pixel_to_char_float x = float_of_int x /. float_of_int pixels_per_char
and char_to_pixel x = pixels_per_char * x
;;

type t =
  | Char of int
  | Pixel of int
  | Percent of int
  | NotALength of string
  | Default

let pretty = function
  | Char x -> string_of_int x ^ " chars"
  | Pixel x -> string_of_int x ^ " pxls"
  | Percent x -> string_of_int x ^ "%"
  | Default -> "default"
  | NotALength s -> "*" ^ s ^ "*"

let is_zero = function
  | Char 0 | Pixel 0 | Percent 0 -> true
  | _ -> false

let as_number_of_chars = function
  | Char n -> n
  | Pixel x -> pixel_to_char x
  | Percent _ | NotALength _ | Default -> raise ConversionFailure
;;

let pixel_of_em x = Pixel (int_of_float (Float.round (float_of_int pixels_per_char *. x)))
and pixel_of_point x = Pixel (int_of_float (Float.round (x /. points_per_pixel)))
and as_percent x = Percent (int_of_float (Float.round x))

let convert unit x =
  (* mainly TeX Book, Chapter 10 *)
  match unit with
  | "bp" -> pixel_of_point (x *. 72.27 /. 72.0)
  | "cc" -> pixel_of_point (x *. 14856.0 /. 1157.0)
  | "cm" -> pixel_of_em ((x *. 28.47) /. base_font_size_float)
  | "dd" -> pixel_of_point (x *. 1238.0 /. 1157.0)
  | "em" -> pixel_of_em x
  | "ex" -> pixel_of_em (x *. base_font_relative_ex_size_float)
  | "in" -> pixel_of_em ((x *. 72.27) /. base_font_size_float)
  | "mm" -> pixel_of_em ((x *. 2.847) /. base_font_size_float)
  | "pc" -> pixel_of_em ((x *. 12.0)  /. base_font_size_float)
  | "pt" -> pixel_of_point x
  | "sp" -> pixel_of_point (x /. 65536.0)
  | "@percent" -> as_percent (100.0 *. x)
  | _ -> NotALength unit
;;

}

rule main_rule = parse
  '-' {let x, unit = positif lexbuf in convert unit (0.0 -. x)}
|  "" {let x, unit = positif lexbuf in convert unit x}

and positif = parse
| ['0'-'9']*'.'?['0'-'9']+
   {let lxm = lexeme lexbuf in float_of_string lxm, unit lexbuf}
| "@percent" {1.0, "@percent"}
| "" {raise ConversionFailure}
and unit = parse
| [' ''\n''\t''\r']+ {unit lexbuf}
| [^' ''\n''\t''\r']* {lexeme lexbuf}

{
open Lexing

let main lexbuf =
  try main_rule lexbuf with
  | ConversionFailure ->
      let sbuf = lexbuf.lex_buffer in
      NotALength (Bytes.sub_string sbuf 0 lexbuf.lex_buffer_len)
}