aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPo Lu2024-01-20 09:30:04 +0800
committerPo Lu2024-01-20 09:30:04 +0800
commitb3e4fbe867f96a28c5dc9db19fcad2af5b4a4b7e (patch)
tree35a6cecddba06947f5d930734a071f29355ac844
parenta34b76cd663e39d9f5d30c4b0e49ba246fac0d63 (diff)
downloademacs-b3e4fbe867f96a28c5dc9db19fcad2af5b4a4b7e.tar.gz
emacs-b3e4fbe867f96a28c5dc9db19fcad2af5b4a4b7e.zip
Round projs computed executing IP/ISECT instructions and improve IUP
* src/sfnt.c (sfnt_multiply_divide_rounded): New function. (sfnt_multiply_divide_signed): Always round values, as fonts which rely on IP to move points in concert with prior motion and subsequently round such points with MDAP are sensitive to minor deviations in the behavior of the former instruction. (load_unscaled): New macro. (IUP_SINGLE_PAIR, sfnt_interpret_iup_1): Compute ratio w/ unscaled points if possible.
-rw-r--r--src/sfnt.c106
1 files changed, 75 insertions, 31 deletions
diff --git a/src/sfnt.c b/src/sfnt.c
index ca4c60e8e3a..88826e1b2c1 100644
--- a/src/sfnt.c
+++ b/src/sfnt.c
@@ -3767,7 +3767,23 @@ sfnt_multiply_divide_2 (struct sfnt_large_integer *ab,
3767 return q; 3767 return q;
3768} 3768}
3769 3769
3770#endif 3770/* Add the specified unsigned 32-bit N to the large integer
3771 INTEGER. */
3772
3773static void
3774sfnt_large_integer_add (struct sfnt_large_integer *integer,
3775 uint32_t n)
3776{
3777 struct sfnt_large_integer number;
3778
3779 number.low = integer->low + n;
3780 number.high = integer->high + (number.low
3781 < integer->low);
3782
3783 *integer = number;
3784}
3785
3786#endif /* !INT64_MAX */
3771 3787
3772/* Calculate (A * B) / C with no rounding and return the result, using 3788/* Calculate (A * B) / C with no rounding and return the result, using
3773 a 64 bit integer if necessary. */ 3789 a 64 bit integer if necessary. */
@@ -3780,32 +3796,37 @@ sfnt_multiply_divide (unsigned int a, unsigned int b, unsigned int c)
3780 3796
3781 sfnt_multiply_divide_1 (a, b, &temp); 3797 sfnt_multiply_divide_1 (a, b, &temp);
3782 return sfnt_multiply_divide_2 (&temp, c); 3798 return sfnt_multiply_divide_2 (&temp, c);
3783#else 3799#else /* INT64_MAX */
3784 uint64_t temp; 3800 uint64_t temp;
3785 3801
3786 temp = (uint64_t) a * (uint64_t) b; 3802 temp = (uint64_t) a * (uint64_t) b;
3787 return temp / c; 3803 return temp / c;
3788#endif 3804#endif /* !INT64_MAX */
3789} 3805}
3790 3806
3791#ifndef INT64_MAX 3807/* Calculate (A * B) / C with rounding and return the result, using a
3808 64 bit integer if necessary. */
3792 3809
3793/* Add the specified unsigned 32-bit N to the large integer 3810static unsigned int
3794 INTEGER. */ 3811sfnt_multiply_divide_rounded (unsigned int a, unsigned int b,
3795 3812 unsigned int c)
3796static void
3797sfnt_large_integer_add (struct sfnt_large_integer *integer,
3798 uint32_t n)
3799{ 3813{
3800 struct sfnt_large_integer number; 3814#ifndef INT64_MAX
3815 struct sfnt_large_integer temp;
3801 3816
3802 number.low = integer->low + n; 3817 sfnt_multiply_divide_1 (a, b, &temp);
3803 number.high = integer->high + (number.low 3818 sfnt_large_integer_add (&temp, c / 2);
3804 < integer->low); 3819 return sfnt_multiply_divide_2 (&temp, c);
3820#else /* INT64_MAX */
3821 uint64_t temp;
3805 3822
3806 *integer = number; 3823 temp = (uint64_t) a * (uint64_t) b + c / 2;
3824 return temp / c;
3825#endif /* !INT64_MAX */
3807} 3826}
3808 3827
3828#ifndef INT64_MAX
3829
3809/* Calculate (A * B) / C, rounding the result with a threshold of N. 3830/* Calculate (A * B) / C, rounding the result with a threshold of N.
3810 Use a 64 bit temporary. */ 3831 Use a 64 bit temporary. */
3811 3832
@@ -3820,9 +3841,9 @@ sfnt_multiply_divide_round (unsigned int a, unsigned int b,
3820 return sfnt_multiply_divide_2 (&temp, c); 3841 return sfnt_multiply_divide_2 (&temp, c);
3821} 3842}
3822 3843
3823#endif /* INT64_MAX */ 3844#endif /* !INT64_MAX */
3824 3845
3825/* The same as sfnt_multiply_divide, but handle signed values 3846/* The same as sfnt_multiply_divide_rounded, but handle signed values
3826 instead. */ 3847 instead. */
3827 3848
3828MAYBE_UNUSED static int 3849MAYBE_UNUSED static int
@@ -3841,8 +3862,8 @@ sfnt_multiply_divide_signed (int a, int b, int c)
3841 if (c < 0) 3862 if (c < 0)
3842 sign = -sign; 3863 sign = -sign;
3843 3864
3844 return (sfnt_multiply_divide (abs (a), abs (b), abs (c)) 3865 return (sfnt_multiply_divide_rounded (abs (a), abs (b),
3845 * sign); 3866 abs (c)) * sign);
3846} 3867}
3847 3868
3848/* Multiply the two 16.16 fixed point numbers X and Y. Return the 3869/* Multiply the two 16.16 fixed point numbers X and Y. Return the
@@ -3858,7 +3879,7 @@ sfnt_mul_fixed (sfnt_fixed x, sfnt_fixed y)
3858 3879
3859 /* This can be done quickly with int64_t. */ 3880 /* This can be done quickly with int64_t. */
3860 return product / (int64_t) 65536; 3881 return product / (int64_t) 65536;
3861#else 3882#else /* !INT64_MAX */
3862 int sign; 3883 int sign;
3863 3884
3864 sign = 1; 3885 sign = 1;
@@ -3871,7 +3892,7 @@ sfnt_mul_fixed (sfnt_fixed x, sfnt_fixed y)
3871 3892
3872 return sfnt_multiply_divide (abs (x), abs (y), 3893 return sfnt_multiply_divide (abs (x), abs (y),
3873 65536) * sign; 3894 65536) * sign;
3874#endif 3895#endif /* INT64_MAX */
3875} 3896}
3876 3897
3877/* Multiply the two 16.16 fixed point numbers X and Y, with rounding 3898/* Multiply the two 16.16 fixed point numbers X and Y, with rounding
@@ -3888,7 +3909,7 @@ sfnt_mul_fixed_round (sfnt_fixed x, sfnt_fixed y)
3888 3909
3889 /* This can be done quickly with int64_t. */ 3910 /* This can be done quickly with int64_t. */
3890 return (product + round) / (int64_t) 65536; 3911 return (product + round) / (int64_t) 65536;
3891#else 3912#else /* !INT64_MAX */
3892 int sign; 3913 int sign;
3893 3914
3894 sign = 1; 3915 sign = 1;
@@ -3901,7 +3922,7 @@ sfnt_mul_fixed_round (sfnt_fixed x, sfnt_fixed y)
3901 3922
3902 return sfnt_multiply_divide_round (abs (x), abs (y), 3923 return sfnt_multiply_divide_round (abs (x), abs (y),
3903 32768, 65536) * sign; 3924 32768, 65536) * sign;
3904#endif 3925#endif /* INT64_MAX */
3905} 3926}
3906 3927
3907/* Set the pen size to the specified point and return. POINT will be 3928/* Set the pen size to the specified point and return. POINT will be
@@ -6542,7 +6563,7 @@ sfnt_mul_f26dot6_fixed (sfnt_f26dot6 x, sfnt_fixed y)
6542 sign = -sign; 6563 sign = -sign;
6543 6564
6544 sfnt_multiply_divide_1 (abs (x), abs (y), &temp); 6565 sfnt_multiply_divide_1 (abs (x), abs (y), &temp);
6545 sfnt_large_integer_add (&temp, 32676); 6566 sfnt_large_integer_add (&temp, 32768);
6546 return sfnt_multiply_divide_2 (&temp, 65536) * sign; 6567 return sfnt_multiply_divide_2 (&temp, 65536) * sign;
6547#endif 6568#endif
6548} 6569}
@@ -11137,6 +11158,11 @@ sfnt_interpret_shp (struct sfnt_interpreter *interpreter,
11137 ? interpreter->glyph_zone->x_points[p] \ 11158 ? interpreter->glyph_zone->x_points[p] \
11138 : interpreter->glyph_zone->y_points[p]) 11159 : interpreter->glyph_zone->y_points[p])
11139 11160
11161#define load_unscaled(p) \
11162 (opcode == 0x31 \
11163 ? interpreter->glyph_zone->simple->x_coordinates[p] \
11164 : interpreter->glyph_zone->simple->y_coordinates[p])
11165
11140#define IUP_SINGLE_PAIR() \ 11166#define IUP_SINGLE_PAIR() \
11141 /* Now make touch_start the first point before, i.e. the first \ 11167 /* Now make touch_start the first point before, i.e. the first \
11142 touched point in this pair. */ \ 11168 touched point in this pair. */ \
@@ -11186,23 +11212,40 @@ sfnt_interpret_shp (struct sfnt_interpreter *interpreter,
11186 if (position >= original_min_pos \ 11212 if (position >= original_min_pos \
11187 && position <= original_max_pos) \ 11213 && position <= original_max_pos) \
11188 { \ 11214 { \
11215 /* Compute the ratio between the two touched point positions \
11216 and the original position of the point being touched with \
11217 positions from the unscaled outline, if at all \
11218 possible. */ \
11219 \
11220 if (interpreter->glyph_zone->simple) \
11221 { \
11222 org_max_pos = load_unscaled (point_max); \
11223 org_min_pos = load_unscaled (point_min); \
11224 position = load_unscaled (i); \
11225 } \
11226 else \
11227 { \
11228 org_max_pos = original_max_pos; \
11229 org_min_pos = original_min_pos; \
11230 } \
11231 \
11189 /* Handle the degenerate case where original_min_pos and \ 11232 /* Handle the degenerate case where original_min_pos and \
11190 original_max_pos have not changed by placing the point in \ 11233 original_max_pos have not changed by placing the point in \
11191 the middle. */ \ 11234 the middle. */ \
11192 if (original_min_pos == original_max_pos) \ 11235 if (org_min_pos == org_max_pos) \
11193 ratio = 077777; \ 11236 ratio = 077777; \
11194 else \ 11237 else \
11195 /* ... preserve the ratio of i between min_pos and \ 11238 /* ... preserve the ratio of i between min_pos and \
11196 max_pos... */ \ 11239 max_pos... */ \
11197 ratio = sfnt_div_fixed ((sfnt_sub (position, \ 11240 ratio = sfnt_div_fixed ((sfnt_sub (position, \
11198 original_min_pos) \ 11241 org_min_pos) \
11199 * 1024), \ 11242 * 1024), \
11200 (sfnt_sub (original_max_pos, \ 11243 (sfnt_sub (org_max_pos, \
11201 original_min_pos) \ 11244 org_min_pos) \
11202 * 1024)); \ 11245 * 1024)); \
11203 \ 11246 \
11204 delta = sfnt_sub (max_pos, min_pos); \ 11247 delta = sfnt_sub (max_pos, min_pos); \
11205 delta = sfnt_mul_fixed (ratio, delta); \ 11248 delta = sfnt_mul_fixed_round (ratio, delta); \
11206 store_point (i, sfnt_add (min_pos, delta)); \ 11249 store_point (i, sfnt_add (min_pos, delta)); \
11207 } \ 11250 } \
11208 else \ 11251 else \
@@ -11237,8 +11280,8 @@ sfnt_interpret_iup_1 (struct sfnt_interpreter *interpreter,
11237 size_t first_point; 11280 size_t first_point;
11238 size_t point_min, point_max, i; 11281 size_t point_min, point_max, i;
11239 sfnt_f26dot6 position, min_pos, max_pos, delta, ratio; 11282 sfnt_f26dot6 position, min_pos, max_pos, delta, ratio;
11240 sfnt_f26dot6 original_max_pos; 11283 sfnt_f26dot6 original_max_pos, org_max_pos;
11241 sfnt_f26dot6 original_min_pos; 11284 sfnt_f26dot6 original_min_pos, org_min_pos;
11242 11285
11243 /* Find the first touched point. If none is found, simply 11286 /* Find the first touched point. If none is found, simply
11244 return. */ 11287 return. */
@@ -11324,6 +11367,7 @@ sfnt_interpret_iup_1 (struct sfnt_interpreter *interpreter,
11324#undef load_point 11367#undef load_point
11325#undef store_point 11368#undef store_point
11326#undef load_original 11369#undef load_original
11370#undef load_unscaled
11327 11371
11328/* Interpret an IUP (``interpolate untouched points'') instruction. 11372/* Interpret an IUP (``interpolate untouched points'') instruction.
11329 INTERPRETER is the interpreter, and OPCODE is the instruction 11373 INTERPRETER is the interpreter, and OPCODE is the instruction