1 (***********************************************************************)
3 (* MLTk, Tcl/Tk interface of Objective Caml *)
5 (* Francois Rouaix, Francois Pessaux, Jun Furuse and Pierre Weis *)
6 (* projet Cristal, INRIA Rocquencourt *)
7 (* Jacques Garrigue, Kyoto University RIMS *)
9 (* Copyright 2002 Institut National de Recherche en Informatique et *)
10 (* en Automatique and Kyoto University. All rights reserved. *)
11 (* This file is distributed under the terms of the GNU Library *)
12 (* General Public License, with the special exception on linking *)
13 (* described in file LICENSE found in the Objective Caml source tree. *)
15 (***********************************************************************)
16 (* find font information *)
20 if !debug then try prerr_endline s with _ -> ()
22 type ('s, 'i) xlfd = {
23 (* some of them are currently not interesting for me *)
30 mutable pixelSize: 'i;
31 mutable pointSize: 'i;
32 mutable resolutionX: 'i;
33 mutable resolutionY: 'i;
35 mutable averageWidth: 'i;
40 let copy xlfd = {xlfd with foundry= xlfd.foundry}
42 let string_of_xlfd s i xlfd =
43 let foundry= s xlfd.foundry
44 and family= s xlfd.family
45 and weight= s xlfd.weight
46 and slant= s xlfd.slant
47 and setWidth = s xlfd.setWidth
48 and addStyle = s xlfd.addStyle
49 and pixelSize= i xlfd.pixelSize
50 and pointSize = i xlfd.pointSize
51 and resolutionX = i xlfd.resolutionX
52 and resolutionY = i xlfd.resolutionY
53 and spacing= s xlfd.spacing
54 and averageWidth = i xlfd.averageWidth
55 and registry= s xlfd.registry
56 and encoding = s xlfd.encoding in
73 exception Parse_Xlfd_Failure of string
75 let parse_xlfd xlfd_string =
76 (* this must not be a pattern *)
77 let split_str char_sep str =
78 let len = String.length str in
79 let rec split beg cur =
80 if cur >= len then [String.sub str beg (len - beg)]
81 else if char_sep (String.get str cur)
83 let nextw = succ cur in
84 (String.sub str beg (cur - beg))
86 else split beg (succ cur) in
89 match split_str (function '-' -> true | _ -> false) xlfd_string with
90 | [ _; foundry; family; weight; slant; setWidth; addStyle; pixelSize;
91 pointSize; resolutionX; resolutionY; spacing; averageWidth;
92 registry; encoding ] ->
99 pixelSize= int_of_string pixelSize;
100 pointSize= int_of_string pointSize;
101 resolutionX= int_of_string resolutionX;
102 resolutionY= int_of_string resolutionY;
104 averageWidth= int_of_string averageWidth;
108 | _ -> raise (Parse_Xlfd_Failure xlfd_string)
110 type valid_xlfd = (string, int) xlfd
112 let string_of_valid_xlfd = string_of_xlfd (fun x -> x) string_of_int
114 type pattern = (string option, int option) xlfd
133 let string_of_pattern =
138 let pat_string = pat (fun x -> x) in
139 let pat_int = pat string_of_int in
140 string_of_xlfd pat_string pat_int
142 let is_vector_font xlfd =
143 (xlfd.pixelSize = 0 && xlfd.resolutionX = 0 && xlfd.resolutionY = 0) ||
146 let list_fonts dispname pattern =
147 let dispopt = match dispname with
149 | Some x -> "-display " ^ x
151 let result = List.map parse_xlfd
152 (Shell.subshell ("xlsfonts "^dispopt^" -fn "^string_of_pattern pattern))
154 if result = [] then raise Not_found
157 let available_pixel_size_aux dispname pattern =
158 (* return available pixel size without font resizing *)
159 (* to obtain good result, *)
160 (* the pattern should contain as many information as possible *)
161 let pattern = copy pattern in
162 pattern.pixelSize <- None;
163 let xlfds = list_fonts dispname pattern in
164 let pxszs = Hashtbl.create 107 in
165 List.iter (fun xlfd ->
166 Hashtbl.add pxszs xlfd.pixelSize xlfd) xlfds;
169 let extract_size_font_hash tbl =
171 Hashtbl.iter (fun k _ ->
172 if not (List.mem k !keys) then keys := k :: !keys) tbl;
173 Sort.list (fun (k1,_) (k2,_) -> k1 < k2)
174 (List.map (fun k -> k, Hashtbl.find_all tbl k) !keys)
176 let available_pixel_size dispname pattern =
177 let pxszs = available_pixel_size_aux dispname pattern in
178 extract_size_font_hash pxszs
180 let nearest_pixel_size dispname vector_ok pattern =
181 (* find the font with the nearest pixel size *)
182 log ("\n*** "^string_of_pattern pattern);
184 match pattern.pixelSize with
185 None -> raise (Failure "invalid pixelSize pattern")
188 let tbl = available_pixel_size_aux dispname pattern in
189 let newtbl = Hashtbl.create 107 in
190 Hashtbl.iter (fun s xlfd ->
193 if is_vector_font xlfd then begin
194 log (Printf.sprintf "%s is vector" (string_of_valid_xlfd xlfd));
195 xlfd.pixelSize <- pxlsz;
196 Hashtbl.add newtbl pxlsz xlfd
198 end else Hashtbl.add newtbl s xlfd
199 else if not (is_vector_font xlfd) && s <> 0 then
200 Hashtbl.add newtbl s xlfd) tbl;
202 let size_font_table = extract_size_font_hash newtbl in
204 let diff = ref 10000 in
205 let min = ref None in
206 List.iter (fun (s,xlfds) ->
207 let d = abs(s - pxlsz) in
208 if d < !diff then begin
209 min := Some (s,xlfds);
211 end) size_font_table;
212 (* if it contains more than one font, just return the first *)
214 | None -> raise Not_found
216 log (Printf.sprintf "Size %d is selected" s);
217 List.iter (fun xlfd -> log (string_of_valid_xlfd xlfd)) xlfds;