Commits (3)
  • Alexei Podtelezhnikov's avatar
    [truetype] Initialize the loader with `hdmx` data. · 6c831d65
    Alexei Podtelezhnikov authored
    The `hdmx` matching can be done before the glyph is loaded.
    
    * include/freetype/internal/tttypes.h (TT_LoaderRec): Add a field.
    * src/truetype/ttgload.c (compute_glyph_metrics): Relocate the `hdmx`
    code from here...
    (tt_loader_init): ... to here, before the glyph is loaded.
    6c831d65
  • Alexei Podtelezhnikov's avatar
    [truetype] Honor FT_LOAD_ADVANCE_ONLY if `hdmx` is usable. · a8ef33e3
    Alexei Podtelezhnikov authored
    This simply shortcuts the glyph loading if FT_LOAD_ADVANCE_ONLY
    is specified by FT_Get_Advances and the `hdmx` data are located.
    Particularly, the classic v35 interpreter or "verified" ClearType
    fonts might see 100x speed up in retrieving the hdmx cache.
    
    * src/truetype/ttgload.c (TT_Load_Glyph): Insert the shortcut.
    a8ef33e3
  • Alexei Podtelezhnikov's avatar
    [truetype] Binary search through the `hdmx` records. · 7add5b2b
    Alexei Podtelezhnikov authored
    The `hdmx` table is supposed to be sorted by ppem size, which
    enables binary search.  We also drop the check for the sufficient
    length of the record because it is now enforced when the table
    is loaded.
    
    * include/freetype/internal/tttypes.h (TT_FaceRec): Store the `hdmx`
    record pointers sorted by ppem instead of ppem's themselves.
    * src/truetype/ttpload.c (tt_face_load_hdmx): Prudently sort records.
    (tt_face_get_device_metrics): Implement binary search to retrieve
    advances.
    7add5b2b
