Tue 01 Sep 2009 08:34:24 AM UTC, original submission:
I've experienced some problems with the calculation of vertBearingX. The calculation of this value is not defined in the OTF font spec so FT does a 'best effort' attempt. However this value is defined in the PDF and postscript spec and that algorithm is better then the one FT currently uses.
FreeType: use the middle of the bounding box as the X coordinate of the vertical origin
Adobe PDF spec: use the middle of the horizontal advance vector as the X coordinate of the vertical origin
FreeType's algorithm goes wrong when you have a really small glyph (like the dot at the end of the sentence) with large bearings. With the FreeType algorithm this dot gets centered on the baseline, with the PDF algorithm it gets the correct location (in the top right). Note that this is a serious issue, it's like printing the dot at the end of a roman sentance at the center of the textline instead of on the baseline like it should. So i believe the PDF spec's algorithm should be used in FreeType as well. See fix below.
The vertBearingY for the glyph described above is also very strange if no vmtx information is present.
Since the height of the bbox is not representable for the height of the glyph visually (the whitespace up to the baseline is a part of the glyph). The fix below also includes some code for a better estimate for vertBearingY.
I also discovered another bug that causes the vmtx to be ignored for OTF CFF fonts. (That's why I noticed that the default vertBearingY was strange for fonts without vmtx :D).
I hope these changes will make vertical text a little more reliable.
Questions:
Is there a way to test the displaying of vertical metrics with only the utilities in ft2demos ?
Why is the calculation of vertBearingY and vertAdvance in ttgload.c so complex ? Can't the
block starting at 1586 be replaced by:
glyph->metrics.vertBearingY = loader->pp3.y - bbox.yMax;
glyph->metrics.vertAdvance = loader->pp3.y - loader->pp4.y;
(linear calculation is still necessary though)
Fixes:
cffgload.c:2714:
has_vertical_info = FT_BOOL( face->vertical_info &&
face->vertical.number_Of_VMetrics > 0 &&
face->vertical.long_metrics );
to
#ifdef FT_CONFIG_OPTION_OLD_INTERNALS
has_vertical_info = FT_BOOL( face->vertical_info &&
face->vertical.number_Of_VMetrics > 0 &&
face->vertical.long_metrics );
#else
has_vertical_info = FT_BOOL( face->vertical_info &&
face->vertical.number_Of_VMetrics > 0 );
#endif
cffgload.c:2807
if ( has_vertical_info )
metrics->vertBearingX = -metrics->width / 2;
else
ft_synthesize_vertical_metrics( metrics,
metrics->vertAdvance );
to
if ( has_vertical_info )
metrics->vertBearingX = metrics->horiBearingX - ( metrics->horiAdvance / 2 );
else
ft_synthesize_vertical_metrics( metrics,
metrics->vertAdvance );
ftobjs.c:2398
FT_BASE_DEF( void )
ft_synthesize_vertical_metrics( FT_Glyph_Metrics* metrics,
FT_Pos advance )
{
/* the factor 1.2 is a heuristical value */
if ( !advance )
advance = metrics->height * 12 / 10;
metrics->vertBearingX = -( metrics->width / 2 );
metrics->vertBearingY = ( advance - metrics->height ) / 2;
metrics->vertAdvance = advance;
}
to
FT_BASE_DEF( void )
ft_synthesize_vertical_metrics( FT_Glyph_Metrics* metrics,
FT_Pos advance )
{
int theHeight = metrics->height;
/* compensate for glyph with bbox above/below the baseline */
if ( 0 > metrics->horiBearingY )
{
if ( theHeight < metrics->horiBearingY )
theHeight = metrics->horiBearingY;
}
else if ( 0 < metrics->horiBearingY )
theHeight -= metrics->horiBearingY;
/* the factor 1.2 is a heuristical value */
if ( !advance )
advance = theHeight * 12 / 10;
metrics->vertBearingX = metrics->horiBearingX - ( metrics->horiAdvance / 2 );
metrics->vertBearingY = ( advance - theHeight ) / 2;
metrics->vertAdvance = advance;
}
ttgload.c:1581
cut and past the block from 1679 here to ensure all metrics besides the vertical ones are completely calculated before starting with the vertical ones:
/* adjust advance width to the value contained in the hdmx table */
if ( !face->postscript.isFixedPitch &&
IS_HINTED( loader->load_flags ) )
{
FT_Byte* widthp;
widthp = tt_face_get_device_metrics( face,
size->root.metrics.x_ppem,
glyph_index );
if ( widthp )
glyph->metrics.horiAdvance = *widthp << 6;
}
/* set glyph dimensions */
glyph->metrics.width = bbox.xMax - bbox.xMin;
glyph->metrics.height = bbox.yMax - bbox.yMin;
ttgload.c:1674
glyph->metrics.vertBearingX = ( bbox.xMin - bbox.xMax ) / 2;
to
glyph->metrics.vertBearingX = glyph->metrics.horiBearingX - ( glyph->metrics.horiAdvance / 2 );
|