[sfnt] Implement PS names for font instances [2/3].
* src/sfnt/sfdriver.c (fix2float) [TT_CONFIG_OPTION_GX_VAR_SUPPORT]: New function to find the shortest representation of a 16.16 fractional number.
This commit is contained in:
parent
4a32dce92a
commit
4fd9cc73e6
|
@ -1,3 +1,11 @@
|
||||||
|
2017-03-14 Werner Lemberg <wl@gnu.org>
|
||||||
|
|
||||||
|
[sfnt] Implement PS names for font instances [2/3].
|
||||||
|
|
||||||
|
* src/sfnt/sfdriver.c (fix2float) [TT_CONFIG_OPTION_GX_VAR_SUPPORT]:
|
||||||
|
New function to find the shortest representation of a 16.16
|
||||||
|
fractional number.
|
||||||
|
|
||||||
2017-03-14 Werner Lemberg <wl@gnu.org>
|
2017-03-14 Werner Lemberg <wl@gnu.org>
|
||||||
|
|
||||||
[sfnt] Implement PS names for font instances [1/3].
|
[sfnt] Implement PS names for font instances [1/3].
|
||||||
|
|
|
@ -601,6 +601,126 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Find the shortest decimal representation of a 16.16 fixed point
|
||||||
|
* number. The function fills `buf' with the result, returning a pointer
|
||||||
|
* to the position after the representation's last byte.
|
||||||
|
*/
|
||||||
|
|
||||||
|
static char*
|
||||||
|
fixed2float( FT_Int fixed,
|
||||||
|
char* buf )
|
||||||
|
{
|
||||||
|
char* p;
|
||||||
|
char* q;
|
||||||
|
char tmp[5];
|
||||||
|
|
||||||
|
FT_Int int_part;
|
||||||
|
FT_Int frac_part;
|
||||||
|
|
||||||
|
FT_Int i;
|
||||||
|
|
||||||
|
|
||||||
|
p = buf;
|
||||||
|
|
||||||
|
if ( fixed == 0 )
|
||||||
|
{
|
||||||
|
*p++ = '0';
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( fixed < 0 )
|
||||||
|
{
|
||||||
|
*p++ = '-';
|
||||||
|
fixed = -fixed;
|
||||||
|
}
|
||||||
|
|
||||||
|
int_part = ( fixed >> 16 ) & 0xFFFF;
|
||||||
|
frac_part = fixed & 0xFFFF;
|
||||||
|
|
||||||
|
/* get digits of integer part (in reverse order) */
|
||||||
|
q = tmp;
|
||||||
|
while ( int_part > 0 )
|
||||||
|
{
|
||||||
|
*q++ = '0' + int_part % 10;
|
||||||
|
int_part /= 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* copy digits in correct order to buffer */
|
||||||
|
while ( q > tmp )
|
||||||
|
*p++ = *--q;
|
||||||
|
|
||||||
|
if ( !frac_part )
|
||||||
|
return p;
|
||||||
|
|
||||||
|
/* save position of point */
|
||||||
|
q = p;
|
||||||
|
*p++ = '.';
|
||||||
|
|
||||||
|
/* apply rounding */
|
||||||
|
frac_part = frac_part * 10 + 5;
|
||||||
|
|
||||||
|
/* get digits of fractional part */
|
||||||
|
for ( i = 0; i < 5; i++ )
|
||||||
|
{
|
||||||
|
*p++ = '0' + frac_part / 0x10000L;
|
||||||
|
|
||||||
|
frac_part %= 0x10000L;
|
||||||
|
if ( !frac_part )
|
||||||
|
break;
|
||||||
|
|
||||||
|
frac_part *= 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
If the remainder stored in `frac_part' (after the last FOR loop) is
|
||||||
|
smaller than 34480*10, the resulting decimal value minus 0.00001 is
|
||||||
|
an equivalent representation of `fixed'.
|
||||||
|
|
||||||
|
The above FOR loop always finds the larger of the two values; I
|
||||||
|
verified this by iterating over all possible fixed point numbers.
|
||||||
|
|
||||||
|
If the remainder is 17232*10, both values are equally good, and we
|
||||||
|
take the next even number (following IEEE 754's `round to nearest,
|
||||||
|
ties to even' rounding rule).
|
||||||
|
|
||||||
|
If the remainder is smaller than 17232*10, the lower of the two
|
||||||
|
numbers is nearer to the exact result (values 17232 and 34480 were
|
||||||
|
also found by testing all possible fixed point values).
|
||||||
|
|
||||||
|
We use this to find a shorter decimal representation. If not ending
|
||||||
|
with digit zero, we take the representation with less error.
|
||||||
|
*/
|
||||||
|
p--;
|
||||||
|
if ( p - q == 5 ) /* five digits? */
|
||||||
|
{
|
||||||
|
/* take the representation that has zero as the last digit */
|
||||||
|
if ( frac_part < 34480 * 10 &&
|
||||||
|
*p == '1' )
|
||||||
|
*p = '0';
|
||||||
|
|
||||||
|
/* otherwise use the one with less error */
|
||||||
|
else if ( frac_part == 17232 * 10 &&
|
||||||
|
*p & 1 )
|
||||||
|
*p -= 1;
|
||||||
|
|
||||||
|
else if ( frac_part < 17232 * 10 &&
|
||||||
|
*p != '0' )
|
||||||
|
*p -= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* remove trailing zeros */
|
||||||
|
while ( *p == '0' )
|
||||||
|
*p-- = '\0';
|
||||||
|
|
||||||
|
return p + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* TT_CONFIG_OPTION_GX_VAR_SUPPORT */
|
||||||
|
|
||||||
|
|
||||||
static const char*
|
static const char*
|
||||||
sfnt_get_ps_name( TT_Face face )
|
sfnt_get_ps_name( TT_Face face )
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in New Issue