SHOW:
|
|
- or go back to the newest paste.
| 1 | open Swf | |
| 2 | ||
| 3 | (* DATA *) | |
| 4 | ||
| 5 | type header = {
| |
| 6 | hd_major_version : int; | |
| 7 | hd_minor_version : int; | |
| 8 | hd_num_tables : int; | |
| 9 | hd_search_range : int; | |
| 10 | hd_entry_selector : int; | |
| 11 | hd_range_shift : int; | |
| 12 | } | |
| 13 | ||
| 14 | type entry = {
| |
| 15 | entry_table_name : string; | |
| 16 | entry_checksum : int32; | |
| 17 | entry_offset : int32; | |
| 18 | entry_length: int32; | |
| 19 | } | |
| 20 | ||
| 21 | (* GLYF *) | |
| 22 | ||
| 23 | type glyf_header = {
| |
| 24 | gh_num_contours : int; | |
| 25 | gh_xmin : int; | |
| 26 | gh_ymin : int; | |
| 27 | gh_xmax : int; | |
| 28 | gh_ymax : int; | |
| 29 | } | |
| 30 | ||
| 31 | type glyf_simple = {
| |
| 32 | gs_end_pts_of_contours : int array; | |
| 33 | gs_instruction_length : int; | |
| 34 | gs_instructions : char array; | |
| 35 | gs_flags : int array; | |
| 36 | gs_x_coordinates : int array; | |
| 37 | gs_y_coordinates : int array; | |
| 38 | } | |
| 39 | ||
| 40 | type transformation_option = | |
| 41 | | Scale of float | |
| 42 | | ScaleXY of float * float | |
| 43 | | ScaleMatrix of float * float * float * float | |
| 44 | ||
| 45 | type glyf_component = {
| |
| 46 | gc_flags : int; | |
| 47 | gc_glyf_index : int; | |
| 48 | gc_arg1 : int; | |
| 49 | gc_arg2 : int; | |
| 50 | gc_transformations : transformation_option list; | |
| 51 | } | |
| 52 | ||
| 53 | type glyf_def = | |
| 54 | | TglyfSimple of glyf_simple | |
| 55 | | TglyfComposite of glyf_component list | |
| 56 | ||
| 57 | type glyf = {
| |
| 58 | glyf_header : glyf_header; | |
| 59 | glyf_def : glyf_def; | |
| 60 | } | |
| 61 | ||
| 62 | (* HMTX *) | |
| 63 | ||
| 64 | type hmtx = {
| |
| 65 | advance_width : int; | |
| 66 | left_side_bearing : int; | |
| 67 | } | |
| 68 | ||
| 69 | (* CMAP *) | |
| 70 | ||
| 71 | type cmap_subtable_header = {
| |
| 72 | csh_platform_id : int; | |
| 73 | csh_platform_specific_id : int; | |
| 74 | csh_offset : int32; | |
| 75 | } | |
| 76 | ||
| 77 | type cmap_format_0 = {
| |
| 78 | c0_format : int; | |
| 79 | c0_length : int; | |
| 80 | c0_language : int; | |
| 81 | c0_glyph_index_array : char array; | |
| 82 | } | |
| 83 | ||
| 84 | type cmap_format_4 = {
| |
| 85 | c4_format : int; | |
| 86 | c4_length : int; | |
| 87 | c4_language : int; | |
| 88 | c4_seg_count_x2 : int; | |
| 89 | c4_search_range : int; | |
| 90 | c4_entry_selector : int; | |
| 91 | c4_range_shift : int; | |
| 92 | c4_end_code : int array; | |
| 93 | c4_reserved_pad : int; | |
| 94 | c4_start_code : int array; | |
| 95 | c4_id_delta : int array; | |
| 96 | c4_id_range_offset : int array; | |
| 97 | c4_glyph_index_array : int array; | |
| 98 | } | |
| 99 | ||
| 100 | type cmap_format_6 = {
| |
| 101 | c6_format : int; | |
| 102 | c6_length : int; | |
| 103 | c6_language : int; | |
| 104 | c6_first_code : int; | |
| 105 | c6_entry_count : int; | |
| 106 | c6_glyph_index_array : int array; | |
| 107 | } | |
| 108 | ||
| 109 | type cmap_subtable_def = | |
| 110 | | Cmap0 of cmap_format_0 | |
| 111 | | Cmap4 of cmap_format_4 | |
| 112 | | Cmap6 of cmap_format_6 | |
| 113 | | CmapUnk of string | |
| 114 | ||
| 115 | type cmap_subtable = {
| |
| 116 | cs_header : cmap_subtable_header; | |
| 117 | cs_def : cmap_subtable_def; | |
| 118 | } | |
| 119 | ||
| 120 | type cmap = {
| |
| 121 | cmap_version : int; | |
| 122 | cmap_num_subtables : int; | |
| 123 | cmap_subtables : cmap_subtable list; | |
| 124 | } | |
| 125 | ||
| 126 | (* KERN *) | |
| 127 | ||
| 128 | type kern_subtable_header = {
| |
| 129 | ksh_length : int32; | |
| 130 | ksh_coverage : int; | |
| 131 | ksh_tuple_index : int; | |
| 132 | } | |
| 133 | ||
| 134 | type kern_pair = {
| |
| 135 | left : int; | |
| 136 | right : int; | |
| 137 | value : int; | |
| 138 | } | |
| 139 | ||
| 140 | type kern_format_0 = {
| |
| 141 | k0_num_pairs : int; | |
| 142 | k0_search_range : int; | |
| 143 | k0_entry_selector : int; | |
| 144 | k0_range_shift : int; | |
| 145 | k0_pairs : kern_pair list; | |
| 146 | } | |
| 147 | ||
| 148 | type kern_format_2 = {
| |
| 149 | k2_row_width : int; | |
| 150 | k2_left_offset_table : int; | |
| 151 | k2_right_offset_table : int; | |
| 152 | k2_array : int; | |
| 153 | k2_first_glyph : int; | |
| 154 | k2_num_glyphs : int; | |
| 155 | k2_offsets : int list; | |
| 156 | } | |
| 157 | ||
| 158 | type kern_subtable_def = | |
| 159 | | Kern0 of kern_format_0 | |
| 160 | | Kern2 of kern_format_2 | |
| 161 | ||
| 162 | type kern_subtable = {
| |
| 163 | ks_header : kern_subtable_header; | |
| 164 | ks_def : kern_subtable_def; | |
| 165 | } | |
| 166 | ||
| 167 | type kern = {
| |
| 168 | kern_version : int32; | |
| 169 | kern_num_tables : int32; | |
| 170 | kern_subtables : kern_subtable list; | |
| 171 | } | |
| 172 | ||
| 173 | (* NAME *) | |
| 174 | ||
| 175 | type name_record = {
| |
| 176 | nr_platform_id : int; | |
| 177 | nr_platform_specific_id : int; | |
| 178 | nr_language_id : int; | |
| 179 | nr_name_id : int; | |
| 180 | nr_length : int; | |
| 181 | nr_offset : int; | |
| 182 | mutable nr_value : string; | |
| 183 | } | |
| 184 | ||
| 185 | type name = {
| |
| 186 | name_format : int; | |
| 187 | name_num_records : int; | |
| 188 | name_offset : int; | |
| 189 | name_records : name_record array; | |
| 190 | } | |
| 191 | ||
| 192 | (* HEAD *) | |
| 193 | ||
| 194 | type head = {
| |
| 195 | hd_version : int32; | |
| 196 | hd_font_revision : int32; | |
| 197 | hd_checksum_adjustment : int32; | |
| 198 | hd_magic_number : int32; | |
| 199 | hd_flags : int; | |
| 200 | hd_units_per_em : int; | |
| 201 | hd_created : float; | |
| 202 | hd_modified : float; | |
| 203 | hd_xmin : int; | |
| 204 | hd_ymin : int; | |
| 205 | hd_xmax : int; | |
| 206 | hd_ymax : int; | |
| 207 | hd_mac_style : int; | |
| 208 | hd_lowest_rec_ppem : int; | |
| 209 | hd_font_direction_hint : int; | |
| 210 | hd_index_to_loc_format : int; | |
| 211 | hd_glyph_data_format : int; | |
| 212 | } | |
| 213 | ||
| 214 | (* HHEA *) | |
| 215 | ||
| 216 | type hhea = {
| |
| 217 | hhea_version : int32; | |
| 218 | hhea_ascent : int; | |
| 219 | hhea_descent : int; | |
| 220 | hhea_line_gap : int; | |
| 221 | hhea_advance_width_max : int; | |
| 222 | hhea_min_left_side_bearing : int; | |
| 223 | hhea_min_right_side_bearing : int; | |
| 224 | hhea_x_max_extent : int; | |
| 225 | hhea_caret_slope_rise : int; | |
| 226 | hhea_caret_slope_run : int; | |
| 227 | hhea_caret_offset : int; | |
| 228 | hhea_reserved : string; | |
| 229 | hhea_metric_data_format : int; | |
| 230 | hhea_number_of_hmetrics :int; | |
| 231 | } | |
| 232 | ||
| 233 | (* LOCA *) | |
| 234 | ||
| 235 | type loca = int32 array | |
| 236 | ||
| 237 | (* MAXP *) | |
| 238 | ||
| 239 | type maxp = {
| |
| 240 | maxp_version_number : int32; | |
| 241 | maxp_num_glyphs : int; | |
| 242 | maxp_max_points : int; | |
| 243 | maxp_max_contours : int; | |
| 244 | maxp_max_component_points : int; | |
| 245 | maxp_max_component_contours : int; | |
| 246 | maxp_max_zones : int; | |
| 247 | maxp_max_twilight_points : int; | |
| 248 | maxp_max_storage : int; | |
| 249 | maxp_max_function_defs : int; | |
| 250 | maxp_max_instruction_defs :int; | |
| 251 | maxp_max_stack_elements : int; | |
| 252 | maxp_max_size_of_instructions :int; | |
| 253 | maxp_max_component_elements :int; | |
| 254 | maxp_max_component_depth :int; | |
| 255 | } | |
| 256 | ||
| 257 | (* OS2 *) | |
| 258 | ||
| 259 | type os2 = {
| |
| 260 | os2_version : int; | |
| 261 | os2_x_avg_char_width : int; | |
| 262 | os2_us_weight_class : int; | |
| 263 | os2_us_width_class : int; | |
| 264 | os2_fs_type : int; | |
| 265 | os2_y_subscript_x_size : int; | |
| 266 | os2_y_subscript_y_size : int; | |
| 267 | os2_y_subscript_x_offset : int; | |
| 268 | os2_y_subscript_y_offset : int; | |
| 269 | os2_y_superscript_x_size : int; | |
| 270 | os2_y_superscript_y_size : int; | |
| 271 | os2_y_superscript_x_offset : int; | |
| 272 | os2_y_superscript_y_offset : int; | |
| 273 | os2_y_strikeout_size : int; | |
| 274 | os2_y_strikeout_position : int; | |
| 275 | os2_s_family_class : int; | |
| 276 | os2_b_family_type : int; | |
| 277 | os2_b_serif_style : int; | |
| 278 | os2_b_weight : int; | |
| 279 | os2_b_proportion : int; | |
| 280 | os2_b_contrast : int; | |
| 281 | os2_b_stroke_variation : int; | |
| 282 | os2_b_arm_style : int; | |
| 283 | os2_b_letterform : int; | |
| 284 | os2_b_midline : int; | |
| 285 | os2_b_x_height : int; | |
| 286 | os2_ul_unicode_range_1 : int32; | |
| 287 | os2_ul_unicode_range_2 : int32; | |
| 288 | os2_ul_unicode_range_3 : int32; | |
| 289 | os2_ul_unicode_range_4 : int32; | |
| 290 | os2_ach_vendor_id : int32; | |
| 291 | os2_fs_selection : int; | |
| 292 | os2_us_first_char_index : int; | |
| 293 | os2_us_last_char_index : int; | |
| 294 | os2_s_typo_ascender : int; | |
| 295 | os2_s_typo_descender : int; | |
| 296 | os2_us_win_ascent : int; | |
| 297 | os2_us_win_descent : int; | |
| 298 | } | |
| 299 | ||
| 300 | type table = | |
| 301 | | TGlyf of glyf array | |
| 302 | | THmtx of hmtx list | |
| 303 | | TCmap of cmap | |
| 304 | | TKern of kern | |
| 305 | | TName of name | |
| 306 | | THead of head | |
| 307 | | THhea of hhea | |
| 308 | | TLoca of loca | |
| 309 | | TMaxp of maxp | |
| 310 | | TOS2 of os2 | |
| 311 | | TUnk of string | |
| 312 | ||
| 313 | type ttf = {
| |
| 314 | ttf_header : header; | |
| 315 | ttf_name : string; | |
| 316 | ttf_directory: (string,entry) Hashtbl.t; | |
| 317 | ttf_tables : (string * table) list; | |
| 318 | } | |
| 319 | ||
| 320 | type ctx = {
| |
| 321 | file : in_channel; | |
| 322 | ch : IO.input; | |
| 323 | mutable entry : entry; | |
| 324 | } | |
| 325 | ||
| 326 | let rd16 = IO.BigEndian.read_i16 | |
| 327 | let rdu16 = IO.BigEndian.read_ui16 | |
| 328 | let rd32 = IO.BigEndian.read_i32 | |
| 329 | let rd32r = IO.BigEndian.read_real_i32 | |
| 330 | let rdd = IO.BigEndian.read_double | |
| 331 | let rbti ch = int_of_char (IO.read ch) | |
| 332 | let ti32 = Int32.of_int | |
| 333 | let ti = Int32.to_int | |
| 334 | ||
| 335 | (* PARSING *) | |
| 336 | ||
| 337 | let parse_header ctx = | |
| 338 | let ch = ctx.ch in | |
| 339 | let major_version = rdu16 ch in | |
| 340 | let minor_version = rdu16 ch in | |
| 341 | let num_tables = rdu16 ch in | |
| 342 | let search_range = rdu16 ch in | |
| 343 | let entry_selector = rdu16 ch in | |
| 344 | let range_shift = rdu16 ch in | |
| 345 | {
| |
| 346 | hd_major_version = major_version; | |
| 347 | hd_minor_version = minor_version; | |
| 348 | hd_num_tables = num_tables; | |
| 349 | hd_search_range = search_range; | |
| 350 | hd_entry_selector = entry_selector; | |
| 351 | hd_range_shift = range_shift; | |
| 352 | } | |
| 353 | ||
| 354 | let parse_directory ctx header = | |
| 355 | let ch = ctx.ch in | |
| 356 | let directory = Hashtbl.create 0 in | |
| 357 | for i = 0 to header.hd_num_tables - 1 do | |
| 358 | let name = IO.nread ch 4 in | |
| 359 | let cs = rd32r ch in | |
| 360 | let off = rd32r ch in | |
| 361 | let length = rd32r ch in | |
| 362 | Hashtbl.add directory name {
| |
| 363 | entry_table_name = name; | |
| 364 | entry_checksum = cs; | |
| 365 | entry_offset = off; | |
| 366 | entry_length = length; | |
| 367 | } | |
| 368 | done; | |
| 369 | directory | |
| 370 | ||
| 371 | let parse_head_table ctx = | |
| 372 | let ch = ctx.ch in | |
| 373 | let version = rd32r ch in | |
| 374 | let font_revision = rd32r ch in | |
| 375 | let checksum_adjustment = rd32r ch in | |
| 376 | let magic_number = rd32r ch in | |
| 377 | let flags = rdu16 ch in | |
| 378 | let units_per_em = rdu16 ch in | |
| 379 | let created = rdd ch in | |
| 380 | let modified = rdd ch in | |
| 381 | let xmin = rd16 ch in | |
| 382 | let ymin = rd16 ch in | |
| 383 | let xmax = rd16 ch in | |
| 384 | let ymax = rd16 ch in | |
| 385 | let mac_style = rdu16 ch in | |
| 386 | let lowest_rec_ppem = rdu16 ch in | |
| 387 | let font_direction_hint = rd16 ch in | |
| 388 | let index_to_loc_format = rd16 ch in | |
| 389 | let glyph_data_format = rd16 ch in | |
| 390 | {
| |
| 391 | hd_version = version; | |
| 392 | hd_font_revision = font_revision; | |
| 393 | hd_checksum_adjustment = checksum_adjustment; | |
| 394 | hd_magic_number = magic_number; | |
| 395 | hd_flags = flags; | |
| 396 | hd_units_per_em = units_per_em; | |
| 397 | hd_created = created; | |
| 398 | hd_modified = modified; | |
| 399 | hd_xmin = xmin; | |
| 400 | hd_ymin = ymin; | |
| 401 | hd_xmax = xmax; | |
| 402 | hd_ymax = ymax; | |
| 403 | hd_mac_style = mac_style; | |
| 404 | hd_lowest_rec_ppem = lowest_rec_ppem; | |
| 405 | hd_font_direction_hint = font_direction_hint; | |
| 406 | hd_index_to_loc_format = index_to_loc_format; | |
| 407 | hd_glyph_data_format = glyph_data_format; | |
| 408 | } | |
| 409 | ||
| 410 | let parse_hhea_table ctx = | |
| 411 | let ch = ctx.ch in | |
| 412 | let version = rd32r ch in | |
| 413 | let ascender = rd16 ch in | |
| 414 | let descender = rd16 ch in | |
| 415 | let line_gap = rd16 ch in | |
| 416 | let advance_width_max = rdu16 ch in | |
| 417 | let min_left_side_bearing = rd16 ch in | |
| 418 | let min_right_side_bearing = rd16 ch in | |
| 419 | let x_max_extent = rd16 ch in | |
| 420 | let caret_slope_rise = rd16 ch in | |
| 421 | let caret_slope_run = rd16 ch in | |
| 422 | let caret_offset = rd16 ch in | |
| 423 | let reserved = IO.nread ch 8 in | |
| 424 | let metric_data_format = rd16 ch in | |
| 425 | let number_of_hmetrics = rdu16 ch in | |
| 426 | {
| |
| 427 | hhea_version = version; | |
| 428 | hhea_ascent = ascender; | |
| 429 | hhea_descent = descender; | |
| 430 | hhea_line_gap = line_gap; | |
| 431 | hhea_advance_width_max = advance_width_max; | |
| 432 | hhea_min_left_side_bearing = min_left_side_bearing; | |
| 433 | hhea_min_right_side_bearing = min_right_side_bearing; | |
| 434 | hhea_x_max_extent = x_max_extent; | |
| 435 | hhea_caret_slope_rise = caret_slope_rise; | |
| 436 | hhea_caret_slope_run = caret_slope_run; | |
| 437 | hhea_caret_offset = caret_offset; | |
| 438 | hhea_reserved = reserved; | |
| 439 | hhea_metric_data_format = metric_data_format; | |
| 440 | hhea_number_of_hmetrics = number_of_hmetrics; | |
| 441 | } | |
| 442 | ||
| 443 | let parse_maxp_table ctx = | |
| 444 | let ch = ctx.ch in | |
| 445 | let version_number = rd32r ch in | |
| 446 | let num_glyphs = rdu16 ch in | |
| 447 | let max_points = rdu16 ch in | |
| 448 | let max_contours = rdu16 ch in | |
| 449 | let max_component_points = rdu16 ch in | |
| 450 | let max_component_contours = rdu16 ch in | |
| 451 | let max_zones = rdu16 ch in | |
| 452 | let max_twilight_points = rdu16 ch in | |
| 453 | let max_storage = rdu16 ch in | |
| 454 | let max_function_defs = rdu16 ch in | |
| 455 | let max_instruction_defs = rdu16 ch in | |
| 456 | let max_stack_elements = rdu16 ch in | |
| 457 | let max_size_of_instructions = rdu16 ch in | |
| 458 | let max_component_elements = rdu16 ch in | |
| 459 | let max_component_depth = rdu16 ch in | |
| 460 | {
| |
| 461 | maxp_version_number = version_number; | |
| 462 | maxp_num_glyphs = num_glyphs; | |
| 463 | maxp_max_points = max_points; | |
| 464 | maxp_max_contours = max_contours; | |
| 465 | maxp_max_component_points = max_component_points; | |
| 466 | maxp_max_component_contours = max_component_contours; | |
| 467 | maxp_max_zones = max_zones; | |
| 468 | maxp_max_twilight_points = max_twilight_points; | |
| 469 | maxp_max_storage = max_storage; | |
| 470 | maxp_max_function_defs = max_function_defs; | |
| 471 | maxp_max_instruction_defs = max_instruction_defs; | |
| 472 | maxp_max_stack_elements = max_stack_elements; | |
| 473 | maxp_max_size_of_instructions = max_size_of_instructions; | |
| 474 | maxp_max_component_elements = max_component_elements; | |
| 475 | maxp_max_component_depth = max_component_depth; | |
| 476 | } | |
| 477 | ||
| 478 | let parse_loca_table head maxp ctx = | |
| 479 | let ch = ctx.ch in | |
| 480 | if head.hd_index_to_loc_format = 0 then | |
| 481 | Array.init (maxp.maxp_num_glyphs + 1) (fun _ -> ti32 ((rdu16 ch) * 2)) | |
| 482 | else | |
| 483 | Array.init (maxp.maxp_num_glyphs + 1) (fun _ -> rd32r ch) | |
| 484 | ||
| 485 | let parse_hmtx_table maxp hhea ctx = | |
| 486 | let ch = ctx.ch in | |
| 487 | let last_advance_width = ref 0 in | |
| 488 | ExtList.List.init maxp.maxp_num_glyphs (fun i -> | |
| 489 | let advance_width = if i > hhea.hhea_number_of_hmetrics then | |
| 490 | !last_advance_width | |
| 491 | else | |
| 492 | rdu16 ch | |
| 493 | in | |
| 494 | last_advance_width := advance_width; | |
| 495 | let left_side_bearing = rd16 ch in | |
| 496 | {
| |
| 497 | advance_width = advance_width; | |
| 498 | left_side_bearing = left_side_bearing; | |
| 499 | } | |
| 500 | ) | |
| 501 | ||
| 502 | let parse_cmap_table ctx = | |
| 503 | let ch = ctx.ch in | |
| 504 | let version = rdu16 ch in | |
| 505 | let num_subtables = rdu16 ch in | |
| 506 | let dir = ExtList.List.init num_subtables (fun _ -> | |
| 507 | let platform_id = rdu16 ch in | |
| 508 | let platform_specific_id = rdu16 ch in | |
| 509 | let offset = rd32r ch in | |
| 510 | {
| |
| 511 | csh_platform_id = platform_id; | |
| 512 | csh_platform_specific_id = platform_specific_id; | |
| 513 | csh_offset = offset; | |
| 514 | } | |
| 515 | ) in | |
| 516 | let parse_sub entry = | |
| 517 | seek_in ctx.file ((ti ctx.entry.entry_offset) + (ti entry.csh_offset)); | |
| 518 | let format = rdu16 ch in | |
| 519 | let length = rdu16 ch in | |
| 520 | let language = rdu16 ch in | |
| 521 | let def = match format with | |
| 522 | | 0 -> | |
| 523 | let glyph_index = Array.init 256 (fun _ -> IO.read ch) in | |
| 524 | Cmap0 {
| |
| 525 | c0_format = 0; | |
| 526 | c0_length = length; | |
| 527 | c0_language = language; | |
| 528 | c0_glyph_index_array = glyph_index; | |
| 529 | } | |
| 530 | | 4 -> | |
| 531 | let seg_count_x2 = rdu16 ch in | |
| 532 | let seg_count = seg_count_x2 / 2 in | |
| 533 | let search_range = rdu16 ch in | |
| 534 | let entry_selector = rdu16 ch in | |
| 535 | let range_shift = rdu16 ch in | |
| 536 | let end_code = Array.init seg_count (fun _ -> rdu16 ch) in | |
| 537 | let reserved = rdu16 ch in | |
| 538 | assert (reserved = 0); | |
| 539 | let start_code = Array.init seg_count (fun _ -> rdu16 ch) in | |
| 540 | let id_delta = Array.init seg_count (fun _ -> rdu16 ch) in | |
| 541 | let id_range_offset = Array.init seg_count (fun _ -> rdu16 ch) in | |
| 542 | let count = length - (8 * seg_count + 16) / 2 in | |
| 543 | let glyph_index = Array.init count (fun _ -> rdu16 ch) in | |
| 544 | (* TODO: whatever Reader.hx does here *) | |
| 545 | Cmap4 {
| |
| 546 | c4_format = format; | |
| 547 | c4_length = length; | |
| 548 | c4_language = language; | |
| 549 | c4_seg_count_x2 = seg_count; | |
| 550 | c4_search_range = search_range; | |
| 551 | c4_entry_selector = entry_selector; | |
| 552 | c4_range_shift = range_shift; | |
| 553 | c4_end_code = end_code; | |
| 554 | c4_reserved_pad = reserved; | |
| 555 | c4_start_code = start_code; | |
| 556 | c4_id_delta = id_delta; | |
| 557 | c4_id_range_offset = id_range_offset; | |
| 558 | c4_glyph_index_array = glyph_index; | |
| 559 | } | |
| 560 | | 6 -> | |
| 561 | let first_code = rdu16 ch in | |
| 562 | let entry_count = rdu16 ch in | |
| 563 | let glyph_index = Array.init entry_count (fun _ -> rdu16 ch) in | |
| 564 | Cmap6 {
| |
| 565 | c6_format = format; | |
| 566 | c6_length = length; | |
| 567 | c6_language = language; | |
| 568 | c6_first_code = first_code; | |
| 569 | c6_entry_count = entry_count; | |
| 570 | c6_glyph_index_array = glyph_index; | |
| 571 | } | |
| 572 | | x -> | |
| 573 | failwith ("Not implemented format: " ^ (string_of_int x));
| |
| 574 | in | |
| 575 | {
| |
| 576 | cs_def = def; | |
| 577 | cs_header = entry; | |
| 578 | } | |
| 579 | ||
| 580 | in | |
| 581 | {
| |
| 582 | cmap_version = version; | |
| 583 | cmap_num_subtables = num_subtables; | |
| 584 | cmap_subtables = List.rev_map parse_sub dir; | |
| 585 | } | |
| 586 | ||
| 587 | let parse_glyf_table maxp loca cmap hmtx ctx = | |
| 588 | let ch = ctx.ch in | |
| 589 | let parse_glyf i = | |
| 590 | seek_in ctx.file ((ti ctx.entry.entry_offset) + (ti loca.(i))); | |
| 591 | let num_contours = rd16 ch in | |
| 592 | let xmin = rd16 ch in | |
| 593 | let ymin = rd16 ch in | |
| 594 | let xmax = rd16 ch in | |
| 595 | let ymax = rd16 ch in | |
| 596 | let header = {
| |
| 597 | gh_num_contours = num_contours; | |
| 598 | gh_xmin = xmin; | |
| 599 | gh_ymin = ymin; | |
| 600 | gh_xmax = xmax; | |
| 601 | gh_ymax = ymax; | |
| 602 | } in | |
| 603 | let def = if num_contours >= 0 then begin | |
| 604 | let num_points = ref 0 in | |
| 605 | let end_pts_of_contours = Array.init num_contours (fun i -> | |
| 606 | let v = rdu16 ch in | |
| 607 | if i = num_contours - 1 then num_points := v + 1; | |
| 608 | v | |
| 609 | ) in | |
| 610 | let instruction_length = rdu16 ch in | |
| 611 | let instructions = Array.init instruction_length (fun _ -> | |
| 612 | IO.read ch | |
| 613 | ) in | |
| 614 | let flags = DynArray.create () in | |
| 615 | let rec loop index = | |
| 616 | if index >= !num_points then () else begin | |
| 617 | let v = rbti ch in | |
| 618 | let incr = if (v land 8) == 0 then begin | |
| 619 | DynArray.add flags v; | |
| 620 | 1 | |
| 621 | end else begin | |
| 622 | let r = (int_of_char (IO.read ch)) in | |
| 623 | for i = 0 to r - 1 do DynArray.add flags v done; | |
| 624 | r | |
| 625 | end in | |
| 626 | loop (index + incr) | |
| 627 | end | |
| 628 | in | |
| 629 | loop 0; | |
| 630 | let x_coordinates = Array.init !num_points (fun i -> | |
| 631 | let flag = DynArray.get flags i in | |
| 632 | if flag land 0x10 <> 0 then begin | |
| 633 | if flag land 0x02 <> 0 then rbti ch | |
| 634 | else 0 | |
| 635 | end else begin | |
| 636 | if flag land 0x02 <> 0 then -rbti ch | |
| 637 | else rd16 ch | |
| 638 | end; | |
| 639 | ) in | |
| 640 | let y_coordinates = Array.init !num_points (fun i -> | |
| 641 | let flag = DynArray.get flags i in | |
| 642 | if flag land 0x20 <> 0 then begin | |
| 643 | if flag land 0x04 <> 0 then rbti ch | |
| 644 | else 0 | |
| 645 | end else begin | |
| 646 | if flag land 0x04 <> 0 then -rbti ch | |
| 647 | else rd16 ch | |
| 648 | end; | |
| 649 | ) in | |
| 650 | TglyfSimple {
| |
| 651 | gs_end_pts_of_contours = end_pts_of_contours; | |
| 652 | gs_instruction_length = instruction_length; | |
| 653 | gs_instructions = instructions; | |
| 654 | gs_flags = DynArray.to_array flags; | |
| 655 | gs_x_coordinates = x_coordinates; | |
| 656 | gs_y_coordinates = y_coordinates; | |
| 657 | } | |
| 658 | end else if num_contours = -1 then begin | |
| 659 | let acc = DynArray.create () in | |
| 660 | let rec loop () = | |
| 661 | let flags = rdu16 ch in | |
| 662 | let glyph_index = rdu16 ch in | |
| 663 | let arg1,arg2 = if flags land 1 <> 0 then begin | |
| 664 | let arg1 = rd16 ch in | |
| 665 | let arg2 = rd16 ch in | |
| 666 | arg1,arg2 | |
| 667 | end else begin | |
| 668 | let arg1 = rbti ch in | |
| 669 | let arg2 = rbti ch in | |
| 670 | arg1,arg2 | |
| 671 | end in | |
| 672 | let fmt214 i = (float_of_int i) /. (float_of_int 0x4000) in | |
| 673 | let tmodes = DynArray.create () in | |
| 674 | if flags land 8 <> 0 then DynArray.add tmodes (Scale (fmt214 (rd16 ch))); | |
| 675 | if flags land 64 <> 0 then begin | |
| 676 | let s1 = fmt214 (rd16 ch) in | |
| 677 | let s2 = fmt214 (rd16 ch) in | |
| 678 | DynArray.add tmodes (ScaleXY (s1,s2)) | |
| 679 | end; | |
| 680 | if flags land 128 <> 0 then begin | |
| 681 | let a = fmt214 (rd16 ch) in | |
| 682 | let b = fmt214 (rd16 ch) in | |
| 683 | let c = fmt214 (rd16 ch) in | |
| 684 | let d = fmt214 (rd16 ch) in | |
| 685 | DynArray.add tmodes (ScaleMatrix (a,b,c,d)) | |
| 686 | end; | |
| 687 | DynArray.add acc {
| |
| 688 | gc_flags = flags; | |
| 689 | gc_glyf_index = glyph_index; | |
| 690 | gc_arg1 = arg1; | |
| 691 | gc_arg2 = arg2; | |
| 692 | gc_transformations = DynArray.to_list tmodes; | |
| 693 | } | |
| 694 | in | |
| 695 | loop (); | |
| 696 | TglyfComposite (DynArray.to_list acc) | |
| 697 | end else | |
| 698 | failwith "Unknown Glyf" | |
| 699 | in | |
| 700 | {
| |
| 701 | glyf_header = header; | |
| 702 | glyf_def = def; | |
| 703 | } | |
| 704 | in | |
| 705 | Array.init maxp.maxp_num_glyphs (fun i -> parse_glyf i) | |
| 706 | ||
| 707 | let parse_kern_table ctx = | |
| 708 | let ch = ctx.ch in | |
| 709 | let version = ti32 (rd16 ch) in | |
| 710 | let num_tables = ti32 (rd16 ch) in | |
| 711 | let tables = ExtList.List.init (ti num_tables) (fun _ -> | |
| 712 | let length = ti32 (rdu16 ch) in | |
| 713 | let tuple_index = rdu16 ch in | |
| 714 | let coverage = rdu16 ch in | |
| 715 | let def = match coverage lsr 8 with | |
| 716 | | 0 -> | |
| 717 | let num_pairs = rdu16 ch in | |
| 718 | let search_range = rdu16 ch in | |
| 719 | let entry_selector = rdu16 ch in | |
| 720 | let range_shift = rdu16 ch in | |
| 721 | let kerning_pairs = ExtList.List.init num_pairs (fun _ -> | |
| 722 | let left = rdu16 ch in | |
| 723 | let right = rdu16 ch in | |
| 724 | let value = rd16 ch in | |
| 725 | {
| |
| 726 | left = left; | |
| 727 | right = right; | |
| 728 | value = value; | |
| 729 | } | |
| 730 | ) in | |
| 731 | Kern0 {
| |
| 732 | k0_num_pairs = num_pairs; | |
| 733 | k0_search_range = search_range; | |
| 734 | k0_entry_selector = entry_selector; | |
| 735 | k0_range_shift = range_shift; | |
| 736 | k0_pairs = kerning_pairs; | |
| 737 | } | |
| 738 | | 2 -> | |
| 739 | let row_width = rdu16 ch in | |
| 740 | let left_offset_table = rdu16 ch in | |
| 741 | let right_offset_table = rdu16 ch in | |
| 742 | let array_offset = rdu16 ch in | |
| 743 | let first_glyph = rdu16 ch in | |
| 744 | let num_glyphs = rdu16 ch in | |
| 745 | let offsets = ExtList.List.init num_glyphs (fun _ -> | |
| 746 | rdu16 ch | |
| 747 | ) in | |
| 748 | Kern2 {
| |
| 749 | k2_row_width = row_width; | |
| 750 | k2_left_offset_table = left_offset_table; | |
| 751 | k2_right_offset_table = right_offset_table; | |
| 752 | k2_array = array_offset; | |
| 753 | k2_first_glyph = first_glyph; | |
| 754 | k2_num_glyphs = num_glyphs; | |
| 755 | k2_offsets = offsets; | |
| 756 | } | |
| 757 | | i -> | |
| 758 | failwith ("Unknown kerning: " ^ (string_of_int i));
| |
| 759 | in | |
| 760 | {
| |
| 761 | ks_def = def; | |
| 762 | ks_header = {
| |
| 763 | ksh_length = length; | |
| 764 | ksh_coverage = coverage; | |
| 765 | ksh_tuple_index = tuple_index; | |
| 766 | } | |
| 767 | } | |
| 768 | ) in | |
| 769 | {
| |
| 770 | kern_version = version; | |
| 771 | kern_num_tables = num_tables; | |
| 772 | kern_subtables = tables; | |
| 773 | } | |
| 774 | ||
| 775 | let parse_name_table ctx = | |
| 776 | let ch = ctx.ch in | |
| 777 | let format = rdu16 ch in | |
| 778 | let num_records = rdu16 ch in | |
| 779 | let offset = rdu16 ch in | |
| 780 | let records = Array.init num_records (fun _ -> | |
| 781 | let platform_id = rdu16 ch in | |
| 782 | let platform_specific_id = rdu16 ch in | |
| 783 | let language_id = rdu16 ch in | |
| 784 | let name_id = rdu16 ch in | |
| 785 | let length = rdu16 ch in | |
| 786 | let offset = rdu16 ch in | |
| 787 | {
| |
| 788 | nr_platform_id = platform_id; | |
| 789 | nr_platform_specific_id = platform_specific_id; | |
| 790 | nr_language_id = language_id; | |
| 791 | nr_name_id = name_id; | |
| 792 | nr_length = length; | |
| 793 | nr_offset = offset; | |
| 794 | nr_value = ""; | |
| 795 | } | |
| 796 | ) in | |
| 797 | let ttf_name = ref "" in | |
| 798 | let records = Array.map (fun r -> | |
| 799 | seek_in ctx.file ((ti ctx.entry.entry_offset) + offset + r.nr_offset); | |
| 800 | r.nr_value <- IO.nread ch r.nr_length; | |
| 801 | if r.nr_name_id = 4 && r.nr_platform_id = 3 || r.nr_platform_id = 0 then ttf_name := r.nr_value; | |
| 802 | r | |
| 803 | ) records in | |
| 804 | {
| |
| 805 | name_format = format; | |
| 806 | name_num_records = num_records; | |
| 807 | name_offset = offset; | |
| 808 | name_records = records; | |
| 809 | },!ttf_name | |
| 810 | ||
| 811 | let parse_os2_table ctx = | |
| 812 | let ch = ctx.ch in | |
| 813 | let version = rdu16 ch in | |
| 814 | let x_avg_char_width = rd16 ch in | |
| 815 | let us_weight_class = rdu16 ch in | |
| 816 | let us_width_class = rdu16 ch in | |
| 817 | let fs_type = rd16 ch in | |
| 818 | let y_subscript_x_size = rd16 ch in | |
| 819 | let y_subscript_y_size = rd16 ch in | |
| 820 | let y_subscript_x_offset = rd16 ch in | |
| 821 | let y_subscript_y_offset = rd16 ch in | |
| 822 | let y_superscript_x_size = rd16 ch in | |
| 823 | let y_superscript_y_size = rd16 ch in | |
| 824 | let y_superscript_x_offset = rd16 ch in | |
| 825 | let y_superscript_y_offset = rd16 ch in | |
| 826 | let y_strikeout_size = rd16 ch in | |
| 827 | let y_strikeout_position = rd16 ch in | |
| 828 | let s_family_class = rd16 ch in | |
| 829 | let b_family_type = rbti ch in | |
| 830 | let b_serif_style = rbti ch in | |
| 831 | let b_weight = rbti ch in | |
| 832 | let b_proportion = rbti ch in | |
| 833 | let b_contrast = rbti ch in | |
| 834 | let b_stroke_variation = rbti ch in | |
| 835 | let b_arm_style = rbti ch in | |
| 836 | let b_letterform = rbti ch in | |
| 837 | let b_midline = rbti ch in | |
| 838 | let b_x_height = rbti ch in | |
| 839 | let ul_unicode_range_1 = rd32r ch in | |
| 840 | let ul_unicode_range_2 = rd32r ch in | |
| 841 | let ul_unicode_range_3 = rd32r ch in | |
| 842 | let ul_unicode_range_4 = rd32r ch in | |
| 843 | let ach_vendor_id = rd32r ch in | |
| 844 | let fs_selection = rd16 ch in | |
| 845 | let us_first_char_index = rdu16 ch in | |
| 846 | let us_last_char_index = rdu16 ch in | |
| 847 | let s_typo_ascender = rd16 ch in | |
| 848 | let s_typo_descender = rd16 ch in | |
| 849 | let us_win_ascent = rdu16 ch in | |
| 850 | let us_win_descent = rdu16 ch in | |
| 851 | {
| |
| 852 | os2_version = version; | |
| 853 | os2_x_avg_char_width = x_avg_char_width; | |
| 854 | os2_us_weight_class = us_weight_class; | |
| 855 | os2_us_width_class = us_width_class; | |
| 856 | os2_fs_type = fs_type; | |
| 857 | os2_y_subscript_x_size = y_subscript_x_size; | |
| 858 | os2_y_subscript_y_size = y_subscript_y_size; | |
| 859 | os2_y_subscript_x_offset = y_subscript_x_offset; | |
| 860 | os2_y_subscript_y_offset = y_subscript_y_offset; | |
| 861 | os2_y_superscript_x_size = y_superscript_x_size; | |
| 862 | os2_y_superscript_y_size = y_superscript_y_size; | |
| 863 | os2_y_superscript_x_offset = y_superscript_x_offset; | |
| 864 | os2_y_superscript_y_offset = y_superscript_y_offset; | |
| 865 | os2_y_strikeout_size = y_strikeout_size; | |
| 866 | os2_y_strikeout_position = y_strikeout_position; | |
| 867 | os2_s_family_class = s_family_class; | |
| 868 | os2_b_family_type = b_family_type; | |
| 869 | os2_b_serif_style = b_serif_style; | |
| 870 | os2_b_weight = b_weight; | |
| 871 | os2_b_proportion = b_proportion; | |
| 872 | os2_b_contrast = b_contrast; | |
| 873 | os2_b_stroke_variation = b_stroke_variation; | |
| 874 | os2_b_arm_style = b_arm_style; | |
| 875 | os2_b_letterform = b_letterform; | |
| 876 | os2_b_midline = b_midline; | |
| 877 | os2_b_x_height = b_x_height; | |
| 878 | os2_ul_unicode_range_1 = ul_unicode_range_1; | |
| 879 | os2_ul_unicode_range_2 = ul_unicode_range_2; | |
| 880 | os2_ul_unicode_range_3 = ul_unicode_range_3; | |
| 881 | os2_ul_unicode_range_4 = ul_unicode_range_4; | |
| 882 | os2_ach_vendor_id = ach_vendor_id; | |
| 883 | os2_fs_selection = fs_selection; | |
| 884 | os2_us_first_char_index = us_first_char_index; | |
| 885 | os2_us_last_char_index = us_last_char_index; | |
| 886 | os2_s_typo_ascender = s_typo_ascender; | |
| 887 | os2_s_typo_descender = s_typo_descender; | |
| 888 | os2_us_win_ascent = us_win_ascent; | |
| 889 | os2_us_win_descent = us_win_descent; | |
| 890 | } | |
| 891 | ||
| 892 | let parse file : ttf = | |
| 893 | let ctx = {
| |
| 894 | file = file; | |
| 895 | ch = IO.input_channel file; | |
| 896 | entry = {
| |
| 897 | entry_table_name = ""; | |
| 898 | entry_offset = ti32 0; | |
| 899 | entry_length = ti32 0; | |
| 900 | entry_checksum = ti32 0; | |
| 901 | } | |
| 902 | } in | |
| 903 | let header = parse_header ctx in | |
| 904 | let directory = parse_directory ctx header in | |
| 905 | let parse_table entry f = | |
| 906 | seek_in file (ti entry.entry_offset); | |
| 907 | ctx.entry <- entry; | |
| 908 | f ctx | |
| 909 | in | |
| 910 | let head = parse_table (Hashtbl.find directory "head") parse_head_table in | |
| 911 | let hhea = parse_table (Hashtbl.find directory "hhea") parse_hhea_table in | |
| 912 | let maxp = parse_table (Hashtbl.find directory "maxp") parse_maxp_table in | |
| 913 | let loca = parse_table (Hashtbl.find directory "loca") (parse_loca_table head maxp) in | |
| 914 | let hmtx = parse_table (Hashtbl.find directory "hmtx") (parse_hmtx_table maxp hhea) in | |
| 915 | let cmap = parse_table (Hashtbl.find directory "cmap") (parse_cmap_table) in | |
| 916 | let glyf = parse_table (Hashtbl.find directory "glyf") (parse_glyf_table maxp loca cmap hmtx) in | |
| 917 | (* let kern = parse_table (Hashtbl.find directory "kern") (parse_kern_table) in *) | |
| 918 | let name,ttf_name = parse_table (Hashtbl.find directory "name") (parse_name_table) in | |
| 919 | let os2 = parse_table (Hashtbl.find directory "OS/2") (parse_os2_table) in | |
| 920 | let tables = ("head", (THead head)) :: ("hhea", (THhea hhea)) :: ("maxp", (TMaxp maxp))
| |
| 921 | :: ("loca", (TLoca loca)) :: ("hmtx", (THmtx hmtx)) :: ("cmap", (TCmap cmap))
| |
| 922 | :: ("glyf", (TGlyf glyf)) :: ("name", (TName name))
| |
| 923 | :: ("OS/2", (TOS2 os2)) :: []
| |
| 924 | in | |
| 925 | {
| |
| 926 | ttf_header = header; | |
| 927 | ttf_name = ttf_name; | |
| 928 | ttf_directory = directory; | |
| 929 | ttf_tables = tables; | |
| 930 | } | |
| 931 | ||
| 932 | (* WRITING *) | |
| 933 | ||
| 934 | (* TODO: move this to swf.ml *) | |
| 935 | ||
| 936 | type font_language_code = | |
| 937 | | LCNone (*0*) | |
| 938 | | LCLatin (*1*) | |
| 939 | | LCJapanese (*2*) | |
| 940 | | LCKorean (*3*) | |
| 941 | | LCSimplifiedChinese (*4*) | |
| 942 | | LCTraditionalChinese (*5*) | |
| 943 | ||
| 944 | type font_glyph_data = {
| |
| 945 | font_char_code: int; | |
| 946 | font_shape: shape_records; | |
| 947 | } | |
| 948 | ||
| 949 | type font_layout_glyph_data = {
| |
| 950 | font_advance: int; | |
| 951 | font_bounds: rect; | |
| 952 | } | |
| 953 | ||
| 954 | type font_kerning_data = {
| |
| 955 | font_char_code1: int; | |
| 956 | font_char_code2: int; | |
| 957 | font_adjust: int; | |
| 958 | } | |
| 959 | ||
| 960 | type font_layout_data = {
| |
| 961 | font_ascent: int; | |
| 962 | font_descent: int; | |
| 963 | font_leading: int; | |
| 964 | font_glyphs: font_layout_glyph_data list; | |
| 965 | font_kerning: font_kerning_data list; | |
| 966 | } | |
| 967 | ||
| 968 | type font2_data = {
| |
| 969 | font_shift_jis: bool; | |
| 970 | font_is_small: bool; | |
| 971 | font_is_ansi: bool; | |
| 972 | font_is_italic: bool; | |
| 973 | font_is_bold: bool; | |
| 974 | font_language: font_language_code; | |
| 975 | font_name: string; | |
| 976 | font_glyphs: font_glyph_data array; | |
| 977 | font_layout: font_layout_data option; | |
| 978 | } | |
| 979 | ||
| 980 | (* This can stay *) | |
| 981 | ||
| 982 | type write_ctx = {
| |
| 983 | head : head; | |
| 984 | cmap : cmap; | |
| 985 | glyf : glyf array; | |
| 986 | } | |
| 987 | ||
| 988 | type glyf_path = {
| |
| 989 | gp_type : int; | |
| 990 | gp_x : float; | |
| 991 | gp_y : float; | |
| 992 | gp_cx : float; | |
| 993 | gp_cy : float; | |
| 994 | } | |
| 995 | ||
| 996 | let mk_path t x y cx cy = {
| |
| 997 | gp_type = t; | |
| 998 | gp_x = x; | |
| 999 | gp_y = y; | |
| 1000 | gp_cx = cx; | |
| 1001 | gp_cy = cy; | |
| 1002 | } | |
| 1003 | ||
| 1004 | let make_path ctx pq p1 p2 arr g = | |
| 1005 | let p1_on_curve = g.gs_flags.(p1) land 0x01 <> 0 in | |
| 1006 | let p2_on_curve = g.gs_flags.(p2) land 0x01 <> 0 in | |
| 1007 | match p1_on_curve, p2_on_curve with | |
| 1008 | | true, true -> | |
| 1009 | let path = mk_path 1 (float_of_int g.gs_x_coordinates.(p2)) (float_of_int g.gs_y_coordinates.(p2)) 0.0 0.0 in | |
| 1010 | DynArray.add arr path; | |
| 1011 | | false, false -> | |
| 1012 | let path = mk_path 2 !pq.gp_x !pq.gp_y (float_of_int g.gs_x_coordinates.(p1)) (float_of_int g.gs_y_coordinates.(p1)) in | |
| 1013 | DynArray.add arr path; | |
| 1014 | pq := (mk_path (-1) (float_of_int g.gs_x_coordinates.(p2)) (float_of_int g.gs_y_coordinates.(p2)) 0.0 0.0) | |
| 1015 | | true, false -> | |
| 1016 | pq := (mk_path (-1) (float_of_int g.gs_x_coordinates.(p2)) (float_of_int g.gs_y_coordinates.(p2)) 0.0 0.0) | |
| 1017 | | false, true -> | |
| 1018 | let path = mk_path 2 (float_of_int g.gs_x_coordinates.(p2)) (float_of_int g.gs_y_coordinates.(p2)) !pq.gp_x !pq.gp_y in | |
| 1019 | DynArray.add arr path | |
| 1020 | ||
| 1021 | let build_paths ctx g = | |
| 1022 | let len = Array.length g.gs_end_pts_of_contours in | |
| 1023 | let arr = DynArray.create () in | |
| 1024 | let cp = ref 0 in | |
| 1025 | let start = ref 0 in | |
| 1026 | let stop = ref 0 in | |
| 1027 | let pq = ref (mk_path (-1) 0.0 0.0 0.0 0.0) in | |
| 1028 | for i = 0 to len - 1 do | |
| 1029 | start := !cp; | |
| 1030 | stop := g.gs_end_pts_of_contours.(i); | |
| 1031 | let path = mk_path 0 (float_of_int g.gs_x_coordinates.(!start)) (float_of_int g.gs_y_coordinates.(!start)) 0.0 0.0 in | |
| 1032 | DynArray.add arr path; | |
| 1033 | for j = 0 to !stop - !start - 1 do | |
| 1034 | make_path ctx pq !cp (!cp + 1) arr g; | |
| 1035 | incr cp; | |
| 1036 | done; | |
| 1037 | make_path ctx pq !stop !start arr g; | |
| 1038 | incr cp; | |
| 1039 | done; | |
| 1040 | DynArray.to_list arr | |
| 1041 | ||
| 1042 | let begin_fill ctx c a = | |
| 1043 | SRStyleChange {
| |
| 1044 | scsr_move = None; | |
| 1045 | scsr_fs0 = None; | |
| 1046 | scsr_fs1 = Some(1); (* Some (c lor (a lsl 24));*) (* CHECK *) | |
| 1047 | scsr_ls = None; (* CHECK *) | |
| 1048 | scsr_new_styles = None; | |
| 1049 | } | |
| 1050 | ||
| 1051 | let move_to ctx x y = | |
| 1052 | SRStyleChange {
| |
| 1053 | scsr_move = Some (0,int_of_float x, int_of_float y); (* TODO *) | |
| 1054 | scsr_fs0 = None; | |
| 1055 | scsr_fs1 = None; (* TODO *) | |
| 1056 | scsr_ls = None; | |
| 1057 | scsr_new_styles = None; | |
| 1058 | } | |
| 1059 | ||
| 1060 | let line_to ctx x y = | |
| 1061 | SRStraightEdge {
| |
| 1062 | sser_nbits = max (SwfParser._nbits (abs(int_of_float x))) (SwfParser._nbits (abs(int_of_float y))); (* TODO ? *) | |
| 1063 | sser_line = Some (int_of_float x), Some (int_of_float y); | |
| 1064 | } | |
| 1065 | ||
| 1066 | let curve_to ctx cx cy x y = | |
| 1067 | SRCurvedEdge {
| |
| 1068 | - | scer_nbits = (max |
| 1068 | + | scer_nbits = 2 + (max |
| 1069 | (max (SwfParser._nbits (abs(int_of_float x))) (SwfParser._nbits (abs(int_of_float y)))) | |
| 1070 | (max (SwfParser._nbits (abs(int_of_float cx))) (SwfParser._nbits (abs(int_of_float cy))))); (* TODO ? *) | |
| 1071 | - | scer_cx = abs(int_of_float cx); |
| 1071 | + | scer_cx = int_of_float cx; |
| 1072 | - | scer_cy = abs(int_of_float cy); |
| 1072 | + | scer_cy = int_of_float cy; |
| 1073 | - | scer_ax = abs(int_of_float x); |
| 1073 | + | scer_ax = int_of_float x; |
| 1074 | - | scer_ay = abs(int_of_float y); |
| 1074 | + | scer_ay = int_of_float y; |
| 1075 | } | |
| 1076 | ||
| 1077 | let write_paths ctx paths = | |
| 1078 | let scale = 100. /. (float_of_int ctx.head.hd_units_per_em) in | |
| 1079 | let srl = DynArray.create () in | |
| 1080 | DynArray.add srl (begin_fill ctx 0 1); | |
| 1081 | List.iter (fun path -> | |
| 1082 | DynArray.add srl (match path.gp_type with | |
| 1083 | | 0 -> move_to ctx (path.gp_x *. scale) ((-1.) *. path.gp_y *. scale); | |
| 1084 | | 1 -> line_to ctx (path.gp_x *. scale) ((-1.) *. path.gp_y *. scale); | |
| 1085 | | 2 -> curve_to ctx (path.gp_cx *. scale) ((-1.) *. path.gp_cy *. scale) (path.gp_x *. scale) ((-1.) *. path.gp_y *. scale); | |
| 1086 | | _ -> assert false) | |
| 1087 | ) paths; | |
| 1088 | {
| |
| 1089 | srs_nfbits = 2; (* TODO *) | |
| 1090 | srs_nlbits = 0; (* TODO *) | |
| 1091 | srs_records = DynArray.to_list srl; | |
| 1092 | } | |
| 1093 | ||
| 1094 | let write_glyph ctx glyf = | |
| 1095 | match glyf.glyf_def with | |
| 1096 | | TglyfSimple g -> | |
| 1097 | let path = build_paths ctx g in | |
| 1098 | {
| |
| 1099 | font_char_code = 0; (* TODO *) | |
| 1100 | font_shape = write_paths ctx path; | |
| 1101 | } | |
| 1102 | | TglyfComposite g -> | |
| 1103 | {
| |
| 1104 | font_char_code = 0; (* TODO *) | |
| 1105 | font_shape = write_paths ctx []; (* TODO *) | |
| 1106 | } | |
| 1107 | ||
| 1108 | let map_char_code cc c4 = | |
| 1109 | (* TODO: well yeah... *) | |
| 1110 | 0 | |
| 1111 | ||
| 1112 | let make_cmap4_map ctx c4 = | |
| 1113 | let lut = Hashtbl.create 0 in | |
| 1114 | let seg_count = c4.c4_seg_count_x2 / 2 in | |
| 1115 | for i = 0 to seg_count - 1 do | |
| 1116 | for j = c4.c4_start_code.(i) to c4.c4_end_code.(i) do | |
| 1117 | let index = map_char_code j c4 in | |
| 1118 | Hashtbl.add lut j index | |
| 1119 | done; | |
| 1120 | done; | |
| 1121 | lut | |
| 1122 | ||
| 1123 | let bi v = if v then 1 else 0 | |
| 1124 | ||
| 1125 | let write_font2 ch b f2 = | |
| 1126 | IO.write_byte ch 255; (* 48 DefineFont 1/2 *) | |
| 1127 | IO.write_byte ch 18; (* 48 DefineFont 2/2 *) | |
| 1128 | IO.write_i32 ch 16777215; (* TODO: tag body size/length *) | |
| 1129 | IO.write_ui16 ch 1; (*TODO: Char id *) | |
| 1130 | ||
| 1131 | IO.write_bits b 1 (bi (f2.font_layout <> None)); | |
| 1132 | IO.write_bits b 1 (bi f2.font_shift_jis); | |
| 1133 | IO.write_bits b 1 (bi f2.font_is_small); | |
| 1134 | IO.write_bits b 1 (bi f2.font_is_ansi); | |
| 1135 | IO.write_bits b 1 (bi false); (* TODO: wide offsets *) | |
| 1136 | IO.write_bits b 1 (bi true); (* TODO: wide codes *) | |
| 1137 | IO.write_bits b 1 (bi f2.font_is_italic); | |
| 1138 | IO.write_bits b 1 (bi f2.font_is_bold); | |
| 1139 | ||
| 1140 | IO.write_byte ch 0; (* TODO: f2.font_language; LCNone *) | |
| 1141 | ||
| 1142 | IO.write_byte ch (String.length f2.font_name); | |
| 1143 | IO.nwrite ch f2.font_name; | |
| 1144 | IO.write_ui16 ch (Array.length f2.font_glyphs); (* numglyps *) | |
| 1145 | Array.iter (fun _ -> IO.write_ui16 ch 0) f2.font_glyphs; (* TODO: offsetTable *) | |
| 1146 | IO.write_ui16 ch (2 * Array.length f2.font_glyphs); (* TODO: offset to codeTable depends on 16 or 32 bit *) | |
| 1147 | ||
| 1148 | Array.iter (fun g -> | |
| 1149 | (* let b = IO.output_bits ch in *) | |
| 1150 | let nlbits = ref g.font_shape.srs_nlbits in | |
| 1151 | let nfbits = ref g.font_shape.srs_nfbits in | |
| 1152 | List.iter (fun r -> | |
| 1153 | match r with | |
| 1154 | | SRStyleChange s -> | |
| 1155 | print_string "SRStyleChange\n"; | |
| 1156 | | SRStraightEdge s-> | |
| 1157 | print_string "SRStraightEdge\n"; | |
| 1158 | | SRCurvedEdge s -> | |
| 1159 | print_string "SRCurvedEdge\n"; | |
| 1160 | print_string "s.scer_nbits: "; print_int s.scer_nbits; print_string "\n"; | |
| 1161 | print_string "s.scer_cx: "; print_int s.scer_cx; print_string "\n"; | |
| 1162 | print_string "s.scer_cy: "; print_int s.scer_cy; print_string "\n"; | |
| 1163 | print_string "s.scer_ax: "; print_int s.scer_ax; print_string "\n"; | |
| 1164 | print_string "s.scer_ay: "; print_int s.scer_ay; print_string "\n"; | |
| 1165 | try | |
| 1166 | SwfParser.write_shape_record ch b nlbits nfbits r; | |
| 1167 | - | with _ -> print_endline "Success!" |
| 1167 | + | with _ -> print_endline "FAILURE!" |
| 1168 | ||
| 1169 | ) g.font_shape.srs_records | |
| 1170 | ) f2.font_glyphs | |
| 1171 | (* TODO: rest *) | |
| 1172 | ||
| 1173 | let write_swf ttf range_str = | |
| 1174 | let ctx = {
| |
| 1175 | head = (match List.assoc "head" ttf.ttf_tables with THead head -> head | _ -> assert false); | |
| 1176 | cmap = (match List.assoc "cmap" ttf.ttf_tables with TCmap cmap -> cmap | _ -> assert false); | |
| 1177 | glyf = (match List.assoc "glyf" ttf.ttf_tables with TGlyf glyf -> glyf | _ -> assert false); | |
| 1178 | } in | |
| 1179 | let rec loop cl = match cl with | |
| 1180 | | [] -> failwith "Cmap4 table not found" | |
| 1181 | | {cs_def = Cmap4 c4} :: _ ->
| |
| 1182 | make_cmap4_map ctx c4 | |
| 1183 | | _ :: cl -> | |
| 1184 | loop cl | |
| 1185 | in | |
| 1186 | let glyph_lut = loop ctx.cmap.cmap_subtables in | |
| 1187 | ignore(glyph_lut); | |
| 1188 | (* TODO: check range, perform lookup *) | |
| 1189 | {
| |
| 1190 | font_shift_jis = false; | |
| 1191 | font_is_small = false; | |
| 1192 | font_is_ansi = false; | |
| 1193 | font_is_italic = false; | |
| 1194 | font_is_bold = false; | |
| 1195 | font_language = LCNone; | |
| 1196 | font_name = "chopin"; (* ttf.ttf_name; *) | |
| 1197 | font_glyphs = Array.map (write_glyph ctx) ctx.glyf; | |
| 1198 | font_layout = None; | |
| 1199 | } | |
| 1200 | ;; | |
| 1201 | let f2 = write_swf (parse (open_in_bin "chopin.ttf")) "" in | |
| 1202 | let ch = (IO.output_channel (open_out_bin "chopin_test.dat")) in | |
| 1203 | let b = IO.output_bits ch in | |
| 1204 | write_font2 ch b f2 | |
| 1205 | ||
| 1206 | (* ocamlopt -I ../extlib -I ../extc enum.cmx extlist.cmx extstring.cmx io.cmx dynarray.cmx multiarray.cmx swf.cmx as3code.cmx as3parse.cmx actionscript.cmx swfparser.cmx ttf.ml -o run.exe *) |