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