misc/libfreetype/src/pfr/pfrgload.c
changeset 5172 88f2e05288ba
equal deleted inserted replaced
5171:f9283dc4860d 5172:88f2e05288ba
       
     1 /***************************************************************************/
       
     2 /*                                                                         */
       
     3 /*  pfrgload.c                                                             */
       
     4 /*                                                                         */
       
     5 /*    FreeType PFR glyph loader (body).                                    */
       
     6 /*                                                                         */
       
     7 /*  Copyright 2002, 2003, 2005, 2007, 2010 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 "pfrgload.h"
       
    20 #include "pfrsbit.h"
       
    21 #include "pfrload.h"            /* for macro definitions */
       
    22 #include FT_INTERNAL_DEBUG_H
       
    23 
       
    24 #include "pfrerror.h"
       
    25 
       
    26 #undef  FT_COMPONENT
       
    27 #define FT_COMPONENT  trace_pfr
       
    28 
       
    29 
       
    30   /*************************************************************************/
       
    31   /*************************************************************************/
       
    32   /*****                                                               *****/
       
    33   /*****                      PFR GLYPH BUILDER                        *****/
       
    34   /*****                                                               *****/
       
    35   /*************************************************************************/
       
    36   /*************************************************************************/
       
    37 
       
    38 
       
    39   FT_LOCAL_DEF( void )
       
    40   pfr_glyph_init( PFR_Glyph       glyph,
       
    41                   FT_GlyphLoader  loader )
       
    42   {
       
    43     FT_ZERO( glyph );
       
    44 
       
    45     glyph->loader     = loader;
       
    46     glyph->path_begun = 0;
       
    47 
       
    48     FT_GlyphLoader_Rewind( loader );
       
    49   }
       
    50 
       
    51 
       
    52   FT_LOCAL_DEF( void )
       
    53   pfr_glyph_done( PFR_Glyph  glyph )
       
    54   {
       
    55     FT_Memory  memory = glyph->loader->memory;
       
    56 
       
    57 
       
    58     FT_FREE( glyph->x_control );
       
    59     glyph->y_control = NULL;
       
    60 
       
    61     glyph->max_xy_control = 0;
       
    62 #if 0
       
    63     glyph->num_x_control  = 0;
       
    64     glyph->num_y_control  = 0;
       
    65 #endif
       
    66 
       
    67     FT_FREE( glyph->subs );
       
    68 
       
    69     glyph->max_subs = 0;
       
    70     glyph->num_subs = 0;
       
    71 
       
    72     glyph->loader     = NULL;
       
    73     glyph->path_begun = 0;
       
    74   }
       
    75 
       
    76 
       
    77   /* close current contour, if any */
       
    78   static void
       
    79   pfr_glyph_close_contour( PFR_Glyph  glyph )
       
    80   {
       
    81     FT_GlyphLoader  loader  = glyph->loader;
       
    82     FT_Outline*     outline = &loader->current.outline;
       
    83     FT_Int          last, first;
       
    84 
       
    85 
       
    86     if ( !glyph->path_begun )
       
    87       return;
       
    88 
       
    89     /* compute first and last point indices in current glyph outline */
       
    90     last  = outline->n_points - 1;
       
    91     first = 0;
       
    92     if ( outline->n_contours > 0 )
       
    93       first = outline->contours[outline->n_contours - 1];
       
    94 
       
    95     /* if the last point falls on the same location than the first one */
       
    96     /* we need to delete it                                            */
       
    97     if ( last > first )
       
    98     {
       
    99       FT_Vector*  p1 = outline->points + first;
       
   100       FT_Vector*  p2 = outline->points + last;
       
   101 
       
   102 
       
   103       if ( p1->x == p2->x && p1->y == p2->y )
       
   104       {
       
   105         outline->n_points--;
       
   106         last--;
       
   107       }
       
   108     }
       
   109 
       
   110     /* don't add empty contours */
       
   111     if ( last >= first )
       
   112       outline->contours[outline->n_contours++] = (short)last;
       
   113 
       
   114     glyph->path_begun = 0;
       
   115   }
       
   116 
       
   117 
       
   118   /* reset glyph to start the loading of a new glyph */
       
   119   static void
       
   120   pfr_glyph_start( PFR_Glyph  glyph )
       
   121   {
       
   122     glyph->path_begun = 0;
       
   123   }
       
   124 
       
   125 
       
   126   static FT_Error
       
   127   pfr_glyph_line_to( PFR_Glyph   glyph,
       
   128                      FT_Vector*  to )
       
   129   {
       
   130     FT_GlyphLoader  loader  = glyph->loader;
       
   131     FT_Outline*     outline = &loader->current.outline;
       
   132     FT_Error        error;
       
   133 
       
   134 
       
   135     /* check that we have begun a new path */
       
   136     if ( !glyph->path_begun )
       
   137     {
       
   138       error = PFR_Err_Invalid_Table;
       
   139       FT_ERROR(( "pfr_glyph_line_to: invalid glyph data\n" ));
       
   140       goto Exit;
       
   141     }
       
   142 
       
   143     error = FT_GLYPHLOADER_CHECK_POINTS( loader, 1, 0 );
       
   144     if ( !error )
       
   145     {
       
   146       FT_UInt  n = outline->n_points;
       
   147 
       
   148 
       
   149       outline->points[n] = *to;
       
   150       outline->tags  [n] = FT_CURVE_TAG_ON;
       
   151 
       
   152       outline->n_points++;
       
   153     }
       
   154 
       
   155   Exit:
       
   156     return error;
       
   157   }
       
   158 
       
   159 
       
   160   static FT_Error
       
   161   pfr_glyph_curve_to( PFR_Glyph   glyph,
       
   162                       FT_Vector*  control1,
       
   163                       FT_Vector*  control2,
       
   164                       FT_Vector*  to )
       
   165   {
       
   166     FT_GlyphLoader  loader  = glyph->loader;
       
   167     FT_Outline*     outline = &loader->current.outline;
       
   168     FT_Error        error;
       
   169 
       
   170 
       
   171     /* check that we have begun a new path */
       
   172     if ( !glyph->path_begun )
       
   173     {
       
   174       error = PFR_Err_Invalid_Table;
       
   175       FT_ERROR(( "pfr_glyph_line_to: invalid glyph data\n" ));
       
   176       goto Exit;
       
   177     }
       
   178 
       
   179     error = FT_GLYPHLOADER_CHECK_POINTS( loader, 3, 0 );
       
   180     if ( !error )
       
   181     {
       
   182       FT_Vector*  vec = outline->points         + outline->n_points;
       
   183       FT_Byte*    tag = (FT_Byte*)outline->tags + outline->n_points;
       
   184 
       
   185 
       
   186       vec[0] = *control1;
       
   187       vec[1] = *control2;
       
   188       vec[2] = *to;
       
   189       tag[0] = FT_CURVE_TAG_CUBIC;
       
   190       tag[1] = FT_CURVE_TAG_CUBIC;
       
   191       tag[2] = FT_CURVE_TAG_ON;
       
   192 
       
   193       outline->n_points = (FT_Short)( outline->n_points + 3 );
       
   194     }
       
   195 
       
   196   Exit:
       
   197     return error;
       
   198   }
       
   199 
       
   200 
       
   201   static FT_Error
       
   202   pfr_glyph_move_to( PFR_Glyph   glyph,
       
   203                      FT_Vector*  to )
       
   204   {
       
   205     FT_GlyphLoader  loader  = glyph->loader;
       
   206     FT_Error        error;
       
   207 
       
   208 
       
   209     /* close current contour if any */
       
   210     pfr_glyph_close_contour( glyph );
       
   211 
       
   212     /* indicate that a new contour has started */
       
   213     glyph->path_begun = 1;
       
   214 
       
   215     /* check that there is space for a new contour and a new point */
       
   216     error = FT_GLYPHLOADER_CHECK_POINTS( loader, 1, 1 );
       
   217     if ( !error )
       
   218       /* add new start point */
       
   219       error = pfr_glyph_line_to( glyph, to );
       
   220 
       
   221     return error;
       
   222   }
       
   223 
       
   224 
       
   225   static void
       
   226   pfr_glyph_end( PFR_Glyph  glyph )
       
   227   {
       
   228     /* close current contour if any */
       
   229     pfr_glyph_close_contour( glyph );
       
   230 
       
   231     /* merge the current glyph into the stack */
       
   232     FT_GlyphLoader_Add( glyph->loader );
       
   233   }
       
   234 
       
   235 
       
   236   /*************************************************************************/
       
   237   /*************************************************************************/
       
   238   /*****                                                               *****/
       
   239   /*****                      PFR GLYPH LOADER                         *****/
       
   240   /*****                                                               *****/
       
   241   /*************************************************************************/
       
   242   /*************************************************************************/
       
   243 
       
   244 
       
   245   /* load a simple glyph */
       
   246   static FT_Error
       
   247   pfr_glyph_load_simple( PFR_Glyph  glyph,
       
   248                          FT_Byte*   p,
       
   249                          FT_Byte*   limit )
       
   250   {
       
   251     FT_Error   error  = PFR_Err_Ok;
       
   252     FT_Memory  memory = glyph->loader->memory;
       
   253     FT_UInt    flags, x_count, y_count, i, count, mask;
       
   254     FT_Int     x;
       
   255 
       
   256 
       
   257     PFR_CHECK( 1 );
       
   258     flags = PFR_NEXT_BYTE( p );
       
   259 
       
   260     /* test for composite glyphs */
       
   261     if ( flags & PFR_GLYPH_IS_COMPOUND )
       
   262       goto Failure;
       
   263 
       
   264     x_count = 0;
       
   265     y_count = 0;
       
   266 
       
   267     if ( flags & PFR_GLYPH_1BYTE_XYCOUNT )
       
   268     {
       
   269       PFR_CHECK( 1 );
       
   270       count   = PFR_NEXT_BYTE( p );
       
   271       x_count = count & 15;
       
   272       y_count = count >> 4;
       
   273     }
       
   274     else
       
   275     {
       
   276       if ( flags & PFR_GLYPH_XCOUNT )
       
   277       {
       
   278         PFR_CHECK( 1 );
       
   279         x_count = PFR_NEXT_BYTE( p );
       
   280       }
       
   281 
       
   282       if ( flags & PFR_GLYPH_YCOUNT )
       
   283       {
       
   284         PFR_CHECK( 1 );
       
   285         y_count = PFR_NEXT_BYTE( p );
       
   286       }
       
   287     }
       
   288 
       
   289     count = x_count + y_count;
       
   290 
       
   291     /* re-allocate array when necessary */
       
   292     if ( count > glyph->max_xy_control )
       
   293     {
       
   294       FT_UInt  new_max = FT_PAD_CEIL( count, 8 );
       
   295 
       
   296 
       
   297       if ( FT_RENEW_ARRAY( glyph->x_control,
       
   298                            glyph->max_xy_control,
       
   299                            new_max ) )
       
   300         goto Exit;
       
   301 
       
   302       glyph->max_xy_control = new_max;
       
   303     }
       
   304 
       
   305     glyph->y_control = glyph->x_control + x_count;
       
   306 
       
   307     mask  = 0;
       
   308     x     = 0;
       
   309 
       
   310     for ( i = 0; i < count; i++ )
       
   311     {
       
   312       if ( ( i & 7 ) == 0 )
       
   313       {
       
   314         PFR_CHECK( 1 );
       
   315         mask = PFR_NEXT_BYTE( p );
       
   316       }
       
   317 
       
   318       if ( mask & 1 )
       
   319       {
       
   320         PFR_CHECK( 2 );
       
   321         x = PFR_NEXT_SHORT( p );
       
   322       }
       
   323       else
       
   324       {
       
   325         PFR_CHECK( 1 );
       
   326         x += PFR_NEXT_BYTE( p );
       
   327       }
       
   328 
       
   329       glyph->x_control[i] = x;
       
   330 
       
   331       mask >>= 1;
       
   332     }
       
   333 
       
   334     /* XXX: for now we ignore the secondary stroke and edge definitions */
       
   335     /*      since we don't want to support native PFR hinting           */
       
   336     /*                                                                  */
       
   337     if ( flags & PFR_GLYPH_EXTRA_ITEMS )
       
   338     {
       
   339       error = pfr_extra_items_skip( &p, limit );
       
   340       if ( error )
       
   341         goto Exit;
       
   342     }
       
   343 
       
   344     pfr_glyph_start( glyph );
       
   345 
       
   346     /* now load a simple glyph */
       
   347     {
       
   348       FT_Vector   pos[4];
       
   349       FT_Vector*  cur;
       
   350 
       
   351 
       
   352       pos[0].x = pos[0].y = 0;
       
   353       pos[3]   = pos[0];
       
   354 
       
   355       for (;;)
       
   356       {
       
   357         FT_UInt  format, format_low, args_format = 0, args_count, n;
       
   358 
       
   359 
       
   360         /***************************************************************/
       
   361         /*  read instruction                                           */
       
   362         /*                                                             */
       
   363         PFR_CHECK( 1 );
       
   364         format     = PFR_NEXT_BYTE( p );
       
   365         format_low = format & 15;
       
   366 
       
   367         switch ( format >> 4 )
       
   368         {
       
   369         case 0:                             /* end glyph */
       
   370           FT_TRACE6(( "- end glyph" ));
       
   371           args_count = 0;
       
   372           break;
       
   373 
       
   374         case 1:                             /* general line operation */
       
   375           FT_TRACE6(( "- general line" ));
       
   376           goto Line1;
       
   377 
       
   378         case 4:                             /* move to inside contour  */
       
   379           FT_TRACE6(( "- move to inside" ));
       
   380           goto Line1;
       
   381 
       
   382         case 5:                             /* move to outside contour */
       
   383           FT_TRACE6(( "- move to outside" ));
       
   384         Line1:
       
   385           args_format = format_low;
       
   386           args_count  = 1;
       
   387           break;
       
   388 
       
   389         case 2:                             /* horizontal line to */
       
   390           FT_TRACE6(( "- horizontal line to cx.%d", format_low ));
       
   391           if ( format_low >= x_count )
       
   392             goto Failure;
       
   393           pos[0].x   = glyph->x_control[format_low];
       
   394           pos[0].y   = pos[3].y;
       
   395           pos[3]     = pos[0];
       
   396           args_count = 0;
       
   397           break;
       
   398 
       
   399         case 3:                             /* vertical line to */
       
   400           FT_TRACE6(( "- vertical line to cy.%d", format_low ));
       
   401           if ( format_low >= y_count )
       
   402             goto Failure;
       
   403           pos[0].x   = pos[3].x;
       
   404           pos[0].y   = glyph->y_control[format_low];
       
   405           pos[3]     = pos[0];
       
   406           args_count = 0;
       
   407           break;
       
   408 
       
   409         case 6:                             /* horizontal to vertical curve */
       
   410           FT_TRACE6(( "- hv curve " ));
       
   411           args_format = 0xB8E;
       
   412           args_count  = 3;
       
   413           break;
       
   414 
       
   415         case 7:                             /* vertical to horizontal curve */
       
   416           FT_TRACE6(( "- vh curve" ));
       
   417           args_format = 0xE2B;
       
   418           args_count  = 3;
       
   419           break;
       
   420 
       
   421         default:                            /* general curve to */
       
   422           FT_TRACE6(( "- general curve" ));
       
   423           args_count  = 4;
       
   424           args_format = format_low;
       
   425         }
       
   426 
       
   427         /***********************************************************/
       
   428         /*  now read arguments                                     */
       
   429         /*                                                         */
       
   430         cur = pos;
       
   431         for ( n = 0; n < args_count; n++ )
       
   432         {
       
   433           FT_UInt  idx;
       
   434           FT_Int   delta;
       
   435 
       
   436 
       
   437           /* read the X argument */
       
   438           switch ( args_format & 3 )
       
   439           {
       
   440           case 0:                           /* 8-bit index */
       
   441             PFR_CHECK( 1 );
       
   442             idx  = PFR_NEXT_BYTE( p );
       
   443             if ( idx >= x_count )
       
   444               goto Failure;
       
   445             cur->x = glyph->x_control[idx];
       
   446             FT_TRACE7(( " cx#%d", idx ));
       
   447             break;
       
   448 
       
   449           case 1:                           /* 16-bit value */
       
   450             PFR_CHECK( 2 );
       
   451             cur->x = PFR_NEXT_SHORT( p );
       
   452             FT_TRACE7(( " x.%d", cur->x ));
       
   453             break;
       
   454 
       
   455           case 2:                           /* 8-bit delta */
       
   456             PFR_CHECK( 1 );
       
   457             delta  = PFR_NEXT_INT8( p );
       
   458             cur->x = pos[3].x + delta;
       
   459             FT_TRACE7(( " dx.%d", delta ));
       
   460             break;
       
   461 
       
   462           default:
       
   463             FT_TRACE7(( " |" ));
       
   464             cur->x = pos[3].x;
       
   465           }
       
   466 
       
   467           /* read the Y argument */
       
   468           switch ( ( args_format >> 2 ) & 3 )
       
   469           {
       
   470           case 0:                           /* 8-bit index */
       
   471             PFR_CHECK( 1 );
       
   472             idx  = PFR_NEXT_BYTE( p );
       
   473             if ( idx >= y_count )
       
   474               goto Failure;
       
   475             cur->y = glyph->y_control[idx];
       
   476             FT_TRACE7(( " cy#%d", idx ));
       
   477             break;
       
   478 
       
   479           case 1:                           /* 16-bit absolute value */
       
   480             PFR_CHECK( 2 );
       
   481             cur->y = PFR_NEXT_SHORT( p );
       
   482             FT_TRACE7(( " y.%d", cur->y ));
       
   483             break;
       
   484 
       
   485           case 2:                           /* 8-bit delta */
       
   486             PFR_CHECK( 1 );
       
   487             delta  = PFR_NEXT_INT8( p );
       
   488             cur->y = pos[3].y + delta;
       
   489             FT_TRACE7(( " dy.%d", delta ));
       
   490             break;
       
   491 
       
   492           default:
       
   493             FT_TRACE7(( " -" ));
       
   494             cur->y = pos[3].y;
       
   495           }
       
   496 
       
   497           /* read the additional format flag for the general curve */
       
   498           if ( n == 0 && args_count == 4 )
       
   499           {
       
   500             PFR_CHECK( 1 );
       
   501             args_format = PFR_NEXT_BYTE( p );
       
   502             args_count--;
       
   503           }
       
   504           else
       
   505             args_format >>= 4;
       
   506 
       
   507           /* save the previous point */
       
   508           pos[3] = cur[0];
       
   509           cur++;
       
   510         }
       
   511 
       
   512         FT_TRACE7(( "\n" ));
       
   513 
       
   514         /***********************************************************/
       
   515         /*  finally, execute instruction                           */
       
   516         /*                                                         */
       
   517         switch ( format >> 4 )
       
   518         {
       
   519         case 0:                             /* end glyph => EXIT */
       
   520           pfr_glyph_end( glyph );
       
   521           goto Exit;
       
   522 
       
   523         case 1:                             /* line operations */
       
   524         case 2:
       
   525         case 3:
       
   526           error = pfr_glyph_line_to( glyph, pos );
       
   527           goto Test_Error;
       
   528 
       
   529         case 4:                             /* move to inside contour  */
       
   530         case 5:                             /* move to outside contour */
       
   531           error = pfr_glyph_move_to( glyph, pos );
       
   532           goto Test_Error;
       
   533 
       
   534         default:                            /* curve operations */
       
   535           error = pfr_glyph_curve_to( glyph, pos, pos + 1, pos + 2 );
       
   536 
       
   537         Test_Error:  /* test error condition */
       
   538           if ( error )
       
   539             goto Exit;
       
   540         }
       
   541       } /* for (;;) */
       
   542     }
       
   543 
       
   544   Exit:
       
   545     return error;
       
   546 
       
   547   Failure:
       
   548   Too_Short:
       
   549     error = PFR_Err_Invalid_Table;
       
   550     FT_ERROR(( "pfr_glyph_load_simple: invalid glyph data\n" ));
       
   551     goto Exit;
       
   552   }
       
   553 
       
   554 
       
   555   /* load a composite/compound glyph */
       
   556   static FT_Error
       
   557   pfr_glyph_load_compound( PFR_Glyph  glyph,
       
   558                            FT_Byte*   p,
       
   559                            FT_Byte*   limit )
       
   560   {
       
   561     FT_Error        error  = PFR_Err_Ok;
       
   562     FT_GlyphLoader  loader = glyph->loader;
       
   563     FT_Memory       memory = loader->memory;
       
   564     PFR_SubGlyph    subglyph;
       
   565     FT_UInt         flags, i, count, org_count;
       
   566     FT_Int          x_pos, y_pos;
       
   567 
       
   568 
       
   569     PFR_CHECK( 1 );
       
   570     flags = PFR_NEXT_BYTE( p );
       
   571 
       
   572     /* test for composite glyphs */
       
   573     if ( !( flags & PFR_GLYPH_IS_COMPOUND ) )
       
   574       goto Failure;
       
   575 
       
   576     count = flags & 0x3F;
       
   577 
       
   578     /* ignore extra items when present */
       
   579     /*                                 */
       
   580     if ( flags & PFR_GLYPH_EXTRA_ITEMS )
       
   581     {
       
   582       error = pfr_extra_items_skip( &p, limit );
       
   583       if (error) goto Exit;
       
   584     }
       
   585 
       
   586     /* we can't rely on the FT_GlyphLoader to load sub-glyphs, because   */
       
   587     /* the PFR format is dumb, using direct file offsets to point to the */
       
   588     /* sub-glyphs (instead of glyph indices).  Sigh.                     */
       
   589     /*                                                                   */
       
   590     /* For now, we load the list of sub-glyphs into a different array    */
       
   591     /* but this will prevent us from using the auto-hinter at its best   */
       
   592     /* quality.                                                          */
       
   593     /*                                                                   */
       
   594     org_count = glyph->num_subs;
       
   595 
       
   596     if ( org_count + count > glyph->max_subs )
       
   597     {
       
   598       FT_UInt  new_max = ( org_count + count + 3 ) & (FT_UInt)-4;
       
   599 
       
   600 
       
   601       /* we arbitrarily limit the number of subglyphs */
       
   602       /* to avoid endless recursion                   */
       
   603       if ( new_max > 64 )
       
   604       {
       
   605         error = PFR_Err_Invalid_Table;
       
   606         FT_ERROR(( "pfr_glyph_load_compound:"
       
   607                    " too many compound glyphs components\n" ));
       
   608         goto Exit;
       
   609       }
       
   610 
       
   611       if ( FT_RENEW_ARRAY( glyph->subs, glyph->max_subs, new_max ) )
       
   612         goto Exit;
       
   613 
       
   614       glyph->max_subs = new_max;
       
   615     }
       
   616 
       
   617     subglyph = glyph->subs + org_count;
       
   618 
       
   619     for ( i = 0; i < count; i++, subglyph++ )
       
   620     {
       
   621       FT_UInt  format;
       
   622 
       
   623 
       
   624       x_pos = 0;
       
   625       y_pos = 0;
       
   626 
       
   627       PFR_CHECK( 1 );
       
   628       format = PFR_NEXT_BYTE( p );
       
   629 
       
   630       /* read scale when available */
       
   631       subglyph->x_scale = 0x10000L;
       
   632       if ( format & PFR_SUBGLYPH_XSCALE )
       
   633       {
       
   634         PFR_CHECK( 2 );
       
   635         subglyph->x_scale = PFR_NEXT_SHORT( p ) << 4;
       
   636       }
       
   637 
       
   638       subglyph->y_scale = 0x10000L;
       
   639       if ( format & PFR_SUBGLYPH_YSCALE )
       
   640       {
       
   641         PFR_CHECK( 2 );
       
   642         subglyph->y_scale = PFR_NEXT_SHORT( p ) << 4;
       
   643       }
       
   644 
       
   645       /* read offset */
       
   646       switch ( format & 3 )
       
   647       {
       
   648       case 1:
       
   649         PFR_CHECK( 2 );
       
   650         x_pos = PFR_NEXT_SHORT( p );
       
   651         break;
       
   652 
       
   653       case 2:
       
   654         PFR_CHECK( 1 );
       
   655         x_pos += PFR_NEXT_INT8( p );
       
   656         break;
       
   657 
       
   658       default:
       
   659         ;
       
   660       }
       
   661 
       
   662       switch ( ( format >> 2 ) & 3 )
       
   663       {
       
   664       case 1:
       
   665         PFR_CHECK( 2 );
       
   666         y_pos = PFR_NEXT_SHORT( p );
       
   667         break;
       
   668 
       
   669       case 2:
       
   670         PFR_CHECK( 1 );
       
   671         y_pos += PFR_NEXT_INT8( p );
       
   672         break;
       
   673 
       
   674       default:
       
   675         ;
       
   676       }
       
   677 
       
   678       subglyph->x_delta = x_pos;
       
   679       subglyph->y_delta = y_pos;
       
   680 
       
   681       /* read glyph position and size now */
       
   682       if ( format & PFR_SUBGLYPH_2BYTE_SIZE )
       
   683       {
       
   684         PFR_CHECK( 2 );
       
   685         subglyph->gps_size = PFR_NEXT_USHORT( p );
       
   686       }
       
   687       else
       
   688       {
       
   689         PFR_CHECK( 1 );
       
   690         subglyph->gps_size = PFR_NEXT_BYTE( p );
       
   691       }
       
   692 
       
   693       if ( format & PFR_SUBGLYPH_3BYTE_OFFSET )
       
   694       {
       
   695         PFR_CHECK( 3 );
       
   696         subglyph->gps_offset = PFR_NEXT_LONG( p );
       
   697       }
       
   698       else
       
   699       {
       
   700         PFR_CHECK( 2 );
       
   701         subglyph->gps_offset = PFR_NEXT_USHORT( p );
       
   702       }
       
   703 
       
   704       glyph->num_subs++;
       
   705     }
       
   706 
       
   707   Exit:
       
   708     return error;
       
   709 
       
   710   Failure:
       
   711   Too_Short:
       
   712     error = PFR_Err_Invalid_Table;
       
   713     FT_ERROR(( "pfr_glyph_load_compound: invalid glyph data\n" ));
       
   714     goto Exit;
       
   715   }
       
   716 
       
   717 
       
   718   static FT_Error
       
   719   pfr_glyph_load_rec( PFR_Glyph  glyph,
       
   720                       FT_Stream  stream,
       
   721                       FT_ULong   gps_offset,
       
   722                       FT_ULong   offset,
       
   723                       FT_ULong   size )
       
   724   {
       
   725     FT_Error  error;
       
   726     FT_Byte*  p;
       
   727     FT_Byte*  limit;
       
   728 
       
   729 
       
   730     if ( FT_STREAM_SEEK( gps_offset + offset ) ||
       
   731          FT_FRAME_ENTER( size )                )
       
   732       goto Exit;
       
   733 
       
   734     p     = (FT_Byte*)stream->cursor;
       
   735     limit = p + size;
       
   736 
       
   737     if ( size > 0 && *p & PFR_GLYPH_IS_COMPOUND )
       
   738     {
       
   739       FT_Int          n, old_count, count;
       
   740       FT_GlyphLoader  loader = glyph->loader;
       
   741       FT_Outline*     base   = &loader->base.outline;
       
   742 
       
   743 
       
   744       old_count = glyph->num_subs;
       
   745 
       
   746       /* this is a compound glyph - load it */
       
   747       error = pfr_glyph_load_compound( glyph, p, limit );
       
   748 
       
   749       FT_FRAME_EXIT();
       
   750 
       
   751       if ( error )
       
   752         goto Exit;
       
   753 
       
   754       count = glyph->num_subs - old_count;
       
   755 
       
   756       FT_TRACE4(( "compound glyph with %d elements (offset %lu):\n",
       
   757                   count, offset ));
       
   758 
       
   759       /* now, load each individual glyph */
       
   760       for ( n = 0; n < count; n++ )
       
   761       {
       
   762         FT_Int        i, old_points, num_points;
       
   763         PFR_SubGlyph  subglyph;
       
   764 
       
   765 
       
   766         FT_TRACE4(( "subglyph %d:\n", n ));
       
   767 
       
   768         subglyph   = glyph->subs + old_count + n;
       
   769         old_points = base->n_points;
       
   770 
       
   771         error = pfr_glyph_load_rec( glyph, stream, gps_offset,
       
   772                                     subglyph->gps_offset,
       
   773                                     subglyph->gps_size );
       
   774         if ( error )
       
   775           break;
       
   776 
       
   777         /* note that `glyph->subs' might have been re-allocated */
       
   778         subglyph   = glyph->subs + old_count + n;
       
   779         num_points = base->n_points - old_points;
       
   780 
       
   781         /* translate and eventually scale the new glyph points */
       
   782         if ( subglyph->x_scale != 0x10000L || subglyph->y_scale != 0x10000L )
       
   783         {
       
   784           FT_Vector*  vec = base->points + old_points;
       
   785 
       
   786 
       
   787           for ( i = 0; i < num_points; i++, vec++ )
       
   788           {
       
   789             vec->x = FT_MulFix( vec->x, subglyph->x_scale ) +
       
   790                        subglyph->x_delta;
       
   791             vec->y = FT_MulFix( vec->y, subglyph->y_scale ) +
       
   792                        subglyph->y_delta;
       
   793           }
       
   794         }
       
   795         else
       
   796         {
       
   797           FT_Vector*  vec = loader->base.outline.points + old_points;
       
   798 
       
   799 
       
   800           for ( i = 0; i < num_points; i++, vec++ )
       
   801           {
       
   802             vec->x += subglyph->x_delta;
       
   803             vec->y += subglyph->y_delta;
       
   804           }
       
   805         }
       
   806 
       
   807         /* proceed to next sub-glyph */
       
   808       }
       
   809 
       
   810       FT_TRACE4(( "end compound glyph with %d elements\n", count ));
       
   811     }
       
   812     else
       
   813     {
       
   814       FT_TRACE4(( "simple glyph (offset %lu)\n", offset ));
       
   815 
       
   816       /* load a simple glyph */
       
   817       error = pfr_glyph_load_simple( glyph, p, limit );
       
   818 
       
   819       FT_FRAME_EXIT();
       
   820     }
       
   821 
       
   822   Exit:
       
   823     return error;
       
   824   }
       
   825 
       
   826 
       
   827   FT_LOCAL_DEF( FT_Error )
       
   828   pfr_glyph_load( PFR_Glyph  glyph,
       
   829                   FT_Stream  stream,
       
   830                   FT_ULong   gps_offset,
       
   831                   FT_ULong   offset,
       
   832                   FT_ULong   size )
       
   833   {
       
   834     /* initialize glyph loader */
       
   835     FT_GlyphLoader_Rewind( glyph->loader );
       
   836 
       
   837     glyph->num_subs = 0;
       
   838 
       
   839     /* load the glyph, recursively when needed */
       
   840     return pfr_glyph_load_rec( glyph, stream, gps_offset, offset, size );
       
   841   }
       
   842 
       
   843 
       
   844 /* END */