1 /* pcfread.c 2 3 FreeType font driver for pcf fonts 4 5 Copyright 2000-2010, 2012, 2013 by 6 Francesco Zappa Nardelli 7 8 Permission is hereby granted, free of charge, to any person obtaining a copy 9 of this software and associated documentation files (the "Software"), to deal 10 in the Software without restriction, including without limitation the rights 11 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 copies of the Software, and to permit persons to whom the Software is 13 furnished to do so, subject to the following conditions: 14 15 The above copyright notice and this permission notice shall be included in 16 all copies or substantial portions of the Software. 17 18 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 THE SOFTWARE. 25 */ 26 27 28 #include <ft2build.h> 29 30 #include FT_INTERNAL_DEBUG_H 31 #include FT_INTERNAL_STREAM_H 32 #include FT_INTERNAL_OBJECTS_H 33 34 #include "pcf.h" 35 #include "pcfread.h" 36 37 #include "pcferror.h" 38 39 40 /*************************************************************************/ 41 /* */ 42 /* The macro FT_COMPONENT is used in trace mode. It is an implicit */ 43 /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */ 44 /* messages during execution. */ 45 /* */ 46 #undef FT_COMPONENT 47 #define FT_COMPONENT trace_pcfread 48 49 50 #ifdef FT_DEBUG_LEVEL_TRACE 51 static const char* const tableNames[] = 52 { 53 "prop", "accl", "mtrcs", "bmps", "imtrcs", 54 "enc", "swidth", "names", "accel" 55 }; 56 #endif 57 58 59 static 60 const FT_Frame_Field pcf_toc_header[] = 61 { 62 #undef FT_STRUCTURE 63 #define FT_STRUCTURE PCF_TocRec 64 65 FT_FRAME_START( 8 ), 66 FT_FRAME_ULONG_LE( version ), 67 FT_FRAME_ULONG_LE( count ), 68 FT_FRAME_END 69 }; 70 71 72 static 73 const FT_Frame_Field pcf_table_header[] = 74 { 75 #undef FT_STRUCTURE 76 #define FT_STRUCTURE PCF_TableRec 77 78 FT_FRAME_START( 16 ), 79 FT_FRAME_ULONG_LE( type ), 80 FT_FRAME_ULONG_LE( format ), 81 FT_FRAME_ULONG_LE( size ), 82 FT_FRAME_ULONG_LE( offset ), 83 FT_FRAME_END 84 }; 85 86 87 static FT_Error pcf_read_TOC(FT_Stream stream,PCF_Face face)88 pcf_read_TOC( FT_Stream stream, 89 PCF_Face face ) 90 { 91 FT_Error error; 92 PCF_Toc toc = &face->toc; 93 PCF_Table tables; 94 95 FT_Memory memory = FT_FACE( face )->memory; 96 FT_UInt n; 97 98 99 if ( FT_STREAM_SEEK ( 0 ) || 100 FT_STREAM_READ_FIELDS ( pcf_toc_header, toc ) ) 101 return FT_THROW( Cannot_Open_Resource ); 102 103 if ( toc->version != PCF_FILE_VERSION || 104 toc->count > FT_ARRAY_MAX( face->toc.tables ) || 105 toc->count == 0 ) 106 return FT_THROW( Invalid_File_Format ); 107 108 if ( FT_NEW_ARRAY( face->toc.tables, toc->count ) ) 109 return FT_THROW( Out_Of_Memory ); 110 111 tables = face->toc.tables; 112 for ( n = 0; n < toc->count; n++ ) 113 { 114 if ( FT_STREAM_READ_FIELDS( pcf_table_header, tables ) ) 115 goto Exit; 116 tables++; 117 } 118 119 /* Sort tables and check for overlaps. Because they are almost */ 120 /* always ordered already, an in-place bubble sort with simultaneous */ 121 /* boundary checking seems appropriate. */ 122 tables = face->toc.tables; 123 124 for ( n = 0; n < toc->count - 1; n++ ) 125 { 126 FT_UInt i, have_change; 127 128 129 have_change = 0; 130 131 for ( i = 0; i < toc->count - 1 - n; i++ ) 132 { 133 PCF_TableRec tmp; 134 135 136 if ( tables[i].offset > tables[i + 1].offset ) 137 { 138 tmp = tables[i]; 139 tables[i] = tables[i + 1]; 140 tables[i + 1] = tmp; 141 142 have_change = 1; 143 } 144 145 if ( ( tables[i].size > tables[i + 1].offset ) || 146 ( tables[i].offset > tables[i + 1].offset - tables[i].size ) ) 147 return FT_THROW( Invalid_Offset ); 148 } 149 150 if ( !have_change ) 151 break; 152 } 153 154 #ifdef FT_DEBUG_LEVEL_TRACE 155 156 { 157 FT_UInt i, j; 158 const char* name = "?"; 159 160 161 FT_TRACE4(( "pcf_read_TOC:\n" )); 162 163 FT_TRACE4(( " number of tables: %ld\n", face->toc.count )); 164 165 tables = face->toc.tables; 166 for ( i = 0; i < toc->count; i++ ) 167 { 168 for ( j = 0; j < sizeof ( tableNames ) / sizeof ( tableNames[0] ); 169 j++ ) 170 if ( tables[i].type == (FT_UInt)( 1 << j ) ) 171 name = tableNames[j]; 172 173 FT_TRACE4(( " %d: type=%s, format=0x%X, " 174 "size=%ld (0x%lX), offset=%ld (0x%lX)\n", 175 i, name, 176 tables[i].format, 177 tables[i].size, tables[i].size, 178 tables[i].offset, tables[i].offset )); 179 } 180 } 181 182 #endif 183 184 return FT_Err_Ok; 185 186 Exit: 187 FT_FREE( face->toc.tables ); 188 return error; 189 } 190 191 192 #define PCF_METRIC_SIZE 12 193 194 static 195 const FT_Frame_Field pcf_metric_header[] = 196 { 197 #undef FT_STRUCTURE 198 #define FT_STRUCTURE PCF_MetricRec 199 200 FT_FRAME_START( PCF_METRIC_SIZE ), 201 FT_FRAME_SHORT_LE( leftSideBearing ), 202 FT_FRAME_SHORT_LE( rightSideBearing ), 203 FT_FRAME_SHORT_LE( characterWidth ), 204 FT_FRAME_SHORT_LE( ascent ), 205 FT_FRAME_SHORT_LE( descent ), 206 FT_FRAME_SHORT_LE( attributes ), 207 FT_FRAME_END 208 }; 209 210 211 static 212 const FT_Frame_Field pcf_metric_msb_header[] = 213 { 214 #undef FT_STRUCTURE 215 #define FT_STRUCTURE PCF_MetricRec 216 217 FT_FRAME_START( PCF_METRIC_SIZE ), 218 FT_FRAME_SHORT( leftSideBearing ), 219 FT_FRAME_SHORT( rightSideBearing ), 220 FT_FRAME_SHORT( characterWidth ), 221 FT_FRAME_SHORT( ascent ), 222 FT_FRAME_SHORT( descent ), 223 FT_FRAME_SHORT( attributes ), 224 FT_FRAME_END 225 }; 226 227 228 #define PCF_COMPRESSED_METRIC_SIZE 5 229 230 static 231 const FT_Frame_Field pcf_compressed_metric_header[] = 232 { 233 #undef FT_STRUCTURE 234 #define FT_STRUCTURE PCF_Compressed_MetricRec 235 236 FT_FRAME_START( PCF_COMPRESSED_METRIC_SIZE ), 237 FT_FRAME_BYTE( leftSideBearing ), 238 FT_FRAME_BYTE( rightSideBearing ), 239 FT_FRAME_BYTE( characterWidth ), 240 FT_FRAME_BYTE( ascent ), 241 FT_FRAME_BYTE( descent ), 242 FT_FRAME_END 243 }; 244 245 246 static FT_Error pcf_get_metric(FT_Stream stream,FT_ULong format,PCF_Metric metric)247 pcf_get_metric( FT_Stream stream, 248 FT_ULong format, 249 PCF_Metric metric ) 250 { 251 FT_Error error = FT_Err_Ok; 252 253 254 if ( PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) ) 255 { 256 const FT_Frame_Field* fields; 257 258 259 /* parsing normal metrics */ 260 fields = PCF_BYTE_ORDER( format ) == MSBFirst 261 ? pcf_metric_msb_header 262 : pcf_metric_header; 263 264 /* the following sets `error' but doesn't return in case of failure */ 265 (void)FT_STREAM_READ_FIELDS( fields, metric ); 266 } 267 else 268 { 269 PCF_Compressed_MetricRec compr; 270 271 272 /* parsing compressed metrics */ 273 if ( FT_STREAM_READ_FIELDS( pcf_compressed_metric_header, &compr ) ) 274 goto Exit; 275 276 metric->leftSideBearing = (FT_Short)( compr.leftSideBearing - 0x80 ); 277 metric->rightSideBearing = (FT_Short)( compr.rightSideBearing - 0x80 ); 278 metric->characterWidth = (FT_Short)( compr.characterWidth - 0x80 ); 279 metric->ascent = (FT_Short)( compr.ascent - 0x80 ); 280 metric->descent = (FT_Short)( compr.descent - 0x80 ); 281 metric->attributes = 0; 282 } 283 284 Exit: 285 return error; 286 } 287 288 289 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)290 pcf_seek_to_table_type( FT_Stream stream, 291 PCF_Table tables, 292 FT_ULong ntables, /* same as PCF_Toc->count */ 293 FT_ULong type, 294 FT_ULong *aformat, 295 FT_ULong *asize ) 296 { 297 FT_Error error = FT_ERR( Invalid_File_Format ); 298 FT_ULong i; 299 300 301 for ( i = 0; i < ntables; i++ ) 302 if ( tables[i].type == type ) 303 { 304 if ( stream->pos > tables[i].offset ) 305 { 306 error = FT_THROW( Invalid_Stream_Skip ); 307 goto Fail; 308 } 309 310 if ( FT_STREAM_SKIP( tables[i].offset - stream->pos ) ) 311 { 312 error = FT_THROW( Invalid_Stream_Skip ); 313 goto Fail; 314 } 315 316 *asize = tables[i].size; 317 *aformat = tables[i].format; 318 319 return FT_Err_Ok; 320 } 321 322 Fail: 323 *asize = 0; 324 return error; 325 } 326 327 328 static FT_Bool pcf_has_table_type(PCF_Table tables,FT_ULong ntables,FT_ULong type)329 pcf_has_table_type( PCF_Table tables, 330 FT_ULong ntables, /* same as PCF_Toc->count */ 331 FT_ULong type ) 332 { 333 FT_ULong i; 334 335 336 for ( i = 0; i < ntables; i++ ) 337 if ( tables[i].type == type ) 338 return TRUE; 339 340 return FALSE; 341 } 342 343 344 #define PCF_PROPERTY_SIZE 9 345 346 static 347 const FT_Frame_Field pcf_property_header[] = 348 { 349 #undef FT_STRUCTURE 350 #define FT_STRUCTURE PCF_ParsePropertyRec 351 352 FT_FRAME_START( PCF_PROPERTY_SIZE ), 353 FT_FRAME_LONG_LE( name ), 354 FT_FRAME_BYTE ( isString ), 355 FT_FRAME_LONG_LE( value ), 356 FT_FRAME_END 357 }; 358 359 360 static 361 const FT_Frame_Field pcf_property_msb_header[] = 362 { 363 #undef FT_STRUCTURE 364 #define FT_STRUCTURE PCF_ParsePropertyRec 365 366 FT_FRAME_START( PCF_PROPERTY_SIZE ), 367 FT_FRAME_LONG( name ), 368 FT_FRAME_BYTE( isString ), 369 FT_FRAME_LONG( value ), 370 FT_FRAME_END 371 }; 372 373 374 FT_LOCAL_DEF( PCF_Property ) pcf_find_property(PCF_Face face,const FT_String * prop)375 pcf_find_property( PCF_Face face, 376 const FT_String* prop ) 377 { 378 PCF_Property properties = face->properties; 379 FT_Bool found = 0; 380 int i; 381 382 383 for ( i = 0 ; i < face->nprops && !found; i++ ) 384 { 385 if ( !ft_strcmp( properties[i].name, prop ) ) 386 found = 1; 387 } 388 389 if ( found ) 390 return properties + i - 1; 391 else 392 return NULL; 393 } 394 395 396 static FT_Error pcf_get_properties(FT_Stream stream,PCF_Face face)397 pcf_get_properties( FT_Stream stream, 398 PCF_Face face ) 399 { 400 PCF_ParseProperty props = 0; 401 PCF_Property properties = NULL; 402 FT_ULong nprops, i; 403 FT_ULong format, size; 404 FT_Error error; 405 FT_Memory memory = FT_FACE( face )->memory; 406 FT_ULong string_size; 407 FT_String* strings = 0; 408 409 410 error = pcf_seek_to_table_type( stream, 411 face->toc.tables, 412 face->toc.count, 413 PCF_PROPERTIES, 414 &format, 415 &size ); 416 if ( error ) 417 goto Bail; 418 419 if ( FT_READ_ULONG_LE( format ) ) 420 goto Bail; 421 422 FT_TRACE4(( "pcf_get_properties:\n" )); 423 424 FT_TRACE4(( " format = %ld\n", format )); 425 426 if ( !PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) ) 427 goto Bail; 428 429 if ( PCF_BYTE_ORDER( format ) == MSBFirst ) 430 (void)FT_READ_ULONG( nprops ); 431 else 432 (void)FT_READ_ULONG_LE( nprops ); 433 if ( error ) 434 goto Bail; 435 436 FT_TRACE4(( " nprop = %d (truncate %d props)\n", 437 (int)nprops, nprops - (int)nprops )); 438 439 nprops = (int)nprops; 440 441 /* rough estimate */ 442 if ( nprops > size / PCF_PROPERTY_SIZE ) 443 { 444 error = FT_THROW( Invalid_Table ); 445 goto Bail; 446 } 447 448 face->nprops = (int)nprops; 449 450 if ( FT_NEW_ARRAY( props, nprops ) ) 451 goto Bail; 452 453 for ( i = 0; i < nprops; i++ ) 454 { 455 if ( PCF_BYTE_ORDER( format ) == MSBFirst ) 456 { 457 if ( FT_STREAM_READ_FIELDS( pcf_property_msb_header, props + i ) ) 458 goto Bail; 459 } 460 else 461 { 462 if ( FT_STREAM_READ_FIELDS( pcf_property_header, props + i ) ) 463 goto Bail; 464 } 465 } 466 467 /* pad the property array */ 468 /* */ 469 /* clever here - nprops is the same as the number of odd-units read, */ 470 /* as only isStringProp are odd length (Keith Packard) */ 471 /* */ 472 if ( nprops & 3 ) 473 { 474 i = 4 - ( nprops & 3 ); 475 if ( FT_STREAM_SKIP( i ) ) 476 { 477 error = FT_THROW( Invalid_Stream_Skip ); 478 goto Bail; 479 } 480 } 481 482 if ( PCF_BYTE_ORDER( format ) == MSBFirst ) 483 (void)FT_READ_ULONG( string_size ); 484 else 485 (void)FT_READ_ULONG_LE( string_size ); 486 if ( error ) 487 goto Bail; 488 489 FT_TRACE4(( " string_size = %ld\n", string_size )); 490 491 /* rough estimate */ 492 if ( string_size > size - nprops * PCF_PROPERTY_SIZE ) 493 { 494 error = FT_THROW( Invalid_Table ); 495 goto Bail; 496 } 497 498 /* allocate one more byte so that we have a final null byte */ 499 if ( FT_NEW_ARRAY( strings, string_size + 1 ) ) 500 goto Bail; 501 502 error = FT_Stream_Read( stream, (FT_Byte*)strings, string_size ); 503 if ( error ) 504 goto Bail; 505 506 if ( FT_NEW_ARRAY( properties, nprops ) ) 507 goto Bail; 508 509 face->properties = properties; 510 511 for ( i = 0; i < nprops; i++ ) 512 { 513 FT_Long name_offset = props[i].name; 514 515 516 if ( ( name_offset < 0 ) || 517 ( (FT_ULong)name_offset > string_size ) ) 518 { 519 error = FT_THROW( Invalid_Offset ); 520 goto Bail; 521 } 522 523 if ( FT_STRDUP( properties[i].name, strings + name_offset ) ) 524 goto Bail; 525 526 FT_TRACE4(( " %s:", properties[i].name )); 527 528 properties[i].isString = props[i].isString; 529 530 if ( props[i].isString ) 531 { 532 FT_Long value_offset = props[i].value; 533 534 535 if ( ( value_offset < 0 ) || 536 ( (FT_ULong)value_offset > string_size ) ) 537 { 538 error = FT_THROW( Invalid_Offset ); 539 goto Bail; 540 } 541 542 if ( FT_STRDUP( properties[i].value.atom, strings + value_offset ) ) 543 goto Bail; 544 545 FT_TRACE4(( " `%s'\n", properties[i].value.atom )); 546 } 547 else 548 { 549 properties[i].value.l = props[i].value; 550 551 FT_TRACE4(( " %d\n", properties[i].value.l )); 552 } 553 } 554 555 error = FT_Err_Ok; 556 557 Bail: 558 FT_FREE( props ); 559 FT_FREE( strings ); 560 561 return error; 562 } 563 564 565 static FT_Error pcf_get_metrics(FT_Stream stream,PCF_Face face)566 pcf_get_metrics( FT_Stream stream, 567 PCF_Face face ) 568 { 569 FT_Error error; 570 FT_Memory memory = FT_FACE( face )->memory; 571 FT_ULong format, size; 572 PCF_Metric metrics = 0; 573 FT_ULong nmetrics, i; 574 575 576 error = pcf_seek_to_table_type( stream, 577 face->toc.tables, 578 face->toc.count, 579 PCF_METRICS, 580 &format, 581 &size ); 582 if ( error ) 583 return error; 584 585 if ( FT_READ_ULONG_LE( format ) ) 586 goto Bail; 587 588 if ( !PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) && 589 !PCF_FORMAT_MATCH( format, PCF_COMPRESSED_METRICS ) ) 590 return FT_THROW( Invalid_File_Format ); 591 592 if ( PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) ) 593 { 594 if ( PCF_BYTE_ORDER( format ) == MSBFirst ) 595 (void)FT_READ_ULONG( nmetrics ); 596 else 597 (void)FT_READ_ULONG_LE( nmetrics ); 598 } 599 else 600 { 601 if ( PCF_BYTE_ORDER( format ) == MSBFirst ) 602 (void)FT_READ_USHORT( nmetrics ); 603 else 604 (void)FT_READ_USHORT_LE( nmetrics ); 605 } 606 if ( error ) 607 return FT_THROW( Invalid_File_Format ); 608 609 face->nmetrics = nmetrics; 610 611 if ( !nmetrics ) 612 return FT_THROW( Invalid_Table ); 613 614 FT_TRACE4(( "pcf_get_metrics:\n" )); 615 616 FT_TRACE4(( " number of metrics: %d\n", nmetrics )); 617 618 /* rough estimate */ 619 if ( PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) ) 620 { 621 if ( nmetrics > size / PCF_METRIC_SIZE ) 622 return FT_THROW( Invalid_Table ); 623 } 624 else 625 { 626 if ( nmetrics > size / PCF_COMPRESSED_METRIC_SIZE ) 627 return FT_THROW( Invalid_Table ); 628 } 629 630 if ( FT_NEW_ARRAY( face->metrics, nmetrics ) ) 631 return FT_THROW( Out_Of_Memory ); 632 633 metrics = face->metrics; 634 for ( i = 0; i < nmetrics; i++ ) 635 { 636 error = pcf_get_metric( stream, format, metrics + i ); 637 638 metrics[i].bits = 0; 639 640 FT_TRACE5(( " idx %d: width=%d, " 641 "lsb=%d, rsb=%d, ascent=%d, descent=%d, swidth=%d\n", 642 i, 643 ( metrics + i )->characterWidth, 644 ( metrics + i )->leftSideBearing, 645 ( metrics + i )->rightSideBearing, 646 ( metrics + i )->ascent, 647 ( metrics + i )->descent, 648 ( metrics + i )->attributes )); 649 650 if ( error ) 651 break; 652 } 653 654 if ( error ) 655 FT_FREE( face->metrics ); 656 657 Bail: 658 return error; 659 } 660 661 662 static FT_Error pcf_get_bitmaps(FT_Stream stream,PCF_Face face)663 pcf_get_bitmaps( FT_Stream stream, 664 PCF_Face face ) 665 { 666 FT_Error error; 667 FT_Memory memory = FT_FACE( face )->memory; 668 FT_Long* offsets = NULL; 669 FT_Long bitmapSizes[GLYPHPADOPTIONS]; 670 FT_ULong format, size; 671 FT_ULong nbitmaps, i, sizebitmaps = 0; 672 673 674 error = pcf_seek_to_table_type( stream, 675 face->toc.tables, 676 face->toc.count, 677 PCF_BITMAPS, 678 &format, 679 &size ); 680 if ( error ) 681 return error; 682 683 error = FT_Stream_EnterFrame( stream, 8 ); 684 if ( error ) 685 return error; 686 687 format = FT_GET_ULONG_LE(); 688 if ( PCF_BYTE_ORDER( format ) == MSBFirst ) 689 nbitmaps = FT_GET_ULONG(); 690 else 691 nbitmaps = FT_GET_ULONG_LE(); 692 693 FT_Stream_ExitFrame( stream ); 694 695 if ( !PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) ) 696 return FT_THROW( Invalid_File_Format ); 697 698 FT_TRACE4(( "pcf_get_bitmaps:\n" )); 699 700 FT_TRACE4(( " number of bitmaps: %d\n", nbitmaps )); 701 702 /* XXX: PCF_Face->nmetrics is singed FT_Long, see pcf.h */ 703 if ( face->nmetrics < 0 || nbitmaps != ( FT_ULong )face->nmetrics ) 704 return FT_THROW( Invalid_File_Format ); 705 706 if ( FT_NEW_ARRAY( offsets, nbitmaps ) ) 707 return error; 708 709 for ( i = 0; i < nbitmaps; i++ ) 710 { 711 if ( PCF_BYTE_ORDER( format ) == MSBFirst ) 712 (void)FT_READ_LONG( offsets[i] ); 713 else 714 (void)FT_READ_LONG_LE( offsets[i] ); 715 716 FT_TRACE5(( " bitmap %d: offset %ld (0x%lX)\n", 717 i, offsets[i], offsets[i] )); 718 } 719 if ( error ) 720 goto Bail; 721 722 for ( i = 0; i < GLYPHPADOPTIONS; i++ ) 723 { 724 if ( PCF_BYTE_ORDER( format ) == MSBFirst ) 725 (void)FT_READ_LONG( bitmapSizes[i] ); 726 else 727 (void)FT_READ_LONG_LE( bitmapSizes[i] ); 728 if ( error ) 729 goto Bail; 730 731 sizebitmaps = bitmapSizes[PCF_GLYPH_PAD_INDEX( format )]; 732 733 FT_TRACE4(( " padding %d implies a size of %ld\n", i, bitmapSizes[i] )); 734 } 735 736 FT_TRACE4(( " %d bitmaps, padding index %ld\n", 737 nbitmaps, 738 PCF_GLYPH_PAD_INDEX( format ) )); 739 FT_TRACE4(( " bitmap size = %d\n", sizebitmaps )); 740 741 FT_UNUSED( sizebitmaps ); /* only used for debugging */ 742 743 for ( i = 0; i < nbitmaps; i++ ) 744 { 745 /* rough estimate */ 746 if ( ( offsets[i] < 0 ) || 747 ( (FT_ULong)offsets[i] > size ) ) 748 { 749 FT_TRACE0(( "pcf_get_bitmaps:" 750 " invalid offset to bitmap data of glyph %d\n", i )); 751 } 752 else 753 face->metrics[i].bits = stream->pos + offsets[i]; 754 } 755 756 face->bitmapsFormat = format; 757 758 Bail: 759 FT_FREE( offsets ); 760 return error; 761 } 762 763 764 static FT_Error pcf_get_encodings(FT_Stream stream,PCF_Face face)765 pcf_get_encodings( FT_Stream stream, 766 PCF_Face face ) 767 { 768 FT_Error error; 769 FT_Memory memory = FT_FACE( face )->memory; 770 FT_ULong format, size; 771 int firstCol, lastCol; 772 int firstRow, lastRow; 773 int nencoding, encodingOffset; 774 int i, j, k; 775 PCF_Encoding encoding = NULL; 776 777 778 error = pcf_seek_to_table_type( stream, 779 face->toc.tables, 780 face->toc.count, 781 PCF_BDF_ENCODINGS, 782 &format, 783 &size ); 784 if ( error ) 785 return error; 786 787 error = FT_Stream_EnterFrame( stream, 14 ); 788 if ( error ) 789 return error; 790 791 format = FT_GET_ULONG_LE(); 792 793 if ( PCF_BYTE_ORDER( format ) == MSBFirst ) 794 { 795 firstCol = FT_GET_SHORT(); 796 lastCol = FT_GET_SHORT(); 797 firstRow = FT_GET_SHORT(); 798 lastRow = FT_GET_SHORT(); 799 face->defaultChar = FT_GET_SHORT(); 800 } 801 else 802 { 803 firstCol = FT_GET_SHORT_LE(); 804 lastCol = FT_GET_SHORT_LE(); 805 firstRow = FT_GET_SHORT_LE(); 806 lastRow = FT_GET_SHORT_LE(); 807 face->defaultChar = FT_GET_SHORT_LE(); 808 } 809 810 FT_Stream_ExitFrame( stream ); 811 812 if ( !PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) ) 813 return FT_THROW( Invalid_File_Format ); 814 815 FT_TRACE4(( "pdf_get_encodings:\n" )); 816 817 FT_TRACE4(( " firstCol %d, lastCol %d, firstRow %d, lastRow %d\n", 818 firstCol, lastCol, firstRow, lastRow )); 819 820 nencoding = ( lastCol - firstCol + 1 ) * ( lastRow - firstRow + 1 ); 821 822 if ( FT_NEW_ARRAY( encoding, nencoding ) ) 823 return FT_THROW( Out_Of_Memory ); 824 825 error = FT_Stream_EnterFrame( stream, 2 * nencoding ); 826 if ( error ) 827 goto Bail; 828 829 k = 0; 830 for ( i = firstRow; i <= lastRow; i++ ) 831 { 832 for ( j = firstCol; j <= lastCol; j++ ) 833 { 834 if ( PCF_BYTE_ORDER( format ) == MSBFirst ) 835 encodingOffset = FT_GET_SHORT(); 836 else 837 encodingOffset = FT_GET_SHORT_LE(); 838 839 if ( encodingOffset != -1 ) 840 { 841 encoding[k].enc = i * 256 + j; 842 encoding[k].glyph = (FT_Short)encodingOffset; 843 844 FT_TRACE5(( " code %d (0x%04X): idx %d\n", 845 encoding[k].enc, encoding[k].enc, encoding[k].glyph )); 846 847 k++; 848 } 849 } 850 } 851 FT_Stream_ExitFrame( stream ); 852 853 if ( FT_RENEW_ARRAY( encoding, nencoding, k ) ) 854 goto Bail; 855 856 face->nencodings = k; 857 face->encodings = encoding; 858 859 return error; 860 861 Bail: 862 FT_FREE( encoding ); 863 return error; 864 } 865 866 867 static 868 const FT_Frame_Field pcf_accel_header[] = 869 { 870 #undef FT_STRUCTURE 871 #define FT_STRUCTURE PCF_AccelRec 872 873 FT_FRAME_START( 20 ), 874 FT_FRAME_BYTE ( noOverlap ), 875 FT_FRAME_BYTE ( constantMetrics ), 876 FT_FRAME_BYTE ( terminalFont ), 877 FT_FRAME_BYTE ( constantWidth ), 878 FT_FRAME_BYTE ( inkInside ), 879 FT_FRAME_BYTE ( inkMetrics ), 880 FT_FRAME_BYTE ( drawDirection ), 881 FT_FRAME_SKIP_BYTES( 1 ), 882 FT_FRAME_LONG_LE ( fontAscent ), 883 FT_FRAME_LONG_LE ( fontDescent ), 884 FT_FRAME_LONG_LE ( maxOverlap ), 885 FT_FRAME_END 886 }; 887 888 889 static 890 const FT_Frame_Field pcf_accel_msb_header[] = 891 { 892 #undef FT_STRUCTURE 893 #define FT_STRUCTURE PCF_AccelRec 894 895 FT_FRAME_START( 20 ), 896 FT_FRAME_BYTE ( noOverlap ), 897 FT_FRAME_BYTE ( constantMetrics ), 898 FT_FRAME_BYTE ( terminalFont ), 899 FT_FRAME_BYTE ( constantWidth ), 900 FT_FRAME_BYTE ( inkInside ), 901 FT_FRAME_BYTE ( inkMetrics ), 902 FT_FRAME_BYTE ( drawDirection ), 903 FT_FRAME_SKIP_BYTES( 1 ), 904 FT_FRAME_LONG ( fontAscent ), 905 FT_FRAME_LONG ( fontDescent ), 906 FT_FRAME_LONG ( maxOverlap ), 907 FT_FRAME_END 908 }; 909 910 911 static FT_Error pcf_get_accel(FT_Stream stream,PCF_Face face,FT_ULong type)912 pcf_get_accel( FT_Stream stream, 913 PCF_Face face, 914 FT_ULong type ) 915 { 916 FT_ULong format, size; 917 FT_Error error; 918 PCF_Accel accel = &face->accel; 919 920 921 error = pcf_seek_to_table_type( stream, 922 face->toc.tables, 923 face->toc.count, 924 type, 925 &format, 926 &size ); 927 if ( error ) 928 goto Bail; 929 930 if ( FT_READ_ULONG_LE( format ) ) 931 goto Bail; 932 933 if ( !PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) && 934 !PCF_FORMAT_MATCH( format, PCF_ACCEL_W_INKBOUNDS ) ) 935 goto Bail; 936 937 if ( PCF_BYTE_ORDER( format ) == MSBFirst ) 938 { 939 if ( FT_STREAM_READ_FIELDS( pcf_accel_msb_header, accel ) ) 940 goto Bail; 941 } 942 else 943 { 944 if ( FT_STREAM_READ_FIELDS( pcf_accel_header, accel ) ) 945 goto Bail; 946 } 947 948 error = pcf_get_metric( stream, 949 format & ( ~PCF_FORMAT_MASK ), 950 &(accel->minbounds) ); 951 if ( error ) 952 goto Bail; 953 954 error = pcf_get_metric( stream, 955 format & ( ~PCF_FORMAT_MASK ), 956 &(accel->maxbounds) ); 957 if ( error ) 958 goto Bail; 959 960 if ( PCF_FORMAT_MATCH( format, PCF_ACCEL_W_INKBOUNDS ) ) 961 { 962 error = pcf_get_metric( stream, 963 format & ( ~PCF_FORMAT_MASK ), 964 &(accel->ink_minbounds) ); 965 if ( error ) 966 goto Bail; 967 968 error = pcf_get_metric( stream, 969 format & ( ~PCF_FORMAT_MASK ), 970 &(accel->ink_maxbounds) ); 971 if ( error ) 972 goto Bail; 973 } 974 else 975 { 976 accel->ink_minbounds = accel->minbounds; /* I'm not sure about this */ 977 accel->ink_maxbounds = accel->maxbounds; 978 } 979 980 Bail: 981 return error; 982 } 983 984 985 static FT_Error pcf_interpret_style(PCF_Face pcf)986 pcf_interpret_style( PCF_Face pcf ) 987 { 988 FT_Error error = FT_Err_Ok; 989 FT_Face face = FT_FACE( pcf ); 990 FT_Memory memory = face->memory; 991 992 PCF_Property prop; 993 994 size_t nn, len; 995 char* strings[4] = { NULL, NULL, NULL, NULL }; 996 size_t lengths[4]; 997 998 999 face->style_flags = 0; 1000 1001 prop = pcf_find_property( pcf, "SLANT" ); 1002 if ( prop && prop->isString && 1003 ( *(prop->value.atom) == 'O' || *(prop->value.atom) == 'o' || 1004 *(prop->value.atom) == 'I' || *(prop->value.atom) == 'i' ) ) 1005 { 1006 face->style_flags |= FT_STYLE_FLAG_ITALIC; 1007 strings[2] = ( *(prop->value.atom) == 'O' || 1008 *(prop->value.atom) == 'o' ) ? (char *)"Oblique" 1009 : (char *)"Italic"; 1010 } 1011 1012 prop = pcf_find_property( pcf, "WEIGHT_NAME" ); 1013 if ( prop && prop->isString && 1014 ( *(prop->value.atom) == 'B' || *(prop->value.atom) == 'b' ) ) 1015 { 1016 face->style_flags |= FT_STYLE_FLAG_BOLD; 1017 strings[1] = (char*)"Bold"; 1018 } 1019 1020 prop = pcf_find_property( pcf, "SETWIDTH_NAME" ); 1021 if ( prop && prop->isString && 1022 *(prop->value.atom) && 1023 !( *(prop->value.atom) == 'N' || *(prop->value.atom) == 'n' ) ) 1024 strings[3] = (char*)( prop->value.atom ); 1025 1026 prop = pcf_find_property( pcf, "ADD_STYLE_NAME" ); 1027 if ( prop && prop->isString && 1028 *(prop->value.atom) && 1029 !( *(prop->value.atom) == 'N' || *(prop->value.atom) == 'n' ) ) 1030 strings[0] = (char*)( prop->value.atom ); 1031 1032 for ( len = 0, nn = 0; nn < 4; nn++ ) 1033 { 1034 lengths[nn] = 0; 1035 if ( strings[nn] ) 1036 { 1037 lengths[nn] = ft_strlen( strings[nn] ); 1038 len += lengths[nn] + 1; 1039 } 1040 } 1041 1042 if ( len == 0 ) 1043 { 1044 strings[0] = (char*)"Regular"; 1045 lengths[0] = ft_strlen( strings[0] ); 1046 len = lengths[0] + 1; 1047 } 1048 1049 { 1050 char* s; 1051 1052 1053 if ( FT_ALLOC( face->style_name, len ) ) 1054 return error; 1055 1056 s = face->style_name; 1057 1058 for ( nn = 0; nn < 4; nn++ ) 1059 { 1060 char* src = strings[nn]; 1061 1062 1063 len = lengths[nn]; 1064 1065 if ( src == NULL ) 1066 continue; 1067 1068 /* separate elements with a space */ 1069 if ( s != face->style_name ) 1070 *s++ = ' '; 1071 1072 ft_memcpy( s, src, len ); 1073 1074 /* need to convert spaces to dashes for */ 1075 /* add_style_name and setwidth_name */ 1076 if ( nn == 0 || nn == 3 ) 1077 { 1078 size_t mm; 1079 1080 1081 for ( mm = 0; mm < len; mm++ ) 1082 if ( s[mm] == ' ' ) 1083 s[mm] = '-'; 1084 } 1085 1086 s += len; 1087 } 1088 *s = 0; 1089 } 1090 1091 return error; 1092 } 1093 1094 1095 FT_LOCAL_DEF( FT_Error ) pcf_load_font(FT_Stream stream,PCF_Face face)1096 pcf_load_font( FT_Stream stream, 1097 PCF_Face face ) 1098 { 1099 FT_Error error; 1100 FT_Memory memory = FT_FACE( face )->memory; 1101 FT_Bool hasBDFAccelerators; 1102 1103 1104 error = pcf_read_TOC( stream, face ); 1105 if ( error ) 1106 goto Exit; 1107 1108 error = pcf_get_properties( stream, face ); 1109 if ( error ) 1110 goto Exit; 1111 1112 /* Use the old accelerators if no BDF accelerators are in the file. */ 1113 hasBDFAccelerators = pcf_has_table_type( face->toc.tables, 1114 face->toc.count, 1115 PCF_BDF_ACCELERATORS ); 1116 if ( !hasBDFAccelerators ) 1117 { 1118 error = pcf_get_accel( stream, face, PCF_ACCELERATORS ); 1119 if ( error ) 1120 goto Exit; 1121 } 1122 1123 /* metrics */ 1124 error = pcf_get_metrics( stream, face ); 1125 if ( error ) 1126 goto Exit; 1127 1128 /* bitmaps */ 1129 error = pcf_get_bitmaps( stream, face ); 1130 if ( error ) 1131 goto Exit; 1132 1133 /* encodings */ 1134 error = pcf_get_encodings( stream, face ); 1135 if ( error ) 1136 goto Exit; 1137 1138 /* BDF style accelerators (i.e. bounds based on encoded glyphs) */ 1139 if ( hasBDFAccelerators ) 1140 { 1141 error = pcf_get_accel( stream, face, PCF_BDF_ACCELERATORS ); 1142 if ( error ) 1143 goto Exit; 1144 } 1145 1146 /* XXX: TO DO: inkmetrics and glyph_names are missing */ 1147 1148 /* now construct the face object */ 1149 { 1150 FT_Face root = FT_FACE( face ); 1151 PCF_Property prop; 1152 1153 1154 root->num_faces = 1; 1155 root->face_index = 0; 1156 1157 root->face_flags |= FT_FACE_FLAG_FIXED_SIZES | 1158 FT_FACE_FLAG_HORIZONTAL | 1159 FT_FACE_FLAG_FAST_GLYPHS; 1160 1161 if ( face->accel.constantWidth ) 1162 root->face_flags |= FT_FACE_FLAG_FIXED_WIDTH; 1163 1164 if ( ( error = pcf_interpret_style( face ) ) != 0 ) 1165 goto Exit; 1166 1167 prop = pcf_find_property( face, "FAMILY_NAME" ); 1168 if ( prop && prop->isString ) 1169 { 1170 if ( FT_STRDUP( root->family_name, prop->value.atom ) ) 1171 goto Exit; 1172 } 1173 else 1174 root->family_name = NULL; 1175 1176 /* 1177 * Note: We shift all glyph indices by +1 since we must 1178 * respect the convention that glyph 0 always corresponds 1179 * to the `missing glyph'. 1180 * 1181 * This implies bumping the number of `available' glyphs by 1. 1182 */ 1183 root->num_glyphs = face->nmetrics + 1; 1184 1185 root->num_fixed_sizes = 1; 1186 if ( FT_NEW_ARRAY( root->available_sizes, 1 ) ) 1187 goto Exit; 1188 1189 { 1190 FT_Bitmap_Size* bsize = root->available_sizes; 1191 FT_Short resolution_x = 0, resolution_y = 0; 1192 1193 1194 FT_MEM_ZERO( bsize, sizeof ( FT_Bitmap_Size ) ); 1195 1196 #if 0 1197 bsize->height = face->accel.maxbounds.ascent << 6; 1198 #endif 1199 bsize->height = (FT_Short)( face->accel.fontAscent + 1200 face->accel.fontDescent ); 1201 1202 prop = pcf_find_property( face, "AVERAGE_WIDTH" ); 1203 if ( prop ) 1204 bsize->width = (FT_Short)( ( prop->value.l + 5 ) / 10 ); 1205 else 1206 bsize->width = (FT_Short)( bsize->height * 2/3 ); 1207 1208 prop = pcf_find_property( face, "POINT_SIZE" ); 1209 if ( prop ) 1210 /* convert from 722.7 decipoints to 72 points per inch */ 1211 bsize->size = 1212 (FT_Pos)( ( prop->value.l * 64 * 7200 + 36135L ) / 72270L ); 1213 1214 prop = pcf_find_property( face, "PIXEL_SIZE" ); 1215 if ( prop ) 1216 bsize->y_ppem = (FT_Short)prop->value.l << 6; 1217 1218 prop = pcf_find_property( face, "RESOLUTION_X" ); 1219 if ( prop ) 1220 resolution_x = (FT_Short)prop->value.l; 1221 1222 prop = pcf_find_property( face, "RESOLUTION_Y" ); 1223 if ( prop ) 1224 resolution_y = (FT_Short)prop->value.l; 1225 1226 if ( bsize->y_ppem == 0 ) 1227 { 1228 bsize->y_ppem = bsize->size; 1229 if ( resolution_y ) 1230 bsize->y_ppem = bsize->y_ppem * resolution_y / 72; 1231 } 1232 if ( resolution_x && resolution_y ) 1233 bsize->x_ppem = bsize->y_ppem * resolution_x / resolution_y; 1234 else 1235 bsize->x_ppem = bsize->y_ppem; 1236 } 1237 1238 /* set up charset */ 1239 { 1240 PCF_Property charset_registry = 0, charset_encoding = 0; 1241 1242 1243 charset_registry = pcf_find_property( face, "CHARSET_REGISTRY" ); 1244 charset_encoding = pcf_find_property( face, "CHARSET_ENCODING" ); 1245 1246 if ( charset_registry && charset_registry->isString && 1247 charset_encoding && charset_encoding->isString ) 1248 { 1249 if ( FT_STRDUP( face->charset_encoding, 1250 charset_encoding->value.atom ) || 1251 FT_STRDUP( face->charset_registry, 1252 charset_registry->value.atom ) ) 1253 goto Exit; 1254 } 1255 } 1256 } 1257 1258 Exit: 1259 if ( error ) 1260 { 1261 /* This is done to respect the behaviour of the original */ 1262 /* PCF font driver. */ 1263 error = FT_THROW( Invalid_File_Format ); 1264 } 1265 1266 return error; 1267 } 1268 1269 1270 /* END */ 1271