View difference between Paste ID: XgaDdL79 and txMH1sWy
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 *)