source: trunk/poppler/freetype2/src/pfr/pfrgload.c @ 251

Last change on this file since 251 was 251, checked in by Eugene Romanenko, 13 years ago

PDF plugin: freetype library updated to version 2.3.5

File size: 22.4 KB
Line 
1/***************************************************************************/
2/*                                                                         */
3/*  pfrgload.c                                                             */
4/*                                                                         */
5/*    FreeType PFR glyph loader (body).                                    */
6/*                                                                         */
7/*  Copyright 2002, 2003, 2005, 2007 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  = 0;
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  = 0;
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      if ( FT_RENEW_ARRAY( glyph->subs, glyph->max_subs, new_max ) )
602        goto Exit;
603
604      glyph->max_subs = new_max;
605    }
606
607    subglyph = glyph->subs + org_count;
608
609    for ( i = 0; i < count; i++, subglyph++ )
610    {
611      FT_UInt  format;
612
613
614      x_pos = 0;
615      y_pos = 0;
616
617      PFR_CHECK( 1 );
618      format = PFR_NEXT_BYTE( p );
619
620      /* read scale when available */
621      subglyph->x_scale = 0x10000L;
622      if ( format & PFR_SUBGLYPH_XSCALE )
623      {
624        PFR_CHECK( 2 );
625        subglyph->x_scale = PFR_NEXT_SHORT( p ) << 4;
626      }
627
628      subglyph->y_scale = 0x10000L;
629      if ( format & PFR_SUBGLYPH_YSCALE )
630      {
631        PFR_CHECK( 2 );
632        subglyph->y_scale = PFR_NEXT_SHORT( p ) << 4;
633      }
634
635      /* read offset */
636      switch ( format & 3 )
637      {
638      case 1:
639        PFR_CHECK( 2 );
640        x_pos = PFR_NEXT_SHORT( p );
641        break;
642
643      case 2:
644        PFR_CHECK( 1 );
645        x_pos += PFR_NEXT_INT8( p );
646        break;
647
648      default:
649        ;
650      }
651
652      switch ( ( format >> 2 ) & 3 )
653      {
654      case 1:
655        PFR_CHECK( 2 );
656        y_pos = PFR_NEXT_SHORT( p );
657        break;
658
659      case 2:
660        PFR_CHECK( 1 );
661        y_pos += PFR_NEXT_INT8( p );
662        break;
663
664      default:
665        ;
666      }
667
668      subglyph->x_delta = x_pos;
669      subglyph->y_delta = y_pos;
670
671      /* read glyph position and size now */
672      if ( format & PFR_SUBGLYPH_2BYTE_SIZE )
673      {
674        PFR_CHECK( 2 );
675        subglyph->gps_size = PFR_NEXT_USHORT( p );
676      }
677      else
678      {
679        PFR_CHECK( 1 );
680        subglyph->gps_size = PFR_NEXT_BYTE( p );
681      }
682
683      if ( format & PFR_SUBGLYPH_3BYTE_OFFSET )
684      {
685        PFR_CHECK( 3 );
686        subglyph->gps_offset = PFR_NEXT_LONG( p );
687      }
688      else
689      {
690        PFR_CHECK( 2 );
691        subglyph->gps_offset = PFR_NEXT_USHORT( p );
692      }
693
694      glyph->num_subs++;
695    }
696
697  Exit:
698    return error;
699
700  Failure:
701  Too_Short:
702    error = PFR_Err_Invalid_Table;
703    FT_ERROR(( "pfr_glyph_load_compound: invalid glyph data\n" ));
704    goto Exit;
705  }
706
707
708  static FT_Error
709  pfr_glyph_load_rec( PFR_Glyph  glyph,
710                      FT_Stream  stream,
711                      FT_ULong   gps_offset,
712                      FT_ULong   offset,
713                      FT_ULong   size )
714  {
715    FT_Error  error;
716    FT_Byte*  p;
717    FT_Byte*  limit;
718
719
720    if ( FT_STREAM_SEEK( gps_offset + offset ) ||
721         FT_FRAME_ENTER( size )                )
722      goto Exit;
723
724    p     = (FT_Byte*)stream->cursor;
725    limit = p + size;
726
727    if ( size > 0 && *p & PFR_GLYPH_IS_COMPOUND )
728    {
729      FT_Int          n, old_count, count;
730      FT_GlyphLoader  loader = glyph->loader;
731      FT_Outline*     base   = &loader->base.outline;
732
733
734      old_count = glyph->num_subs;
735
736      /* this is a compound glyph - load it */
737      error = pfr_glyph_load_compound( glyph, p, limit );
738
739      FT_FRAME_EXIT();
740
741      if ( error )
742        goto Exit;
743
744      count = glyph->num_subs - old_count;
745
746      /* now, load each individual glyph */
747      for ( n = 0; n < count; n++ )
748      {
749        FT_Int        i, old_points, num_points;
750        PFR_SubGlyph  subglyph;
751
752
753        subglyph   = glyph->subs + old_count + n;
754        old_points = base->n_points;
755
756        error = pfr_glyph_load_rec( glyph, stream, gps_offset,
757                                    subglyph->gps_offset,
758                                    subglyph->gps_size );
759        if ( error )
760          goto Exit;
761
762        /* note that `glyph->subs' might have been re-allocated */
763        subglyph   = glyph->subs + old_count + n;
764        num_points = base->n_points - old_points;
765
766        /* translate and eventually scale the new glyph points */
767        if ( subglyph->x_scale != 0x10000L || subglyph->y_scale != 0x10000L )
768        {
769          FT_Vector*  vec = base->points + old_points;
770
771
772          for ( i = 0; i < num_points; i++, vec++ )
773          {
774            vec->x = FT_MulFix( vec->x, subglyph->x_scale ) +
775                       subglyph->x_delta;
776            vec->y = FT_MulFix( vec->y, subglyph->y_scale ) +
777                       subglyph->y_delta;
778          }
779        }
780        else
781        {
782          FT_Vector*  vec = loader->base.outline.points + old_points;
783
784
785          for ( i = 0; i < num_points; i++, vec++ )
786          {
787            vec->x += subglyph->x_delta;
788            vec->y += subglyph->y_delta;
789          }
790        }
791
792        /* proceed to next sub-glyph */
793      }
794    }
795    else
796    {
797      /* load a simple glyph */
798      error = pfr_glyph_load_simple( glyph, p, limit );
799
800      FT_FRAME_EXIT();
801    }
802
803  Exit:
804    return error;
805  }
806
807
808
809
810
811  FT_LOCAL_DEF( FT_Error )
812  pfr_glyph_load( PFR_Glyph  glyph,
813                  FT_Stream  stream,
814                  FT_ULong   gps_offset,
815                  FT_ULong   offset,
816                  FT_ULong   size )
817  {
818    /* initialize glyph loader */
819    FT_GlyphLoader_Rewind( glyph->loader );
820
821    glyph->num_subs = 0;
822
823    /* load the glyph, recursively when needed */
824    return pfr_glyph_load_rec( glyph, stream, gps_offset, offset, size );
825  }
826
827
828/* END */
Note: See TracBrowser for help on using the repository browser.