Home | History | Annotate | Download | only in cff
      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 */
    640