Subversion Repositories Kolibri OS

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
4349 Serge 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 */