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 TTFData
  23. type glyf_transformation_matrix = {
  24. mutable a : float;
  25. mutable b : float;
  26. mutable c : float;
  27. mutable d : float;
  28. mutable tx : float;
  29. mutable ty : float;
  30. }
  31. type glyf_path = {
  32. gp_type : int;
  33. gp_x : float;
  34. gp_y : float;
  35. gp_cx : float;
  36. gp_cy : float;
  37. }
  38. type simple_point = {
  39. x : float;
  40. y : float;
  41. }
  42. let mk_path t x y cx cy = {
  43. gp_type = t;
  44. gp_x = x;
  45. gp_y = y;
  46. gp_cx = cx;
  47. gp_cy = cy;
  48. }
  49. let identity () = {
  50. a = 1.0;
  51. b = 0.0;
  52. c = 0.0;
  53. d = 1.0;
  54. tx = 0.0;
  55. ty = 0.0;
  56. }
  57. let multiply m x y =
  58. x *. m.a +. y *. m.b +. m.tx,
  59. x *. m.c +. y *. m.d +. m.ty
  60. (* TODO: check if this can be done in the parser directly *)
  61. let matrix_from_composite gc =
  62. let a,b,c,d = match gc.gc_transformation with
  63. | NoScale -> 1.0,0.0,0.0,1.0
  64. | Scale f -> f,0.0,0.0,f
  65. | ScaleXY(fx,fy) -> fx,0.0,0.0,fy
  66. | ScaleMatrix (a,b,c,d) -> a,b,c,d
  67. in
  68. let arg1 = float_of_int gc.gc_arg1 in
  69. let arg2 = float_of_int gc.gc_arg2 in
  70. {
  71. a = a;
  72. b = b;
  73. c = c;
  74. d = d;
  75. (* TODO: point offsets *)
  76. tx = arg1 *. a +. arg2 *. b;
  77. ty = arg1 *. c +. arg2 *. d;
  78. }
  79. let relative_matrix m = {m with tx = 0.0; ty = 0.0}
  80. let make_coords relative mo g = match mo with
  81. | None ->
  82. 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))
  83. | Some m ->
  84. let m = if relative then relative_matrix m else m in
  85. Array.init (Array.length g.gs_x_coordinates) (fun i ->
  86. let x,y = float_of_int g.gs_x_coordinates.(i),float_of_int g.gs_y_coordinates.(i) in
  87. multiply m x y
  88. )
  89. let build_paths relative mo g =
  90. let len = Array.length g.gs_x_coordinates in
  91. let current_end = ref 0 in
  92. let end_pts = Array.init len (fun i ->
  93. if g.gs_end_pts_of_contours.(!current_end) = i then begin
  94. incr current_end;
  95. true
  96. end else
  97. false
  98. ) in
  99. let is_on i = g.gs_flags.(i) land 0x01 <> 0 in
  100. let is_end i = end_pts.(i) in
  101. let arr = DynArray.create () in
  102. let tx,ty = match mo with None -> 0.0,0.0 | Some m -> m.tx,m.ty in
  103. let last_added = ref {
  104. x = 0.0;
  105. y = 0.0;
  106. } in
  107. let add_rel t x y cx cy =
  108. let p = match t with
  109. | 0 ->
  110. mk_path t (x +. tx) (y +. ty) cx cy
  111. | 1 ->
  112. mk_path t (x -. !last_added.x) (y -. !last_added.y) cx cy
  113. | 2 ->
  114. mk_path t (x -. cx) (y -. cy) (cx -. !last_added.x) (cy -. !last_added.y)
  115. | _ ->
  116. assert false
  117. in
  118. last_added := { x = x; y = y; };
  119. DynArray.add arr p
  120. in
  121. let add_abs t x y cx cy = DynArray.add arr (mk_path t x y cx cy) in
  122. let add = if relative then add_rel else add_abs in
  123. let coords = make_coords relative mo g in
  124. let left = ref [] in
  125. let right = ref [] in
  126. let new_contour = ref true in
  127. let p = ref { x = 0.0; y = 0.0 } in
  128. for i = 0 to len - 1 do
  129. p := {
  130. x = !p.x +. fst coords.(i);
  131. y = !p.y +. snd coords.(i);
  132. };
  133. let p = !p in
  134. let is_on = is_on i in
  135. let is_end = is_end i in
  136. let rec flush pl = match pl with
  137. | c :: a :: [] -> add 2 a.x a.y c.x c.y
  138. | a :: [] -> add 1 a.x a.y 0.0 0.0
  139. | c1 :: c2 :: pl ->
  140. add 2 (c1.x +. (c2.x -. c1.x) /. 2.0) (c1.y +. (c2.y -. c1.y) /. 2.0) c1.x c1.y;
  141. flush (c2 :: pl)
  142. | _ ->
  143. Printf.printf "Fail, len: %i\n" (List.length pl);
  144. in
  145. if !new_contour then begin
  146. if is_on then begin
  147. new_contour := false;
  148. add 0 p.x p.y 0.0 0.0;
  149. end;
  150. left := p :: !left
  151. end else if is_on || is_end then begin
  152. right := p :: !right;
  153. if is_on then begin
  154. flush (List.rev !right);
  155. right := []
  156. end;
  157. if is_end then begin
  158. new_contour := true;
  159. flush ((List.rev !right) @ (List.rev !left));
  160. left := [];
  161. right := [];
  162. end
  163. end else
  164. right := p :: !right
  165. done;
  166. DynArray.to_list arr
  167. let rec build_glyph_paths ttf relative ?(transformation=None) glyf =
  168. match glyf with
  169. | TGlyfSimple (h,g) ->
  170. build_paths relative transformation g
  171. | TGlyfComposite (h,gl) ->
  172. List.concat (List.map (fun g ->
  173. let t = Some (matrix_from_composite g) in
  174. build_glyph_paths ttf relative ~transformation:t (ttf.ttf_glyfs.(g.gc_glyf_index))
  175. ) gl)
  176. | TGlyfNull ->
  177. []
  178. let map_char_code cc c4 =
  179. let index = ref 0 in
  180. let seg_count = c4.c4_seg_count_x2 / 2 in
  181. if cc >= 0xFFFF then 0 else begin
  182. for i = 0 to seg_count - 1 do
  183. if c4.c4_end_code.(i) >= cc && c4.c4_start_code.(i) <= cc then begin
  184. if c4.c4_id_range_offset.(i) > 0 then
  185. let v = c4.c4_id_range_offset.(i)/2 + cc - c4.c4_start_code.(i) - seg_count + i in
  186. index := c4.c4_glyph_index_array.(v)
  187. else
  188. index := (c4.c4_id_delta.(i) + cc) mod 65536
  189. end
  190. done;
  191. !index
  192. end
  193. let parse_range_str str =
  194. let last = ref (Char.code '\\') in
  195. let range = ref false in
  196. let lut = Hashtbl.create 0 in
  197. UTF8.iter (fun code ->
  198. let code = UCharExt.code code in
  199. if code = Char.code '-' && !last <> Char.code '\\' then
  200. range := true
  201. else if !range then begin
  202. range := false;
  203. for i = !last to code do
  204. Hashtbl.replace lut i true;
  205. done;
  206. end else begin
  207. Hashtbl.replace lut code true;
  208. last := code;
  209. end
  210. ) str;
  211. if !range then Hashtbl.replace lut (Char.code '-') true;
  212. lut
  213. let build_lut ttf range_str =
  214. let lut = Hashtbl.create 0 in
  215. Hashtbl.add lut 0 0;
  216. Hashtbl.add lut 1 1;
  217. Hashtbl.add lut 2 2;
  218. let add_character = if range_str = "" then
  219. fun k v -> Hashtbl.replace lut k v
  220. else begin
  221. let range = parse_range_str range_str in
  222. fun k v -> if Hashtbl.mem range k then Hashtbl.replace lut k v
  223. end
  224. in
  225. let make_cmap4_map c4 =
  226. let seg_count = c4.c4_seg_count_x2 / 2 in
  227. for i = 0 to seg_count - 1 do
  228. for j = c4.c4_start_code.(i) to c4.c4_end_code.(i) do
  229. let index = map_char_code j c4 in
  230. add_character j index;
  231. done;
  232. done
  233. in
  234. (* let make_cmap12_map c12 =
  235. List.iter (fun group ->
  236. let rec loop cc gi =
  237. add_character cc gi;
  238. if cc < (Int32.to_int group.c12g_end_char_code) then loop (cc + 1) (gi + 1)
  239. in
  240. loop (Int32.to_int group.c12g_start_char_code) (Int32.to_int group.c12g_start_glyph_code)
  241. ) c12.c12_groups
  242. in *)
  243. List.iter (fun st -> match st.cs_def with
  244. | Cmap0 c0 ->
  245. Array.iteri (fun i c -> add_character i (int_of_char c)) c0.c0_glyph_index_array;
  246. | Cmap4 c4 ->
  247. make_cmap4_map c4;
  248. | Cmap12 c12 ->
  249. (*
  250. TODO: this causes an exception with some fonts:
  251. Fatal error: exception IO.Overflow("write_ui16")
  252. *)
  253. (* make_cmap12_map ctx lut c12; *)
  254. ()
  255. | _ ->
  256. (* TODO *)
  257. ()
  258. ) ttf.ttf_cmap.cmap_subtables;
  259. lut