219 lines
6.8 KiB
OCaml
219 lines
6.8 KiB
OCaml
(***********************************************************************)
|
|
(* *)
|
|
(* MLTk, Tcl/Tk interface of Objective Caml *)
|
|
(* *)
|
|
(* Francois Rouaix, Francois Pessaux, Jun Furuse and Pierre Weis *)
|
|
(* projet Cristal, INRIA Rocquencourt *)
|
|
(* Jacques Garrigue, Kyoto University RIMS *)
|
|
(* *)
|
|
(* Copyright 2002 Institut National de Recherche en Informatique et *)
|
|
(* en Automatique and Kyoto University. All rights reserved. *)
|
|
(* This file is distributed under the terms of the GNU Library *)
|
|
(* General Public License, with the special exception on linking *)
|
|
(* described in file LICENSE found in the Objective Caml source tree. *)
|
|
(* *)
|
|
(***********************************************************************)
|
|
(* find font information *)
|
|
|
|
let debug = ref false
|
|
let log s =
|
|
if !debug then try prerr_endline s with _ -> ()
|
|
|
|
type ('s, 'i) xlfd = {
|
|
(* some of them are currently not interesting for me *)
|
|
mutable foundry: 's;
|
|
mutable family: 's;
|
|
mutable weight: 's;
|
|
mutable slant: 's;
|
|
mutable setWidth: 's;
|
|
mutable addStyle: 's;
|
|
mutable pixelSize: 'i;
|
|
mutable pointSize: 'i;
|
|
mutable resolutionX: 'i;
|
|
mutable resolutionY: 'i;
|
|
mutable spacing: 's;
|
|
mutable averageWidth: 'i;
|
|
mutable registry: 's;
|
|
mutable encoding: 's
|
|
}
|
|
|
|
let copy xlfd = {xlfd with foundry= xlfd.foundry}
|
|
|
|
let string_of_xlfd s i xlfd =
|
|
let foundry= s xlfd.foundry
|
|
and family= s xlfd.family
|
|
and weight= s xlfd.weight
|
|
and slant= s xlfd.slant
|
|
and setWidth = s xlfd.setWidth
|
|
and addStyle = s xlfd.addStyle
|
|
and pixelSize= i xlfd.pixelSize
|
|
and pointSize = i xlfd.pointSize
|
|
and resolutionX = i xlfd.resolutionX
|
|
and resolutionY = i xlfd.resolutionY
|
|
and spacing= s xlfd.spacing
|
|
and averageWidth = i xlfd.averageWidth
|
|
and registry= s xlfd.registry
|
|
and encoding = s xlfd.encoding in
|
|
|
|
"-"^foundry^
|
|
"-"^family^
|
|
"-"^weight^
|
|
"-"^slant^
|
|
"-"^setWidth ^
|
|
"-"^addStyle ^
|
|
"-"^pixelSize^
|
|
"-"^pointSize ^
|
|
"-"^resolutionX ^
|
|
"-"^resolutionY ^
|
|
"-"^spacing^
|
|
"-"^averageWidth ^
|
|
"-"^registry^
|
|
"-"^encoding
|
|
|
|
exception Parse_Xlfd_Failure of string
|
|
|
|
let parse_xlfd xlfd_string =
|
|
(* this must not be a pattern *)
|
|
let split_str char_sep str =
|
|
let len = String.length str in
|
|
let rec split beg cur =
|
|
if cur >= len then [String.sub str beg (len - beg)]
|
|
else if char_sep (String.get str cur)
|
|
then
|
|
let nextw = succ cur in
|
|
(String.sub str beg (cur - beg))
|
|
::(split nextw nextw)
|
|
else split beg (succ cur) in
|
|
split 0 0
|
|
in
|
|
match split_str (function '-' -> true | _ -> false) xlfd_string with
|
|
| [ _; foundry; family; weight; slant; setWidth; addStyle; pixelSize;
|
|
pointSize; resolutionX; resolutionY; spacing; averageWidth;
|
|
registry; encoding ] ->
|
|
{ foundry= foundry;
|
|
family= family;
|
|
weight= weight;
|
|
slant= slant;
|
|
setWidth= setWidth;
|
|
addStyle= addStyle;
|
|
pixelSize= int_of_string pixelSize;
|
|
pointSize= int_of_string pointSize;
|
|
resolutionX= int_of_string resolutionX;
|
|
resolutionY= int_of_string resolutionY;
|
|
spacing= spacing;
|
|
averageWidth= int_of_string averageWidth;
|
|
registry= registry;
|
|
encoding= encoding;
|
|
}
|
|
| _ -> raise (Parse_Xlfd_Failure xlfd_string)
|
|
|
|
type valid_xlfd = (string, int) xlfd
|
|
|
|
let string_of_valid_xlfd = string_of_xlfd (fun x -> x) string_of_int
|
|
|
|
type pattern = (string option, int option) xlfd
|
|
|
|
let empty_pattern =
|
|
{ foundry= None;
|
|
family= None;
|
|
weight= None;
|
|
slant= None;
|
|
setWidth= None;
|
|
addStyle= None;
|
|
pixelSize= None;
|
|
pointSize= None;
|
|
resolutionX= None;
|
|
resolutionY= None;
|
|
spacing= None;
|
|
averageWidth= None;
|
|
registry= None;
|
|
encoding= None;
|
|
}
|
|
|
|
let string_of_pattern =
|
|
let pat f = function
|
|
Some x -> f x
|
|
| None -> "*"
|
|
in
|
|
let pat_string = pat (fun x -> x) in
|
|
let pat_int = pat string_of_int in
|
|
string_of_xlfd pat_string pat_int
|
|
|
|
let is_vector_font xlfd =
|
|
(xlfd.pixelSize = 0 && xlfd.resolutionX = 0 && xlfd.resolutionY = 0) ||
|
|
xlfd.spacing <> "c"
|
|
|
|
let list_fonts dispname pattern =
|
|
let dispopt = match dispname with
|
|
None -> ""
|
|
| Some x -> "-display " ^ x
|
|
in
|
|
let result = List.map parse_xlfd
|
|
(Shell.subshell ("xlsfonts "^dispopt^" -fn "^string_of_pattern pattern))
|
|
in
|
|
if result = [] then raise Not_found
|
|
else result
|
|
|
|
let available_pixel_size_aux dispname pattern =
|
|
(* return available pixel size without font resizing *)
|
|
(* to obtain good result, *)
|
|
(* the pattern should contain as many information as possible *)
|
|
let pattern = copy pattern in
|
|
pattern.pixelSize <- None;
|
|
let xlfds = list_fonts dispname pattern in
|
|
let pxszs = Hashtbl.create 107 in
|
|
List.iter (fun xlfd ->
|
|
Hashtbl.add pxszs xlfd.pixelSize xlfd) xlfds;
|
|
pxszs
|
|
|
|
let extract_size_font_hash tbl =
|
|
let keys = ref [] in
|
|
Hashtbl.iter (fun k _ ->
|
|
if not (List.mem k !keys) then keys := k :: !keys) tbl;
|
|
Sort.list (fun (k1,_) (k2,_) -> k1 < k2)
|
|
(List.map (fun k -> k, Hashtbl.find_all tbl k) !keys)
|
|
|
|
let available_pixel_size dispname pattern =
|
|
let pxszs = available_pixel_size_aux dispname pattern in
|
|
extract_size_font_hash pxszs
|
|
|
|
let nearest_pixel_size dispname vector_ok pattern =
|
|
(* find the font with the nearest pixel size *)
|
|
log ("\n*** "^string_of_pattern pattern);
|
|
let pxlsz =
|
|
match pattern.pixelSize with
|
|
None -> raise (Failure "invalid pixelSize pattern")
|
|
| Some x -> x
|
|
in
|
|
let tbl = available_pixel_size_aux dispname pattern in
|
|
let newtbl = Hashtbl.create 107 in
|
|
Hashtbl.iter (fun s xlfd ->
|
|
if vector_ok then
|
|
if s = 0 then begin
|
|
if is_vector_font xlfd then begin
|
|
log (Printf.sprintf "%s is vector" (string_of_valid_xlfd xlfd));
|
|
xlfd.pixelSize <- pxlsz;
|
|
Hashtbl.add newtbl pxlsz xlfd
|
|
end
|
|
end else Hashtbl.add newtbl s xlfd
|
|
else if not (is_vector_font xlfd) && s <> 0 then
|
|
Hashtbl.add newtbl s xlfd) tbl;
|
|
|
|
let size_font_table = extract_size_font_hash newtbl in
|
|
|
|
let diff = ref 10000 in
|
|
let min = ref None in
|
|
List.iter (fun (s,xlfds) ->
|
|
let d = abs(s - pxlsz) in
|
|
if d < !diff then begin
|
|
min := Some (s,xlfds);
|
|
diff := d
|
|
end) size_font_table;
|
|
(* if it contains more than one font, just return the first *)
|
|
match !min with
|
|
| None -> raise Not_found
|
|
| Some(s, xlfds) ->
|
|
log (Printf.sprintf "Size %d is selected" s);
|
|
List.iter (fun xlfd -> log (string_of_valid_xlfd xlfd)) xlfds;
|
|
List.hd xlfds
|