Increase accuracy of IP instruction
* src/sfnt.c (sfnt_interpret_ip): Avoid precision loss by retrieving original positions from the unscaled outline, whenever possible.
This commit is contained in:
parent
f19f5604de
commit
daec3e7b41
1 changed files with 83 additions and 3 deletions
86
src/sfnt.c
86
src/sfnt.c
|
@ -9640,6 +9640,8 @@ sfnt_interpret_ip (struct sfnt_interpreter *interpreter)
|
||||||
sfnt_f26dot6 new_distance;
|
sfnt_f26dot6 new_distance;
|
||||||
uint32_t p;
|
uint32_t p;
|
||||||
sfnt_f26dot6 x, y, original_x, original_y;
|
sfnt_f26dot6 x, y, original_x, original_y;
|
||||||
|
struct sfnt_interpreter_zone *zone;
|
||||||
|
bool scale;
|
||||||
|
|
||||||
/* First load both reference points. */
|
/* First load both reference points. */
|
||||||
sfnt_address_zp0 (interpreter, interpreter->state.rp1,
|
sfnt_address_zp0 (interpreter, interpreter->state.rp1,
|
||||||
|
@ -9649,6 +9651,57 @@ sfnt_interpret_ip (struct sfnt_interpreter *interpreter)
|
||||||
&rp2x, &rp2y, &rp2_original_x,
|
&rp2x, &rp2y, &rp2_original_x,
|
||||||
&rp2_original_y);
|
&rp2_original_y);
|
||||||
|
|
||||||
|
/* If RP1, RP2, and all arguments all fall within the glyph zone and
|
||||||
|
a simple glyph is loaded, replace their original coordinates as
|
||||||
|
loaded here with coordinates from the unscaled glyph outline. */
|
||||||
|
|
||||||
|
zone = interpreter->glyph_zone;
|
||||||
|
scale = false;
|
||||||
|
|
||||||
|
if (zone && zone->simple
|
||||||
|
&& interpreter->state.zp0
|
||||||
|
&& interpreter->state.zp1
|
||||||
|
&& interpreter->state.zp2)
|
||||||
|
{
|
||||||
|
p = interpreter->state.rp1;
|
||||||
|
|
||||||
|
/* If P is a phantom point... */
|
||||||
|
if (p >= zone->simple->number_of_points)
|
||||||
|
{
|
||||||
|
/* ...scale the phantom point to the size of the original
|
||||||
|
outline. */
|
||||||
|
rp1_original_x = sfnt_div_fixed (rp1_original_x,
|
||||||
|
interpreter->scale);
|
||||||
|
rp1_original_y = sfnt_div_fixed (rp1_original_y,
|
||||||
|
interpreter->scale);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
rp1_original_x = zone->simple->x_coordinates[p];
|
||||||
|
rp1_original_y = zone->simple->y_coordinates[p];
|
||||||
|
}
|
||||||
|
|
||||||
|
p = interpreter->state.rp2;
|
||||||
|
|
||||||
|
/* If P is a phantom point... */
|
||||||
|
if (p >= zone->simple->number_of_points)
|
||||||
|
{
|
||||||
|
/* ...scale the phantom point to the size of the original
|
||||||
|
outline. */
|
||||||
|
rp2_original_x = sfnt_div_fixed (rp2_original_x,
|
||||||
|
interpreter->scale);
|
||||||
|
rp2_original_y = sfnt_div_fixed (rp2_original_y,
|
||||||
|
interpreter->scale);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
rp2_original_x = zone->simple->x_coordinates[p];
|
||||||
|
rp2_original_y = zone->simple->y_coordinates[p];
|
||||||
|
}
|
||||||
|
|
||||||
|
scale = true;
|
||||||
|
}
|
||||||
|
|
||||||
/* Get the original distance between of RP1 and RP2 measured
|
/* Get the original distance between of RP1 and RP2 measured
|
||||||
relative to the dual projection vector. */
|
relative to the dual projection vector. */
|
||||||
range = sfnt_dual_project_vector (interpreter,
|
range = sfnt_dual_project_vector (interpreter,
|
||||||
|
@ -9657,6 +9710,9 @@ sfnt_interpret_ip (struct sfnt_interpreter *interpreter)
|
||||||
sfnt_sub (rp2_original_y,
|
sfnt_sub (rp2_original_y,
|
||||||
rp1_original_y));
|
rp1_original_y));
|
||||||
|
|
||||||
|
if (scale)
|
||||||
|
range = sfnt_mul_fixed_round (range, interpreter->scale);
|
||||||
|
|
||||||
/* Get the new distance. */
|
/* Get the new distance. */
|
||||||
new_range = sfnt_dual_project_vector (interpreter,
|
new_range = sfnt_dual_project_vector (interpreter,
|
||||||
sfnt_sub (rp2x, rp1x),
|
sfnt_sub (rp2x, rp1x),
|
||||||
|
@ -9670,6 +9726,25 @@ sfnt_interpret_ip (struct sfnt_interpreter *interpreter)
|
||||||
sfnt_address_zp2 (interpreter, p, &x, &y, &original_x,
|
sfnt_address_zp2 (interpreter, p, &x, &y, &original_x,
|
||||||
&original_y);
|
&original_y);
|
||||||
|
|
||||||
|
if (scale)
|
||||||
|
{
|
||||||
|
/* If P is a phantom point... */
|
||||||
|
if (p >= zone->simple->number_of_points)
|
||||||
|
{
|
||||||
|
/* ...scale the phantom point to the size of the original
|
||||||
|
outline. */
|
||||||
|
original_x = sfnt_div_fixed (original_x,
|
||||||
|
interpreter->scale);
|
||||||
|
original_y = sfnt_div_fixed (original_y,
|
||||||
|
interpreter->scale);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
original_x = zone->simple->x_coordinates[p];
|
||||||
|
original_y = zone->simple->y_coordinates[p];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Now compute the old distance from this point to rp1. */
|
/* Now compute the old distance from this point to rp1. */
|
||||||
org_distance
|
org_distance
|
||||||
= sfnt_dual_project_vector (interpreter,
|
= sfnt_dual_project_vector (interpreter,
|
||||||
|
@ -9678,6 +9753,10 @@ sfnt_interpret_ip (struct sfnt_interpreter *interpreter)
|
||||||
sfnt_sub (original_y,
|
sfnt_sub (original_y,
|
||||||
rp1_original_y));
|
rp1_original_y));
|
||||||
|
|
||||||
|
if (scale)
|
||||||
|
org_distance = sfnt_mul_fixed_round (org_distance,
|
||||||
|
interpreter->scale);
|
||||||
|
|
||||||
/* And the current distance from this point to rp1, so
|
/* And the current distance from this point to rp1, so
|
||||||
how much to move can be determined. */
|
how much to move can be determined. */
|
||||||
cur_distance
|
cur_distance
|
||||||
|
@ -11447,7 +11526,8 @@ sfnt_interpret_mirp (struct sfnt_interpreter *interpreter,
|
||||||
coordinate from the font designer's intentions, either exaggerating
|
coordinate from the font designer's intentions, either exaggerating
|
||||||
or neutralizing the slant of the stem to which it belongs.
|
or neutralizing the slant of the stem to which it belongs.
|
||||||
|
|
||||||
This behavior applies only to MDRP, which see. */
|
This behavior applies only to MDRP (which see), although a similar
|
||||||
|
strategy is also applied while interpreting IP instructions. */
|
||||||
|
|
||||||
static sfnt_f26dot6
|
static sfnt_f26dot6
|
||||||
sfnt_project_zp1_zp0_org (struct sfnt_interpreter *interpreter,
|
sfnt_project_zp1_zp0_org (struct sfnt_interpreter *interpreter,
|
||||||
|
@ -20715,8 +20795,8 @@ main (int argc, char **argv)
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define FANCY_PPEM 16
|
#define FANCY_PPEM 14
|
||||||
#define EASY_PPEM 16
|
#define EASY_PPEM 14
|
||||||
|
|
||||||
interpreter = NULL;
|
interpreter = NULL;
|
||||||
head = sfnt_read_head_table (fd, font);
|
head = sfnt_read_head_table (fd, font);
|
||||||
|
|
Loading…
Add table
Reference in a new issue