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 ) bdf_cmap_init(FT_CMap bdfcmap,FT_Pointer init_data)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 ) bdf_cmap_done(FT_CMap bdfcmap)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 ) bdf_cmap_char_index(FT_CMap bdfcmap,FT_UInt32 charcode)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_ULong min, max, mid; /* num_encodings */ 96 FT_UShort result = 0; /* encodings->glyph */ 97 98 99 min = 0; 100 max = cmap->num_encodings; 101 mid = ( min + max ) >> 1; 102 103 while ( min < max ) 104 { 105 FT_ULong code; 106 107 108 if ( mid >= max || mid < min ) 109 mid = ( min + max ) >> 1; 110 111 code = encodings[mid].enc; 112 113 if ( charcode == code ) 114 { 115 /* increase glyph index by 1 -- */ 116 /* we reserve slot 0 for the undefined glyph */ 117 result = encodings[mid].glyph + 1; 118 break; 119 } 120 121 if ( charcode < code ) 122 max = mid; 123 else 124 min = mid + 1; 125 126 /* prediction in a continuous block */ 127 mid += charcode - code; 128 } 129 130 return result; 131 } 132 133 134 FT_CALLBACK_DEF( FT_UInt ) bdf_cmap_char_next(FT_CMap bdfcmap,FT_UInt32 * acharcode)135 bdf_cmap_char_next( FT_CMap bdfcmap, 136 FT_UInt32 *acharcode ) 137 { 138 BDF_CMap cmap = (BDF_CMap)bdfcmap; 139 BDF_encoding_el* encodings = cmap->encodings; 140 FT_ULong min, max, mid; /* num_encodings */ 141 FT_UShort result = 0; /* encodings->glyph */ 142 FT_ULong charcode = *acharcode + 1; 143 144 145 min = 0; 146 max = cmap->num_encodings; 147 mid = ( min + max ) >> 1; 148 149 while ( min < max ) 150 { 151 FT_ULong code; /* same as BDF_encoding_el.enc */ 152 153 154 if ( mid >= max || mid < min ) 155 mid = ( min + max ) >> 1; 156 157 code = encodings[mid].enc; 158 159 if ( charcode == code ) 160 { 161 /* increase glyph index by 1 -- */ 162 /* we reserve slot 0 for the undefined glyph */ 163 result = encodings[mid].glyph + 1; 164 goto Exit; 165 } 166 167 if ( charcode < code ) 168 max = mid; 169 else 170 min = mid + 1; 171 172 /* prediction in a continuous block */ 173 mid += charcode - code; 174 } 175 176 charcode = 0; 177 if ( min < cmap->num_encodings ) 178 { 179 charcode = encodings[min].enc; 180 result = encodings[min].glyph + 1; 181 } 182 183 Exit: 184 if ( charcode > 0xFFFFFFFFUL ) 185 { 186 FT_TRACE1(( "bdf_cmap_char_next: charcode 0x%lx > 32bit API", 187 charcode )); 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 %ld (used %ld)\n", 406 font->glyphs_size, 407 font->glyphs_used )); 408 FT_TRACE4(( " number of unencoded glyphs: allocated %ld (used %ld)\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 %ld\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 %ld\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 %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 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 %ld, 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 %ld 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 %ld 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%lx is truncated\n", 906 prop->value.l )); 907 } 908 aproperty->type = BDF_PROPERTY_TYPE_INTEGER; 909 aproperty->u.integer = (FT_Int32)prop->value.l; 910 break; 911 912 case BDF_CARDINAL: 913 if ( prop->value.ul > 0xFFFFFFFFUL ) 914 { 915 FT_TRACE1(( "bdf_get_bdf_property:" 916 " too large cardinal 0x%lx is truncated\n", 917 prop->value.ul )); 918 } 919 aproperty->type = BDF_PROPERTY_TYPE_CARDINAL; 920 aproperty->u.cardinal = (FT_UInt32)prop->value.ul; 921 break; 922 923 default: 924 goto Fail; 925 } 926 return 0; 927 } 928 929 Fail: 930 return FT_THROW( Invalid_Argument ); 931 } 932 933 934 static FT_Error bdf_get_charset_id(BDF_Face face,const char ** acharset_encoding,const char ** acharset_registry)935 bdf_get_charset_id( BDF_Face face, 936 const char* *acharset_encoding, 937 const char* *acharset_registry ) 938 { 939 *acharset_encoding = face->charset_encoding; 940 *acharset_registry = face->charset_registry; 941 942 return 0; 943 } 944 945 946 static const FT_Service_BDFRec bdf_service_bdf = 947 { 948 (FT_BDF_GetCharsetIdFunc)bdf_get_charset_id, /* get_charset_id */ 949 (FT_BDF_GetPropertyFunc) bdf_get_bdf_property /* get_property */ 950 }; 951 952 953 /* 954 * 955 * SERVICES LIST 956 * 957 */ 958 959 static const FT_ServiceDescRec bdf_services[] = 960 { 961 { FT_SERVICE_ID_BDF, &bdf_service_bdf }, 962 { FT_SERVICE_ID_FONT_FORMAT, FT_FONT_FORMAT_BDF }, 963 { NULL, NULL } 964 }; 965 966 967 FT_CALLBACK_DEF( FT_Module_Interface ) bdf_driver_requester(FT_Module module,const char * name)968 bdf_driver_requester( FT_Module module, 969 const char* name ) 970 { 971 FT_UNUSED( module ); 972 973 return ft_service_list_lookup( bdf_services, name ); 974 } 975 976 977 978 FT_CALLBACK_TABLE_DEF 979 const FT_Driver_ClassRec bdf_driver_class = 980 { 981 { 982 FT_MODULE_FONT_DRIVER | 983 FT_MODULE_DRIVER_NO_OUTLINES, 984 sizeof ( FT_DriverRec ), 985 986 "bdf", 987 0x10000L, 988 0x20000L, 989 990 NULL, /* module-specific interface */ 991 992 NULL, /* FT_Module_Constructor module_init */ 993 NULL, /* FT_Module_Destructor module_done */ 994 bdf_driver_requester /* FT_Module_Requester get_interface */ 995 }, 996 997 sizeof ( BDF_FaceRec ), 998 sizeof ( FT_SizeRec ), 999 sizeof ( FT_GlyphSlotRec ), 1000 1001 BDF_Face_Init, /* FT_Face_InitFunc init_face */ 1002 BDF_Face_Done, /* FT_Face_DoneFunc done_face */ 1003 NULL, /* FT_Size_InitFunc init_size */ 1004 NULL, /* FT_Size_DoneFunc done_size */ 1005 NULL, /* FT_Slot_InitFunc init_slot */ 1006 NULL, /* FT_Slot_DoneFunc done_slot */ 1007 1008 BDF_Glyph_Load, /* FT_Slot_LoadFunc load_glyph */ 1009 1010 NULL, /* FT_Face_GetKerningFunc get_kerning */ 1011 NULL, /* FT_Face_AttachFunc attach_file */ 1012 NULL, /* FT_Face_GetAdvancesFunc get_advances */ 1013 1014 BDF_Size_Request, /* FT_Size_RequestFunc request_size */ 1015 BDF_Size_Select /* FT_Size_SelectFunc select_size */ 1016 }; 1017 1018 1019 /* END */ 1020