Blame jpf/jpf_font.ml

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