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_QALLOC( 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( bdfface->available_sizes ) ) 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 /* sanity checks */ 455 if ( font->font_ascent > 0x7FFF || font->font_ascent < -0x7FFF ) 456 { 457 font->font_ascent = font->font_ascent < 0 ? -0x7FFF : 0x7FFF; 458 FT_TRACE0(( "BDF_Face_Init: clamping font ascent to value %ld\n", 459 font->font_ascent )); 460 } 461 if ( font->font_descent > 0x7FFF || font->font_descent < -0x7FFF ) 462 { 463 font->font_descent = font->font_descent < 0 ? -0x7FFF : 0x7FFF; 464 FT_TRACE0(( "BDF_Face_Init: clamping font descent to value %ld\n", 465 font->font_descent )); 466 } 467 468 bsize->height = (FT_Short)( font->font_ascent + font->font_descent ); 469 470 prop = bdf_get_font_property( font, "AVERAGE_WIDTH" ); 471 if ( prop ) 472 { 473 #ifdef FT_DEBUG_LEVEL_TRACE 474 if ( prop->value.l < 0 ) 475 FT_TRACE0(( "BDF_Face_Init: negative average width\n" )); 476 #endif 477 if ( prop->value.l > 0x7FFFL * 10 - 5 || 478 prop->value.l < -( 0x7FFFL * 10 - 5 ) ) 479 { 480 bsize->width = 0x7FFF; 481 FT_TRACE0(( "BDF_Face_Init: clamping average width to value %d\n", 482 bsize->width )); 483 } 484 else 485 bsize->width = FT_ABS( (FT_Short)( ( prop->value.l + 5 ) / 10 ) ); 486 } 487 else 488 { 489 /* this is a heuristical value */ 490 bsize->width = ( bsize->height * 2 + 1 ) / 3; 491 } 492 493 prop = bdf_get_font_property( font, "POINT_SIZE" ); 494 if ( prop ) 495 { 496 #ifdef FT_DEBUG_LEVEL_TRACE 497 if ( prop->value.l < 0 ) 498 FT_TRACE0(( "BDF_Face_Init: negative point size\n" )); 499 #endif 500 /* convert from 722.7 decipoints to 72 points per inch */ 501 if ( prop->value.l > 0x504C2L || /* 0x7FFF * 72270/7200 */ 502 prop->value.l < -0x504C2L ) 503 { 504 bsize->size = 0x7FFF; 505 FT_TRACE0(( "BDF_Face_Init: clamping point size to value %ld\n", 506 bsize->size )); 507 } 508 else 509 bsize->size = FT_MulDiv( FT_ABS( prop->value.l ), 510 64 * 7200, 511 72270L ); 512 } 513 else if ( font->point_size ) 514 { 515 if ( font->point_size > 0x7FFF ) 516 { 517 bsize->size = 0x7FFF; 518 FT_TRACE0(( "BDF_Face_Init: clamping point size to value %ld\n", 519 bsize->size )); 520 } 521 else 522 bsize->size = (FT_Pos)font->point_size << 6; 523 } 524 else 525 { 526 /* this is a heuristical value */ 527 bsize->size = bsize->width * 64; 528 } 529 530 prop = bdf_get_font_property( font, "PIXEL_SIZE" ); 531 if ( prop ) 532 { 533 #ifdef FT_DEBUG_LEVEL_TRACE 534 if ( prop->value.l < 0 ) 535 FT_TRACE0(( "BDF_Face_Init: negative pixel size\n" )); 536 #endif 537 if ( prop->value.l > 0x7FFF || prop->value.l < -0x7FFF ) 538 { 539 bsize->y_ppem = 0x7FFF << 6; 540 FT_TRACE0(( "BDF_Face_Init: clamping pixel size to value %ld\n", 541 bsize->y_ppem )); 542 } 543 else 544 bsize->y_ppem = FT_ABS( (FT_Short)prop->value.l ) << 6; 545 } 546 547 prop = bdf_get_font_property( font, "RESOLUTION_X" ); 548 if ( prop ) 549 value = prop->value.l; 550 else 551 value = (long)font->resolution_x; 552 if ( value ) 553 { 554 #ifdef FT_DEBUG_LEVEL_TRACE 555 if ( value < 0 ) 556 FT_TRACE0(( "BDF_Face_Init: negative X resolution\n" )); 557 #endif 558 if ( value > 0x7FFF || value < -0x7FFF ) 559 { 560 resolution_x = 0x7FFF; 561 FT_TRACE0(( "BDF_Face_Init: clamping X resolution to value %d\n", 562 resolution_x )); 563 } 564 else 565 resolution_x = FT_ABS( (FT_Short)value ); 566 } 567 568 prop = bdf_get_font_property( font, "RESOLUTION_Y" ); 569 if ( prop ) 570 value = prop->value.l; 571 else 572 value = (long)font->resolution_y; 573 if ( value ) 574 { 575 #ifdef FT_DEBUG_LEVEL_TRACE 576 if ( value < 0 ) 577 FT_TRACE0(( "BDF_Face_Init: negative Y resolution\n" )); 578 #endif 579 if ( value > 0x7FFF || value < -0x7FFF ) 580 { 581 resolution_y = 0x7FFF; 582 FT_TRACE0(( "BDF_Face_Init: clamping Y resolution to value %d\n", 583 resolution_y )); 584 } 585 else 586 resolution_y = FT_ABS( (FT_Short)value ); 587 } 588 589 if ( bsize->y_ppem == 0 ) 590 { 591 bsize->y_ppem = bsize->size; 592 if ( resolution_y ) 593 bsize->y_ppem = FT_MulDiv( bsize->y_ppem, resolution_y, 72 ); 594 } 595 if ( resolution_x && resolution_y ) 596 bsize->x_ppem = FT_MulDiv( bsize->y_ppem, 597 resolution_x, 598 resolution_y ); 599 else 600 bsize->x_ppem = bsize->y_ppem; 601 } 602 603 /* encoding table */ 604 { 605 bdf_glyph_t* cur = font->glyphs; 606 unsigned long n; 607 608 609 if ( FT_QNEW_ARRAY( face->en_table, font->glyphs_size ) ) 610 goto Exit; 611 612 face->default_glyph = 0; 613 for ( n = 0; n < font->glyphs_size; n++ ) 614 { 615 (face->en_table[n]).enc = cur[n].encoding; 616 FT_TRACE4(( " idx %ld, val 0x%lX\n", n, cur[n].encoding )); 617 (face->en_table[n]).glyph = (FT_UShort)n; 618 619 if ( cur[n].encoding == font->default_char ) 620 { 621 if ( n < FT_UINT_MAX ) 622 face->default_glyph = (FT_UInt)n; 623 else 624 FT_TRACE1(( "BDF_Face_Init:" 625 " idx %ld is too large for this system\n", n )); 626 } 627 } 628 } 629 630 /* charmaps */ 631 { 632 bdf_property_t *charset_registry, *charset_encoding; 633 FT_Bool unicode_charmap = 0; 634 635 636 charset_registry = 637 bdf_get_font_property( font, "CHARSET_REGISTRY" ); 638 charset_encoding = 639 bdf_get_font_property( font, "CHARSET_ENCODING" ); 640 if ( charset_registry && charset_encoding ) 641 { 642 if ( charset_registry->format == BDF_ATOM && 643 charset_encoding->format == BDF_ATOM && 644 charset_registry->value.atom && 645 charset_encoding->value.atom ) 646 { 647 const char* s; 648 649 650 if ( FT_STRDUP( face->charset_encoding, 651 charset_encoding->value.atom ) || 652 FT_STRDUP( face->charset_registry, 653 charset_registry->value.atom ) ) 654 goto Exit; 655 656 /* Uh, oh, compare first letters manually to avoid dependency */ 657 /* on locales. */ 658 s = face->charset_registry; 659 if ( ( s[0] == 'i' || s[0] == 'I' ) && 660 ( s[1] == 's' || s[1] == 'S' ) && 661 ( s[2] == 'o' || s[2] == 'O' ) ) 662 { 663 s += 3; 664 if ( !ft_strcmp( s, "10646" ) || 665 ( !ft_strcmp( s, "8859" ) && 666 !ft_strcmp( face->charset_encoding, "1" ) ) ) 667 unicode_charmap = 1; 668 /* another name for ASCII */ 669 else if ( !ft_strcmp( s, "646.1991" ) && 670 !ft_strcmp( face->charset_encoding, "IRV" ) ) 671 unicode_charmap = 1; 672 } 673 674 { 675 FT_CharMapRec charmap; 676 677 678 charmap.face = FT_FACE( face ); 679 charmap.encoding = FT_ENCODING_NONE; 680 /* initial platform/encoding should indicate unset status? */ 681 charmap.platform_id = TT_PLATFORM_APPLE_UNICODE; 682 charmap.encoding_id = TT_APPLE_ID_DEFAULT; 683 684 if ( unicode_charmap ) 685 { 686 charmap.encoding = FT_ENCODING_UNICODE; 687 charmap.platform_id = TT_PLATFORM_MICROSOFT; 688 charmap.encoding_id = TT_MS_ID_UNICODE_CS; 689 } 690 691 error = FT_CMap_New( &bdf_cmap_class, NULL, &charmap, NULL ); 692 } 693 694 goto Exit; 695 } 696 } 697 698 /* otherwise assume Adobe standard encoding */ 699 700 { 701 FT_CharMapRec charmap; 702 703 704 charmap.face = FT_FACE( face ); 705 charmap.encoding = FT_ENCODING_ADOBE_STANDARD; 706 charmap.platform_id = TT_PLATFORM_ADOBE; 707 charmap.encoding_id = TT_ADOBE_ID_STANDARD; 708 709 error = FT_CMap_New( &bdf_cmap_class, NULL, &charmap, NULL ); 710 711 /* Select default charmap */ 712 if ( bdfface->num_charmaps ) 713 bdfface->charmap = bdfface->charmaps[0]; 714 } 715 } 716 } 717 718 Exit: 719 return error; 720 721 Fail: 722 BDF_Face_Done( bdfface ); 723 return FT_THROW( Unknown_File_Format ); 724 } 725 726 727 FT_CALLBACK_DEF( FT_Error ) BDF_Size_Select(FT_Size size,FT_ULong strike_index)728 BDF_Size_Select( FT_Size size, 729 FT_ULong strike_index ) 730 { 731 bdf_font_t* bdffont = ( (BDF_Face)size->face )->bdffont; 732 733 734 FT_Select_Metrics( size->face, strike_index ); 735 736 size->metrics.ascender = bdffont->font_ascent * 64; 737 size->metrics.descender = -bdffont->font_descent * 64; 738 size->metrics.max_advance = bdffont->bbx.width * 64; 739 740 return FT_Err_Ok; 741 } 742 743 744 FT_CALLBACK_DEF( FT_Error ) BDF_Size_Request(FT_Size size,FT_Size_Request req)745 BDF_Size_Request( FT_Size size, 746 FT_Size_Request req ) 747 { 748 FT_Face face = size->face; 749 FT_Bitmap_Size* bsize = face->available_sizes; 750 bdf_font_t* bdffont = ( (BDF_Face)face )->bdffont; 751 FT_Error error = FT_ERR( Invalid_Pixel_Size ); 752 FT_Long height; 753 754 755 height = FT_REQUEST_HEIGHT( req ); 756 height = ( height + 32 ) >> 6; 757 758 switch ( req->type ) 759 { 760 case FT_SIZE_REQUEST_TYPE_NOMINAL: 761 if ( height == ( ( bsize->y_ppem + 32 ) >> 6 ) ) 762 error = FT_Err_Ok; 763 break; 764 765 case FT_SIZE_REQUEST_TYPE_REAL_DIM: 766 if ( height == ( bdffont->font_ascent + 767 bdffont->font_descent ) ) 768 error = FT_Err_Ok; 769 break; 770 771 default: 772 error = FT_THROW( Unimplemented_Feature ); 773 break; 774 } 775 776 if ( error ) 777 return error; 778 else 779 return BDF_Size_Select( size, 0 ); 780 } 781 782 783 784 FT_CALLBACK_DEF( FT_Error ) BDF_Glyph_Load(FT_GlyphSlot slot,FT_Size size,FT_UInt glyph_index,FT_Int32 load_flags)785 BDF_Glyph_Load( FT_GlyphSlot slot, 786 FT_Size size, 787 FT_UInt glyph_index, 788 FT_Int32 load_flags ) 789 { 790 BDF_Face bdf = (BDF_Face)FT_SIZE_FACE( size ); 791 FT_Face face = FT_FACE( bdf ); 792 FT_Error error = FT_Err_Ok; 793 FT_Bitmap* bitmap = &slot->bitmap; 794 bdf_glyph_t glyph; 795 int bpp = bdf->bdffont->bpp; 796 797 FT_UNUSED( load_flags ); 798 799 800 if ( !face ) 801 { 802 error = FT_THROW( Invalid_Face_Handle ); 803 goto Exit; 804 } 805 806 if ( glyph_index >= (FT_UInt)face->num_glyphs ) 807 { 808 error = FT_THROW( Invalid_Argument ); 809 goto Exit; 810 } 811 812 FT_TRACE1(( "BDF_Glyph_Load: glyph index %d\n", glyph_index )); 813 814 /* index 0 is the undefined glyph */ 815 if ( glyph_index == 0 ) 816 glyph_index = bdf->default_glyph; 817 else 818 glyph_index--; 819 820 /* slot, bitmap => freetype, glyph => bdflib */ 821 glyph = bdf->bdffont->glyphs[glyph_index]; 822 823 bitmap->rows = glyph.bbx.height; 824 bitmap->width = glyph.bbx.width; 825 if ( glyph.bpr > FT_INT_MAX ) 826 FT_TRACE1(( "BDF_Glyph_Load: too large pitch %ld is truncated\n", 827 glyph.bpr )); 828 bitmap->pitch = (int)glyph.bpr; /* same as FT_Bitmap.pitch */ 829 830 /* note: we don't allocate a new array to hold the bitmap; */ 831 /* we can simply point to it */ 832 ft_glyphslot_set_bitmap( slot, glyph.bitmap ); 833 834 switch ( bpp ) 835 { 836 case 1: 837 bitmap->pixel_mode = FT_PIXEL_MODE_MONO; 838 break; 839 case 2: 840 bitmap->pixel_mode = FT_PIXEL_MODE_GRAY2; 841 break; 842 case 4: 843 bitmap->pixel_mode = FT_PIXEL_MODE_GRAY4; 844 break; 845 case 8: 846 bitmap->pixel_mode = FT_PIXEL_MODE_GRAY; 847 bitmap->num_grays = 256; 848 break; 849 } 850 851 slot->format = FT_GLYPH_FORMAT_BITMAP; 852 slot->bitmap_left = glyph.bbx.x_offset; 853 slot->bitmap_top = glyph.bbx.ascent; 854 855 slot->metrics.horiAdvance = (FT_Pos)( glyph.dwidth * 64 ); 856 slot->metrics.horiBearingX = (FT_Pos)( glyph.bbx.x_offset * 64 ); 857 slot->metrics.horiBearingY = (FT_Pos)( glyph.bbx.ascent * 64 ); 858 slot->metrics.width = (FT_Pos)( bitmap->width * 64 ); 859 slot->metrics.height = (FT_Pos)( bitmap->rows * 64 ); 860 861 /* 862 * XXX DWIDTH1 and VVECTOR should be parsed and 863 * used here, provided such fonts do exist. 864 */ 865 ft_synthesize_vertical_metrics( &slot->metrics, 866 bdf->bdffont->bbx.height * 64 ); 867 868 Exit: 869 return error; 870 } 871 872 873 /* 874 * 875 * BDF SERVICE 876 * 877 */ 878 879 static FT_Error bdf_get_bdf_property(BDF_Face face,const char * prop_name,BDF_PropertyRec * aproperty)880 bdf_get_bdf_property( BDF_Face face, 881 const char* prop_name, 882 BDF_PropertyRec *aproperty ) 883 { 884 bdf_property_t* prop; 885 886 887 FT_ASSERT( face && face->bdffont ); 888 889 prop = bdf_get_font_property( face->bdffont, prop_name ); 890 if ( prop ) 891 { 892 switch ( prop->format ) 893 { 894 case BDF_ATOM: 895 aproperty->type = BDF_PROPERTY_TYPE_ATOM; 896 aproperty->u.atom = prop->value.atom; 897 break; 898 899 case BDF_INTEGER: 900 if ( prop->value.l > 0x7FFFFFFFL || prop->value.l < ( -1 - 0x7FFFFFFFL ) ) 901 { 902 FT_TRACE1(( "bdf_get_bdf_property:" 903 " too large integer 0x%lx is truncated\n", 904 prop->value.l )); 905 } 906 aproperty->type = BDF_PROPERTY_TYPE_INTEGER; 907 aproperty->u.integer = (FT_Int32)prop->value.l; 908 break; 909 910 case BDF_CARDINAL: 911 if ( prop->value.ul > 0xFFFFFFFFUL ) 912 { 913 FT_TRACE1(( "bdf_get_bdf_property:" 914 " too large cardinal 0x%lx is truncated\n", 915 prop->value.ul )); 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