Introduce a way of quickly retrieving (embedded) bitmap metrics.

`FT_Load_Glyph' doesn't generate a bitmap for a non-bitmap glyph
until the user calls `FT_Render_Glyph'.  However, it always
allocates memory for bitmaps and copies or decodes the contents of a
bitmap glyph, which can be quite slow for PNG data.

* include/freetype/freetype.h (FT_LOAD_BITMAP_METRICS_ONLY): New
macro.

* src/base/ftobjs.c (FT_Load_Glyph): Unset FT_LOAD_RENDER if
FT_LOAD_BITMAP_METRICS_ONLY is used.

* src/sfnt/ttsbit.c (tt_sbit_decoder_alloc_bitmap,
tt_sbit_decoder_load_bitmap): Add argument to control allocation of
the glyph slot.
(tt_sbit_decoder_load_image, tt_sbit_decoder_load_compound,
tt_face_load_sbit_image): Updated.

* src/pcf/pcfdrivr.c (PCF_Glyph_Load): Quickly exit if
`FT_LOAD_BITMAP_METRICS_ONLY' is set.

* src/pfr/pfrsbit.c, src/pfr/pfrsbit.h (pfr_slot_load_bitmap): Add
argument to control allocation of the glyph slot.
* src/pfr/pfrobjs (pfr_slot_load): Updated.

* src/winfonts/winfnt.c (FNT_Load_Glyph): Ditto.

* docs/CHANGES: Updated.
This commit is contained in:
Werner Lemberg 2016-11-06 12:32:51 +01:00
parent 57f73d1f77
commit 37e193e935
10 changed files with 134 additions and 57 deletions

View File

@ -1,4 +1,37 @@
2016-10-29 Werner Lemberg <wl@gnu.org> 2016-11-06 Seigo Nonaka <nona@google.com>
Werner Lemberg <wl@gnu.org>
Introduce a way of quickly retrieving (embedded) bitmap metrics.
`FT_Load_Glyph' doesn't generate a bitmap for a non-bitmap glyph
until the user calls `FT_Render_Glyph'. However, it always
allocates memory for bitmaps and copies or decodes the contents of a
bitmap glyph, which can be quite slow for PNG data.
* include/freetype/freetype.h (FT_LOAD_BITMAP_METRICS_ONLY): New
macro.
* src/base/ftobjs.c (FT_Load_Glyph): Unset FT_LOAD_RENDER if
FT_LOAD_BITMAP_METRICS_ONLY is used.
* src/sfnt/ttsbit.c (tt_sbit_decoder_alloc_bitmap,
tt_sbit_decoder_load_bitmap): Add argument to control allocation of
the glyph slot.
(tt_sbit_decoder_load_image, tt_sbit_decoder_load_compound,
tt_face_load_sbit_image): Updated.
* src/pcf/pcfdrivr.c (PCF_Glyph_Load): Quickly exit if
`FT_LOAD_BITMAP_METRICS_ONLY' is set.
* src/pfr/pfrsbit.c, src/pfr/pfrsbit.h (pfr_slot_load_bitmap): Add
argument to control allocation of the glyph slot.
* src/pfr/pfrobjs (pfr_slot_load): Updated.
* src/winfonts/winfnt.c (FNT_Load_Glyph): Ditto.
* docs/CHANGES: Updated.
2016-11-06 Werner Lemberg <wl@gnu.org>
Synchronize with gnulib (#49448). Synchronize with gnulib (#49448).

View File

@ -37,6 +37,9 @@ CHANGES BETWEEN 2.7 and 2.7.1
blend coordinates of the currently selected variation instance blend coordinates of the currently selected variation instance
has been added to the Multiple Masters interface. has been added to the Multiple Masters interface.
- A new load flag `FT_LOAD_BITMAP_METRICS_ONLY' to retrieve bitmap
information without loading the (embedded) bitmap itself.
====================================================================== ======================================================================

View File

@ -2802,6 +2802,14 @@ FT_BEGIN_HEADER
* *
* Currently, this flag is only implemented for TrueType fonts. * Currently, this flag is only implemented for TrueType fonts.
* *
* FT_LOAD_BITMAP_METRICS_ONLY ::
* This flag is used to request loading of the metrics and bitmap
* image information of a (possibly embedded) bitmap glyph without
* allocating or copying the bitmap image data itself. No effect if
* the target glyph is not a bitmap image.
*
* This flag unsets @FT_LOAD_RENDER.
*
* FT_LOAD_CROP_BITMAP :: * FT_LOAD_CROP_BITMAP ::
* Ignored. Deprecated. * Ignored. Deprecated.
* *
@ -2848,6 +2856,7 @@ FT_BEGIN_HEADER
/* Bits 16..19 are used by `FT_LOAD_TARGET_' */ /* Bits 16..19 are used by `FT_LOAD_TARGET_' */
#define FT_LOAD_COLOR ( 1L << 20 ) #define FT_LOAD_COLOR ( 1L << 20 )
#define FT_LOAD_COMPUTE_METRICS ( 1L << 21 ) #define FT_LOAD_COMPUTE_METRICS ( 1L << 21 )
#define FT_LOAD_BITMAP_METRICS_ONLY ( 1L << 22 )
/* */ /* */

View File

@ -641,6 +641,9 @@
load_flags &= ~FT_LOAD_RENDER; load_flags &= ~FT_LOAD_RENDER;
} }
if ( load_flags & FT_LOAD_BITMAP_METRICS_ONLY )
load_flags &= ~FT_LOAD_RENDER;
/* /*
* Determine whether we need to auto-hint or not. * Determine whether we need to auto-hint or not.
* The general rules are: * The general rules are:

View File

@ -492,8 +492,6 @@ THE SOFTWARE.
PCF_Metric metric; PCF_Metric metric;
FT_ULong bytes; FT_ULong bytes;
FT_UNUSED( load_flags );
FT_TRACE1(( "PCF_Glyph_Load: glyph index %d\n", glyph_index )); FT_TRACE1(( "PCF_Glyph_Load: glyph index %d\n", glyph_index ));
@ -550,6 +548,24 @@ THE SOFTWARE.
return FT_THROW( Invalid_File_Format ); return FT_THROW( Invalid_File_Format );
} }
slot->format = FT_GLYPH_FORMAT_BITMAP;
slot->bitmap_left = metric->leftSideBearing;
slot->bitmap_top = metric->ascent;
slot->metrics.horiAdvance = (FT_Pos)( metric->characterWidth * 64 );
slot->metrics.horiBearingX = (FT_Pos)( metric->leftSideBearing * 64 );
slot->metrics.horiBearingY = (FT_Pos)( metric->ascent * 64 );
slot->metrics.width = (FT_Pos)( ( metric->rightSideBearing -
metric->leftSideBearing ) * 64 );
slot->metrics.height = (FT_Pos)( bitmap->rows * 64 );
ft_synthesize_vertical_metrics( &slot->metrics,
( face->accel.fontAscent +
face->accel.fontDescent ) * 64 );
if ( load_flags & FT_LOAD_BITMAP_METRICS_ONLY )
goto Exit;
/* XXX: to do: are there cases that need repadding the bitmap? */ /* XXX: to do: are there cases that need repadding the bitmap? */
bytes = (FT_ULong)bitmap->pitch * bitmap->rows; bytes = (FT_ULong)bitmap->pitch * bitmap->rows;
@ -582,21 +598,6 @@ THE SOFTWARE.
} }
} }
slot->format = FT_GLYPH_FORMAT_BITMAP;
slot->bitmap_left = metric->leftSideBearing;
slot->bitmap_top = metric->ascent;
slot->metrics.horiAdvance = (FT_Pos)( metric->characterWidth * 64 );
slot->metrics.horiBearingX = (FT_Pos)( metric->leftSideBearing * 64 );
slot->metrics.horiBearingY = (FT_Pos)( metric->ascent * 64 );
slot->metrics.width = (FT_Pos)( ( metric->rightSideBearing -
metric->leftSideBearing ) * 64 );
slot->metrics.height = (FT_Pos)( bitmap->rows * 64 );
ft_synthesize_vertical_metrics( &slot->metrics,
( face->accel.fontAscent +
face->accel.fontDescent ) * 64 );
Exit: Exit:
return error; return error;
} }

