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
/***************************************************************************/
/* */
/* pfrobjs.c */
/* */
/* FreeType PFR object methods (body). */
/* */
/* Copyright 2002, 2003, 2004, 2005, 2006, 2007, 2008, 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 "pfrobjs.h"
#include "pfrload.h"
#include "pfrgload.h"
#include "pfrcmap.h"
#include "pfrsbit.h"
#include FT_OUTLINE_H
#include FT_INTERNAL_DEBUG_H
#include FT_TRUETYPE_IDS_H
#include "pfrerror.h"
#undef FT_COMPONENT
#define FT_COMPONENT trace_pfr
/*************************************************************************/
/*************************************************************************/
/***** *****/
/***** FACE OBJECT METHODS *****/
/***** *****/
/*************************************************************************/
/*************************************************************************/
FT_LOCAL_DEF( void )
pfr_face_done( FT_Face pfrface ) /* PFR_Face */
{
PFR_Face face = (PFR_Face)pfrface;
FT_Memory memory;
if ( !face )
return;
memory = pfrface->driver->root.memory;
/* we don't want dangling pointers */
pfrface->family_name = NULL;
pfrface->style_name = NULL;
/* finalize the physical font record */
pfr_phy_font_done( &face->phy_font, FT_FACE_MEMORY( face ) );
/* no need to finalize the logical font or the header */
FT_FREE( pfrface->available_sizes );
}
FT_LOCAL_DEF( FT_Error )
pfr_face_init( FT_Stream stream,
FT_Face pfrface,
FT_Int face_index,
FT_Int num_params,
FT_Parameter* params )
{
PFR_Face face = (PFR_Face)pfrface;
FT_Error error;
FT_UNUSED( num_params );
FT_UNUSED( params );
/* load the header and check it */
error = pfr_header_load( &face->header, stream );
if ( error )
goto Exit;
if ( !pfr_header_check( &face->header ) )
{
FT_TRACE4(( "pfr_face_init: not a valid PFR font\n" ));
error = PFR_Err_Unknown_File_Format;
goto Exit;
}
/* check face index */
{
FT_UInt num_faces;
error = pfr_log_font_count( stream,
face->header.log_dir_offset,
&num_faces );
if ( error )
goto Exit;
pfrface->num_faces = num_faces;
}
if ( face_index < 0 )
goto Exit;
if ( face_index >= pfrface->num_faces )
{
FT_ERROR(( "pfr_face_init: invalid face index\n" ));
error = PFR_Err_Invalid_Argument;
goto Exit;
}
/* load the face */
error = pfr_log_font_load(
&face->log_font, stream, face_index,
face->header.log_dir_offset,
FT_BOOL( face->header.phy_font_max_size_high != 0 ) );
if ( error )
goto Exit;
/* now load the physical font descriptor */
error = pfr_phy_font_load( &face->phy_font, stream,
face->log_font.phys_offset,
face->log_font.phys_size );
if ( error )
goto Exit;
/* now set up all root face fields */
{
PFR_PhyFont phy_font = &face->phy_font;
pfrface->face_index = face_index;
pfrface->num_glyphs = phy_font->num_chars + 1;
pfrface->face_flags = FT_FACE_FLAG_SCALABLE;
/* if all characters point to the same gps_offset 0, we */
/* assume that the font only contains bitmaps */
{
FT_UInt nn;
for ( nn = 0; nn < phy_font->num_chars; nn++ )
if ( phy_font->chars[nn].gps_offset != 0 )
break;
if ( nn == phy_font->num_chars )
{
if ( phy_font->num_strikes > 0 )
pfrface->face_flags = 0; /* not scalable */
else
{
FT_ERROR(( "pfr_face_init: font doesn't contain glyphs\n" ));
error = PFR_Err_Invalid_File_Format;
goto Exit;
}
}
}
if ( (phy_font->flags & PFR_PHY_PROPORTIONAL) == 0 )
pfrface->face_flags |= FT_FACE_FLAG_FIXED_WIDTH;
if ( phy_font->flags & PFR_PHY_VERTICAL )
pfrface->face_flags |= FT_FACE_FLAG_VERTICAL;
else
pfrface->face_flags |= FT_FACE_FLAG_HORIZONTAL;
if ( phy_font->num_strikes > 0 )
pfrface->face_flags |= FT_FACE_FLAG_FIXED_SIZES;
if ( phy_font->num_kern_pairs > 0 )
pfrface->face_flags |= FT_FACE_FLAG_KERNING;
/* If no family name was found in the "undocumented" auxiliary
* data, use the font ID instead. This sucks but is better than
* nothing.
*/
pfrface->family_name = phy_font->family_name;
if ( pfrface->family_name == NULL )
pfrface->family_name = phy_font->font_id;
/* note that the style name can be NULL in certain PFR fonts,
* probably meaning "Regular"
*/
pfrface->style_name = phy_font->style_name;
pfrface->num_fixed_sizes = 0;
pfrface->available_sizes = 0;
pfrface->bbox = phy_font->bbox;
pfrface->units_per_EM = (FT_UShort)phy_font->outline_resolution;
pfrface->ascender = (FT_Short) phy_font->bbox.yMax;
pfrface->descender = (FT_Short) phy_font->bbox.yMin;
pfrface->height = (FT_Short)( ( pfrface->units_per_EM * 12 ) / 10 );
if ( pfrface->height < pfrface->ascender - pfrface->descender )
pfrface->height = (FT_Short)(pfrface->ascender - pfrface->descender);
if ( phy_font->num_strikes > 0 )
{
FT_UInt n, count = phy_font->num_strikes;
FT_Bitmap_Size* size;
PFR_Strike strike;
FT_Memory memory = pfrface->stream->memory;
if ( FT_NEW_ARRAY( pfrface->available_sizes, count ) )
goto Exit;
size = pfrface->available_sizes;
strike = phy_font->strikes;
for ( n = 0; n < count; n++, size++, strike++ )
{
size->height = (FT_UShort)strike->y_ppm;
size->width = (FT_UShort)strike->x_ppm;
size->size = strike->y_ppm << 6;
size->x_ppem = strike->x_ppm << 6;
size->y_ppem = strike->y_ppm << 6;
}
pfrface->num_fixed_sizes = count;
}
/* now compute maximum advance width */
if ( ( phy_font->flags & PFR_PHY_PROPORTIONAL ) == 0 )
pfrface->max_advance_width = (FT_Short)phy_font->standard_advance;
else
{
FT_Int max = 0;
FT_UInt count = phy_font->num_chars;
PFR_Char gchar = phy_font->chars;
for ( ; count > 0; count--, gchar++ )
{
if ( max < gchar->advance )
max = gchar->advance;
}
pfrface->max_advance_width = (FT_Short)max;
}
pfrface->max_advance_height = pfrface->height;
pfrface->underline_position = (FT_Short)( -pfrface->units_per_EM / 10 );
pfrface->underline_thickness = (FT_Short)( pfrface->units_per_EM / 30 );
/* create charmap */
{
FT_CharMapRec charmap;
charmap.face = pfrface;
charmap.platform_id = TT_PLATFORM_MICROSOFT;
charmap.encoding_id = TT_MS_ID_UNICODE_CS;
charmap.encoding = FT_ENCODING_UNICODE;
error = FT_CMap_New( &pfr_cmap_class_rec, NULL, &charmap, NULL );
#if 0
/* Select default charmap */
if ( pfrface->num_charmaps )
pfrface->charmap = pfrface->charmaps[0];
#endif
}
/* check whether we've loaded any kerning pairs */
if ( phy_font->num_kern_pairs )
pfrface->face_flags |= FT_FACE_FLAG_KERNING;
}
Exit:
return error;
}
/*************************************************************************/
/*************************************************************************/
/***** *****/
/***** SLOT OBJECT METHOD *****/
/***** *****/
/*************************************************************************/
/*************************************************************************/
FT_LOCAL_DEF( FT_Error )
pfr_slot_init( FT_GlyphSlot pfrslot ) /* PFR_Slot */
{
PFR_Slot slot = (PFR_Slot)pfrslot;
FT_GlyphLoader loader = pfrslot->internal->loader;
pfr_glyph_init( &slot->glyph, loader );
return 0;
}
FT_LOCAL_DEF( void )
pfr_slot_done( FT_GlyphSlot pfrslot ) /* PFR_Slot */
{
PFR_Slot slot = (PFR_Slot)pfrslot;
pfr_glyph_done( &slot->glyph );
}
FT_LOCAL_DEF( FT_Error )
pfr_slot_load( FT_GlyphSlot pfrslot, /* PFR_Slot */
FT_Size pfrsize, /* PFR_Size */
FT_UInt gindex,
FT_Int32 load_flags )
{
PFR_Slot slot = (PFR_Slot)pfrslot;
PFR_Size size = (PFR_Size)pfrsize;
FT_Error error;
PFR_Face face = (PFR_Face)pfrslot->face;
PFR_Char gchar;
FT_Outline* outline = &pfrslot->outline;
FT_ULong gps_offset;
if ( gindex > 0 )
gindex--;
if ( !face || gindex >= face->phy_font.num_chars )
{
error = PFR_Err_Invalid_Argument;
goto Exit;
}
/* try to load an embedded bitmap */
if ( ( load_flags & ( FT_LOAD_NO_SCALE | FT_LOAD_NO_BITMAP ) ) == 0 )
{
error = pfr_slot_load_bitmap( slot, size, gindex );
if ( error == 0 )
goto Exit;
}
if ( load_flags & FT_LOAD_SBITS_ONLY )
{
error = PFR_Err_Invalid_Argument;
goto Exit;
}
gchar = face->phy_font.chars + gindex;
pfrslot->format = FT_GLYPH_FORMAT_OUTLINE;
outline->n_points = 0;
outline->n_contours = 0;
gps_offset = face->header.gps_section_offset;
/* load the glyph outline (FT_LOAD_NO_RECURSE isn't supported) */
error = pfr_glyph_load( &slot->glyph, face->root.stream,
gps_offset, gchar->gps_offset, gchar->gps_size );
if ( !error )
{
FT_BBox cbox;
FT_Glyph_Metrics* metrics = &pfrslot->metrics;
FT_Pos advance;
FT_Int em_metrics, em_outline;
FT_Bool scaling;
scaling = FT_BOOL( ( load_flags & FT_LOAD_NO_SCALE ) == 0 );
/* copy outline data */
*outline = slot->glyph.loader->base.outline;
outline->flags &= ~FT_OUTLINE_OWNER;
outline->flags |= FT_OUTLINE_REVERSE_FILL;
if ( size && pfrsize->metrics.y_ppem < 24 )
outline->flags |= FT_OUTLINE_HIGH_PRECISION;
/* compute the advance vector */
metrics->horiAdvance = 0;
metrics->vertAdvance = 0;
advance = gchar->advance;
em_metrics = face->phy_font.metrics_resolution;
em_outline = face->phy_font.outline_resolution;
if ( em_metrics != em_outline )
advance = FT_MulDiv( advance, em_outline, em_metrics );
if ( face->phy_font.flags & PFR_PHY_VERTICAL )
metrics->vertAdvance = advance;
else
metrics->horiAdvance = advance;
pfrslot->linearHoriAdvance = metrics->horiAdvance;
pfrslot->linearVertAdvance = metrics->vertAdvance;
/* make-up vertical metrics(?) */
metrics->vertBearingX = 0;
metrics->vertBearingY = 0;
#if 0 /* some fonts seem to be broken here! */
/* Apply the font matrix, if any. */
/* TODO: Test existing fonts with unusual matrix */
/* whether we have to adjust Units per EM. */
{
FT_Matrix font_matrix;
font_matrix.xx = face->log_font.matrix[0] << 8;
font_matrix.yx = face->log_font.matrix[1] << 8;
font_matrix.xy = face->log_font.matrix[2] << 8;
font_matrix.yy = face->log_font.matrix[3] << 8;
FT_Outline_Transform( outline, &font_matrix );
}
#endif
/* scale when needed */
if ( scaling )
{
FT_Int n;
FT_Fixed x_scale = pfrsize->metrics.x_scale;
FT_Fixed y_scale = pfrsize->metrics.y_scale;
FT_Vector* vec = outline->points;
/* scale outline points */
for ( n = 0; n < outline->n_points; n++, vec++ )
{
vec->x = FT_MulFix( vec->x, x_scale );
vec->y = FT_MulFix( vec->y, y_scale );
}
/* scale the advance */
metrics->horiAdvance = FT_MulFix( metrics->horiAdvance, x_scale );
metrics->vertAdvance = FT_MulFix( metrics->vertAdvance, y_scale );
}
/* compute the rest of the metrics */
FT_Outline_Get_CBox( outline, &cbox );
metrics->width = cbox.xMax - cbox.xMin;
metrics->height = cbox.yMax - cbox.yMin;
metrics->horiBearingX = cbox.xMin;
metrics->horiBearingY = cbox.yMax - metrics->height;
}
Exit:
return error;
}
/*************************************************************************/
/*************************************************************************/
/***** *****/
/***** KERNING METHOD *****/
/***** *****/
/*************************************************************************/
/*************************************************************************/
FT_LOCAL_DEF( FT_Error )
pfr_face_get_kerning( FT_Face pfrface, /* PFR_Face */
FT_UInt glyph1,
FT_UInt glyph2,
FT_Vector* kerning )
{
PFR_Face face = (PFR_Face)pfrface;
FT_Error error = PFR_Err_Ok;
PFR_PhyFont phy_font = &face->phy_font;
FT_UInt32 code1, code2, pair;
kerning->x = 0;
kerning->y = 0;
if ( glyph1 > 0 )
glyph1--;
if ( glyph2 > 0 )
glyph2--;
/* convert glyph indices to character codes */
if ( glyph1 > phy_font->num_chars ||
glyph2 > phy_font->num_chars )
goto Exit;
code1 = phy_font->chars[glyph1].char_code;
code2 = phy_font->chars[glyph2].char_code;
pair = PFR_KERN_INDEX( code1, code2 );
/* now search the list of kerning items */
{
PFR_KernItem item = phy_font->kern_items;
FT_Stream stream = pfrface->stream;
for ( ; item; item = item->next )
{
if ( pair >= item->pair1 && pair <= item->pair2 )
goto FoundPair;
}
goto Exit;
FoundPair: /* we found an item, now parse it and find the value if any */
if ( FT_STREAM_SEEK( item->offset ) ||
FT_FRAME_ENTER( item->pair_count * item->pair_size ) )
goto Exit;
{
FT_UInt count = item->pair_count;
FT_UInt size = item->pair_size;
FT_UInt power = (FT_UInt)ft_highpow2( (FT_UInt32)count );
FT_UInt probe = power * size;
FT_UInt extra = count - power;
FT_Byte* base = stream->cursor;
FT_Bool twobytes = FT_BOOL( item->flags & 1 );
FT_Bool twobyte_adj = FT_BOOL( item->flags & 2 );
FT_Byte* p;
FT_UInt32 cpair;
if ( extra > 0 )
{
p = base + extra * size;
if ( twobytes )
cpair = FT_NEXT_ULONG( p );
else
cpair = PFR_NEXT_KPAIR( p );
if ( cpair == pair )
goto Found;
if ( cpair < pair )
{
if ( twobyte_adj )
p += 2;
else
p++;
base = p;
}
}
while ( probe > size )
{
probe >>= 1;
p = base + probe;
if ( twobytes )
cpair = FT_NEXT_ULONG( p );
else
cpair = PFR_NEXT_KPAIR( p );
if ( cpair == pair )
goto Found;
if ( cpair < pair )
base += probe;
}
p = base;
if ( twobytes )
cpair = FT_NEXT_ULONG( p );
else
cpair = PFR_NEXT_KPAIR( p );
if ( cpair == pair )
{
FT_Int value;
Found:
if ( twobyte_adj )
value = FT_PEEK_SHORT( p );
else
value = p[0];
kerning->x = item->base_adj + value;
}
}
FT_FRAME_EXIT();
}
Exit:
return error;
}
/* END */