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 PCF 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_ULong* offsets = NULL; 814 FT_ULong 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_ULONG( offsets[i] ); 882 else 883 (void)FT_READ_ULONG_LE( offsets[i] ); 884 885 FT_TRACE5(( " bitmap %lu: offset %lu (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_ULONG( bitmapSizes[i] ); 895 else 896 (void)FT_READ_ULONG_LE( bitmapSizes[i] ); 897 if ( error ) 898 goto Bail; 899 900 sizebitmaps = bitmapSizes[PCF_GLYPH_PAD_INDEX( format )]; 901 902 FT_TRACE4(( " %ld-bit padding implies a size of %lu\n", 903 8 << i, bitmapSizes[i] )); 904 } 905 906 FT_TRACE4(( " %lu bitmaps, using %ld-bit padding\n", 907 nbitmaps, 908 8 << PCF_GLYPH_PAD_INDEX( format ) )); 909 FT_TRACE4(( " bitmap size: %lu\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] > size ) 919 { 920 FT_TRACE0(( "pcf_get_bitmaps:" 921 " invalid offset to bitmap data of glyph %lu\n", i )); 922 } 923 else 924 face->metrics[i].bits = stream->pos + offsets[i]; 925 } 926 927 face->bitmapsFormat = format; 928 929 Bail: 930 FT_FREE( offsets ); 931 return error; 932 } 933 934 935 /* 936 * This file uses X11 terminology for PCF data; an `encoding' in X11 speak 937 * is the same as a character code in FreeType speak. 938 */ 939 static FT_Error pcf_get_encodings(FT_Stream stream,PCF_Face face)940 pcf_get_encodings( FT_Stream stream, 941 PCF_Face face ) 942 { 943 FT_Error error; 944 FT_Memory memory = FT_FACE( face )->memory; 945 FT_ULong format, size; 946 FT_UShort firstCol, lastCol; 947 FT_UShort firstRow, lastRow; 948 FT_ULong nencoding; 949 FT_UShort defaultCharRow, defaultCharCol; 950 FT_UShort encodingOffset, defaultCharEncodingOffset; 951 FT_UShort i, j; 952 FT_Byte* pos; 953 FT_ULong k; 954 PCF_Encoding encoding = NULL; 955 956 957 error = pcf_seek_to_table_type( stream, 958 face->toc.tables, 959 face->toc.count, 960 PCF_BDF_ENCODINGS, 961 &format, 962 &size ); 963 if ( error ) 964 return error; 965 966 error = FT_Stream_EnterFrame( stream, 14 ); 967 if ( error ) 968 return error; 969 970 format = FT_GET_ULONG_LE(); 971 972 /* X11's reference implementation uses the equivalent to */ 973 /* `FT_GET_SHORT' for `defaultChar', however this doesn't */ 974 /* make sense for most encodings. */ 975 if ( PCF_BYTE_ORDER( format ) == MSBFirst ) 976 { 977 firstCol = FT_GET_USHORT(); 978 lastCol = FT_GET_USHORT(); 979 firstRow = FT_GET_USHORT(); 980 lastRow = FT_GET_USHORT(); 981 face->defaultChar = FT_GET_USHORT(); 982 } 983 else 984 { 985 firstCol = FT_GET_USHORT_LE(); 986 lastCol = FT_GET_USHORT_LE(); 987 firstRow = FT_GET_USHORT_LE(); 988 lastRow = FT_GET_USHORT_LE(); 989 face->defaultChar = FT_GET_USHORT_LE(); 990 } 991 992 FT_Stream_ExitFrame( stream ); 993 994 FT_TRACE4(( "pcf_get_encodings:\n" 995 " format: 0x%lX (%s)\n", 996 format, 997 PCF_BYTE_ORDER( format ) == MSBFirst ? "MSB" : "LSB" )); 998 999 if ( !PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) ) 1000 return FT_THROW( Invalid_File_Format ); 1001 1002 FT_TRACE4(( " firstCol 0x%X, lastCol 0x%X\n" 1003 " firstRow 0x%X, lastRow 0x%X\n" 1004 " defaultChar 0x%X\n", 1005 firstCol, lastCol, 1006 firstRow, lastRow, 1007 face->defaultChar )); 1008 1009 /* sanity checks; we limit numbers of rows and columns to 256 */ 1010 if ( firstCol > lastCol || 1011 lastCol > 0xFF || 1012 firstRow > lastRow || 1013 lastRow > 0xFF ) 1014 return FT_THROW( Invalid_Table ); 1015 1016 nencoding = (FT_ULong)( lastCol - firstCol + 1 ) * 1017 (FT_ULong)( lastRow - firstRow + 1 ); 1018 1019 if ( FT_NEW_ARRAY( encoding, nencoding ) ) 1020 return error; 1021 1022 error = FT_Stream_EnterFrame( stream, 2 * nencoding ); 1023 if ( error ) 1024 goto Bail; 1025 1026 FT_TRACE5(( "\n" )); 1027 1028 defaultCharRow = face->defaultChar >> 8; 1029 defaultCharCol = face->defaultChar & 0xFF; 1030 1031 /* validate default character */ 1032 if ( defaultCharRow < firstRow || 1033 defaultCharRow > lastRow || 1034 defaultCharCol < firstCol || 1035 defaultCharCol > lastCol ) 1036 { 1037 face->defaultChar = firstRow * 256U + firstCol; 1038 FT_TRACE0(( "pcf_get_encodings:" 1039 " Invalid default character set to %u\n", 1040 face->defaultChar )); 1041 1042 defaultCharRow = face->defaultChar >> 8; 1043 defaultCharCol = face->defaultChar & 0xFF; 1044 } 1045 1046 /* FreeType mandates that glyph index 0 is the `undefined glyph', */ 1047 /* which PCF calls the `default character'. For this reason, we */ 1048 /* swap the positions of glyph index 0 and the index corresponding */ 1049 /* to `defaultChar' in case they are different. */ 1050 1051 /* `stream->cursor' still points at the beginning of the frame; */ 1052 /* we can thus easily get the offset to the default character */ 1053 pos = stream->cursor + 1054 2 * ( ( defaultCharRow - firstRow ) * ( lastCol - firstCol + 1 ) + 1055 defaultCharCol - firstCol ); 1056 1057 if ( PCF_BYTE_ORDER( format ) == MSBFirst ) 1058 defaultCharEncodingOffset = FT_PEEK_USHORT( pos ); 1059 else 1060 defaultCharEncodingOffset = FT_PEEK_USHORT_LE( pos ); 1061 1062 if ( defaultCharEncodingOffset >= face->nmetrics ) 1063 { 1064 FT_TRACE0(( "pcf_get_encodings:" 1065 " Invalid glyph index for default character," 1066 " setting to zero\n" )); 1067 defaultCharEncodingOffset = 0; 1068 } 1069 1070 if ( defaultCharEncodingOffset ) 1071 { 1072 /* do the swapping */ 1073 PCF_MetricRec tmp = face->metrics[defaultCharEncodingOffset]; 1074 1075 1076 face->metrics[defaultCharEncodingOffset] = face->metrics[0]; 1077 face->metrics[0] = tmp; 1078 } 1079 1080 k = 0; 1081 for ( i = firstRow; i <= lastRow; i++ ) 1082 { 1083 for ( j = firstCol; j <= lastCol; j++ ) 1084 { 1085 /* X11's reference implementation uses the equivalent to */ 1086 /* `FT_GET_SHORT', however PCF fonts with more than 32768 */ 1087 /* characters (e.g., `unifont.pcf') clearly show that an */ 1088 /* unsigned value is needed. */ 1089 if ( PCF_BYTE_ORDER( format ) == MSBFirst ) 1090 encodingOffset = FT_GET_USHORT(); 1091 else 1092 encodingOffset = FT_GET_USHORT_LE(); 1093 1094 if ( encodingOffset != 0xFFFFU ) 1095 { 1096 if ( encodingOffset == defaultCharEncodingOffset ) 1097 encodingOffset = 0; 1098 else if ( encodingOffset == 0 ) 1099 encodingOffset = defaultCharEncodingOffset; 1100 1101 encoding[k].enc = i * 256U + j; 1102 encoding[k].glyph = encodingOffset; 1103 1104 FT_TRACE5(( " code %u (0x%04X): idx %u\n", 1105 encoding[k].enc, encoding[k].enc, encoding[k].glyph )); 1106 1107 k++; 1108 } 1109 } 1110 } 1111 FT_Stream_ExitFrame( stream ); 1112 1113 if ( FT_RENEW_ARRAY( encoding, nencoding, k ) ) 1114 goto Bail; 1115 1116 face->nencodings = k; 1117 face->encodings = encoding; 1118 1119 return error; 1120 1121 Bail: 1122 FT_FREE( encoding ); 1123 return error; 1124 } 1125 1126 1127 static 1128 const FT_Frame_Field pcf_accel_header[] = 1129 { 1130 #undef FT_STRUCTURE 1131 #define FT_STRUCTURE PCF_AccelRec 1132 1133 FT_FRAME_START( 20 ), 1134 FT_FRAME_BYTE ( noOverlap ), 1135 FT_FRAME_BYTE ( constantMetrics ), 1136 FT_FRAME_BYTE ( terminalFont ), 1137 FT_FRAME_BYTE ( constantWidth ), 1138 FT_FRAME_BYTE ( inkInside ), 1139 FT_FRAME_BYTE ( inkMetrics ), 1140 FT_FRAME_BYTE ( drawDirection ), 1141 FT_FRAME_SKIP_BYTES( 1 ), 1142 FT_FRAME_LONG_LE ( fontAscent ), 1143 FT_FRAME_LONG_LE ( fontDescent ), 1144 FT_FRAME_LONG_LE ( maxOverlap ), 1145 FT_FRAME_END 1146 }; 1147 1148 1149 static 1150 const FT_Frame_Field pcf_accel_msb_header[] = 1151 { 1152 #undef FT_STRUCTURE 1153 #define FT_STRUCTURE PCF_AccelRec 1154 1155 FT_FRAME_START( 20 ), 1156 FT_FRAME_BYTE ( noOverlap ), 1157 FT_FRAME_BYTE ( constantMetrics ), 1158 FT_FRAME_BYTE ( terminalFont ), 1159 FT_FRAME_BYTE ( constantWidth ), 1160 FT_FRAME_BYTE ( inkInside ), 1161 FT_FRAME_BYTE ( inkMetrics ), 1162 FT_FRAME_BYTE ( drawDirection ), 1163 FT_FRAME_SKIP_BYTES( 1 ), 1164 FT_FRAME_LONG ( fontAscent ), 1165 FT_FRAME_LONG ( fontDescent ), 1166 FT_FRAME_LONG ( maxOverlap ), 1167 FT_FRAME_END 1168 }; 1169 1170 1171 static FT_Error pcf_get_accel(FT_Stream stream,PCF_Face face,FT_ULong type)1172 pcf_get_accel( FT_Stream stream, 1173 PCF_Face face, 1174 FT_ULong type ) 1175 { 1176 FT_ULong format, size; 1177 FT_Error error; 1178 PCF_Accel accel = &face->accel; 1179 1180 1181 error = pcf_seek_to_table_type( stream, 1182 face->toc.tables, 1183 face->toc.count, 1184 type, 1185 &format, 1186 &size ); 1187 if ( error ) 1188 goto Bail; 1189 1190 if ( FT_READ_ULONG_LE( format ) ) 1191 goto Bail; 1192 1193 FT_TRACE4(( "pcf_get_accel%s:\n" 1194 " format: 0x%lX (%s, %s)\n", 1195 type == PCF_BDF_ACCELERATORS ? " (getting BDF accelerators)" 1196 : "", 1197 format, 1198 PCF_BYTE_ORDER( format ) == MSBFirst ? "MSB" : "LSB", 1199 PCF_FORMAT_MATCH( format, PCF_ACCEL_W_INKBOUNDS ) ? 1200 "accelerated" : "not accelerated" )); 1201 1202 if ( !PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) && 1203 !PCF_FORMAT_MATCH( format, PCF_ACCEL_W_INKBOUNDS ) ) 1204 goto Bail; 1205 1206 if ( PCF_BYTE_ORDER( format ) == MSBFirst ) 1207 { 1208 if ( FT_STREAM_READ_FIELDS( pcf_accel_msb_header, accel ) ) 1209 goto Bail; 1210 } 1211 else 1212 { 1213 if ( FT_STREAM_READ_FIELDS( pcf_accel_header, accel ) ) 1214 goto Bail; 1215 } 1216 1217 FT_TRACE5(( " noOverlap=%s, constantMetrics=%s," 1218 " terminalFont=%s, constantWidth=%s\n" 1219 " inkInside=%s, inkMetrics=%s, drawDirection=%s\n" 1220 " fontAscent=%ld, fontDescent=%ld, maxOverlap=%ld\n", 1221 accel->noOverlap ? "yes" : "no", 1222 accel->constantMetrics ? "yes" : "no", 1223 accel->terminalFont ? "yes" : "no", 1224 accel->constantWidth ? "yes" : "no", 1225 accel->inkInside ? "yes" : "no", 1226 accel->inkMetrics ? "yes" : "no", 1227 accel->drawDirection ? "RTL" : "LTR", 1228 accel->fontAscent, 1229 accel->fontDescent, 1230 accel->maxOverlap )); 1231 1232 /* sanity checks */ 1233 if ( FT_ABS( accel->fontAscent ) > 0x7FFF ) 1234 { 1235 accel->fontAscent = accel->fontAscent < 0 ? -0x7FFF : 0x7FFF; 1236 FT_TRACE0(( "pfc_get_accel: clamping font ascent to value %d\n", 1237 accel->fontAscent )); 1238 } 1239 if ( FT_ABS( accel->fontDescent ) > 0x7FFF ) 1240 { 1241 accel->fontDescent = accel->fontDescent < 0 ? -0x7FFF : 0x7FFF; 1242 FT_TRACE0(( "pfc_get_accel: clamping font descent to value %d\n", 1243 accel->fontDescent )); 1244 } 1245 1246 FT_TRACE5(( " minbounds:" )); 1247 error = pcf_get_metric( stream, 1248 format & ( ~PCF_FORMAT_MASK ), 1249 &(accel->minbounds) ); 1250 if ( error ) 1251 goto Bail; 1252 1253 FT_TRACE5(( " maxbounds:" )); 1254 error = pcf_get_metric( stream, 1255 format & ( ~PCF_FORMAT_MASK ), 1256 &(accel->maxbounds) ); 1257 if ( error ) 1258 goto Bail; 1259 1260 if ( PCF_FORMAT_MATCH( format, PCF_ACCEL_W_INKBOUNDS ) ) 1261 { 1262 FT_TRACE5(( " ink minbounds:" )); 1263 error = pcf_get_metric( stream, 1264 format & ( ~PCF_FORMAT_MASK ), 1265 &(accel->ink_minbounds) ); 1266 if ( error ) 1267 goto Bail; 1268 1269 FT_TRACE5(( " ink maxbounds:" )); 1270 error = pcf_get_metric( stream, 1271 format & ( ~PCF_FORMAT_MASK ), 1272 &(accel->ink_maxbounds) ); 1273 if ( error ) 1274 goto Bail; 1275 } 1276 else 1277 { 1278 accel->ink_minbounds = accel->minbounds; 1279 accel->ink_maxbounds = accel->maxbounds; 1280 } 1281 1282 Bail: 1283 return error; 1284 } 1285 1286 1287 static FT_Error pcf_interpret_style(PCF_Face pcf)1288 pcf_interpret_style( PCF_Face pcf ) 1289 { 1290 FT_Error error = FT_Err_Ok; 1291 FT_Face face = FT_FACE( pcf ); 1292 FT_Memory memory = face->memory; 1293 1294 PCF_Property prop; 1295 1296 size_t nn, len; 1297 char* strings[4] = { NULL, NULL, NULL, NULL }; 1298 size_t lengths[4]; 1299 1300 1301 face->style_flags = 0; 1302 1303 prop = pcf_find_property( pcf, "SLANT" ); 1304 if ( prop && prop->isString && 1305 ( *(prop->value.atom) == 'O' || *(prop->value.atom) == 'o' || 1306 *(prop->value.atom) == 'I' || *(prop->value.atom) == 'i' ) ) 1307 { 1308 face->style_flags |= FT_STYLE_FLAG_ITALIC; 1309 strings[2] = ( *(prop->value.atom) == 'O' || 1310 *(prop->value.atom) == 'o' ) ? (char *)"Oblique" 1311 : (char *)"Italic"; 1312 } 1313 1314 prop = pcf_find_property( pcf, "WEIGHT_NAME" ); 1315 if ( prop && prop->isString && 1316 ( *(prop->value.atom) == 'B' || *(prop->value.atom) == 'b' ) ) 1317 { 1318 face->style_flags |= FT_STYLE_FLAG_BOLD; 1319 strings[1] = (char*)"Bold"; 1320 } 1321 1322 prop = pcf_find_property( pcf, "SETWIDTH_NAME" ); 1323 if ( prop && prop->isString && 1324 *(prop->value.atom) && 1325 !( *(prop->value.atom) == 'N' || *(prop->value.atom) == 'n' ) ) 1326 strings[3] = (char*)( prop->value.atom ); 1327 1328 prop = pcf_find_property( pcf, "ADD_STYLE_NAME" ); 1329 if ( prop && prop->isString && 1330 *(prop->value.atom) && 1331 !( *(prop->value.atom) == 'N' || *(prop->value.atom) == 'n' ) ) 1332 strings[0] = (char*)( prop->value.atom ); 1333 1334 for ( len = 0, nn = 0; nn < 4; nn++ ) 1335 { 1336 lengths[nn] = 0; 1337 if ( strings[nn] ) 1338 { 1339 lengths[nn] = ft_strlen( strings[nn] ); 1340 len += lengths[nn] + 1; 1341 } 1342 } 1343 1344 if ( len == 0 ) 1345 { 1346 strings[0] = (char*)"Regular"; 1347 lengths[0] = ft_strlen( strings[0] ); 1348 len = lengths[0] + 1; 1349 } 1350 1351 { 1352 char* s; 1353 1354 1355 if ( FT_ALLOC( face->style_name, len ) ) 1356 return error; 1357 1358 s = face->style_name; 1359 1360 for ( nn = 0; nn < 4; nn++ ) 1361 { 1362 char* src = strings[nn]; 1363 1364 1365 len = lengths[nn]; 1366 1367 if ( !src ) 1368 continue; 1369 1370 /* separate elements with a space */ 1371 if ( s != face->style_name ) 1372 *s++ = ' '; 1373 1374 ft_memcpy( s, src, len ); 1375 1376 /* need to convert spaces to dashes for */ 1377 /* add_style_name and setwidth_name */ 1378 if ( nn == 0 || nn == 3 ) 1379 { 1380 size_t mm; 1381 1382 1383 for ( mm = 0; mm < len; mm++ ) 1384 if ( s[mm] == ' ' ) 1385 s[mm] = '-'; 1386 } 1387 1388 s += len; 1389 } 1390 *s = 0; 1391 } 1392 1393 return error; 1394 } 1395 1396 1397 FT_LOCAL_DEF( FT_Error ) pcf_load_font(FT_Stream stream,PCF_Face face,FT_Long face_index)1398 pcf_load_font( FT_Stream stream, 1399 PCF_Face face, 1400 FT_Long face_index ) 1401 { 1402 FT_Face root = FT_FACE( face ); 1403 FT_Error error; 1404 FT_Memory memory = FT_FACE( face )->memory; 1405 FT_Bool hasBDFAccelerators; 1406 1407 1408 error = pcf_read_TOC( stream, face ); 1409 if ( error ) 1410 goto Exit; 1411 1412 root->num_faces = 1; 1413 root->face_index = 0; 1414 1415 /* If we are performing a simple font format check, exit immediately. */ 1416 if ( face_index < 0 ) 1417 return FT_Err_Ok; 1418 1419 error = pcf_get_properties( stream, face ); 1420 if ( error ) 1421 goto Exit; 1422 1423 /* Use the old accelerators if no BDF accelerators are in the file. */ 1424 hasBDFAccelerators = pcf_has_table_type( face->toc.tables, 1425 face->toc.count, 1426 PCF_BDF_ACCELERATORS ); 1427 if ( !hasBDFAccelerators ) 1428 { 1429 error = pcf_get_accel( stream, face, PCF_ACCELERATORS ); 1430 if ( error ) 1431 goto Exit; 1432 } 1433 1434 /* metrics */ 1435 error = pcf_get_metrics( stream, face ); 1436 if ( error ) 1437 goto Exit; 1438 1439 /* bitmaps */ 1440 error = pcf_get_bitmaps( stream, face ); 1441 if ( error ) 1442 goto Exit; 1443 1444 /* encodings */ 1445 error = pcf_get_encodings( stream, face ); 1446 if ( error ) 1447 goto Exit; 1448 1449 /* BDF style accelerators (i.e. bounds based on encoded glyphs) */ 1450 if ( hasBDFAccelerators ) 1451 { 1452 error = pcf_get_accel( stream, face, PCF_BDF_ACCELERATORS ); 1453 if ( error ) 1454 goto Exit; 1455 } 1456 1457 /* XXX: TO DO: inkmetrics and glyph_names are missing */ 1458 1459 /* now construct the face object */ 1460 { 1461 PCF_Property prop; 1462 1463 1464 root->face_flags |= FT_FACE_FLAG_FIXED_SIZES | 1465 FT_FACE_FLAG_HORIZONTAL; 1466 1467 if ( face->accel.constantWidth ) 1468 root->face_flags |= FT_FACE_FLAG_FIXED_WIDTH; 1469 1470 if ( FT_SET_ERROR( pcf_interpret_style( face ) ) ) 1471 goto Exit; 1472 1473 prop = pcf_find_property( face, "FAMILY_NAME" ); 1474 if ( prop && prop->isString ) 1475 { 1476 1477 #ifdef PCF_CONFIG_OPTION_LONG_FAMILY_NAMES 1478 1479 PCF_Driver driver = (PCF_Driver)FT_FACE_DRIVER( face ); 1480 1481 1482 if ( !driver->no_long_family_names ) 1483 { 1484 /* Prepend the foundry name plus a space to the family name. */ 1485 /* There are many fonts just called `Fixed' which look */ 1486 /* completely different, and which have nothing to do with each */ 1487 /* other. When selecting `Fixed' in KDE or Gnome one gets */ 1488 /* results that appear rather random, the style changes often if */ 1489 /* one changes the size and one cannot select some fonts at all. */ 1490 /* */ 1491 /* We also check whether we have `wide' characters; all put */ 1492 /* together, we get family names like `Sony Fixed' or `Misc */ 1493 /* Fixed Wide'. */ 1494 1495 PCF_Property foundry_prop, point_size_prop, average_width_prop; 1496 1497 int l = ft_strlen( prop->value.atom ) + 1; 1498 int wide = 0; 1499 1500 1501 foundry_prop = pcf_find_property( face, "FOUNDRY" ); 1502 point_size_prop = pcf_find_property( face, "POINT_SIZE" ); 1503 average_width_prop = pcf_find_property( face, "AVERAGE_WIDTH" ); 1504 1505 if ( point_size_prop && average_width_prop ) 1506 { 1507 if ( average_width_prop->value.l >= point_size_prop->value.l ) 1508 { 1509 /* This font is at least square shaped or even wider */ 1510 wide = 1; 1511 l += ft_strlen( " Wide" ); 1512 } 1513 } 1514 1515 if ( foundry_prop && foundry_prop->isString ) 1516 { 1517 l += ft_strlen( foundry_prop->value.atom ) + 1; 1518 1519 if ( FT_NEW_ARRAY( root->family_name, l ) ) 1520 goto Exit; 1521 1522 ft_strcpy( root->family_name, foundry_prop->value.atom ); 1523 ft_strcat( root->family_name, " " ); 1524 ft_strcat( root->family_name, prop->value.atom ); 1525 } 1526 else 1527 { 1528 if ( FT_NEW_ARRAY( root->family_name, l ) ) 1529 goto Exit; 1530 1531 ft_strcpy( root->family_name, prop->value.atom ); 1532 } 1533 1534 if ( wide ) 1535 ft_strcat( root->family_name, " Wide" ); 1536 } 1537 else 1538 1539 #endif /* PCF_CONFIG_OPTION_LONG_FAMILY_NAMES */ 1540 1541 { 1542 if ( FT_STRDUP( root->family_name, prop->value.atom ) ) 1543 goto Exit; 1544 } 1545 } 1546 else 1547 root->family_name = NULL; 1548 1549 root->num_glyphs = (FT_Long)face->nmetrics; 1550 1551 root->num_fixed_sizes = 1; 1552 if ( FT_NEW_ARRAY( root->available_sizes, 1 ) ) 1553 goto Exit; 1554 1555 { 1556 FT_Bitmap_Size* bsize = root->available_sizes; 1557 FT_Short resolution_x = 0, resolution_y = 0; 1558 1559 1560 FT_ZERO( bsize ); 1561 1562 /* for simplicity, we take absolute values of integer properties */ 1563 1564 #if 0 1565 bsize->height = face->accel.maxbounds.ascent << 6; 1566 #endif 1567 1568 #ifdef FT_DEBUG_LEVEL_TRACE 1569 if ( face->accel.fontAscent + face->accel.fontDescent < 0 ) 1570 FT_TRACE0(( "pcf_load_font: negative height\n" )); 1571 #endif 1572 if ( FT_ABS( face->accel.fontAscent + 1573 face->accel.fontDescent ) > 0x7FFF ) 1574 { 1575 bsize->height = 0x7FFF; 1576 FT_TRACE0(( "pcf_load_font: clamping height to value %d\n", 1577 bsize->height )); 1578 } 1579 else 1580 bsize->height = FT_ABS( (FT_Short)( face->accel.fontAscent + 1581 face->accel.fontDescent ) ); 1582 1583 prop = pcf_find_property( face, "AVERAGE_WIDTH" ); 1584 if ( prop ) 1585 { 1586 #ifdef FT_DEBUG_LEVEL_TRACE 1587 if ( prop->value.l < 0 ) 1588 FT_TRACE0(( "pcf_load_font: negative average width\n" )); 1589 #endif 1590 if ( ( FT_ABS( prop->value.l ) > 0x7FFFL * 10 - 5 ) ) 1591 { 1592 bsize->width = 0x7FFF; 1593 FT_TRACE0(( "pcf_load_font: clamping average width to value %d\n", 1594 bsize->width )); 1595 } 1596 else 1597 bsize->width = FT_ABS( (FT_Short)( ( prop->value.l + 5 ) / 10 ) ); 1598 } 1599 else 1600 { 1601 /* this is a heuristical value */ 1602 bsize->width = (FT_Short)FT_MulDiv( bsize->height, 2, 3 ); 1603 } 1604 1605 prop = pcf_find_property( face, "POINT_SIZE" ); 1606 if ( prop ) 1607 { 1608 #ifdef FT_DEBUG_LEVEL_TRACE 1609 if ( prop->value.l < 0 ) 1610 FT_TRACE0(( "pcf_load_font: negative point size\n" )); 1611 #endif 1612 /* convert from 722.7 decipoints to 72 points per inch */ 1613 if ( FT_ABS( prop->value.l ) > 0x504C2L ) /* 0x7FFF * 72270/7200 */ 1614 { 1615 bsize->size = 0x7FFF; 1616 FT_TRACE0(( "pcf_load_font: clamping point size to value %d\n", 1617 bsize->size )); 1618 } 1619 else 1620 bsize->size = FT_MulDiv( FT_ABS( prop->value.l ), 1621 64 * 7200, 1622 72270L ); 1623 } 1624 1625 prop = pcf_find_property( face, "PIXEL_SIZE" ); 1626 if ( prop ) 1627 { 1628 #ifdef FT_DEBUG_LEVEL_TRACE 1629 if ( prop->value.l < 0 ) 1630 FT_TRACE0(( "pcf_load_font: negative pixel size\n" )); 1631 #endif 1632 if ( FT_ABS( prop->value.l ) > 0x7FFF ) 1633 { 1634 bsize->y_ppem = 0x7FFF << 6; 1635 FT_TRACE0(( "pcf_load_font: clamping pixel size to value %d\n", 1636 bsize->y_ppem )); 1637 } 1638 else 1639 bsize->y_ppem = FT_ABS( (FT_Short)prop->value.l ) << 6; 1640 } 1641 1642 prop = pcf_find_property( face, "RESOLUTION_X" ); 1643 if ( prop ) 1644 { 1645 #ifdef FT_DEBUG_LEVEL_TRACE 1646 if ( prop->value.l < 0 ) 1647 FT_TRACE0(( "pcf_load_font: negative X resolution\n" )); 1648 #endif 1649 if ( FT_ABS( prop->value.l ) > 0x7FFF ) 1650 { 1651 resolution_x = 0x7FFF; 1652 FT_TRACE0(( "pcf_load_font: clamping X resolution to value %d\n", 1653 resolution_x )); 1654 } 1655 else 1656 resolution_x = FT_ABS( (FT_Short)prop->value.l ); 1657 } 1658 1659 prop = pcf_find_property( face, "RESOLUTION_Y" ); 1660 if ( prop ) 1661 { 1662 #ifdef FT_DEBUG_LEVEL_TRACE 1663 if ( prop->value.l < 0 ) 1664 FT_TRACE0(( "pcf_load_font: negative Y resolution\n" )); 1665 #endif 1666 if ( FT_ABS( prop->value.l ) > 0x7FFF ) 1667 { 1668 resolution_y = 0x7FFF; 1669 FT_TRACE0(( "pcf_load_font: clamping Y resolution to value %d\n", 1670 resolution_y )); 1671 } 1672 else 1673 resolution_y = FT_ABS( (FT_Short)prop->value.l ); 1674 } 1675 1676 if ( bsize->y_ppem == 0 ) 1677 { 1678 bsize->y_ppem = bsize->size; 1679 if ( resolution_y ) 1680 bsize->y_ppem = FT_MulDiv( bsize->y_ppem, resolution_y, 72 ); 1681 } 1682 if ( resolution_x && resolution_y ) 1683 bsize->x_ppem = FT_MulDiv( bsize->y_ppem, 1684 resolution_x, 1685 resolution_y ); 1686 else 1687 bsize->x_ppem = bsize->y_ppem; 1688 } 1689 1690 /* set up charset */ 1691 { 1692 PCF_Property charset_registry, charset_encoding; 1693 1694 1695 charset_registry = pcf_find_property( face, "CHARSET_REGISTRY" ); 1696 charset_encoding = pcf_find_property( face, "CHARSET_ENCODING" ); 1697 1698 if ( charset_registry && charset_registry->isString && 1699 charset_encoding && charset_encoding->isString ) 1700 { 1701 if ( FT_STRDUP( face->charset_encoding, 1702 charset_encoding->value.atom ) || 1703 FT_STRDUP( face->charset_registry, 1704 charset_registry->value.atom ) ) 1705 goto Exit; 1706 } 1707 } 1708 } 1709 1710 Exit: 1711 if ( error ) 1712 { 1713 /* This is done to respect the behaviour of the original */ 1714 /* PCF font driver. */ 1715 error = FT_THROW( Invalid_File_Format ); 1716 } 1717 1718 return error; 1719 } 1720 1721 1722 /* END */ 1723