diff options
author | Po Lu <luangruo@yahoo.com> | 2024-01-02 12:26:57 +0800 |
---|---|---|
committer | Po Lu <luangruo@yahoo.com> | 2024-01-02 12:27:19 +0800 |
commit | ce7a95711c0746eb7320ea18799b66599764c49a (patch) | |
tree | c41eedc0595f0acc0e4b055efa7be6b3976a90a1 | |
parent | f77840a5526e40c381a9208a0c5097f652be8e03 (diff) | |
download | emacs-ce7a95711c0746eb7320ea18799b66599764c49a.tar.gz |
Improve rounding of projection vector versors
* src/sfnt.c (sfnt_short_frac_dot): New function.
(sfnt_validate_gs): Guarantee dot product of freedom and
projection vectors are properly rounded. If the final product
is short of 1/16th of a vector, reset it to an entire vector.
-rw-r--r-- | src/sfnt.c | 26 |
1 files changed, 21 insertions, 5 deletions
diff --git a/src/sfnt.c b/src/sfnt.c index ead41b89025..e66292c6ad8 100644 --- a/src/sfnt.c +++ b/src/sfnt.c @@ -10721,6 +10721,15 @@ sfnt_move (sfnt_f26dot6 *restrict x, sfnt_f26dot6 *restrict y, } } +/* Compute the dot product of the two versors A and B with + rounding. */ + +static sfnt_f2dot14 +sfnt_short_frac_dot (sfnt_f2dot14 a, sfnt_f2dot14 b) +{ + return (sfnt_f2dot14) ((((long) a * b) + 8192) / 16384); +} + /* Validate the graphics state GS. Establish function pointers for rounding and projection. Establish dot product used to convert vector distances between @@ -10797,11 +10806,18 @@ sfnt_validate_gs (struct sfnt_graphics_state *gs) gs->vector_dot_product = gs->projection_vector.y; else /* Actually calculate the dot product. */ - gs->vector_dot_product = ((((long) gs->projection_vector.x - * gs->freedom_vector.x) - + ((long) gs->projection_vector.y - * gs->freedom_vector.y)) - / 16384); + gs->vector_dot_product = (sfnt_short_frac_dot (gs->projection_vector.x, + gs->freedom_vector.x) + + sfnt_short_frac_dot (gs->projection_vector.y, + gs->freedom_vector.y)); + + /* If the product is less than 1/16th of a vector, prevent overflow + by resetting it to 1. */ + + if (gs->vector_dot_product > -0x400 + && gs->vector_dot_product < 0x400) + gs->vector_dot_product = (gs->vector_dot_product < 0 + ? -0x4000 : 0x4000); /* Now figure out which function to use to move distances. Handle the common case where both the freedom and projection vectors are |