Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Blame | Last modification | View Log | Download | RSS feed

  1. /***************************************************************************/
  2. /*                                                                         */
  3. /*  pfrgload.c                                                             */
  4. /*                                                                         */
  5. /*    FreeType PFR glyph loader (body).                                    */
  6. /*                                                                         */
  7. /*  Copyright 2002, 2003, 2005, 2007, 2010, 2013 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 = FT_THROW( 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 = FT_THROW( 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  = FT_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 = FT_THROW( 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  = FT_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 = FT_THROW( 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 = FT_THROW( 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 */
  845.