tTFTools.ml 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275
  1. (*
  2. * Copyright (C)2005-2014 Haxe Foundation
  3. *
  4. * Permission is hereby granted, free of charge, to any person obtaining a
  5. * copy of this software and associated documentation files (the "Software"),
  6. * to deal in the Software without restriction, including without limitation
  7. * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  8. * and/or sell copies of the Software, and to permit persons to whom the
  9. * Software is furnished to do so, subject to the following conditions:
  10. *
  11. * The above copyright notice and this permission notice shall be included in
  12. * all copies or substantial portions of the Software.
  13. *
  14. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  19. * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  20. * DEALINGS IN THE SOFTWARE.
  21. *)
  22. open Extlib_leftovers
  23. open TTFData
  24. type glyf_transformation_matrix = {
  25. mutable a : float;
  26. mutable b : float;
  27. mutable c : float;
  28. mutable d : float;
  29. mutable tx : float;
  30. mutable ty : float;
  31. }
  32. type glyf_path = {
  33. gp_type : int;
  34. gp_x : float;
  35. gp_y : float;
  36. gp_cx : float;
  37. gp_cy : float;
  38. }
  39. type simple_point = {
  40. x : float;
  41. y : float;
  42. }
  43. let mk_path t x y cx cy = {
  44. gp_type = t;
  45. gp_x = x;
  46. gp_y = y;
  47. gp_cx = cx;
  48. gp_cy = cy;
  49. }
  50. let identity () = {
  51. a = 1.0;
  52. b = 0.0;
  53. c = 0.0;
  54. d = 1.0;
  55. tx = 0.0;
  56. ty = 0.0;
  57. }
  58. let multiply m x y =
  59. x *. m.a +. y *. m.b +. m.tx,
  60. x *. m.c +. y *. m.d +. m.ty
  61. (* TODO: check if this can be done in the parser directly *)
  62. let matrix_from_composite gc =
  63. let a,b,c,d = match gc.gc_transformation with
  64. | NoScale -> 1.0,0.0,0.0,1.0
  65. | Scale f -> f,0.0,0.0,f
  66. | ScaleXY(fx,fy) -> fx,0.0,0.0,fy
  67. | ScaleMatrix (a,b,c,d) -> a,b,c,d
  68. in
  69. let arg1 = float_of_int gc.gc_arg1 in
  70. let arg2 = float_of_int gc.gc_arg2 in
  71. {
  72. a = a;
  73. b = b;
  74. c = c;
  75. d = d;
  76. (* TODO: point offsets *)
  77. tx = arg1 *. a +. arg2 *. b;
  78. ty = arg1 *. c +. arg2 *. d;
  79. }
  80. let relative_matrix m = {m with tx = 0.0; ty = 0.0}
  81. let make_coords relative mo g = match mo with
  82. | None ->
  83. 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))
  84. | Some m ->
  85. let m = if relative then relative_matrix m else m in
  86. Array.init (Array.length g.gs_x_coordinates) (fun i ->
  87. let x,y = float_of_int g.gs_x_coordinates.(i),float_of_int g.gs_y_coordinates.(i) in
  88. multiply m x y
  89. )
  90. let build_paths relative mo g =
  91. let len = Array.length g.gs_x_coordinates in
  92. let current_end = ref 0 in
  93. let end_pts = Array.init len (fun i ->
  94. if g.gs_end_pts_of_contours.(!current_end) = i then begin
  95. incr current_end;
  96. true
  97. end else
  98. false
  99. ) in
  100. let is_on i = g.gs_flags.(i) land 0x01 <> 0 in
  101. let is_end i = end_pts.(i) in
  102. let arr = DynArray.create () in
  103. let tx,ty = match mo with None -> 0.0,0.0 | Some m -> m.tx,m.ty in
  104. let last_added = ref {
  105. x = 0.0;
  106. y = 0.0;
  107. } in
  108. let add_rel t x y cx cy =
  109. let p = match t with
  110. | 0 ->
  111. mk_path t (x +. tx) (y +. ty) cx cy
  112. | 1 ->
  113. mk_path t (x -. !last_added.x) (y -. !last_added.y) cx cy
  114. | 2 ->
  115. mk_path t (x -. cx) (y -. cy) (cx -. !last_added.x) (cy -. !last_added.y)
  116. | _ ->
  117. assert false
  118. in
  119. last_added := { x = x; y = y; };
  120. DynArray.add arr p
  121. in
  122. let add_abs t x y cx cy = DynArray.add arr (mk_path t x y cx cy) in
  123. let add = if relative then add_rel else add_abs in
  124. let coords = make_coords relative mo g in
  125. let left = ref [] in
  126. let right = ref [] in
  127. let new_contour = ref true in
  128. let p = ref { x = 0.0; y = 0.0 } in
  129. for i = 0 to len - 1 do
  130. p := {
  131. x = !p.x +. fst coords.(i);
  132. y = !p.y +. snd coords.(i);
  133. };
  134. let p = !p in
  135. let is_on = is_on i in
  136. let is_end = is_end i in
  137. let rec flush pl = match pl with
  138. | c :: a :: [] -> add 2 a.x a.y c.x c.y
  139. | a :: [] -> add 1 a.x a.y 0.0 0.0
  140. | c1 :: c2 :: pl ->
  141. add 2 (c1.x +. (c2.x -. c1.x) /. 2.0) (c1.y +. (c2.y -. c1.y) /. 2.0) c1.x c1.y;
  142. flush (c2 :: pl)
  143. | _ ->
  144. Printf.printf "Fail, len: %i\n" (List.length pl);
  145. in
  146. if !new_contour then begin
  147. if is_on then begin
  148. new_contour := false;
  149. add 0 p.x p.y 0.0 0.0;
  150. end;
  151. left := p :: !left
  152. end else if is_on || is_end then begin
  153. right := p :: !right;
  154. if is_on then begin
  155. flush (List.rev !right);
  156. right := []
  157. end;
  158. if is_end then begin
  159. new_contour := true;
  160. flush ((List.rev !right) @ (List.rev !left));
  161. left := [];
  162. right := [];
  163. end
  164. end else
  165. right := p :: !right
  166. done;
  167. DynArray.to_list arr
  168. let rec build_glyph_paths ttf relative ?(transformation=None) glyf =
  169. match glyf with
  170. | TGlyfSimple (h,g) ->
  171. build_paths relative transformation g
  172. | TGlyfComposite (h,gl) ->
  173. List.concat (List.map (fun g ->
  174. let t = Some (matrix_from_composite g) in
  175. build_glyph_paths ttf relative ~transformation:t (ttf.ttf_glyfs.(g.gc_glyf_index))
  176. ) gl)
  177. | TGlyfNull ->
  178. []
  179. let map_char_code cc c4 =
  180. let index = ref 0 in
  181. let seg_count = c4.c4_seg_count_x2 / 2 in
  182. if cc >= 0xFFFF then 0 else begin
  183. for i = 0 to seg_count - 1 do
  184. if c4.c4_end_code.(i) >= cc && c4.c4_start_code.(i) <= cc then begin
  185. if c4.c4_id_range_offset.(i) > 0 then
  186. let v = c4.c4_id_range_offset.(i)/2 + cc - c4.c4_start_code.(i) - seg_count + i in
  187. index := c4.c4_glyph_index_array.(v)
  188. else
  189. index := (c4.c4_id_delta.(i) + cc) mod 65536
  190. end
  191. done;
  192. !index
  193. end
  194. let parse_range_str str =
  195. let last = ref (Char.code '\\') in
  196. let range = ref false in
  197. let lut = Hashtbl.create 0 in
  198. UTF8.iter (fun code ->
  199. let code = UCharExt.code code in
  200. if code = Char.code '-' && !last <> Char.code '\\' then
  201. range := true
  202. else if !range then begin
  203. range := false;
  204. for i = !last to code do
  205. Hashtbl.replace lut i true;
  206. done;
  207. end else begin
  208. Hashtbl.replace lut code true;
  209. last := code;
  210. end
  211. ) str;
  212. if !range then Hashtbl.replace lut (Char.code '-') true;
  213. lut
  214. let build_lut ttf range_str =
  215. let lut = Hashtbl.create 0 in
  216. Hashtbl.add lut 0 0;
  217. Hashtbl.add lut 1 1;
  218. Hashtbl.add lut 2 2;
  219. let add_character = if range_str = "" then
  220. fun k v -> Hashtbl.replace lut k v
  221. else begin
  222. let range = parse_range_str range_str in
  223. fun k v -> if Hashtbl.mem range k then Hashtbl.replace lut k v
  224. end
  225. in
  226. let make_cmap4_map c4 =
  227. let seg_count = c4.c4_seg_count_x2 / 2 in
  228. for i = 0 to seg_count - 1 do
  229. for j = c4.c4_start_code.(i) to c4.c4_end_code.(i) do
  230. let index = map_char_code j c4 in
  231. add_character j index;
  232. done;
  233. done
  234. in
  235. (* let make_cmap12_map c12 =
  236. List.iter (fun group ->
  237. let rec loop cc gi =
  238. add_character cc gi;
  239. if cc < (Int32.to_int group.c12g_end_char_code) then loop (cc + 1) (gi + 1)
  240. in
  241. loop (Int32.to_int group.c12g_start_char_code) (Int32.to_int group.c12g_start_glyph_code)
  242. ) c12.c12_groups
  243. in *)
  244. List.iter (fun st -> match st.cs_def with
  245. | Cmap0 c0 ->
  246. Array.iteri (fun i c -> add_character i (int_of_char c)) c0.c0_glyph_index_array;
  247. | Cmap4 c4 ->
  248. make_cmap4_map c4;
  249. | Cmap12 c12 ->
  250. (*
  251. TODO: this causes an exception with some fonts:
  252. Fatal error: exception IO.Overflow("write_ui16")
  253. *)
  254. (* make_cmap12_map ctx lut c12; *)
  255. ()
  256. | _ ->
  257. (* TODO *)
  258. ()
  259. ) ttf.ttf_cmap.cmap_subtables;
  260. lut