1 /***************************************************************************/
5 /* FreeType PFR glyph loader (body). */
7 /* Copyright 2002, 2003, 2005, 2007 by */
8 /* David Turner, Robert Wilhelm, and Werner Lemberg. */
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. */
16 /***************************************************************************/
21 #include "pfrload.h" /* for macro definitions */
22 #include FT_INTERNAL_DEBUG_H
27 #define FT_COMPONENT trace_pfr
30 /*************************************************************************/
31 /*************************************************************************/
33 /***** PFR GLYPH BUILDER *****/
35 /*************************************************************************/
36 /*************************************************************************/
40 pfr_glyph_init( PFR_Glyph glyph
,
41 FT_GlyphLoader loader
)
45 glyph
->loader
= loader
;
46 glyph
->path_begun
= 0;
48 FT_GlyphLoader_Rewind( loader
);
53 pfr_glyph_done( PFR_Glyph glyph
)
55 FT_Memory memory
= glyph
->loader
->memory
;
58 FT_FREE( glyph
->x_control
);
59 glyph
->y_control
= NULL
;
61 glyph
->max_xy_control
= 0;
63 glyph
->num_x_control
= 0;
64 glyph
->num_y_control
= 0;
67 FT_FREE( glyph
->subs
);
73 glyph
->path_begun
= 0;
77 /* close current contour, if any */
79 pfr_glyph_close_contour( PFR_Glyph glyph
)
81 FT_GlyphLoader loader
= glyph
->loader
;
82 FT_Outline
* outline
= &loader
->current
.outline
;
86 if ( !glyph
->path_begun
)
89 /* compute first and last point indices in current glyph outline */
90 last
= outline
->n_points
- 1;
92 if ( outline
->n_contours
> 0 )
93 first
= outline
->contours
[outline
->n_contours
- 1];
95 /* if the last point falls on the same location than the first one */
96 /* we need to delete it */
99 FT_Vector
* p1
= outline
->points
+ first
;
100 FT_Vector
* p2
= outline
->points
+ last
;
103 if ( p1
->x
== p2
->x
&& p1
->y
== p2
->y
)
110 /* don't add empty contours */
112 outline
->contours
[outline
->n_contours
++] = (short)last
;
114 glyph
->path_begun
= 0;
118 /* reset glyph to start the loading of a new glyph */
120 pfr_glyph_start( PFR_Glyph glyph
)
122 glyph
->path_begun
= 0;
127 pfr_glyph_line_to( PFR_Glyph glyph
,
130 FT_GlyphLoader loader
= glyph
->loader
;
131 FT_Outline
* outline
= &loader
->current
.outline
;
135 /* check that we have begun a new path */
136 if ( !glyph
->path_begun
)
138 error
= PFR_Err_Invalid_Table
;
139 FT_ERROR(( "pfr_glyph_line_to: invalid glyph data\n" ));
143 error
= FT_GLYPHLOADER_CHECK_POINTS( loader
, 1, 0 );
146 FT_UInt n
= outline
->n_points
;
149 outline
->points
[n
] = *to
;
150 outline
->tags
[n
] = FT_CURVE_TAG_ON
;
161 pfr_glyph_curve_to( PFR_Glyph glyph
,
166 FT_GlyphLoader loader
= glyph
->loader
;
167 FT_Outline
* outline
= &loader
->current
.outline
;
171 /* check that we have begun a new path */
172 if ( !glyph
->path_begun
)
174 error
= PFR_Err_Invalid_Table
;
175 FT_ERROR(( "pfr_glyph_line_to: invalid glyph data\n" ));
179 error
= FT_GLYPHLOADER_CHECK_POINTS( loader
, 3, 0 );
182 FT_Vector
* vec
= outline
->points
+ outline
->n_points
;
183 FT_Byte
* tag
= (FT_Byte
*)outline
->tags
+ outline
->n_points
;
189 tag
[0] = FT_CURVE_TAG_CUBIC
;
190 tag
[1] = FT_CURVE_TAG_CUBIC
;
191 tag
[2] = FT_CURVE_TAG_ON
;
193 outline
->n_points
= (FT_Short
)( outline
->n_points
+ 3 );
202 pfr_glyph_move_to( PFR_Glyph glyph
,
205 FT_GlyphLoader loader
= glyph
->loader
;
209 /* close current contour if any */
210 pfr_glyph_close_contour( glyph
);
212 /* indicate that a new contour has started */
213 glyph
->path_begun
= 1;
215 /* check that there is space for a new contour and a new point */
216 error
= FT_GLYPHLOADER_CHECK_POINTS( loader
, 1, 1 );
218 /* add new start point */
219 error
= pfr_glyph_line_to( glyph
, to
);
226 pfr_glyph_end( PFR_Glyph glyph
)
228 /* close current contour if any */
229 pfr_glyph_close_contour( glyph
);
231 /* merge the current glyph into the stack */
232 FT_GlyphLoader_Add( glyph
->loader
);
236 /*************************************************************************/
237 /*************************************************************************/
239 /***** PFR GLYPH LOADER *****/
241 /*************************************************************************/
242 /*************************************************************************/
245 /* load a simple glyph */
247 pfr_glyph_load_simple( PFR_Glyph glyph
,
252 FT_Memory memory
= glyph
->loader
->memory
;
253 FT_UInt flags
, x_count
, y_count
, i
, count
, mask
;
258 flags
= PFR_NEXT_BYTE( p
);
260 /* test for composite glyphs */
261 if ( flags
& PFR_GLYPH_IS_COMPOUND
)
267 if ( flags
& PFR_GLYPH_1BYTE_XYCOUNT
)
270 count
= PFR_NEXT_BYTE( p
);
271 x_count
= ( count
& 15 );
272 y_count
= ( count
>> 4 );
276 if ( flags
& PFR_GLYPH_XCOUNT
)
279 x_count
= PFR_NEXT_BYTE( p
);
282 if ( flags
& PFR_GLYPH_YCOUNT
)
285 y_count
= PFR_NEXT_BYTE( p
);
289 count
= x_count
+ y_count
;
291 /* re-allocate array when necessary */
292 if ( count
> glyph
->max_xy_control
)
294 FT_UInt new_max
= FT_PAD_CEIL( count
, 8 );
297 if ( FT_RENEW_ARRAY( glyph
->x_control
,
298 glyph
->max_xy_control
,
302 glyph
->max_xy_control
= new_max
;
305 glyph
->y_control
= glyph
->x_control
+ x_count
;
310 for ( i
= 0; i
< count
; i
++ )
312 if ( ( i
& 7 ) == 0 )
315 mask
= PFR_NEXT_BYTE( p
);
321 x
= PFR_NEXT_SHORT( p
);
326 x
+= PFR_NEXT_BYTE( p
);
329 glyph
->x_control
[i
] = x
;
334 /* XXX: for now we ignore the secondary stroke and edge definitions */
335 /* since we don't want to support native PFR hinting */
337 if ( flags
& PFR_GLYPH_EXTRA_ITEMS
)
339 error
= pfr_extra_items_skip( &p
, limit
);
344 pfr_glyph_start( glyph
);
346 /* now load a simple glyph */
352 pos
[0].x
= pos
[0].y
= 0;
357 FT_UInt format
, format_low
, args_format
= 0, args_count
, n
;
360 /***************************************************************/
361 /* read instruction */
364 format
= PFR_NEXT_BYTE( p
);
365 format_low
= format
& 15;
367 switch ( format
>> 4 )
369 case 0: /* end glyph */
370 FT_TRACE6(( "- end glyph" ));
374 case 1: /* general line operation */
375 FT_TRACE6(( "- general line" ));
378 case 4: /* move to inside contour */
379 FT_TRACE6(( "- move to inside" ));
382 case 5: /* move to outside contour */
383 FT_TRACE6(( "- move to outside" ));
385 args_format
= format_low
;
389 case 2: /* horizontal line to */
390 FT_TRACE6(( "- horizontal line to cx.%d", format_low
));
391 if ( format_low
> x_count
)
393 pos
[0].x
= glyph
->x_control
[format_low
];
399 case 3: /* vertical line to */
400 FT_TRACE6(( "- vertical line to cy.%d", format_low
));
401 if ( format_low
> y_count
)
404 pos
[0].y
= glyph
->y_control
[format_low
];
409 case 6: /* horizontal to vertical curve */
410 FT_TRACE6(( "- hv curve " ));
415 case 7: /* vertical to horizontal curve */
416 FT_TRACE6(( "- vh curve" ));
421 default: /* general curve to */
422 FT_TRACE6(( "- general curve" ));
424 args_format
= format_low
;
427 /***********************************************************/
428 /* now read arguments */
431 for ( n
= 0; n
< args_count
; n
++ )
437 /* read the X argument */
438 switch ( args_format
& 3 )
440 case 0: /* 8-bit index */
442 idx
= PFR_NEXT_BYTE( p
);
445 cur
->x
= glyph
->x_control
[idx
];
446 FT_TRACE7(( " cx#%d", idx
));
449 case 1: /* 16-bit value */
451 cur
->x
= PFR_NEXT_SHORT( p
);
452 FT_TRACE7(( " x.%d", cur
->x
));
455 case 2: /* 8-bit delta */
457 delta
= PFR_NEXT_INT8( p
);
458 cur
->x
= pos
[3].x
+ delta
;
459 FT_TRACE7(( " dx.%d", delta
));
467 /* read the Y argument */
468 switch ( ( args_format
>> 2 ) & 3 )
470 case 0: /* 8-bit index */
472 idx
= PFR_NEXT_BYTE( p
);
475 cur
->y
= glyph
->y_control
[idx
];
476 FT_TRACE7(( " cy#%d", idx
));
479 case 1: /* 16-bit absolute value */
481 cur
->y
= PFR_NEXT_SHORT( p
);
482 FT_TRACE7(( " y.%d", cur
->y
));
485 case 2: /* 8-bit delta */
487 delta
= PFR_NEXT_INT8( p
);
488 cur
->y
= pos
[3].y
+ delta
;
489 FT_TRACE7(( " dy.%d", delta
));
497 /* read the additional format flag for the general curve */
498 if ( n
== 0 && args_count
== 4 )
501 args_format
= PFR_NEXT_BYTE( p
);
507 /* save the previous point */
514 /***********************************************************/
515 /* finally, execute instruction */
517 switch ( format
>> 4 )
519 case 0: /* end glyph => EXIT */
520 pfr_glyph_end( glyph
);
523 case 1: /* line operations */
526 error
= pfr_glyph_line_to( glyph
, pos
);
529 case 4: /* move to inside contour */
530 case 5: /* move to outside contour */
531 error
= pfr_glyph_move_to( glyph
, pos
);
534 default: /* curve operations */
535 error
= pfr_glyph_curve_to( glyph
, pos
, pos
+ 1, pos
+ 2 );
537 Test_Error
: /* test error condition */
549 error
= PFR_Err_Invalid_Table
;
550 FT_ERROR(( "pfr_glyph_load_simple: invalid glyph data\n" ));
555 /* load a composite/compound glyph */
557 pfr_glyph_load_compound( PFR_Glyph glyph
,
562 FT_GlyphLoader loader
= glyph
->loader
;
563 FT_Memory memory
= loader
->memory
;
564 PFR_SubGlyph subglyph
;
565 FT_UInt flags
, i
, count
, org_count
;
570 flags
= PFR_NEXT_BYTE( p
);
572 /* test for composite glyphs */
573 if ( !( flags
& PFR_GLYPH_IS_COMPOUND
) )
576 count
= flags
& 0x3F;
578 /* ignore extra items when present */
580 if ( flags
& PFR_GLYPH_EXTRA_ITEMS
)
582 error
= pfr_extra_items_skip( &p
, limit
);
583 if (error
) goto Exit
;
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. */
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 */
594 org_count
= glyph
->num_subs
;
596 if ( org_count
+ count
> glyph
->max_subs
)
598 FT_UInt new_max
= ( org_count
+ count
+ 3 ) & (FT_UInt
)-4;
601 if ( FT_RENEW_ARRAY( glyph
->subs
, glyph
->max_subs
, new_max
) )
604 glyph
->max_subs
= new_max
;
607 subglyph
= glyph
->subs
+ org_count
;
609 for ( i
= 0; i
< count
; i
++, subglyph
++ )
618 format
= PFR_NEXT_BYTE( p
);
620 /* read scale when available */
621 subglyph
->x_scale
= 0x10000L
;
622 if ( format
& PFR_SUBGLYPH_XSCALE
)
625 subglyph
->x_scale
= PFR_NEXT_SHORT( p
) << 4;
628 subglyph
->y_scale
= 0x10000L
;
629 if ( format
& PFR_SUBGLYPH_YSCALE
)
632 subglyph
->y_scale
= PFR_NEXT_SHORT( p
) << 4;
636 switch ( format
& 3 )
640 x_pos
= PFR_NEXT_SHORT( p
);
645 x_pos
+= PFR_NEXT_INT8( p
);
652 switch ( ( format
>> 2 ) & 3 )
656 y_pos
= PFR_NEXT_SHORT( p
);
661 y_pos
+= PFR_NEXT_INT8( p
);
668 subglyph
->x_delta
= x_pos
;
669 subglyph
->y_delta
= y_pos
;
671 /* read glyph position and size now */
672 if ( format
& PFR_SUBGLYPH_2BYTE_SIZE
)
675 subglyph
->gps_size
= PFR_NEXT_USHORT( p
);
680 subglyph
->gps_size
= PFR_NEXT_BYTE( p
);
683 if ( format
& PFR_SUBGLYPH_3BYTE_OFFSET
)
686 subglyph
->gps_offset
= PFR_NEXT_LONG( p
);
691 subglyph
->gps_offset
= PFR_NEXT_USHORT( p
);
702 error
= PFR_Err_Invalid_Table
;
703 FT_ERROR(( "pfr_glyph_load_compound: invalid glyph data\n" ));
709 pfr_glyph_load_rec( PFR_Glyph glyph
,
720 if ( FT_STREAM_SEEK( gps_offset
+ offset
) ||
721 FT_FRAME_ENTER( size
) )
724 p
= (FT_Byte
*)stream
->cursor
;
727 if ( size
> 0 && *p
& PFR_GLYPH_IS_COMPOUND
)
729 FT_Int n
, old_count
, count
;
730 FT_GlyphLoader loader
= glyph
->loader
;
731 FT_Outline
* base
= &loader
->base
.outline
;
734 old_count
= glyph
->num_subs
;
736 /* this is a compound glyph - load it */
737 error
= pfr_glyph_load_compound( glyph
, p
, limit
);
744 count
= glyph
->num_subs
- old_count
;
746 /* now, load each individual glyph */
747 for ( n
= 0; n
< count
; n
++ )
749 FT_Int i
, old_points
, num_points
;
750 PFR_SubGlyph subglyph
;
753 subglyph
= glyph
->subs
+ old_count
+ n
;
754 old_points
= base
->n_points
;
756 error
= pfr_glyph_load_rec( glyph
, stream
, gps_offset
,
757 subglyph
->gps_offset
,
758 subglyph
->gps_size
);
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
;
766 /* translate and eventually scale the new glyph points */
767 if ( subglyph
->x_scale
!= 0x10000L
|| subglyph
->y_scale
!= 0x10000L
)
769 FT_Vector
* vec
= base
->points
+ old_points
;
772 for ( i
= 0; i
< num_points
; i
++, vec
++ )
774 vec
->x
= FT_MulFix( vec
->x
, subglyph
->x_scale
) +
776 vec
->y
= FT_MulFix( vec
->y
, subglyph
->y_scale
) +
782 FT_Vector
* vec
= loader
->base
.outline
.points
+ old_points
;
785 for ( i
= 0; i
< num_points
; i
++, vec
++ )
787 vec
->x
+= subglyph
->x_delta
;
788 vec
->y
+= subglyph
->y_delta
;
792 /* proceed to next sub-glyph */
797 /* load a simple glyph */
798 error
= pfr_glyph_load_simple( glyph
, p
, limit
);
811 FT_LOCAL_DEF( FT_Error
)
812 pfr_glyph_load( PFR_Glyph glyph
,
818 /* initialize glyph loader */
819 FT_GlyphLoader_Rewind( glyph
->loader
);
823 /* load the glyph, recursively when needed */
824 return pfr_glyph_load_rec( glyph
, stream
, gps_offset
, offset
, size
);