Home | History | Annotate | Download | only in base
      1 /***************************************************************************/
      2 /*                                                                         */
      3 /*  ftgloadr.c                                                             */
      4 /*                                                                         */
      5 /*    The FreeType glyph loader (body).                                    */
      6 /*                                                                         */
      7 /*  Copyright 2002-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 #include <ft2build.h>
     20 #include FT_INTERNAL_DEBUG_H
     21 #include FT_INTERNAL_GLYPH_LOADER_H
     22 #include FT_INTERNAL_MEMORY_H
     23 #include FT_INTERNAL_OBJECTS_H
     24 
     25 #undef  FT_COMPONENT
     26 #define FT_COMPONENT  trace_gloader
     27 
     28 
     29   /*************************************************************************/
     30   /*************************************************************************/
     31   /*************************************************************************/
     32   /*****                                                               *****/
     33   /*****                                                               *****/
     34   /*****                    G L Y P H   L O A D E R                    *****/
     35   /*****                                                               *****/
     36   /*****                                                               *****/
     37   /*************************************************************************/
     38   /*************************************************************************/
     39   /*************************************************************************/
     40 
     41   /*************************************************************************/
     42   /*                                                                       */
     43   /* The glyph loader is a simple object which is used to load a set of    */
     44   /* glyphs easily.  It is critical for the correct loading of composites. */
     45   /*                                                                       */
     46   /* Ideally, one can see it as a stack of abstract `glyph' objects.       */
     47   /*                                                                       */
     48   /*   loader.base     Is really the bottom of the stack.  It describes a  */
     49   /*                   single glyph image made of the juxtaposition of     */
     50   /*                   several glyphs (those `in the stack').              */
     51   /*                                                                       */
     52   /*   loader.current  Describes the top of the stack, on which a new      */
     53   /*                   glyph can be loaded.                                */
     54   /*                                                                       */
     55   /*   Rewind          Clears the stack.                                   */
     56   /*   Prepare         Set up `loader.current' for addition of a new glyph */
     57   /*                   image.                                              */
     58   /*   Add             Add the `current' glyph image to the `base' one,    */
     59   /*                   and prepare for another one.                        */
     60   /*                                                                       */
     61   /* The glyph loader is now a base object.  Each driver used to           */
     62   /* re-implement it in one way or the other, which wasted code and        */
     63   /* energy.                                                               */
     64   /*                                                                       */
     65   /*************************************************************************/
     66 
     67 
     68   /* create a new glyph loader */
     69   FT_BASE_DEF( FT_Error )
     70   FT_GlyphLoader_New( FT_Memory        memory,
     71                       FT_GlyphLoader  *aloader )
     72   {
     73     FT_GlyphLoader  loader = NULL;
     74     FT_Error        error;
     75 
     76 
     77     if ( !FT_NEW( loader ) )
     78     {
     79       loader->memory = memory;
     80       *aloader       = loader;
     81     }
     82     return error;
     83   }
     84 
     85 
     86   /* rewind the glyph loader - reset counters to 0 */
     87   FT_BASE_DEF( void )
     88   FT_GlyphLoader_Rewind( FT_GlyphLoader  loader )
     89   {
     90     FT_GlyphLoad  base    = &loader->base;
     91     FT_GlyphLoad  current = &loader->current;
     92 
     93 
     94     base->outline.n_points   = 0;
     95     base->outline.n_contours = 0;
     96     base->num_subglyphs      = 0;
     97 
     98     *current = *base;
     99   }
    100 
    101 
    102   /* reset the glyph loader, frees all allocated tables */
    103   /* and starts from zero                               */
    104   FT_BASE_DEF( void )
    105   FT_GlyphLoader_Reset( FT_GlyphLoader  loader )
    106   {
    107     FT_Memory memory = loader->memory;
    108 
    109 
    110     FT_FREE( loader->base.outline.points );
    111     FT_FREE( loader->base.outline.tags );
    112     FT_FREE( loader->base.outline.contours );
    113     FT_FREE( loader->base.extra_points );
    114     FT_FREE( loader->base.subglyphs );
    115 
    116     loader->base.extra_points2 = NULL;
    117 
    118     loader->max_points    = 0;
    119     loader->max_contours  = 0;
    120     loader->max_subglyphs = 0;
    121 
    122     FT_GlyphLoader_Rewind( loader );
    123   }
    124 
    125 
    126   /* delete a glyph loader */
    127   FT_BASE_DEF( void )
    128   FT_GlyphLoader_Done( FT_GlyphLoader  loader )
    129   {
    130     if ( loader )
    131     {
    132       FT_Memory memory = loader->memory;
    133 
    134 
    135       FT_GlyphLoader_Reset( loader );
    136       FT_FREE( loader );
    137     }
    138   }
    139 
    140 
    141   /* re-adjust the `current' outline fields */
    142   static void
    143   FT_GlyphLoader_Adjust_Points( FT_GlyphLoader  loader )
    144   {
    145     FT_Outline*  base    = &loader->base.outline;
    146     FT_Outline*  current = &loader->current.outline;
    147 
    148 
    149     current->points   = base->points   + base->n_points;
    150     current->tags     = base->tags     + base->n_points;
    151     current->contours = base->contours + base->n_contours;
    152 
    153     /* handle extra points table - if any */
    154     if ( loader->use_extra )
    155     {
    156       loader->current.extra_points  = loader->base.extra_points +
    157                                       base->n_points;
    158 
    159       loader->current.extra_points2 = loader->base.extra_points2 +
    160                                       base->n_points;
    161     }
    162   }
    163 
    164 
    165   FT_BASE_DEF( FT_Error )
    166   FT_GlyphLoader_CreateExtra( FT_GlyphLoader  loader )
    167   {
    168     FT_Error   error;
    169     FT_Memory  memory = loader->memory;
    170 
    171 
    172     if ( !FT_NEW_ARRAY( loader->base.extra_points, 2 * loader->max_points ) )
    173     {
    174       loader->use_extra          = 1;
    175       loader->base.extra_points2 = loader->base.extra_points +
    176                                    loader->max_points;
    177 
    178       FT_GlyphLoader_Adjust_Points( loader );
    179     }
    180     return error;
    181   }
    182 
    183 
    184   /* re-adjust the `current' subglyphs field */
    185   static void
    186   FT_GlyphLoader_Adjust_Subglyphs( FT_GlyphLoader  loader )
    187   {
    188     FT_GlyphLoad  base    = &loader->base;
    189     FT_GlyphLoad  current = &loader->current;
    190 
    191 
    192     current->subglyphs = base->subglyphs + base->num_subglyphs;
    193   }
    194 
    195 
    196   /* Ensure that we can add `n_points' and `n_contours' to our glyph.      */
    197   /* This function reallocates its outline tables if necessary.  Note that */
    198   /* it DOESN'T change the number of points within the loader!             */
    199   /*                                                                       */
    200   FT_BASE_DEF( FT_Error )
    201   FT_GlyphLoader_CheckPoints( FT_GlyphLoader  loader,
    202                               FT_UInt         n_points,
    203                               FT_UInt         n_contours )
    204   {
    205     FT_Memory    memory  = loader->memory;
    206     FT_Error     error   = FT_Err_Ok;
    207     FT_Outline*  base    = &loader->base.outline;
    208     FT_Outline*  current = &loader->current.outline;
    209     FT_Bool      adjust  = 0;
    210 
    211     FT_UInt      new_max, old_max;
    212 
    213 
    214     /* check points & tags */
    215     new_max = (FT_UInt)base->n_points + (FT_UInt)current->n_points +
    216               n_points;
    217     old_max = loader->max_points;
    218 
    219     if ( new_max > old_max )
    220     {
    221       new_max = FT_PAD_CEIL( new_max, 8 );
    222 
    223       if ( new_max > FT_OUTLINE_POINTS_MAX )
    224         return FT_THROW( Array_Too_Large );
    225 
    226       if ( FT_RENEW_ARRAY( base->points, old_max, new_max ) ||
    227            FT_RENEW_ARRAY( base->tags,   old_max, new_max ) )
    228         goto Exit;
    229 
    230       if ( loader->use_extra )
    231       {
    232         if ( FT_RENEW_ARRAY( loader->base.extra_points,
    233                              old_max * 2, new_max * 2 ) )
    234           goto Exit;
    235 
    236         FT_ARRAY_MOVE( loader->base.extra_points + new_max,
    237                        loader->base.extra_points + old_max,
    238                        old_max );
    239 
    240         loader->base.extra_points2 = loader->base.extra_points + new_max;
    241       }
    242 
    243       adjust = 1;
    244       loader->max_points = new_max;
    245     }
    246 
    247     /* check contours */
    248     old_max = loader->max_contours;
    249     new_max = (FT_UInt)base->n_contours + (FT_UInt)current->n_contours +
    250               n_contours;
    251     if ( new_max > old_max )
    252     {
    253       new_max = FT_PAD_CEIL( new_max, 4 );
    254 
    255       if ( new_max > FT_OUTLINE_CONTOURS_MAX )
    256         return FT_THROW( Array_Too_Large );
    257 
    258       if ( FT_RENEW_ARRAY( base->contours, old_max, new_max ) )
    259         goto Exit;
    260 
    261       adjust = 1;
    262       loader->max_contours = new_max;
    263     }
    264 
    265     if ( adjust )
    266       FT_GlyphLoader_Adjust_Points( loader );
    267 
    268   Exit:
    269     if ( error )
    270       FT_GlyphLoader_Reset( loader );
    271 
    272     return error;
    273   }
    274 
    275 
    276   /* Ensure that we can add `n_subglyphs' to our glyph. this function */
    277   /* reallocates its subglyphs table if necessary.  Note that it DOES */
    278   /* NOT change the number of subglyphs within the loader!            */
    279   /*                                                                  */
    280   FT_BASE_DEF( FT_Error )
    281   FT_GlyphLoader_CheckSubGlyphs( FT_GlyphLoader  loader,
    282                                  FT_UInt         n_subs )
    283   {
    284     FT_Memory     memory = loader->memory;
    285     FT_Error      error  = FT_Err_Ok;
    286     FT_UInt       new_max, old_max;
    287 
    288     FT_GlyphLoad  base    = &loader->base;
    289     FT_GlyphLoad  current = &loader->current;
    290 
    291 
    292     new_max = base->num_subglyphs + current->num_subglyphs + n_subs;
    293     old_max = loader->max_subglyphs;
    294     if ( new_max > old_max )
    295     {
    296       new_max = FT_PAD_CEIL( new_max, 2 );
    297       if ( FT_RENEW_ARRAY( base->subglyphs, old_max, new_max ) )
    298         goto Exit;
    299 
    300       loader->max_subglyphs = new_max;
    301 
    302       FT_GlyphLoader_Adjust_Subglyphs( loader );
    303     }
    304 
    305   Exit:
    306     return error;
    307   }
    308 
    309 
    310   /* prepare loader for the addition of a new glyph on top of the base one */
    311   FT_BASE_DEF( void )
    312   FT_GlyphLoader_Prepare( FT_GlyphLoader  loader )
    313   {
    314     FT_GlyphLoad  current = &loader->current;
    315 
    316 
    317     current->outline.n_points   = 0;
    318     current->outline.n_contours = 0;
    319     current->num_subglyphs      = 0;
    320 
    321     FT_GlyphLoader_Adjust_Points   ( loader );
    322     FT_GlyphLoader_Adjust_Subglyphs( loader );
    323   }
    324 
    325 
    326   /* add current glyph to the base image -- and prepare for another */
    327   FT_BASE_DEF( void )
    328   FT_GlyphLoader_Add( FT_GlyphLoader  loader )
    329   {
    330     FT_GlyphLoad  base;
    331     FT_GlyphLoad  current;
    332 
    333     FT_Int        n_curr_contours;
    334     FT_Int        n_base_points;
    335     FT_Int        n;
    336 
    337 
    338     if ( !loader )
    339       return;
    340 
    341     base    = &loader->base;
    342     current = &loader->current;
    343 
    344     n_curr_contours = current->outline.n_contours;
    345     n_base_points   = base->outline.n_points;
    346 
    347     base->outline.n_points =
    348       (short)( base->outline.n_points + current->outline.n_points );
    349     base->outline.n_contours =
    350       (short)( base->outline.n_contours + current->outline.n_contours );
    351 
    352     base->num_subglyphs += current->num_subglyphs;
    353 
    354     /* adjust contours count in newest outline */
    355     for ( n = 0; n < n_curr_contours; n++ )
    356       current->outline.contours[n] =
    357         (short)( current->outline.contours[n] + n_base_points );
    358 
    359     /* prepare for another new glyph image */
    360     FT_GlyphLoader_Prepare( loader );
    361   }
    362 
    363 
    364   FT_BASE_DEF( FT_Error )
    365   FT_GlyphLoader_CopyPoints( FT_GlyphLoader  target,
    366                              FT_GlyphLoader  source )
    367   {
    368     FT_Error  error;
    369     FT_UInt   num_points   = (FT_UInt)source->base.outline.n_points;
    370     FT_UInt   num_contours = (FT_UInt)source->base.outline.n_contours;
    371 
    372 
    373     error = FT_GlyphLoader_CheckPoints( target, num_points, num_contours );
    374     if ( !error )
    375     {
    376       FT_Outline*  out = &target->base.outline;
    377       FT_Outline*  in  = &source->base.outline;
    378 
    379 
    380       FT_ARRAY_COPY( out->points, in->points,
    381                      num_points );
    382       FT_ARRAY_COPY( out->tags, in->tags,
    383                      num_points );
    384       FT_ARRAY_COPY( out->contours, in->contours,
    385                      num_contours );
    386 
    387       /* do we need to copy the extra points? */
    388       if ( target->use_extra && source->use_extra )
    389       {
    390         FT_ARRAY_COPY( target->base.extra_points, source->base.extra_points,
    391                        num_points );
    392         FT_ARRAY_COPY( target->base.extra_points2, source->base.extra_points2,
    393                        num_points );
    394       }
    395 
    396       out->n_points   = (short)num_points;
    397       out->n_contours = (short)num_contours;
    398 
    399       FT_GlyphLoader_Adjust_Points( target );
    400     }
    401 
    402     return error;
    403   }
    404 
    405 
    406 /* END */
    407