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
/***************************************************************************/
/* */
/* pfrsbit.c */
/* */
/* FreeType PFR bitmap loader (body). */
/* */
/* Copyright 2002, 2003, 2006, 2009, 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 "pfrsbit.h"
#include "pfrload.h"
#include FT_INTERNAL_DEBUG_H
#include FT_INTERNAL_STREAM_H
#include "pfrerror.h"
#undef FT_COMPONENT
#define FT_COMPONENT trace_pfr
/*************************************************************************/
/*************************************************************************/
/***** *****/
/***** PFR BIT WRITER *****/
/***** *****/
/*************************************************************************/
/*************************************************************************/
typedef struct PFR_BitWriter_
{
FT_Byte* line; /* current line start */
FT_Int pitch; /* line size in bytes */
FT_Int width; /* width in pixels/bits */
FT_Int rows; /* number of remaining rows to scan */
FT_Int total; /* total number of bits to draw */
} PFR_BitWriterRec, *PFR_BitWriter;
static void
pfr_bitwriter_init( PFR_BitWriter writer,
FT_Bitmap* target,
FT_Bool decreasing )
{
writer->line = target->buffer;
writer->pitch = target->pitch;
writer->width = target->width;
writer->rows = target->rows;
writer->total = writer->width * writer->rows;
if ( !decreasing )
{
writer->line += writer->pitch * ( target->rows-1 );
writer->pitch = -writer->pitch;
}
}
static void
pfr_bitwriter_decode_bytes( PFR_BitWriter writer,
FT_Byte* p,
FT_Byte* limit )
{
FT_Int n, reload;
FT_Int left = writer->width;
FT_Byte* cur = writer->line;
FT_UInt mask = 0x80;
FT_UInt val = 0;
FT_UInt c = 0;
n = (FT_Int)( limit - p ) * 8;
if ( n > writer->total )
n = writer->total;
reload = n & 7;
for ( ; n > 0; n-- )
{
if ( ( n & 7 ) == reload )
val = *p++;
if ( val & 0x80 )
c |= mask;
val <<= 1;
mask >>= 1;
if ( --left <= 0 )
{
cur[0] = (FT_Byte)c;
left = writer->width;
mask = 0x80;
writer->line += writer->pitch;
cur = writer->line;
c = 0;
}
else if ( mask == 0 )
{
cur[0] = (FT_Byte)c;
mask = 0x80;
c = 0;
cur ++;
}
}
if ( mask != 0x80 )
cur[0] = (FT_Byte)c;
}
static void
pfr_bitwriter_decode_rle1( PFR_BitWriter writer,
FT_Byte* p,
FT_Byte* limit )
{
FT_Int n, phase, count, counts[2], reload;
FT_Int left = writer->width;
FT_Byte* cur = writer->line;
FT_UInt mask = 0x80;
FT_UInt c = 0;
n = writer->total;
phase = 1;
counts[0] = 0;
counts[1] = 0;
count = 0;
reload = 1;
for ( ; n > 0; n-- )
{
if ( reload )
{
do
{
if ( phase )
{
FT_Int v;
if ( p >= limit )
break;
v = *p++;
counts[0] = v >> 4;
counts[1] = v & 15;
phase = 0;
count = counts[0];
}
else
{
phase = 1;
count = counts[1];
}
} while ( count == 0 );
}
if ( phase )
c |= mask;
mask >>= 1;
if ( --left <= 0 )
{
cur[0] = (FT_Byte) c;
left = writer->width;
mask = 0x80;
writer->line += writer->pitch;
cur = writer->line;
c = 0;
}
else if ( mask == 0 )
{
cur[0] = (FT_Byte)c;
mask = 0x80;
c = 0;
cur ++;
}
reload = ( --count <= 0 );
}
if ( mask != 0x80 )
cur[0] = (FT_Byte) c;
}
static void
pfr_bitwriter_decode_rle2( PFR_BitWriter writer,
FT_Byte* p,
FT_Byte* limit )
{
FT_Int n, phase, count, reload;
FT_Int left = writer->width;
FT_Byte* cur = writer->line;
FT_UInt mask = 0x80;
FT_UInt c = 0;
n = writer->total;
phase = 1;
count = 0;
reload = 1;
for ( ; n > 0; n-- )
{
if ( reload )
{
do
{
if ( p >= limit )
break;
count = *p++;
phase = phase ^ 1;
} while ( count == 0 );
}
if ( phase )
c |= mask;
mask >>= 1;
if ( --left <= 0 )
{
cur[0] = (FT_Byte) c;
c = 0;
mask = 0x80;
left = writer->width;
writer->line += writer->pitch;
cur = writer->line;
}
else if ( mask == 0 )
{
cur[0] = (FT_Byte)c;
c = 0;
mask = 0x80;
cur ++;
}
reload = ( --count <= 0 );
}
if ( mask != 0x80 )
cur[0] = (FT_Byte) c;
}
/*************************************************************************/
/*************************************************************************/
/***** *****/
/***** BITMAP DATA DECODING *****/
/***** *****/
/*************************************************************************/
/*************************************************************************/
static void
pfr_lookup_bitmap_data( FT_Byte* base,
FT_Byte* limit,
FT_UInt count,
FT_UInt flags,
FT_UInt char_code,
FT_ULong* found_offset,
FT_ULong* found_size )
{
FT_UInt left, right, char_len;
FT_Bool two = FT_BOOL( flags & 1 );
FT_Byte* buff;
char_len = 4;
if ( two ) char_len += 1;
if ( flags & 2 ) char_len += 1;
if ( flags & 4 ) char_len += 1;
left = 0;
right = count;
while ( left < right )
{
FT_UInt middle, code;
middle = ( left + right ) >> 1;
buff = base + middle * char_len;
/* check that we are not outside of the table -- */
/* this is possible with broken fonts... */
if ( buff + char_len > limit )
goto Fail;
if ( two )
code = PFR_NEXT_USHORT( buff );
else
code = PFR_NEXT_BYTE( buff );
if ( code == char_code )
goto Found_It;
if ( code < char_code )
left = middle;
else
right = middle;
}
Fail:
/* Not found */
*found_size = 0;
*found_offset = 0;
return;
Found_It:
if ( flags & 2 )
*found_size = PFR_NEXT_USHORT( buff );
else
*found_size = PFR_NEXT_BYTE( buff );
if ( flags & 4 )
*found_offset = PFR_NEXT_ULONG( buff );
else
*found_offset = PFR_NEXT_USHORT( buff );
}
/* load bitmap metrics. "*padvance" must be set to the default value */
/* before calling this function... */
/* */
static FT_Error
pfr_load_bitmap_metrics( FT_Byte** pdata,
FT_Byte* limit,
FT_Long scaled_advance,
FT_Long *axpos,
FT_Long *aypos,
FT_UInt *axsize,
FT_UInt *aysize,
FT_Long *aadvance,
FT_UInt *aformat )
{
FT_Error error = PFR_Err_Ok;
FT_Byte flags;
FT_Char b;
FT_Byte* p = *pdata;
FT_Long xpos, ypos, advance;
FT_UInt xsize, ysize;
PFR_CHECK( 1 );
flags = PFR_NEXT_BYTE( p );
xpos = 0;
ypos = 0;
xsize = 0;
ysize = 0;
advance = 0;
switch ( flags & 3 )
{
case 0:
PFR_CHECK( 1 );
b = PFR_NEXT_INT8( p );
xpos = b >> 4;
ypos = ( (FT_Char)( b << 4 ) ) >> 4;
break;
case 1:
PFR_CHECK( 2 );
xpos = PFR_NEXT_INT8( p );
ypos = PFR_NEXT_INT8( p );
break;
case 2:
PFR_CHECK( 4 );
xpos = PFR_NEXT_SHORT( p );
ypos = PFR_NEXT_SHORT( p );
break;
case 3:
PFR_CHECK( 6 );
xpos = PFR_NEXT_LONG( p );
ypos = PFR_NEXT_LONG( p );
break;
default:
;
}
flags >>= 2;
switch ( flags & 3 )
{
case 0:
/* blank image */
xsize = 0;
ysize = 0;
break;
case 1:
PFR_CHECK( 1 );
b = PFR_NEXT_BYTE( p );
xsize = ( b >> 4 ) & 0xF;
ysize = b & 0xF;
break;
case 2:
PFR_CHECK( 2 );
xsize = PFR_NEXT_BYTE( p );
ysize = PFR_NEXT_BYTE( p );
break;
case 3:
PFR_CHECK( 4 );
xsize = PFR_NEXT_USHORT( p );
ysize = PFR_NEXT_USHORT( p );
break;
default:
;
}
flags >>= 2;
switch ( flags & 3 )
{
case 0:
advance = scaled_advance;
break;
case 1:
PFR_CHECK( 1 );
advance = PFR_NEXT_INT8( p ) << 8;
break;
case 2:
PFR_CHECK( 2 );
advance = PFR_NEXT_SHORT( p );
break;
case 3:
PFR_CHECK( 3 );
advance = PFR_NEXT_LONG( p );
break;
default:
;
}
*axpos = xpos;
*aypos = ypos;
*axsize = xsize;
*aysize = ysize;
*aadvance = advance;
*aformat = flags >> 2;
*pdata = p;
Exit:
return error;
Too_Short:
error = PFR_Err_Invalid_Table;
FT_ERROR(( "pfr_load_bitmap_metrics: invalid glyph data\n" ));
goto Exit;
}
static FT_Error
pfr_load_bitmap_bits( FT_Byte* p,
FT_Byte* limit,
FT_UInt format,
FT_Bool decreasing,
FT_Bitmap* target )
{
FT_Error error = PFR_Err_Ok;
PFR_BitWriterRec writer;
if ( target->rows > 0 && target->width > 0 )
{
pfr_bitwriter_init( &writer, target, decreasing );
switch ( format )
{
case 0: /* packed bits */
pfr_bitwriter_decode_bytes( &writer, p, limit );
break;
case 1: /* RLE1 */
pfr_bitwriter_decode_rle1( &writer, p, limit );
break;
case 2: /* RLE2 */
pfr_bitwriter_decode_rle2( &writer, p, limit );
break;
default:
FT_ERROR(( "pfr_read_bitmap_data: invalid image type\n" ));
error = PFR_Err_Invalid_File_Format;
}
}
return error;
}
/*************************************************************************/
/*************************************************************************/
/***** *****/
/***** BITMAP LOADING *****/
/***** *****/
/*************************************************************************/
/*************************************************************************/
FT_LOCAL( FT_Error )
pfr_slot_load_bitmap( PFR_Slot glyph,
PFR_Size size,
FT_UInt glyph_index )
{
FT_Error error;
PFR_Face face = (PFR_Face) glyph->root.face;
FT_Stream stream = face->root.stream;
PFR_PhyFont phys = &face->phy_font;
FT_ULong gps_offset;
FT_ULong gps_size;
PFR_Char character;
PFR_Strike strike;
character = &phys->chars[glyph_index];
/* Look-up a bitmap strike corresponding to the current */
/* character dimensions */
{
FT_UInt n;
strike = phys->strikes;
for ( n = 0; n < phys->num_strikes; n++ )
{
if ( strike->x_ppm == (FT_UInt)size->root.metrics.x_ppem &&
strike->y_ppm == (FT_UInt)size->root.metrics.y_ppem )
{
goto Found_Strike;
}
strike++;
}
/* couldn't find it */
return PFR_Err_Invalid_Argument;
}
Found_Strike:
/* Now lookup the glyph's position within the file */
{
FT_UInt char_len;
char_len = 4;
if ( strike->flags & 1 ) char_len += 1;
if ( strike->flags & 2 ) char_len += 1;
if ( strike->flags & 4 ) char_len += 1;
/* Access data directly in the frame to speed lookups */
if ( FT_STREAM_SEEK( phys->bct_offset + strike->bct_offset ) ||
FT_FRAME_ENTER( char_len * strike->num_bitmaps ) )
goto Exit;
pfr_lookup_bitmap_data( stream->cursor,
stream->limit,
strike->num_bitmaps,
strike->flags,
character->char_code,
&gps_offset,
&gps_size );
FT_FRAME_EXIT();
if ( gps_size == 0 )
{
/* Could not find a bitmap program string for this glyph */
error = PFR_Err_Invalid_Argument;
goto Exit;
}
}
/* get the bitmap metrics */
{
FT_Long xpos = 0, ypos = 0, advance = 0;
FT_UInt xsize = 0, ysize = 0, format = 0;
FT_Byte* p;
/* compute linear advance */
advance = character->advance;
if ( phys->metrics_resolution != phys->outline_resolution )
advance = FT_MulDiv( advance,
phys->outline_resolution,
phys->metrics_resolution );
glyph->root.linearHoriAdvance = advance;
/* compute default advance, i.e., scaled advance. This can be */
/* overridden in the bitmap header of certain glyphs. */
advance = FT_MulDiv( (FT_Fixed)size->root.metrics.x_ppem << 8,
character->advance,
phys->metrics_resolution );
if ( FT_STREAM_SEEK( face->header.gps_section_offset + gps_offset ) ||
FT_FRAME_ENTER( gps_size ) )
goto Exit;
p = stream->cursor;
error = pfr_load_bitmap_metrics( &p, stream->limit,
advance,
&xpos, &ypos,
&xsize, &ysize,
&advance, &format );
/*
* XXX: on 16bit system, we return an error for huge bitmap
* which causes a size truncation, because truncated
* size properties makes bitmap glyph broken.
*/
if ( xpos > FT_INT_MAX || ( ypos + ysize ) > FT_INT_MAX )
{
FT_TRACE1(( "pfr_slot_load_bitmap:" ));
FT_TRACE1(( "huge bitmap glyph %dx%d over FT_GlyphSlot\n",
xpos, ypos ));
error = PFR_Err_Invalid_Pixel_Size;
}
if ( !error )
{
glyph->root.format = FT_GLYPH_FORMAT_BITMAP;
/* Set up glyph bitmap and metrics */
/* XXX: needs casts to fit FT_Bitmap.{width|rows|pitch} */
glyph->root.bitmap.width = (FT_Int)xsize;
glyph->root.bitmap.rows = (FT_Int)ysize;
glyph->root.bitmap.pitch = (FT_Int)( xsize + 7 ) >> 3;
glyph->root.bitmap.pixel_mode = FT_PIXEL_MODE_MONO;
/* XXX: needs casts to fit FT_Glyph_Metrics.{width|height} */
glyph->root.metrics.width = (FT_Pos)xsize << 6;
glyph->root.metrics.height = (FT_Pos)ysize << 6;
glyph->root.metrics.horiBearingX = xpos << 6;
glyph->root.metrics.horiBearingY = ypos << 6;
glyph->root.metrics.horiAdvance = FT_PIX_ROUND( ( advance >> 2 ) );
glyph->root.metrics.vertBearingX = - glyph->root.metrics.width >> 1;
glyph->root.metrics.vertBearingY = 0;
glyph->root.metrics.vertAdvance = size->root.metrics.height;
/* XXX: needs casts fit FT_GlyphSlotRec.bitmap_{left|top} */
glyph->root.bitmap_left = (FT_Int)xpos;
glyph->root.bitmap_top = (FT_Int)(ypos + ysize);
/* Allocate and read bitmap data */
{
FT_ULong len = glyph->root.bitmap.pitch * ysize;
error = ft_glyphslot_alloc_bitmap( &glyph->root, len );
if ( !error )
{
error = pfr_load_bitmap_bits(
p,
stream->limit,
format,
FT_BOOL(face->header.color_flags & 2),
&glyph->root.bitmap );
}
}
}
FT_FRAME_EXIT();
}
Exit:
return error;
}
/* END */