/***************************************************************************/ /* */ /* pfrsbit.c */ /* */ /* FreeType PFR bitmap loader (body). */ /* */ /* Copyright 2002 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] = c; mask = 0x80; c = 0; cur ++; } } if ( mask != 0x80 ) cur[0] = 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] = 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] = 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_Int count, FT_Byte flags, FT_UInt char_code, FT_ULong* found_offset, FT_ULong* found_size ) { FT_UInt left, right, char_len; FT_Bool two = 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 = 0; 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_UInt decreasing, FT_Bitmap* target ) { FT_Error error = 0; 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 = FT_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 FT_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 = FT_Err_Invalid_Argument; goto Exit; } } /* get the bitmap metrics */ { FT_Long xpos, ypos, advance; FT_UInt xsize, ysize, format; FT_Byte* p; advance = FT_MulDiv( size->root.metrics.x_ppem << 8, character->advance, phys->metrics_resolution ); /* XXX: handle linearHoriAdvance correctly! */ 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 ); if ( !error ) { glyph->root.format = FT_GLYPH_FORMAT_BITMAP; /* Set up glyph bitmap and metrics */ glyph->root.bitmap.width = (FT_Int)xsize; glyph->root.bitmap.rows = (FT_Int)ysize; glyph->root.bitmap.pitch = (FT_Long)( xsize + 7 ) >> 3; glyph->root.bitmap.pixel_mode = FT_PIXEL_MODE_MONO; glyph->root.metrics.width = (FT_Long)xsize << 6; glyph->root.metrics.height = (FT_Long)ysize << 6; glyph->root.metrics.horiBearingX = xpos << 6; glyph->root.metrics.horiBearingY = ypos << 6; glyph->root.metrics.horiAdvance = ( ( advance >> 2 ) + 32 ) & -64; glyph->root.metrics.vertBearingX = - glyph->root.metrics.width >> 1; glyph->root.metrics.vertBearingY = 0; glyph->root.metrics.vertAdvance = size->root.metrics.height; glyph->root.bitmap_left = xpos; glyph->root.bitmap_top = ypos + ysize; /* Allocate and read bitmap data */ { FT_Memory memory = face->root.memory; FT_Long len = glyph->root.bitmap.pitch * ysize; if ( !FT_ALLOC( glyph->root.bitmap.buffer, len ) ) { error = pfr_load_bitmap_bits( p, stream->limit, format, face->header.color_flags & 2, &glyph->root.bitmap ); } } } FT_FRAME_EXIT(); } Exit: return error; } /* END */