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