[cff] Fix matrix scaling (#47848).

* include/freetype/config/ftstdlib.h (FT_LONG_MIN): New macro.

* src/cff/cffparse.c (cff_parse_font_matrix): Use largest scaling
value of all matrix coefficients to scale matrix.

* src/cff/cffobjs.c (cff_face_init): Use `matrix->yx' member for
matrix normalization if `matrix->yy' is zero.
This commit is contained in:
Werner Lemberg 2016-05-17 19:54:09 +02:00
parent 533887a947
commit 119e8e41ef
4 changed files with 88 additions and 21 deletions

View File

@ -1,3 +1,15 @@
2016-05-17 Werner Lemberg <wl@gnu.org>
[cff] Fix matrix scaling (#47848).
* include/freetype/config/ftstdlib.h (FT_LONG_MIN): New macro.
* src/cff/cffparse.c (cff_parse_font_matrix): Use largest scaling
value of all matrix coefficients to scale matrix.
* src/cff/cffobjs.c (cff_face_init): Use `matrix->yx' member for
matrix normalization if `matrix->yy' is zero.
2016-05-16 Werner Lemberg <wl@gnu.org>
[base] Reject invalid sfnt Mac resource (#47891).

View File

@ -63,6 +63,7 @@
#define FT_INT_MAX INT_MAX
#define FT_INT_MIN INT_MIN
#define FT_UINT_MAX UINT_MAX
#define FT_LONG_MIN LONG_MIN
#define FT_LONG_MAX LONG_MAX
#define FT_ULONG_MAX ULONG_MAX

View File

@ -670,10 +670,11 @@
if ( !dict->has_font_matrix )
dict->units_per_em = pure_cff ? 1000 : face->root.units_per_EM;
/* Normalize the font matrix so that `matrix->yy' is 1; the */
/* scaling is done with `units_per_em' then (at this point, */
/* it already contains the scaling factor, but without */
/* normalization of the matrix). */
/* Normalize the font matrix so that `matrix->yy' is 1; if */
/* it is zero, we use `matrix->yx' instead. The scaling is */
/* done with `units_per_em' then (at this point, it already */
/* contains the scaling factor, but without normalization */
/* of the matrix). */
/* */
/* Note that the offsets must be expressed in integer font */
/* units. */
@ -682,9 +683,12 @@
FT_Matrix* matrix = &dict->font_matrix;
FT_Vector* offset = &dict->font_offset;
FT_ULong* upm = &dict->units_per_em;
FT_Fixed temp = FT_ABS( matrix->yy );
FT_Fixed temp;
temp = matrix->yy ? FT_ABS( matrix->yy )
: FT_ABS( matrix->yx );
if ( temp != 0x10000L )
{
*upm = (FT_ULong)FT_DivFix( (FT_Long)*upm, temp );
@ -752,7 +756,10 @@
matrix = &sub->font_matrix;
offset = &sub->font_offset;
upm = &sub->units_per_em;
temp = FT_ABS( matrix->yy );
temp = matrix->yy ? FT_ABS( matrix->yy )
: FT_ABS( matrix->yx );
if ( temp != 0x10000L )
{

View File

@ -521,7 +521,11 @@
if ( parser->top >= parser->stack + 6 )
{
FT_Long scaling;
FT_Fixed values[6];
FT_Long scalings[6];
FT_Long min_scaling, max_scaling;
int i;
error = FT_Err_Ok;
@ -530,22 +534,36 @@
/* We expect a well-formed font matrix, this is, the matrix elements */
/* `xx' and `yy' are of approximately the same magnitude. To avoid */
/* loss of precision, we use the magnitude of element `xx' to scale */
/* all other elements. The scaling factor is then contained in the */
/* `units_per_em' value. */
/* loss of precision, we use the magnitude of the largest matrix */
/* element to scale all other elements. The scaling factor is then */
/* contained in the `units_per_em' value. */
matrix->xx = cff_parse_fixed_dynamic( data++, &scaling );
max_scaling = FT_LONG_MIN;
min_scaling = FT_LONG_MAX;
scaling = -scaling;
for ( i = 0; i < 6; i++ )
{
values[i] = cff_parse_fixed_dynamic( data++, &scalings[i] );
if ( values[i] )
{
if ( scalings[i] > max_scaling )
max_scaling = scalings[i];
if ( scalings[i] < min_scaling )
min_scaling = scalings[i];
}
}
if ( scaling < 0 || scaling > 9 )
if ( max_scaling < -9 ||
max_scaling > 0 ||
( max_scaling - min_scaling ) < 0 ||
( max_scaling - min_scaling ) > 9 )
{
/* Return default matrix in case of unlikely values. */
FT_TRACE1(( "cff_parse_font_matrix:"
" strange scaling value for xx element (%d),\n"
" strange scaling values (minimum %d, maximum %d),\n"
" "
" using default matrix\n", scaling ));
" using default matrix\n", min_scaling, max_scaling ));
matrix->xx = 0x10000L;
matrix->yx = 0;
@ -558,13 +576,42 @@
goto Exit;
}
matrix->yx = cff_parse_fixed_scaled( data++, scaling );
matrix->xy = cff_parse_fixed_scaled( data++, scaling );
matrix->yy = cff_parse_fixed_scaled( data++, scaling );
offset->x = cff_parse_fixed_scaled( data++, scaling );
offset->y = cff_parse_fixed_scaled( data, scaling );
for ( i = 0; i < 6; i++ )
{
FT_Fixed value = values[i];
FT_Long divisor, half_divisor;
*upm = (FT_ULong)power_tens[scaling];
if ( !value )
continue;
divisor = power_tens[max_scaling - scalings[i]];
half_divisor = divisor >> 1;
if ( value < 0 )
{
if ( FT_LONG_MIN + half_divisor < value )
values[i] = ( value - half_divisor ) / divisor;
else
values[i] = FT_LONG_MIN / divisor;
}
else
{
if ( FT_LONG_MAX - half_divisor > value )
values[i] = ( value + half_divisor ) / divisor;
else
values[i] = FT_LONG_MAX / divisor;
}
}
matrix->xx = values[0];
matrix->yx = values[1];
matrix->xy = values[2];
matrix->yy = values[3];
offset->x = values[4];
offset->y = values[5];
*upm = (FT_ULong)power_tens[-max_scaling];
FT_TRACE4(( " [%f %f %f %f %f %f]\n",
(double)matrix->xx / *upm / 65536,