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