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