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_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 ) bdf_cmap_char_next(FT_CMap bdfcmap,FT_UInt32 * acharcode)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 bdf_interpret_style(BDF_Face bdf)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 ) BDF_Face_Done(FT_Face face)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 ) BDF_Face_Init(FT_Stream stream,FT_Face face,FT_Int face_index,FT_Int num_params,FT_Parameter * params)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 bdf_options_t options; 353 354 FT_UNUSED( num_params ); 355 FT_UNUSED( params ); 356 357 358 FT_TRACE2(( "BDF driver\n" )); 359 360 if ( FT_STREAM_SEEK( 0 ) ) 361 goto Exit; 362 363 options.correct_metrics = 1; /* FZ XXX: options semantics */ 364 options.keep_unencoded = 1; 365 options.keep_comments = 0; 366 options.font_spacing = BDF_PROPORTIONAL; 367 368 error = bdf_load_font( stream, memory, &options, &font ); 369 if ( FT_ERR_EQ( error, Missing_Startfont_Field ) ) 370 { 371 FT_TRACE2(( " not a BDF file\n" )); 372 goto Fail; 373 } 374 else if ( error ) 375 goto Exit; 376 377 /* we have a bdf font: let's construct the face object */ 378 bdfface->bdffont = font; 379 380 /* BDF cannot have multiple faces in a single font file. 381 * XXX: non-zero face_index is already invalid argument, but 382 * Type1, Type42 driver has a convention to return 383 * an invalid argument error when the font could be 384 * opened by the specified driver. 385 */ 386 if ( face_index > 0 && ( face_index & 0xFFFF ) > 0 ) 387 { 388 FT_ERROR(( "BDF_Face_Init: invalid face index\n" )); 389 BDF_Face_Done( face ); 390 return FT_THROW( Invalid_Argument ); 391 } 392 393 { 394 bdf_property_t* prop = NULL; 395 396 397 FT_TRACE4(( " number of glyphs: allocated %ld (used %ld)\n", 398 font->glyphs_size, 399 font->glyphs_used )); 400 FT_TRACE4(( " number of unencoded glyphs: allocated %ld (used %ld)\n", 401 font->unencoded_size, 402 font->unencoded_used )); 403 404 face->num_faces = 1; 405 face->face_index = 0; 406 407 face->face_flags |= FT_FACE_FLAG_FIXED_SIZES | 408 FT_FACE_FLAG_HORIZONTAL; 409 410 prop = bdf_get_font_property( font, "SPACING" ); 411 if ( prop && prop->format == BDF_ATOM && 412 prop->value.atom && 413 ( *(prop->value.atom) == 'M' || *(prop->value.atom) == 'm' || 414 *(prop->value.atom) == 'C' || *(prop->value.atom) == 'c' ) ) 415 face->face_flags |= FT_FACE_FLAG_FIXED_WIDTH; 416 417 /* FZ XXX: TO DO: FT_FACE_FLAGS_VERTICAL */ 418 /* FZ XXX: I need a font to implement this */ 419 420 prop = bdf_get_font_property( font, "FAMILY_NAME" ); 421 if ( prop && prop->value.atom ) 422 { 423 if ( FT_STRDUP( face->family_name, prop->value.atom ) ) 424 goto Exit; 425 } 426 else 427 face->family_name = NULL; 428 429 if ( FT_SET_ERROR( bdf_interpret_style( bdfface ) ) ) 430 goto Exit; 431 432 /* the number of glyphs (with one slot for the undefined glyph */ 433 /* at position 0 and all unencoded glyphs) */ 434 face->num_glyphs = (FT_Long)( font->glyphs_size + 1 ); 435 436 face->num_fixed_sizes = 1; 437 if ( FT_NEW( face->available_sizes ) ) 438 goto Exit; 439 440 { 441 FT_Bitmap_Size* bsize = face->available_sizes; 442 FT_Short resolution_x = 0; 443 FT_Short resolution_y = 0; 444 long value; 445 446 447 /* sanity checks */ 448 if ( font->font_ascent > 0x7FFF || font->font_ascent < -0x7FFF ) 449 { 450 font->font_ascent = font->font_ascent < 0 ? -0x7FFF : 0x7FFF; 451 FT_TRACE0(( "BDF_Face_Init: clamping font ascent to value %ld\n", 452 font->font_ascent )); 453 } 454 if ( font->font_descent > 0x7FFF || font->font_descent < -0x7FFF ) 455 { 456 font->font_descent = font->font_descent < 0 ? -0x7FFF : 0x7FFF; 457 FT_TRACE0(( "BDF_Face_Init: clamping font descent to value %ld\n", 458 font->font_descent )); 459 } 460 461 bsize->height = (FT_Short)( font->font_ascent + font->font_descent ); 462 463 prop = bdf_get_font_property( font, "AVERAGE_WIDTH" ); 464 if ( prop ) 465 { 466 #ifdef FT_DEBUG_LEVEL_TRACE 467 if ( prop->value.l < 0 ) 468 FT_TRACE0(( "BDF_Face_Init: negative average width\n" )); 469 #endif 470 if ( prop->value.l > 0x7FFFL * 10 - 5 || 471 prop->value.l < -( 0x7FFFL * 10 - 5 ) ) 472 { 473 bsize->width = 0x7FFF; 474 FT_TRACE0(( "BDF_Face_Init: clamping average width to value %d\n", 475 bsize->width )); 476 } 477 else 478 bsize->width = FT_ABS( (FT_Short)( ( prop->value.l + 5 ) / 10 ) ); 479 } 480 else 481 { 482 /* this is a heuristical value */ 483 bsize->width = ( bsize->height * 2 + 1 ) / 3; 484 } 485 486 prop = bdf_get_font_property( font, "POINT_SIZE" ); 487 if ( prop ) 488 { 489 #ifdef FT_DEBUG_LEVEL_TRACE 490 if ( prop->value.l < 0 ) 491 FT_TRACE0(( "BDF_Face_Init: negative point size\n" )); 492 #endif 493 /* convert from 722.7 decipoints to 72 points per inch */ 494 if ( prop->value.l > 0x504C2L || /* 0x7FFF * 72270/7200 */ 495 prop->value.l < -0x504C2L ) 496 { 497 bsize->size = 0x7FFF; 498 FT_TRACE0(( "BDF_Face_Init: clamping point size to value %ld\n", 499 bsize->size )); 500 } 501 else 502 bsize->size = FT_MulDiv( FT_ABS( prop->value.l ), 503 64 * 7200, 504 72270L ); 505 } 506 else if ( font->point_size ) 507 { 508 if ( font->point_size > 0x7FFF ) 509 { 510 bsize->size = 0x7FFF; 511 FT_TRACE0(( "BDF_Face_Init: clamping point size to value %ld\n", 512 bsize->size )); 513 } 514 else 515 bsize->size = (FT_Pos)font->point_size << 6; 516 } 517 else 518 { 519 /* this is a heuristical value */ 520 bsize->size = bsize->width * 64; 521 } 522 523 prop = bdf_get_font_property( font, "PIXEL_SIZE" ); 524 if ( prop ) 525 { 526 #ifdef FT_DEBUG_LEVEL_TRACE 527 if ( prop->value.l < 0 ) 528 FT_TRACE0(( "BDF_Face_Init: negative pixel size\n" )); 529 #endif 530 if ( prop->value.l > 0x7FFF || prop->value.l < -0x7FFF ) 531 { 532 bsize->y_ppem = 0x7FFF << 6; 533 FT_TRACE0(( "BDF_Face_Init: clamping pixel size to value %ld\n", 534 bsize->y_ppem )); 535 } 536 else 537 bsize->y_ppem = FT_ABS( (FT_Short)prop->value.l ) << 6; 538 } 539 540 prop = bdf_get_font_property( font, "RESOLUTION_X" ); 541 if ( prop ) 542 value = prop->value.l; 543 else 544 value = (long)font->resolution_x; 545 if ( value ) 546 { 547 #ifdef FT_DEBUG_LEVEL_TRACE 548 if ( value < 0 ) 549 FT_TRACE0(( "BDF_Face_Init: negative X resolution\n" )); 550 #endif 551 if ( value > 0x7FFF || value < -0x7FFF ) 552 { 553 resolution_x = 0x7FFF; 554 FT_TRACE0(( "BDF_Face_Init: clamping X resolution to value %d\n", 555 resolution_x )); 556 } 557 else 558 resolution_x = FT_ABS( (FT_Short)value ); 559 } 560 561 prop = bdf_get_font_property( font, "RESOLUTION_Y" ); 562 if ( prop ) 563 value = prop->value.l; 564 else 565 value = (long)font->resolution_y; 566 if ( value ) 567 { 568 #ifdef FT_DEBUG_LEVEL_TRACE 569 if ( value < 0 ) 570 FT_TRACE0(( "BDF_Face_Init: negative Y resolution\n" )); 571 #endif 572 if ( value > 0x7FFF || value < -0x7FFF ) 573 { 574 resolution_y = 0x7FFF; 575 FT_TRACE0(( "BDF_Face_Init: clamping Y resolution to value %d\n", 576 resolution_y )); 577 } 578 else 579 resolution_y = FT_ABS( (FT_Short)value ); 580 } 581 582 if ( bsize->y_ppem == 0 ) 583 { 584 bsize->y_ppem = bsize->size; 585 if ( resolution_y ) 586 bsize->y_ppem = FT_MulDiv( bsize->y_ppem, resolution_y, 72 ); 587 } 588 if ( resolution_x && resolution_y ) 589 bsize->x_ppem = FT_MulDiv( bsize->y_ppem, 590 resolution_x, 591 resolution_y ); 592 else 593 bsize->x_ppem = bsize->y_ppem; 594 } 595 596 /* encoding table */ 597 { 598 bdf_glyph_t* cur = font->glyphs; 599 unsigned long n; 600 601 602 if ( FT_QNEW_ARRAY( bdfface->en_table, font->glyphs_size ) ) 603 goto Exit; 604 605 bdfface->default_glyph = 0; 606 for ( n = 0; n < font->glyphs_size; n++ ) 607 { 608 (bdfface->en_table[n]).enc = cur[n].encoding; 609 FT_TRACE4(( " idx %ld, val 0x%lX\n", n, cur[n].encoding )); 610 (bdfface->en_table[n]).glyph = (FT_UShort)n; 611 612 if ( cur[n].encoding == font->default_char ) 613 { 614 if ( n < FT_UINT_MAX ) 615 bdfface->default_glyph = (FT_UInt)n; 616 else 617 FT_TRACE1(( "BDF_Face_Init:" 618 " idx %ld is too large for this system\n", n )); 619 } 620 } 621 } 622 623 /* charmaps */ 624 { 625 bdf_property_t *charset_registry, *charset_encoding; 626 FT_Bool unicode_charmap = 0; 627 628 629 charset_registry = 630 bdf_get_font_property( font, "CHARSET_REGISTRY" ); 631 charset_encoding = 632 bdf_get_font_property( font, "CHARSET_ENCODING" ); 633 if ( charset_registry && charset_encoding ) 634 { 635 if ( charset_registry->format == BDF_ATOM && 636 charset_encoding->format == BDF_ATOM && 637 charset_registry->value.atom && 638 charset_encoding->value.atom ) 639 { 640 const char* s; 641 642 643 if ( FT_STRDUP( bdfface->charset_encoding, 644 charset_encoding->value.atom ) || 645 FT_STRDUP( bdfface->charset_registry, 646 charset_registry->value.atom ) ) 647 goto Exit; 648 649 /* Uh, oh, compare first letters manually to avoid dependency */ 650 /* on locales. */ 651 s = bdfface->charset_registry; 652 if ( ( s[0] == 'i' || s[0] == 'I' ) && 653 ( s[1] == 's' || s[1] == 'S' ) && 654 ( s[2] == 'o' || s[2] == 'O' ) ) 655 { 656 s += 3; 657 if ( !ft_strcmp( s, "10646" ) || 658 ( !ft_strcmp( s, "8859" ) && 659 !ft_strcmp( bdfface->charset_encoding, "1" ) ) ) 660 unicode_charmap = 1; 661 /* another name for ASCII */ 662 else if ( !ft_strcmp( s, "646.1991" ) && 663 !ft_strcmp( bdfface->charset_encoding, "IRV" ) ) 664 unicode_charmap = 1; 665 } 666 667 { 668 FT_CharMapRec charmap; 669 670 671 charmap.face = face; 672 charmap.encoding = FT_ENCODING_NONE; 673 /* initial platform/encoding should indicate unset status? */ 674 charmap.platform_id = TT_PLATFORM_APPLE_UNICODE; 675 charmap.encoding_id = TT_APPLE_ID_DEFAULT; 676 677 if ( unicode_charmap ) 678 { 679 charmap.encoding = FT_ENCODING_UNICODE; 680 charmap.platform_id = TT_PLATFORM_MICROSOFT; 681 charmap.encoding_id = TT_MS_ID_UNICODE_CS; 682 } 683 684 error = FT_CMap_New( &bdf_cmap_class, NULL, &charmap, NULL ); 685 } 686 687 goto Exit; 688 } 689 } 690 691 /* otherwise assume Adobe standard encoding */ 692 693 { 694 FT_CharMapRec charmap; 695 696 697 charmap.face = face; 698 charmap.encoding = FT_ENCODING_ADOBE_STANDARD; 699 charmap.platform_id = TT_PLATFORM_ADOBE; 700 charmap.encoding_id = TT_ADOBE_ID_STANDARD; 701 702 error = FT_CMap_New( &bdf_cmap_class, NULL, &charmap, NULL ); 703 704 /* Select default charmap */ 705 if ( face->num_charmaps ) 706 face->charmap = face->charmaps[0]; 707 } 708 } 709 } 710 711 Exit: 712 return error; 713 714 Fail: 715 BDF_Face_Done( face ); 716 return FT_THROW( Unknown_File_Format ); 717 } 718 719 720 FT_CALLBACK_DEF( FT_Error ) BDF_Size_Select(FT_Size size,FT_ULong strike_index)721 BDF_Size_Select( FT_Size size, 722 FT_ULong strike_index ) 723 { 724 bdf_font_t* bdffont = ( (BDF_Face)size->face )->bdffont; 725 726 727 FT_Select_Metrics( size->face, strike_index ); 728 729 size->metrics.ascender = bdffont->font_ascent * 64; 730 size->metrics.descender = -bdffont->font_descent * 64; 731 size->metrics.max_advance = bdffont->bbx.width * 64; 732 733 return FT_Err_Ok; 734 } 735 736 737 FT_CALLBACK_DEF( FT_Error ) BDF_Size_Request(FT_Size size,FT_Size_Request req)738 BDF_Size_Request( FT_Size size, 739 FT_Size_Request req ) 740 { 741 FT_Face face = size->face; 742 FT_Bitmap_Size* bsize = face->available_sizes; 743 bdf_font_t* bdffont = ( (BDF_Face)face )->bdffont; 744 FT_Error error = FT_ERR( Invalid_Pixel_Size ); 745 FT_Long height; 746 747 748 height = FT_REQUEST_HEIGHT( req ); 749 height = ( height + 32 ) >> 6; 750 751 switch ( req->type ) 752 { 753 case FT_SIZE_REQUEST_TYPE_NOMINAL: 754 if ( height == ( ( bsize->y_ppem + 32 ) >> 6 ) ) 755 error = FT_Err_Ok; 756 break; 757 758 case FT_SIZE_REQUEST_TYPE_REAL_DIM: 759 if ( height == ( bdffont->font_ascent + 760 bdffont->font_descent ) ) 761 error = FT_Err_Ok; 762 break; 763 764 default: 765 error = FT_THROW( Unimplemented_Feature ); 766 break; 767 } 768 769 if ( error ) 770 return error; 771 else 772 return BDF_Size_Select( size, 0 ); 773 } 774 775 776 777 FT_CALLBACK_DEF( FT_Error ) BDF_Glyph_Load(FT_GlyphSlot slot,FT_Size size,FT_UInt glyph_index,FT_Int32 load_flags)778 BDF_Glyph_Load( FT_GlyphSlot slot, 779 FT_Size size, 780 FT_UInt glyph_index, 781 FT_Int32 load_flags ) 782 { 783 BDF_Face bdf = (BDF_Face)FT_SIZE_FACE( size ); 784 FT_Face face = FT_FACE( bdf ); 785 FT_Error error = FT_Err_Ok; 786 FT_Bitmap* bitmap = &slot->bitmap; 787 bdf_glyph_t glyph; 788 int bpp = bdf->bdffont->bpp; 789 790 FT_UNUSED( load_flags ); 791 792 793 if ( !face ) 794 { 795 error = FT_THROW( Invalid_Face_Handle ); 796 goto Exit; 797 } 798 799 if ( glyph_index >= (FT_UInt)face->num_glyphs ) 800 { 801 error = FT_THROW( Invalid_Argument ); 802 goto Exit; 803 } 804 805 FT_TRACE1(( "BDF_Glyph_Load: glyph index %d\n", glyph_index )); 806 807 /* index 0 is the undefined glyph */ 808 if ( glyph_index == 0 ) 809 glyph_index = bdf->default_glyph; 810 else 811 glyph_index--; 812 813 /* slot, bitmap => freetype, glyph => bdflib */ 814 glyph = bdf->bdffont->glyphs[glyph_index]; 815 816 bitmap->rows = glyph.bbx.height; 817 bitmap->width = glyph.bbx.width; 818 if ( glyph.bpr > FT_INT_MAX ) 819 FT_TRACE1(( "BDF_Glyph_Load: too large pitch %ld is truncated\n", 820 glyph.bpr )); 821 bitmap->pitch = (int)glyph.bpr; /* same as FT_Bitmap.pitch */ 822 823 /* note: we don't allocate a new array to hold the bitmap; */ 824 /* we can simply point to it */ 825 ft_glyphslot_set_bitmap( slot, glyph.bitmap ); 826 827 switch ( bpp ) 828 { 829 case 1: 830 bitmap->pixel_mode = FT_PIXEL_MODE_MONO; 831 break; 832 case 2: 833 bitmap->pixel_mode = FT_PIXEL_MODE_GRAY2; 834 break; 835 case 4: 836 bitmap->pixel_mode = FT_PIXEL_MODE_GRAY4; 837 break; 838 case 8: 839 bitmap->pixel_mode = FT_PIXEL_MODE_GRAY; 840 bitmap->num_grays = 256; 841 break; 842 } 843 844 slot->format = FT_GLYPH_FORMAT_BITMAP; 845 slot->bitmap_left = glyph.bbx.x_offset; 846 slot->bitmap_top = glyph.bbx.ascent; 847 848 slot->metrics.horiAdvance = (FT_Pos)( glyph.dwidth * 64 ); 849 slot->metrics.horiBearingX = (FT_Pos)( glyph.bbx.x_offset * 64 ); 850 slot->metrics.horiBearingY = (FT_Pos)( glyph.bbx.ascent * 64 ); 851 slot->metrics.width = (FT_Pos)( bitmap->width * 64 ); 852 slot->metrics.height = (FT_Pos)( bitmap->rows * 64 ); 853 854 /* 855 * XXX DWIDTH1 and VVECTOR should be parsed and 856 * used here, provided such fonts do exist. 857 */ 858 ft_synthesize_vertical_metrics( &slot->metrics, 859 bdf->bdffont->bbx.height * 64 ); 860 861 Exit: 862 return error; 863 } 864 865 866 /* 867 * 868 * BDF SERVICE 869 * 870 */ 871 872 FT_CALLBACK_DEF( FT_Error ) bdf_get_bdf_property(FT_Face face,const char * prop_name,BDF_PropertyRec * aproperty)873 bdf_get_bdf_property( FT_Face face, /* BDF_Face */ 874 const char* prop_name, 875 BDF_PropertyRec *aproperty ) 876 { 877 BDF_Face bdfface = (BDF_Face)face; 878 bdf_property_t* prop; 879 880 881 FT_ASSERT( bdfface && bdfface->bdffont ); 882 883 prop = bdf_get_font_property( bdfface->bdffont, prop_name ); 884 if ( prop ) 885 { 886 switch ( prop->format ) 887 { 888 case BDF_ATOM: 889 aproperty->type = BDF_PROPERTY_TYPE_ATOM; 890 aproperty->u.atom = prop->value.atom; 891 break; 892 893 case BDF_INTEGER: 894 if ( prop->value.l > 0x7FFFFFFFL || prop->value.l < ( -1 - 0x7FFFFFFFL ) ) 895 { 896 FT_TRACE1(( "bdf_get_bdf_property:" 897 " too large integer 0x%lx is truncated\n", 898 prop->value.l )); 899 } 900 aproperty->type = BDF_PROPERTY_TYPE_INTEGER; 901 aproperty->u.integer = (FT_Int32)prop->value.l; 902 break; 903 904 case BDF_CARDINAL: 905 if ( prop->value.ul > 0xFFFFFFFFUL ) 906 { 907 FT_TRACE1(( "bdf_get_bdf_property:" 908 " too large cardinal 0x%lx is truncated\n", 909 prop->value.ul )); 910 } 911 aproperty->type = BDF_PROPERTY_TYPE_CARDINAL; 912 aproperty->u.cardinal = (FT_UInt32)prop->value.ul; 913 break; 914 915 default: 916 goto Fail; 917 } 918 return 0; 919 } 920 921 Fail: 922 return FT_THROW( Invalid_Argument ); 923 } 924 925 926 FT_CALLBACK_DEF( FT_Error ) bdf_get_charset_id(FT_Face face,const char ** acharset_encoding,const char ** acharset_registry)927 bdf_get_charset_id( FT_Face face, /* BDF_Face */ 928 const char* *acharset_encoding, 929 const char* *acharset_registry ) 930 { 931 BDF_Face bdfface = (BDF_Face)face; 932 933 934 *acharset_encoding = bdfface->charset_encoding; 935 *acharset_registry = bdfface->charset_registry; 936 937 return 0; 938 } 939 940 941 static const FT_Service_BDFRec bdf_service_bdf = 942 { 943 (FT_BDF_GetCharsetIdFunc)bdf_get_charset_id, /* get_charset_id */ 944 (FT_BDF_GetPropertyFunc) bdf_get_bdf_property /* get_property */ 945 }; 946 947 948 /* 949 * 950 * SERVICES LIST 951 * 952 */ 953 954 static const FT_ServiceDescRec bdf_services[] = 955 { 956 { FT_SERVICE_ID_BDF, &bdf_service_bdf }, 957 { FT_SERVICE_ID_FONT_FORMAT, FT_FONT_FORMAT_BDF }, 958 { NULL, NULL } 959 }; 960 961 962 FT_CALLBACK_DEF( FT_Module_Interface ) bdf_driver_requester(FT_Module module,const char * name)963 bdf_driver_requester( FT_Module module, 964 const char* name ) 965 { 966 FT_UNUSED( module ); 967 968 return ft_service_list_lookup( bdf_services, name ); 969 } 970 971 972 FT_CALLBACK_TABLE_DEF 973 const FT_Driver_ClassRec bdf_driver_class = 974 { 975 { 976 FT_MODULE_FONT_DRIVER | 977 FT_MODULE_DRIVER_NO_OUTLINES, 978 sizeof ( FT_DriverRec ), 979 980 "bdf", 981 0x10000L, 982 0x20000L, 983 984 NULL, /* module-specific interface */ 985 986 NULL, /* FT_Module_Constructor module_init */ 987 NULL, /* FT_Module_Destructor module_done */ 988 bdf_driver_requester /* FT_Module_Requester get_interface */ 989 }, 990 991 sizeof ( BDF_FaceRec ), 992 sizeof ( FT_SizeRec ), 993 sizeof ( FT_GlyphSlotRec ), 994 995 BDF_Face_Init, /* FT_Face_InitFunc init_face */ 996 BDF_Face_Done, /* FT_Face_DoneFunc done_face */ 997 NULL, /* FT_Size_InitFunc init_size */ 998 NULL, /* FT_Size_DoneFunc done_size */ 999 NULL, /* FT_Slot_InitFunc init_slot */ 1000 NULL, /* FT_Slot_DoneFunc done_slot */ 1001 1002 BDF_Glyph_Load, /* FT_Slot_LoadFunc load_glyph */ 1003 1004 NULL, /* FT_Face_GetKerningFunc get_kerning */ 1005 NULL, /* FT_Face_AttachFunc attach_file */ 1006 NULL, /* FT_Face_GetAdvancesFunc get_advances */ 1007 1008 BDF_Size_Request, /* FT_Size_RequestFunc request_size */ 1009 BDF_Size_Select /* FT_Size_SelectFunc select_size */ 1010 }; 1011 1012 1013 /* END */ 1014