source: trunk/poppler/freetype-2.1.10/src/pfr/pfrgload.c @ 2

Last change on this file since 2 was 2, checked in by Eugene Romanenko, 15 years ago

First import

File size: 21.0 KB
Line 
1/***************************************************************************/
2/*                                                                         */
3/*  pfrgload.c                                                             */
4/*                                                                         */
5/*    FreeType PFR glyph loader (body).                                    */
6/*                                                                         */
7/*  Copyright 2002, 2003 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    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
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
118  pfr_glyph_start( PFR_Glyph  glyph )
119  {
120    glyph->path_begun = 0;
121  }
122
123
124  static FT_Error
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
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
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 space 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
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
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 = FT_PAD_CEIL( count, 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
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
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 )
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    glyph->num_subs = 0;
797
798    /* load the glyph, recursively when needed */
799    return pfr_glyph_load_rec( glyph, stream, gps_offset, offset, size );
800  }
801
802
803/* END */
Note: See TracBrowser for help on using the repository browser.