Home | History | Annotate | Download | only in base
      1 /****************************************************************************
      2  *
      3  * ftglyph.c
      4  *
      5  *   FreeType convenience functions to handle glyphs (body).
      6  *
      7  * Copyright 1996-2018 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    *
     20    * This file contains the definition of several convenience functions
     21    * that can be used by client applications to easily retrieve glyph
     22    * bitmaps and outlines from a given face.
     23    *
     24    * These functions should be optional if you are writing a font server
     25    * or text layout engine on top of FreeType.  However, they are pretty
     26    * handy for many other simple uses of the library.
     27    *
     28    */
     29 
     30 
     31 #include <ft2build.h>
     32 #include FT_INTERNAL_DEBUG_H
     33 
     34 #include FT_GLYPH_H
     35 #include FT_OUTLINE_H
     36 #include FT_BITMAP_H
     37 #include FT_INTERNAL_OBJECTS_H
     38 
     39 
     40   /**************************************************************************
     41    *
     42    * The macro FT_COMPONENT is used in trace mode.  It is an implicit
     43    * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log
     44    * messages during execution.
     45    */
     46 #undef  FT_COMPONENT
     47 #define FT_COMPONENT  trace_glyph
     48 
     49 
     50   /*************************************************************************/
     51   /*************************************************************************/
     52   /****                                                                 ****/
     53   /****   FT_BitmapGlyph support                                        ****/
     54   /****                                                                 ****/
     55   /*************************************************************************/
     56   /*************************************************************************/
     57 
     58   FT_CALLBACK_DEF( FT_Error )
     59   ft_bitmap_glyph_init( FT_Glyph      bitmap_glyph,
     60                         FT_GlyphSlot  slot )
     61   {
     62     FT_BitmapGlyph  glyph   = (FT_BitmapGlyph)bitmap_glyph;
     63     FT_Error        error   = FT_Err_Ok;
     64     FT_Library      library = FT_GLYPH( glyph )->library;
     65 
     66 
     67     if ( slot->format != FT_GLYPH_FORMAT_BITMAP )
     68     {
     69       error = FT_THROW( Invalid_Glyph_Format );
     70       goto Exit;
     71     }
     72 
     73     glyph->left = slot->bitmap_left;
     74     glyph->top  = slot->bitmap_top;
     75 
     76     /* do lazy copying whenever possible */
     77     if ( slot->internal->flags & FT_GLYPH_OWN_BITMAP )
     78     {
     79       glyph->bitmap = slot->bitmap;
     80       slot->internal->flags &= ~FT_GLYPH_OWN_BITMAP;
     81     }
     82     else
     83     {
     84       FT_Bitmap_Init( &glyph->bitmap );
     85       error = FT_Bitmap_Copy( library, &slot->bitmap, &glyph->bitmap );
     86     }
     87 
     88   Exit:
     89     return error;
     90   }
     91 
     92 
     93   FT_CALLBACK_DEF( FT_Error )
     94   ft_bitmap_glyph_copy( FT_Glyph  bitmap_source,
     95                         FT_Glyph  bitmap_target )
     96   {
     97     FT_Library      library = bitmap_source->library;
     98     FT_BitmapGlyph  source  = (FT_BitmapGlyph)bitmap_source;
     99     FT_BitmapGlyph  target  = (FT_BitmapGlyph)bitmap_target;
    100 
    101 
    102     target->left = source->left;
    103     target->top  = source->top;
    104 
    105     return FT_Bitmap_Copy( library, &source->bitmap, &target->bitmap );
    106   }
    107 
    108 
    109   FT_CALLBACK_DEF( void )
    110   ft_bitmap_glyph_done( FT_Glyph  bitmap_glyph )
    111   {
    112     FT_BitmapGlyph  glyph   = (FT_BitmapGlyph)bitmap_glyph;
    113     FT_Library      library = FT_GLYPH( glyph )->library;
    114 
    115 
    116     FT_Bitmap_Done( library, &glyph->bitmap );
    117   }
    118 
    119 
    120   FT_CALLBACK_DEF( void )
    121   ft_bitmap_glyph_bbox( FT_Glyph  bitmap_glyph,
    122                         FT_BBox*  cbox )
    123   {
    124     FT_BitmapGlyph  glyph = (FT_BitmapGlyph)bitmap_glyph;
    125 
    126 
    127     cbox->xMin = glyph->left * 64;
    128     cbox->xMax = cbox->xMin + (FT_Pos)( glyph->bitmap.width * 64 );
    129     cbox->yMax = glyph->top * 64;
    130     cbox->yMin = cbox->yMax - (FT_Pos)( glyph->bitmap.rows * 64 );
    131   }
    132 
    133 
    134   FT_DEFINE_GLYPH(
    135     ft_bitmap_glyph_class,
    136 
    137     sizeof ( FT_BitmapGlyphRec ),
    138     FT_GLYPH_FORMAT_BITMAP,
    139 
    140     ft_bitmap_glyph_init,    /* FT_Glyph_InitFunc       glyph_init      */
    141     ft_bitmap_glyph_done,    /* FT_Glyph_DoneFunc       glyph_done      */
    142     ft_bitmap_glyph_copy,    /* FT_Glyph_CopyFunc       glyph_copy      */
    143     NULL,                    /* FT_Glyph_TransformFunc  glyph_transform */
    144     ft_bitmap_glyph_bbox,    /* FT_Glyph_GetBBoxFunc    glyph_bbox      */
    145     NULL                     /* FT_Glyph_PrepareFunc    glyph_prepare   */
    146   )
    147 
    148 
    149   /*************************************************************************/
    150   /*************************************************************************/
    151   /****                                                                 ****/
    152   /****   FT_OutlineGlyph support                                       ****/
    153   /****                                                                 ****/
    154   /*************************************************************************/
    155   /*************************************************************************/
    156 
    157 
    158   FT_CALLBACK_DEF( FT_Error )
    159   ft_outline_glyph_init( FT_Glyph      outline_glyph,
    160                          FT_GlyphSlot  slot )
    161   {
    162     FT_OutlineGlyph  glyph   = (FT_OutlineGlyph)outline_glyph;
    163     FT_Error         error   = FT_Err_Ok;
    164     FT_Library       library = FT_GLYPH( glyph )->library;
    165     FT_Outline*      source  = &slot->outline;
    166     FT_Outline*      target  = &glyph->outline;
    167 
    168 
    169     /* check format in glyph slot */
    170     if ( slot->format != FT_GLYPH_FORMAT_OUTLINE )
    171     {
    172       error = FT_THROW( Invalid_Glyph_Format );
    173       goto Exit;
    174     }
    175 
    176     /* allocate new outline */
    177     error = FT_Outline_New( library,
    178                             (FT_UInt)source->n_points,
    179                             source->n_contours,
    180                             &glyph->outline );
    181     if ( error )
    182       goto Exit;
    183 
    184     FT_Outline_Copy( source, target );
    185 
    186   Exit:
    187     return error;
    188   }
    189 
    190 
    191   FT_CALLBACK_DEF( void )
    192   ft_outline_glyph_done( FT_Glyph  outline_glyph )
    193   {
    194     FT_OutlineGlyph  glyph = (FT_OutlineGlyph)outline_glyph;
    195 
    196 
    197     FT_Outline_Done( FT_GLYPH( glyph )->library, &glyph->outline );
    198   }
    199 
    200 
    201   FT_CALLBACK_DEF( FT_Error )
    202   ft_outline_glyph_copy( FT_Glyph  outline_source,
    203                          FT_Glyph  outline_target )
    204   {
    205     FT_OutlineGlyph  source  = (FT_OutlineGlyph)outline_source;
    206     FT_OutlineGlyph  target  = (FT_OutlineGlyph)outline_target;
    207     FT_Error         error;
    208     FT_Library       library = FT_GLYPH( source )->library;
    209 
    210 
    211     error = FT_Outline_New( library,
    212                             (FT_UInt)source->outline.n_points,
    213                             source->outline.n_contours,
    214                             &target->outline );
    215     if ( !error )
    216       FT_Outline_Copy( &source->outline, &target->outline );
    217 
    218     return error;
    219   }
    220 
    221 
    222   FT_CALLBACK_DEF( void )
    223   ft_outline_glyph_transform( FT_Glyph          outline_glyph,
    224                               const FT_Matrix*  matrix,
    225                               const FT_Vector*  delta )
    226   {
    227     FT_OutlineGlyph  glyph = (FT_OutlineGlyph)outline_glyph;
    228 
    229 
    230     if ( matrix )
    231       FT_Outline_Transform( &glyph->outline, matrix );
    232 
    233     if ( delta )
    234       FT_Outline_Translate( &glyph->outline, delta->x, delta->y );
    235   }
    236 
    237 
    238   FT_CALLBACK_DEF( void )
    239   ft_outline_glyph_bbox( FT_Glyph  outline_glyph,
    240                          FT_BBox*  bbox )
    241   {
    242     FT_OutlineGlyph  glyph = (FT_OutlineGlyph)outline_glyph;
    243 
    244 
    245     FT_Outline_Get_CBox( &glyph->outline, bbox );
    246   }
    247 
    248 
    249   FT_CALLBACK_DEF( FT_Error )
    250   ft_outline_glyph_prepare( FT_Glyph      outline_glyph,
    251                             FT_GlyphSlot  slot )
    252   {
    253     FT_OutlineGlyph  glyph = (FT_OutlineGlyph)outline_glyph;
    254 
    255 
    256     slot->format         = FT_GLYPH_FORMAT_OUTLINE;
    257     slot->outline        = glyph->outline;
    258     slot->outline.flags &= ~FT_OUTLINE_OWNER;
    259 
    260     return FT_Err_Ok;
    261   }
    262 
    263 
    264   FT_DEFINE_GLYPH(
    265     ft_outline_glyph_class,
    266 
    267     sizeof ( FT_OutlineGlyphRec ),
    268     FT_GLYPH_FORMAT_OUTLINE,
    269 
    270     ft_outline_glyph_init,      /* FT_Glyph_InitFunc       glyph_init      */
    271     ft_outline_glyph_done,      /* FT_Glyph_DoneFunc       glyph_done      */
    272     ft_outline_glyph_copy,      /* FT_Glyph_CopyFunc       glyph_copy      */
    273     ft_outline_glyph_transform, /* FT_Glyph_TransformFunc  glyph_transform */
    274     ft_outline_glyph_bbox,      /* FT_Glyph_GetBBoxFunc    glyph_bbox      */
    275     ft_outline_glyph_prepare    /* FT_Glyph_PrepareFunc    glyph_prepare   */
    276   )
    277 
    278 
    279   /*************************************************************************/
    280   /*************************************************************************/
    281   /****                                                                 ****/
    282   /****   FT_Glyph class and API                                        ****/
    283   /****                                                                 ****/
    284   /*************************************************************************/
    285   /*************************************************************************/
    286 
    287    static FT_Error
    288    ft_new_glyph( FT_Library             library,
    289                  const FT_Glyph_Class*  clazz,
    290                  FT_Glyph*              aglyph )
    291    {
    292      FT_Memory  memory = library->memory;
    293      FT_Error   error;
    294      FT_Glyph   glyph  = NULL;
    295 
    296 
    297      *aglyph = NULL;
    298 
    299      if ( !FT_ALLOC( glyph, clazz->glyph_size ) )
    300      {
    301        glyph->library = library;
    302        glyph->clazz   = clazz;
    303        glyph->format  = clazz->glyph_format;
    304 
    305        *aglyph = glyph;
    306      }
    307 
    308      return error;
    309    }
    310 
    311 
    312   /* documentation is in ftglyph.h */
    313 
    314   FT_EXPORT_DEF( FT_Error )
    315   FT_Glyph_Copy( FT_Glyph   source,
    316                  FT_Glyph  *target )
    317   {
    318     FT_Glyph               copy;
    319     FT_Error               error;
    320     const FT_Glyph_Class*  clazz;
    321 
    322 
    323     /* check arguments */
    324     if ( !target || !source || !source->clazz )
    325     {
    326       error = FT_THROW( Invalid_Argument );
    327       goto Exit;
    328     }
    329 
    330     *target = NULL;
    331 
    332     if ( !source || !source->clazz )
    333     {
    334       error = FT_THROW( Invalid_Argument );
    335       goto Exit;
    336     }
    337 
    338     clazz = source->clazz;
    339     error = ft_new_glyph( source->library, clazz, &copy );
    340     if ( error )
    341       goto Exit;
    342 
    343     copy->advance = source->advance;
    344     copy->format  = source->format;
    345 
    346     if ( clazz->glyph_copy )
    347       error = clazz->glyph_copy( source, copy );
    348 
    349     if ( error )
    350       FT_Done_Glyph( copy );
    351     else
    352       *target = copy;
    353 
    354   Exit:
    355     return error;
    356   }
    357 
    358 
    359   /* documentation is in ftglyph.h */
    360 
    361   FT_EXPORT( FT_Error )
    362   FT_New_Glyph( FT_Library       library,
    363                 FT_Glyph_Format  format,
    364                 FT_Glyph        *aglyph )
    365   {
    366     const FT_Glyph_Class*  clazz = NULL;
    367 
    368     if ( !library || !aglyph )
    369       return FT_THROW( Invalid_Argument );
    370 
    371     /* if it is a bitmap, that's easy :-) */
    372     if ( format == FT_GLYPH_FORMAT_BITMAP )
    373       clazz = &ft_bitmap_glyph_class;
    374 
    375     /* if it is an outline */
    376     else if ( format == FT_GLYPH_FORMAT_OUTLINE )
    377       clazz = &ft_outline_glyph_class;
    378 
    379     else
    380     {
    381       /* try to find a renderer that supports the glyph image format */
    382       FT_Renderer  render = FT_Lookup_Renderer( library, format, 0 );
    383 
    384 
    385       if ( render )
    386         clazz = &render->glyph_class;
    387     }
    388 
    389     if ( !clazz )
    390       return FT_THROW( Invalid_Glyph_Format );
    391 
    392     /* create FT_Glyph object */
    393     return ft_new_glyph( library, clazz, aglyph );
    394   }
    395 
    396 
    397   /* documentation is in ftglyph.h */
    398 
    399   FT_EXPORT_DEF( FT_Error )
    400   FT_Get_Glyph( FT_GlyphSlot  slot,
    401                 FT_Glyph     *aglyph )
    402   {
    403     FT_Error    error;
    404     FT_Glyph    glyph;
    405 
    406 
    407     if ( !slot )
    408       return FT_THROW( Invalid_Slot_Handle );
    409 
    410     if ( !aglyph )
    411       return FT_THROW( Invalid_Argument );
    412 
    413     /* create FT_Glyph object */
    414     error = FT_New_Glyph( slot->library, slot->format, &glyph );
    415     if ( error )
    416       goto Exit;
    417 
    418     /* copy advance while converting 26.6 to 16.16 format */
    419     if ( slot->advance.x >=  0x8000L * 64 ||
    420          slot->advance.x <= -0x8000L * 64 )
    421     {
    422       FT_ERROR(( "FT_Get_Glyph: advance width too large\n" ));
    423       error = FT_THROW( Invalid_Argument );
    424       goto Exit2;
    425     }
    426     if ( slot->advance.y >=  0x8000L * 64 ||
    427          slot->advance.y <= -0x8000L * 64 )
    428     {
    429       FT_ERROR(( "FT_Get_Glyph: advance height too large\n" ));
    430       error = FT_THROW( Invalid_Argument );
    431       goto Exit2;
    432     }
    433 
    434     glyph->advance.x = slot->advance.x * 1024;
    435     glyph->advance.y = slot->advance.y * 1024;
    436 
    437     /* now import the image from the glyph slot */
    438     error = glyph->clazz->glyph_init( glyph, slot );
    439 
    440   Exit2:
    441     /* if an error occurred, destroy the glyph */
    442     if ( error )
    443       FT_Done_Glyph( glyph );
    444     else
    445       *aglyph = glyph;
    446 
    447   Exit:
    448     return error;
    449   }
    450 
    451 
    452   /* documentation is in ftglyph.h */
    453 
    454   FT_EXPORT_DEF( FT_Error )
    455   FT_Glyph_Transform( FT_Glyph    glyph,
    456                       FT_Matrix*  matrix,
    457                       FT_Vector*  delta )
    458   {
    459     FT_Error  error = FT_Err_Ok;
    460 
    461 
    462     if ( !glyph || !glyph->clazz )
    463       error = FT_THROW( Invalid_Argument );
    464     else
    465     {
    466       const FT_Glyph_Class*  clazz = glyph->clazz;
    467 
    468 
    469       if ( clazz->glyph_transform )
    470       {
    471         /* transform glyph image */
    472         clazz->glyph_transform( glyph, matrix, delta );
    473 
    474         /* transform advance vector */
    475         if ( matrix )
    476           FT_Vector_Transform( &glyph->advance, matrix );
    477       }
    478       else
    479         error = FT_THROW( Invalid_Glyph_Format );
    480     }
    481     return error;
    482   }
    483 
    484 
    485   /* documentation is in ftglyph.h */
    486 
    487   FT_EXPORT_DEF( void )
    488   FT_Glyph_Get_CBox( FT_Glyph  glyph,
    489                      FT_UInt   bbox_mode,
    490                      FT_BBox  *acbox )
    491   {
    492     const FT_Glyph_Class*  clazz;
    493 
    494 
    495     if ( !acbox )
    496       return;
    497 
    498     acbox->xMin = acbox->yMin = acbox->xMax = acbox->yMax = 0;
    499 
    500     if ( !glyph || !glyph->clazz )
    501       return;
    502 
    503     clazz = glyph->clazz;
    504     if ( !clazz->glyph_bbox )
    505       return;
    506 
    507     /* retrieve bbox in 26.6 coordinates */
    508     clazz->glyph_bbox( glyph, acbox );
    509 
    510     /* perform grid fitting if needed */
    511     if ( bbox_mode == FT_GLYPH_BBOX_GRIDFIT ||
    512          bbox_mode == FT_GLYPH_BBOX_PIXELS  )
    513     {
    514       acbox->xMin = FT_PIX_FLOOR( acbox->xMin );
    515       acbox->yMin = FT_PIX_FLOOR( acbox->yMin );
    516       acbox->xMax = FT_PIX_CEIL( acbox->xMax );
    517       acbox->yMax = FT_PIX_CEIL( acbox->yMax );
    518     }
    519 
    520     /* convert to integer pixels if needed */
    521     if ( bbox_mode == FT_GLYPH_BBOX_TRUNCATE ||
    522          bbox_mode == FT_GLYPH_BBOX_PIXELS   )
    523     {
    524       acbox->xMin >>= 6;
    525       acbox->yMin >>= 6;
    526       acbox->xMax >>= 6;
    527       acbox->yMax >>= 6;
    528     }
    529   }
    530 
    531 
    532   /* documentation is in ftglyph.h */
    533 
    534   FT_EXPORT_DEF( FT_Error )
    535   FT_Glyph_To_Bitmap( FT_Glyph*       the_glyph,
    536                       FT_Render_Mode  render_mode,
    537                       FT_Vector*      origin,
    538                       FT_Bool         destroy )
    539   {
    540     FT_GlyphSlotRec           dummy;
    541     FT_GlyphSlot_InternalRec  dummy_internal;
    542     FT_Error                  error = FT_Err_Ok;
    543     FT_Glyph                  b, glyph;
    544     FT_BitmapGlyph            bitmap = NULL;
    545     const FT_Glyph_Class*     clazz;
    546 
    547     FT_Library                library;
    548 
    549 
    550     /* check argument */
    551     if ( !the_glyph )
    552       goto Bad;
    553     glyph = *the_glyph;
    554     if ( !glyph )
    555       goto Bad;
    556 
    557     clazz   = glyph->clazz;
    558     library = glyph->library;
    559     if ( !library || !clazz )
    560       goto Bad;
    561 
    562     /* when called with a bitmap glyph, do nothing and return successfully */
    563     if ( clazz == &ft_bitmap_glyph_class )
    564       goto Exit;
    565 
    566     if ( !clazz->glyph_prepare )
    567       goto Bad;
    568 
    569     /* we render the glyph into a glyph bitmap using a `dummy' glyph slot */
    570     /* then calling FT_Render_Glyph_Internal()                            */
    571 
    572     FT_ZERO( &dummy );
    573     FT_ZERO( &dummy_internal );
    574     dummy.internal = &dummy_internal;
    575     dummy.library  = library;
    576     dummy.format   = clazz->glyph_format;
    577 
    578     /* create result bitmap glyph */
    579     error = ft_new_glyph( library, &ft_bitmap_glyph_class, &b );
    580     if ( error )
    581       goto Exit;
    582     bitmap = (FT_BitmapGlyph)b;
    583 
    584 #if 1
    585     /* if `origin' is set, translate the glyph image */
    586     if ( origin )
    587       FT_Glyph_Transform( glyph, 0, origin );
    588 #else
    589     FT_UNUSED( origin );
    590 #endif
    591 
    592     /* prepare dummy slot for rendering */
    593     error = clazz->glyph_prepare( glyph, &dummy );
    594     if ( !error )
    595       error = FT_Render_Glyph_Internal( glyph->library, &dummy, render_mode );
    596 
    597 #if 1
    598     if ( !destroy && origin )
    599     {
    600       FT_Vector  v;
    601 
    602 
    603       v.x = -origin->x;
    604       v.y = -origin->y;
    605       FT_Glyph_Transform( glyph, 0, &v );
    606     }
    607 #endif
    608 
    609     if ( error )
    610       goto Exit;
    611 
    612     /* in case of success, copy the bitmap to the glyph bitmap */
    613     error = ft_bitmap_glyph_init( (FT_Glyph)bitmap, &dummy );
    614     if ( error )
    615       goto Exit;
    616 
    617     /* copy advance */
    618     bitmap->root.advance = glyph->advance;
    619 
    620     if ( destroy )
    621       FT_Done_Glyph( glyph );
    622 
    623     *the_glyph = FT_GLYPH( bitmap );
    624 
    625   Exit:
    626     if ( error && bitmap )
    627       FT_Done_Glyph( FT_GLYPH( bitmap ) );
    628 
    629     return error;
    630 
    631   Bad:
    632     error = FT_THROW( Invalid_Argument );
    633     goto Exit;
    634   }
    635 
    636 
    637   /* documentation is in ftglyph.h */
    638 
    639   FT_EXPORT_DEF( void )
    640   FT_Done_Glyph( FT_Glyph  glyph )
    641   {
    642     if ( glyph )
    643     {
    644       FT_Memory              memory = glyph->library->memory;
    645       const FT_Glyph_Class*  clazz  = glyph->clazz;
    646 
    647 
    648       if ( clazz->glyph_done )
    649         clazz->glyph_done( glyph );
    650 
    651       FT_FREE( glyph );
    652     }
    653   }
    654 
    655 
    656 /* END */
    657