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