disabling the discovery of SDL13+ on desktop. SDL13 has become SDL2 with a completely different ABI and will require a new FindSDL2 module for Cmake to be found; for current sdl development installations, hedgewars will either use the compatibility layer (present in sdl1.3 but not in sdl2) or just fail to build (in case sdl2 is installed but sdl1.2.* is not). whew
/***************************************************************************/
/* */
/* pfrgload.c */
/* */
/* FreeType PFR glyph loader (body). */
/* */
/* Copyright 2002, 2003, 2005, 2007, 2010 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 = PFR_Err_Ok;
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 = PFR_Err_Ok;
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 ) & (FT_UInt)-4;
/* we arbitrarily limit the number of subglyphs */
/* to avoid endless recursion */
if ( new_max > 64 )
{
error = PFR_Err_Invalid_Table;
FT_ERROR(( "pfr_glyph_load_compound:"
" too many compound glyphs components\n" ));
goto Exit;
}
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;
FT_TRACE4(( "compound glyph with %d elements (offset %lu):\n",
count, offset ));
/* now, load each individual glyph */
for ( n = 0; n < count; n++ )
{
FT_Int i, old_points, num_points;
PFR_SubGlyph subglyph;
FT_TRACE4(( "subglyph %d:\n", n ));
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 )
break;
/* 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 */
}
FT_TRACE4(( "end compound glyph with %d elements\n", count ));
}
else
{
FT_TRACE4(( "simple glyph (offset %lu)\n", offset ));
/* 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 */