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