1 /**************************************************************************** 2 * 3 * pfrobjs.c 4 * 5 * FreeType PFR object methods (body). 6 * 7 * Copyright (C) 2002-2020 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 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 ) ); 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 ) 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 269 /* check whether we have loaded any kerning pairs */ 270 if ( phy_font->num_kern_pairs ) 271 pfrface->face_flags |= FT_FACE_FLAG_KERNING; 272 } 273 274 Exit: 275 return error; 276 } 277 278 279 /*************************************************************************/ 280 /*************************************************************************/ 281 /***** *****/ 282 /***** SLOT OBJECT METHOD *****/ 283 /***** *****/ 284 /*************************************************************************/ 285 /*************************************************************************/ 286 287 FT_LOCAL_DEF( FT_Error ) pfr_slot_init(FT_GlyphSlot pfrslot)288 pfr_slot_init( FT_GlyphSlot pfrslot ) /* PFR_Slot */ 289 { 290 PFR_Slot slot = (PFR_Slot)pfrslot; 291 FT_GlyphLoader loader = pfrslot->internal->loader; 292 293 294 pfr_glyph_init( &slot->glyph, loader ); 295 296 return 0; 297 } 298 299 300 FT_LOCAL_DEF( void ) pfr_slot_done(FT_GlyphSlot pfrslot)301 pfr_slot_done( FT_GlyphSlot pfrslot ) /* PFR_Slot */ 302 { 303 PFR_Slot slot = (PFR_Slot)pfrslot; 304 305 306 pfr_glyph_done( &slot->glyph ); 307 } 308 309 310 FT_LOCAL_DEF( FT_Error ) pfr_slot_load(FT_GlyphSlot pfrslot,FT_Size pfrsize,FT_UInt gindex,FT_Int32 load_flags)311 pfr_slot_load( FT_GlyphSlot pfrslot, /* PFR_Slot */ 312 FT_Size pfrsize, /* PFR_Size */ 313 FT_UInt gindex, 314 FT_Int32 load_flags ) 315 { 316 PFR_Slot slot = (PFR_Slot)pfrslot; 317 PFR_Size size = (PFR_Size)pfrsize; 318 FT_Error error; 319 PFR_Face face = (PFR_Face)pfrslot->face; 320 PFR_Char gchar; 321 FT_Outline* outline = &pfrslot->outline; 322 FT_ULong gps_offset; 323 324 325 FT_TRACE1(( "pfr_slot_load: glyph index %d\n", gindex )); 326 327 if ( gindex > 0 ) 328 gindex--; 329 330 if ( !face || gindex >= face->phy_font.num_chars ) 331 { 332 error = FT_THROW( Invalid_Argument ); 333 goto Exit; 334 } 335 336 /* try to load an embedded bitmap */ 337 if ( ( load_flags & ( FT_LOAD_NO_SCALE | FT_LOAD_NO_BITMAP ) ) == 0 ) 338 { 339 error = pfr_slot_load_bitmap( 340 slot, 341 size, 342 gindex, 343 ( load_flags & FT_LOAD_BITMAP_METRICS_ONLY ) != 0 ); 344 if ( !error ) 345 goto Exit; 346 } 347 348 if ( load_flags & FT_LOAD_SBITS_ONLY ) 349 { 350 error = FT_THROW( Invalid_Argument ); 351 goto Exit; 352 } 353 354 gchar = face->phy_font.chars + gindex; 355 pfrslot->format = FT_GLYPH_FORMAT_OUTLINE; 356 outline->n_points = 0; 357 outline->n_contours = 0; 358 gps_offset = face->header.gps_section_offset; 359 360 /* load the glyph outline (FT_LOAD_NO_RECURSE isn't supported) */ 361 error = pfr_glyph_load( &slot->glyph, face->root.stream, 362 gps_offset, gchar->gps_offset, gchar->gps_size ); 363 364 if ( !error ) 365 { 366 FT_BBox cbox; 367 FT_Glyph_Metrics* metrics = &pfrslot->metrics; 368 FT_Pos advance; 369 FT_UInt em_metrics, em_outline; 370 FT_Bool scaling; 371 372 373 scaling = FT_BOOL( !( load_flags & FT_LOAD_NO_SCALE ) ); 374 375 /* copy outline data */ 376 *outline = slot->glyph.loader->base.outline; 377 378 outline->flags &= ~FT_OUTLINE_OWNER; 379 outline->flags |= FT_OUTLINE_REVERSE_FILL; 380 381 if ( pfrsize->metrics.y_ppem < 24 ) 382 outline->flags |= FT_OUTLINE_HIGH_PRECISION; 383 384 /* compute the advance vector */ 385 metrics->horiAdvance = 0; 386 metrics->vertAdvance = 0; 387 388 advance = gchar->advance; 389 em_metrics = face->phy_font.metrics_resolution; 390 em_outline = face->phy_font.outline_resolution; 391 392 if ( em_metrics != em_outline ) 393 advance = FT_MulDiv( advance, 394 (FT_Long)em_outline, 395 (FT_Long)em_metrics ); 396 397 if ( face->phy_font.flags & PFR_PHY_VERTICAL ) 398 metrics->vertAdvance = advance; 399 else 400 metrics->horiAdvance = advance; 401 402 pfrslot->linearHoriAdvance = metrics->horiAdvance; 403 pfrslot->linearVertAdvance = metrics->vertAdvance; 404 405 /* make up vertical metrics(?) */ 406 metrics->vertBearingX = 0; 407 metrics->vertBearingY = 0; 408 409 #if 0 /* some fonts seem to be broken here! */ 410 411 /* Apply the font matrix, if any. */ 412 /* TODO: Test existing fonts with unusual matrix */ 413 /* whether we have to adjust Units per EM. */ 414 { 415 FT_Matrix font_matrix; 416 417 418 font_matrix.xx = face->log_font.matrix[0] << 8; 419 font_matrix.yx = face->log_font.matrix[1] << 8; 420 font_matrix.xy = face->log_font.matrix[2] << 8; 421 font_matrix.yy = face->log_font.matrix[3] << 8; 422 423 FT_Outline_Transform( outline, &font_matrix ); 424 } 425 #endif 426 427 /* scale when needed */ 428 if ( scaling ) 429 { 430 FT_Int n; 431 FT_Fixed x_scale = pfrsize->metrics.x_scale; 432 FT_Fixed y_scale = pfrsize->metrics.y_scale; 433 FT_Vector* vec = outline->points; 434 435 436 /* scale outline points */ 437 for ( n = 0; n < outline->n_points; n++, vec++ ) 438 { 439 vec->x = FT_MulFix( vec->x, x_scale ); 440 vec->y = FT_MulFix( vec->y, y_scale ); 441 } 442 443 /* scale the advance */ 444 metrics->horiAdvance = FT_MulFix( metrics->horiAdvance, x_scale ); 445 metrics->vertAdvance = FT_MulFix( metrics->vertAdvance, y_scale ); 446 } 447 448 /* compute the rest of the metrics */ 449 FT_Outline_Get_CBox( outline, &cbox ); 450 451 metrics->width = cbox.xMax - cbox.xMin; 452 metrics->height = cbox.yMax - cbox.yMin; 453 metrics->horiBearingX = cbox.xMin; 454 metrics->horiBearingY = cbox.yMax - metrics->height; 455 } 456 457 Exit: 458 return error; 459 } 460 461 462 /*************************************************************************/ 463 /*************************************************************************/ 464 /***** *****/ 465 /***** KERNING METHOD *****/ 466 /***** *****/ 467 /*************************************************************************/ 468 /*************************************************************************/ 469 470 FT_LOCAL_DEF( FT_Error ) pfr_face_get_kerning(FT_Face pfrface,FT_UInt glyph1,FT_UInt glyph2,FT_Vector * kerning)471 pfr_face_get_kerning( FT_Face pfrface, /* PFR_Face */ 472 FT_UInt glyph1, 473 FT_UInt glyph2, 474 FT_Vector* kerning ) 475 { 476 PFR_Face face = (PFR_Face)pfrface; 477 FT_Error error = FT_Err_Ok; 478 PFR_PhyFont phy_font = &face->phy_font; 479 FT_UInt32 code1, code2, pair; 480 481 482 kerning->x = 0; 483 kerning->y = 0; 484 485 if ( glyph1 > 0 ) 486 glyph1--; 487 488 if ( glyph2 > 0 ) 489 glyph2--; 490 491 /* convert glyph indices to character codes */ 492 if ( glyph1 > phy_font->num_chars || 493 glyph2 > phy_font->num_chars ) 494 goto Exit; 495 496 code1 = phy_font->chars[glyph1].char_code; 497 code2 = phy_font->chars[glyph2].char_code; 498 pair = PFR_KERN_INDEX( code1, code2 ); 499 500 /* now search the list of kerning items */ 501 { 502 PFR_KernItem item = phy_font->kern_items; 503 FT_Stream stream = pfrface->stream; 504 505 506 for ( ; item; item = item->next ) 507 { 508 if ( pair >= item->pair1 && pair <= item->pair2 ) 509 goto FoundPair; 510 } 511 goto Exit; 512 513 FoundPair: /* we found an item, now parse it and find the value if any */ 514 if ( FT_STREAM_SEEK( item->offset ) || 515 FT_FRAME_ENTER( item->pair_count * item->pair_size ) ) 516 goto Exit; 517 518 { 519 FT_UInt count = item->pair_count; 520 FT_UInt size = item->pair_size; 521 FT_UInt power = 1 << FT_MSB( count ); 522 FT_UInt probe = power * size; 523 FT_UInt extra = count - power; 524 FT_Byte* base = stream->cursor; 525 FT_Bool twobytes = FT_BOOL( item->flags & PFR_KERN_2BYTE_CHAR ); 526 FT_Bool twobyte_adj = FT_BOOL( item->flags & PFR_KERN_2BYTE_ADJ ); 527 FT_Byte* p; 528 FT_UInt32 cpair; 529 530 531 if ( extra > 0 ) 532 { 533 p = base + extra * size; 534 535 if ( twobytes ) 536 cpair = FT_NEXT_ULONG( p ); 537 else 538 cpair = PFR_NEXT_KPAIR( p ); 539 540 if ( cpair == pair ) 541 goto Found; 542 543 if ( cpair < pair ) 544 { 545 if ( twobyte_adj ) 546 p += 2; 547 else 548 p++; 549 base = p; 550 } 551 } 552 553 while ( probe > size ) 554 { 555 probe >>= 1; 556 p = base + probe; 557 558 if ( twobytes ) 559 cpair = FT_NEXT_ULONG( p ); 560 else 561 cpair = PFR_NEXT_KPAIR( p ); 562 563 if ( cpair == pair ) 564 goto Found; 565 566 if ( cpair < pair ) 567 base += probe; 568 } 569 570 p = base; 571 572 if ( twobytes ) 573 cpair = FT_NEXT_ULONG( p ); 574 else 575 cpair = PFR_NEXT_KPAIR( p ); 576 577 if ( cpair == pair ) 578 { 579 FT_Int value; 580 581 582 Found: 583 if ( twobyte_adj ) 584 value = FT_PEEK_SHORT( p ); 585 else 586 value = p[0]; 587 588 kerning->x = item->base_adj + value; 589 } 590 } 591 592 FT_FRAME_EXIT(); 593 } 594 595 Exit: 596 return error; 597 } 598 599 600 /* END */ 601