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