1 /***************************************************************************/
5 /* FreeType PFR glyph loader (body). */
7 /* Copyright 2002 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;
62 glyph->num_x_control = 0;
63 glyph->num_y_control = 0;
65 FT_FREE( glyph->subs );
71 glyph->path_begun = 0;
75 /* close current contour, if any */
77 pfr_glyph_close_contour( PFR_Glyph glyph )
79 FT_GlyphLoader loader = glyph->loader;
80 FT_Outline* outline = &loader->current.outline;
84 if ( !glyph->path_begun )
87 /* compute first and last point indices in current glyph outline */
88 last = outline->n_points - 1;
90 if ( outline->n_contours > 0 )
91 first = outline->contours[outline->n_contours - 1];
93 /* if the last point falls on the same location than the first one */
94 /* we need to delete it */
97 FT_Vector* p1 = outline->points + first;
98 FT_Vector* p2 = outline->points + last;
101 if ( p1->x == p2->x && p1->y == p2->y )
108 /* don't add empty contours */
110 outline->contours[outline->n_contours++] = (short)last;
112 glyph->path_begun = 0;
116 /* reset glyph to start the loading of a new glyph */
118 pfr_glyph_start( PFR_Glyph glyph )
120 glyph->path_begun = 0;
125 pfr_glyph_line_to( PFR_Glyph glyph,
128 FT_GlyphLoader loader = glyph->loader;
129 FT_Outline* outline = &loader->current.outline;
133 /* check that we have begun a new path */
134 FT_ASSERT( glyph->path_begun != 0 );
136 error = FT_GlyphLoader_CheckPoints( loader, 1, 0 );
139 FT_UInt n = outline->n_points;
142 outline->points[n] = *to;
143 outline->tags [n] = FT_CURVE_TAG_ON;
153 pfr_glyph_curve_to( PFR_Glyph glyph,
158 FT_GlyphLoader loader = glyph->loader;
159 FT_Outline* outline = &loader->current.outline;
163 /* check that we have begun a new path */
164 FT_ASSERT( glyph->path_begun != 0 );
166 error = FT_GlyphLoader_CheckPoints( loader, 3, 0 );
169 FT_Vector* vec = outline->points + outline->n_points;
170 FT_Byte* tag = (FT_Byte*)outline->tags + outline->n_points;
176 tag[0] = FT_CURVE_TAG_CUBIC;
177 tag[1] = FT_CURVE_TAG_CUBIC;
178 tag[2] = FT_CURVE_TAG_ON;
180 outline->n_points = (FT_Short)( outline->n_points + 3 );
188 pfr_glyph_move_to( PFR_Glyph glyph,
191 FT_GlyphLoader loader = glyph->loader;
195 /* close current contour if any */
196 pfr_glyph_close_contour( glyph );
198 /* indicate that a new contour has started */
199 glyph->path_begun = 1;
201 /* check that there is room for a new contour and a new point */
202 error = FT_GlyphLoader_CheckPoints( loader, 1, 1 );
204 /* add new start point */
205 error = pfr_glyph_line_to( glyph, to );
212 pfr_glyph_end( PFR_Glyph glyph )
214 /* close current contour if any */
215 pfr_glyph_close_contour( glyph );
217 /* merge the current glyph into the stack */
218 FT_GlyphLoader_Add( glyph->loader );
222 /*************************************************************************/
223 /*************************************************************************/
225 /***** PFR GLYPH LOADER *****/
227 /*************************************************************************/
228 /*************************************************************************/
231 /* load a simple glyph */
233 pfr_glyph_load_simple( PFR_Glyph glyph,
238 FT_Memory memory = glyph->loader->memory;
239 FT_UInt flags, x_count, y_count, i, count, mask;
244 flags = PFR_NEXT_BYTE( p );
246 /* test for composite glyphs */
247 FT_ASSERT( ( flags & PFR_GLYPH_IS_COMPOUND ) == 0 );
252 if ( flags & PFR_GLYPH_1BYTE_XYCOUNT )
255 count = PFR_NEXT_BYTE( p );
256 x_count = ( count & 15 );
257 y_count = ( count >> 4 );
261 if ( flags & PFR_GLYPH_XCOUNT )
264 x_count = PFR_NEXT_BYTE( p );
267 if ( flags & PFR_GLYPH_YCOUNT )
270 y_count = PFR_NEXT_BYTE( p );
274 count = x_count + y_count;
276 /* re-allocate array when necessary */
277 if ( count > glyph->max_xy_control )
279 FT_UInt new_max = ( count + 7 ) & -8;
282 if ( FT_RENEW_ARRAY( glyph->x_control,
283 glyph->max_xy_control,
287 glyph->max_xy_control = new_max;
290 glyph->y_control = glyph->x_control + x_count;
295 for ( i = 0; i < count; i++ )
297 if ( ( i & 7 ) == 0 )
300 mask = PFR_NEXT_BYTE( p );
306 x = PFR_NEXT_SHORT( p );
311 x += PFR_NEXT_BYTE( p );
314 glyph->x_control[i] = x;
319 /* XXX: for now we ignore the secondary stroke and edge definitions */
320 /* since we don't want to support native PFR hinting */
322 if ( flags & PFR_GLYPH_EXTRA_ITEMS )
324 error = pfr_extra_items_skip( &p, limit );
329 pfr_glyph_start( glyph );
331 /* now load a simple glyph */
337 pos[0].x = pos[0].y = 0;
342 FT_Int format, args_format = 0, args_count, n;
345 /***************************************************************/
346 /* read instruction */
349 format = PFR_NEXT_BYTE( p );
351 switch ( format >> 4 )
353 case 0: /* end glyph */
354 FT_TRACE6(( "- end glyph" ));
358 case 1: /* general line operation */
359 FT_TRACE6(( "- general line" ));
362 case 4: /* move to inside contour */
363 FT_TRACE6(( "- move to inside" ));
366 case 5: /* move to outside contour */
367 FT_TRACE6(( "- move to outside" ));
369 args_format = format & 15;
373 case 2: /* horizontal line to */
374 FT_TRACE6(( "- horizontal line to cx.%d", format & 15 ));
376 pos[0].x = glyph->x_control[format & 15];
381 case 3: /* vertical line to */
382 FT_TRACE6(( "- vertical line to cy.%d", format & 15 ));
384 pos[0].y = glyph->y_control[format & 15];
389 case 6: /* horizontal to vertical curve */
390 FT_TRACE6(( "- hv curve " ));
395 case 7: /* vertical to horizontal curve */
396 FT_TRACE6(( "- vh curve" ));
401 default: /* general curve to */
402 FT_TRACE6(( "- general curve" ));
404 args_format = format & 15;
407 /***********************************************************/
408 /* now read arguments */
411 for ( n = 0; n < args_count; n++ )
416 /* read the X argument */
417 switch ( args_format & 3 )
419 case 0: /* 8-bit index */
421 idx = PFR_NEXT_BYTE( p );
422 cur->x = glyph->x_control[idx];
423 FT_TRACE7(( " cx#%d", idx ));
426 case 1: /* 16-bit value */
428 cur->x = PFR_NEXT_SHORT( p );
429 FT_TRACE7(( " x.%d", cur->x ));
432 case 2: /* 8-bit delta */
434 delta = PFR_NEXT_INT8( p );
435 cur->x = pos[3].x + delta;
436 FT_TRACE7(( " dx.%d", delta ));
444 /* read the Y argument */
445 switch ( ( args_format >> 2 ) & 3 )
447 case 0: /* 8-bit index */
449 idx = PFR_NEXT_BYTE( p );
450 cur->y = glyph->y_control[idx];
451 FT_TRACE7(( " cy#%d", idx ));
454 case 1: /* 16-bit absolute value */
456 cur->y = PFR_NEXT_SHORT( p );
457 FT_TRACE7(( " y.%d", cur->y ));
460 case 2: /* 8-bit delta */
462 delta = PFR_NEXT_INT8( p );
463 cur->y = pos[3].y + delta;
464 FT_TRACE7(( " dy.%d", delta ));
472 /* read the additional format flag for the general curve */
473 if ( n == 0 && args_count == 4 )
476 args_format = PFR_NEXT_BYTE( p );
482 /* save the previous point */
489 /***********************************************************/
490 /* finally, execute instruction */
492 switch ( format >> 4 )
494 case 0: /* end glyph => EXIT */
495 pfr_glyph_end( glyph );
498 case 1: /* line operations */
501 error = pfr_glyph_line_to( glyph, pos );
504 case 4: /* move to inside contour */
505 case 5: /* move to outside contour */
506 error = pfr_glyph_move_to( glyph, pos );
509 default: /* curve operations */
510 error = pfr_glyph_curve_to( glyph, pos, pos + 1, pos + 2 );
512 Test_Error: /* test error condition */
523 error = PFR_Err_Invalid_Table;
524 FT_ERROR(( "pfr_glyph_load_simple: invalid glyph data\n" ));
529 /* load a composite/compound glyph */
531 pfr_glyph_load_compound( PFR_Glyph glyph,
536 FT_GlyphLoader loader = glyph->loader;
537 FT_Memory memory = loader->memory;
538 PFR_SubGlyph subglyph;
539 FT_UInt flags, i, count, org_count;
544 flags = PFR_NEXT_BYTE( p );
546 /* test for composite glyphs */
547 FT_ASSERT( ( flags & PFR_GLYPH_IS_COMPOUND ) != 0 );
549 count = flags & 0x3F;
551 /* ignore extra items when present */
553 if ( flags & PFR_GLYPH_EXTRA_ITEMS )
555 error = pfr_extra_items_skip( &p, limit );
556 if (error) goto Exit;
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. */
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 */
567 org_count = glyph->num_subs;
569 if ( org_count + count > glyph->max_subs )
571 FT_UInt new_max = ( org_count + count + 3 ) & -4;
574 if ( FT_RENEW_ARRAY( glyph->subs, glyph->max_subs, new_max ) )
577 glyph->max_subs = new_max;
580 subglyph = glyph->subs + org_count;
582 for ( i = 0; i < count; i++, subglyph++ )
591 format = PFR_NEXT_BYTE( p );
593 /* read scale when available */
594 subglyph->x_scale = 0x10000L;
595 if ( format & PFR_SUBGLYPH_XSCALE )
598 subglyph->x_scale = PFR_NEXT_SHORT( p ) << 4;
601 subglyph->y_scale = 0x10000L;
602 if ( format & PFR_SUBGLYPH_YSCALE )
605 subglyph->y_scale = PFR_NEXT_SHORT( p ) << 4;
609 switch ( format & 3 )
613 x_pos = PFR_NEXT_SHORT( p );
618 x_pos += PFR_NEXT_INT8( p );
625 switch ( ( format >> 2 ) & 3 )
629 y_pos = PFR_NEXT_SHORT( p );
634 y_pos += PFR_NEXT_INT8( p );
641 subglyph->x_delta = x_pos;
642 subglyph->y_delta = y_pos;
644 /* read glyph position and size now */
645 if ( format & PFR_SUBGLYPH_2BYTE_SIZE )
648 subglyph->gps_size = PFR_NEXT_USHORT( p );
653 subglyph->gps_size = PFR_NEXT_BYTE( p );
656 if ( format & PFR_SUBGLYPH_3BYTE_OFFSET )
659 subglyph->gps_offset = PFR_NEXT_LONG( p );
664 subglyph->gps_offset = PFR_NEXT_USHORT( p );
674 error = PFR_Err_Invalid_Table;
675 FT_ERROR(( "pfr_glyph_load_compound: invalid glyph data\n" ));
684 pfr_glyph_load_rec( PFR_Glyph glyph,
695 if ( FT_STREAM_SEEK( gps_offset + offset ) ||
696 FT_FRAME_ENTER( size ) )
699 p = (FT_Byte*)stream->cursor;
702 if ( size > 0 && *p & PFR_GLYPH_IS_COMPOUND )
704 FT_Int n, old_count, count;
705 FT_GlyphLoader loader = glyph->loader;
706 FT_Outline* base = &loader->base.outline;
709 old_count = glyph->num_subs;
711 /* this is a compound glyph - load it */
712 error = pfr_glyph_load_compound( glyph, p, limit );
719 count = glyph->num_subs - old_count;
721 /* now, load each individual glyph */
722 for ( n = 0; n < count; n++ )
724 FT_Int i, old_points, num_points;
725 PFR_SubGlyph subglyph;
728 subglyph = glyph->subs + old_count + n;
729 old_points = base->n_points;
731 error = pfr_glyph_load_rec( glyph, stream, gps_offset,
732 subglyph->gps_offset,
733 subglyph->gps_size );
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;
741 /* translate and eventually scale the new glyph points */
742 if ( subglyph->x_scale != 0x10000L || subglyph->y_scale != 0x10000L )
744 FT_Vector* vec = base->points + old_points;
747 for ( i = 0; i < num_points; i++, vec++ )
749 vec->x = FT_MulFix( vec->x, subglyph->x_scale ) +
751 vec->y = FT_MulFix( vec->y, subglyph->y_scale ) +
757 FT_Vector* vec = loader->base.outline.points + old_points;
760 for ( i = 0; i < num_points; i++, vec++ )
762 vec->x += subglyph->x_delta;
763 vec->y += subglyph->y_delta;
767 /* proceed to next sub-glyph */
772 /* load a simple glyph */
773 error = pfr_glyph_load_simple( glyph, p, limit );
786 FT_LOCAL_DEF( FT_Error )
787 pfr_glyph_load( PFR_Glyph glyph,
793 /* initialize glyph loader */
794 FT_GlyphLoader_Rewind( glyph->loader );
796 /* load the glyph, recursively when needed */
797 return pfr_glyph_load_rec( glyph, stream, gps_offset, offset, size );