-/***************************************************************************/\r
-/* */\r
-/* pfrgload.c */\r
-/* */\r
-/* FreeType PFR glyph loader (body). */\r
-/* */\r
-/* Copyright 2002, 2003, 2005, 2007 by */\r
-/* David Turner, Robert Wilhelm, and Werner Lemberg. */\r
-/* */\r
-/* This file is part of the FreeType project, and may only be used, */\r
-/* modified, and distributed under the terms of the FreeType project */\r
-/* license, LICENSE.TXT. By continuing to use, modify, or distribute */\r
-/* this file you indicate that you have read the license and */\r
-/* understand and accept it fully. */\r
-/* */\r
-/***************************************************************************/\r
-\r
-\r
-#include "pfrgload.h"\r
-#include "pfrsbit.h"\r
-#include "pfrload.h" /* for macro definitions */\r
-#include FT_INTERNAL_DEBUG_H\r
-\r
-#include "pfrerror.h"\r
-\r
-#undef FT_COMPONENT\r
-#define FT_COMPONENT trace_pfr\r
-\r
-\r
- /*************************************************************************/\r
- /*************************************************************************/\r
- /***** *****/\r
- /***** PFR GLYPH BUILDER *****/\r
- /***** *****/\r
- /*************************************************************************/\r
- /*************************************************************************/\r
-\r
-\r
- FT_LOCAL_DEF( void )\r
- pfr_glyph_init( PFR_Glyph glyph,\r
- FT_GlyphLoader loader )\r
- {\r
- FT_ZERO( glyph );\r
-\r
- glyph->loader = loader;\r
- glyph->path_begun = 0;\r
-\r
- FT_GlyphLoader_Rewind( loader );\r
- }\r
-\r
-\r
- FT_LOCAL_DEF( void )\r
- pfr_glyph_done( PFR_Glyph glyph )\r
- {\r
- FT_Memory memory = glyph->loader->memory;\r
-\r
-\r
- FT_FREE( glyph->x_control );\r
- glyph->y_control = NULL;\r
-\r
- glyph->max_xy_control = 0;\r
-#if 0\r
- glyph->num_x_control = 0;\r
- glyph->num_y_control = 0;\r
-#endif\r
-\r
- FT_FREE( glyph->subs );\r
-\r
- glyph->max_subs = 0;\r
- glyph->num_subs = 0;\r
-\r
- glyph->loader = NULL;\r
- glyph->path_begun = 0;\r
- }\r
-\r
-\r
- /* close current contour, if any */\r
- static void\r
- pfr_glyph_close_contour( PFR_Glyph glyph )\r
- {\r
- FT_GlyphLoader loader = glyph->loader;\r
- FT_Outline* outline = &loader->current.outline;\r
- FT_Int last, first;\r
-\r
-\r
- if ( !glyph->path_begun )\r
- return;\r
-\r
- /* compute first and last point indices in current glyph outline */\r
- last = outline->n_points - 1;\r
- first = 0;\r
- if ( outline->n_contours > 0 )\r
- first = outline->contours[outline->n_contours - 1];\r
-\r
- /* if the last point falls on the same location than the first one */\r
- /* we need to delete it */\r
- if ( last > first )\r
- {\r
- FT_Vector* p1 = outline->points + first;\r
- FT_Vector* p2 = outline->points + last;\r
-\r
-\r
- if ( p1->x == p2->x && p1->y == p2->y )\r
- {\r
- outline->n_points--;\r
- last--;\r
- }\r
- }\r
-\r
- /* don't add empty contours */\r
- if ( last >= first )\r
- outline->contours[outline->n_contours++] = (short)last;\r
-\r
- glyph->path_begun = 0;\r
- }\r
-\r
-\r
- /* reset glyph to start the loading of a new glyph */\r
- static void\r
- pfr_glyph_start( PFR_Glyph glyph )\r
- {\r
- glyph->path_begun = 0;\r
- }\r
-\r
-\r
- static FT_Error\r
- pfr_glyph_line_to( PFR_Glyph glyph,\r
- FT_Vector* to )\r
- {\r
- FT_GlyphLoader loader = glyph->loader;\r
- FT_Outline* outline = &loader->current.outline;\r
- FT_Error error;\r
-\r
-\r
- /* check that we have begun a new path */\r
- if ( !glyph->path_begun )\r
- {\r
- error = PFR_Err_Invalid_Table;\r
- FT_ERROR(( "pfr_glyph_line_to: invalid glyph data\n" ));\r
- goto Exit;\r
- }\r
-\r
- error = FT_GLYPHLOADER_CHECK_POINTS( loader, 1, 0 );\r
- if ( !error )\r
- {\r
- FT_UInt n = outline->n_points;\r
-\r
-\r
- outline->points[n] = *to;\r
- outline->tags [n] = FT_CURVE_TAG_ON;\r
-\r
- outline->n_points++;\r
- }\r
-\r
- Exit:\r
- return error;\r
- }\r
-\r
-\r
- static FT_Error\r
- pfr_glyph_curve_to( PFR_Glyph glyph,\r
- FT_Vector* control1,\r
- FT_Vector* control2,\r
- FT_Vector* to )\r
- {\r
- FT_GlyphLoader loader = glyph->loader;\r
- FT_Outline* outline = &loader->current.outline;\r
- FT_Error error;\r
-\r
-\r
- /* check that we have begun a new path */\r
- if ( !glyph->path_begun )\r
- {\r
- error = PFR_Err_Invalid_Table;\r
- FT_ERROR(( "pfr_glyph_line_to: invalid glyph data\n" ));\r
- goto Exit;\r
- }\r
-\r
- error = FT_GLYPHLOADER_CHECK_POINTS( loader, 3, 0 );\r
- if ( !error )\r
- {\r
- FT_Vector* vec = outline->points + outline->n_points;\r
- FT_Byte* tag = (FT_Byte*)outline->tags + outline->n_points;\r
-\r
-\r
- vec[0] = *control1;\r
- vec[1] = *control2;\r
- vec[2] = *to;\r
- tag[0] = FT_CURVE_TAG_CUBIC;\r
- tag[1] = FT_CURVE_TAG_CUBIC;\r
- tag[2] = FT_CURVE_TAG_ON;\r
-\r
- outline->n_points = (FT_Short)( outline->n_points + 3 );\r
- }\r
-\r
- Exit:\r
- return error;\r
- }\r
-\r
-\r
- static FT_Error\r
- pfr_glyph_move_to( PFR_Glyph glyph,\r
- FT_Vector* to )\r
- {\r
- FT_GlyphLoader loader = glyph->loader;\r
- FT_Error error;\r
-\r
-\r
- /* close current contour if any */\r
- pfr_glyph_close_contour( glyph );\r
-\r
- /* indicate that a new contour has started */\r
- glyph->path_begun = 1;\r
-\r
- /* check that there is space for a new contour and a new point */\r
- error = FT_GLYPHLOADER_CHECK_POINTS( loader, 1, 1 );\r
- if ( !error )\r
- /* add new start point */\r
- error = pfr_glyph_line_to( glyph, to );\r
-\r
- return error;\r
- }\r
-\r
-\r
- static void\r
- pfr_glyph_end( PFR_Glyph glyph )\r
- {\r
- /* close current contour if any */\r
- pfr_glyph_close_contour( glyph );\r
-\r
- /* merge the current glyph into the stack */\r
- FT_GlyphLoader_Add( glyph->loader );\r
- }\r
-\r
-\r
- /*************************************************************************/\r
- /*************************************************************************/\r
- /***** *****/\r
- /***** PFR GLYPH LOADER *****/\r
- /***** *****/\r
- /*************************************************************************/\r
- /*************************************************************************/\r
-\r
-\r
- /* load a simple glyph */\r
- static FT_Error\r
- pfr_glyph_load_simple( PFR_Glyph glyph,\r
- FT_Byte* p,\r
- FT_Byte* limit )\r
- {\r
- FT_Error error = 0;\r
- FT_Memory memory = glyph->loader->memory;\r
- FT_UInt flags, x_count, y_count, i, count, mask;\r
- FT_Int x;\r
-\r
-\r
- PFR_CHECK( 1 );\r
- flags = PFR_NEXT_BYTE( p );\r
-\r
- /* test for composite glyphs */\r
- if ( flags & PFR_GLYPH_IS_COMPOUND )\r
- goto Failure;\r
-\r
- x_count = 0;\r
- y_count = 0;\r
-\r
- if ( flags & PFR_GLYPH_1BYTE_XYCOUNT )\r
- {\r
- PFR_CHECK( 1 );\r
- count = PFR_NEXT_BYTE( p );\r
- x_count = ( count & 15 );\r
- y_count = ( count >> 4 );\r
- }\r
- else\r
- {\r
- if ( flags & PFR_GLYPH_XCOUNT )\r
- {\r
- PFR_CHECK( 1 );\r
- x_count = PFR_NEXT_BYTE( p );\r
- }\r
-\r
- if ( flags & PFR_GLYPH_YCOUNT )\r
- {\r
- PFR_CHECK( 1 );\r
- y_count = PFR_NEXT_BYTE( p );\r
- }\r
- }\r
-\r
- count = x_count + y_count;\r
-\r
- /* re-allocate array when necessary */\r
- if ( count > glyph->max_xy_control )\r
- {\r
- FT_UInt new_max = FT_PAD_CEIL( count, 8 );\r
-\r
-\r
- if ( FT_RENEW_ARRAY( glyph->x_control,\r
- glyph->max_xy_control,\r
- new_max ) )\r
- goto Exit;\r
-\r
- glyph->max_xy_control = new_max;\r
- }\r
-\r
- glyph->y_control = glyph->x_control + x_count;\r
-\r
- mask = 0;\r
- x = 0;\r
-\r
- for ( i = 0; i < count; i++ )\r
- {\r
- if ( ( i & 7 ) == 0 )\r
- {\r
- PFR_CHECK( 1 );\r
- mask = PFR_NEXT_BYTE( p );\r
- }\r
-\r
- if ( mask & 1 )\r
- {\r
- PFR_CHECK( 2 );\r
- x = PFR_NEXT_SHORT( p );\r
- }\r
- else\r
- {\r
- PFR_CHECK( 1 );\r
- x += PFR_NEXT_BYTE( p );\r
- }\r
-\r
- glyph->x_control[i] = x;\r
-\r
- mask >>= 1;\r
- }\r
-\r
- /* XXX: for now we ignore the secondary stroke and edge definitions */\r
- /* since we don't want to support native PFR hinting */\r
- /* */\r
- if ( flags & PFR_GLYPH_EXTRA_ITEMS )\r
- {\r
- error = pfr_extra_items_skip( &p, limit );\r
- if ( error )\r
- goto Exit;\r
- }\r
-\r
- pfr_glyph_start( glyph );\r
-\r
- /* now load a simple glyph */\r
- {\r
- FT_Vector pos[4];\r
- FT_Vector* cur;\r
-\r
-\r
- pos[0].x = pos[0].y = 0;\r
- pos[3] = pos[0];\r
-\r
- for (;;)\r
- {\r
- FT_UInt format, format_low, args_format = 0, args_count, n;\r
-\r
-\r
- /***************************************************************/\r
- /* read instruction */\r
- /* */\r
- PFR_CHECK( 1 );\r
- format = PFR_NEXT_BYTE( p );\r
- format_low = format & 15;\r
-\r
- switch ( format >> 4 )\r
- {\r
- case 0: /* end glyph */\r
- FT_TRACE6(( "- end glyph" ));\r
- args_count = 0;\r
- break;\r
-\r
- case 1: /* general line operation */\r
- FT_TRACE6(( "- general line" ));\r
- goto Line1;\r
-\r
- case 4: /* move to inside contour */\r
- FT_TRACE6(( "- move to inside" ));\r
- goto Line1;\r
-\r
- case 5: /* move to outside contour */\r
- FT_TRACE6(( "- move to outside" ));\r
- Line1:\r
- args_format = format_low;\r
- args_count = 1;\r
- break;\r
-\r
- case 2: /* horizontal line to */\r
- FT_TRACE6(( "- horizontal line to cx.%d", format_low ));\r
- if ( format_low > x_count )\r
- goto Failure;\r
- pos[0].x = glyph->x_control[format_low];\r
- pos[0].y = pos[3].y;\r
- pos[3] = pos[0];\r
- args_count = 0;\r
- break;\r
-\r
- case 3: /* vertical line to */\r
- FT_TRACE6(( "- vertical line to cy.%d", format_low ));\r
- if ( format_low > y_count )\r
- goto Failure;\r
- pos[0].x = pos[3].x;\r
- pos[0].y = glyph->y_control[format_low];\r
- pos[3] = pos[0];\r
- args_count = 0;\r
- break;\r
-\r
- case 6: /* horizontal to vertical curve */\r
- FT_TRACE6(( "- hv curve " ));\r
- args_format = 0xB8E;\r
- args_count = 3;\r
- break;\r
-\r
- case 7: /* vertical to horizontal curve */\r
- FT_TRACE6(( "- vh curve" ));\r
- args_format = 0xE2B;\r
- args_count = 3;\r
- break;\r
-\r
- default: /* general curve to */\r
- FT_TRACE6(( "- general curve" ));\r
- args_count = 4;\r
- args_format = format_low;\r
- }\r
-\r
- /***********************************************************/\r
- /* now read arguments */\r
- /* */\r
- cur = pos;\r
- for ( n = 0; n < args_count; n++ )\r
- {\r
- FT_UInt idx;\r
- FT_Int delta;\r
-\r
-\r
- /* read the X argument */\r
- switch ( args_format & 3 )\r
- {\r
- case 0: /* 8-bit index */\r
- PFR_CHECK( 1 );\r
- idx = PFR_NEXT_BYTE( p );\r
- if ( idx > x_count )\r
- goto Failure;\r
- cur->x = glyph->x_control[idx];\r
- FT_TRACE7(( " cx#%d", idx ));\r
- break;\r
-\r
- case 1: /* 16-bit value */\r
- PFR_CHECK( 2 );\r
- cur->x = PFR_NEXT_SHORT( p );\r
- FT_TRACE7(( " x.%d", cur->x ));\r
- break;\r
-\r
- case 2: /* 8-bit delta */\r
- PFR_CHECK( 1 );\r
- delta = PFR_NEXT_INT8( p );\r
- cur->x = pos[3].x + delta;\r
- FT_TRACE7(( " dx.%d", delta ));\r
- break;\r
-\r
- default:\r
- FT_TRACE7(( " |" ));\r
- cur->x = pos[3].x;\r
- }\r
-\r
- /* read the Y argument */\r
- switch ( ( args_format >> 2 ) & 3 )\r
- {\r
- case 0: /* 8-bit index */\r
- PFR_CHECK( 1 );\r
- idx = PFR_NEXT_BYTE( p );\r
- if ( idx > y_count )\r
- goto Failure;\r
- cur->y = glyph->y_control[idx];\r
- FT_TRACE7(( " cy#%d", idx ));\r
- break;\r
-\r
- case 1: /* 16-bit absolute value */\r
- PFR_CHECK( 2 );\r
- cur->y = PFR_NEXT_SHORT( p );\r
- FT_TRACE7(( " y.%d", cur->y ));\r
- break;\r
-\r
- case 2: /* 8-bit delta */\r
- PFR_CHECK( 1 );\r
- delta = PFR_NEXT_INT8( p );\r
- cur->y = pos[3].y + delta;\r
- FT_TRACE7(( " dy.%d", delta ));\r
- break;\r
-\r
- default:\r
- FT_TRACE7(( " -" ));\r
- cur->y = pos[3].y;\r
- }\r
-\r
- /* read the additional format flag for the general curve */\r
- if ( n == 0 && args_count == 4 )\r
- {\r
- PFR_CHECK( 1 );\r
- args_format = PFR_NEXT_BYTE( p );\r
- args_count--;\r
- }\r
- else\r
- args_format >>= 4;\r
-\r
- /* save the previous point */\r
- pos[3] = cur[0];\r
- cur++;\r
- }\r
-\r
- FT_TRACE7(( "\n" ));\r
-\r
- /***********************************************************/\r
- /* finally, execute instruction */\r
- /* */\r
- switch ( format >> 4 )\r
- {\r
- case 0: /* end glyph => EXIT */\r
- pfr_glyph_end( glyph );\r
- goto Exit;\r
-\r
- case 1: /* line operations */\r
- case 2:\r
- case 3:\r
- error = pfr_glyph_line_to( glyph, pos );\r
- goto Test_Error;\r
-\r
- case 4: /* move to inside contour */\r
- case 5: /* move to outside contour */\r
- error = pfr_glyph_move_to( glyph, pos );\r
- goto Test_Error;\r
-\r
- default: /* curve operations */\r
- error = pfr_glyph_curve_to( glyph, pos, pos + 1, pos + 2 );\r
-\r
- Test_Error: /* test error condition */\r
- if ( error )\r
- goto Exit;\r
- }\r
- } /* for (;;) */\r
- }\r
-\r
- Exit:\r
- return error;\r
-\r
- Failure:\r
- Too_Short:\r
- error = PFR_Err_Invalid_Table;\r
- FT_ERROR(( "pfr_glyph_load_simple: invalid glyph data\n" ));\r
- goto Exit;\r
- }\r
-\r
-\r
- /* load a composite/compound glyph */\r
- static FT_Error\r
- pfr_glyph_load_compound( PFR_Glyph glyph,\r
- FT_Byte* p,\r
- FT_Byte* limit )\r
- {\r
- FT_Error error = 0;\r
- FT_GlyphLoader loader = glyph->loader;\r
- FT_Memory memory = loader->memory;\r
- PFR_SubGlyph subglyph;\r
- FT_UInt flags, i, count, org_count;\r
- FT_Int x_pos, y_pos;\r
-\r
-\r
- PFR_CHECK( 1 );\r
- flags = PFR_NEXT_BYTE( p );\r
-\r
- /* test for composite glyphs */\r
- if ( !( flags & PFR_GLYPH_IS_COMPOUND ) )\r
- goto Failure;\r
-\r
- count = flags & 0x3F;\r
-\r
- /* ignore extra items when present */\r
- /* */\r
- if ( flags & PFR_GLYPH_EXTRA_ITEMS )\r
- {\r
- error = pfr_extra_items_skip( &p, limit );\r
- if (error) goto Exit;\r
- }\r
-\r
- /* we can't rely on the FT_GlyphLoader to load sub-glyphs, because */\r
- /* the PFR format is dumb, using direct file offsets to point to the */\r
- /* sub-glyphs (instead of glyph indices). Sigh. */\r
- /* */\r
- /* For now, we load the list of sub-glyphs into a different array */\r
- /* but this will prevent us from using the auto-hinter at its best */\r
- /* quality. */\r
- /* */\r
- org_count = glyph->num_subs;\r
-\r
- if ( org_count + count > glyph->max_subs )\r
- {\r
- FT_UInt new_max = ( org_count + count + 3 ) & -4;\r
-\r
-\r
- if ( FT_RENEW_ARRAY( glyph->subs, glyph->max_subs, new_max ) )\r
- goto Exit;\r
-\r
- glyph->max_subs = new_max;\r
- }\r
-\r
- subglyph = glyph->subs + org_count;\r
-\r
- for ( i = 0; i < count; i++, subglyph++ )\r
- {\r
- FT_UInt format;\r
-\r
-\r
- x_pos = 0;\r
- y_pos = 0;\r
-\r
- PFR_CHECK( 1 );\r
- format = PFR_NEXT_BYTE( p );\r
-\r
- /* read scale when available */\r
- subglyph->x_scale = 0x10000L;\r
- if ( format & PFR_SUBGLYPH_XSCALE )\r
- {\r
- PFR_CHECK( 2 );\r
- subglyph->x_scale = PFR_NEXT_SHORT( p ) << 4;\r
- }\r
-\r
- subglyph->y_scale = 0x10000L;\r
- if ( format & PFR_SUBGLYPH_YSCALE )\r
- {\r
- PFR_CHECK( 2 );\r
- subglyph->y_scale = PFR_NEXT_SHORT( p ) << 4;\r
- }\r
-\r
- /* read offset */\r
- switch ( format & 3 )\r
- {\r
- case 1:\r
- PFR_CHECK( 2 );\r
- x_pos = PFR_NEXT_SHORT( p );\r
- break;\r
-\r
- case 2:\r
- PFR_CHECK( 1 );\r
- x_pos += PFR_NEXT_INT8( p );\r
- break;\r
-\r
- default:\r
- ;\r
- }\r
-\r
- switch ( ( format >> 2 ) & 3 )\r
- {\r
- case 1:\r
- PFR_CHECK( 2 );\r
- y_pos = PFR_NEXT_SHORT( p );\r
- break;\r
-\r
- case 2:\r
- PFR_CHECK( 1 );\r
- y_pos += PFR_NEXT_INT8( p );\r
- break;\r
-\r
- default:\r
- ;\r
- }\r
-\r
- subglyph->x_delta = x_pos;\r
- subglyph->y_delta = y_pos;\r
-\r
- /* read glyph position and size now */\r
- if ( format & PFR_SUBGLYPH_2BYTE_SIZE )\r
- {\r
- PFR_CHECK( 2 );\r
- subglyph->gps_size = PFR_NEXT_USHORT( p );\r
- }\r
- else\r
- {\r
- PFR_CHECK( 1 );\r
- subglyph->gps_size = PFR_NEXT_BYTE( p );\r
- }\r
-\r
- if ( format & PFR_SUBGLYPH_3BYTE_OFFSET )\r
- {\r
- PFR_CHECK( 3 );\r
- subglyph->gps_offset = PFR_NEXT_LONG( p );\r
- }\r
- else\r
- {\r
- PFR_CHECK( 2 );\r
- subglyph->gps_offset = PFR_NEXT_USHORT( p );\r
- }\r
-\r
- glyph->num_subs++;\r
- }\r
-\r
- Exit:\r
- return error;\r
-\r
- Failure:\r
- Too_Short:\r
- error = PFR_Err_Invalid_Table;\r
- FT_ERROR(( "pfr_glyph_load_compound: invalid glyph data\n" ));\r
- goto Exit;\r
- }\r
-\r
-\r
- static FT_Error\r
- pfr_glyph_load_rec( PFR_Glyph glyph,\r
- FT_Stream stream,\r
- FT_ULong gps_offset,\r
- FT_ULong offset,\r
- FT_ULong size )\r
- {\r
- FT_Error error;\r
- FT_Byte* p;\r
- FT_Byte* limit;\r
-\r
-\r
- if ( FT_STREAM_SEEK( gps_offset + offset ) ||\r
- FT_FRAME_ENTER( size ) )\r
- goto Exit;\r
-\r
- p = (FT_Byte*)stream->cursor;\r
- limit = p + size;\r
-\r
- if ( size > 0 && *p & PFR_GLYPH_IS_COMPOUND )\r
- {\r
- FT_Int n, old_count, count;\r
- FT_GlyphLoader loader = glyph->loader;\r
- FT_Outline* base = &loader->base.outline;\r
-\r
-\r
- old_count = glyph->num_subs;\r
-\r
- /* this is a compound glyph - load it */\r
- error = pfr_glyph_load_compound( glyph, p, limit );\r
-\r
- FT_FRAME_EXIT();\r
-\r
- if ( error )\r
- goto Exit;\r
-\r
- count = glyph->num_subs - old_count;\r
-\r
- /* now, load each individual glyph */\r
- for ( n = 0; n < count; n++ )\r
- {\r
- FT_Int i, old_points, num_points;\r
- PFR_SubGlyph subglyph;\r
-\r
-\r
- subglyph = glyph->subs + old_count + n;\r
- old_points = base->n_points;\r
-\r
- error = pfr_glyph_load_rec( glyph, stream, gps_offset,\r
- subglyph->gps_offset,\r
- subglyph->gps_size );\r
- if ( error )\r
- goto Exit;\r
-\r
- /* note that `glyph->subs' might have been re-allocated */\r
- subglyph = glyph->subs + old_count + n;\r
- num_points = base->n_points - old_points;\r
-\r
- /* translate and eventually scale the new glyph points */\r
- if ( subglyph->x_scale != 0x10000L || subglyph->y_scale != 0x10000L )\r
- {\r
- FT_Vector* vec = base->points + old_points;\r
-\r
-\r
- for ( i = 0; i < num_points; i++, vec++ )\r
- {\r
- vec->x = FT_MulFix( vec->x, subglyph->x_scale ) +\r
- subglyph->x_delta;\r
- vec->y = FT_MulFix( vec->y, subglyph->y_scale ) +\r
- subglyph->y_delta;\r
- }\r
- }\r
- else\r
- {\r
- FT_Vector* vec = loader->base.outline.points + old_points;\r
-\r
-\r
- for ( i = 0; i < num_points; i++, vec++ )\r
- {\r
- vec->x += subglyph->x_delta;\r
- vec->y += subglyph->y_delta;\r
- }\r
- }\r
-\r
- /* proceed to next sub-glyph */\r
- }\r
- }\r
- else\r
- {\r
- /* load a simple glyph */\r
- error = pfr_glyph_load_simple( glyph, p, limit );\r
-\r
- FT_FRAME_EXIT();\r
- }\r
-\r
- Exit:\r
- return error;\r
- }\r
-\r
-\r
-\r
-\r
-\r
- FT_LOCAL_DEF( FT_Error )\r
- pfr_glyph_load( PFR_Glyph glyph,\r
- FT_Stream stream,\r
- FT_ULong gps_offset,\r
- FT_ULong offset,\r
- FT_ULong size )\r
- {\r
- /* initialize glyph loader */\r
- FT_GlyphLoader_Rewind( glyph->loader );\r
-\r
- glyph->num_subs = 0;\r
-\r
- /* load the glyph, recursively when needed */\r
- return pfr_glyph_load_rec( glyph, stream, gps_offset, offset, size );\r
- }\r
-\r
-\r
-/* END */\r
+/***************************************************************************/
+/* */
+/* pfrgload.c */
+/* */
+/* FreeType PFR glyph loader (body). */
+/* */
+/* Copyright 2002, 2003, 2005, 2007 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#include "pfrgload.h"
+#include "pfrsbit.h"
+#include "pfrload.h" /* for macro definitions */
+#include FT_INTERNAL_DEBUG_H
+
+#include "pfrerror.h"
+
+#undef FT_COMPONENT
+#define FT_COMPONENT trace_pfr
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /***** *****/
+ /***** PFR GLYPH BUILDER *****/
+ /***** *****/
+ /*************************************************************************/
+ /*************************************************************************/
+
+
+ FT_LOCAL_DEF( void )
+ pfr_glyph_init( PFR_Glyph glyph,
+ FT_GlyphLoader loader )
+ {
+ FT_ZERO( glyph );
+
+ glyph->loader = loader;
+ glyph->path_begun = 0;
+
+ FT_GlyphLoader_Rewind( loader );
+ }
+
+
+ FT_LOCAL_DEF( void )
+ pfr_glyph_done( PFR_Glyph glyph )
+ {
+ FT_Memory memory = glyph->loader->memory;
+
+
+ FT_FREE( glyph->x_control );
+ glyph->y_control = NULL;
+
+ glyph->max_xy_control = 0;
+#if 0
+ glyph->num_x_control = 0;
+ glyph->num_y_control = 0;
+#endif
+
+ FT_FREE( glyph->subs );
+
+ glyph->max_subs = 0;
+ glyph->num_subs = 0;
+
+ glyph->loader = NULL;
+ glyph->path_begun = 0;
+ }
+
+
+ /* close current contour, if any */
+ static void
+ pfr_glyph_close_contour( PFR_Glyph glyph )
+ {
+ FT_GlyphLoader loader = glyph->loader;
+ FT_Outline* outline = &loader->current.outline;
+ FT_Int last, first;
+
+
+ if ( !glyph->path_begun )
+ return;
+
+ /* compute first and last point indices in current glyph outline */
+ last = outline->n_points - 1;
+ first = 0;
+ if ( outline->n_contours > 0 )
+ first = outline->contours[outline->n_contours - 1];
+
+ /* if the last point falls on the same location than the first one */
+ /* we need to delete it */
+ if ( last > first )
+ {
+ FT_Vector* p1 = outline->points + first;
+ FT_Vector* p2 = outline->points + last;
+
+
+ if ( p1->x == p2->x && p1->y == p2->y )
+ {
+ outline->n_points--;
+ last--;
+ }
+ }
+
+ /* don't add empty contours */
+ if ( last >= first )
+ outline->contours[outline->n_contours++] = (short)last;
+
+ glyph->path_begun = 0;
+ }
+
+
+ /* reset glyph to start the loading of a new glyph */
+ static void
+ pfr_glyph_start( PFR_Glyph glyph )
+ {
+ glyph->path_begun = 0;
+ }
+
+
+ static FT_Error
+ pfr_glyph_line_to( PFR_Glyph glyph,
+ FT_Vector* to )
+ {
+ FT_GlyphLoader loader = glyph->loader;
+ FT_Outline* outline = &loader->current.outline;
+ FT_Error error;
+
+
+ /* check that we have begun a new path */
+ if ( !glyph->path_begun )
+ {
+ error = PFR_Err_Invalid_Table;
+ FT_ERROR(( "pfr_glyph_line_to: invalid glyph data\n" ));
+ goto Exit;
+ }
+
+ error = FT_GLYPHLOADER_CHECK_POINTS( loader, 1, 0 );
+ if ( !error )
+ {
+ FT_UInt n = outline->n_points;
+
+
+ outline->points[n] = *to;
+ outline->tags [n] = FT_CURVE_TAG_ON;
+
+ outline->n_points++;
+ }
+
+ Exit:
+ return error;
+ }
+
+
+ static FT_Error
+ pfr_glyph_curve_to( PFR_Glyph glyph,
+ FT_Vector* control1,
+ FT_Vector* control2,
+ FT_Vector* to )
+ {
+ FT_GlyphLoader loader = glyph->loader;
+ FT_Outline* outline = &loader->current.outline;
+ FT_Error error;
+
+
+ /* check that we have begun a new path */
+ if ( !glyph->path_begun )
+ {
+ error = PFR_Err_Invalid_Table;
+ FT_ERROR(( "pfr_glyph_line_to: invalid glyph data\n" ));
+ goto Exit;
+ }
+
+ error = FT_GLYPHLOADER_CHECK_POINTS( loader, 3, 0 );
+ if ( !error )
+ {
+ FT_Vector* vec = outline->points + outline->n_points;
+ FT_Byte* tag = (FT_Byte*)outline->tags + outline->n_points;
+
+
+ vec[0] = *control1;
+ vec[1] = *control2;
+ vec[2] = *to;
+ tag[0] = FT_CURVE_TAG_CUBIC;
+ tag[1] = FT_CURVE_TAG_CUBIC;
+ tag[2] = FT_CURVE_TAG_ON;
+
+ outline->n_points = (FT_Short)( outline->n_points + 3 );
+ }
+
+ Exit:
+ return error;
+ }
+
+
+ static FT_Error
+ pfr_glyph_move_to( PFR_Glyph glyph,
+ FT_Vector* to )
+ {
+ FT_GlyphLoader loader = glyph->loader;
+ FT_Error error;
+
+
+ /* close current contour if any */
+ pfr_glyph_close_contour( glyph );
+
+ /* indicate that a new contour has started */
+ glyph->path_begun = 1;
+
+ /* check that there is space for a new contour and a new point */
+ error = FT_GLYPHLOADER_CHECK_POINTS( loader, 1, 1 );
+ if ( !error )
+ /* add new start point */
+ error = pfr_glyph_line_to( glyph, to );
+
+ return error;
+ }
+
+
+ static void
+ pfr_glyph_end( PFR_Glyph glyph )
+ {
+ /* close current contour if any */
+ pfr_glyph_close_contour( glyph );
+
+ /* merge the current glyph into the stack */
+ FT_GlyphLoader_Add( glyph->loader );
+ }
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /***** *****/
+ /***** PFR GLYPH LOADER *****/
+ /***** *****/
+ /*************************************************************************/
+ /*************************************************************************/
+
+
+ /* load a simple glyph */
+ static FT_Error
+ pfr_glyph_load_simple( PFR_Glyph glyph,
+ FT_Byte* p,
+ FT_Byte* limit )
+ {
+ FT_Error error = 0;
+ FT_Memory memory = glyph->loader->memory;
+ FT_UInt flags, x_count, y_count, i, count, mask;
+ FT_Int x;
+
+
+ PFR_CHECK( 1 );
+ flags = PFR_NEXT_BYTE( p );
+
+ /* test for composite glyphs */
+ if ( flags & PFR_GLYPH_IS_COMPOUND )
+ goto Failure;
+
+ x_count = 0;
+ y_count = 0;
+
+ if ( flags & PFR_GLYPH_1BYTE_XYCOUNT )
+ {
+ PFR_CHECK( 1 );
+ count = PFR_NEXT_BYTE( p );
+ x_count = ( count & 15 );
+ y_count = ( count >> 4 );
+ }
+ else
+ {
+ if ( flags & PFR_GLYPH_XCOUNT )
+ {
+ PFR_CHECK( 1 );
+ x_count = PFR_NEXT_BYTE( p );
+ }
+
+ if ( flags & PFR_GLYPH_YCOUNT )
+ {
+ PFR_CHECK( 1 );
+ y_count = PFR_NEXT_BYTE( p );
+ }
+ }
+
+ count = x_count + y_count;
+
+ /* re-allocate array when necessary */
+ if ( count > glyph->max_xy_control )
+ {
+ FT_UInt new_max = FT_PAD_CEIL( count, 8 );
+
+
+ if ( FT_RENEW_ARRAY( glyph->x_control,
+ glyph->max_xy_control,
+ new_max ) )
+ goto Exit;
+
+ glyph->max_xy_control = new_max;
+ }
+
+ glyph->y_control = glyph->x_control + x_count;
+
+ mask = 0;
+ x = 0;
+
+ for ( i = 0; i < count; i++ )
+ {
+ if ( ( i & 7 ) == 0 )
+ {
+ PFR_CHECK( 1 );
+ mask = PFR_NEXT_BYTE( p );
+ }
+
+ if ( mask & 1 )
+ {
+ PFR_CHECK( 2 );
+ x = PFR_NEXT_SHORT( p );
+ }
+ else
+ {
+ PFR_CHECK( 1 );
+ x += PFR_NEXT_BYTE( p );
+ }
+
+ glyph->x_control[i] = x;
+
+ mask >>= 1;
+ }
+
+ /* XXX: for now we ignore the secondary stroke and edge definitions */
+ /* since we don't want to support native PFR hinting */
+ /* */
+ if ( flags & PFR_GLYPH_EXTRA_ITEMS )
+ {
+ error = pfr_extra_items_skip( &p, limit );
+ if ( error )
+ goto Exit;
+ }
+
+ pfr_glyph_start( glyph );
+
+ /* now load a simple glyph */
+ {
+ FT_Vector pos[4];
+ FT_Vector* cur;
+
+
+ pos[0].x = pos[0].y = 0;
+ pos[3] = pos[0];
+
+ for (;;)
+ {
+ FT_UInt format, format_low, args_format = 0, args_count, n;
+
+
+ /***************************************************************/
+ /* read instruction */
+ /* */
+ PFR_CHECK( 1 );
+ format = PFR_NEXT_BYTE( p );
+ format_low = format & 15;
+
+ switch ( format >> 4 )
+ {
+ case 0: /* end glyph */
+ FT_TRACE6(( "- end glyph" ));
+ args_count = 0;
+ break;
+
+ case 1: /* general line operation */
+ FT_TRACE6(( "- general line" ));
+ goto Line1;
+
+ case 4: /* move to inside contour */
+ FT_TRACE6(( "- move to inside" ));
+ goto Line1;
+
+ case 5: /* move to outside contour */
+ FT_TRACE6(( "- move to outside" ));
+ Line1:
+ args_format = format_low;
+ args_count = 1;
+ break;
+
+ case 2: /* horizontal line to */
+ FT_TRACE6(( "- horizontal line to cx.%d", format_low ));
+ if ( format_low > x_count )
+ goto Failure;
+ pos[0].x = glyph->x_control[format_low];
+ pos[0].y = pos[3].y;
+ pos[3] = pos[0];
+ args_count = 0;
+ break;
+
+ case 3: /* vertical line to */
+ FT_TRACE6(( "- vertical line to cy.%d", format_low ));
+ if ( format_low > y_count )
+ goto Failure;
+ pos[0].x = pos[3].x;
+ pos[0].y = glyph->y_control[format_low];
+ pos[3] = pos[0];
+ args_count = 0;
+ break;
+
+ case 6: /* horizontal to vertical curve */
+ FT_TRACE6(( "- hv curve " ));
+ args_format = 0xB8E;
+ args_count = 3;
+ break;
+
+ case 7: /* vertical to horizontal curve */
+ FT_TRACE6(( "- vh curve" ));
+ args_format = 0xE2B;
+ args_count = 3;
+ break;
+
+ default: /* general curve to */
+ FT_TRACE6(( "- general curve" ));
+ args_count = 4;
+ args_format = format_low;
+ }
+
+ /***********************************************************/
+ /* now read arguments */
+ /* */
+ cur = pos;
+ for ( n = 0; n < args_count; n++ )
+ {
+ FT_UInt idx;
+ FT_Int delta;
+
+
+ /* read the X argument */
+ switch ( args_format & 3 )
+ {
+ case 0: /* 8-bit index */
+ PFR_CHECK( 1 );
+ idx = PFR_NEXT_BYTE( p );
+ if ( idx > x_count )
+ goto Failure;
+ cur->x = glyph->x_control[idx];
+ FT_TRACE7(( " cx#%d", idx ));
+ break;
+
+ case 1: /* 16-bit value */
+ PFR_CHECK( 2 );
+ cur->x = PFR_NEXT_SHORT( p );
+ FT_TRACE7(( " x.%d", cur->x ));
+ break;
+
+ case 2: /* 8-bit delta */
+ PFR_CHECK( 1 );
+ delta = PFR_NEXT_INT8( p );
+ cur->x = pos[3].x + delta;
+ FT_TRACE7(( " dx.%d", delta ));
+ break;
+
+ default:
+ FT_TRACE7(( " |" ));
+ cur->x = pos[3].x;
+ }
+
+ /* read the Y argument */
+ switch ( ( args_format >> 2 ) & 3 )
+ {
+ case 0: /* 8-bit index */
+ PFR_CHECK( 1 );
+ idx = PFR_NEXT_BYTE( p );
+ if ( idx > y_count )
+ goto Failure;
+ cur->y = glyph->y_control[idx];
+ FT_TRACE7(( " cy#%d", idx ));
+ break;
+
+ case 1: /* 16-bit absolute value */
+ PFR_CHECK( 2 );
+ cur->y = PFR_NEXT_SHORT( p );
+ FT_TRACE7(( " y.%d", cur->y ));
+ break;
+
+ case 2: /* 8-bit delta */
+ PFR_CHECK( 1 );
+ delta = PFR_NEXT_INT8( p );
+ cur->y = pos[3].y + delta;
+ FT_TRACE7(( " dy.%d", delta ));
+ break;
+
+ default:
+ FT_TRACE7(( " -" ));
+ cur->y = pos[3].y;
+ }
+
+ /* read the additional format flag for the general curve */
+ if ( n == 0 && args_count == 4 )
+ {
+ PFR_CHECK( 1 );
+ args_format = PFR_NEXT_BYTE( p );
+ args_count--;
+ }
+ else
+ args_format >>= 4;
+
+ /* save the previous point */
+ pos[3] = cur[0];
+ cur++;
+ }
+
+ FT_TRACE7(( "\n" ));
+
+ /***********************************************************/
+ /* finally, execute instruction */
+ /* */
+ switch ( format >> 4 )
+ {
+ case 0: /* end glyph => EXIT */
+ pfr_glyph_end( glyph );
+ goto Exit;
+
+ case 1: /* line operations */
+ case 2:
+ case 3:
+ error = pfr_glyph_line_to( glyph, pos );
+ goto Test_Error;
+
+ case 4: /* move to inside contour */
+ case 5: /* move to outside contour */
+ error = pfr_glyph_move_to( glyph, pos );
+ goto Test_Error;
+
+ default: /* curve operations */
+ error = pfr_glyph_curve_to( glyph, pos, pos + 1, pos + 2 );
+
+ Test_Error: /* test error condition */
+ if ( error )
+ goto Exit;
+ }
+ } /* for (;;) */
+ }
+
+ Exit:
+ return error;
+
+ Failure:
+ Too_Short:
+ error = PFR_Err_Invalid_Table;
+ FT_ERROR(( "pfr_glyph_load_simple: invalid glyph data\n" ));
+ goto Exit;
+ }
+
+
+ /* load a composite/compound glyph */
+ static FT_Error
+ pfr_glyph_load_compound( PFR_Glyph glyph,
+ FT_Byte* p,
+ FT_Byte* limit )
+ {
+ FT_Error error = 0;
+ FT_GlyphLoader loader = glyph->loader;
+ FT_Memory memory = loader->memory;
+ PFR_SubGlyph subglyph;
+ FT_UInt flags, i, count, org_count;
+ FT_Int x_pos, y_pos;
+
+
+ PFR_CHECK( 1 );
+ flags = PFR_NEXT_BYTE( p );
+
+ /* test for composite glyphs */
+ if ( !( flags & PFR_GLYPH_IS_COMPOUND ) )
+ goto Failure;
+
+ count = flags & 0x3F;
+
+ /* ignore extra items when present */
+ /* */
+ if ( flags & PFR_GLYPH_EXTRA_ITEMS )
+ {
+ error = pfr_extra_items_skip( &p, limit );
+ if (error) goto Exit;
+ }
+
+ /* we can't rely on the FT_GlyphLoader to load sub-glyphs, because */
+ /* the PFR format is dumb, using direct file offsets to point to the */
+ /* sub-glyphs (instead of glyph indices). Sigh. */
+ /* */
+ /* For now, we load the list of sub-glyphs into a different array */
+ /* but this will prevent us from using the auto-hinter at its best */
+ /* quality. */
+ /* */
+ org_count = glyph->num_subs;
+
+ if ( org_count + count > glyph->max_subs )
+ {
+ FT_UInt new_max = ( org_count + count + 3 ) & -4;
+
+
+ if ( FT_RENEW_ARRAY( glyph->subs, glyph->max_subs, new_max ) )
+ goto Exit;
+
+ glyph->max_subs = new_max;
+ }
+
+ subglyph = glyph->subs + org_count;
+
+ for ( i = 0; i < count; i++, subglyph++ )
+ {
+ FT_UInt format;
+
+
+ x_pos = 0;
+ y_pos = 0;
+
+ PFR_CHECK( 1 );
+ format = PFR_NEXT_BYTE( p );
+
+ /* read scale when available */
+ subglyph->x_scale = 0x10000L;
+ if ( format & PFR_SUBGLYPH_XSCALE )
+ {
+ PFR_CHECK( 2 );
+ subglyph->x_scale = PFR_NEXT_SHORT( p ) << 4;
+ }
+
+ subglyph->y_scale = 0x10000L;
+ if ( format & PFR_SUBGLYPH_YSCALE )
+ {
+ PFR_CHECK( 2 );
+ subglyph->y_scale = PFR_NEXT_SHORT( p ) << 4;
+ }
+
+ /* read offset */
+ switch ( format & 3 )
+ {
+ case 1:
+ PFR_CHECK( 2 );
+ x_pos = PFR_NEXT_SHORT( p );
+ break;
+
+ case 2:
+ PFR_CHECK( 1 );
+ x_pos += PFR_NEXT_INT8( p );
+ break;
+
+ default:
+ ;
+ }
+
+ switch ( ( format >> 2 ) & 3 )
+ {
+ case 1:
+ PFR_CHECK( 2 );
+ y_pos = PFR_NEXT_SHORT( p );
+ break;
+
+ case 2:
+ PFR_CHECK( 1 );
+ y_pos += PFR_NEXT_INT8( p );
+ break;
+
+ default:
+ ;
+ }
+
+ subglyph->x_delta = x_pos;
+ subglyph->y_delta = y_pos;
+
+ /* read glyph position and size now */
+ if ( format & PFR_SUBGLYPH_2BYTE_SIZE )
+ {
+ PFR_CHECK( 2 );
+ subglyph->gps_size = PFR_NEXT_USHORT( p );
+ }
+ else
+ {
+ PFR_CHECK( 1 );
+ subglyph->gps_size = PFR_NEXT_BYTE( p );
+ }
+
+ if ( format & PFR_SUBGLYPH_3BYTE_OFFSET )
+ {
+ PFR_CHECK( 3 );
+ subglyph->gps_offset = PFR_NEXT_LONG( p );
+ }
+ else
+ {
+ PFR_CHECK( 2 );
+ subglyph->gps_offset = PFR_NEXT_USHORT( p );
+ }
+
+ glyph->num_subs++;
+ }
+
+ Exit:
+ return error;
+
+ Failure:
+ Too_Short:
+ error = PFR_Err_Invalid_Table;
+ FT_ERROR(( "pfr_glyph_load_compound: invalid glyph data\n" ));
+ goto Exit;
+ }
+
+
+ static FT_Error
+ pfr_glyph_load_rec( PFR_Glyph glyph,
+ FT_Stream stream,
+ FT_ULong gps_offset,
+ FT_ULong offset,
+ FT_ULong size )
+ {
+ FT_Error error;
+ FT_Byte* p;
+ FT_Byte* limit;
+
+
+ if ( FT_STREAM_SEEK( gps_offset + offset ) ||
+ FT_FRAME_ENTER( size ) )
+ goto Exit;
+
+ p = (FT_Byte*)stream->cursor;
+ limit = p + size;
+
+ if ( size > 0 && *p & PFR_GLYPH_IS_COMPOUND )
+ {
+ FT_Int n, old_count, count;
+ FT_GlyphLoader loader = glyph->loader;
+ FT_Outline* base = &loader->base.outline;
+
+
+ old_count = glyph->num_subs;
+
+ /* this is a compound glyph - load it */
+ error = pfr_glyph_load_compound( glyph, p, limit );
+
+ FT_FRAME_EXIT();
+
+ if ( error )
+ goto Exit;
+
+ count = glyph->num_subs - old_count;
+
+ /* now, load each individual glyph */
+ for ( n = 0; n < count; n++ )
+ {
+ FT_Int i, old_points, num_points;
+ PFR_SubGlyph subglyph;
+
+
+ subglyph = glyph->subs + old_count + n;
+ old_points = base->n_points;
+
+ error = pfr_glyph_load_rec( glyph, stream, gps_offset,
+ subglyph->gps_offset,
+ subglyph->gps_size );
+ if ( error )
+ goto Exit;
+
+ /* note that `glyph->subs' might have been re-allocated */
+ subglyph = glyph->subs + old_count + n;
+ num_points = base->n_points - old_points;
+
+ /* translate and eventually scale the new glyph points */
+ if ( subglyph->x_scale != 0x10000L || subglyph->y_scale != 0x10000L )
+ {
+ FT_Vector* vec = base->points + old_points;
+
+
+ for ( i = 0; i < num_points; i++, vec++ )
+ {
+ vec->x = FT_MulFix( vec->x, subglyph->x_scale ) +
+ subglyph->x_delta;
+ vec->y = FT_MulFix( vec->y, subglyph->y_scale ) +
+ subglyph->y_delta;
+ }
+ }
+ else
+ {
+ FT_Vector* vec = loader->base.outline.points + old_points;
+
+
+ for ( i = 0; i < num_points; i++, vec++ )
+ {
+ vec->x += subglyph->x_delta;
+ vec->y += subglyph->y_delta;
+ }
+ }
+
+ /* proceed to next sub-glyph */
+ }
+ }
+ else
+ {
+ /* load a simple glyph */
+ error = pfr_glyph_load_simple( glyph, p, limit );
+
+ FT_FRAME_EXIT();
+ }
+
+ Exit:
+ return error;
+ }
+
+
+
+
+
+ FT_LOCAL_DEF( FT_Error )
+ pfr_glyph_load( PFR_Glyph glyph,
+ FT_Stream stream,
+ FT_ULong gps_offset,
+ FT_ULong offset,
+ FT_ULong size )
+ {
+ /* initialize glyph loader */
+ FT_GlyphLoader_Rewind( glyph->loader );
+
+ glyph->num_subs = 0;
+
+ /* load the glyph, recursively when needed */
+ return pfr_glyph_load_rec( glyph, stream, gps_offset, offset, size );
+ }
+
+
+/* END */