1 /***************************************************************************/ 2 /* */ 3 /* pfrobjs.c */ 4 /* */ 5 /* FreeType PFR object methods (body). */ 6 /* */ 7 /* Copyright 2002-2015 by */ 8 /* David Turner, Robert Wilhelm, and Werner Lemberg. */ 9 /* */ 10 /* This file is part of the FreeType project, and may only be used, */ 11 /* modified, and distributed under the terms of the FreeType project */ 12 /* license, LICENSE.TXT. By continuing to use, modify, or distribute */ 13 /* this file you indicate that you have read the license and */ 14 /* understand and accept it fully. */ 15 /* */ 16 /***************************************************************************/ 17 18 19 #include "pfrobjs.h" 20 #include "pfrload.h" 21 #include "pfrgload.h" 22 #include "pfrcmap.h" 23 #include "pfrsbit.h" 24 #include FT_OUTLINE_H 25 #include FT_INTERNAL_DEBUG_H 26 #include FT_INTERNAL_CALC_H 27 #include FT_TRUETYPE_IDS_H 28 29 #include "pfrerror.h" 30 31 #undef FT_COMPONENT 32 #define FT_COMPONENT trace_pfr 33 34 35 /*************************************************************************/ 36 /*************************************************************************/ 37 /***** *****/ 38 /***** FACE OBJECT METHODS *****/ 39 /***** *****/ 40 /*************************************************************************/ 41 /*************************************************************************/ 42 43 FT_LOCAL_DEF( void ) 44 pfr_face_done( FT_Face pfrface ) /* PFR_Face */ 45 { 46 PFR_Face face = (PFR_Face)pfrface; 47 FT_Memory memory; 48 49 50 if ( !face ) 51 return; 52 53 memory = pfrface->driver->root.memory; 54 55 /* we don't want dangling pointers */ 56 pfrface->family_name = NULL; 57 pfrface->style_name = NULL; 58 59 /* finalize the physical font record */ 60 pfr_phy_font_done( &face->phy_font, FT_FACE_MEMORY( face ) ); 61 62 /* no need to finalize the logical font or the header */ 63 FT_FREE( pfrface->available_sizes ); 64 } 65 66 67 FT_LOCAL_DEF( FT_Error ) 68 pfr_face_init( FT_Stream stream, 69 FT_Face pfrface, 70 FT_Int face_index, 71 FT_Int num_params, 72 FT_Parameter* params ) 73 { 74 PFR_Face face = (PFR_Face)pfrface; 75 FT_Error error; 76 77 FT_UNUSED( num_params ); 78 FT_UNUSED( params ); 79 80 81 FT_TRACE2(( "PFR driver\n" )); 82 83 /* load the header and check it */ 84 error = pfr_header_load( &face->header, stream ); 85 if ( error ) 86 goto Exit; 87 88 if ( !pfr_header_check( &face->header ) ) 89 { 90 FT_TRACE2(( " not a PFR font\n" )); 91 error = FT_THROW( Unknown_File_Format ); 92 goto Exit; 93 } 94 95 /* check face index */ 96 { 97 FT_Long num_faces; 98 99 100 error = pfr_log_font_count( stream, 101 face->header.log_dir_offset, 102 &num_faces ); 103 if ( error ) 104 goto Exit; 105 106 pfrface->num_faces = num_faces; 107 } 108 109 if ( face_index < 0 ) 110 goto Exit; 111 112 if ( ( face_index & 0xFFFF ) >= pfrface->num_faces ) 113 { 114 FT_ERROR(( "pfr_face_init: invalid face index\n" )); 115 error = FT_THROW( Invalid_Argument ); 116 goto Exit; 117 } 118 119 /* load the face */ 120 error = pfr_log_font_load( 121 &face->log_font, 122 stream, 123 (FT_UInt)( face_index & 0xFFFF ), 124 face->header.log_dir_offset, 125 FT_BOOL( face->header.phy_font_max_size_high != 0 ) ); 126 if ( error ) 127 goto Exit; 128 129 /* now load the physical font descriptor */ 130 error = pfr_phy_font_load( &face->phy_font, stream, 131 face->log_font.phys_offset, 132 face->log_font.phys_size ); 133 if ( error ) 134 goto Exit; 135 136 /* now set up all root face fields */ 137 { 138 PFR_PhyFont phy_font = &face->phy_font; 139 140 141 pfrface->face_index = face_index & 0xFFFF; 142 pfrface->num_glyphs = (FT_Long)phy_font->num_chars + 1; 143 144 pfrface->face_flags |= FT_FACE_FLAG_SCALABLE; 145 146 /* if gps_offset == 0 for all characters, we */ 147 /* assume that the font only contains bitmaps */ 148 { 149 FT_UInt nn; 150 151 152 for ( nn = 0; nn < phy_font->num_chars; nn++ ) 153 if ( phy_font->chars[nn].gps_offset != 0 ) 154 break; 155 156 if ( nn == phy_font->num_chars ) 157 { 158 if ( phy_font->num_strikes > 0 ) 159 pfrface->face_flags = 0; /* not scalable */ 160 else 161 { 162 FT_ERROR(( "pfr_face_init: font doesn't contain glyphs\n" )); 163 error = FT_THROW( Invalid_File_Format ); 164 goto Exit; 165 } 166 } 167 } 168 169 if ( ( phy_font->flags & PFR_PHY_PROPORTIONAL ) == 0 ) 170 pfrface->face_flags |= FT_FACE_FLAG_FIXED_WIDTH; 171 172 if ( phy_font->flags & PFR_PHY_VERTICAL ) 173 pfrface->face_flags |= FT_FACE_FLAG_VERTICAL; 174 else 175 pfrface->face_flags |= FT_FACE_FLAG_HORIZONTAL; 176 177 if ( phy_font->num_strikes > 0 ) 178 pfrface->face_flags |= FT_FACE_FLAG_FIXED_SIZES; 179 180 if ( phy_font->num_kern_pairs > 0 ) 181 pfrface->face_flags |= FT_FACE_FLAG_KERNING; 182 183 /* If no family name was found in the `undocumented' auxiliary 184 * data, use the font ID instead. This sucks but is better than 185 * nothing. 186 */ 187 pfrface->family_name = phy_font->family_name; 188 if ( pfrface->family_name == NULL ) 189 pfrface->family_name = phy_font->font_id; 190 191 /* note that the style name can be NULL in certain PFR fonts, 192 * probably meaning `Regular' 193 */ 194 pfrface->style_name = phy_font->style_name; 195 196 pfrface->num_fixed_sizes = 0; 197 pfrface->available_sizes = NULL; 198 199 pfrface->bbox = phy_font->bbox; 200 pfrface->units_per_EM = (FT_UShort)phy_font->outline_resolution; 201 pfrface->ascender = (FT_Short) phy_font->bbox.yMax; 202 pfrface->descender = (FT_Short) phy_font->bbox.yMin; 203 204 pfrface->height = (FT_Short)( ( pfrface->units_per_EM * 12 ) / 10 ); 205 if ( pfrface->height < pfrface->ascender - pfrface->descender ) 206 pfrface->height = (FT_Short)(pfrface->ascender - pfrface->descender); 207 208 if ( phy_font->num_strikes > 0 ) 209 { 210 FT_UInt n, count = phy_font->num_strikes; 211 FT_Bitmap_Size* size; 212 PFR_Strike strike; 213 FT_Memory memory = pfrface->stream->memory; 214 215 216 if ( FT_NEW_ARRAY( pfrface->available_sizes, count ) ) 217 goto Exit; 218 219 size = pfrface->available_sizes; 220 strike = phy_font->strikes; 221 for ( n = 0; n < count; n++, size++, strike++ ) 222 { 223 size->height = (FT_Short)strike->y_ppm; 224 size->width = (FT_Short)strike->x_ppm; 225 size->size = (FT_Pos)( strike->y_ppm << 6 ); 226 size->x_ppem = (FT_Pos)( strike->x_ppm << 6 ); 227 size->y_ppem = (FT_Pos)( strike->y_ppm << 6 ); 228 } 229 pfrface->num_fixed_sizes = (FT_Int)count; 230 } 231 232 /* now compute maximum advance width */ 233 if ( ( phy_font->flags & PFR_PHY_PROPORTIONAL ) == 0 ) 234 pfrface->max_advance_width = (FT_Short)phy_font->standard_advance; 235 else 236 { 237 FT_Int max = 0; 238 FT_UInt count = phy_font->num_chars; 239 PFR_Char gchar = phy_font->chars; 240 241 242 for ( ; count > 0; count--, gchar++ ) 243 { 244 if ( max < gchar->advance ) 245 max = gchar->advance; 246 } 247 248 pfrface->max_advance_width = (FT_Short)max; 249 } 250 251 pfrface->max_advance_height = pfrface->height; 252 253 pfrface->underline_position = (FT_Short)( -pfrface->units_per_EM / 10 ); 254 pfrface->underline_thickness = (FT_Short)( pfrface->units_per_EM / 30 ); 255 256 /* create charmap */ 257 { 258 FT_CharMapRec charmap; 259 260 261 charmap.face = pfrface; 262 charmap.platform_id = TT_PLATFORM_MICROSOFT; 263 charmap.encoding_id = TT_MS_ID_UNICODE_CS; 264 charmap.encoding = FT_ENCODING_UNICODE; 265 266 error = FT_CMap_New( &pfr_cmap_class_rec, NULL, &charmap, NULL ); 267 268 #if 0 269 /* select default charmap */ 270 if ( pfrface->num_charmaps ) 271 pfrface->charmap = pfrface->charmaps[0]; 272 #endif 273 } 274 275 /* check whether we have loaded any kerning pairs */ 276 if ( phy_font->num_kern_pairs ) 277 pfrface->face_flags |= FT_FACE_FLAG_KERNING; 278 } 279 280 Exit: 281 return error; 282 } 283 284 285 /*************************************************************************/ 286 /*************************************************************************/ 287 /***** *****/ 288 /***** SLOT OBJECT METHOD *****/ 289 /***** *****/ 290 /*************************************************************************/ 291 /*************************************************************************/ 292 293 FT_LOCAL_DEF( FT_Error ) 294 pfr_slot_init( FT_GlyphSlot pfrslot ) /* PFR_Slot */ 295 { 296 PFR_Slot slot = (PFR_Slot)pfrslot; 297 FT_GlyphLoader loader = pfrslot->internal->loader; 298 299 300 pfr_glyph_init( &slot->glyph, loader ); 301 302 return 0; 303 } 304 305 306 FT_LOCAL_DEF( void ) 307 pfr_slot_done( FT_GlyphSlot pfrslot ) /* PFR_Slot */ 308 { 309 PFR_Slot slot = (PFR_Slot)pfrslot; 310 311 312 pfr_glyph_done( &slot->glyph ); 313 } 314 315 316 FT_LOCAL_DEF( FT_Error ) 317 pfr_slot_load( FT_GlyphSlot pfrslot, /* PFR_Slot */ 318 FT_Size pfrsize, /* PFR_Size */ 319 FT_UInt gindex, 320 FT_Int32 load_flags ) 321 { 322 PFR_Slot slot = (PFR_Slot)pfrslot; 323 PFR_Size size = (PFR_Size)pfrsize; 324 FT_Error error; 325 PFR_Face face = (PFR_Face)pfrslot->face; 326 PFR_Char gchar; 327 FT_Outline* outline = &pfrslot->outline; 328 FT_ULong gps_offset; 329 330 331 FT_TRACE1(( "pfr_slot_load: glyph index %d\n", gindex )); 332 333 if ( gindex > 0 ) 334 gindex--; 335 336 if ( !face || gindex >= face->phy_font.num_chars ) 337 { 338 error = FT_THROW( Invalid_Argument ); 339 goto Exit; 340 } 341 342 /* try to load an embedded bitmap */ 343 if ( ( load_flags & ( FT_LOAD_NO_SCALE | FT_LOAD_NO_BITMAP ) ) == 0 ) 344 { 345 error = pfr_slot_load_bitmap( slot, size, gindex ); 346 if ( error == 0 ) 347 goto Exit; 348 } 349 350 if ( load_flags & FT_LOAD_SBITS_ONLY ) 351 { 352 error = FT_THROW( Invalid_Argument ); 353 goto Exit; 354 } 355 356 gchar = face->phy_font.chars + gindex; 357 pfrslot->format = FT_GLYPH_FORMAT_OUTLINE; 358 outline->n_points = 0; 359 outline->n_contours = 0; 360 gps_offset = face->header.gps_section_offset; 361 362 /* load the glyph outline (FT_LOAD_NO_RECURSE isn't supported) */ 363 error = pfr_glyph_load( &slot->glyph, face->root.stream, 364 gps_offset, gchar->gps_offset, gchar->gps_size ); 365 366 if ( !error ) 367 { 368 FT_BBox cbox; 369 FT_Glyph_Metrics* metrics = &pfrslot->metrics; 370 FT_Pos advance; 371 FT_UInt em_metrics, em_outline; 372 FT_Bool scaling; 373 374 375 scaling = FT_BOOL( ( load_flags & FT_LOAD_NO_SCALE ) == 0 ); 376 377 /* copy outline data */ 378 *outline = slot->glyph.loader->base.outline; 379 380 outline->flags &= ~FT_OUTLINE_OWNER; 381 outline->flags |= FT_OUTLINE_REVERSE_FILL; 382 383 if ( size && pfrsize->metrics.y_ppem < 24 ) 384 outline->flags |= FT_OUTLINE_HIGH_PRECISION; 385 386 /* compute the advance vector */ 387 metrics->horiAdvance = 0; 388 metrics->vertAdvance = 0; 389 390 advance = gchar->advance; 391 em_metrics = face->phy_font.metrics_resolution; 392 em_outline = face->phy_font.outline_resolution; 393 394 if ( em_metrics != em_outline ) 395 advance = FT_MulDiv( advance, 396 (FT_Long)em_outline, 397 (FT_Long)em_metrics ); 398 399 if ( face->phy_font.flags & PFR_PHY_VERTICAL ) 400 metrics->vertAdvance = advance; 401 else 402 metrics->horiAdvance = advance; 403 404 pfrslot->linearHoriAdvance = metrics->horiAdvance; 405 pfrslot->linearVertAdvance = metrics->vertAdvance; 406 407 /* make up vertical metrics(?) */ 408 metrics->vertBearingX = 0; 409 metrics->vertBearingY = 0; 410 411 #if 0 /* some fonts seem to be broken here! */ 412 413 /* Apply the font matrix, if any. */ 414 /* TODO: Test existing fonts with unusual matrix */ 415 /* whether we have to adjust Units per EM. */ 416 { 417 FT_Matrix font_matrix; 418 419 420 font_matrix.xx = face->log_font.matrix[0] << 8; 421 font_matrix.yx = face->log_font.matrix[1] << 8; 422 font_matrix.xy = face->log_font.matrix[2] << 8; 423 font_matrix.yy = face->log_font.matrix[3] << 8; 424 425 FT_Outline_Transform( outline, &font_matrix ); 426 } 427 #endif 428 429 /* scale when needed */ 430 if ( scaling ) 431 { 432 FT_Int n; 433 FT_Fixed x_scale = pfrsize->metrics.x_scale; 434 FT_Fixed y_scale = pfrsize->metrics.y_scale; 435 FT_Vector* vec = outline->points; 436 437 438 /* scale outline points */ 439 for ( n = 0; n < outline->n_points; n++, vec++ ) 440 { 441 vec->x = FT_MulFix( vec->x, x_scale ); 442 vec->y = FT_MulFix( vec->y, y_scale ); 443 } 444 445 /* scale the advance */ 446 metrics->horiAdvance = FT_MulFix( metrics->horiAdvance, x_scale ); 447 metrics->vertAdvance = FT_MulFix( metrics->vertAdvance, y_scale ); 448 } 449 450 /* compute the rest of the metrics */ 451 FT_Outline_Get_CBox( outline, &cbox ); 452 453 metrics->width = cbox.xMax - cbox.xMin; 454 metrics->height = cbox.yMax - cbox.yMin; 455 metrics->horiBearingX = cbox.xMin; 456 metrics->horiBearingY = cbox.yMax - metrics->height; 457 } 458 459 Exit: 460 return error; 461 } 462 463 464 /*************************************************************************/ 465 /*************************************************************************/ 466 /***** *****/ 467 /***** KERNING METHOD *****/ 468 /***** *****/ 469 /*************************************************************************/ 470 /*************************************************************************/ 471 472 FT_LOCAL_DEF( FT_Error ) 473 pfr_face_get_kerning( FT_Face pfrface, /* PFR_Face */ 474 FT_UInt glyph1, 475 FT_UInt glyph2, 476 FT_Vector* kerning ) 477 { 478 PFR_Face face = (PFR_Face)pfrface; 479 FT_Error error = FT_Err_Ok; 480 PFR_PhyFont phy_font = &face->phy_font; 481 FT_UInt32 code1, code2, pair; 482 483 484 kerning->x = 0; 485 kerning->y = 0; 486 487 if ( glyph1 > 0 ) 488 glyph1--; 489 490 if ( glyph2 > 0 ) 491 glyph2--; 492 493 /* convert glyph indices to character codes */ 494 if ( glyph1 > phy_font->num_chars || 495 glyph2 > phy_font->num_chars ) 496 goto Exit; 497 498 code1 = phy_font->chars[glyph1].char_code; 499 code2 = phy_font->chars[glyph2].char_code; 500 pair = PFR_KERN_INDEX( code1, code2 ); 501 502 /* now search the list of kerning items */ 503 { 504 PFR_KernItem item = phy_font->kern_items; 505 FT_Stream stream = pfrface->stream; 506 507 508 for ( ; item; item = item->next ) 509 { 510 if ( pair >= item->pair1 && pair <= item->pair2 ) 511 goto FoundPair; 512 } 513 goto Exit; 514 515 FoundPair: /* we found an item, now parse it and find the value if any */ 516 if ( FT_STREAM_SEEK( item->offset ) || 517 FT_FRAME_ENTER( item->pair_count * item->pair_size ) ) 518 goto Exit; 519 520 { 521 FT_UInt count = item->pair_count; 522 FT_UInt size = item->pair_size; 523 FT_UInt power = 1 << FT_MSB( count ); 524 FT_UInt probe = power * size; 525 FT_UInt extra = count - power; 526 FT_Byte* base = stream->cursor; 527 FT_Bool twobytes = FT_BOOL( item->flags & 1 ); 528 FT_Bool twobyte_adj = FT_BOOL( item->flags & 2 ); 529 FT_Byte* p; 530 FT_UInt32 cpair; 531 532 533 if ( extra > 0 ) 534 { 535 p = base + extra * size; 536 537 if ( twobytes ) 538 cpair = FT_NEXT_ULONG( p ); 539 else 540 cpair = PFR_NEXT_KPAIR( p ); 541 542 if ( cpair == pair ) 543 goto Found; 544 545 if ( cpair < pair ) 546 { 547 if ( twobyte_adj ) 548 p += 2; 549 else 550 p++; 551 base = p; 552 } 553 } 554 555 while ( probe > size ) 556 { 557 probe >>= 1; 558 p = base + probe; 559 560 if ( twobytes ) 561 cpair = FT_NEXT_ULONG( p ); 562 else 563 cpair = PFR_NEXT_KPAIR( p ); 564 565 if ( cpair == pair ) 566 goto Found; 567 568 if ( cpair < pair ) 569 base += probe; 570 } 571 572 p = base; 573 574 if ( twobytes ) 575 cpair = FT_NEXT_ULONG( p ); 576 else 577 cpair = PFR_NEXT_KPAIR( p ); 578 579 if ( cpair == pair ) 580 { 581 FT_Int value; 582 583 584 Found: 585 if ( twobyte_adj ) 586 value = FT_PEEK_SHORT( p ); 587 else 588 value = p[0]; 589 590 kerning->x = item->base_adj + value; 591 } 592 } 593 594 FT_FRAME_EXIT(); 595 } 596 597 Exit: 598 return error; 599 } 600 601 602 /* END */ 603