Initial commit of OpenSPARC T2 design and verification files.
[OpenSPARC-T2-DV] / tools / perl-5.8.0 / lib / site_perl / 5.8.0 / Pastel / Font / TTF.pm
CommitLineData
86530b38
AT
1package Pastel::Font::TTF;
2
3use Pastel::Mixin::Mixin;
4use IO::File;
5use Carp;
6@ISA = qw(Pastel::Mixin::Mixin);
7use strict;
8
9my $PLATFORM_ID = 3;
10my $ENCODING_ID = 1;
11
12sub new
13{
14 my $arg = shift;
15 my $class = ref($arg) || $arg;
16 my $self = {};
17
18 bless $self, $class;
19 $self->_init(@_);
20
21 return $self;
22
23}
24
25sub _init {
26
27 my ($self, @args) = @_;
28 $self->{_fh} = undef;
29 $self->{family} = undef;
30 $self->{glyphs} = [];
31 $self->{tables} = {};
32 $self->{platform} = 3;
33 $self->{encoding} = 1;
34 $self->{subfamily} = undef;
35}
36
37sub create_from_file {
38 my ($self,@args) = @_;
39 my $mod = Pastel::Font::TTF->new();
40 my ($path, $file) = $mod->_rearrange(["PATH","FILE"],@args);
41 my $fh;
42
43 if(defined($path) || defined($file)){
44
45 if(defined($path)){
46 $mod->set_file_handle($path);
47 return $mod;
48 }
49 if(defined($file)){
50 $mod->set_file_handle($file);
51 return $mod;
52 }
53
54 } else {
55 croak "Supply filename in Pastel::Font::TTF::create_from_file()\n";
56 }
57}
58
59sub set_file_handle {
60 my $self = shift;
61 my $path = shift;
62 my $fh = IO::File->new();
63
64 if($fh->open("< $path")){
65 binmode($fh);
66 $self->{_fh} = $fh;
67 } else {
68 croak "Could not open $path in Pastel::Font::TTF::set_file_handle\n";
69 }
70 $self->make_directory_entry();
71
72}
73
74sub get_file_handle {
75 my $self = shift;
76 if (defined($self->{_fh})){
77 return $self->{_fh};
78 } else {
79 return 0;
80 }
81}
82
83sub make_directory_entry {
84 my $self = shift;
85 my $fh = $self->get_file_handle();
86 my $buf="";
87
88 eval{read($fh, $buf, 12)};
89 if($@){
90 croak "Read error in Pastel::Font::TTF::make_directory_entry\n";
91 }
92
93 my ($version, $number) = unpack("Nn", $buf);
94 #print "Version = $version, Number of tables = $number\n";
95 # print "\nTABLE\tOFFSET\tLENGTH\n";
96
97 for(my $i = 0; $i < $number; $i++){
98 #print "Inside for\n";
99 read($fh, $buf, 16);
100 my ( $table, $offset, $length) = unpack("a4x4NN", $buf);
101 $self->{table}->{$table} = $offset;
102
103#print "$table\t$offset\t$length\n";
104}
105 #print $self->{table}->{'OS/2'};
106}
107
108#sub get_font_family {
109# my $self = shift;
110# my $buf;
111# my $fh = $self->get_file_handle();
112
113# my $LANGUAGE_ID;
114# my $PLATFORM_ID = $self->{platform};
115# my $ENCODING_ID = $self->{encoding};
116
117# if ( $self->{platform} =="1" && $self->{encoding} =="0"){
118# $LANGUAGE_ID = 0;
119# }
120# else {
121# $LANGUAGE_ID = 1033;
122# }
123
124# my $add = $self->get_table_address('name');
125
126# seek ($fh, $add, 0);
127# read($fh, $buf, 6);
128# my ( $num , $offset) = unpack ("x2nn", $buf);
129# #print "*******NAME : Number of records, $num, Offset: $offset\n";
130
131# my ($copyright_offset, $font_family_name_offset,
132# $subfamily_offset, $id_offset,$full_name_offset,
133# $version_string_offset, $postscript_offset, $trademark_offset);
134
135# my ($copyright_length, $font_family_length,
136# $subfamily_length, $id_length, $full_name_length,
137# $version_length, $postscript_length, $trademark_length);
138
139# for (my $i = 0; $i < $num; $i++){
140# read ($fh, $buf, 12);
141# my ($id, $encoding, $language, $name_id, $length, $string_offset)
142# = unpack("n6", $buf);
143# #print "****NAMERECORDS: $id, $encoding, $language, $name_id, $length, $string_offset\n";
144
145# if ( ($id == $PLATFORM_ID)&& # Windows??
146# ($encoding == $ENCODING_ID) && #UGL??
147# ($language == $LANGUAGE_ID)
148# ) {
149# if ($name_id == 0 ) { #Copyright
150# $copyright_offset = $string_offset;
151# $copyright_length = $length;
152# }
153# if ($name_id == 1 ) { # Familyname
154# $font_family_name_offset = $string_offset;
155# $font_family_length = $length;
156# }
157# if ($name_id == 2 ) { # Subfamily
158# $subfamily_offset = $string_offset;
159# $subfamily_length = $length;
160# }
161# if ($name_id == 3 ) { # Identifier
162# $id_offset = $string_offset;
163# $id_length = $length;
164# }
165# if ($name_id == 4 ) { # Full name
166# $full_name_offset = $string_offset;
167# $full_name_length = $length;
168# }
169# if ($name_id == 5 ) { #version string
170# $version_string_offset = $string_offset;
171# $version_length = $length;
172# }
173# if ( $name_id == 6) { # Postscript name
174# $postscript_offset = $string_offset;
175# $postscript_length = $length;
176# }
177# if ($name_id == 7 ) { # Trademark
178# $trademark_offset = $string_offset;
179# $trademark_length = $length;
180# }
181# }
182
183# } # End for loop;
184
185# # Print copyright
186# seek ( $fh, $add + $offset + $copyright_offset, 0);
187# read ($fh, $buf, $copyright_length);
188# # print "COPYRIGHT: $buf\n\n";
189
190# # Print familyname
191# seek ($fh, $add + $offset + $font_family_name_offset, 0 );
192# read ( $fh, $buf, $font_family_length);
193# return $buf;
194## print "FAMILY: $buf\n\n";
195
196# #Print Subfamily
197# seek ($fh, $add + $offset + $subfamily_offset, 0);
198# read ($fh, $buf, $subfamily_length);
199# #print "SUBFAMILY: $buf\n\n";
200
201# #Print Identifier
202# seek ( $fh, $add + $offset +$id_offset, 0);
203# read ($fh, $buf, $id_length);
204# #print "ID: $buf\n\n";
205
206# #Print Full name
207# seek ( $fh, $add + $offset +$full_name_offset, 0);
208# read ($fh, $buf, $full_name_length);
209# #print "FULL NAME: $buf\n\n";
210
211# #Print Version string
212# seek ( $fh, $add + $offset +$version_string_offset, 0);
213# read ($fh, $buf, $version_length);
214# #print "VERSION: $buf\n\n";
215
216
217# #Print Postscript
218# seek ( $fh, $add + $offset +$postscript_offset, 0);
219# read ($fh, $buf, $postscript_length);
220# #print "Postscript: $buf\n\n";
221
222##Print Trademark
223# seek ( $fh, $add + $offset +$trademark_offset, 0);
224# read ($fh, $buf, $trademark_length);
225# #print "TRADEMARK: $buf\n\n";
226
227
228#}
229
230sub get_table_address {
231 my $self = shift;
232 my $table_name = shift;
233
234 if (defined($self->{table}->{$table_name})){
235 return $self->{table}->{$table_name};
236 } else {
237 croak "Undefined table address in Pastel::Font::TTF::get_table_address()\n";
238 }
239}
240
241sub make_glyph_index {
242 my $self = shift;
243 my $buf;
244 my $offset;
245 my $fh = $self->get_file_handle();
246 my $PLATFORM_ID = $self->{platform};
247 my $ENCODING_ID = $self->{encoding};
248 # Glyph indices are stored in "cmap" table. We get the offset of the
249 # "cmap" table from the %table hash
250
251 my $cmap = $self->get_table_address('cmap');
252
253 #Go there
254 seek ($fh, $cmap, 0);
255
256 #'cmap' table starts with
257 # USHORT Table version number
258 # USHORT Number of encoding tables
259 # Read 4 bytes
260 read ($fh, $buf, 4);
261
262 #Get number of tables and skip the version number
263 my ($num) = unpack ("x2n", $buf);
264
265 # Read the tables. There will $num tables
266 # Each one for a specific encoding and platform id
267 # There are three most important id and encoding-
268 # Windows : ID=3 Encoding = 1
269 # Windows symbol : ID=3 Encoding = 0
270 # Mac/Poscript : ID=1 Encoding = 0
271
272 #Each subtable:
273 # USHORT Platform ID
274 # USHORT Platform specific encoding ID
275 # ULONG Byte ofset from the begining of the 'cmap' table
276
277 for(my $i = 0; $i < $num; $i++){
278 read($fh, $buf, 8);
279 my($id, $encoding, $off) = unpack("nnN", $buf);
280
281 if($id == $PLATFORM_ID && $encoding == $ENCODING_ID){
282 $offset = $off;
283 }
284 }
285
286 #Goto the specific table
287 seek($fh, $cmap + $offset, 0);
288
289 # Mac/Poscript table with encoding 0 use the following format
290 # USHORT format set to 0
291 # USHORT length
292 # USHORT version starts at 0
293 # BYTE glyphIdArray[256] There is no trick here just read the whole
294 # thing as 256 array
295
296 # If MAC/Postcript table
297 if ($PLATFORM_ID =="1" && $ENCODING_ID=="0"){
298 # Skip the format, length and version information
299 read($fh, $buf, 6);
300 #print (unpack("nnn", $buf));
301 # Now read the 256 element array directly
302
303 for (my $i =0; $i < 256; $i++){
304 read($fh, $buf,1);
305 #print $buf;
306 $self->{glyphs}->[$i] = unpack("C", $buf);
307 #print $self->{glyphs}->[$i];
308 print "Char $i\t\t-> Index $self->{glyphs}->[$i]\n";
309 }
310
311 }
312
313 # Windows table with encoding 1 use the following format FORMAT 4
314 # USHORT format Format number is set to 4.
315# USHORT length Length in bytes.
316# USHORT version Version number (starts at 0).
317# USHORT segCountX2 2 x segCount.
318# USHORT searchRange 2 x (2**floor(log2(segCount)))
319# USHORT entrySelector log2(searchRange/2)
320# USHORT rangeShift 2 x segCount - searchRange
321# USHORT endCount[segCount] End characterCode for each segment,
322# last =0xFFFF.
323# USHORT reservedPad Set to 0.
324# USHORT startCount[segCount] Start character code for each segment.
325# USHORT idDelta[segCount] Delta for all character codes in segment.
326# USHORT idRangeOffset[segCount]Offsets into glyphIdArray or 0
327# USHORT glyphIdArray[ ] Glyph index array (arbitrary length)
328 if ( $PLATFORM_ID == "3" && $ENCODING_ID =="1"){
329 read ($fh, $buf, 6);
330 my ($format, $length, $version) = unpack("nnn", $buf);
331 #print "Format: $format\tLength: $length\tVersion: $version\n\n";
332 read ($fh, $buf,8);
333 my ($seg_countX2, $search_range, $entry_selector, $range_shift)
334 = unpack("nnnn", $buf);
335 my $seg_count = $seg_countX2 / 2;
336 # print "SegcountX2:\t\t$seg_countX2\n";
337# print "Search Range:\t$search_range\n";
338# print "Entry:\t$entry_selector\n";
339# print "Range Shift:\t$range_shift\n";
340
341 read($fh, $buf, 2 * $seg_count);
342 my(@end_count) = unpack("n" x $seg_count, $buf);
343 #print "EndCount: ", join("\t",@end_count), "\n";
344 read($fh, $buf, 2);
345 my $reserve_pad = unpack("n", $buf);
346 #print "Reserve Pad: $reserve_pad\n";
347
348 read($fh, $buf, 2 * $seg_count);
349 my(@start_count) = unpack("n" x $seg_count, $buf);
350 #print "Start Count: ", join("\t",@start_count), "\n";
351
352 read($fh, $buf, 2 * $seg_count);
353 my(@id_delta) = unpack("n" x $seg_count, $buf);
354 #print "idDelta: ", join("\t",@id_delta), "\n";
355
356 read($fh, $buf, 2 * $seg_count);
357 my(@id_range_offset) = unpack("n" x $seg_count, $buf);
358 #print "idRangeOffset: ", join("\t",@id_range_offset), "\n";
359
360 my $num = read($fh, $buf, $length - ($seg_count * 8) - 16);
361 my (@glyph_id) = unpack("n" x ($num / 2), $buf);
362
363# for(my $i = 0; $i <@end_count; $i++){
364# if ( ($INDEX <= $end_count[$i]) && ($INDEX >= $start_count[$i]) ){
365# if ($id_range_offset[$i] == 0){
366# return $INDEX + $id_delta[$i] -($id_delta[$i]> 32767 ? 65536: 0);
367# }
368# else {
369# my $offset = $INDEX - $start_count[$i];
370# print "OFFSET ===== $offset\n";
371# if ($glyph_id[$offset] == 0){
372
373# return 0;
374# }
375# else{
376
377# return $glyph_id[$offset] + $id_delta[$i] - ($id_delta[$i]> 32767 ? 65536: 0);
378
379# }
380# }
381# }
382
383# }
384
385 for ( my $i = 0; $i < 256; $i++){
386 for (my $j = 0; $j <$seg_count; $j++){
387
388 if ($end_count[$j] >= $i && $start_count[$j] <= $i){
389 #print "ID RANGE OFFSET $id_range_offset[$j]", "\n";
390 if ($id_range_offset[$j] != 0){
391
392 $self->{glyphs}->[$i] = $glyph_id[$id_range_offset[$j]/2 + ($i - $start_count[$j]) - ($seg_count - $j)];
393 }
394 else {
395 $self->{glyphs}->[$i] = ($id_delta[$j] + $i) % 65536;
396 }
397 }
398 }
399 if (!defined($self->{glyphs}->[$i])){
400 #$self->{glyphs}->[$i] = $glyph_id[0];
401 $self->{glyphs}->[$i] = 0;
402 }
403 #print "Char $i -> \t\t $self->{glyphs}->[$i]\n";
404 }
405
406 }
407}
408
409sub get_advance_width {
410 my $self = shift;
411 my $fh = $self->get_file_handle();
412 my $buf;
413
414 seek($fh, $self->{table}->{"hhea"}, 0);
415 read($fh, $buf, 36) == 36 || die "reading hhea table";
416 my($h_num) = unpack("x34n", $buf);
417 my $num = $h_num;
418 my $index = shift;
419 seek($fh, $self->{table}->{"hmtx"}, 0);
420 read($fh, $buf, 4 * $num) == 4 * $num || die "reading hmtx table";
421 my (@h_temp) = unpack("n" x (2 * $num), $buf);
422 # print "******@h_temp\n";
423 my (@advanced_width);
424 my (@lsb);
425 for (my $i = 0; $i < @h_temp; $i +=2){
426 push (@advanced_width,$h_temp[$i]);
427 #print $h_temp[$i];
428 }
429 for (my $i = 1; $i < @h_temp; $i +=2){
430 push (@lsb,$h_temp[$i]);
431 }
432#print @advanced_width, "\n";
433#print @lsb;
434
435 if ($index > @lsb){$index = @lsb;}
436 my $a = $advanced_width[$index] - ($advanced_width[$index] > 32768 ? 65536 : 0);
437 my $l = $lsb[$index] - ($lsb[$index] > 32768 ? 65536 :0);
438
439 #return $a, $l;
440 return $a;
441 }
442
443sub get_leading {
444 my $self = shift;
445 if (defined($self->{leading})){
446 return $self->{leading};
447 } else {
448 $self->_parse_os2();
449 #$self->{leading} = $self->_get_leading();
450 return $self->{leading};
451 }
452}
453
454sub _get_leading {
455 my $self = shift;
456 my $fh = $self->get_file_handle();
457
458 # Get the adress of the OS/2 table
459 my $add = $self->get_table_address('OS/2');
460 my $buf;
461 #print $add, "\n";
462
463 #Leading is sTypoLineGap in OS/2 table
464 seek($fh, $add, 0);
465 read($fh, $buf, 74) == 74 || die "reading OS/2 table";
466 my ($leading) = unpack("x72n", $buf);
467 #print join(" ",@panose), "\n";
468 #print $leading, "\n";
469 return $leading - ($leading > 32768 ? 65536 : 0);
470}
471
472sub get_units_per_em {
473 my $self = shift;
474
475 # Get Headtable address
476 my $add = $self->get_table_address("head");
477 my $buf;
478 my $fh = $self->get_file_handle();
479
480 seek($fh, $add, 0);
481
482 read($fh, $buf, 54) == 54 || die "reading head table";
483 my($units_per_em, $index_to_loc) = unpack("x18nx30n", $buf);
484
485 # print "Unit/EM: $units_per_em\tIndex_to_loc: $index_to_loc\n\n";
486
487 return $units_per_em;
488}
489
490
491sub get_ascent {
492 my $self = shift;
493 if (defined($self->{ascent})){
494 return $self->{ascent};
495 } else {
496 $self->_parse_os2();
497 #$self->{ascent} = $self->_get_ascent();
498 return $self->{ascent};
499 }
500}
501
502sub _get_ascent {
503 my $self = shift;
504 my $fh = $self->get_file_handle();
505
506 # Get the adress of the OS/2 table
507 my $add = $self->get_table_address('OS/2');
508 my $buf;
509 #print $add, "\n";
510
511 # Ascent is is sTypoAscender in OS/2 table
512 seek($fh, $add, 0);
513 read($fh, $buf, 70) == 70 || die "reading OS/2 table";
514 my ($ascent) = unpack("x68n", $buf);
515 #print join(" ",@panose), "\n";
516 #print $ascent, "\n";
517 return $ascent - ($ascent > 32768 ? 65536 : 0);
518}
519
520sub get_descent {
521 my $self = shift;
522 if (defined($self->{descent})){
523 return $self->{descent};
524 } else {
525 $self->_parse_os2();
526 #$self->{descent} = $self->_get_descent();
527 return $self->{descent};
528 }
529}
530
531sub _parse_os2 {
532 my $self = shift;
533 my $fh = $self->get_file_handle();
534 my $add = $self->get_table_address('OS/2');
535 my $buf;
536
537 seek($fh, $add, 0);
538 read($fh, $buf, 74) == 74 || die "reading OS/2 table";
539 my ($ascent, $descent, $leading) =
540 unpack("x68nnn", $buf);
541 $self->{ascent} = $ascent - ($ascent > 32768 ? 65536 : 0);
542 $self->{descent} = $descent - ($descent > 32768 ? 65536 :0);
543 $self->{leading} = $leading - ($leading > 32768 ? 65536 :0);
544}
545sub get_font_family {
546 my $self = shift;
547 if ( defined($self->{family}) ){
548 return $self->{family};
549 } else {
550 $self->_parse_name_table();
551 }
552 return $self->{family};
553}
554
555sub get_subfamily {
556 my $self = shift;
557 if ( defined( $self->{subfamily})){
558 return $self->{subfamily};
559 } else {
560 $self->_parse_name_table();
561 }
562return $self->{subfamily};
563 }
564
565sub _parse_name_table {
566
567 my $self = shift;
568 my $buf;
569 my $fh = $self->get_file_handle();
570
571 my $LANGUAGE_ID;
572
573 if ( $PLATFORM_ID =="1" && $ENCODING_ID =="0"){
574 $LANGUAGE_ID = 0;
575 }
576 else {
577 $LANGUAGE_ID = 1033;
578 }
579 my $add = $self->get_table_address("name");
580 seek ($fh, $add, 0);
581 read($fh, $buf, 6);
582 my ( $num , $offset) = unpack ("x2nn", $buf);
583 #print "*******NAME : Number of records, $num, Offset: $offset\n";
584
585 my ($copyright_offset, $font_family_name_offset,
586 $subfamily_offset, $id_offset,$full_name_offset,
587 $version_string_offset, $postscript_offset, $trademark_offset);
588
589 my ($copyright_length, $font_family_length,
590 $subfamily_length, $id_length, $full_name_length,
591 $version_length, $postscript_length, $trademark_length);
592
593 for (my $i = 0; $i < $num; $i++){
594 read ($fh, $buf, 12);
595 my ($id, $encoding, $language, $name_id, $length, $string_offset)
596 = unpack("n6", $buf);
597 #print "****NAMERECORDS: $id, $encoding, $language, $name_id, $length, $string_offset\n";
598
599 if ( ($id == $PLATFORM_ID)&& # Windows??
600 ($encoding == $ENCODING_ID) && #UGL??
601 ($language == $LANGUAGE_ID)
602 ) {
603 if ($name_id == 0 ) { #Copyright
604 $copyright_offset = $string_offset;
605 $copyright_length = $length;
606 }
607 if ($name_id == 1 ) { # Familyname
608 $font_family_name_offset = $string_offset;
609 $font_family_length = $length;
610 }
611 if ($name_id == 2 ) { # Subfamily
612 $subfamily_offset = $string_offset;
613 $subfamily_length = $length;
614 }
615 if ($name_id == 3 ) { # Identifier
616 $id_offset = $string_offset;
617 $id_length = $length;
618 }
619 if ($name_id == 4 ) { # Full name
620 $full_name_offset = $string_offset;
621 $full_name_length = $length;
622 }
623 if ($name_id == 5 ) { #version string
624 $version_string_offset = $string_offset;
625 $version_length = $length;
626 }
627 if ( $name_id == 6) { # Postscript name
628 $postscript_offset = $string_offset;
629 $postscript_length = $length;
630 }
631 if ($name_id == 7 ) { # Trademark
632 $trademark_offset = $string_offset;
633 $trademark_length = $length;
634 }
635 }
636
637 } # End for loop;
638
639 # Print copyright
640 seek ( $fh, $self->get_table_address("name") + $offset + $copyright_offset, 0);
641 read ($fh, $buf, $copyright_length);
642 # print "COPYRIGHT: $buf\n\n";
643
644 # Print familyname
645 seek ($fh, $self->get_table_address("name") + $offset + $font_family_name_offset, 0 );
646 read ( $fh, $buf, $font_family_length);
647
648
649 #print $s;
650 $self->{family}= $self->_remove_white_space($buf, $font_family_length);
651 #print "\n****", "@char", "*****\n";
652 #return "@char";
653# print "FAMILY: $buf\n\n";
654
655 #Print Subfamily
656 seek ($fh, $self->get_table_address('name') + $offset + $subfamily_offset, 0);
657 read ($fh, $buf, $subfamily_length);
658 #print "SUBFAMILY: $buf\n\n";
659 $self->{subfamily} = $self->_remove_white_space($buf, $subfamily_length);
660
661 #Print Identifier
662 seek ( $fh, $self->get_table_address('name') + $offset +$id_offset, 0);
663 read ($fh, $buf, $id_length);
664 #print "ID: $buf\n\n";
665
666 #Print Full name
667 seek ( $fh, $self->get_table_address('name') + $offset +$full_name_offset, 0);
668 read ($fh, $buf, $full_name_length);
669 #print "FULL NAME: $buf\n\n";
670
671 #Print Version string
672 seek ( $fh, $self->get_table_address('name') + $offset +$version_string_offset, 0);
673 read ($fh, $buf, $version_length);
674 #print "VERSION: $buf\n\n";
675
676
677 #Print Postscript
678 seek ( $fh, $self->get_table_address('name') + $offset +$postscript_offset, 0);
679 read ($fh, $buf, $postscript_length);
680 #print "Postscript: $buf\n\n";
681
682#Print Trademark
683 seek ( $fh, $self->get_table_address('name') + $offset +$trademark_offset, 0);
684 read ($fh, $buf, $trademark_length);
685 #print "TRADEMARK: $buf\n\n";
686
687
688}
689
690sub _remove_white_space {
691 my $self = shift;
692 my $buf = shift;
693 my $font_family_length = shift;
694 my @char = unpack("C*",$buf);
695 my $i = $font_family_length;
696 my $s = "";
697 my $j = 0;
698 while ( $j < $i){
699 if (defined $char[$j+1]){
700 $s .= pack("C",$char[$j+1]);}
701 $j += 2;
702 }
703 return $s;
704}
7051;