1 /* bdfdrivr.c 2 3 FreeType font driver for bdf files 4 5 Copyright (C) 2001-2008, 2011, 2013, 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 #include <ft2build.h> 28 29 #include FT_INTERNAL_DEBUG_H 30 #include FT_INTERNAL_STREAM_H 31 #include FT_INTERNAL_OBJECTS_H 32 #include FT_BDF_H 33 #include FT_TRUETYPE_IDS_H 34 35 #include FT_SERVICE_BDF_H 36 #include FT_SERVICE_FONT_FORMAT_H 37 38 #include "bdf.h" 39 #include "bdfdrivr.h" 40 41 #include "bdferror.h" 42 43 44 /*************************************************************************/ 45 /* */ 46 /* The macro FT_COMPONENT is used in trace mode. It is an implicit */ 47 /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */ 48 /* messages during execution. */ 49 /* */ 50 #undef FT_COMPONENT 51 #define FT_COMPONENT trace_bdfdriver 52 53 54 typedef struct BDF_CMapRec_ 55 { 56 FT_CMapRec cmap; 57 FT_ULong num_encodings; /* ftobjs.h: FT_CMap->clazz->size */ 58 BDF_encoding_el* encodings; 59 60 } BDF_CMapRec, *BDF_CMap; 61 62 63 FT_CALLBACK_DEF( FT_Error ) bdf_cmap_init(FT_CMap bdfcmap,FT_Pointer init_data)64 bdf_cmap_init( FT_CMap bdfcmap, 65 FT_Pointer init_data ) 66 { 67 BDF_CMap cmap = (BDF_CMap)bdfcmap; 68 BDF_Face face = (BDF_Face)FT_CMAP_FACE( cmap ); 69 FT_UNUSED( init_data ); 70 71 72 cmap->num_encodings = face->bdffont->glyphs_used; 73 cmap->encodings = face->en_table; 74 75 return FT_Err_Ok; 76 } 77 78 79 FT_CALLBACK_DEF( void ) bdf_cmap_done(FT_CMap bdfcmap)80 bdf_cmap_done( FT_CMap bdfcmap ) 81 { 82 BDF_CMap cmap = (BDF_CMap)bdfcmap; 83 84 85 cmap->encodings = NULL; 86 cmap->num_encodings = 0; 87 } 88 89 90 FT_CALLBACK_DEF( FT_UInt ) bdf_cmap_char_index(FT_CMap bdfcmap,FT_UInt32 charcode)91 bdf_cmap_char_index( FT_CMap bdfcmap, 92 FT_UInt32 charcode ) 93 { 94 BDF_CMap cmap = (BDF_CMap)bdfcmap; 95 BDF_encoding_el* encodings = cmap->encodings; 96 FT_ULong min, max, mid; /* num_encodings */ 97 FT_UShort result = 0; /* encodings->glyph */ 98 99 100 min = 0; 101 max = cmap->num_encodings; 102 103 while ( min < max ) 104 { 105 FT_ULong code; 106 107 108 mid = ( min + max ) >> 1; 109 code = (FT_ULong)encodings[mid].enc; 110 111 if ( charcode == code ) 112 { 113 /* increase glyph index by 1 -- */ 114 /* we reserve slot 0 for the undefined glyph */ 115 result = encodings[mid].glyph + 1; 116 break; 117 } 118 119 if ( charcode < code ) 120 max = mid; 121 else 122 min = mid + 1; 123 } 124 125 return result; 126 } 127 128 129 FT_CALLBACK_DEF( FT_UInt ) bdf_cmap_char_next(FT_CMap bdfcmap,FT_UInt32 * acharcode)130 bdf_cmap_char_next( FT_CMap bdfcmap, 131 FT_UInt32 *acharcode ) 132 { 133 BDF_CMap cmap = (BDF_CMap)bdfcmap; 134 BDF_encoding_el* encodings = cmap->encodings; 135 FT_ULong min, max, mid; /* num_encodings */ 136 FT_UShort result = 0; /* encodings->glyph */ 137 FT_ULong charcode = *acharcode + 1; 138 139 140 min = 0; 141 max = cmap->num_encodings; 142 143 while ( min < max ) 144 { 145 FT_ULong code; /* same as BDF_encoding_el.enc */ 146 147 148 mid = ( min + max ) >> 1; 149 code = (FT_ULong)encodings[mid].enc; 150 151 if ( charcode == code ) 152 { 153 /* increase glyph index by 1 -- */ 154 /* we reserve slot 0 for the undefined glyph */ 155 result = encodings[mid].glyph + 1; 156 goto Exit; 157 } 158 159 if ( charcode < code ) 160 max = mid; 161 else 162 min = mid + 1; 163 } 164 165 charcode = 0; 166 if ( min < cmap->num_encodings ) 167 { 168 charcode = (FT_ULong)encodings[min].enc; 169 result = encodings[min].glyph + 1; 170 } 171 172 Exit: 173 if ( charcode > 0xFFFFFFFFUL ) 174 { 175 FT_TRACE1(( "bdf_cmap_char_next: charcode 0x%x > 32bit API" )); 176 *acharcode = 0; 177 /* XXX: result should be changed to indicate an overflow error */ 178 } 179 else 180 *acharcode = (FT_UInt32)charcode; 181 return result; 182 } 183 184 185 static 186 const FT_CMap_ClassRec bdf_cmap_class = 187 { 188 sizeof ( BDF_CMapRec ), 189 bdf_cmap_init, 190 bdf_cmap_done, 191 bdf_cmap_char_index, 192 bdf_cmap_char_next, 193 194 NULL, NULL, NULL, NULL, NULL 195 }; 196 197 198 static FT_Error bdf_interpret_style(BDF_Face bdf)199 bdf_interpret_style( BDF_Face bdf ) 200 { 201 FT_Error error = FT_Err_Ok; 202 FT_Face face = FT_FACE( bdf ); 203 FT_Memory memory = face->memory; 204 bdf_font_t* font = bdf->bdffont; 205 bdf_property_t* prop; 206 207 char* strings[4] = { NULL, NULL, NULL, NULL }; 208 size_t nn, len, lengths[4]; 209 210 211 face->style_flags = 0; 212 213 prop = bdf_get_font_property( font, (char *)"SLANT" ); 214 if ( prop && prop->format == BDF_ATOM && 215 prop->value.atom && 216 ( *(prop->value.atom) == 'O' || *(prop->value.atom) == 'o' || 217 *(prop->value.atom) == 'I' || *(prop->value.atom) == 'i' ) ) 218 { 219 face->style_flags |= FT_STYLE_FLAG_ITALIC; 220 strings[2] = ( *(prop->value.atom) == 'O' || *(prop->value.atom) == 'o' ) 221 ? (char *)"Oblique" 222 : (char *)"Italic"; 223 } 224 225 prop = bdf_get_font_property( font, (char *)"WEIGHT_NAME" ); 226 if ( prop && prop->format == BDF_ATOM && 227 prop->value.atom && 228 ( *(prop->value.atom) == 'B' || *(prop->value.atom) == 'b' ) ) 229 { 230 face->style_flags |= FT_STYLE_FLAG_BOLD; 231 strings[1] = (char *)"Bold"; 232 } 233 234 prop = bdf_get_font_property( font, (char *)"SETWIDTH_NAME" ); 235 if ( prop && prop->format == BDF_ATOM && 236 prop->value.atom && *(prop->value.atom) && 237 !( *(prop->value.atom) == 'N' || *(prop->value.atom) == 'n' ) ) 238 strings[3] = (char *)(prop->value.atom); 239 240 prop = bdf_get_font_property( font, (char *)"ADD_STYLE_NAME" ); 241 if ( prop && prop->format == BDF_ATOM && 242 prop->value.atom && *(prop->value.atom) && 243 !( *(prop->value.atom) == 'N' || *(prop->value.atom) == 'n' ) ) 244 strings[0] = (char *)(prop->value.atom); 245 246 for ( len = 0, nn = 0; nn < 4; nn++ ) 247 { 248 lengths[nn] = 0; 249 if ( strings[nn] ) 250 { 251 lengths[nn] = ft_strlen( strings[nn] ); 252 len += lengths[nn] + 1; 253 } 254 } 255 256 if ( len == 0 ) 257 { 258 strings[0] = (char *)"Regular"; 259 lengths[0] = ft_strlen( strings[0] ); 260 len = lengths[0] + 1; 261 } 262 263 { 264 char* s; 265 266 267 if ( FT_ALLOC( face->style_name, len ) ) 268 return error; 269 270 s = face->style_name; 271 272 for ( nn = 0; nn < 4; nn++ ) 273 { 274 char* src = strings[nn]; 275 276 277 len = lengths[nn]; 278 279 if ( !src ) 280 continue; 281 282 /* separate elements with a space */ 283 if ( s != face->style_name ) 284 *s++ = ' '; 285 286 ft_memcpy( s, src, len ); 287 288 /* need to convert spaces to dashes for */ 289 /* add_style_name and setwidth_name */ 290 if ( nn == 0 || nn == 3 ) 291 { 292 size_t mm; 293 294 295 for ( mm = 0; mm < len; mm++ ) 296 if ( s[mm] == ' ' ) 297 s[mm] = '-'; 298 } 299 300 s += len; 301 } 302 *s = 0; 303 } 304 305 return error; 306 } 307 308 309 FT_CALLBACK_DEF( void ) BDF_Face_Done(FT_Face bdfface)310 BDF_Face_Done( FT_Face bdfface ) /* BDF_Face */ 311 { 312 BDF_Face face = (BDF_Face)bdfface; 313 FT_Memory memory; 314 315 316 if ( !face ) 317 return; 318 319 memory = FT_FACE_MEMORY( face ); 320 321 bdf_free_font( face->bdffont ); 322 323 FT_FREE( face->en_table ); 324 325 FT_FREE( face->charset_encoding ); 326 FT_FREE( face->charset_registry ); 327 FT_FREE( bdfface->family_name ); 328 FT_FREE( bdfface->style_name ); 329 330 FT_FREE( bdfface->available_sizes ); 331 332 FT_FREE( face->bdffont ); 333 } 334 335 336 FT_CALLBACK_DEF( FT_Error ) BDF_Face_Init(FT_Stream stream,FT_Face bdfface,FT_Int face_index,FT_Int num_params,FT_Parameter * params)337 BDF_Face_Init( FT_Stream stream, 338 FT_Face bdfface, /* BDF_Face */ 339 FT_Int face_index, 340 FT_Int num_params, 341 FT_Parameter* params ) 342 { 343 FT_Error error = FT_Err_Ok; 344 BDF_Face face = (BDF_Face)bdfface; 345 FT_Memory memory = FT_FACE_MEMORY( face ); 346 347 bdf_font_t* font = NULL; 348 bdf_options_t options; 349 350 FT_UNUSED( num_params ); 351 FT_UNUSED( params ); 352 353 354 FT_TRACE2(( "BDF driver\n" )); 355 356 if ( FT_STREAM_SEEK( 0 ) ) 357 goto Exit; 358 359 options.correct_metrics = 1; /* FZ XXX: options semantics */ 360 options.keep_unencoded = 1; 361 options.keep_comments = 0; 362 options.font_spacing = BDF_PROPORTIONAL; 363 364 error = bdf_load_font( stream, memory, &options, &font ); 365 if ( FT_ERR_EQ( error, Missing_Startfont_Field ) ) 366 { 367 FT_TRACE2(( " not a BDF file\n" )); 368 goto Fail; 369 } 370 else if ( error ) 371 goto Exit; 372 373 /* we have a bdf font: let's construct the face object */ 374 face->bdffont = font; 375 376 /* BDF cannot have multiple faces in a single font file. 377 * XXX: non-zero face_index is already invalid argument, but 378 * Type1, Type42 driver has a convention to return 379 * an invalid argument error when the font could be 380 * opened by the specified driver. 381 */ 382 if ( face_index > 0 && ( face_index & 0xFFFF ) > 0 ) 383 { 384 FT_ERROR(( "BDF_Face_Init: invalid face index\n" )); 385 BDF_Face_Done( bdfface ); 386 return FT_THROW( Invalid_Argument ); 387 } 388 389 { 390 bdf_property_t* prop = NULL; 391 392 393 FT_TRACE4(( " number of glyphs: allocated %d (used %d)\n", 394 font->glyphs_size, 395 font->glyphs_used )); 396 FT_TRACE4(( " number of unencoded glyphs: allocated %d (used %d)\n", 397 font->unencoded_size, 398 font->unencoded_used )); 399 400 bdfface->num_faces = 1; 401 bdfface->face_index = 0; 402 403 bdfface->face_flags |= FT_FACE_FLAG_FIXED_SIZES | 404 FT_FACE_FLAG_HORIZONTAL | 405 FT_FACE_FLAG_FAST_GLYPHS; 406 407 prop = bdf_get_font_property( font, "SPACING" ); 408 if ( prop && prop->format == BDF_ATOM && 409 prop->value.atom && 410 ( *(prop->value.atom) == 'M' || *(prop->value.atom) == 'm' || 411 *(prop->value.atom) == 'C' || *(prop->value.atom) == 'c' ) ) 412 bdfface->face_flags |= FT_FACE_FLAG_FIXED_WIDTH; 413 414 /* FZ XXX: TO DO: FT_FACE_FLAGS_VERTICAL */ 415 /* FZ XXX: I need a font to implement this */ 416 417 prop = bdf_get_font_property( font, "FAMILY_NAME" ); 418 if ( prop && prop->value.atom ) 419 { 420 if ( FT_STRDUP( bdfface->family_name, prop->value.atom ) ) 421 goto Exit; 422 } 423 else 424 bdfface->family_name = NULL; 425 426 if ( FT_SET_ERROR( bdf_interpret_style( face ) ) ) 427 goto Exit; 428 429 /* the number of glyphs (with one slot for the undefined glyph */ 430 /* at position 0 and all unencoded glyphs) */ 431 bdfface->num_glyphs = (FT_Long)( font->glyphs_size + 1 ); 432 433 bdfface->num_fixed_sizes = 1; 434 if ( FT_NEW_ARRAY( bdfface->available_sizes, 1 ) ) 435 goto Exit; 436 437 { 438 FT_Bitmap_Size* bsize = bdfface->available_sizes; 439 FT_Short resolution_x = 0, resolution_y = 0; 440 long value; 441 442 443 FT_ZERO( bsize ); 444 445 /* sanity checks */ 446 if ( font->font_ascent > 0x7FFF || font->font_ascent < -0x7FFF ) 447 { 448 font->font_ascent = font->font_ascent < 0 ? -0x7FFF : 0x7FFF; 449 FT_TRACE0(( "BDF_Face_Init: clamping font ascent to value %d\n", 450 font->font_ascent )); 451 } 452 if ( font->font_descent > 0x7FFF || font->font_descent < -0x7FFF ) 453 { 454 font->font_descent = font->font_descent < 0 ? -0x7FFF : 0x7FFF; 455 FT_TRACE0(( "BDF_Face_Init: clamping font descent to value %d\n", 456 font->font_descent )); 457 } 458 459 bsize->height = (FT_Short)( font->font_ascent + font->font_descent ); 460 461 prop = bdf_get_font_property( font, "AVERAGE_WIDTH" ); 462 if ( prop ) 463 { 464 #ifdef FT_DEBUG_LEVEL_TRACE 465 if ( prop->value.l < 0 ) 466 FT_TRACE0(( "BDF_Face_Init: negative average width\n" )); 467 #endif 468 if ( prop->value.l > 0x7FFFL * 10 - 5 || 469 prop->value.l < -( 0x7FFFL * 10 - 5 ) ) 470 { 471 bsize->width = 0x7FFF; 472 FT_TRACE0(( "BDF_Face_Init: clamping average width to value %d\n", 473 bsize->width )); 474 } 475 else 476 bsize->width = FT_ABS( (FT_Short)( ( prop->value.l + 5 ) / 10 ) ); 477 } 478 else 479 { 480 /* this is a heuristical value */ 481 bsize->width = (FT_Short)FT_MulDiv( bsize->height, 2, 3 ); 482 } 483 484 prop = bdf_get_font_property( font, "POINT_SIZE" ); 485 if ( prop ) 486 { 487 #ifdef FT_DEBUG_LEVEL_TRACE 488 if ( prop->value.l < 0 ) 489 FT_TRACE0(( "BDF_Face_Init: negative point size\n" )); 490 #endif 491 /* convert from 722.7 decipoints to 72 points per inch */ 492 if ( prop->value.l > 0x504C2L || /* 0x7FFF * 72270/7200 */ 493 prop->value.l < -0x504C2L ) 494 { 495 bsize->size = 0x7FFF; 496 FT_TRACE0(( "BDF_Face_Init: clamping point size to value %d\n", 497 bsize->size )); 498 } 499 else 500 bsize->size = FT_MulDiv( FT_ABS( prop->value.l ), 501 64 * 7200, 502 72270L ); 503 } 504 else if ( font->point_size ) 505 { 506 if ( font->point_size > 0x7FFF ) 507 { 508 bsize->size = 0x7FFF; 509 FT_TRACE0(( "BDF_Face_Init: clamping point size to value %d\n", 510 bsize->size )); 511 } 512 else 513 bsize->size = (FT_Pos)font->point_size << 6; 514 } 515 else 516 { 517 /* this is a heuristical value */ 518 bsize->size = bsize->width * 64; 519 } 520 521 prop = bdf_get_font_property( font, "PIXEL_SIZE" ); 522 if ( prop ) 523 { 524 #ifdef FT_DEBUG_LEVEL_TRACE 525 if ( prop->value.l < 0 ) 526 FT_TRACE0(( "BDF_Face_Init: negative pixel size\n" )); 527 #endif 528 if ( prop->value.l > 0x7FFF || prop->value.l < -0x7FFF ) 529 { 530 bsize->y_ppem = 0x7FFF << 6; 531 FT_TRACE0(( "BDF_Face_Init: clamping pixel size to value %d\n", 532 bsize->y_ppem )); 533 } 534 else 535 bsize->y_ppem = FT_ABS( (FT_Short)prop->value.l ) << 6; 536 } 537 538 prop = bdf_get_font_property( font, "RESOLUTION_X" ); 539 if ( prop ) 540 value = prop->value.l; 541 else 542 value = (long)font->resolution_x; 543 if ( value ) 544 { 545 #ifdef FT_DEBUG_LEVEL_TRACE 546 if ( value < 0 ) 547 FT_TRACE0(( "BDF_Face_Init: negative X resolution\n" )); 548 #endif 549 if ( value > 0x7FFF || value < -0x7FFF ) 550 { 551 resolution_x = 0x7FFF; 552 FT_TRACE0(( "BDF_Face_Init: clamping X resolution to value %d\n", 553 resolution_x )); 554 } 555 else 556 resolution_x = FT_ABS( (FT_Short)value ); 557 } 558 559 prop = bdf_get_font_property( font, "RESOLUTION_Y" ); 560 if ( prop ) 561 value = prop->value.l; 562 else 563 value = (long)font->resolution_y; 564 if ( value ) 565 { 566 #ifdef FT_DEBUG_LEVEL_TRACE 567 if ( value < 0 ) 568 FT_TRACE0(( "BDF_Face_Init: negative Y resolution\n" )); 569 #endif 570 if ( value > 0x7FFF || value < -0x7FFF ) 571 { 572 resolution_y = 0x7FFF; 573 FT_TRACE0(( "BDF_Face_Init: clamping Y resolution to value %d\n", 574 resolution_y )); 575 } 576 else 577 resolution_y = FT_ABS( (FT_Short)value ); 578 } 579 580 if ( bsize->y_ppem == 0 ) 581 { 582 bsize->y_ppem = bsize->size; 583 if ( resolution_y ) 584 bsize->y_ppem = FT_MulDiv( bsize->y_ppem, resolution_y, 72 ); 585 } 586 if ( resolution_x && resolution_y ) 587 bsize->x_ppem = FT_MulDiv( bsize->y_ppem, 588 resolution_x, 589 resolution_y ); 590 else 591 bsize->x_ppem = bsize->y_ppem; 592 } 593 594 /* encoding table */ 595 { 596 bdf_glyph_t* cur = font->glyphs; 597 unsigned long n; 598 599 600 if ( FT_NEW_ARRAY( face->en_table, font->glyphs_size ) ) 601 goto Exit; 602 603 face->default_glyph = 0; 604 for ( n = 0; n < font->glyphs_size; n++ ) 605 { 606 (face->en_table[n]).enc = cur[n].encoding; 607 FT_TRACE4(( " idx %d, val 0x%lX\n", n, cur[n].encoding )); 608 (face->en_table[n]).glyph = (FT_UShort)n; 609 610 if ( cur[n].encoding == font->default_char ) 611 { 612 if ( n < FT_UINT_MAX ) 613 face->default_glyph = (FT_UInt)n; 614 else 615 FT_TRACE1(( "BDF_Face_Init:" 616 " idx %d is too large for this system\n", n )); 617 } 618 } 619 } 620 621 /* charmaps */ 622 { 623 bdf_property_t *charset_registry, *charset_encoding; 624 FT_Bool unicode_charmap = 0; 625 626 627 charset_registry = 628 bdf_get_font_property( font, "CHARSET_REGISTRY" ); 629 charset_encoding = 630 bdf_get_font_property( font, "CHARSET_ENCODING" ); 631 if ( charset_registry && charset_encoding ) 632 { 633 if ( charset_registry->format == BDF_ATOM && 634 charset_encoding->format == BDF_ATOM && 635 charset_registry->value.atom && 636 charset_encoding->value.atom ) 637 { 638 const char* s; 639 640 641 if ( FT_STRDUP( face->charset_encoding, 642 charset_encoding->value.atom ) || 643 FT_STRDUP( face->charset_registry, 644 charset_registry->value.atom ) ) 645 goto Exit; 646 647 /* Uh, oh, compare first letters manually to avoid dependency */ 648 /* on locales. */ 649 s = face->charset_registry; 650 if ( ( s[0] == 'i' || s[0] == 'I' ) && 651 ( s[1] == 's' || s[1] == 'S' ) && 652 ( s[2] == 'o' || s[2] == 'O' ) ) 653 { 654 s += 3; 655 if ( !ft_strcmp( s, "10646" ) || 656 ( !ft_strcmp( s, "8859" ) && 657 !ft_strcmp( face->charset_encoding, "1" ) ) ) 658 unicode_charmap = 1; 659 /* another name for ASCII */ 660 else if ( !ft_strcmp( s, "646.1991" ) && 661 !ft_strcmp( face->charset_encoding, "IRV" ) ) 662 unicode_charmap = 1; 663 } 664 665 { 666 FT_CharMapRec charmap; 667 668 669 charmap.face = FT_FACE( face ); 670 charmap.encoding = FT_ENCODING_NONE; 671 /* initial platform/encoding should indicate unset status? */ 672 charmap.platform_id = TT_PLATFORM_APPLE_UNICODE; 673 charmap.encoding_id = TT_APPLE_ID_DEFAULT; 674 675 if ( unicode_charmap ) 676 { 677 charmap.encoding = FT_ENCODING_UNICODE; 678 charmap.platform_id = TT_PLATFORM_MICROSOFT; 679 charmap.encoding_id = TT_MS_ID_UNICODE_CS; 680 } 681 682 error = FT_CMap_New( &bdf_cmap_class, NULL, &charmap, NULL ); 683 } 684 685 goto Exit; 686 } 687 } 688 689 /* otherwise assume Adobe standard encoding */ 690 691 { 692 FT_CharMapRec charmap; 693 694 695 charmap.face = FT_FACE( face ); 696 charmap.encoding = FT_ENCODING_ADOBE_STANDARD; 697 charmap.platform_id = TT_PLATFORM_ADOBE; 698 charmap.encoding_id = TT_ADOBE_ID_STANDARD; 699 700 error = FT_CMap_New( &bdf_cmap_class, NULL, &charmap, NULL ); 701 702 /* Select default charmap */ 703 if ( bdfface->num_charmaps ) 704 bdfface->charmap = bdfface->charmaps[0]; 705 } 706 } 707 } 708 709 Exit: 710 return error; 711 712 Fail: 713 BDF_Face_Done( bdfface ); 714 return FT_THROW( Unknown_File_Format ); 715 } 716 717 718 FT_CALLBACK_DEF( FT_Error ) BDF_Size_Select(FT_Size size,FT_ULong strike_index)719 BDF_Size_Select( FT_Size size, 720 FT_ULong strike_index ) 721 { 722 bdf_font_t* bdffont = ( (BDF_Face)size->face )->bdffont; 723 724 725 FT_Select_Metrics( size->face, strike_index ); 726 727 size->metrics.ascender = bdffont->font_ascent * 64; 728 size->metrics.descender = -bdffont->font_descent * 64; 729 size->metrics.max_advance = bdffont->bbx.width * 64; 730 731 return FT_Err_Ok; 732 } 733 734 735 FT_CALLBACK_DEF( FT_Error ) BDF_Size_Request(FT_Size size,FT_Size_Request req)736 BDF_Size_Request( FT_Size size, 737 FT_Size_Request req ) 738 { 739 FT_Face face = size->face; 740 FT_Bitmap_Size* bsize = face->available_sizes; 741 bdf_font_t* bdffont = ( (BDF_Face)face )->bdffont; 742 FT_Error error = FT_ERR( Invalid_Pixel_Size ); 743 FT_Long height; 744 745 746 height = FT_REQUEST_HEIGHT( req ); 747 height = ( height + 32 ) >> 6; 748 749 switch ( req->type ) 750 { 751 case FT_SIZE_REQUEST_TYPE_NOMINAL: 752 if ( height == ( ( bsize->y_ppem + 32 ) >> 6 ) ) 753 error = FT_Err_Ok; 754 break; 755 756 case FT_SIZE_REQUEST_TYPE_REAL_DIM: 757 if ( height == ( bdffont->font_ascent + 758 bdffont->font_descent ) ) 759 error = FT_Err_Ok; 760 break; 761 762 default: 763 error = FT_THROW( Unimplemented_Feature ); 764 break; 765 } 766 767 if ( error ) 768 return error; 769 else 770 return BDF_Size_Select( size, 0 ); 771 } 772 773 774 775 FT_CALLBACK_DEF( FT_Error ) BDF_Glyph_Load(FT_GlyphSlot slot,FT_Size size,FT_UInt glyph_index,FT_Int32 load_flags)776 BDF_Glyph_Load( FT_GlyphSlot slot, 777 FT_Size size, 778 FT_UInt glyph_index, 779 FT_Int32 load_flags ) 780 { 781 BDF_Face bdf = (BDF_Face)FT_SIZE_FACE( size ); 782 FT_Face face = FT_FACE( bdf ); 783 FT_Error error = FT_Err_Ok; 784 FT_Bitmap* bitmap = &slot->bitmap; 785 bdf_glyph_t glyph; 786 int bpp = bdf->bdffont->bpp; 787 788 FT_UNUSED( load_flags ); 789 790 791 if ( !face ) 792 { 793 error = FT_THROW( Invalid_Face_Handle ); 794 goto Exit; 795 } 796 797 if ( glyph_index >= (FT_UInt)face->num_glyphs ) 798 { 799 error = FT_THROW( Invalid_Argument ); 800 goto Exit; 801 } 802 803 FT_TRACE1(( "BDF_Glyph_Load: glyph index %d\n", glyph_index )); 804 805 /* index 0 is the undefined glyph */ 806 if ( glyph_index == 0 ) 807 glyph_index = bdf->default_glyph; 808 else 809 glyph_index--; 810 811 /* slot, bitmap => freetype, glyph => bdflib */ 812 glyph = bdf->bdffont->glyphs[glyph_index]; 813 814 bitmap->rows = glyph.bbx.height; 815 bitmap->width = glyph.bbx.width; 816 if ( glyph.bpr > FT_INT_MAX ) 817 FT_TRACE1(( "BDF_Glyph_Load: too large pitch %d is truncated\n", 818 glyph.bpr )); 819 bitmap->pitch = (int)glyph.bpr; /* same as FT_Bitmap.pitch */ 820 821 /* note: we don't allocate a new array to hold the bitmap; */ 822 /* we can simply point to it */ 823 ft_glyphslot_set_bitmap( slot, glyph.bitmap ); 824 825 switch ( bpp ) 826 { 827 case 1: 828 bitmap->pixel_mode = FT_PIXEL_MODE_MONO; 829 break; 830 case 2: 831 bitmap->pixel_mode = FT_PIXEL_MODE_GRAY2; 832 break; 833 case 4: 834 bitmap->pixel_mode = FT_PIXEL_MODE_GRAY4; 835 break; 836 case 8: 837 bitmap->pixel_mode = FT_PIXEL_MODE_GRAY; 838 bitmap->num_grays = 256; 839 break; 840 } 841 842 slot->format = FT_GLYPH_FORMAT_BITMAP; 843 slot->bitmap_left = glyph.bbx.x_offset; 844 slot->bitmap_top = glyph.bbx.ascent; 845 846 slot->metrics.horiAdvance = (FT_Pos)( glyph.dwidth * 64 ); 847 slot->metrics.horiBearingX = (FT_Pos)( glyph.bbx.x_offset * 64 ); 848 slot->metrics.horiBearingY = (FT_Pos)( glyph.bbx.ascent * 64 ); 849 slot->metrics.width = (FT_Pos)( bitmap->width * 64 ); 850 slot->metrics.height = (FT_Pos)( bitmap->rows * 64 ); 851 852 /* 853 * XXX DWIDTH1 and VVECTOR should be parsed and 854 * used here, provided such fonts do exist. 855 */ 856 ft_synthesize_vertical_metrics( &slot->metrics, 857 bdf->bdffont->bbx.height * 64 ); 858 859 Exit: 860 return error; 861 } 862 863 864 /* 865 * 866 * BDF SERVICE 867 * 868 */ 869 870 static FT_Error bdf_get_bdf_property(BDF_Face face,const char * prop_name,BDF_PropertyRec * aproperty)871 bdf_get_bdf_property( BDF_Face face, 872 const char* prop_name, 873 BDF_PropertyRec *aproperty ) 874 { 875 bdf_property_t* prop; 876 877 878 FT_ASSERT( face && face->bdffont ); 879 880 prop = bdf_get_font_property( face->bdffont, prop_name ); 881 if ( prop ) 882 { 883 switch ( prop->format ) 884 { 885 case BDF_ATOM: 886 aproperty->type = BDF_PROPERTY_TYPE_ATOM; 887 aproperty->u.atom = prop->value.atom; 888 break; 889 890 case BDF_INTEGER: 891 if ( prop->value.l > 0x7FFFFFFFL || prop->value.l < ( -1 - 0x7FFFFFFFL ) ) 892 { 893 FT_TRACE1(( "bdf_get_bdf_property:" 894 " too large integer 0x%x is truncated\n" )); 895 } 896 aproperty->type = BDF_PROPERTY_TYPE_INTEGER; 897 aproperty->u.integer = (FT_Int32)prop->value.l; 898 break; 899 900 case BDF_CARDINAL: 901 if ( prop->value.ul > 0xFFFFFFFFUL ) 902 { 903 FT_TRACE1(( "bdf_get_bdf_property:" 904 " too large cardinal 0x%x is truncated\n" )); 905 } 906 aproperty->type = BDF_PROPERTY_TYPE_CARDINAL; 907 aproperty->u.cardinal = (FT_UInt32)prop->value.ul; 908 break; 909 910 default: 911 goto Fail; 912 } 913 return 0; 914 } 915 916 Fail: 917 return FT_THROW( Invalid_Argument ); 918 } 919 920 921 static FT_Error bdf_get_charset_id(BDF_Face face,const char ** acharset_encoding,const char ** acharset_registry)922 bdf_get_charset_id( BDF_Face face, 923 const char* *acharset_encoding, 924 const char* *acharset_registry ) 925 { 926 *acharset_encoding = face->charset_encoding; 927 *acharset_registry = face->charset_registry; 928 929 return 0; 930 } 931 932 933 static const FT_Service_BDFRec bdf_service_bdf = 934 { 935 (FT_BDF_GetCharsetIdFunc)bdf_get_charset_id, /* get_charset_id */ 936 (FT_BDF_GetPropertyFunc) bdf_get_bdf_property /* get_property */ 937 }; 938 939 940 /* 941 * 942 * SERVICES LIST 943 * 944 */ 945 946 static const FT_ServiceDescRec bdf_services[] = 947 { 948 { FT_SERVICE_ID_BDF, &bdf_service_bdf }, 949 { FT_SERVICE_ID_FONT_FORMAT, FT_FONT_FORMAT_BDF }, 950 { NULL, NULL } 951 }; 952 953 954 FT_CALLBACK_DEF( FT_Module_Interface ) bdf_driver_requester(FT_Module module,const char * name)955 bdf_driver_requester( FT_Module module, 956 const char* name ) 957 { 958 FT_UNUSED( module ); 959 960 return ft_service_list_lookup( bdf_services, name ); 961 } 962 963 964 965 FT_CALLBACK_TABLE_DEF 966 const FT_Driver_ClassRec bdf_driver_class = 967 { 968 { 969 FT_MODULE_FONT_DRIVER | 970 FT_MODULE_DRIVER_NO_OUTLINES, 971 sizeof ( FT_DriverRec ), 972 973 "bdf", 974 0x10000L, 975 0x20000L, 976 977 NULL, /* module-specific interface */ 978 979 NULL, /* FT_Module_Constructor module_init */ 980 NULL, /* FT_Module_Destructor module_done */ 981 bdf_driver_requester /* FT_Module_Requester get_interface */ 982 }, 983 984 sizeof ( BDF_FaceRec ), 985 sizeof ( FT_SizeRec ), 986 sizeof ( FT_GlyphSlotRec ), 987 988 BDF_Face_Init, /* FT_Face_InitFunc init_face */ 989 BDF_Face_Done, /* FT_Face_DoneFunc done_face */ 990 NULL, /* FT_Size_InitFunc init_size */ 991 NULL, /* FT_Size_DoneFunc done_size */ 992 NULL, /* FT_Slot_InitFunc init_slot */ 993 NULL, /* FT_Slot_DoneFunc done_slot */ 994 995 BDF_Glyph_Load, /* FT_Slot_LoadFunc load_glyph */ 996 997 NULL, /* FT_Face_GetKerningFunc get_kerning */ 998 NULL, /* FT_Face_AttachFunc attach_file */ 999 NULL, /* FT_Face_GetAdvancesFunc get_advances */ 1000 1001 BDF_Size_Request, /* FT_Size_RequestFunc request_size */ 1002 BDF_Size_Select /* FT_Size_SelectFunc select_size */ 1003 }; 1004 1005 1006 /* END */ 1007