......@@ -1390,8 +1390,8 @@ FT_BEGIN_HEADER
* hdmx_record_size ::
* The size of a single hdmx record.
*
* hdmx_record_sizes ::
* An array holding the ppem sizes available in the 'hdmx' table.
* hdmx_records ::
* A array of pointers to the 'hdmx' table records sorted by ppem.
*
* sbit_table ::
* A pointer to the font's embedded bitmap location table.
......@@ -1605,7 +1605,7 @@ FT_BEGIN_HEADER
FT_ULong hdmx_table_size;
FT_UInt hdmx_record_count;
FT_ULong hdmx_record_size;
FT_Byte* hdmx_record_sizes;
FT_Byte** hdmx_records;
FT_Byte* sbit_table;
FT_ULong sbit_table_size;
......@@ -1769,6 +1769,9 @@ FT_BEGIN_HEADER
/* since version 2.6.2 */
FT_ListRec composites;
/* since version 2.11.2 */
FT_Byte* widthp;
} TT_LoaderRec;
......
......@@ -2230,10 +2230,6 @@
FT_UInt glyph_index )
{
TT_Face face = loader->face;
#if defined TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY || \
defined TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL
TT_Driver driver = (TT_Driver)FT_FACE_DRIVER( face );
#endif
FT_BBox bbox;
FT_Fixed y_scale;
......@@ -2256,37 +2252,10 @@
glyph->metrics.horiBearingX = bbox.xMin;
glyph->metrics.horiBearingY = bbox.yMax;
glyph->metrics.horiAdvance = SUB_LONG(loader->pp2.x, loader->pp1.x);
/* Adjust advance width to the value contained in the hdmx table */
/* unless FT_LOAD_COMPUTE_METRICS is set or backward compatibility */
/* mode of the v40 interpreter is active. See `ttinterp.h' for */
/* details on backward compatibility mode. */
if ( IS_HINTED( loader->load_flags ) &&
!( loader->load_flags & FT_LOAD_COMPUTE_METRICS ) &&
#ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL
!( driver->interpreter_version == TT_INTERPRETER_VERSION_40 &&
( loader->exec && loader->exec->backward_compatibility ) ) &&
#endif
#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
!( driver->interpreter_version == TT_INTERPRETER_VERSION_38 &&
!SPH_OPTION_BITMAP_WIDTHS &&
FT_LOAD_TARGET_MODE( loader->load_flags ) !=
FT_RENDER_MODE_MONO &&
( loader->exec && !loader->exec->compatible_widths ) ) &&
#endif
!face->postscript.isFixedPitch )
{
FT_Byte* widthp;
widthp = tt_face_get_device_metrics( face,
size->metrics->x_ppem,
glyph_index );
if ( widthp )
glyph->metrics.horiAdvance = *widthp * 64;
}
if ( loader->widthp )
glyph->metrics.horiAdvance = loader->widthp[glyph_index] * 64;
else
glyph->metrics.horiAdvance = SUB_LONG(loader->pp2.x, loader->pp1.x);
/* set glyph dimensions */
glyph->metrics.width = SUB_LONG( bbox.xMax, bbox.xMin );
......@@ -2752,6 +2721,32 @@
exec->pedantic_hinting = FT_BOOL( load_flags & FT_LOAD_PEDANTIC );
loader->exec = exec;
loader->instructions = exec->glyphIns;
/* Use the hdmx table if any unless FT_LOAD_COMPUTE_METRICS */
/* is set or backward compatibility mode of the v38 or v40 */
/* interpreters is active. See `ttinterp.h' for details on */
/* backward compatibility mode. */
if ( IS_HINTED( loader->load_flags ) &&
!( loader->load_flags & FT_LOAD_COMPUTE_METRICS ) &&
#ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL
!( driver->interpreter_version == TT_INTERPRETER_VERSION_40 &&
exec->backward_compatibility ) &&
#endif
#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
!( driver->interpreter_version == TT_INTERPRETER_VERSION_38 &&
!SPH_OPTION_BITMAP_WIDTHS &&
FT_LOAD_TARGET_MODE( loader->load_flags ) !=
FT_RENDER_MODE_MONO &&
exec->compatible_widths ) &&
#endif
!face->postscript.isFixedPitch )
{
loader->widthp = tt_face_get_device_metrics( face,
size->metrics->x_ppem,
0 );
}
else
loader->widthp = NULL;
}
#endif /* TT_USE_BYTECODE_INTERPRETER */
......@@ -2950,6 +2945,15 @@
if ( error )
goto Exit;
/* done if we are only interested in the `hdmx` advance */
if ( load_flags & FT_LOAD_ADVANCE_ONLY &&
!( load_flags & FT_LOAD_VERTICAL_LAYOUT ) &&
loader.widthp )
{
glyph->metrics.horiAdvance = loader.widthp[glyph_index] * 64;
goto Done;
}
glyph->format = FT_GLYPH_FORMAT_OUTLINE;
glyph->num_subglyphs = 0;
glyph->outline.flags = 0;
......@@ -3028,6 +3032,7 @@
glyph->outline.n_points,
glyph->outline.flags ));
Done:
tt_loader_done( &loader );
Exit:
......
......@@ -498,6 +498,14 @@
}
FT_COMPARE_DEF( int )
compare_ppem( const void* a,
const void* b )
{
return **(FT_Byte**)a - **(FT_Byte**)b;
}
/**************************************************************************
*
* @Function:
......@@ -574,20 +582,21 @@
goto Fail;
}
if ( FT_QNEW_ARRAY( face->hdmx_record_sizes, num_records ) )
if ( FT_QNEW_ARRAY( face->hdmx_records, num_records ) )
goto Fail;
/* XXX: We do not check if the records are sorted by ppem */
/* and cannot use binary search later. */
for ( nn = 0; nn < num_records; nn++ )
{
if ( p + record_size > limit )
break;
face->hdmx_record_sizes[nn] = p[0];
p += record_size;
face->hdmx_records[nn] = p;
p += record_size;
}
/* The records must be already sorted by ppem but it does not */
/* hurt to make sure so that the binary search works later. */
ft_qsort( face->hdmx_records, nn, sizeof ( FT_Byte* ), compare_ppem );
face->hdmx_record_count = nn;
face->hdmx_table_size = table_size;
face->hdmx_record_size = record_size;
......@@ -611,7 +620,7 @@
FT_Memory memory = stream->memory;
FT_FREE( face->hdmx_record_sizes );
FT_FREE( face->hdmx_records );
FT_FRAME_RELEASE( face->hdmx_table );
}
......@@ -619,27 +628,34 @@
/**************************************************************************
*
* Return the advance width table for a given pixel size if it is found
* in the font's `hdmx' table (if any).
* in the font's `hdmx' table (if any). The records must be sorted for
* the binary search to work properly.
*/
FT_LOCAL_DEF( FT_Byte* )
tt_face_get_device_metrics( TT_Face face,
FT_UInt ppem,
FT_UInt gindex )
{
FT_UInt nn;
FT_Byte* result = NULL;
FT_ULong record_size = face->hdmx_record_size;
FT_Byte* record = FT_OFFSET( face->hdmx_table, 8 );
FT_UInt min = 0;
FT_UInt max = face->hdmx_record_count;
FT_UInt mid;
FT_Byte* result = NULL;
while ( min < max )
{
mid = ( min + max ) >> 1;
for ( nn = 0; nn < face->hdmx_record_count; nn++ )
if ( face->hdmx_record_sizes[nn] == ppem )
if ( face->hdmx_records[mid][0] > ppem )
max = mid;
else if ( face->hdmx_records[mid][0] < ppem )
min = mid + 1;
else
{
gindex += 2;
if ( gindex < record_size )
result = record + nn * record_size + gindex;
result = face->hdmx_records[mid] + 2 + gindex;
break;
}
}
return result;
}
......