pcfread.c revision 10bf05a31d63c6674fd057514d1066d1f081f4aa
1/* pcfread.c 2 3 FreeType font driver for pcf fonts 4 5 Copyright 2000, 2001, 2002, 2003, 2004 by 6 Francesco Zappa Nardelli 7 8Permission is hereby granted, free of charge, to any person obtaining a copy 9of this software and associated documentation files (the "Software"), to deal 10in the Software without restriction, including without limitation the rights 11to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12copies of the Software, and to permit persons to whom the Software is 13furnished to do so, subject to the following conditions: 14 15The above copyright notice and this permission notice shall be included in 16all copies or substantial portions of the Software. 17 18THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24THE SOFTWARE. 25*/ 26 27 28#include <ft2build.h> 29 30#include FT_INTERNAL_DEBUG_H 31#include FT_INTERNAL_STREAM_H 32#include FT_INTERNAL_OBJECTS_H 33 34#include "pcf.h" 35#include "pcfdrivr.h" 36#include "pcfread.h" 37 38#include "pcferror.h" 39 40 41 /*************************************************************************/ 42 /* */ 43 /* The macro FT_COMPONENT is used in trace mode. It is an implicit */ 44 /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */ 45 /* messages during execution. */ 46 /* */ 47#undef FT_COMPONENT 48#define FT_COMPONENT trace_pcfread 49 50 51#if defined( FT_DEBUG_LEVEL_TRACE ) 52 static const char* const tableNames[] = 53 { 54 "prop", "accl", "mtrcs", "bmps", "imtrcs", 55 "enc", "swidth", "names", "accel" 56 }; 57#endif 58 59 60 static 61 const FT_Frame_Field pcf_toc_header[] = 62 { 63#undef FT_STRUCTURE 64#define FT_STRUCTURE PCF_TocRec 65 66 FT_FRAME_START( 8 ), 67 FT_FRAME_ULONG_LE( version ), 68 FT_FRAME_ULONG_LE( count ), 69 FT_FRAME_END 70 }; 71 72 73 static 74 const FT_Frame_Field pcf_table_header[] = 75 { 76#undef FT_STRUCTURE 77#define FT_STRUCTURE PCF_TableRec 78 79 FT_FRAME_START( 16 ), 80 FT_FRAME_ULONG_LE( type ), 81 FT_FRAME_ULONG_LE( format ), 82 FT_FRAME_ULONG_LE( size ), 83 FT_FRAME_ULONG_LE( offset ), 84 FT_FRAME_END 85 }; 86 87 88 static FT_Error 89 pcf_read_TOC( FT_Stream stream, 90 PCF_Face face ) 91 { 92 FT_Error error; 93 PCF_Toc toc = &face->toc; 94 PCF_Table tables; 95 96 FT_Memory memory = FT_FACE(face)->memory; 97 FT_UInt n; 98 99 100 if ( FT_STREAM_SEEK ( 0 ) || 101 FT_STREAM_READ_FIELDS ( pcf_toc_header, toc ) ) 102 return PCF_Err_Cannot_Open_Resource; 103 104 if ( toc->version != PCF_FILE_VERSION ) 105 return PCF_Err_Invalid_File_Format; 106 107 if ( FT_NEW_ARRAY( face->toc.tables, toc->count ) ) 108 return PCF_Err_Out_Of_Memory; 109 110 tables = face->toc.tables; 111 for ( n = 0; n < toc->count; n++ ) 112 { 113 if ( FT_STREAM_READ_FIELDS( pcf_table_header, tables ) ) 114 goto Exit; 115 tables++; 116 } 117 118#if defined( FT_DEBUG_LEVEL_TRACE ) 119 120 { 121 FT_UInt i, j; 122 const char* name = "?"; 123 124 125 FT_TRACE4(( "Tables count: %ld\n", face->toc.count )); 126 tables = face->toc.tables; 127 for ( i = 0; i < toc->count; i++ ) 128 { 129 for( j = 0; j < sizeof ( tableNames ) / sizeof ( tableNames[0] ); j++ ) 130 if ( tables[i].type == (FT_UInt)( 1 << j ) ) 131 name = tableNames[j]; 132 133 FT_TRACE4(( "Table %d: type=%-6s format=0x%04lX " 134 "size=0x%06lX (%8ld) offset=0x%04lX\n", 135 i, name, 136 tables[i].format, 137 tables[i].size, tables[i].size, 138 tables[i].offset )); 139 } 140 } 141 142#endif 143 144 return PCF_Err_Ok; 145 146 Exit: 147 FT_FREE( face->toc.tables ); 148 return error; 149 } 150 151 152 static 153 const FT_Frame_Field pcf_metric_header[] = 154 { 155#undef FT_STRUCTURE 156#define FT_STRUCTURE PCF_MetricRec 157 158 FT_FRAME_START( 12 ), 159 FT_FRAME_SHORT_LE( leftSideBearing ), 160 FT_FRAME_SHORT_LE( rightSideBearing ), 161 FT_FRAME_SHORT_LE( characterWidth ), 162 FT_FRAME_SHORT_LE( ascent ), 163 FT_FRAME_SHORT_LE( descent ), 164 FT_FRAME_SHORT_LE( attributes ), 165 FT_FRAME_END 166 }; 167 168 169 static 170 const FT_Frame_Field pcf_metric_msb_header[] = 171 { 172#undef FT_STRUCTURE 173#define FT_STRUCTURE PCF_MetricRec 174 175 FT_FRAME_START( 12 ), 176 FT_FRAME_SHORT( leftSideBearing ), 177 FT_FRAME_SHORT( rightSideBearing ), 178 FT_FRAME_SHORT( characterWidth ), 179 FT_FRAME_SHORT( ascent ), 180 FT_FRAME_SHORT( descent ), 181 FT_FRAME_SHORT( attributes ), 182 FT_FRAME_END 183 }; 184 185 186 static 187 const FT_Frame_Field pcf_compressed_metric_header[] = 188 { 189#undef FT_STRUCTURE 190#define FT_STRUCTURE PCF_Compressed_MetricRec 191 192 FT_FRAME_START( 5 ), 193 FT_FRAME_BYTE( leftSideBearing ), 194 FT_FRAME_BYTE( rightSideBearing ), 195 FT_FRAME_BYTE( characterWidth ), 196 FT_FRAME_BYTE( ascent ), 197 FT_FRAME_BYTE( descent ), 198 FT_FRAME_END 199 }; 200 201 202 static FT_Error 203 pcf_get_metric( FT_Stream stream, 204 FT_ULong format, 205 PCF_Metric metric ) 206 { 207 FT_Error error = PCF_Err_Ok; 208 209 210 if ( PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) ) 211 { 212 const FT_Frame_Field* fields; 213 214 215 /* parsing normal metrics */ 216 fields = PCF_BYTE_ORDER( format ) == MSBFirst 217 ? pcf_metric_msb_header 218 : pcf_metric_header; 219 220 /* the following sets 'error' but doesn't return in case of failure */ 221 (void)FT_STREAM_READ_FIELDS( fields, metric ); 222 } 223 else 224 { 225 PCF_Compressed_MetricRec compr; 226 227 228 /* parsing compressed metrics */ 229 if ( FT_STREAM_READ_FIELDS( pcf_compressed_metric_header, &compr ) ) 230 goto Exit; 231 232 metric->leftSideBearing = (FT_Short)( compr.leftSideBearing - 0x80 ); 233 metric->rightSideBearing = (FT_Short)( compr.rightSideBearing - 0x80 ); 234 metric->characterWidth = (FT_Short)( compr.characterWidth - 0x80 ); 235 metric->ascent = (FT_Short)( compr.ascent - 0x80 ); 236 metric->descent = (FT_Short)( compr.descent - 0x80 ); 237 metric->attributes = 0; 238 } 239 240 Exit: 241 return error; 242 } 243 244 245 static FT_Error 246 pcf_seek_to_table_type( FT_Stream stream, 247 PCF_Table tables, 248 FT_Int ntables, 249 FT_ULong type, 250 FT_ULong *aformat, 251 FT_ULong *asize ) 252 { 253 FT_Error error = PCF_Err_Invalid_File_Format; 254 FT_Int i; 255 256 257 for ( i = 0; i < ntables; i++ ) 258 if ( tables[i].type == type ) 259 { 260 if ( stream->pos > tables[i].offset ) { 261 error = PCF_Err_Invalid_Stream_Skip; 262 goto Fail; 263 } 264 265 if ( FT_STREAM_SKIP( tables[i].offset - stream->pos ) ) { 266 error = PCF_Err_Invalid_Stream_Skip; 267 goto Fail; 268 } 269 270 *asize = tables[i].size; /* unused - to be removed */ 271 *aformat = tables[i].format; 272 273 return PCF_Err_Ok; 274 } 275 276 Fail: 277 return error; 278 } 279 280 281 static FT_Bool 282 pcf_has_table_type( PCF_Table tables, 283 FT_Int ntables, 284 FT_ULong type ) 285 { 286 FT_Int i; 287 288 289 for ( i = 0; i < ntables; i++ ) 290 if ( tables[i].type == type ) 291 return TRUE; 292 293 return FALSE; 294 } 295 296 297 static 298 const FT_Frame_Field pcf_property_header[] = 299 { 300#undef FT_STRUCTURE 301#define FT_STRUCTURE PCF_ParsePropertyRec 302 303 FT_FRAME_START( 9 ), 304 FT_FRAME_LONG_LE( name ), 305 FT_FRAME_BYTE ( isString ), 306 FT_FRAME_LONG_LE( value ), 307 FT_FRAME_END 308 }; 309 310 311 static 312 const FT_Frame_Field pcf_property_msb_header[] = 313 { 314#undef FT_STRUCTURE 315#define FT_STRUCTURE PCF_ParsePropertyRec 316 317 FT_FRAME_START( 9 ), 318 FT_FRAME_LONG( name ), 319 FT_FRAME_BYTE( isString ), 320 FT_FRAME_LONG( value ), 321 FT_FRAME_END 322 }; 323 324 325 FT_LOCAL_DEF( PCF_Property ) 326 pcf_find_property( PCF_Face face, 327 const FT_String* prop ) 328 { 329 PCF_Property properties = face->properties; 330 FT_Bool found = 0; 331 int i; 332 333 334 for ( i = 0 ; i < face->nprops && !found; i++ ) 335 { 336 if ( !ft_strcmp( properties[i].name, prop ) ) 337 found = 1; 338 } 339 340 if ( found ) 341 return properties + i - 1; 342 else 343 return NULL; 344 } 345 346 347 static FT_Error 348 pcf_get_properties( FT_Stream stream, 349 PCF_Face face ) 350 { 351 PCF_ParseProperty props = 0; 352 PCF_Property properties = 0; 353 FT_Int nprops, i; 354 FT_ULong format, size; 355 FT_Error error; 356 FT_Memory memory = FT_FACE(face)->memory; 357 FT_ULong string_size; 358 FT_String* strings = 0; 359 360 361 error = pcf_seek_to_table_type( stream, 362 face->toc.tables, 363 face->toc.count, 364 PCF_PROPERTIES, 365 &format, 366 &size ); 367 if ( error ) 368 goto Bail; 369 370 if ( FT_READ_ULONG_LE( format ) ) 371 goto Bail; 372 373 FT_TRACE4(( "get_prop: format = %ld\n", format )); 374 375 if ( !PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) ) 376 goto Bail; 377 378 if ( PCF_BYTE_ORDER( format ) == MSBFirst ) 379 (void)FT_READ_ULONG( nprops ); 380 else 381 (void)FT_READ_ULONG_LE( nprops ); 382 if ( error ) 383 goto Bail; 384 385 FT_TRACE4(( "get_prop: nprop = %d\n", nprops )); 386 387 if ( FT_NEW_ARRAY( props, nprops ) ) 388 goto Bail; 389 390 for ( i = 0; i < nprops; i++ ) 391 { 392 if ( PCF_BYTE_ORDER( format ) == MSBFirst ) 393 { 394 if ( FT_STREAM_READ_FIELDS( pcf_property_msb_header, props + i ) ) 395 goto Bail; 396 } 397 else 398 { 399 if ( FT_STREAM_READ_FIELDS( pcf_property_header, props + i ) ) 400 goto Bail; 401 } 402 } 403 404 /* pad the property array */ 405 /* */ 406 /* clever here - nprops is the same as the number of odd-units read, */ 407 /* as only isStringProp are odd length (Keith Packard) */ 408 /* */ 409 if ( nprops & 3 ) 410 { 411 i = 4 - ( nprops & 3 ); 412 FT_Stream_Skip( stream, i ); 413 } 414 415 if ( PCF_BYTE_ORDER( format ) == MSBFirst ) 416 (void)FT_READ_ULONG( string_size ); 417 else 418 (void)FT_READ_ULONG_LE( string_size ); 419 if ( error ) 420 goto Bail; 421 422 FT_TRACE4(( "get_prop: string_size = %ld\n", string_size )); 423 424 if ( FT_NEW_ARRAY( strings, string_size ) ) 425 goto Bail; 426 427 error = FT_Stream_Read( stream, (FT_Byte*)strings, string_size ); 428 if ( error ) 429 goto Bail; 430 431 if ( FT_NEW_ARRAY( properties, nprops ) ) 432 goto Bail; 433 434 for ( i = 0; i < nprops; i++ ) 435 { 436 /* XXX: make atom */ 437 if ( FT_NEW_ARRAY( properties[i].name, 438 ft_strlen( strings + props[i].name ) + 1 ) ) 439 goto Bail; 440 ft_strcpy( properties[i].name,strings + props[i].name ); 441 442 properties[i].isString = props[i].isString; 443 444 if ( props[i].isString ) 445 { 446 if ( FT_NEW_ARRAY( properties[i].value.atom, 447 ft_strlen( strings + props[i].value ) + 1 ) ) 448 goto Bail; 449 ft_strcpy( properties[i].value.atom, strings + props[i].value ); 450 } 451 else 452 properties[i].value.integer = props[i].value; 453 } 454 455 face->properties = properties; 456 face->nprops = nprops; 457 458 FT_FREE( props ); 459 FT_FREE( strings ); 460 461 return PCF_Err_Ok; 462 463 Bail: 464 FT_FREE( props ); 465 FT_FREE( strings ); 466 467 return error; 468 } 469 470 471 static FT_Error 472 pcf_get_metrics( FT_Stream stream, 473 PCF_Face face ) 474 { 475 FT_Error error = PCF_Err_Ok; 476 FT_Memory memory = FT_FACE(face)->memory; 477 FT_ULong format = 0; 478 FT_ULong size = 0; 479 PCF_Metric metrics = 0; 480 int i; 481 int nmetrics = -1; 482 483 484 error = pcf_seek_to_table_type( stream, 485 face->toc.tables, 486 face->toc.count, 487 PCF_METRICS, 488 &format, 489 &size ); 490 if ( error ) 491 return error; 492 493 error = FT_READ_ULONG_LE( format ); 494 495 if ( !PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) && 496 !PCF_FORMAT_MATCH( format, PCF_COMPRESSED_METRICS ) ) 497 return PCF_Err_Invalid_File_Format; 498 499 if ( PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) ) 500 { 501 if ( PCF_BYTE_ORDER( format ) == MSBFirst ) 502 (void)FT_READ_ULONG( nmetrics ); 503 else 504 (void)FT_READ_ULONG_LE( nmetrics ); 505 } 506 else 507 { 508 if ( PCF_BYTE_ORDER( format ) == MSBFirst ) 509 (void)FT_READ_USHORT( nmetrics ); 510 else 511 (void)FT_READ_USHORT_LE( nmetrics ); 512 } 513 if ( error || nmetrics == -1 ) 514 return PCF_Err_Invalid_File_Format; 515 516 face->nmetrics = nmetrics; 517 518 if ( FT_NEW_ARRAY( face->metrics, nmetrics ) ) 519 return PCF_Err_Out_Of_Memory; 520 521 metrics = face->metrics; 522 for ( i = 0; i < nmetrics; i++ ) 523 { 524 pcf_get_metric( stream, format, metrics + i ); 525 526 metrics[i].bits = 0; 527 528 FT_TRACE4(( "%d : width=%d, " 529 "lsb=%d, rsb=%d, ascent=%d, descent=%d, swidth=%d\n", 530 i, 531 ( metrics + i )->characterWidth, 532 ( metrics + i )->leftSideBearing, 533 ( metrics + i )->rightSideBearing, 534 ( metrics + i )->ascent, 535 ( metrics + i )->descent, 536 ( metrics + i )->attributes )); 537 538 if ( error ) 539 break; 540 } 541 542 if ( error ) 543 FT_FREE( face->metrics ); 544 return error; 545 } 546 547 548 static FT_Error 549 pcf_get_bitmaps( FT_Stream stream, 550 PCF_Face face ) 551 { 552 FT_Error error = PCF_Err_Ok; 553 FT_Memory memory = FT_FACE(face)->memory; 554 FT_Long* offsets; 555 FT_Long bitmapSizes[GLYPHPADOPTIONS]; 556 FT_ULong format, size; 557 int nbitmaps, i, sizebitmaps = 0; 558 char* bitmaps; 559 560 561 error = pcf_seek_to_table_type( stream, 562 face->toc.tables, 563 face->toc.count, 564 PCF_BITMAPS, 565 &format, 566 &size ); 567 if ( error ) 568 return error; 569 570 error = FT_Stream_EnterFrame( stream, 8 ); 571 if ( error ) 572 return error; 573 574 format = FT_GET_ULONG_LE(); 575 if ( PCF_BYTE_ORDER( format ) == MSBFirst ) 576 nbitmaps = FT_GET_ULONG(); 577 else 578 nbitmaps = FT_GET_ULONG_LE(); 579 580 FT_Stream_ExitFrame( stream ); 581 582 if ( !PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) ) 583 return PCF_Err_Invalid_File_Format; 584 585 if ( nbitmaps != face->nmetrics ) 586 return PCF_Err_Invalid_File_Format; 587 588 if ( FT_NEW_ARRAY( offsets, nbitmaps ) ) 589 return error; 590 591 for ( i = 0; i < nbitmaps; i++ ) 592 { 593 if ( PCF_BYTE_ORDER( format ) == MSBFirst ) 594 (void)FT_READ_LONG( offsets[i] ); 595 else 596 (void)FT_READ_LONG_LE( offsets[i] ); 597 598 FT_TRACE4(( "bitmap %d is at offset %ld\n", i, offsets[i] )); 599 } 600 if ( error ) 601 goto Bail; 602 603 for ( i = 0; i < GLYPHPADOPTIONS; i++ ) 604 { 605 if ( PCF_BYTE_ORDER( format ) == MSBFirst ) 606 (void)FT_READ_LONG( bitmapSizes[i] ); 607 else 608 (void)FT_READ_LONG_LE( bitmapSizes[i] ); 609 if ( error ) 610 goto Bail; 611 612 sizebitmaps = bitmapSizes[PCF_GLYPH_PAD_INDEX( format )]; 613 614 FT_TRACE4(( "padding %d implies a size of %ld\n", i, bitmapSizes[i] )); 615 } 616 617 FT_TRACE4(( " %d bitmaps, padding index %ld\n", 618 nbitmaps, 619 PCF_GLYPH_PAD_INDEX( format ) )); 620 FT_TRACE4(( "bitmap size = %d\n", sizebitmaps )); 621 622 FT_UNUSED( sizebitmaps ); /* only used for debugging */ 623 624 for ( i = 0; i < nbitmaps; i++ ) 625 face->metrics[i].bits = stream->pos + offsets[i]; 626 627 face->bitmapsFormat = format; 628 629 FT_FREE ( offsets ); 630 return error; 631 632 Bail: 633 FT_FREE ( offsets ); 634 FT_FREE ( bitmaps ); 635 return error; 636 } 637 638 639 static FT_Error 640 pcf_get_encodings( FT_Stream stream, 641 PCF_Face face ) 642 { 643 FT_Error error = PCF_Err_Ok; 644 FT_Memory memory = FT_FACE(face)->memory; 645 FT_ULong format, size; 646 int firstCol, lastCol; 647 int firstRow, lastRow; 648 int nencoding, encodingOffset; 649 int i, j; 650 PCF_Encoding tmpEncoding, encoding = 0; 651 652 653 error = pcf_seek_to_table_type( stream, 654 face->toc.tables, 655 face->toc.count, 656 PCF_BDF_ENCODINGS, 657 &format, 658 &size ); 659 if ( error ) 660 return error; 661 662 error = FT_Stream_EnterFrame( stream, 14 ); 663 if ( error ) 664 return error; 665 666 format = FT_GET_ULONG_LE(); 667 668 if ( PCF_BYTE_ORDER( format ) == MSBFirst ) 669 { 670 firstCol = FT_GET_SHORT(); 671 lastCol = FT_GET_SHORT(); 672 firstRow = FT_GET_SHORT(); 673 lastRow = FT_GET_SHORT(); 674 face->defaultChar = FT_GET_SHORT(); 675 } 676 else 677 { 678 firstCol = FT_GET_SHORT_LE(); 679 lastCol = FT_GET_SHORT_LE(); 680 firstRow = FT_GET_SHORT_LE(); 681 lastRow = FT_GET_SHORT_LE(); 682 face->defaultChar = FT_GET_SHORT_LE(); 683 } 684 685 FT_Stream_ExitFrame( stream ); 686 687 if ( !PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) ) 688 return PCF_Err_Invalid_File_Format; 689 690 FT_TRACE4(( "enc: firstCol %d, lastCol %d, firstRow %d, lastRow %d\n", 691 firstCol, lastCol, firstRow, lastRow )); 692 693 nencoding = ( lastCol - firstCol + 1 ) * ( lastRow - firstRow + 1 ); 694 695 if ( FT_NEW_ARRAY( tmpEncoding, nencoding ) ) 696 return PCF_Err_Out_Of_Memory; 697 698 error = FT_Stream_EnterFrame( stream, 2 * nencoding ); 699 if ( error ) 700 goto Bail; 701 702 for ( i = 0, j = 0 ; i < nencoding; i++ ) 703 { 704 if ( PCF_BYTE_ORDER( format ) == MSBFirst ) 705 encodingOffset = FT_GET_SHORT(); 706 else 707 encodingOffset = FT_GET_SHORT_LE(); 708 709 if ( encodingOffset != -1 ) 710 { 711 tmpEncoding[j].enc = ( ( ( i / ( lastCol - firstCol + 1 ) ) + 712 firstRow ) * 256 ) + 713 ( ( i % ( lastCol - firstCol + 1 ) ) + 714 firstCol ); 715 716 tmpEncoding[j].glyph = (FT_Short)encodingOffset; 717 j++; 718 } 719 720 FT_TRACE4(( "enc n. %d ; Uni %ld ; Glyph %d\n", 721 i, tmpEncoding[j - 1].enc, encodingOffset )); 722 } 723 FT_Stream_ExitFrame( stream ); 724 725 if ( FT_NEW_ARRAY( encoding, j ) ) 726 goto Bail; 727 728 for ( i = 0; i < j; i++ ) 729 { 730 encoding[i].enc = tmpEncoding[i].enc; 731 encoding[i].glyph = tmpEncoding[i].glyph; 732 } 733 734 face->nencodings = j; 735 face->encodings = encoding; 736 FT_FREE( tmpEncoding ); 737 738 return error; 739 740 Bail: 741 FT_FREE( encoding ); 742 FT_FREE( tmpEncoding ); 743 return error; 744 } 745 746 747 static 748 const FT_Frame_Field pcf_accel_header[] = 749 { 750#undef FT_STRUCTURE 751#define FT_STRUCTURE PCF_AccelRec 752 753 FT_FRAME_START( 20 ), 754 FT_FRAME_BYTE ( noOverlap ), 755 FT_FRAME_BYTE ( constantMetrics ), 756 FT_FRAME_BYTE ( terminalFont ), 757 FT_FRAME_BYTE ( constantWidth ), 758 FT_FRAME_BYTE ( inkInside ), 759 FT_FRAME_BYTE ( inkMetrics ), 760 FT_FRAME_BYTE ( drawDirection ), 761 FT_FRAME_SKIP_BYTES( 1 ), 762 FT_FRAME_LONG_LE ( fontAscent ), 763 FT_FRAME_LONG_LE ( fontDescent ), 764 FT_FRAME_LONG_LE ( maxOverlap ), 765 FT_FRAME_END 766 }; 767 768 769 static 770 const FT_Frame_Field pcf_accel_msb_header[] = 771 { 772#undef FT_STRUCTURE 773#define FT_STRUCTURE PCF_AccelRec 774 775 FT_FRAME_START( 20 ), 776 FT_FRAME_BYTE ( noOverlap ), 777 FT_FRAME_BYTE ( constantMetrics ), 778 FT_FRAME_BYTE ( terminalFont ), 779 FT_FRAME_BYTE ( constantWidth ), 780 FT_FRAME_BYTE ( inkInside ), 781 FT_FRAME_BYTE ( inkMetrics ), 782 FT_FRAME_BYTE ( drawDirection ), 783 FT_FRAME_SKIP_BYTES( 1 ), 784 FT_FRAME_LONG ( fontAscent ), 785 FT_FRAME_LONG ( fontDescent ), 786 FT_FRAME_LONG ( maxOverlap ), 787 FT_FRAME_END 788 }; 789 790 791 static FT_Error 792 pcf_get_accel( FT_Stream stream, 793 PCF_Face face, 794 FT_ULong type ) 795 { 796 FT_ULong format, size; 797 FT_Error error = PCF_Err_Ok; 798 PCF_Accel accel = &face->accel; 799 800 801 error = pcf_seek_to_table_type( stream, 802 face->toc.tables, 803 face->toc.count, 804 type, 805 &format, 806 &size ); 807 if ( error ) 808 goto Bail; 809 810 error = FT_READ_ULONG_LE( format ); 811 812 if ( !PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) && 813 !PCF_FORMAT_MATCH( format, PCF_ACCEL_W_INKBOUNDS ) ) 814 goto Bail; 815 816 if ( PCF_BYTE_ORDER( format ) == MSBFirst ) 817 { 818 if ( FT_STREAM_READ_FIELDS( pcf_accel_msb_header, accel ) ) 819 goto Bail; 820 } 821 else 822 { 823 if ( FT_STREAM_READ_FIELDS( pcf_accel_header, accel ) ) 824 goto Bail; 825 } 826 827 error = pcf_get_metric( stream, 828 format & ( ~PCF_FORMAT_MASK ), 829 &(accel->minbounds) ); 830 if ( error ) 831 goto Bail; 832 833 error = pcf_get_metric( stream, 834 format & ( ~PCF_FORMAT_MASK ), 835 &(accel->maxbounds) ); 836 if ( error ) 837 goto Bail; 838 839 if ( PCF_FORMAT_MATCH( format, PCF_ACCEL_W_INKBOUNDS ) ) 840 { 841 error = pcf_get_metric( stream, 842 format & ( ~PCF_FORMAT_MASK ), 843 &(accel->ink_minbounds) ); 844 if ( error ) 845 goto Bail; 846 847 error = pcf_get_metric( stream, 848 format & ( ~PCF_FORMAT_MASK ), 849 &(accel->ink_maxbounds) ); 850 if ( error ) 851 goto Bail; 852 } 853 else 854 { 855 accel->ink_minbounds = accel->minbounds; /* I'm not sure about this */ 856 accel->ink_maxbounds = accel->maxbounds; 857 } 858 return error; 859 860 Bail: 861 return error; 862 } 863 864 865 static FT_Error 866 pcf_interpret_style( PCF_Face pcf ) 867 { 868 FT_Error error = PCF_Err_Ok; 869 FT_Face face = FT_FACE( pcf ); 870 FT_Memory memory = face->memory; 871 872 PCF_Property prop; 873 874 char *istr = NULL, *bstr = NULL; 875 char *sstr = NULL, *astr = NULL; 876 877 int parts = 0, len = 0; 878 879 880 face->style_flags = 0; 881 882 prop = pcf_find_property( pcf, "SLANT" ); 883 if ( prop && prop->isString && 884 ( *(prop->value.atom) == 'O' || *(prop->value.atom) == 'o' || 885 *(prop->value.atom) == 'I' || *(prop->value.atom) == 'i' ) ) 886 { 887 face->style_flags |= FT_STYLE_FLAG_ITALIC; 888 istr = ( *(prop->value.atom) == 'O' || *(prop->value.atom) == 'o' ) 889 ? (char *)"Oblique" 890 : (char *)"Italic"; 891 len += ft_strlen( istr ); 892 parts++; 893 } 894 895 prop = pcf_find_property( pcf, "WEIGHT_NAME" ); 896 if ( prop && prop->isString && 897 ( *(prop->value.atom) == 'B' || *(prop->value.atom) == 'b' ) ) 898 { 899 face->style_flags |= FT_STYLE_FLAG_BOLD; 900 bstr = (char *)"Bold"; 901 len += ft_strlen( bstr ); 902 parts++; 903 } 904 905 prop = pcf_find_property( pcf, "SETWIDTH_NAME" ); 906 if ( prop && prop->isString && 907 *(prop->value.atom) && 908 !( *(prop->value.atom) == 'N' || *(prop->value.atom) == 'n' ) ) 909 { 910 sstr = (char *)(prop->value.atom); 911 len += ft_strlen( sstr ); 912 parts++; 913 } 914 915 prop = pcf_find_property( pcf, "ADD_STYLE_NAME" ); 916 if ( prop && prop->isString && 917 *(prop->value.atom) && 918 !( *(prop->value.atom) == 'N' || *(prop->value.atom) == 'n' ) ) 919 { 920 astr = (char *)(prop->value.atom); 921 len += ft_strlen( astr ); 922 parts++; 923 } 924 925 if ( !parts || !len ) 926 face->style_name = (char *)"Regular"; 927 else 928 { 929 char *style, *s; 930 unsigned int i; 931 932 933 if ( FT_ALLOC( style, len + parts ) ) 934 return error; 935 936 s = style; 937 938 if ( astr ) 939 { 940 ft_strcpy( s, astr ); 941 for ( i = 0; i < ft_strlen( astr ); i++, s++ ) 942 if ( *s == ' ' ) 943 *s = '-'; /* replace spaces with dashes */ 944 *(s++) = ' '; 945 } 946 if ( bstr ) 947 { 948 ft_strcpy( s, bstr ); 949 s += ft_strlen( bstr ); 950 *(s++) = ' '; 951 } 952 if ( istr ) 953 { 954 ft_strcpy( s, istr ); 955 s += ft_strlen( istr ); 956 *(s++) = ' '; 957 } 958 if ( sstr ) 959 { 960 ft_strcpy( s, sstr ); 961 for ( i = 0; i < ft_strlen( sstr ); i++, s++ ) 962 if ( *s == ' ' ) 963 *s = '-'; /* replace spaces with dashes */ 964 *(s++) = ' '; 965 } 966 *(--s) = '\0'; /* overwrite last ' ', terminate the string */ 967 968 face->style_name = style; /* allocated string */ 969 } 970 971 return error; 972 } 973 974 975 FT_LOCAL_DEF( FT_Error ) 976 pcf_load_font( FT_Stream stream, 977 PCF_Face face ) 978 { 979 FT_Error error = PCF_Err_Ok; 980 FT_Memory memory = FT_FACE(face)->memory; 981 FT_Bool hasBDFAccelerators; 982 983 984 error = pcf_read_TOC( stream, face ); 985 if ( error ) 986 goto Exit; 987 988 error = pcf_get_properties( stream, face ); 989 if ( error ) 990 goto Exit; 991 992 /* Use the old accelerators if no BDF accelerators are in the file. */ 993 hasBDFAccelerators = pcf_has_table_type( face->toc.tables, 994 face->toc.count, 995 PCF_BDF_ACCELERATORS ); 996 if ( !hasBDFAccelerators ) 997 { 998 error = pcf_get_accel( stream, face, PCF_ACCELERATORS ); 999 if ( error ) 1000 goto Exit; 1001 } 1002 1003 /* metrics */ 1004 error = pcf_get_metrics( stream, face ); 1005 if ( error ) 1006 goto Exit; 1007 1008 /* bitmaps */ 1009 error = pcf_get_bitmaps( stream, face ); 1010 if ( error ) 1011 goto Exit; 1012 1013 /* encodings */ 1014 error = pcf_get_encodings( stream, face ); 1015 if ( error ) 1016 goto Exit; 1017 1018 /* BDF style accelerators (i.e. bounds based on encoded glyphs) */ 1019 if ( hasBDFAccelerators ) 1020 { 1021 error = pcf_get_accel( stream, face, PCF_BDF_ACCELERATORS ); 1022 if ( error ) 1023 goto Exit; 1024 } 1025 1026 /* XXX: TO DO: inkmetrics and glyph_names are missing */ 1027 1028 /* now construct the face object */ 1029 { 1030 FT_Face root = FT_FACE( face ); 1031 PCF_Property prop; 1032 1033 1034 root->num_faces = 1; 1035 root->face_index = 0; 1036 root->face_flags = FT_FACE_FLAG_FIXED_SIZES | 1037 FT_FACE_FLAG_HORIZONTAL | 1038 FT_FACE_FLAG_FAST_GLYPHS; 1039 1040 if ( face->accel.constantWidth ) 1041 root->face_flags |= FT_FACE_FLAG_FIXED_WIDTH; 1042 1043 if ( ( error = pcf_interpret_style( face ) ) != 0 ) 1044 goto Exit; 1045 1046 prop = pcf_find_property( face, "FAMILY_NAME" ); 1047 if ( prop && prop->isString ) 1048 { 1049 int l = ft_strlen( prop->value.atom ) + 1; 1050 1051 1052 if ( FT_NEW_ARRAY( root->family_name, l ) ) 1053 goto Exit; 1054 ft_strcpy( root->family_name, prop->value.atom ); 1055 } 1056 else 1057 root->family_name = NULL; 1058 1059 /* Note: We shift all glyph indices by +1 since we must 1060 * respect the convention that glyph 0 always corresponds 1061 * to the "missing glyph". 1062 * 1063 * This implies bumping the number of "available" glyphs by 1. 1064 */ 1065 root->num_glyphs = face->nmetrics + 1; 1066 1067 root->num_fixed_sizes = 1; 1068 if ( FT_NEW_ARRAY( root->available_sizes, 1 ) ) 1069 goto Exit; 1070 1071 { 1072 FT_Bitmap_Size* bsize = root->available_sizes; 1073 FT_Short resolution_x = 0, resolution_y = 0; 1074 1075 1076 FT_MEM_ZERO( bsize, sizeof ( FT_Bitmap_Size ) ); 1077 1078 bsize->height = face->accel.fontAscent + face->accel.fontDescent; 1079 1080 prop = pcf_find_property( face, "AVERAGE_WIDTH" ); 1081 if ( prop ) 1082 bsize->width = (FT_Short)( ( prop->value.integer + 5 ) / 10 ); 1083 else 1084 bsize->width = bsize->height * 2/3; 1085 1086 prop = pcf_find_property( face, "POINT_SIZE" ); 1087 if ( prop ) 1088 /* convert from 722.7 decipoints to 72 points per inch */ 1089 bsize->size = 1090 (FT_Pos)( ( prop->value.integer * 64 * 7200 + 36135L ) / 72270L ); 1091 1092 prop = pcf_find_property( face, "PIXEL_SIZE" ); 1093 if ( prop ) 1094 bsize->y_ppem = (FT_Short)prop->value.integer << 6; 1095 1096 prop = pcf_find_property( face, "RESOLUTION_X" ); 1097 if ( prop ) 1098 resolution_x = (FT_Short)prop->value.integer; 1099 1100 prop = pcf_find_property( face, "RESOLUTION_Y" ); 1101 if ( prop ) 1102 resolution_y = (FT_Short)prop->value.integer; 1103 1104 if ( bsize->y_ppem == 0 ) 1105 { 1106 bsize->y_ppem = bsize->size; 1107 if ( resolution_y ) 1108 bsize->y_ppem = bsize->y_ppem * resolution_y / 72; 1109 } 1110 if ( resolution_x && resolution_y ) 1111 bsize->x_ppem = bsize->y_ppem * resolution_x / resolution_y; 1112 else 1113 bsize->x_ppem = bsize->y_ppem; 1114 } 1115 1116 /* set up charset */ 1117 { 1118 PCF_Property charset_registry = 0, charset_encoding = 0; 1119 1120 1121 charset_registry = pcf_find_property( face, "CHARSET_REGISTRY" ); 1122 charset_encoding = pcf_find_property( face, "CHARSET_ENCODING" ); 1123 1124 if ( charset_registry && charset_registry->isString && 1125 charset_encoding && charset_encoding->isString ) 1126 { 1127 if ( FT_NEW_ARRAY( face->charset_encoding, 1128 ft_strlen( charset_encoding->value.atom ) + 1 ) ) 1129 goto Exit; 1130 1131 if ( FT_NEW_ARRAY( face->charset_registry, 1132 ft_strlen( charset_registry->value.atom ) + 1 ) ) 1133 goto Exit; 1134 1135 ft_strcpy( face->charset_registry, charset_registry->value.atom ); 1136 ft_strcpy( face->charset_encoding, charset_encoding->value.atom ); 1137 } 1138 } 1139 } 1140 1141 Exit: 1142 if ( error ) 1143 { 1144 /* this is done to respect the behaviour of the original */ 1145 /* PCF font driver. */ 1146 error = PCF_Err_Invalid_File_Format; 1147 } 1148 1149 return error; 1150 } 1151 1152 1153/* END */ 1154