diff options
| author | Po Lu | 2024-01-17 09:30:47 +0800 |
|---|---|---|
| committer | Po Lu | 2024-01-17 09:30:47 +0800 |
| commit | daec3e7b410cdb8deefbb241d056f8b42dfb40ac (patch) | |
| tree | 99f1df71c09e51bf9bec0534cf430d69a64bfb6a | |
| parent | f19f5604deb72c4d548702b2d9b8565805ffbca1 (diff) | |
| download | emacs-daec3e7b410cdb8deefbb241d056f8b42dfb40ac.tar.gz emacs-daec3e7b410cdb8deefbb241d056f8b42dfb40ac.zip | |
Increase accuracy of IP instruction
* src/sfnt.c (sfnt_interpret_ip): Avoid precision loss by
retrieving original positions from the unscaled outline,
whenever possible.
| -rw-r--r-- | src/sfnt.c | 86 |
1 files changed, 83 insertions, 3 deletions
diff --git a/src/sfnt.c b/src/sfnt.c index 2f0153b9a75..ca4c60e8e3a 100644 --- a/src/sfnt.c +++ b/src/sfnt.c | |||
| @@ -9640,6 +9640,8 @@ sfnt_interpret_ip (struct sfnt_interpreter *interpreter) | |||
| 9640 | sfnt_f26dot6 new_distance; | 9640 | sfnt_f26dot6 new_distance; |
| 9641 | uint32_t p; | 9641 | uint32_t p; |
| 9642 | sfnt_f26dot6 x, y, original_x, original_y; | 9642 | sfnt_f26dot6 x, y, original_x, original_y; |
| 9643 | struct sfnt_interpreter_zone *zone; | ||
| 9644 | bool scale; | ||
| 9643 | 9645 | ||
| 9644 | /* First load both reference points. */ | 9646 | /* First load both reference points. */ |
| 9645 | sfnt_address_zp0 (interpreter, interpreter->state.rp1, | 9647 | sfnt_address_zp0 (interpreter, interpreter->state.rp1, |
| @@ -9649,6 +9651,57 @@ sfnt_interpret_ip (struct sfnt_interpreter *interpreter) | |||
| 9649 | &rp2x, &rp2y, &rp2_original_x, | 9651 | &rp2x, &rp2y, &rp2_original_x, |
| 9650 | &rp2_original_y); | 9652 | &rp2_original_y); |
| 9651 | 9653 | ||
| 9654 | /* If RP1, RP2, and all arguments all fall within the glyph zone and | ||
| 9655 | a simple glyph is loaded, replace their original coordinates as | ||
| 9656 | loaded here with coordinates from the unscaled glyph outline. */ | ||
| 9657 | |||
| 9658 | zone = interpreter->glyph_zone; | ||
| 9659 | scale = false; | ||
| 9660 | |||
| 9661 | if (zone && zone->simple | ||
| 9662 | && interpreter->state.zp0 | ||
| 9663 | && interpreter->state.zp1 | ||
| 9664 | && interpreter->state.zp2) | ||
| 9665 | { | ||
| 9666 | p = interpreter->state.rp1; | ||
| 9667 | |||
| 9668 | /* If P is a phantom point... */ | ||
| 9669 | if (p >= zone->simple->number_of_points) | ||
| 9670 | { | ||
| 9671 | /* ...scale the phantom point to the size of the original | ||
| 9672 | outline. */ | ||
| 9673 | rp1_original_x = sfnt_div_fixed (rp1_original_x, | ||
| 9674 | interpreter->scale); | ||
| 9675 | rp1_original_y = sfnt_div_fixed (rp1_original_y, | ||
| 9676 | interpreter->scale); | ||
| 9677 | } | ||
| 9678 | else | ||
| 9679 | { | ||
| 9680 | rp1_original_x = zone->simple->x_coordinates[p]; | ||
| 9681 | rp1_original_y = zone->simple->y_coordinates[p]; | ||
| 9682 | } | ||
| 9683 | |||
| 9684 | p = interpreter->state.rp2; | ||
| 9685 | |||
| 9686 | /* If P is a phantom point... */ | ||
| 9687 | if (p >= zone->simple->number_of_points) | ||
| 9688 | { | ||
| 9689 | /* ...scale the phantom point to the size of the original | ||
| 9690 | outline. */ | ||
| 9691 | rp2_original_x = sfnt_div_fixed (rp2_original_x, | ||
| 9692 | interpreter->scale); | ||
| 9693 | rp2_original_y = sfnt_div_fixed (rp2_original_y, | ||
| 9694 | interpreter->scale); | ||
| 9695 | } | ||
| 9696 | else | ||
| 9697 | { | ||
| 9698 | rp2_original_x = zone->simple->x_coordinates[p]; | ||
| 9699 | rp2_original_y = zone->simple->y_coordinates[p]; | ||
| 9700 | } | ||
| 9701 | |||
| 9702 | scale = true; | ||
| 9703 | } | ||
| 9704 | |||
| 9652 | /* Get the original distance between of RP1 and RP2 measured | 9705 | /* Get the original distance between of RP1 and RP2 measured |
| 9653 | relative to the dual projection vector. */ | 9706 | relative to the dual projection vector. */ |
| 9654 | range = sfnt_dual_project_vector (interpreter, | 9707 | range = sfnt_dual_project_vector (interpreter, |
| @@ -9657,6 +9710,9 @@ sfnt_interpret_ip (struct sfnt_interpreter *interpreter) | |||
| 9657 | sfnt_sub (rp2_original_y, | 9710 | sfnt_sub (rp2_original_y, |
| 9658 | rp1_original_y)); | 9711 | rp1_original_y)); |
| 9659 | 9712 | ||
| 9713 | if (scale) | ||
| 9714 | range = sfnt_mul_fixed_round (range, interpreter->scale); | ||
| 9715 | |||
| 9660 | /* Get the new distance. */ | 9716 | /* Get the new distance. */ |
| 9661 | new_range = sfnt_dual_project_vector (interpreter, | 9717 | new_range = sfnt_dual_project_vector (interpreter, |
| 9662 | sfnt_sub (rp2x, rp1x), | 9718 | sfnt_sub (rp2x, rp1x), |
| @@ -9670,6 +9726,25 @@ sfnt_interpret_ip (struct sfnt_interpreter *interpreter) | |||
| 9670 | sfnt_address_zp2 (interpreter, p, &x, &y, &original_x, | 9726 | sfnt_address_zp2 (interpreter, p, &x, &y, &original_x, |
| 9671 | &original_y); | 9727 | &original_y); |
| 9672 | 9728 | ||
| 9729 | if (scale) | ||
| 9730 | { | ||
| 9731 | /* If P is a phantom point... */ | ||
| 9732 | if (p >= zone->simple->number_of_points) | ||
| 9733 | { | ||
| 9734 | /* ...scale the phantom point to the size of the original | ||
| 9735 | outline. */ | ||
| 9736 | original_x = sfnt_div_fixed (original_x, | ||
| 9737 | interpreter->scale); | ||
| 9738 | original_y = sfnt_div_fixed (original_y, | ||
| 9739 | interpreter->scale); | ||
| 9740 | } | ||
| 9741 | else | ||
| 9742 | { | ||
| 9743 | original_x = zone->simple->x_coordinates[p]; | ||
| 9744 | original_y = zone->simple->y_coordinates[p]; | ||
| 9745 | } | ||
| 9746 | } | ||
| 9747 | |||
| 9673 | /* Now compute the old distance from this point to rp1. */ | 9748 | /* Now compute the old distance from this point to rp1. */ |
| 9674 | org_distance | 9749 | org_distance |
| 9675 | = sfnt_dual_project_vector (interpreter, | 9750 | = sfnt_dual_project_vector (interpreter, |
| @@ -9678,6 +9753,10 @@ sfnt_interpret_ip (struct sfnt_interpreter *interpreter) | |||
| 9678 | sfnt_sub (original_y, | 9753 | sfnt_sub (original_y, |
| 9679 | rp1_original_y)); | 9754 | rp1_original_y)); |
| 9680 | 9755 | ||
| 9756 | if (scale) | ||
| 9757 | org_distance = sfnt_mul_fixed_round (org_distance, | ||
| 9758 | interpreter->scale); | ||
| 9759 | |||
| 9681 | /* And the current distance from this point to rp1, so | 9760 | /* And the current distance from this point to rp1, so |
| 9682 | how much to move can be determined. */ | 9761 | how much to move can be determined. */ |
| 9683 | cur_distance | 9762 | cur_distance |
| @@ -11447,7 +11526,8 @@ sfnt_interpret_mirp (struct sfnt_interpreter *interpreter, | |||
| 11447 | coordinate from the font designer's intentions, either exaggerating | 11526 | coordinate from the font designer's intentions, either exaggerating |
| 11448 | or neutralizing the slant of the stem to which it belongs. | 11527 | or neutralizing the slant of the stem to which it belongs. |
| 11449 | 11528 | ||
| 11450 | This behavior applies only to MDRP, which see. */ | 11529 | This behavior applies only to MDRP (which see), although a similar |
| 11530 | strategy is also applied while interpreting IP instructions. */ | ||
| 11451 | 11531 | ||
| 11452 | static sfnt_f26dot6 | 11532 | static sfnt_f26dot6 |
| 11453 | sfnt_project_zp1_zp0_org (struct sfnt_interpreter *interpreter, | 11533 | sfnt_project_zp1_zp0_org (struct sfnt_interpreter *interpreter, |
| @@ -20715,8 +20795,8 @@ main (int argc, char **argv) | |||
| 20715 | return 1; | 20795 | return 1; |
| 20716 | } | 20796 | } |
| 20717 | 20797 | ||
| 20718 | #define FANCY_PPEM 16 | 20798 | #define FANCY_PPEM 14 |
| 20719 | #define EASY_PPEM 16 | 20799 | #define EASY_PPEM 14 |
| 20720 | 20800 | ||
| 20721 | interpreter = NULL; | 20801 | interpreter = NULL; |
| 20722 | head = sfnt_read_head_table (fd, font); | 20802 | head = sfnt_read_head_table (fd, font); |