OLD | NEW |
(Empty) | |
| 1 /***************************************************************************/ |
| 2 /* */ |
| 3 /* cf2ft.c */ |
| 4 /* */ |
| 5 /* FreeType Glue Component to Adobe's Interpreter (body). */ |
| 6 /* */ |
| 7 /* Copyright 2013 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 |
| 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 FT_ASSERT( transform->a > 0 && transform->d > 0 ); |
| 65 FT_ASSERT( transform->b == 0 && transform->c == 0 ); |
| 66 FT_ASSERT( transform->tx == 0 && transform->ty == 0 ); |
| 67 |
| 68 if ( unitsPerEm > 0x7FFF ) |
| 69 return FT_THROW( Glyph_Too_Big ); |
| 70 |
| 71 maxScale = FT_DivFix( CF2_MAX_SIZE, cf2_intToFixed( unitsPerEm ) ); |
| 72 |
| 73 if ( transform->a > maxScale || transform->d > maxScale ) |
| 74 return FT_THROW( Glyph_Too_Big ); |
| 75 |
| 76 return FT_Err_Ok; |
| 77 } |
| 78 |
| 79 |
| 80 static void |
| 81 cf2_setGlyphWidth( CF2_Outline outline, |
| 82 CF2_Fixed width ) |
| 83 { |
| 84 CFF_Decoder* decoder = outline->decoder; |
| 85 |
| 86 |
| 87 FT_ASSERT( decoder ); |
| 88 |
| 89 decoder->glyph_width = cf2_fixedToInt( width ); |
| 90 } |
| 91 |
| 92 |
| 93 /* Clean up font instance. */ |
| 94 static void |
| 95 cf2_free_instance( void* ptr ) |
| 96 { |
| 97 CF2_Font font = (CF2_Font)ptr; |
| 98 |
| 99 |
| 100 if ( font ) |
| 101 { |
| 102 FT_Memory memory = font->memory; |
| 103 |
| 104 |
| 105 (void)memory; |
| 106 } |
| 107 } |
| 108 |
| 109 |
| 110 /********************************************/ |
| 111 /* */ |
| 112 /* functions for handling client outline; */ |
| 113 /* FreeType uses coordinates in 26.6 format */ |
| 114 /* */ |
| 115 /********************************************/ |
| 116 |
| 117 static void |
| 118 cf2_builder_moveTo( CF2_OutlineCallbacks callbacks, |
| 119 const CF2_CallbackParams params ) |
| 120 { |
| 121 /* downcast the object pointer */ |
| 122 CF2_Outline outline = (CF2_Outline)callbacks; |
| 123 CFF_Builder* builder; |
| 124 |
| 125 (void)params; /* only used in debug mode */ |
| 126 |
| 127 |
| 128 FT_ASSERT( outline && outline->decoder ); |
| 129 FT_ASSERT( params->op == CF2_PathOpMoveTo ); |
| 130 |
| 131 builder = &outline->decoder->builder; |
| 132 |
| 133 /* note: two successive moves simply close the contour twice */ |
| 134 cff_builder_close_contour( builder ); |
| 135 builder->path_begun = 0; |
| 136 } |
| 137 |
| 138 |
| 139 static void |
| 140 cf2_builder_lineTo( CF2_OutlineCallbacks callbacks, |
| 141 const CF2_CallbackParams params ) |
| 142 { |
| 143 /* downcast the object pointer */ |
| 144 CF2_Outline outline = (CF2_Outline)callbacks; |
| 145 CFF_Builder* builder; |
| 146 |
| 147 |
| 148 FT_ASSERT( outline && outline->decoder ); |
| 149 FT_ASSERT( params->op == CF2_PathOpLineTo ); |
| 150 |
| 151 builder = &outline->decoder->builder; |
| 152 |
| 153 if ( !builder->path_begun ) |
| 154 { |
| 155 /* record the move before the line; also check points and set */ |
| 156 /* `path_begun' */ |
| 157 cff_builder_start_point( builder, |
| 158 params->pt0.x, |
| 159 params->pt0.y ); |
| 160 } |
| 161 |
| 162 /* `cff_builder_add_point1' includes a check_points call for one point */ |
| 163 cff_builder_add_point1( builder, |
| 164 params->pt1.x, |
| 165 params->pt1.y ); |
| 166 } |
| 167 |
| 168 |
| 169 static void |
| 170 cf2_builder_cubeTo( CF2_OutlineCallbacks callbacks, |
| 171 const CF2_CallbackParams params ) |
| 172 { |
| 173 /* downcast the object pointer */ |
| 174 CF2_Outline outline = (CF2_Outline)callbacks; |
| 175 CFF_Builder* builder; |
| 176 |
| 177 |
| 178 FT_ASSERT( outline && outline->decoder ); |
| 179 FT_ASSERT( params->op == CF2_PathOpCubeTo ); |
| 180 |
| 181 builder = &outline->decoder->builder; |
| 182 |
| 183 if ( !builder->path_begun ) |
| 184 { |
| 185 /* record the move before the line; also check points and set */ |
| 186 /* `path_begun' */ |
| 187 cff_builder_start_point( builder, |
| 188 params->pt0.x, |
| 189 params->pt0.y ); |
| 190 } |
| 191 |
| 192 /* prepare room for 3 points: 2 off-curve, 1 on-curve */ |
| 193 cff_check_points( builder, 3 ); |
| 194 |
| 195 cff_builder_add_point( builder, |
| 196 params->pt1.x, |
| 197 params->pt1.y, 0 ); |
| 198 cff_builder_add_point( builder, |
| 199 params->pt2.x, |
| 200 params->pt2.y, 0 ); |
| 201 cff_builder_add_point( builder, |
| 202 params->pt3.x, |
| 203 params->pt3.y, 1 ); |
| 204 } |
| 205 |
| 206 |
| 207 static void |
| 208 cf2_outline_init( CF2_Outline outline, |
| 209 FT_Memory memory, |
| 210 FT_Error* error ) |
| 211 { |
| 212 FT_MEM_ZERO( outline, sizeof ( CF2_OutlineRec ) ); |
| 213 |
| 214 outline->root.memory = memory; |
| 215 outline->root.error = error; |
| 216 |
| 217 outline->root.moveTo = cf2_builder_moveTo; |
| 218 outline->root.lineTo = cf2_builder_lineTo; |
| 219 outline->root.cubeTo = cf2_builder_cubeTo; |
| 220 } |
| 221 |
| 222 |
| 223 /* get scaling and hint flag from GlyphSlot */ |
| 224 static void |
| 225 cf2_getScaleAndHintFlag( CFF_Decoder* decoder, |
| 226 CF2_Fixed* x_scale, |
| 227 CF2_Fixed* y_scale, |
| 228 FT_Bool* hinted, |
| 229 FT_Bool* scaled ) |
| 230 { |
| 231 FT_ASSERT( decoder && decoder->builder.glyph ); |
| 232 |
| 233 /* note: FreeType scale includes a factor of 64 */ |
| 234 *hinted = decoder->builder.glyph->hint; |
| 235 *scaled = decoder->builder.glyph->scaled; |
| 236 |
| 237 if ( *hinted ) |
| 238 { |
| 239 *x_scale = FT_DivFix( decoder->builder.glyph->x_scale, |
| 240 cf2_intToFixed( 64 ) ); |
| 241 *y_scale = FT_DivFix( decoder->builder.glyph->y_scale, |
| 242 cf2_intToFixed( 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 |
| 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 ) |
| 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 /* now get an outline for this glyph; */ |
| 348 /* also get units per em to validate scale */ |
| 349 font->unitsPerEm = (CF2_Int)cf2_getUnitsPerEm( decoder ); |
| 350 |
| 351 error2 = cf2_checkTransform( &transform, font->unitsPerEm ); |
| 352 if ( error2 ) |
| 353 return error2; |
| 354 |
| 355 error2 = cf2_getGlyphOutline( font, &buf, &transform, &glyphWidth ); |
| 356 if ( error2 ) |
| 357 return FT_ERR( Invalid_File_Format ); |
| 358 |
| 359 cf2_setGlyphWidth( &font->outline, glyphWidth ); |
| 360 |
| 361 return FT_Err_Ok; |
| 362 } |
| 363 } |
| 364 |
| 365 |
| 366 /* get pointer to current FreeType subfont (based on current glyphID) */ |
| 367 FT_LOCAL_DEF( CFF_SubFont ) |
| 368 cf2_getSubfont( CFF_Decoder* decoder ) |
| 369 { |
| 370 FT_ASSERT( decoder && decoder->current_subfont ); |
| 371 |
| 372 return decoder->current_subfont; |
| 373 } |
| 374 |
| 375 |
| 376 /* get `y_ppem' from `CFF_Size' */ |
| 377 FT_LOCAL_DEF( CF2_Fixed ) |
| 378 cf2_getPpemY( CFF_Decoder* decoder ) |
| 379 { |
| 380 FT_ASSERT( decoder && |
| 381 decoder->builder.face && |
| 382 decoder->builder.face->root.size ); |
| 383 FT_ASSERT( decoder->builder.face->root.size->metrics.y_ppem ); |
| 384 |
| 385 return cf2_intToFixed( |
| 386 decoder->builder.face->root.size->metrics.y_ppem ); |
| 387 } |
| 388 |
| 389 |
| 390 /* get standard stem widths for the current subfont; */ |
| 391 /* FreeType stores these as integer font units */ |
| 392 /* (note: variable names seem swapped) */ |
| 393 FT_LOCAL_DEF( CF2_Fixed ) |
| 394 cf2_getStdVW( CFF_Decoder* decoder ) |
| 395 { |
| 396 FT_ASSERT( decoder && decoder->current_subfont ); |
| 397 |
| 398 return cf2_intToFixed( |
| 399 decoder->current_subfont->private_dict.standard_height ); |
| 400 } |
| 401 |
| 402 |
| 403 FT_LOCAL_DEF( CF2_Fixed ) |
| 404 cf2_getStdHW( CFF_Decoder* decoder ) |
| 405 { |
| 406 FT_ASSERT( decoder && decoder->current_subfont ); |
| 407 |
| 408 return cf2_intToFixed( |
| 409 decoder->current_subfont->private_dict.standard_width ); |
| 410 } |
| 411 |
| 412 |
| 413 /* note: FreeType stores 1000 times the actual value for `BlueScale' */ |
| 414 FT_LOCAL_DEF( void ) |
| 415 cf2_getBlueMetrics( CFF_Decoder* decoder, |
| 416 CF2_Fixed* blueScale, |
| 417 CF2_Fixed* blueShift, |
| 418 CF2_Fixed* blueFuzz ) |
| 419 { |
| 420 FT_ASSERT( decoder && decoder->current_subfont ); |
| 421 |
| 422 *blueScale = FT_DivFix( |
| 423 decoder->current_subfont->private_dict.blue_scale, |
| 424 cf2_intToFixed( 1000 ) ); |
| 425 *blueShift = cf2_intToFixed( |
| 426 decoder->current_subfont->private_dict.blue_shift ); |
| 427 *blueFuzz = cf2_intToFixed( |
| 428 decoder->current_subfont->private_dict.blue_fuzz ); |
| 429 } |
| 430 |
| 431 |
| 432 /* get blue values counts and arrays; the FreeType parser has validated */ |
| 433 /* the counts and verified that each is an even number */ |
| 434 FT_LOCAL_DEF( void ) |
| 435 cf2_getBlueValues( CFF_Decoder* decoder, |
| 436 size_t* count, |
| 437 FT_Pos* *data ) |
| 438 { |
| 439 FT_ASSERT( decoder && decoder->current_subfont ); |
| 440 |
| 441 *count = decoder->current_subfont->private_dict.num_blue_values; |
| 442 *data = (FT_Pos*) |
| 443 &decoder->current_subfont->private_dict.blue_values; |
| 444 } |
| 445 |
| 446 |
| 447 FT_LOCAL_DEF( void ) |
| 448 cf2_getOtherBlues( CFF_Decoder* decoder, |
| 449 size_t* count, |
| 450 FT_Pos* *data ) |
| 451 { |
| 452 FT_ASSERT( decoder && decoder->current_subfont ); |
| 453 |
| 454 *count = decoder->current_subfont->private_dict.num_other_blues; |
| 455 *data = (FT_Pos*) |
| 456 &decoder->current_subfont->private_dict.other_blues; |
| 457 } |
| 458 |
| 459 |
| 460 FT_LOCAL_DEF( void ) |
| 461 cf2_getFamilyBlues( CFF_Decoder* decoder, |
| 462 size_t* count, |
| 463 FT_Pos* *data ) |
| 464 { |
| 465 FT_ASSERT( decoder && decoder->current_subfont ); |
| 466 |
| 467 *count = decoder->current_subfont->private_dict.num_family_blues; |
| 468 *data = (FT_Pos*) |
| 469 &decoder->current_subfont->private_dict.family_blues; |
| 470 } |
| 471 |
| 472 |
| 473 FT_LOCAL_DEF( void ) |
| 474 cf2_getFamilyOtherBlues( CFF_Decoder* decoder, |
| 475 size_t* count, |
| 476 FT_Pos* *data ) |
| 477 { |
| 478 FT_ASSERT( decoder && decoder->current_subfont ); |
| 479 |
| 480 *count = decoder->current_subfont->private_dict.num_family_other_blues; |
| 481 *data = (FT_Pos*) |
| 482 &decoder->current_subfont->private_dict.family_other_blues; |
| 483 } |
| 484 |
| 485 |
| 486 FT_LOCAL_DEF( CF2_Int ) |
| 487 cf2_getLanguageGroup( CFF_Decoder* decoder ) |
| 488 { |
| 489 FT_ASSERT( decoder && decoder->current_subfont ); |
| 490 |
| 491 return decoder->current_subfont->private_dict.language_group; |
| 492 } |
| 493 |
| 494 |
| 495 /* convert unbiased subroutine index to `CF2_Buffer' and */ |
| 496 /* return 0 on success */ |
| 497 FT_LOCAL_DEF( CF2_Int ) |
| 498 cf2_initGlobalRegionBuffer( CFF_Decoder* decoder, |
| 499 CF2_UInt idx, |
| 500 CF2_Buffer buf ) |
| 501 { |
| 502 FT_ASSERT( decoder && decoder->globals ); |
| 503 |
| 504 FT_ZERO( buf ); |
| 505 |
| 506 idx += decoder->globals_bias; |
| 507 if ( idx >= decoder->num_globals ) |
| 508 return TRUE; /* error */ |
| 509 |
| 510 buf->start = |
| 511 buf->ptr = decoder->globals[idx]; |
| 512 buf->end = decoder->globals[idx + 1]; |
| 513 |
| 514 return FALSE; /* success */ |
| 515 } |
| 516 |
| 517 |
| 518 /* convert AdobeStandardEncoding code to CF2_Buffer; */ |
| 519 /* used for seac component */ |
| 520 FT_LOCAL_DEF( FT_Error ) |
| 521 cf2_getSeacComponent( CFF_Decoder* decoder, |
| 522 CF2_UInt code, |
| 523 CF2_Buffer buf ) |
| 524 { |
| 525 CF2_Int gid; |
| 526 FT_Byte* charstring; |
| 527 FT_ULong len; |
| 528 FT_Error error; |
| 529 |
| 530 |
| 531 FT_ASSERT( decoder ); |
| 532 |
| 533 FT_ZERO( buf ); |
| 534 |
| 535 gid = cff_lookup_glyph_by_stdcharcode( decoder->cff, code ); |
| 536 if ( gid < 0 ) |
| 537 return FT_THROW( Invalid_Glyph_Format ); |
| 538 |
| 539 error = cff_get_glyph_data( decoder->builder.face, |
| 540 gid, |
| 541 &charstring, |
| 542 &len ); |
| 543 /* TODO: for now, just pass the FreeType error through */ |
| 544 if ( error ) |
| 545 return error; |
| 546 |
| 547 /* assume input has been validated */ |
| 548 FT_ASSERT( charstring + len >= charstring ); |
| 549 |
| 550 buf->start = charstring; |
| 551 buf->end = charstring + len; |
| 552 buf->ptr = buf->start; |
| 553 |
| 554 return FT_Err_Ok; |
| 555 } |
| 556 |
| 557 |
| 558 FT_LOCAL_DEF( void ) |
| 559 cf2_freeSeacComponent( CFF_Decoder* decoder, |
| 560 CF2_Buffer buf ) |
| 561 { |
| 562 FT_ASSERT( decoder ); |
| 563 |
| 564 cff_free_glyph_data( decoder->builder.face, |
| 565 (FT_Byte**)&buf->start, |
| 566 (FT_ULong)( buf->end - buf->start ) ); |
| 567 } |
| 568 |
| 569 |
| 570 FT_LOCAL_DEF( CF2_Int ) |
| 571 cf2_initLocalRegionBuffer( CFF_Decoder* decoder, |
| 572 CF2_UInt idx, |
| 573 CF2_Buffer buf ) |
| 574 { |
| 575 FT_ASSERT( decoder && decoder->locals ); |
| 576 |
| 577 FT_ZERO( buf ); |
| 578 |
| 579 idx += decoder->locals_bias; |
| 580 if ( idx >= decoder->num_locals ) |
| 581 return TRUE; /* error */ |
| 582 |
| 583 buf->start = |
| 584 buf->ptr = decoder->locals[idx]; |
| 585 buf->end = decoder->locals[idx + 1]; |
| 586 |
| 587 return FALSE; /* success */ |
| 588 } |
| 589 |
| 590 |
| 591 FT_LOCAL_DEF( CF2_Fixed ) |
| 592 cf2_getDefaultWidthX( CFF_Decoder* decoder ) |
| 593 { |
| 594 FT_ASSERT( decoder && decoder->current_subfont ); |
| 595 |
| 596 return cf2_intToFixed( |
| 597 decoder->current_subfont->private_dict.default_width ); |
| 598 } |
| 599 |
| 600 |
| 601 FT_LOCAL_DEF( CF2_Fixed ) |
| 602 cf2_getNominalWidthX( CFF_Decoder* decoder ) |
| 603 { |
| 604 FT_ASSERT( decoder && decoder->current_subfont ); |
| 605 |
| 606 return cf2_intToFixed( |
| 607 decoder->current_subfont->private_dict.nominal_width ); |
| 608 } |
| 609 |
| 610 |
| 611 FT_LOCAL_DEF( void ) |
| 612 cf2_outline_reset( CF2_Outline outline ) |
| 613 { |
| 614 CFF_Decoder* decoder = outline->decoder; |
| 615 |
| 616 |
| 617 FT_ASSERT( decoder ); |
| 618 |
| 619 outline->root.windingMomentum = 0; |
| 620 |
| 621 FT_GlyphLoader_Rewind( decoder->builder.loader ); |
| 622 } |
| 623 |
| 624 |
| 625 FT_LOCAL_DEF( void ) |
| 626 cf2_outline_close( CF2_Outline outline ) |
| 627 { |
| 628 CFF_Decoder* decoder = outline->decoder; |
| 629 |
| 630 |
| 631 FT_ASSERT( decoder ); |
| 632 |
| 633 cff_builder_close_contour( &decoder->builder ); |
| 634 |
| 635 FT_GlyphLoader_Add( decoder->builder.loader ); |
| 636 } |
| 637 |
| 638 |
| 639 /* END */ |
OLD | NEW |