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