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