1 /***************************************************************************/ 2 /* */ 3 /* cf2ft.c */ 4 /* */ 5 /* FreeType Glue Component to Adobe's Interpreter (body). */ 6 /* */ 7 /* Copyright 2013-2014 Adobe Systems Incorporated. */ 8 /* */ 9 /* This software, and all works of authorship, whether in source or */ 10 /* object code form as indicated by the copyright notice(s) included */ 11 /* herein (collectively, the "Work") is made available, and may only be */ 12 /* used, modified, and distributed under the FreeType Project License, */ 13 /* LICENSE.TXT. Additionally, subject to the terms and conditions of the */ 14 /* FreeType Project License, each contributor to the Work hereby grants */ 15 /* to any individual or legal entity exercising permissions granted by */ 16 /* the FreeType Project License and this section (hereafter, "You" or */ 17 /* "Your") a perpetual, worldwide, non-exclusive, no-charge, */ 18 /* royalty-free, irrevocable (except as stated in this section) patent */ 19 /* license to make, have made, use, offer to sell, sell, import, and */ 20 /* otherwise transfer the Work, where such license applies only to those */ 21 /* patent claims licensable by such contributor that are necessarily */ 22 /* infringed by their contribution(s) alone or by combination of their */ 23 /* contribution(s) with the Work to which such contribution(s) was */ 24 /* submitted. If You institute patent litigation against any entity */ 25 /* (including a cross-claim or counterclaim in a lawsuit) alleging that */ 26 /* the Work or a contribution incorporated within the Work constitutes */ 27 /* direct or contributory patent infringement, then any patent licenses */ 28 /* granted to You under this License for that Work shall terminate as of */ 29 /* the date such litigation is filed. */ 30 /* */ 31 /* By using, modifying, or distributing the Work you indicate that you */ 32 /* have read and understood the terms and conditions of the */ 33 /* FreeType Project License as well as those provided in this section, */ 34 /* and you accept them fully. */ 35 /* */ 36 /***************************************************************************/ 37 38 39 #include "cf2ft.h" 40 #include FT_INTERNAL_DEBUG_H 41 42 #include "cf2font.h" 43 #include "cf2error.h" 44 45 46 #define CF2_MAX_SIZE cf2_intToFixed( 2000 ) /* max ppem */ 47 48 49 /* 50 * This check should avoid most internal overflow cases. Clients should 51 * generally respond to `Glyph_Too_Big' by getting a glyph outline 52 * at EM size, scaling it and filling it as a graphics operation. 53 * 54 */ 55 static FT_Error cf2_checkTransform(const CF2_Matrix * transform,CF2_Int unitsPerEm)56 cf2_checkTransform( const CF2_Matrix* transform, 57 CF2_Int unitsPerEm ) 58 { 59 CF2_Fixed maxScale; 60 61 62 FT_ASSERT( unitsPerEm > 0 ); 63 64 if ( transform->a <= 0 || transform->d <= 0 ) 65 return FT_THROW( Invalid_Size_Handle ); 66 67 FT_ASSERT( transform->b == 0 && transform->c == 0 ); 68 FT_ASSERT( transform->tx == 0 && transform->ty == 0 ); 69 70 if ( unitsPerEm > 0x7FFF ) 71 return FT_THROW( Glyph_Too_Big ); 72 73 maxScale = FT_DivFix( CF2_MAX_SIZE, cf2_intToFixed( unitsPerEm ) ); 74 75 if ( transform->a > maxScale || transform->d > maxScale ) 76 return FT_THROW( Glyph_Too_Big ); 77 78 return FT_Err_Ok; 79 } 80 81 82 static void cf2_setGlyphWidth(CF2_Outline outline,CF2_Fixed width)83 cf2_setGlyphWidth( CF2_Outline outline, 84 CF2_Fixed width ) 85 { 86 CFF_Decoder* decoder = outline->decoder; 87 88 89 FT_ASSERT( decoder ); 90 91 decoder->glyph_width = cf2_fixedToInt( width ); 92 } 93 94 95 /* Clean up font instance. */ 96 static void cf2_free_instance(void * ptr)97 cf2_free_instance( void* ptr ) 98 { 99 CF2_Font font = (CF2_Font)ptr; 100 101 102 if ( font ) 103 { 104 FT_Memory memory = font->memory; 105 106 107 (void)memory; 108 } 109 } 110 111 112 /********************************************/ 113 /* */ 114 /* functions for handling client outline; */ 115 /* FreeType uses coordinates in 26.6 format */ 116 /* */ 117 /********************************************/ 118 119 static void cf2_builder_moveTo(CF2_OutlineCallbacks callbacks,const CF2_CallbackParams params)120 cf2_builder_moveTo( CF2_OutlineCallbacks callbacks, 121 const CF2_CallbackParams params ) 122 { 123 /* downcast the object pointer */ 124 CF2_Outline outline = (CF2_Outline)callbacks; 125 CFF_Builder* builder; 126 127 (void)params; /* only used in debug mode */ 128 129 130 FT_ASSERT( outline && outline->decoder ); 131 FT_ASSERT( params->op == CF2_PathOpMoveTo ); 132 133 builder = &outline->decoder->builder; 134 135 /* note: two successive moves simply close the contour twice */ 136 cff_builder_close_contour( builder ); 137 builder->path_begun = 0; 138 } 139 140 141 static void cf2_builder_lineTo(CF2_OutlineCallbacks callbacks,const CF2_CallbackParams params)142 cf2_builder_lineTo( CF2_OutlineCallbacks callbacks, 143 const CF2_CallbackParams params ) 144 { 145 /* downcast the object pointer */ 146 CF2_Outline outline = (CF2_Outline)callbacks; 147 CFF_Builder* builder; 148 149 150 FT_ASSERT( outline && outline->decoder ); 151 FT_ASSERT( params->op == CF2_PathOpLineTo ); 152 153 builder = &outline->decoder->builder; 154 155 if ( !builder->path_begun ) 156 { 157 /* record the move before the line; also check points and set */ 158 /* `path_begun' */ 159 cff_builder_start_point( builder, 160 params->pt0.x, 161 params->pt0.y ); 162 } 163 164 /* `cff_builder_add_point1' includes a check_points call for one point */ 165 cff_builder_add_point1( builder, 166 params->pt1.x, 167 params->pt1.y ); 168 } 169 170 171 static void cf2_builder_cubeTo(CF2_OutlineCallbacks callbacks,const CF2_CallbackParams params)172 cf2_builder_cubeTo( CF2_OutlineCallbacks callbacks, 173 const CF2_CallbackParams params ) 174 { 175 /* downcast the object pointer */ 176 CF2_Outline outline = (CF2_Outline)callbacks; 177 CFF_Builder* builder; 178 179 180 FT_ASSERT( outline && outline->decoder ); 181 FT_ASSERT( params->op == CF2_PathOpCubeTo ); 182 183 builder = &outline->decoder->builder; 184 185 if ( !builder->path_begun ) 186 { 187 /* record the move before the line; also check points and set */ 188 /* `path_begun' */ 189 cff_builder_start_point( builder, 190 params->pt0.x, 191 params->pt0.y ); 192 } 193 194 /* prepare room for 3 points: 2 off-curve, 1 on-curve */ 195 cff_check_points( builder, 3 ); 196 197 cff_builder_add_point( builder, 198 params->pt1.x, 199 params->pt1.y, 0 ); 200 cff_builder_add_point( builder, 201 params->pt2.x, 202 params->pt2.y, 0 ); 203 cff_builder_add_point( builder, 204 params->pt3.x, 205 params->pt3.y, 1 ); 206 } 207 208 209 static void cf2_outline_init(CF2_Outline outline,FT_Memory memory,FT_Error * error)210 cf2_outline_init( CF2_Outline outline, 211 FT_Memory memory, 212 FT_Error* error ) 213 { 214 FT_MEM_ZERO( outline, sizeof ( CF2_OutlineRec ) ); 215 216 outline->root.memory = memory; 217 outline->root.error = error; 218 219 outline->root.moveTo = cf2_builder_moveTo; 220 outline->root.lineTo = cf2_builder_lineTo; 221 outline->root.cubeTo = cf2_builder_cubeTo; 222 } 223 224 225 /* get scaling and hint flag from GlyphSlot */ 226 static void cf2_getScaleAndHintFlag(CFF_Decoder * decoder,CF2_Fixed * x_scale,CF2_Fixed * y_scale,FT_Bool * hinted,FT_Bool * scaled)227 cf2_getScaleAndHintFlag( CFF_Decoder* decoder, 228 CF2_Fixed* x_scale, 229 CF2_Fixed* y_scale, 230 FT_Bool* hinted, 231 FT_Bool* scaled ) 232 { 233 FT_ASSERT( decoder && decoder->builder.glyph ); 234 235 /* note: FreeType scale includes a factor of 64 */ 236 *hinted = decoder->builder.glyph->hint; 237 *scaled = decoder->builder.glyph->scaled; 238 239 if ( *hinted ) 240 { 241 *x_scale = ( decoder->builder.glyph->x_scale + 32 ) / 64; 242 *y_scale = ( decoder->builder.glyph->y_scale + 32 ) / 64; 243 } 244 else 245 { 246 /* for unhinted outlines, `cff_slot_load' does the scaling, */ 247 /* thus render at `unity' scale */ 248 249 *x_scale = 0x0400; /* 1/64 as 16.16 */ 250 *y_scale = 0x0400; 251 } 252 } 253 254 255 /* get units per em from `FT_Face' */ 256 /* TODO: should handle font matrix concatenation? */ 257 static FT_UShort cf2_getUnitsPerEm(CFF_Decoder * decoder)258 cf2_getUnitsPerEm( CFF_Decoder* decoder ) 259 { 260 FT_ASSERT( decoder && decoder->builder.face ); 261 FT_ASSERT( decoder->builder.face->root.units_per_EM ); 262 263 return decoder->builder.face->root.units_per_EM; 264 } 265 266 267 /* Main entry point: Render one glyph. */ 268 FT_LOCAL_DEF( FT_Error ) cf2_decoder_parse_charstrings(CFF_Decoder * decoder,FT_Byte * charstring_base,FT_ULong charstring_len)269 cf2_decoder_parse_charstrings( CFF_Decoder* decoder, 270 FT_Byte* charstring_base, 271 FT_ULong charstring_len ) 272 { 273 FT_Memory memory; 274 FT_Error error = FT_Err_Ok; 275 CF2_Font font; 276 277 278 FT_ASSERT( decoder && decoder->cff ); 279 280 memory = decoder->builder.memory; 281 282 /* CF2 data is saved here across glyphs */ 283 font = (CF2_Font)decoder->cff->cf2_instance.data; 284 285 /* on first glyph, allocate instance structure */ 286 if ( decoder->cff->cf2_instance.data == NULL ) 287 { 288 decoder->cff->cf2_instance.finalizer = 289 (FT_Generic_Finalizer)cf2_free_instance; 290 291 if ( FT_ALLOC( decoder->cff->cf2_instance.data, 292 sizeof ( CF2_FontRec ) ) ) 293 return FT_THROW( Out_Of_Memory ); 294 295 font = (CF2_Font)decoder->cff->cf2_instance.data; 296 297 font->memory = memory; 298 299 /* initialize a client outline, to be shared by each glyph rendered */ 300 cf2_outline_init( &font->outline, font->memory, &font->error ); 301 } 302 303 /* save decoder; it is a stack variable and will be different on each */ 304 /* call */ 305 font->decoder = decoder; 306 font->outline.decoder = decoder; 307 308 { 309 /* build parameters for Adobe engine */ 310 311 CFF_Builder* builder = &decoder->builder; 312 CFF_Driver driver = (CFF_Driver)FT_FACE_DRIVER( builder->face ); 313 314 /* local error */ 315 FT_Error error2 = FT_Err_Ok; 316 CF2_BufferRec buf; 317 CF2_Matrix transform; 318 CF2_F16Dot16 glyphWidth; 319 320 FT_Bool hinted; 321 FT_Bool scaled; 322 323 324 /* FreeType has already looked up the GID; convert to */ 325 /* `RegionBuffer', assuming that the input has been validated */ 326 FT_ASSERT( charstring_base + charstring_len >= charstring_base ); 327 328 FT_ZERO( &buf ); 329 buf.start = 330 buf.ptr = charstring_base; 331 buf.end = charstring_base + charstring_len; 332 333 FT_ZERO( &transform ); 334 335 cf2_getScaleAndHintFlag( decoder, 336 &transform.a, 337 &transform.d, 338 &hinted, 339 &scaled ); 340 341 font->renderingFlags = 0; 342 if ( hinted ) 343 font->renderingFlags |= CF2_FlagsHinted; 344 if ( scaled && !driver->no_stem_darkening ) 345 font->renderingFlags |= CF2_FlagsDarkened; 346 347 font->darkenParams[0] = driver->darken_params[0]; 348 font->darkenParams[1] = driver->darken_params[1]; 349 font->darkenParams[2] = driver->darken_params[2]; 350 font->darkenParams[3] = driver->darken_params[3]; 351 font->darkenParams[4] = driver->darken_params[4]; 352 font->darkenParams[5] = driver->darken_params[5]; 353 font->darkenParams[6] = driver->darken_params[6]; 354 font->darkenParams[7] = driver->darken_params[7]; 355 356 /* now get an outline for this glyph; */ 357 /* also get units per em to validate scale */ 358 font->unitsPerEm = (CF2_Int)cf2_getUnitsPerEm( decoder ); 359 360 if ( scaled ) 361 { 362 error2 = cf2_checkTransform( &transform, font->unitsPerEm ); 363 if ( error2 ) 364 return error2; 365 } 366 367 error2 = cf2_getGlyphOutline( font, &buf, &transform, &glyphWidth ); 368 if ( error2 ) 369 return FT_ERR( Invalid_File_Format ); 370 371 cf2_setGlyphWidth( &font->outline, glyphWidth ); 372 373 return FT_Err_Ok; 374 } 375 } 376 377 378 /* get pointer to current FreeType subfont (based on current glyphID) */ 379 FT_LOCAL_DEF( CFF_SubFont ) cf2_getSubfont(CFF_Decoder * decoder)380 cf2_getSubfont( CFF_Decoder* decoder ) 381 { 382 FT_ASSERT( decoder && decoder->current_subfont ); 383 384 return decoder->current_subfont; 385 } 386 387 388 /* get `y_ppem' from `CFF_Size' */ 389 FT_LOCAL_DEF( CF2_Fixed ) cf2_getPpemY(CFF_Decoder * decoder)390 cf2_getPpemY( CFF_Decoder* decoder ) 391 { 392 FT_ASSERT( decoder && 393 decoder->builder.face && 394 decoder->builder.face->root.size ); 395 396 /* 397 * Note that `y_ppem' can be zero if there wasn't a call to 398 * `FT_Set_Char_Size' or something similar. However, this isn't a 399 * problem since we come to this place in the code only if 400 * FT_LOAD_NO_SCALE is set (the other case gets caught by 401 * `cf2_checkTransform'). The ppem value is needed to compute the stem 402 * darkening, which is disabled for getting the unscaled outline. 403 * 404 */ 405 return cf2_intToFixed( 406 decoder->builder.face->root.size->metrics.y_ppem ); 407 } 408 409 410 /* get standard stem widths for the current subfont; */ 411 /* FreeType stores these as integer font units */ 412 /* (note: variable names seem swapped) */ 413 FT_LOCAL_DEF( CF2_Fixed ) cf2_getStdVW(CFF_Decoder * decoder)414 cf2_getStdVW( CFF_Decoder* decoder ) 415 { 416 FT_ASSERT( decoder && decoder->current_subfont ); 417 418 return cf2_intToFixed( 419 decoder->current_subfont->private_dict.standard_height ); 420 } 421 422 423 FT_LOCAL_DEF( CF2_Fixed ) cf2_getStdHW(CFF_Decoder * decoder)424 cf2_getStdHW( CFF_Decoder* decoder ) 425 { 426 FT_ASSERT( decoder && decoder->current_subfont ); 427 428 return cf2_intToFixed( 429 decoder->current_subfont->private_dict.standard_width ); 430 } 431 432 433 /* note: FreeType stores 1000 times the actual value for `BlueScale' */ 434 FT_LOCAL_DEF( void ) cf2_getBlueMetrics(CFF_Decoder * decoder,CF2_Fixed * blueScale,CF2_Fixed * blueShift,CF2_Fixed * blueFuzz)435 cf2_getBlueMetrics( CFF_Decoder* decoder, 436 CF2_Fixed* blueScale, 437 CF2_Fixed* blueShift, 438 CF2_Fixed* blueFuzz ) 439 { 440 FT_ASSERT( decoder && decoder->current_subfont ); 441 442 *blueScale = FT_DivFix( 443 decoder->current_subfont->private_dict.blue_scale, 444 cf2_intToFixed( 1000 ) ); 445 *blueShift = cf2_intToFixed( 446 decoder->current_subfont->private_dict.blue_shift ); 447 *blueFuzz = cf2_intToFixed( 448 decoder->current_subfont->private_dict.blue_fuzz ); 449 } 450 451 452 /* get blue values counts and arrays; the FreeType parser has validated */ 453 /* the counts and verified that each is an even number */ 454 FT_LOCAL_DEF( void ) cf2_getBlueValues(CFF_Decoder * decoder,size_t * count,FT_Pos ** data)455 cf2_getBlueValues( CFF_Decoder* decoder, 456 size_t* count, 457 FT_Pos* *data ) 458 { 459 FT_ASSERT( decoder && decoder->current_subfont ); 460 461 *count = decoder->current_subfont->private_dict.num_blue_values; 462 *data = (FT_Pos*) 463 &decoder->current_subfont->private_dict.blue_values; 464 } 465 466 467 FT_LOCAL_DEF( void ) cf2_getOtherBlues(CFF_Decoder * decoder,size_t * count,FT_Pos ** data)468 cf2_getOtherBlues( CFF_Decoder* decoder, 469 size_t* count, 470 FT_Pos* *data ) 471 { 472 FT_ASSERT( decoder && decoder->current_subfont ); 473 474 *count = decoder->current_subfont->private_dict.num_other_blues; 475 *data = (FT_Pos*) 476 &decoder->current_subfont->private_dict.other_blues; 477 } 478 479 480 FT_LOCAL_DEF( void ) cf2_getFamilyBlues(CFF_Decoder * decoder,size_t * count,FT_Pos ** data)481 cf2_getFamilyBlues( CFF_Decoder* decoder, 482 size_t* count, 483 FT_Pos* *data ) 484 { 485 FT_ASSERT( decoder && decoder->current_subfont ); 486 487 *count = decoder->current_subfont->private_dict.num_family_blues; 488 *data = (FT_Pos*) 489 &decoder->current_subfont->private_dict.family_blues; 490 } 491 492 493 FT_LOCAL_DEF( void ) cf2_getFamilyOtherBlues(CFF_Decoder * decoder,size_t * count,FT_Pos ** data)494 cf2_getFamilyOtherBlues( CFF_Decoder* decoder, 495 size_t* count, 496 FT_Pos* *data ) 497 { 498 FT_ASSERT( decoder && decoder->current_subfont ); 499 500 *count = decoder->current_subfont->private_dict.num_family_other_blues; 501 *data = (FT_Pos*) 502 &decoder->current_subfont->private_dict.family_other_blues; 503 } 504 505 506 FT_LOCAL_DEF( CF2_Int ) cf2_getLanguageGroup(CFF_Decoder * decoder)507 cf2_getLanguageGroup( CFF_Decoder* decoder ) 508 { 509 FT_ASSERT( decoder && decoder->current_subfont ); 510 511 return decoder->current_subfont->private_dict.language_group; 512 } 513 514 515 /* convert unbiased subroutine index to `CF2_Buffer' and */ 516 /* return 0 on success */ 517 FT_LOCAL_DEF( CF2_Int ) cf2_initGlobalRegionBuffer(CFF_Decoder * decoder,CF2_UInt idx,CF2_Buffer buf)518 cf2_initGlobalRegionBuffer( CFF_Decoder* decoder, 519 CF2_UInt idx, 520 CF2_Buffer buf ) 521 { 522 FT_ASSERT( decoder ); 523 524 FT_ZERO( buf ); 525 526 idx += decoder->globals_bias; 527 if ( idx >= decoder->num_globals ) 528 return TRUE; /* error */ 529 530 FT_ASSERT( decoder->globals ); 531 532 buf->start = 533 buf->ptr = decoder->globals[idx]; 534 buf->end = decoder->globals[idx + 1]; 535 536 return FALSE; /* success */ 537 } 538 539 540 /* convert AdobeStandardEncoding code to CF2_Buffer; */ 541 /* used for seac component */ 542 FT_LOCAL_DEF( FT_Error ) cf2_getSeacComponent(CFF_Decoder * decoder,CF2_UInt code,CF2_Buffer buf)543 cf2_getSeacComponent( CFF_Decoder* decoder, 544 CF2_UInt code, 545 CF2_Buffer buf ) 546 { 547 CF2_Int gid; 548 FT_Byte* charstring; 549 FT_ULong len; 550 FT_Error error; 551 552 553 FT_ASSERT( decoder ); 554 555 FT_ZERO( buf ); 556 557 gid = cff_lookup_glyph_by_stdcharcode( decoder->cff, code ); 558 if ( gid < 0 ) 559 return FT_THROW( Invalid_Glyph_Format ); 560 561 error = cff_get_glyph_data( decoder->builder.face, 562 gid, 563 &charstring, 564 &len ); 565 /* TODO: for now, just pass the FreeType error through */ 566 if ( error ) 567 return error; 568 569 /* assume input has been validated */ 570 FT_ASSERT( charstring + len >= charstring ); 571 572 buf->start = charstring; 573 buf->end = charstring + len; 574 buf->ptr = buf->start; 575 576 return FT_Err_Ok; 577 } 578 579 580 FT_LOCAL_DEF( void ) cf2_freeSeacComponent(CFF_Decoder * decoder,CF2_Buffer buf)581 cf2_freeSeacComponent( CFF_Decoder* decoder, 582 CF2_Buffer buf ) 583 { 584 FT_ASSERT( decoder ); 585 586 cff_free_glyph_data( decoder->builder.face, 587 (FT_Byte**)&buf->start, 588 (FT_ULong)( buf->end - buf->start ) ); 589 } 590 591 592 FT_LOCAL_DEF( CF2_Int ) cf2_initLocalRegionBuffer(CFF_Decoder * decoder,CF2_UInt idx,CF2_Buffer buf)593 cf2_initLocalRegionBuffer( CFF_Decoder* decoder, 594 CF2_UInt idx, 595 CF2_Buffer buf ) 596 { 597 FT_ASSERT( decoder ); 598 599 FT_ZERO( buf ); 600 601 idx += decoder->locals_bias; 602 if ( idx >= decoder->num_locals ) 603 return TRUE; /* error */ 604 605 FT_ASSERT( decoder->locals ); 606 607 buf->start = 608 buf->ptr = decoder->locals[idx]; 609 buf->end = decoder->locals[idx + 1]; 610 611 return FALSE; /* success */ 612 } 613 614 615 FT_LOCAL_DEF( CF2_Fixed ) cf2_getDefaultWidthX(CFF_Decoder * decoder)616 cf2_getDefaultWidthX( CFF_Decoder* decoder ) 617 { 618 FT_ASSERT( decoder && decoder->current_subfont ); 619 620 return cf2_intToFixed( 621 decoder->current_subfont->private_dict.default_width ); 622 } 623 624 625 FT_LOCAL_DEF( CF2_Fixed ) cf2_getNominalWidthX(CFF_Decoder * decoder)626 cf2_getNominalWidthX( CFF_Decoder* decoder ) 627 { 628 FT_ASSERT( decoder && decoder->current_subfont ); 629 630 return cf2_intToFixed( 631 decoder->current_subfont->private_dict.nominal_width ); 632 } 633 634 635 FT_LOCAL_DEF( void ) cf2_outline_reset(CF2_Outline outline)636 cf2_outline_reset( CF2_Outline outline ) 637 { 638 CFF_Decoder* decoder = outline->decoder; 639 640 641 FT_ASSERT( decoder ); 642 643 outline->root.windingMomentum = 0; 644 645 FT_GlyphLoader_Rewind( decoder->builder.loader ); 646 } 647 648 649 FT_LOCAL_DEF( void ) cf2_outline_close(CF2_Outline outline)650 cf2_outline_close( CF2_Outline outline ) 651 { 652 CFF_Decoder* decoder = outline->decoder; 653 654 655 FT_ASSERT( decoder ); 656 657 cff_builder_close_contour( &decoder->builder ); 658 659 FT_GlyphLoader_Add( decoder->builder.loader ); 660 } 661 662 663 /* END */ 664