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