PageRenderTime 75ms CodeModel.GetById 2ms app.highlight 67ms RepoModel.GetById 1ms app.codeStats 0ms

/src/freetype/src/pfr/pfrgload.c

https://bitbucket.org/cabalistic/ogredeps/
C | 844 lines | 571 code | 183 blank | 90 comment | 65 complexity | 4d2d5a854bbc8cd69a3413b0c1846a36 MD5 | raw file
  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 */