1 /* pcfread.c 2 3 FreeType font driver for pcf fonts 4 5 Copyright 2000-2010, 2012-2014 by 6 Francesco Zappa Nardelli 7 8 Permission is hereby granted, free of charge, to any person obtaining a copy 9 of this software and associated documentation files (the "Software"), to deal 10 in the Software without restriction, including without limitation the rights 11 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 copies of the Software, and to permit persons to whom the Software is 13 furnished to do so, subject to the following conditions: 14 15 The above copyright notice and this permission notice shall be included in 16 all copies or substantial portions of the Software. 17 18 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 THE 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 "pcfread.h" 36 37 #include "pcferror.h" 38 39 40 /*************************************************************************/ 41 /* */ 42 /* The macro FT_COMPONENT is used in trace mode. It is an implicit */ 43 /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */ 44 /* messages during execution. */ 45 /* */ 46 #undef FT_COMPONENT 47 #define FT_COMPONENT trace_pcfread 48 49 50 #ifdef FT_DEBUG_LEVEL_TRACE 51 static const char* const tableNames[] = 52 { 53 "properties", 54 "accelerators", 55 "metrics", 56 "bitmaps", 57 "ink metrics", 58 "encodings", 59 "swidths", 60 "glyph names", 61 "BDF accelerators" 62 }; 63 #endif 64 65 66 static 67 const FT_Frame_Field pcf_toc_header[] = 68 { 69 #undef FT_STRUCTURE 70 #define FT_STRUCTURE PCF_TocRec 71 72 FT_FRAME_START( 8 ), 73 FT_FRAME_ULONG_LE( version ), 74 FT_FRAME_ULONG_LE( count ), 75 FT_FRAME_END 76 }; 77 78 79 static 80 const FT_Frame_Field pcf_table_header[] = 81 { 82 #undef FT_STRUCTURE 83 #define FT_STRUCTURE PCF_TableRec 84 85 FT_FRAME_START( 16 ), 86 FT_FRAME_ULONG_LE( type ), 87 FT_FRAME_ULONG_LE( format ), 88 FT_FRAME_ULONG_LE( size ), /* rounded up to a multiple of 4 */ 89 FT_FRAME_ULONG_LE( offset ), 90 FT_FRAME_END 91 }; 92 93 94 static FT_Error pcf_read_TOC(FT_Stream stream,PCF_Face face)95 pcf_read_TOC( FT_Stream stream, 96 PCF_Face face ) 97 { 98 FT_Error error; 99 PCF_Toc toc = &face->toc; 100 PCF_Table tables; 101 102 FT_Memory memory = FT_FACE( face )->memory; 103 FT_UInt n; 104 105 FT_ULong size; 106 107 108 if ( FT_STREAM_SEEK( 0 ) || 109 FT_STREAM_READ_FIELDS( pcf_toc_header, toc ) ) 110 return FT_THROW( Cannot_Open_Resource ); 111 112 if ( toc->version != PCF_FILE_VERSION || 113 toc->count == 0 ) 114 return FT_THROW( Invalid_File_Format ); 115 116 if ( stream->size < 16 ) 117 return FT_THROW( Invalid_File_Format ); 118 119 /* we need 16 bytes per TOC entry, */ 120 /* and there can be most 9 tables */ 121 if ( toc->count > ( stream->size >> 4 ) || 122 toc->count > 9 ) 123 { 124 FT_TRACE0(( "pcf_read_TOC: adjusting number of tables" 125 " (from %d to %d)\n", 126 toc->count, 127 FT_MIN( stream->size >> 4, 9 ) )); 128 toc->count = FT_MIN( stream->size >> 4, 9 ); 129 } 130 131 if ( FT_NEW_ARRAY( face->toc.tables, toc->count ) ) 132 return error; 133 134 tables = face->toc.tables; 135 for ( n = 0; n < toc->count; n++ ) 136 { 137 if ( FT_STREAM_READ_FIELDS( pcf_table_header, tables ) ) 138 goto Exit; 139 tables++; 140 } 141 142 /* Sort tables and check for overlaps. Because they are almost */ 143 /* always ordered already, an in-place bubble sort with simultaneous */ 144 /* boundary checking seems appropriate. */ 145 tables = face->toc.tables; 146 147 for ( n = 0; n < toc->count - 1; n++ ) 148 { 149 FT_UInt i, have_change; 150 151 152 have_change = 0; 153 154 for ( i = 0; i < toc->count - 1 - n; i++ ) 155 { 156 PCF_TableRec tmp; 157 158 159 if ( tables[i].offset > tables[i + 1].offset ) 160 { 161 tmp = tables[i]; 162 tables[i] = tables[i + 1]; 163 tables[i + 1] = tmp; 164 165 have_change = 1; 166 } 167 168 if ( ( tables[i].size > tables[i + 1].offset ) || 169 ( tables[i].offset > tables[i + 1].offset - tables[i].size ) ) 170 { 171 error = FT_THROW( Invalid_Offset ); 172 goto Exit; 173 } 174 } 175 176 if ( !have_change ) 177 break; 178 } 179 180 /* 181 * We now check whether the `size' and `offset' values are reasonable: 182 * `offset' + `size' must not exceed the stream size. 183 * 184 * Note, however, that X11's `pcfWriteFont' routine (used by the 185 * `bdftopcf' program to create PDF font files) has two special 186 * features. 187 * 188 * - It always assigns the accelerator table a size of 100 bytes in the 189 * TOC, regardless of its real size, which can vary between 34 and 72 190 * bytes. 191 * 192 * - Due to the way the routine is designed, it ships out the last font 193 * table with its real size, ignoring the TOC's size value. Since 194 * the TOC size values are always rounded up to a multiple of 4, the 195 * difference can be up to three bytes for all tables except the 196 * accelerator table, for which the difference can be as large as 66 197 * bytes. 198 * 199 */ 200 201 tables = face->toc.tables; 202 size = stream->size; 203 204 for ( n = 0; n < toc->count - 1; n++ ) 205 { 206 /* we need two checks to avoid overflow */ 207 if ( ( tables->size > size ) || 208 ( tables->offset > size - tables->size ) ) 209 { 210 error = FT_THROW( Invalid_Table ); 211 goto Exit; 212 } 213 tables++; 214 } 215 216 /* only check `tables->offset' for last table element ... */ 217 if ( ( tables->offset > size ) ) 218 { 219 error = FT_THROW( Invalid_Table ); 220 goto Exit; 221 } 222 /* ... and adjust `tables->size' to the real value if necessary */ 223 if ( tables->size > size - tables->offset ) 224 tables->size = size - tables->offset; 225 226 #ifdef FT_DEBUG_LEVEL_TRACE 227 228 { 229 FT_UInt i, j; 230 const char* name = "?"; 231 232 233 FT_TRACE4(( "pcf_read_TOC:\n" )); 234 235 FT_TRACE4(( " number of tables: %ld\n", face->toc.count )); 236 237 tables = face->toc.tables; 238 for ( i = 0; i < toc->count; i++ ) 239 { 240 for ( j = 0; j < sizeof ( tableNames ) / sizeof ( tableNames[0] ); 241 j++ ) 242 if ( tables[i].type == (FT_UInt)( 1 << j ) ) 243 name = tableNames[j]; 244 245 FT_TRACE4(( " %d: type=%s, format=0x%X," 246 " size=%ld (0x%lX), offset=%ld (0x%lX)\n", 247 i, name, 248 tables[i].format, 249 tables[i].size, tables[i].size, 250 tables[i].offset, tables[i].offset )); 251 } 252 } 253 254 #endif 255 256 return FT_Err_Ok; 257 258 Exit: 259 FT_FREE( face->toc.tables ); 260 return error; 261 } 262 263 264 #define PCF_METRIC_SIZE 12 265 266 static 267 const FT_Frame_Field pcf_metric_header[] = 268 { 269 #undef FT_STRUCTURE 270 #define FT_STRUCTURE PCF_MetricRec 271 272 FT_FRAME_START( PCF_METRIC_SIZE ), 273 FT_FRAME_SHORT_LE( leftSideBearing ), 274 FT_FRAME_SHORT_LE( rightSideBearing ), 275 FT_FRAME_SHORT_LE( characterWidth ), 276 FT_FRAME_SHORT_LE( ascent ), 277 FT_FRAME_SHORT_LE( descent ), 278 FT_FRAME_SHORT_LE( attributes ), 279 FT_FRAME_END 280 }; 281 282 283 static 284 const FT_Frame_Field pcf_metric_msb_header[] = 285 { 286 #undef FT_STRUCTURE 287 #define FT_STRUCTURE PCF_MetricRec 288 289 FT_FRAME_START( PCF_METRIC_SIZE ), 290 FT_FRAME_SHORT( leftSideBearing ), 291 FT_FRAME_SHORT( rightSideBearing ), 292 FT_FRAME_SHORT( characterWidth ), 293 FT_FRAME_SHORT( ascent ), 294 FT_FRAME_SHORT( descent ), 295 FT_FRAME_SHORT( attributes ), 296 FT_FRAME_END 297 }; 298 299 300 #define PCF_COMPRESSED_METRIC_SIZE 5 301 302 static 303 const FT_Frame_Field pcf_compressed_metric_header[] = 304 { 305 #undef FT_STRUCTURE 306 #define FT_STRUCTURE PCF_Compressed_MetricRec 307 308 FT_FRAME_START( PCF_COMPRESSED_METRIC_SIZE ), 309 FT_FRAME_BYTE( leftSideBearing ), 310 FT_FRAME_BYTE( rightSideBearing ), 311 FT_FRAME_BYTE( characterWidth ), 312 FT_FRAME_BYTE( ascent ), 313 FT_FRAME_BYTE( descent ), 314 FT_FRAME_END 315 }; 316 317 318 static FT_Error pcf_get_metric(FT_Stream stream,FT_ULong format,PCF_Metric metric)319 pcf_get_metric( FT_Stream stream, 320 FT_ULong format, 321 PCF_Metric metric ) 322 { 323 FT_Error error = FT_Err_Ok; 324 325 326 if ( PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) ) 327 { 328 const FT_Frame_Field* fields; 329 330 331 /* parsing normal metrics */ 332 fields = ( PCF_BYTE_ORDER( format ) == MSBFirst ) 333 ? pcf_metric_msb_header 334 : pcf_metric_header; 335 336 /* the following sets `error' but doesn't return in case of failure */ 337 (void)FT_STREAM_READ_FIELDS( fields, metric ); 338 } 339 else 340 { 341 PCF_Compressed_MetricRec compr; 342 343 344 /* parsing compressed metrics */ 345 if ( FT_STREAM_READ_FIELDS( pcf_compressed_metric_header, &compr ) ) 346 goto Exit; 347 348 metric->leftSideBearing = (FT_Short)( compr.leftSideBearing - 0x80 ); 349 metric->rightSideBearing = (FT_Short)( compr.rightSideBearing - 0x80 ); 350 metric->characterWidth = (FT_Short)( compr.characterWidth - 0x80 ); 351 metric->ascent = (FT_Short)( compr.ascent - 0x80 ); 352 metric->descent = (FT_Short)( compr.descent - 0x80 ); 353 metric->attributes = 0; 354 } 355 356 FT_TRACE5(( " width=%d," 357 " lsb=%d, rsb=%d," 358 " ascent=%d, descent=%d," 359 " attributes=%d\n", 360 metric->characterWidth, 361 metric->leftSideBearing, 362 metric->rightSideBearing, 363 metric->ascent, 364 metric->descent, 365 metric->attributes )); 366 367 Exit: 368 return error; 369 } 370 371 372 static FT_Error pcf_seek_to_table_type(FT_Stream stream,PCF_Table tables,FT_ULong ntables,FT_ULong type,FT_ULong * aformat,FT_ULong * asize)373 pcf_seek_to_table_type( FT_Stream stream, 374 PCF_Table tables, 375 FT_ULong ntables, /* same as PCF_Toc->count */ 376 FT_ULong type, 377 FT_ULong *aformat, 378 FT_ULong *asize ) 379 { 380 FT_Error error = FT_ERR( Invalid_File_Format ); 381 FT_ULong i; 382 383 384 for ( i = 0; i < ntables; i++ ) 385 if ( tables[i].type == type ) 386 { 387 if ( stream->pos > tables[i].offset ) 388 { 389 error = FT_THROW( Invalid_Stream_Skip ); 390 goto Fail; 391 } 392 393 if ( FT_STREAM_SKIP( tables[i].offset - stream->pos ) ) 394 { 395 error = FT_THROW( Invalid_Stream_Skip ); 396 goto Fail; 397 } 398 399 *asize = tables[i].size; 400 *aformat = tables[i].format; 401 402 return FT_Err_Ok; 403 } 404 405 Fail: 406 *asize = 0; 407 return error; 408 } 409 410 411 static FT_Bool pcf_has_table_type(PCF_Table tables,FT_ULong ntables,FT_ULong type)412 pcf_has_table_type( PCF_Table tables, 413 FT_ULong ntables, /* same as PCF_Toc->count */ 414 FT_ULong type ) 415 { 416 FT_ULong i; 417 418 419 for ( i = 0; i < ntables; i++ ) 420 if ( tables[i].type == type ) 421 return TRUE; 422 423 return FALSE; 424 } 425 426 427 #define PCF_PROPERTY_SIZE 9 428 429 static 430 const FT_Frame_Field pcf_property_header[] = 431 { 432 #undef FT_STRUCTURE 433 #define FT_STRUCTURE PCF_ParsePropertyRec 434 435 FT_FRAME_START( PCF_PROPERTY_SIZE ), 436 FT_FRAME_LONG_LE( name ), 437 FT_FRAME_BYTE ( isString ), 438 FT_FRAME_LONG_LE( value ), 439 FT_FRAME_END 440 }; 441 442 443 static 444 const FT_Frame_Field pcf_property_msb_header[] = 445 { 446 #undef FT_STRUCTURE 447 #define FT_STRUCTURE PCF_ParsePropertyRec 448 449 FT_FRAME_START( PCF_PROPERTY_SIZE ), 450 FT_FRAME_LONG( name ), 451 FT_FRAME_BYTE( isString ), 452 FT_FRAME_LONG( value ), 453 FT_FRAME_END 454 }; 455 456 457 FT_LOCAL_DEF( PCF_Property ) pcf_find_property(PCF_Face face,const FT_String * prop)458 pcf_find_property( PCF_Face face, 459 const FT_String* prop ) 460 { 461 PCF_Property properties = face->properties; 462 FT_Bool found = 0; 463 int i; 464 465 466 for ( i = 0; i < face->nprops && !found; i++ ) 467 { 468 if ( !ft_strcmp( properties[i].name, prop ) ) 469 found = 1; 470 } 471 472 if ( found ) 473 return properties + i - 1; 474 else 475 return NULL; 476 } 477 478 479 static FT_Error pcf_get_properties(FT_Stream stream,PCF_Face face)480 pcf_get_properties( FT_Stream stream, 481 PCF_Face face ) 482 { 483 PCF_ParseProperty props = NULL; 484 PCF_Property properties = NULL; 485 FT_ULong nprops, orig_nprops, i; 486 FT_ULong format, size; 487 FT_Error error; 488 FT_Memory memory = FT_FACE( face )->memory; 489 FT_ULong string_size; 490 FT_String* strings = NULL; 491 492 493 error = pcf_seek_to_table_type( stream, 494 face->toc.tables, 495 face->toc.count, 496 PCF_PROPERTIES, 497 &format, 498 &size ); 499 if ( error ) 500 goto Bail; 501 502 if ( FT_READ_ULONG_LE( format ) ) 503 goto Bail; 504 505 FT_TRACE4(( "pcf_get_properties:\n" 506 " format: 0x%lX (%s)\n", 507 format, 508 PCF_BYTE_ORDER( format ) == MSBFirst ? "MSB" : "LSB" )); 509 510 if ( !PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) ) 511 goto Bail; 512 513 if ( PCF_BYTE_ORDER( format ) == MSBFirst ) 514 (void)FT_READ_ULONG( orig_nprops ); 515 else 516 (void)FT_READ_ULONG_LE( orig_nprops ); 517 if ( error ) 518 goto Bail; 519 520 FT_TRACE4(( " number of properties: %ld\n", orig_nprops )); 521 522 /* rough estimate */ 523 if ( orig_nprops > size / PCF_PROPERTY_SIZE ) 524 { 525 error = FT_THROW( Invalid_Table ); 526 goto Bail; 527 } 528 529 /* as a heuristic limit to avoid excessive allocation in */ 530 /* gzip bombs (i.e., very small, invalid input data that */ 531 /* pretends to expand to an insanely large file) we only */ 532 /* load the first 256 properties */ 533 if ( orig_nprops > 256 ) 534 { 535 FT_TRACE0(( "pcf_get_properties:" 536 " only loading first 256 properties\n" )); 537 nprops = 256; 538 } 539 else 540 nprops = orig_nprops; 541 542 face->nprops = (int)nprops; 543 544 if ( FT_NEW_ARRAY( props, nprops ) ) 545 goto Bail; 546 547 for ( i = 0; i < nprops; i++ ) 548 { 549 if ( PCF_BYTE_ORDER( format ) == MSBFirst ) 550 { 551 if ( FT_STREAM_READ_FIELDS( pcf_property_msb_header, props + i ) ) 552 goto Bail; 553 } 554 else 555 { 556 if ( FT_STREAM_READ_FIELDS( pcf_property_header, props + i ) ) 557 goto Bail; 558 } 559 } 560 561 /* this skip will only work if we really have an extremely large */ 562 /* number of properties; it will fail for fake data, avoiding an */ 563 /* unnecessarily large allocation later on */ 564 if ( FT_STREAM_SKIP( ( orig_nprops - nprops ) * PCF_PROPERTY_SIZE ) ) 565 { 566 error = FT_THROW( Invalid_Stream_Skip ); 567 goto Bail; 568 } 569 570 /* pad the property array */ 571 /* */ 572 /* clever here - nprops is the same as the number of odd-units read, */ 573 /* as only isStringProp are odd length (Keith Packard) */ 574 /* */ 575 if ( orig_nprops & 3 ) 576 { 577 i = 4 - ( orig_nprops & 3 ); 578 if ( FT_STREAM_SKIP( i ) ) 579 { 580 error = FT_THROW( Invalid_Stream_Skip ); 581 goto Bail; 582 } 583 } 584 585 if ( PCF_BYTE_ORDER( format ) == MSBFirst ) 586 (void)FT_READ_ULONG( string_size ); 587 else 588 (void)FT_READ_ULONG_LE( string_size ); 589 if ( error ) 590 goto Bail; 591 592 FT_TRACE4(( " string size: %ld\n", string_size )); 593 594 /* rough estimate */ 595 if ( string_size > size - orig_nprops * PCF_PROPERTY_SIZE ) 596 { 597 error = FT_THROW( Invalid_Table ); 598 goto Bail; 599 } 600 601 /* the strings in the `strings' array are PostScript strings, */ 602 /* which can have a maximum length of 65536 characters each */ 603 if ( string_size > 16777472 ) /* 256 * (65536 + 1) */ 604 { 605 FT_TRACE0(( "pcf_get_properties:" 606 " loading only 16777472 bytes of strings array\n" )); 607 string_size = 16777472; 608 } 609 610 /* allocate one more byte so that we have a final null byte */ 611 if ( FT_NEW_ARRAY( strings, string_size + 1 ) ) 612 goto Bail; 613 614 error = FT_Stream_Read( stream, (FT_Byte*)strings, string_size ); 615 if ( error ) 616 goto Bail; 617 618 if ( FT_NEW_ARRAY( properties, nprops ) ) 619 goto Bail; 620 621 face->properties = properties; 622 623 FT_TRACE4(( "\n" )); 624 for ( i = 0; i < nprops; i++ ) 625 { 626 FT_Long name_offset = props[i].name; 627 628 629 if ( ( name_offset < 0 ) || 630 ( (FT_ULong)name_offset > string_size ) ) 631 { 632 error = FT_THROW( Invalid_Offset ); 633 goto Bail; 634 } 635 636 if ( FT_STRDUP( properties[i].name, strings + name_offset ) ) 637 goto Bail; 638 639 FT_TRACE4(( " %s:", properties[i].name )); 640 641 properties[i].isString = props[i].isString; 642 643 if ( props[i].isString ) 644 { 645 FT_Long value_offset = props[i].value; 646 647 648 if ( ( value_offset < 0 ) || 649 ( (FT_ULong)value_offset > string_size ) ) 650 { 651 error = FT_THROW( Invalid_Offset ); 652 goto Bail; 653 } 654 655 if ( FT_STRDUP( properties[i].value.atom, strings + value_offset ) ) 656 goto Bail; 657 658 FT_TRACE4(( " `%s'\n", properties[i].value.atom )); 659 } 660 else 661 { 662 properties[i].value.l = props[i].value; 663 664 FT_TRACE4(( " %d\n", properties[i].value.l )); 665 } 666 } 667 668 error = FT_Err_Ok; 669 670 Bail: 671 FT_FREE( props ); 672 FT_FREE( strings ); 673 674 return error; 675 } 676 677 678 static FT_Error pcf_get_metrics(FT_Stream stream,PCF_Face face)679 pcf_get_metrics( FT_Stream stream, 680 PCF_Face face ) 681 { 682 FT_Error error; 683 FT_Memory memory = FT_FACE( face )->memory; 684 FT_ULong format, size; 685 PCF_Metric metrics = NULL; 686 FT_ULong nmetrics, orig_nmetrics, i; 687 688 689 error = pcf_seek_to_table_type( stream, 690 face->toc.tables, 691 face->toc.count, 692 PCF_METRICS, 693 &format, 694 &size ); 695 if ( error ) 696 return error; 697 698 if ( FT_READ_ULONG_LE( format ) ) 699 goto Bail; 700 701 FT_TRACE4(( "pcf_get_metrics:\n" 702 " format: 0x%lX (%s, %s)\n", 703 format, 704 PCF_BYTE_ORDER( format ) == MSBFirst ? "MSB" : "LSB", 705 PCF_FORMAT_MATCH( format, PCF_COMPRESSED_METRICS ) ? 706 "compressed" : "uncompressed" )); 707 708 if ( !PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) && 709 !PCF_FORMAT_MATCH( format, PCF_COMPRESSED_METRICS ) ) 710 return FT_THROW( Invalid_File_Format ); 711 712 if ( PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) ) 713 { 714 if ( PCF_BYTE_ORDER( format ) == MSBFirst ) 715 (void)FT_READ_ULONG( orig_nmetrics ); 716 else 717 (void)FT_READ_ULONG_LE( orig_nmetrics ); 718 } 719 else 720 { 721 if ( PCF_BYTE_ORDER( format ) == MSBFirst ) 722 (void)FT_READ_USHORT( orig_nmetrics ); 723 else 724 (void)FT_READ_USHORT_LE( orig_nmetrics ); 725 } 726 if ( error ) 727 return FT_THROW( Invalid_File_Format ); 728 729 FT_TRACE4(( " number of metrics: %ld\n", orig_nmetrics )); 730 731 /* rough estimate */ 732 if ( PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) ) 733 { 734 if ( orig_nmetrics > size / PCF_METRIC_SIZE ) 735 return FT_THROW( Invalid_Table ); 736 } 737 else 738 { 739 if ( orig_nmetrics > size / PCF_COMPRESSED_METRIC_SIZE ) 740 return FT_THROW( Invalid_Table ); 741 } 742 743 if ( !orig_nmetrics ) 744 return FT_THROW( Invalid_Table ); 745 746 /* PCF is a format from ancient times; Unicode was in its */ 747 /* infancy, and widely used two-byte character sets for CJK */ 748 /* scripts (Big 5, GB 2312, JIS X 0208, etc.) did have at most */ 749 /* 15000 characters. Even the more exotic CNS 11643 and CCCII */ 750 /* standards, which were essentially three-byte character sets, */ 751 /* provided less then 65536 assigned characters. */ 752 /* */ 753 /* While technically possible to have a larger number of glyphs */ 754 /* in PCF files, we thus limit the number to 65536. */ 755 if ( orig_nmetrics > 65536 ) 756 { 757 FT_TRACE0(( "pcf_get_metrics:" 758 " only loading first 65536 metrics\n" )); 759 nmetrics = 65536; 760 } 761 else 762 nmetrics = orig_nmetrics; 763 764 face->nmetrics = nmetrics; 765 766 if ( FT_NEW_ARRAY( face->metrics, nmetrics ) ) 767 return error; 768 769 metrics = face->metrics; 770 771 FT_TRACE4(( "\n" )); 772 for ( i = 0; i < nmetrics; i++, metrics++ ) 773 { 774 FT_TRACE5(( " idx %ld:", i )); 775 error = pcf_get_metric( stream, format, metrics ); 776 777 metrics->bits = 0; 778 779 if ( error ) 780 break; 781 782 /* sanity checks -- those values are used in `PCF_Glyph_Load' to */ 783 /* compute a glyph's bitmap dimensions, thus setting them to zero in */ 784 /* case of an error disables this particular glyph only */ 785 if ( metrics->rightSideBearing < metrics->leftSideBearing || 786 metrics->ascent < -metrics->descent ) 787 { 788 metrics->characterWidth = 0; 789 metrics->leftSideBearing = 0; 790 metrics->rightSideBearing = 0; 791 metrics->ascent = 0; 792 metrics->descent = 0; 793 794 FT_TRACE0(( "pcf_get_metrics:" 795 " invalid metrics for glyph %d\n", i )); 796 } 797 } 798 799 if ( error ) 800 FT_FREE( face->metrics ); 801 802 Bail: 803 return error; 804 } 805 806 807 static FT_Error pcf_get_bitmaps(FT_Stream stream,PCF_Face face)808 pcf_get_bitmaps( FT_Stream stream, 809 PCF_Face face ) 810 { 811 FT_Error error; 812 FT_Memory memory = FT_FACE( face )->memory; 813 FT_Long* offsets = NULL; 814 FT_Long bitmapSizes[GLYPHPADOPTIONS]; 815 FT_ULong format, size; 816 FT_ULong nbitmaps, orig_nbitmaps, i, sizebitmaps = 0; 817 818 819 error = pcf_seek_to_table_type( stream, 820 face->toc.tables, 821 face->toc.count, 822 PCF_BITMAPS, 823 &format, 824 &size ); 825 if ( error ) 826 return error; 827 828 error = FT_Stream_EnterFrame( stream, 8 ); 829 if ( error ) 830 return error; 831 832 format = FT_GET_ULONG_LE(); 833 if ( PCF_BYTE_ORDER( format ) == MSBFirst ) 834 orig_nbitmaps = FT_GET_ULONG(); 835 else 836 orig_nbitmaps = FT_GET_ULONG_LE(); 837 838 FT_Stream_ExitFrame( stream ); 839 840 FT_TRACE4(( "pcf_get_bitmaps:\n" 841 " format: 0x%lX\n" 842 " (%s, %s,\n" 843 " padding=%d bit%s, scanning=%d bit%s)\n", 844 format, 845 PCF_BYTE_ORDER( format ) == MSBFirst 846 ? "most significant byte first" 847 : "least significant byte first", 848 PCF_BIT_ORDER( format ) == MSBFirst 849 ? "most significant bit first" 850 : "least significant bit first", 851 8 << PCF_GLYPH_PAD_INDEX( format ), 852 ( 8 << PCF_GLYPH_PAD_INDEX( format ) ) == 1 ? "" : "s", 853 8 << PCF_SCAN_UNIT_INDEX( format ), 854 ( 8 << PCF_SCAN_UNIT_INDEX( format ) ) == 1 ? "" : "s" )); 855 856 if ( !PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) ) 857 return FT_THROW( Invalid_File_Format ); 858 859 FT_TRACE4(( " number of bitmaps: %ld\n", orig_nbitmaps )); 860 861 /* see comment in `pcf_get_metrics' */ 862 if ( orig_nbitmaps > 65536 ) 863 { 864 FT_TRACE0(( "pcf_get_bitmaps:" 865 " only loading first 65536 bitmaps\n" )); 866 nbitmaps = 65536; 867 } 868 else 869 nbitmaps = orig_nbitmaps; 870 871 if ( nbitmaps != face->nmetrics ) 872 return FT_THROW( Invalid_File_Format ); 873 874 if ( FT_NEW_ARRAY( offsets, nbitmaps ) ) 875 return error; 876 877 FT_TRACE5(( "\n" )); 878 for ( i = 0; i < nbitmaps; i++ ) 879 { 880 if ( PCF_BYTE_ORDER( format ) == MSBFirst ) 881 (void)FT_READ_LONG( offsets[i] ); 882 else 883 (void)FT_READ_LONG_LE( offsets[i] ); 884 885 FT_TRACE5(( " bitmap %ld: offset %ld (0x%lX)\n", 886 i, offsets[i], offsets[i] )); 887 } 888 if ( error ) 889 goto Bail; 890 891 for ( i = 0; i < GLYPHPADOPTIONS; i++ ) 892 { 893 if ( PCF_BYTE_ORDER( format ) == MSBFirst ) 894 (void)FT_READ_LONG( bitmapSizes[i] ); 895 else 896 (void)FT_READ_LONG_LE( bitmapSizes[i] ); 897 if ( error ) 898 goto Bail; 899 900 sizebitmaps = (FT_ULong)bitmapSizes[PCF_GLYPH_PAD_INDEX( format )]; 901 902 FT_TRACE4(( " %ld-bit padding implies a size of %ld\n", 903 8 << i, bitmapSizes[i] )); 904 } 905 906 FT_TRACE4(( " %ld bitmaps, using %ld-bit padding\n", 907 nbitmaps, 908 8 << PCF_GLYPH_PAD_INDEX( format ) )); 909 FT_TRACE4(( " bitmap size: %ld\n", sizebitmaps )); 910 911 FT_UNUSED( sizebitmaps ); /* only used for debugging */ 912 913 /* right now, we only check the bitmap offsets; */ 914 /* actual bitmaps are only loaded on demand */ 915 for ( i = 0; i < nbitmaps; i++ ) 916 { 917 /* rough estimate */ 918 if ( ( offsets[i] < 0 ) || 919 ( (FT_ULong)offsets[i] > size ) ) 920 { 921 FT_TRACE0(( "pcf_get_bitmaps:" 922 " invalid offset to bitmap data of glyph %ld\n", i )); 923 } 924 else 925 face->metrics[i].bits = stream->pos + (FT_ULong)offsets[i]; 926 } 927 928 face->bitmapsFormat = format; 929 930 Bail: 931 FT_FREE( offsets ); 932 return error; 933 } 934 935 936 static FT_Error pcf_get_encodings(FT_Stream stream,PCF_Face face)937 pcf_get_encodings( FT_Stream stream, 938 PCF_Face face ) 939 { 940 FT_Error error; 941 FT_Memory memory = FT_FACE( face )->memory; 942 FT_ULong format, size; 943 int firstCol, lastCol; 944 int firstRow, lastRow; 945 FT_ULong nencoding; 946 FT_UShort encodingOffset; 947 int i, j; 948 FT_ULong k; 949 PCF_Encoding encoding = NULL; 950 951 952 error = pcf_seek_to_table_type( stream, 953 face->toc.tables, 954 face->toc.count, 955 PCF_BDF_ENCODINGS, 956 &format, 957 &size ); 958 if ( error ) 959 return error; 960 961 error = FT_Stream_EnterFrame( stream, 14 ); 962 if ( error ) 963 return error; 964 965 format = FT_GET_ULONG_LE(); 966 967 if ( PCF_BYTE_ORDER( format ) == MSBFirst ) 968 { 969 firstCol = FT_GET_SHORT(); 970 lastCol = FT_GET_SHORT(); 971 firstRow = FT_GET_SHORT(); 972 lastRow = FT_GET_SHORT(); 973 face->defaultChar = FT_GET_SHORT(); 974 } 975 else 976 { 977 firstCol = FT_GET_SHORT_LE(); 978 lastCol = FT_GET_SHORT_LE(); 979 firstRow = FT_GET_SHORT_LE(); 980 lastRow = FT_GET_SHORT_LE(); 981 face->defaultChar = FT_GET_SHORT_LE(); 982 } 983 984 FT_Stream_ExitFrame( stream ); 985 986 FT_TRACE4(( "pcf_get_encodings:\n" 987 " format: 0x%lX (%s)\n", 988 format, 989 PCF_BYTE_ORDER( format ) == MSBFirst ? "MSB" : "LSB" )); 990 991 if ( !PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) ) 992 return FT_THROW( Invalid_File_Format ); 993 994 FT_TRACE4(( " firstCol 0x%X, lastCol 0x%X\n" 995 " firstRow 0x%X, lastRow 0x%X\n", 996 firstCol, lastCol, 997 firstRow, lastRow )); 998 999 /* sanity checks; we limit numbers of rows and columns to 256 */ 1000 if ( firstCol < 0 || 1001 firstCol > lastCol || 1002 lastCol > 0xFF || 1003 firstRow < 0 || 1004 firstRow > lastRow || 1005 lastRow > 0xFF ) 1006 return FT_THROW( Invalid_Table ); 1007 1008 nencoding = (FT_ULong)( lastCol - firstCol + 1 ) * 1009 (FT_ULong)( lastRow - firstRow + 1 ); 1010 1011 if ( FT_NEW_ARRAY( encoding, nencoding ) ) 1012 return error; 1013 1014 error = FT_Stream_EnterFrame( stream, 2 * nencoding ); 1015 if ( error ) 1016 goto Bail; 1017 1018 FT_TRACE5(( "\n" )); 1019 1020 k = 0; 1021 for ( i = firstRow; i <= lastRow; i++ ) 1022 { 1023 for ( j = firstCol; j <= lastCol; j++ ) 1024 { 1025 /* X11's reference implementation uses the equivalent to */ 1026 /* `FT_GET_SHORT', however PCF fonts with more than 32768 */ 1027 /* characters (e.g. `unifont.pcf') clearly show that an */ 1028 /* unsigned value is needed. */ 1029 if ( PCF_BYTE_ORDER( format ) == MSBFirst ) 1030 encodingOffset = FT_GET_USHORT(); 1031 else 1032 encodingOffset = FT_GET_USHORT_LE(); 1033 1034 if ( encodingOffset != 0xFFFFU ) 1035 { 1036 encoding[k].enc = i * 256 + j; 1037 encoding[k].glyph = encodingOffset; 1038 1039 FT_TRACE5(( " code %d (0x%04X): idx %d\n", 1040 encoding[k].enc, encoding[k].enc, encoding[k].glyph )); 1041 1042 k++; 1043 } 1044 } 1045 } 1046 FT_Stream_ExitFrame( stream ); 1047 1048 if ( FT_RENEW_ARRAY( encoding, nencoding, k ) ) 1049 goto Bail; 1050 1051 face->nencodings = k; 1052 face->encodings = encoding; 1053 1054 return error; 1055 1056 Bail: 1057 FT_FREE( encoding ); 1058 return error; 1059 } 1060 1061 1062 static 1063 const FT_Frame_Field pcf_accel_header[] = 1064 { 1065 #undef FT_STRUCTURE 1066 #define FT_STRUCTURE PCF_AccelRec 1067 1068 FT_FRAME_START( 20 ), 1069 FT_FRAME_BYTE ( noOverlap ), 1070 FT_FRAME_BYTE ( constantMetrics ), 1071 FT_FRAME_BYTE ( terminalFont ), 1072 FT_FRAME_BYTE ( constantWidth ), 1073 FT_FRAME_BYTE ( inkInside ), 1074 FT_FRAME_BYTE ( inkMetrics ), 1075 FT_FRAME_BYTE ( drawDirection ), 1076 FT_FRAME_SKIP_BYTES( 1 ), 1077 FT_FRAME_LONG_LE ( fontAscent ), 1078 FT_FRAME_LONG_LE ( fontDescent ), 1079 FT_FRAME_LONG_LE ( maxOverlap ), 1080 FT_FRAME_END 1081 }; 1082 1083 1084 static 1085 const FT_Frame_Field pcf_accel_msb_header[] = 1086 { 1087 #undef FT_STRUCTURE 1088 #define FT_STRUCTURE PCF_AccelRec 1089 1090 FT_FRAME_START( 20 ), 1091 FT_FRAME_BYTE ( noOverlap ), 1092 FT_FRAME_BYTE ( constantMetrics ), 1093 FT_FRAME_BYTE ( terminalFont ), 1094 FT_FRAME_BYTE ( constantWidth ), 1095 FT_FRAME_BYTE ( inkInside ), 1096 FT_FRAME_BYTE ( inkMetrics ), 1097 FT_FRAME_BYTE ( drawDirection ), 1098 FT_FRAME_SKIP_BYTES( 1 ), 1099 FT_FRAME_LONG ( fontAscent ), 1100 FT_FRAME_LONG ( fontDescent ), 1101 FT_FRAME_LONG ( maxOverlap ), 1102 FT_FRAME_END 1103 }; 1104 1105 1106 static FT_Error pcf_get_accel(FT_Stream stream,PCF_Face face,FT_ULong type)1107 pcf_get_accel( FT_Stream stream, 1108 PCF_Face face, 1109 FT_ULong type ) 1110 { 1111 FT_ULong format, size; 1112 FT_Error error; 1113 PCF_Accel accel = &face->accel; 1114 1115 1116 error = pcf_seek_to_table_type( stream, 1117 face->toc.tables, 1118 face->toc.count, 1119 type, 1120 &format, 1121 &size ); 1122 if ( error ) 1123 goto Bail; 1124 1125 if ( FT_READ_ULONG_LE( format ) ) 1126 goto Bail; 1127 1128 FT_TRACE4(( "pcf_get_accel%s:\n" 1129 " format: 0x%lX (%s, %s)\n", 1130 type == PCF_BDF_ACCELERATORS ? " (getting BDF accelerators)" 1131 : "", 1132 format, 1133 PCF_BYTE_ORDER( format ) == MSBFirst ? "MSB" : "LSB", 1134 PCF_FORMAT_MATCH( format, PCF_ACCEL_W_INKBOUNDS ) ? 1135 "accelerated" : "not accelerated" )); 1136 1137 if ( !PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) && 1138 !PCF_FORMAT_MATCH( format, PCF_ACCEL_W_INKBOUNDS ) ) 1139 goto Bail; 1140 1141 if ( PCF_BYTE_ORDER( format ) == MSBFirst ) 1142 { 1143 if ( FT_STREAM_READ_FIELDS( pcf_accel_msb_header, accel ) ) 1144 goto Bail; 1145 } 1146 else 1147 { 1148 if ( FT_STREAM_READ_FIELDS( pcf_accel_header, accel ) ) 1149 goto Bail; 1150 } 1151 1152 FT_TRACE5(( " noOverlap=%s, constantMetrics=%s," 1153 " terminalFont=%s, constantWidth=%s\n" 1154 " inkInside=%s, inkMetrics=%s, drawDirection=%s\n" 1155 " fontAscent=%ld, fontDescent=%ld, maxOverlap=%ld\n", 1156 accel->noOverlap ? "yes" : "no", 1157 accel->constantMetrics ? "yes" : "no", 1158 accel->terminalFont ? "yes" : "no", 1159 accel->constantWidth ? "yes" : "no", 1160 accel->inkInside ? "yes" : "no", 1161 accel->inkMetrics ? "yes" : "no", 1162 accel->drawDirection ? "RTL" : "LTR", 1163 accel->fontAscent, 1164 accel->fontDescent, 1165 accel->maxOverlap )); 1166 1167 /* sanity checks */ 1168 if ( FT_ABS( accel->fontAscent ) > 0x7FFF ) 1169 { 1170 accel->fontAscent = accel->fontAscent < 0 ? -0x7FFF : 0x7FFF; 1171 FT_TRACE0(( "pfc_get_accel: clamping font ascent to value %d\n", 1172 accel->fontAscent )); 1173 } 1174 if ( FT_ABS( accel->fontDescent ) > 0x7FFF ) 1175 { 1176 accel->fontDescent = accel->fontDescent < 0 ? -0x7FFF : 0x7FFF; 1177 FT_TRACE0(( "pfc_get_accel: clamping font descent to value %d\n", 1178 accel->fontDescent )); 1179 } 1180 1181 FT_TRACE5(( " minbounds:" )); 1182 error = pcf_get_metric( stream, 1183 format & ( ~PCF_FORMAT_MASK ), 1184 &(accel->minbounds) ); 1185 if ( error ) 1186 goto Bail; 1187 1188 FT_TRACE5(( " maxbounds:" )); 1189 error = pcf_get_metric( stream, 1190 format & ( ~PCF_FORMAT_MASK ), 1191 &(accel->maxbounds) ); 1192 if ( error ) 1193 goto Bail; 1194 1195 if ( PCF_FORMAT_MATCH( format, PCF_ACCEL_W_INKBOUNDS ) ) 1196 { 1197 FT_TRACE5(( " ink minbounds:" )); 1198 error = pcf_get_metric( stream, 1199 format & ( ~PCF_FORMAT_MASK ), 1200 &(accel->ink_minbounds) ); 1201 if ( error ) 1202 goto Bail; 1203 1204 FT_TRACE5(( " ink maxbounds:" )); 1205 error = pcf_get_metric( stream, 1206 format & ( ~PCF_FORMAT_MASK ), 1207 &(accel->ink_maxbounds) ); 1208 if ( error ) 1209 goto Bail; 1210 } 1211 else 1212 { 1213 accel->ink_minbounds = accel->minbounds; 1214 accel->ink_maxbounds = accel->maxbounds; 1215 } 1216 1217 Bail: 1218 return error; 1219 } 1220 1221 1222 static FT_Error pcf_interpret_style(PCF_Face pcf)1223 pcf_interpret_style( PCF_Face pcf ) 1224 { 1225 FT_Error error = FT_Err_Ok; 1226 FT_Face face = FT_FACE( pcf ); 1227 FT_Memory memory = face->memory; 1228 1229 PCF_Property prop; 1230 1231 size_t nn, len; 1232 char* strings[4] = { NULL, NULL, NULL, NULL }; 1233 size_t lengths[4]; 1234 1235 1236 face->style_flags = 0; 1237 1238 prop = pcf_find_property( pcf, "SLANT" ); 1239 if ( prop && prop->isString && 1240 ( *(prop->value.atom) == 'O' || *(prop->value.atom) == 'o' || 1241 *(prop->value.atom) == 'I' || *(prop->value.atom) == 'i' ) ) 1242 { 1243 face->style_flags |= FT_STYLE_FLAG_ITALIC; 1244 strings[2] = ( *(prop->value.atom) == 'O' || 1245 *(prop->value.atom) == 'o' ) ? (char *)"Oblique" 1246 : (char *)"Italic"; 1247 } 1248 1249 prop = pcf_find_property( pcf, "WEIGHT_NAME" ); 1250 if ( prop && prop->isString && 1251 ( *(prop->value.atom) == 'B' || *(prop->value.atom) == 'b' ) ) 1252 { 1253 face->style_flags |= FT_STYLE_FLAG_BOLD; 1254 strings[1] = (char*)"Bold"; 1255 } 1256 1257 prop = pcf_find_property( pcf, "SETWIDTH_NAME" ); 1258 if ( prop && prop->isString && 1259 *(prop->value.atom) && 1260 !( *(prop->value.atom) == 'N' || *(prop->value.atom) == 'n' ) ) 1261 strings[3] = (char*)( prop->value.atom ); 1262 1263 prop = pcf_find_property( pcf, "ADD_STYLE_NAME" ); 1264 if ( prop && prop->isString && 1265 *(prop->value.atom) && 1266 !( *(prop->value.atom) == 'N' || *(prop->value.atom) == 'n' ) ) 1267 strings[0] = (char*)( prop->value.atom ); 1268 1269 for ( len = 0, nn = 0; nn < 4; nn++ ) 1270 { 1271 lengths[nn] = 0; 1272 if ( strings[nn] ) 1273 { 1274 lengths[nn] = ft_strlen( strings[nn] ); 1275 len += lengths[nn] + 1; 1276 } 1277 } 1278 1279 if ( len == 0 ) 1280 { 1281 strings[0] = (char*)"Regular"; 1282 lengths[0] = ft_strlen( strings[0] ); 1283 len = lengths[0] + 1; 1284 } 1285 1286 { 1287 char* s; 1288 1289 1290 if ( FT_ALLOC( face->style_name, len ) ) 1291 return error; 1292 1293 s = face->style_name; 1294 1295 for ( nn = 0; nn < 4; nn++ ) 1296 { 1297 char* src = strings[nn]; 1298 1299 1300 len = lengths[nn]; 1301 1302 if ( !src ) 1303 continue; 1304 1305 /* separate elements with a space */ 1306 if ( s != face->style_name ) 1307 *s++ = ' '; 1308 1309 ft_memcpy( s, src, len ); 1310 1311 /* need to convert spaces to dashes for */ 1312 /* add_style_name and setwidth_name */ 1313 if ( nn == 0 || nn == 3 ) 1314 { 1315 size_t mm; 1316 1317 1318 for ( mm = 0; mm < len; mm++ ) 1319 if ( s[mm] == ' ' ) 1320 s[mm] = '-'; 1321 } 1322 1323 s += len; 1324 } 1325 *s = 0; 1326 } 1327 1328 return error; 1329 } 1330 1331 1332 FT_LOCAL_DEF( FT_Error ) pcf_load_font(FT_Stream stream,PCF_Face face,FT_Long face_index)1333 pcf_load_font( FT_Stream stream, 1334 PCF_Face face, 1335 FT_Long face_index ) 1336 { 1337 FT_Face root = FT_FACE( face ); 1338 FT_Error error; 1339 FT_Memory memory = FT_FACE( face )->memory; 1340 FT_Bool hasBDFAccelerators; 1341 1342 1343 error = pcf_read_TOC( stream, face ); 1344 if ( error ) 1345 goto Exit; 1346 1347 root->num_faces = 1; 1348 root->face_index = 0; 1349 1350 /* If we are performing a simple font format check, exit immediately. */ 1351 if ( face_index < 0 ) 1352 return FT_Err_Ok; 1353 1354 error = pcf_get_properties( stream, face ); 1355 if ( error ) 1356 goto Exit; 1357 1358 /* Use the old accelerators if no BDF accelerators are in the file. */ 1359 hasBDFAccelerators = pcf_has_table_type( face->toc.tables, 1360 face->toc.count, 1361 PCF_BDF_ACCELERATORS ); 1362 if ( !hasBDFAccelerators ) 1363 { 1364 error = pcf_get_accel( stream, face, PCF_ACCELERATORS ); 1365 if ( error ) 1366 goto Exit; 1367 } 1368 1369 /* metrics */ 1370 error = pcf_get_metrics( stream, face ); 1371 if ( error ) 1372 goto Exit; 1373 1374 /* bitmaps */ 1375 error = pcf_get_bitmaps( stream, face ); 1376 if ( error ) 1377 goto Exit; 1378 1379 /* encodings */ 1380 error = pcf_get_encodings( stream, face ); 1381 if ( error ) 1382 goto Exit; 1383 1384 /* BDF style accelerators (i.e. bounds based on encoded glyphs) */ 1385 if ( hasBDFAccelerators ) 1386 { 1387 error = pcf_get_accel( stream, face, PCF_BDF_ACCELERATORS ); 1388 if ( error ) 1389 goto Exit; 1390 } 1391 1392 /* XXX: TO DO: inkmetrics and glyph_names are missing */ 1393 1394 /* now construct the face object */ 1395 { 1396 PCF_Property prop; 1397 1398 1399 root->face_flags |= FT_FACE_FLAG_FIXED_SIZES | 1400 FT_FACE_FLAG_HORIZONTAL | 1401 FT_FACE_FLAG_FAST_GLYPHS; 1402 1403 if ( face->accel.constantWidth ) 1404 root->face_flags |= FT_FACE_FLAG_FIXED_WIDTH; 1405 1406 if ( FT_SET_ERROR( pcf_interpret_style( face ) ) ) 1407 goto Exit; 1408 1409 prop = pcf_find_property( face, "FAMILY_NAME" ); 1410 if ( prop && prop->isString ) 1411 { 1412 1413 #ifdef PCF_CONFIG_OPTION_LONG_FAMILY_NAMES 1414 1415 PCF_Driver driver = (PCF_Driver)FT_FACE_DRIVER( face ); 1416 1417 1418 if ( !driver->no_long_family_names ) 1419 { 1420 /* Prepend the foundry name plus a space to the family name. */ 1421 /* There are many fonts just called `Fixed' which look */ 1422 /* completely different, and which have nothing to do with each */ 1423 /* other. When selecting `Fixed' in KDE or Gnome one gets */ 1424 /* results that appear rather random, the style changes often if */ 1425 /* one changes the size and one cannot select some fonts at all. */ 1426 /* */ 1427 /* We also check whether we have `wide' characters; all put */ 1428 /* together, we get family names like `Sony Fixed' or `Misc */ 1429 /* Fixed Wide'. */ 1430 1431 PCF_Property foundry_prop, point_size_prop, average_width_prop; 1432 1433 int l = ft_strlen( prop->value.atom ) + 1; 1434 int wide = 0; 1435 1436 1437 foundry_prop = pcf_find_property( face, "FOUNDRY" ); 1438 point_size_prop = pcf_find_property( face, "POINT_SIZE" ); 1439 average_width_prop = pcf_find_property( face, "AVERAGE_WIDTH" ); 1440 1441 if ( point_size_prop && average_width_prop ) 1442 { 1443 if ( average_width_prop->value.l >= point_size_prop->value.l ) 1444 { 1445 /* This font is at least square shaped or even wider */ 1446 wide = 1; 1447 l += ft_strlen( " Wide" ); 1448 } 1449 } 1450 1451 if ( foundry_prop && foundry_prop->isString ) 1452 { 1453 l += ft_strlen( foundry_prop->value.atom ) + 1; 1454 1455 if ( FT_NEW_ARRAY( root->family_name, l ) ) 1456 goto Exit; 1457 1458 ft_strcpy( root->family_name, foundry_prop->value.atom ); 1459 ft_strcat( root->family_name, " " ); 1460 ft_strcat( root->family_name, prop->value.atom ); 1461 } 1462 else 1463 { 1464 if ( FT_NEW_ARRAY( root->family_name, l ) ) 1465 goto Exit; 1466 1467 ft_strcpy( root->family_name, prop->value.atom ); 1468 } 1469 1470 if ( wide ) 1471 ft_strcat( root->family_name, " Wide" ); 1472 } 1473 else 1474 1475 #endif /* PCF_CONFIG_OPTION_LONG_FAMILY_NAMES */ 1476 1477 { 1478 if ( FT_STRDUP( root->family_name, prop->value.atom ) ) 1479 goto Exit; 1480 } 1481 } 1482 else 1483 root->family_name = NULL; 1484 1485 /* 1486 * Note: We shift all glyph indices by +1 since we must 1487 * respect the convention that glyph 0 always corresponds 1488 * to the `missing glyph'. 1489 * 1490 * This implies bumping the number of `available' glyphs by 1. 1491 */ 1492 root->num_glyphs = (FT_Long)( face->nmetrics + 1 ); 1493 1494 root->num_fixed_sizes = 1; 1495 if ( FT_NEW_ARRAY( root->available_sizes, 1 ) ) 1496 goto Exit; 1497 1498 { 1499 FT_Bitmap_Size* bsize = root->available_sizes; 1500 FT_Short resolution_x = 0, resolution_y = 0; 1501 1502 1503 FT_ZERO( bsize ); 1504 1505 /* for simplicity, we take absolute values of integer properties */ 1506 1507 #if 0 1508 bsize->height = face->accel.maxbounds.ascent << 6; 1509 #endif 1510 1511 #ifdef FT_DEBUG_LEVEL_TRACE 1512 if ( face->accel.fontAscent + face->accel.fontDescent < 0 ) 1513 FT_TRACE0(( "pcf_load_font: negative height\n" )); 1514 #endif 1515 if ( FT_ABS( face->accel.fontAscent + 1516 face->accel.fontDescent ) > 0x7FFF ) 1517 { 1518 bsize->height = 0x7FFF; 1519 FT_TRACE0(( "pcf_load_font: clamping height to value %d\n", 1520 bsize->height )); 1521 } 1522 else 1523 bsize->height = FT_ABS( (FT_Short)( face->accel.fontAscent + 1524 face->accel.fontDescent ) ); 1525 1526 prop = pcf_find_property( face, "AVERAGE_WIDTH" ); 1527 if ( prop ) 1528 { 1529 #ifdef FT_DEBUG_LEVEL_TRACE 1530 if ( prop->value.l < 0 ) 1531 FT_TRACE0(( "pcf_load_font: negative average width\n" )); 1532 #endif 1533 if ( ( FT_ABS( prop->value.l ) > 0x7FFFL * 10 - 5 ) ) 1534 { 1535 bsize->width = 0x7FFF; 1536 FT_TRACE0(( "pcf_load_font: clamping average width to value %d\n", 1537 bsize->width )); 1538 } 1539 else 1540 bsize->width = FT_ABS( (FT_Short)( ( prop->value.l + 5 ) / 10 ) ); 1541 } 1542 else 1543 { 1544 /* this is a heuristical value */ 1545 bsize->width = (FT_Short)FT_MulDiv( bsize->height, 2, 3 ); 1546 } 1547 1548 prop = pcf_find_property( face, "POINT_SIZE" ); 1549 if ( prop ) 1550 { 1551 #ifdef FT_DEBUG_LEVEL_TRACE 1552 if ( prop->value.l < 0 ) 1553 FT_TRACE0(( "pcf_load_font: negative point size\n" )); 1554 #endif 1555 /* convert from 722.7 decipoints to 72 points per inch */ 1556 if ( FT_ABS( prop->value.l ) > 0x504C2L ) /* 0x7FFF * 72270/7200 */ 1557 { 1558 bsize->size = 0x7FFF; 1559 FT_TRACE0(( "pcf_load_font: clamping point size to value %d\n", 1560 bsize->size )); 1561 } 1562 else 1563 bsize->size = FT_MulDiv( FT_ABS( prop->value.l ), 1564 64 * 7200, 1565 72270L ); 1566 } 1567 1568 prop = pcf_find_property( face, "PIXEL_SIZE" ); 1569 if ( prop ) 1570 { 1571 #ifdef FT_DEBUG_LEVEL_TRACE 1572 if ( prop->value.l < 0 ) 1573 FT_TRACE0(( "pcf_load_font: negative pixel size\n" )); 1574 #endif 1575 if ( FT_ABS( prop->value.l ) > 0x7FFF ) 1576 { 1577 bsize->y_ppem = 0x7FFF << 6; 1578 FT_TRACE0(( "pcf_load_font: clamping pixel size to value %d\n", 1579 bsize->y_ppem )); 1580 } 1581 else 1582 bsize->y_ppem = FT_ABS( (FT_Short)prop->value.l ) << 6; 1583 } 1584 1585 prop = pcf_find_property( face, "RESOLUTION_X" ); 1586 if ( prop ) 1587 { 1588 #ifdef FT_DEBUG_LEVEL_TRACE 1589 if ( prop->value.l < 0 ) 1590 FT_TRACE0(( "pcf_load_font: negative X resolution\n" )); 1591 #endif 1592 if ( FT_ABS( prop->value.l ) > 0x7FFF ) 1593 { 1594 resolution_x = 0x7FFF; 1595 FT_TRACE0(( "pcf_load_font: clamping X resolution to value %d\n", 1596 resolution_x )); 1597 } 1598 else 1599 resolution_x = FT_ABS( (FT_Short)prop->value.l ); 1600 } 1601 1602 prop = pcf_find_property( face, "RESOLUTION_Y" ); 1603 if ( prop ) 1604 { 1605 #ifdef FT_DEBUG_LEVEL_TRACE 1606 if ( prop->value.l < 0 ) 1607 FT_TRACE0(( "pcf_load_font: negative Y resolution\n" )); 1608 #endif 1609 if ( FT_ABS( prop->value.l ) > 0x7FFF ) 1610 { 1611 resolution_y = 0x7FFF; 1612 FT_TRACE0(( "pcf_load_font: clamping Y resolution to value %d\n", 1613 resolution_y )); 1614 } 1615 else 1616 resolution_y = FT_ABS( (FT_Short)prop->value.l ); 1617 } 1618 1619 if ( bsize->y_ppem == 0 ) 1620 { 1621 bsize->y_ppem = bsize->size; 1622 if ( resolution_y ) 1623 bsize->y_ppem = FT_MulDiv( bsize->y_ppem, resolution_y, 72 ); 1624 } 1625 if ( resolution_x && resolution_y ) 1626 bsize->x_ppem = FT_MulDiv( bsize->y_ppem, 1627 resolution_x, 1628 resolution_y ); 1629 else 1630 bsize->x_ppem = bsize->y_ppem; 1631 } 1632 1633 /* set up charset */ 1634 { 1635 PCF_Property charset_registry, charset_encoding; 1636 1637 1638 charset_registry = pcf_find_property( face, "CHARSET_REGISTRY" ); 1639 charset_encoding = pcf_find_property( face, "CHARSET_ENCODING" ); 1640 1641 if ( charset_registry && charset_registry->isString && 1642 charset_encoding && charset_encoding->isString ) 1643 { 1644 if ( FT_STRDUP( face->charset_encoding, 1645 charset_encoding->value.atom ) || 1646 FT_STRDUP( face->charset_registry, 1647 charset_registry->value.atom ) ) 1648 goto Exit; 1649 } 1650 } 1651 } 1652 1653 Exit: 1654 if ( error ) 1655 { 1656 /* This is done to respect the behaviour of the original */ 1657 /* PCF font driver. */ 1658 error = FT_THROW( Invalid_File_Format ); 1659 } 1660 1661 return error; 1662 } 1663 1664 1665 /* END */ 1666