src/pfr/pfrgload.c, src/pfr/pfrobjs.c, src/pfr/pfrtypes.h, Jamfile, src/base/ftobjs.c: adding support for embedded bitmaps to the PFR driver, and rewriting its kerning loader / handler to use all kerning pairs in a physical font (and not just the first item). * src/tools/docmaker/content.py, src/tools/docmaker/sources.py, src/tools/docmaker/tohtml.py: fixing a few nasty bugs * src/sfnt/ttcmap0.c: the validator for format 4 sub-tables is now capable of dealing with invalid "length" fields at the start of the sub-table. This allows fonts like "mg______.ttf" (i.e. Marriage) to return accurate charmaps.BRANCH-2-1-5
parent
91878e734b
commit
6550e01be3
14 changed files with 1071 additions and 161 deletions
@ -0,0 +1,629 @@ |
||||
#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're 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; |
||||
} |
@ -0,0 +1,32 @@ |
||||
/***************************************************************************/ |
||||
/* */ |
||||
/* pfrsbit.c */ |
||||
/* */ |
||||
/* FreeType PFR bitmap loader */ |
||||
/* */ |
||||
/* 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. */ |
||||
/* */ |
||||
/***************************************************************************/ |
||||
|
||||
#ifndef __PFRSBIT_H__ |
||||
#define __PFRSBIT_H__ |
||||
|
||||
#include "pfrobjs.h" |
||||
|
||||
FT_BEGIN_HEADER |
||||
|
||||
FT_LOCAL( FT_Error ) |
||||
pfr_slot_load_bitmap( PFR_Slot glyph, |
||||
PFR_Size size, |
||||
FT_UInt glyph_index ); |
||||
|
||||
FT_END_HEADER |
||||
|
||||
#endif /* __PFR_SBIT_H__ */ |
Loading…
Reference in new issue