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