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