123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275 |
- (*
- * Copyright (C)2005-2014 Haxe Foundation
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *)
- open Extlib_leftovers
- open TTFData
- type glyf_transformation_matrix = {
- mutable a : float;
- mutable b : float;
- mutable c : float;
- mutable d : float;
- mutable tx : float;
- mutable ty : float;
- }
- type glyf_path = {
- gp_type : int;
- gp_x : float;
- gp_y : float;
- gp_cx : float;
- gp_cy : float;
- }
- type simple_point = {
- x : float;
- y : float;
- }
- let mk_path t x y cx cy = {
- gp_type = t;
- gp_x = x;
- gp_y = y;
- gp_cx = cx;
- gp_cy = cy;
- }
- let identity () = {
- a = 1.0;
- b = 0.0;
- c = 0.0;
- d = 1.0;
- tx = 0.0;
- ty = 0.0;
- }
- let multiply m x y =
- x *. m.a +. y *. m.b +. m.tx,
- x *. m.c +. y *. m.d +. m.ty
- (* TODO: check if this can be done in the parser directly *)
- let matrix_from_composite gc =
- let a,b,c,d = match gc.gc_transformation with
- | NoScale -> 1.0,0.0,0.0,1.0
- | Scale f -> f,0.0,0.0,f
- | ScaleXY(fx,fy) -> fx,0.0,0.0,fy
- | ScaleMatrix (a,b,c,d) -> a,b,c,d
- in
- let arg1 = float_of_int gc.gc_arg1 in
- let arg2 = float_of_int gc.gc_arg2 in
- {
- a = a;
- b = b;
- c = c;
- d = d;
- (* TODO: point offsets *)
- tx = arg1 *. a +. arg2 *. b;
- ty = arg1 *. c +. arg2 *. d;
- }
- let relative_matrix m = {m with tx = 0.0; ty = 0.0}
- let make_coords relative mo g = match mo with
- | None ->
- Array.init (Array.length g.gs_x_coordinates) (fun i -> float_of_int g.gs_x_coordinates.(i),float_of_int g.gs_y_coordinates.(i))
- | Some m ->
- let m = if relative then relative_matrix m else m in
- Array.init (Array.length g.gs_x_coordinates) (fun i ->
- let x,y = float_of_int g.gs_x_coordinates.(i),float_of_int g.gs_y_coordinates.(i) in
- multiply m x y
- )
- let build_paths relative mo g =
- let len = Array.length g.gs_x_coordinates in
- let current_end = ref 0 in
- let end_pts = Array.init len (fun i ->
- if g.gs_end_pts_of_contours.(!current_end) = i then begin
- incr current_end;
- true
- end else
- false
- ) in
- let is_on i = g.gs_flags.(i) land 0x01 <> 0 in
- let is_end i = end_pts.(i) in
- let arr = DynArray.create () in
- let tx,ty = match mo with None -> 0.0,0.0 | Some m -> m.tx,m.ty in
- let last_added = ref {
- x = 0.0;
- y = 0.0;
- } in
- let add_rel t x y cx cy =
- let p = match t with
- | 0 ->
- mk_path t (x +. tx) (y +. ty) cx cy
- | 1 ->
- mk_path t (x -. !last_added.x) (y -. !last_added.y) cx cy
- | 2 ->
- mk_path t (x -. cx) (y -. cy) (cx -. !last_added.x) (cy -. !last_added.y)
- | _ ->
- assert false
- in
- last_added := { x = x; y = y; };
- DynArray.add arr p
- in
- let add_abs t x y cx cy = DynArray.add arr (mk_path t x y cx cy) in
- let add = if relative then add_rel else add_abs in
- let coords = make_coords relative mo g in
- let left = ref [] in
- let right = ref [] in
- let new_contour = ref true in
- let p = ref { x = 0.0; y = 0.0 } in
- for i = 0 to len - 1 do
- p := {
- x = !p.x +. fst coords.(i);
- y = !p.y +. snd coords.(i);
- };
- let p = !p in
- let is_on = is_on i in
- let is_end = is_end i in
- let rec flush pl = match pl with
- | c :: a :: [] -> add 2 a.x a.y c.x c.y
- | a :: [] -> add 1 a.x a.y 0.0 0.0
- | c1 :: c2 :: pl ->
- add 2 (c1.x +. (c2.x -. c1.x) /. 2.0) (c1.y +. (c2.y -. c1.y) /. 2.0) c1.x c1.y;
- flush (c2 :: pl)
- | _ ->
- Printf.printf "Fail, len: %i\n" (List.length pl);
- in
- if !new_contour then begin
- if is_on then begin
- new_contour := false;
- add 0 p.x p.y 0.0 0.0;
- end;
- left := p :: !left
- end else if is_on || is_end then begin
- right := p :: !right;
- if is_on then begin
- flush (List.rev !right);
- right := []
- end;
- if is_end then begin
- new_contour := true;
- flush ((List.rev !right) @ (List.rev !left));
- left := [];
- right := [];
- end
- end else
- right := p :: !right
- done;
- DynArray.to_list arr
- let rec build_glyph_paths ttf relative ?(transformation=None) glyf =
- match glyf with
- | TGlyfSimple (h,g) ->
- build_paths relative transformation g
- | TGlyfComposite (h,gl) ->
- List.concat (List.map (fun g ->
- let t = Some (matrix_from_composite g) in
- build_glyph_paths ttf relative ~transformation:t (ttf.ttf_glyfs.(g.gc_glyf_index))
- ) gl)
- | TGlyfNull ->
- []
- let map_char_code cc c4 =
- let index = ref 0 in
- let seg_count = c4.c4_seg_count_x2 / 2 in
- if cc >= 0xFFFF then 0 else begin
- for i = 0 to seg_count - 1 do
- if c4.c4_end_code.(i) >= cc && c4.c4_start_code.(i) <= cc then begin
- if c4.c4_id_range_offset.(i) > 0 then
- let v = c4.c4_id_range_offset.(i)/2 + cc - c4.c4_start_code.(i) - seg_count + i in
- index := c4.c4_glyph_index_array.(v)
- else
- index := (c4.c4_id_delta.(i) + cc) mod 65536
- end
- done;
- !index
- end
- let parse_range_str str =
- let last = ref (Char.code '\\') in
- let range = ref false in
- let lut = Hashtbl.create 0 in
- UTF8.iter (fun code ->
- let code = UCharExt.code code in
- if code = Char.code '-' && !last <> Char.code '\\' then
- range := true
- else if !range then begin
- range := false;
- for i = !last to code do
- Hashtbl.replace lut i true;
- done;
- end else begin
- Hashtbl.replace lut code true;
- last := code;
- end
- ) str;
- if !range then Hashtbl.replace lut (Char.code '-') true;
- lut
- let build_lut ttf range_str =
- let lut = Hashtbl.create 0 in
- Hashtbl.add lut 0 0;
- Hashtbl.add lut 1 1;
- Hashtbl.add lut 2 2;
- let add_character = if range_str = "" then
- fun k v -> Hashtbl.replace lut k v
- else begin
- let range = parse_range_str range_str in
- fun k v -> if Hashtbl.mem range k then Hashtbl.replace lut k v
- end
- in
- let make_cmap4_map c4 =
- let seg_count = c4.c4_seg_count_x2 / 2 in
- for i = 0 to seg_count - 1 do
- for j = c4.c4_start_code.(i) to c4.c4_end_code.(i) do
- let index = map_char_code j c4 in
- add_character j index;
- done;
- done
- in
- (* let make_cmap12_map c12 =
- List.iter (fun group ->
- let rec loop cc gi =
- add_character cc gi;
- if cc < (Int32.to_int group.c12g_end_char_code) then loop (cc + 1) (gi + 1)
- in
- loop (Int32.to_int group.c12g_start_char_code) (Int32.to_int group.c12g_start_glyph_code)
- ) c12.c12_groups
- in *)
- List.iter (fun st -> match st.cs_def with
- | Cmap0 c0 ->
- Array.iteri (fun i c -> add_character i (int_of_char c)) c0.c0_glyph_index_array;
- | Cmap4 c4 ->
- make_cmap4_map c4;
- | Cmap12 c12 ->
- (*
- TODO: this causes an exception with some fonts:
- Fatal error: exception IO.Overflow("write_ui16")
- *)
- (* make_cmap12_map ctx lut c12; *)
- ()
- | _ ->
- (* TODO *)
- ()
- ) ttf.ttf_cmap.cmap_subtables;
- lut
|