View File

@ -342,7 +342,11 @@
/* try to load an embedded bitmap */ /* try to load an embedded bitmap */
if ( ( load_flags & ( FT_LOAD_NO_SCALE | FT_LOAD_NO_BITMAP ) ) == 0 ) if ( ( load_flags & ( FT_LOAD_NO_SCALE | FT_LOAD_NO_BITMAP ) ) == 0 )
{ {
error = pfr_slot_load_bitmap( slot, size, gindex ); error = pfr_slot_load_bitmap(
slot,
size,
gindex,
( load_flags & FT_LOAD_BITMAP_METRICS_ONLY ) != 0 );
if ( error == 0 ) if ( error == 0 )
goto Exit; goto Exit;
} }

View File

@ -578,7 +578,8 @@
FT_LOCAL( FT_Error ) FT_LOCAL( FT_Error )
pfr_slot_load_bitmap( PFR_Slot glyph, pfr_slot_load_bitmap( PFR_Slot glyph,
PFR_Size size, PFR_Size size,
FT_UInt glyph_index ) FT_UInt glyph_index,
FT_Bool metrics_only )
{ {
FT_Error error; FT_Error error;
PFR_Face face = (PFR_Face) glyph->root.face; PFR_Face face = (PFR_Face) glyph->root.face;
@ -775,6 +776,9 @@
glyph->root.bitmap_left = (FT_Int)xpos; glyph->root.bitmap_left = (FT_Int)xpos;
glyph->root.bitmap_top = (FT_Int)( ypos + (FT_Long)ysize ); glyph->root.bitmap_top = (FT_Int)( ypos + (FT_Long)ysize );
if ( metrics_only )
goto Exit1;
/* Allocate and read bitmap data */ /* Allocate and read bitmap data */
{ {
FT_ULong len = (FT_ULong)glyph->root.bitmap.pitch * ysize; FT_ULong len = (FT_ULong)glyph->root.bitmap.pitch * ysize;

View File

@ -26,7 +26,8 @@ FT_BEGIN_HEADER
FT_LOCAL( FT_Error ) FT_LOCAL( FT_Error )
pfr_slot_load_bitmap( PFR_Slot glyph, pfr_slot_load_bitmap( PFR_Slot glyph,
PFR_Size size, PFR_Size size,
FT_UInt glyph_index ); FT_UInt glyph_index,
FT_Bool metrics_only );
FT_END_HEADER FT_END_HEADER

View File

@ -536,7 +536,8 @@
static FT_Error static FT_Error
tt_sbit_decoder_alloc_bitmap( TT_SBitDecoder decoder ) tt_sbit_decoder_alloc_bitmap( TT_SBitDecoder decoder,
FT_Bool metrics_only )
{ {
FT_Error error = FT_Err_Ok; FT_Error error = FT_Err_Ok;
FT_UInt width, height; FT_UInt width, height;
@ -599,6 +600,9 @@
if ( size == 0 ) if ( size == 0 )
goto Exit; /* exit successfully! */ goto Exit; /* exit successfully! */
if ( metrics_only )
goto Exit; /* only metrics are requested */
error = ft_glyphslot_alloc_bitmap( decoder->face->root.glyph, size ); error = ft_glyphslot_alloc_bitmap( decoder->face->root.glyph, size );
if ( error ) if ( error )
goto Exit; goto Exit;
@ -665,7 +669,8 @@
FT_UInt glyph_index, FT_UInt glyph_index,
FT_Int x_pos, FT_Int x_pos,
FT_Int y_pos, FT_Int y_pos,
FT_UInt recurse_count ); FT_UInt recurse_count,
FT_Bool metrics_only );
typedef FT_Error (*TT_SBitDecoder_LoadFunc)( typedef FT_Error (*TT_SBitDecoder_LoadFunc)(
TT_SBitDecoder decoder, TT_SBitDecoder decoder,
@ -995,7 +1000,9 @@
gindex, gindex,
x_pos + dx, x_pos + dx,
y_pos + dy, y_pos + dy,
recurse_count + 1 ); recurse_count + 1,
/* request full bitmap image */
FALSE );
if ( error ) if ( error )
break; break;
} }
@ -1077,7 +1084,8 @@
FT_ULong glyph_size, FT_ULong glyph_size,
FT_Int x_pos, FT_Int x_pos,
FT_Int y_pos, FT_Int y_pos,
FT_UInt recurse_count ) FT_UInt recurse_count,
FT_Bool metrics_only )
{ {
FT_Error error; FT_Error error;
FT_Stream stream = decoder->stream; FT_Stream stream = decoder->stream;
@ -1199,11 +1207,15 @@
if ( !decoder->bitmap_allocated ) if ( !decoder->bitmap_allocated )
{ {
error = tt_sbit_decoder_alloc_bitmap( decoder ); error = tt_sbit_decoder_alloc_bitmap( decoder, metrics_only );
if ( error ) if ( error )
goto Fail; goto Fail;
} }
if ( metrics_only )
goto Fail; /* this is not an error */
error = loader( decoder, p, p_limit, x_pos, y_pos, recurse_count ); error = loader( decoder, p, p_limit, x_pos, y_pos, recurse_count );
} }
@ -1220,7 +1232,8 @@
FT_UInt glyph_index, FT_UInt glyph_index,
FT_Int x_pos, FT_Int x_pos,
FT_Int y_pos, FT_Int y_pos,
FT_UInt recurse_count ) FT_UInt recurse_count,
FT_Bool metrics_only )
{ {
FT_Byte* p = decoder->eblc_base + decoder->strike_index_array; FT_Byte* p = decoder->eblc_base + decoder->strike_index_array;
FT_Byte* p_limit = decoder->eblc_limit; FT_Byte* p_limit = decoder->eblc_limit;
@ -1405,7 +1418,8 @@
image_end, image_end,
x_pos, x_pos,
y_pos, y_pos,
recurse_count ); recurse_count,
metrics_only );
Failure: Failure:
return FT_THROW( Invalid_Table ); return FT_THROW( Invalid_Table );
@ -1567,11 +1581,13 @@
error = tt_sbit_decoder_init( decoder, face, strike_index, metrics ); error = tt_sbit_decoder_init( decoder, face, strike_index, metrics );
if ( !error ) if ( !error )
{ {
error = tt_sbit_decoder_load_image( decoder, error = tt_sbit_decoder_load_image(
glyph_index, decoder,
0, glyph_index,
0, 0,
0 ); 0,
0,
( load_flags & FT_LOAD_BITMAP_METRICS_ONLY ) != 0 );
tt_sbit_decoder_done( decoder ); tt_sbit_decoder_done( decoder );
} }
} }
@ -1592,9 +1608,10 @@
} }
/* Flatten color bitmaps if color was not requested. */ /* Flatten color bitmaps if color was not requested. */
if ( !error && if ( !error &&
!( load_flags & FT_LOAD_COLOR ) && !( load_flags & FT_LOAD_COLOR ) &&
map->pixel_mode == FT_PIXEL_MODE_BGRA ) !( load_flags & FT_LOAD_BITMAP_METRICS_ONLY ) &&
map->pixel_mode == FT_PIXEL_MODE_BGRA )
{ {
FT_Bitmap new_map; FT_Bitmap new_map;
FT_Library library = face->root.glyph->library; FT_Library library = face->root.glyph->library;

View File

@ -1000,8 +1000,6 @@
FT_ULong offset; FT_ULong offset;
FT_Bool new_format; FT_Bool new_format;
FT_UNUSED( load_flags );
if ( !face ) if ( !face )
{ {
@ -1055,6 +1053,26 @@
goto Exit; goto Exit;
} }
bitmap->rows = font->header.pixel_height;
bitmap->pixel_mode = FT_PIXEL_MODE_MONO;
slot->bitmap_left = 0;
slot->bitmap_top = font->header.ascent;
slot->format = FT_GLYPH_FORMAT_BITMAP;
/* now set up metrics */
slot->metrics.width = (FT_Pos)( bitmap->width << 6 );
slot->metrics.height = (FT_Pos)( bitmap->rows << 6 );
slot->metrics.horiAdvance = (FT_Pos)( bitmap->width << 6 );
slot->metrics.horiBearingX = 0;
slot->metrics.horiBearingY = slot->bitmap_top << 6;
ft_synthesize_vertical_metrics( &slot->metrics,
(FT_Pos)( bitmap->rows << 6 ) );
if ( load_flags & FT_LOAD_BITMAP_METRICS_ONLY )
goto Exit;
/* jump to glyph data */ /* jump to glyph data */
p = font->fnt_frame + /* font->header.bits_offset */ + offset; p = font->fnt_frame + /* font->header.bits_offset */ + offset;
@ -1066,10 +1084,7 @@
FT_Byte* write; FT_Byte* write;
bitmap->pitch = (int)pitch; bitmap->pitch = (int)pitch;
bitmap->rows = font->header.pixel_height;
bitmap->pixel_mode = FT_PIXEL_MODE_MONO;
if ( !pitch || if ( !pitch ||
offset + pitch * bitmap->rows > font->header.file_size ) offset + pitch * bitmap->rows > font->header.file_size )
{ {
@ -1093,23 +1108,10 @@
for ( write = column; p < limit; p++, write += bitmap->pitch ) for ( write = column; p < limit; p++, write += bitmap->pitch )
*write = *p; *write = *p;
} }
slot->internal->flags = FT_GLYPH_OWN_BITMAP;
} }
slot->internal->flags = FT_GLYPH_OWN_BITMAP;
slot->bitmap_left = 0;
slot->bitmap_top = font->header.ascent;
slot->format = FT_GLYPH_FORMAT_BITMAP;
/* now set up metrics */
slot->metrics.width = (FT_Pos)( bitmap->width << 6 );
slot->metrics.height = (FT_Pos)( bitmap->rows << 6 );
slot->metrics.horiAdvance = (FT_Pos)( bitmap->width << 6 );
slot->metrics.horiBearingX = 0;
slot->metrics.horiBearingY = slot->bitmap_top << 6;
ft_synthesize_vertical_metrics( &slot->metrics,
(FT_Pos)( bitmap->rows << 6 ) );
Exit: Exit:
return error; return error;
} }