diff options
| author | Po Lu | 2023-02-16 23:57:01 +0800 |
|---|---|---|
| committer | Po Lu | 2023-02-16 23:57:01 +0800 |
| commit | 2dcce30290dc7782e9de3b4adf59f38b42408c98 (patch) | |
| tree | 67b79ee1049c8fa31c8fdc2c9c67df77ac4e86ee /src | |
| parent | cf24b61985c26cbf2e5a24cb0b64a8528aa3a9cc (diff) | |
| download | emacs-2dcce30290dc7782e9de3b4adf59f38b42408c98.tar.gz emacs-2dcce30290dc7782e9de3b4adf59f38b42408c98.zip | |
Update Android port
* doc/emacs/android.texi (Android Fonts):
* doc/emacs/input.texi (On-Screen Keyboards):
* doc/lispref/commands.texi (Misc Events): Update documentation.
* java/org/gnu/emacs/EmacsInputConnection.java (setSelection):
New function.
* java/org/gnu/emacs/EmacsSurfaceView.java (EmacsSurfaceView)
(reconfigureFrontBuffer): Make bitmap references weak
references.
* java/org/gnu/emacs/EmacsView.java (handleDirtyBitmap): Don't
clear surfaceView bitmap.
* lisp/comint.el (comint-mode):
* lisp/international/fontset.el (script-representative-chars)
(setup-default-fontset): Improve detection of CJK fonts.
* lisp/isearch.el (set-text-conversion-style): New variable.
(isearch-mode, isearch-done): Save and restore the text
conversion style.
* lisp/minibuffer.el (minibuffer-mode): Set an appropriate text
conversion style.
* lisp/simple.el (analyze-text-conversion): Run
post-self-insert-hook properly.
* lisp/subr.el (read-char-from-minibuffer): Disable text
conversion when reading character.
* src/androidterm.c (show_back_buffer): Don't check that F is
not garbaged.
(android_update_selection, android_reset_conversion): Use the
ephemeral last point and handle text conversion being disabled.
* src/buffer.c (syms_of_buffer): Convert old style DEFVAR.
* src/keyboard.c (kbd_buffer_get_event): Handle text conversion
first.
* src/lisp.h: Update prototypes.
* src/lread.c (read_filtered_event): Temporarily disable text
conversion.
* src/sfnt.c (sfnt_decompose_glyph_1, sfnt_decompose_glyph_2):
New functions.
(sfnt_decompose_glyph, sfnt_decompose_instructed_outline):
Refactor contour decomposition to those two functions.
(main): Update tests.
* src/sfntfont-android.c (system_font_directories): Add empty
field.
(Fandroid_enumerate_fonts, init_sfntfont_android): Enumerate
fonts in a user fonts directory.
* src/sfntfont.c (struct sfnt_font_desc): New field
`num_glyphs'.
(sfnt_enum_font_1): Set num_glyphs and avoid duplicate fonts.
(sfntfont_glyph_valid): New function.
(sfntfont_lookup_char, sfntfont_list_1): Make sure glyphs found
are valid.
* src/textconv.c (sync_overlay, really_commit_text)
(really_set_composing_text, really_set_composing_region)
(really_delete_surrounding_text, really_set_point_and_mark)
(handle_pending_conversion_events_1)
(handle_pending_conversion_events, conversion_disabled_p)
(disable_text_conversion, resume_text_conversion)
(Fset_text_conversion_style, syms_of_textconv): Update to
respect new options.
* src/textconv.h:
* src/window.h (GCALIGNED_STRUCT): New field
`ephemeral_last_point'.
* src/xdisp.c (mark_window_display_accurate_1): Set it.
Diffstat (limited to 'src')
| -rw-r--r-- | src/androidterm.c | 25 | ||||
| -rw-r--r-- | src/buffer.c | 22 | ||||
| -rw-r--r-- | src/keyboard.c | 39 | ||||
| -rw-r--r-- | src/lisp.h | 2 | ||||
| -rw-r--r-- | src/lread.c | 26 | ||||
| -rw-r--r-- | src/sfnt.c | 625 | ||||
| -rw-r--r-- | src/sfntfont-android.c | 13 | ||||
| -rw-r--r-- | src/sfntfont.c | 87 | ||||
| -rw-r--r-- | src/textconv.c | 234 | ||||
| -rw-r--r-- | src/textconv.h | 1 | ||||
| -rw-r--r-- | src/window.h | 15 | ||||
| -rw-r--r-- | src/xdisp.c | 3 |
12 files changed, 702 insertions, 390 deletions
diff --git a/src/androidterm.c b/src/androidterm.c index 0c990d3d2d2..c6f75ec9219 100644 --- a/src/androidterm.c +++ b/src/androidterm.c | |||
| @@ -258,10 +258,6 @@ show_back_buffer (struct frame *f) | |||
| 258 | { | 258 | { |
| 259 | struct android_swap_info swap_info; | 259 | struct android_swap_info swap_info; |
| 260 | 260 | ||
| 261 | /* Somehow Android frames can be swapped while garbaged. */ | ||
| 262 | if (FRAME_GARBAGED_P (f)) | ||
| 263 | return; | ||
| 264 | |||
| 265 | memset (&swap_info, 0, sizeof (swap_info)); | 261 | memset (&swap_info, 0, sizeof (swap_info)); |
| 266 | swap_info.swap_window = FRAME_ANDROID_WINDOW (f); | 262 | swap_info.swap_window = FRAME_ANDROID_WINDOW (f); |
| 267 | swap_info.swap_action = ANDROID_COPIED; | 263 | swap_info.swap_action = ANDROID_COPIED; |
| @@ -5128,7 +5124,8 @@ android_update_selection (struct frame *f, struct window *w) | |||
| 5128 | /* Figure out where the point and mark are. If the mark is not | 5124 | /* Figure out where the point and mark are. If the mark is not |
| 5129 | active, then point is set to equal mark. */ | 5125 | active, then point is set to equal mark. */ |
| 5130 | b = XBUFFER (w->contents); | 5126 | b = XBUFFER (w->contents); |
| 5131 | point = min (w->last_point, TYPE_MAXIMUM (jint)); | 5127 | point = min (w->ephemeral_last_point, |
| 5128 | TYPE_MAXIMUM (jint)); | ||
| 5132 | mark = ((!NILP (BVAR (b, mark_active)) | 5129 | mark = ((!NILP (BVAR (b, mark_active)) |
| 5133 | && w->last_mark != -1) | 5130 | && w->last_mark != -1) |
| 5134 | ? min (w->last_mark, TYPE_MAXIMUM (jint)) | 5131 | ? min (w->last_mark, TYPE_MAXIMUM (jint)) |
| @@ -5150,6 +5147,7 @@ android_reset_conversion (struct frame *f) | |||
| 5150 | enum android_ic_mode mode; | 5147 | enum android_ic_mode mode; |
| 5151 | struct window *w; | 5148 | struct window *w; |
| 5152 | struct buffer *buffer; | 5149 | struct buffer *buffer; |
| 5150 | Lisp_Object style; | ||
| 5153 | 5151 | ||
| 5154 | /* Reset the input method. | 5152 | /* Reset the input method. |
| 5155 | 5153 | ||
| @@ -5160,19 +5158,20 @@ android_reset_conversion (struct frame *f) | |||
| 5160 | w = XWINDOW (f->selected_window); | 5158 | w = XWINDOW (f->selected_window); |
| 5161 | buffer = XBUFFER (WINDOW_BUFFER (w)); | 5159 | buffer = XBUFFER (WINDOW_BUFFER (w)); |
| 5162 | 5160 | ||
| 5163 | if (NILP (BVAR (buffer, text_conversion_style))) | 5161 | style = (EQ (find_symbol_value (Qoverriding_text_conversion_style), |
| 5162 | Qlambda) | ||
| 5163 | ? BVAR (buffer, text_conversion_style) | ||
| 5164 | : find_symbol_value (Qoverriding_text_conversion_style)); | ||
| 5165 | |||
| 5166 | if (NILP (style) || conversion_disabled_p ()) | ||
| 5164 | mode = ANDROID_IC_MODE_NULL; | 5167 | mode = ANDROID_IC_MODE_NULL; |
| 5165 | else if (EQ (BVAR (buffer, text_conversion_style), | 5168 | else if (EQ (style, Qaction) || EQ (f->selected_window, |
| 5166 | Qaction)) | 5169 | f->minibuffer_window)) |
| 5167 | mode = ANDROID_IC_MODE_ACTION; | 5170 | mode = ANDROID_IC_MODE_ACTION; |
| 5168 | else | 5171 | else |
| 5169 | mode = ANDROID_IC_MODE_TEXT; | 5172 | mode = ANDROID_IC_MODE_TEXT; |
| 5170 | 5173 | ||
| 5171 | android_reset_ic (FRAME_ANDROID_WINDOW (f), | 5174 | android_reset_ic (FRAME_ANDROID_WINDOW (f), mode); |
| 5172 | (EQ (f->selected_window, | ||
| 5173 | f->minibuffer_window) | ||
| 5174 | ? ANDROID_IC_MODE_ACTION | ||
| 5175 | : mode)); | ||
| 5176 | 5175 | ||
| 5177 | /* Move its selection to the specified position. */ | 5176 | /* Move its selection to the specified position. */ |
| 5178 | android_update_selection (f, NULL); | 5177 | android_update_selection (f, NULL); |
diff --git a/src/buffer.c b/src/buffer.c index af4aa583c96..393b8c5340a 100644 --- a/src/buffer.c +++ b/src/buffer.c | |||
| @@ -5862,15 +5862,19 @@ Use Custom to set this variable and update the display. */); | |||
| 5862 | DEFVAR_PER_BUFFER ("text-conversion-style", &BVAR (current_buffer, | 5862 | DEFVAR_PER_BUFFER ("text-conversion-style", &BVAR (current_buffer, |
| 5863 | text_conversion_style), | 5863 | text_conversion_style), |
| 5864 | Qnil, | 5864 | Qnil, |
| 5865 | "How the on screen keyboard's input method should insert in this buffer.\n\ | 5865 | doc: /* How the on screen keyboard's input method should insert in this buffer. |
| 5866 | When nil, the input method will be disabled and an ordinary keyboard\n\ | 5866 | When nil, the input method will be disabled and an ordinary keyboard |
| 5867 | will be displayed in its place.\n\ | 5867 | will be displayed in its place. |
| 5868 | When the symbol `action', the input method will insert text directly, but\n\ | 5868 | When the symbol `action', the input method will insert text directly, but |
| 5869 | will send `return' key events instead of inserting new line characters.\n\ | 5869 | will send `return' key events instead of inserting new line characters. |
| 5870 | Any other value means that the input method will insert text directly.\n\ | 5870 | Any other value means that the input method will insert text directly. |
| 5871 | \n\ | 5871 | |
| 5872 | This variable does not take immediate effect when set; rather, it takes\n\ | 5872 | If you need to make non-buffer local changes to this variable, use |
| 5873 | effect upon the next redisplay after the selected window or buffer changes."); | 5873 | `overriding-text-conversion-style', which see. |
| 5874 | |||
| 5875 | This variable does not take immediate effect when set; rather, it | ||
| 5876 | takes effect upon the next redisplay after the selected window or | ||
| 5877 | buffer changes. */); | ||
| 5874 | 5878 | ||
| 5875 | DEFVAR_LISP ("kill-buffer-query-functions", Vkill_buffer_query_functions, | 5879 | DEFVAR_LISP ("kill-buffer-query-functions", Vkill_buffer_query_functions, |
| 5876 | doc: /* List of functions called with no args to query before killing a buffer. | 5880 | doc: /* List of functions called with no args to query before killing a buffer. |
diff --git a/src/keyboard.c b/src/keyboard.c index 538fdffc199..a8062adc468 100644 --- a/src/keyboard.c +++ b/src/keyboard.c | |||
| @@ -4050,14 +4050,6 @@ kbd_buffer_get_event (KBOARD **kbp, | |||
| 4050 | x_handle_pending_selection_requests (); | 4050 | x_handle_pending_selection_requests (); |
| 4051 | #endif | 4051 | #endif |
| 4052 | 4052 | ||
| 4053 | #ifdef HAVE_TEXT_CONVERSION | ||
| 4054 | /* Handle pending ``text conversion'' requests from an input | ||
| 4055 | method. */ | ||
| 4056 | |||
| 4057 | if (had_pending_conversion_events) | ||
| 4058 | handle_pending_conversion_events (); | ||
| 4059 | #endif | ||
| 4060 | |||
| 4061 | if (CONSP (Vunread_command_events)) | 4053 | if (CONSP (Vunread_command_events)) |
| 4062 | { | 4054 | { |
| 4063 | Lisp_Object first; | 4055 | Lisp_Object first; |
| @@ -4067,6 +4059,24 @@ kbd_buffer_get_event (KBOARD **kbp, | |||
| 4067 | return first; | 4059 | return first; |
| 4068 | } | 4060 | } |
| 4069 | 4061 | ||
| 4062 | #ifdef HAVE_TEXT_CONVERSION | ||
| 4063 | /* There are pending text conversion operations. Text conversion | ||
| 4064 | events should be generated before processing any other keyboard | ||
| 4065 | input. */ | ||
| 4066 | if (had_pending_conversion_events) | ||
| 4067 | { | ||
| 4068 | handle_pending_conversion_events (); | ||
| 4069 | obj = Qtext_conversion; | ||
| 4070 | |||
| 4071 | /* See the comment in handle_pending_conversion_events_1. | ||
| 4072 | Note that in addition, text conversion events are not | ||
| 4073 | generated if no edits were actually made. */ | ||
| 4074 | if (conversion_disabled_p () | ||
| 4075 | || NILP (Vtext_conversion_edits)) | ||
| 4076 | obj = Qnil; | ||
| 4077 | } | ||
| 4078 | else | ||
| 4079 | #endif | ||
| 4070 | /* At this point, we know that there is a readable event available | 4080 | /* At this point, we know that there is a readable event available |
| 4071 | somewhere. If the event queue is empty, then there must be a | 4081 | somewhere. If the event queue is empty, then there must be a |
| 4072 | mouse movement enabled and available. */ | 4082 | mouse movement enabled and available. */ |
| @@ -4415,24 +4425,11 @@ kbd_buffer_get_event (KBOARD **kbp, | |||
| 4415 | else if (had_pending_selection_requests) | 4425 | else if (had_pending_selection_requests) |
| 4416 | obj = Qnil; | 4426 | obj = Qnil; |
| 4417 | #endif | 4427 | #endif |
| 4418 | #ifdef HAVE_TEXT_CONVERSION | ||
| 4419 | /* This is an internal event used to prevent Emacs from becoming | ||
| 4420 | idle immediately after a text conversion operation. */ | ||
| 4421 | else if (had_pending_conversion_events) | ||
| 4422 | obj = Qtext_conversion; | ||
| 4423 | #endif | ||
| 4424 | else | 4428 | else |
| 4425 | /* We were promised by the above while loop that there was | 4429 | /* We were promised by the above while loop that there was |
| 4426 | something for us to read! */ | 4430 | something for us to read! */ |
| 4427 | emacs_abort (); | 4431 | emacs_abort (); |
| 4428 | 4432 | ||
| 4429 | #ifdef HAVE_TEXT_CONVERSION | ||
| 4430 | /* While not implemented as keyboard commands, changes made by the | ||
| 4431 | input method still mean that Emacs is no longer idle. */ | ||
| 4432 | if (had_pending_conversion_events) | ||
| 4433 | timer_stop_idle (); | ||
| 4434 | #endif | ||
| 4435 | |||
| 4436 | input_pending = readable_events (0); | 4433 | input_pending = readable_events (0); |
| 4437 | 4434 | ||
| 4438 | Vlast_event_frame = internal_last_event_frame; | 4435 | Vlast_event_frame = internal_last_event_frame; |
diff --git a/src/lisp.h b/src/lisp.h index a39ca8cc541..56ef338a5b1 100644 --- a/src/lisp.h +++ b/src/lisp.h | |||
| @@ -5234,6 +5234,8 @@ extern void reset_frame_state (struct frame *); | |||
| 5234 | extern void report_selected_window_change (struct frame *); | 5234 | extern void report_selected_window_change (struct frame *); |
| 5235 | extern void report_point_change (struct frame *, struct window *, | 5235 | extern void report_point_change (struct frame *, struct window *, |
| 5236 | struct buffer *); | 5236 | struct buffer *); |
| 5237 | extern void disable_text_conversion (void); | ||
| 5238 | extern void resume_text_conversion (void); | ||
| 5237 | extern void syms_of_textconv (void); | 5239 | extern void syms_of_textconv (void); |
| 5238 | #endif | 5240 | #endif |
| 5239 | 5241 | ||
diff --git a/src/lread.c b/src/lread.c index 6abcea556bf..150d8a01e10 100644 --- a/src/lread.c +++ b/src/lread.c | |||
| @@ -672,7 +672,11 @@ static void substitute_in_interval (INTERVAL, void *); | |||
| 672 | if the character warrants that. | 672 | if the character warrants that. |
| 673 | 673 | ||
| 674 | If SECONDS is a number, wait that many seconds for input, and | 674 | If SECONDS is a number, wait that many seconds for input, and |
| 675 | return Qnil if no input arrives within that time. */ | 675 | return Qnil if no input arrives within that time. |
| 676 | |||
| 677 | If text conversion is enabled and ASCII_REQUIRED && ERROR_NONASCII, | ||
| 678 | temporarily disable any input method which wants to perform | ||
| 679 | edits. */ | ||
| 676 | 680 | ||
| 677 | static Lisp_Object | 681 | static Lisp_Object |
| 678 | read_filtered_event (bool no_switch_frame, bool ascii_required, | 682 | read_filtered_event (bool no_switch_frame, bool ascii_required, |
| @@ -680,12 +684,28 @@ read_filtered_event (bool no_switch_frame, bool ascii_required, | |||
| 680 | { | 684 | { |
| 681 | Lisp_Object val, delayed_switch_frame; | 685 | Lisp_Object val, delayed_switch_frame; |
| 682 | struct timespec end_time; | 686 | struct timespec end_time; |
| 687 | #ifdef HAVE_TEXT_CONVERSION | ||
| 688 | specpdl_ref count; | ||
| 689 | #endif | ||
| 683 | 690 | ||
| 684 | #ifdef HAVE_WINDOW_SYSTEM | 691 | #ifdef HAVE_WINDOW_SYSTEM |
| 685 | if (display_hourglass_p) | 692 | if (display_hourglass_p) |
| 686 | cancel_hourglass (); | 693 | cancel_hourglass (); |
| 687 | #endif | 694 | #endif |
| 688 | 695 | ||
| 696 | #ifdef HAVE_TEXT_CONVERSION | ||
| 697 | count = SPECPDL_INDEX (); | ||
| 698 | |||
| 699 | /* Don't use text conversion when trying to just read a | ||
| 700 | character. */ | ||
| 701 | |||
| 702 | if (ascii_required && error_nonascii) | ||
| 703 | { | ||
| 704 | disable_text_conversion (); | ||
| 705 | record_unwind_protect_void (resume_text_conversion); | ||
| 706 | } | ||
| 707 | #endif | ||
| 708 | |||
| 689 | delayed_switch_frame = Qnil; | 709 | delayed_switch_frame = Qnil; |
| 690 | 710 | ||
| 691 | /* Compute timeout. */ | 711 | /* Compute timeout. */ |
| @@ -761,7 +781,11 @@ read_filtered_event (bool no_switch_frame, bool ascii_required, | |||
| 761 | 781 | ||
| 762 | #endif | 782 | #endif |
| 763 | 783 | ||
| 784 | #ifdef HAVE_TEXT_CONVERSION | ||
| 785 | return unbind_to (count, val); | ||
| 786 | #else | ||
| 764 | return val; | 787 | return val; |
| 788 | #endif | ||
| 765 | } | 789 | } |
| 766 | 790 | ||
| 767 | DEFUN ("read-char", Fread_char, Sread_char, 0, 3, 0, | 791 | DEFUN ("read-char", Fread_char, Sread_char, 0, 3, 0, |
diff --git a/src/sfnt.c b/src/sfnt.c index 38f6984b93c..b6f4a48ea8b 100644 --- a/src/sfnt.c +++ b/src/sfnt.c | |||
| @@ -2708,6 +2708,281 @@ sfnt_lerp_half (struct sfnt_point *control1, struct sfnt_point *control2, | |||
| 2708 | result->y = control1->y + ((control2->y - control1->y) >> 1); | 2708 | result->y = control1->y + ((control2->y - control1->y) >> 1); |
| 2709 | } | 2709 | } |
| 2710 | 2710 | ||
| 2711 | /* Decompose contour data inside X, Y and FLAGS, between the indices | ||
| 2712 | HERE and LAST. Call LINE_TO, CURVE_TO and MOVE_TO as appropriate, | ||
| 2713 | with DCONTEXT as an argument. Apply SCALE to each point; SCALE | ||
| 2714 | should be the factor necessary to turn points into 16.16 fixed | ||
| 2715 | point. | ||
| 2716 | |||
| 2717 | Value is 1 upon failure, else 0. */ | ||
| 2718 | |||
| 2719 | static int | ||
| 2720 | sfnt_decompose_glyph_1 (size_t here, size_t last, | ||
| 2721 | sfnt_move_to_proc move_to, | ||
| 2722 | sfnt_line_to_proc line_to, | ||
| 2723 | sfnt_curve_to_proc curve_to, | ||
| 2724 | void *dcontext, | ||
| 2725 | sfnt_fword *x, | ||
| 2726 | sfnt_fword *y, unsigned char *flags, | ||
| 2727 | int scale) | ||
| 2728 | { | ||
| 2729 | struct sfnt_point control1, control2, start, mid; | ||
| 2730 | size_t i; | ||
| 2731 | |||
| 2732 | /* The contour is empty. */ | ||
| 2733 | |||
| 2734 | if (here == last) | ||
| 2735 | return 1; | ||
| 2736 | |||
| 2737 | /* Move the pen to the start of the contour. Apparently some fonts | ||
| 2738 | have off the curve points as the start of a contour, so when that | ||
| 2739 | happens lerp between the first and last points. */ | ||
| 2740 | |||
| 2741 | if (flags[here] & 01) /* On Curve */ | ||
| 2742 | { | ||
| 2743 | control1.x = x[here] * scale; | ||
| 2744 | control1.y = y[here] * scale; | ||
| 2745 | start = control1; | ||
| 2746 | } | ||
| 2747 | else if (flags[last] & 01) | ||
| 2748 | { | ||
| 2749 | /* Start at the last point if it is on the curve. Here, the | ||
| 2750 | start really becomes the middle of a spline. */ | ||
| 2751 | control1.x = x[last] * scale; | ||
| 2752 | control1.y = y[last] * scale; | ||
| 2753 | start = control1; | ||
| 2754 | |||
| 2755 | /* Curve back one point early. */ | ||
| 2756 | last -= 1; | ||
| 2757 | here -= 1; | ||
| 2758 | } | ||
| 2759 | else | ||
| 2760 | { | ||
| 2761 | /* Lerp between the start and the end. */ | ||
| 2762 | control1.x = x[here] * scale; | ||
| 2763 | control1.y = y[here] * scale; | ||
| 2764 | control2.x = x[last] * scale; | ||
| 2765 | control2.y = y[last] * scale; | ||
| 2766 | sfnt_lerp_half (&control1, &control2, &start); | ||
| 2767 | |||
| 2768 | /* In either of these cases, start iterating from just here as | ||
| 2769 | opposed to here + 1, since logically the contour now starts | ||
| 2770 | from the last curve. */ | ||
| 2771 | here -= 1; | ||
| 2772 | } | ||
| 2773 | |||
| 2774 | /* Move to the start. */ | ||
| 2775 | move_to (start, dcontext); | ||
| 2776 | |||
| 2777 | /* Now handle each point between here + 1 and last. */ | ||
| 2778 | |||
| 2779 | i = here; | ||
| 2780 | while (++i <= last) | ||
| 2781 | { | ||
| 2782 | /* If the point is on the curve, then draw a line here from the | ||
| 2783 | last control point. */ | ||
| 2784 | |||
| 2785 | if (flags[i] & 01) | ||
| 2786 | { | ||
| 2787 | control1.x = x[i] * scale; | ||
| 2788 | control1.y = y[i] * scale; | ||
| 2789 | |||
| 2790 | line_to (control1, dcontext); | ||
| 2791 | |||
| 2792 | /* Move to the next point. */ | ||
| 2793 | continue; | ||
| 2794 | } | ||
| 2795 | |||
| 2796 | /* Off the curve points are more interesting. They are handled | ||
| 2797 | one by one, with points in between being interpolated, until | ||
| 2798 | either the last point is reached or an on-curve point is | ||
| 2799 | processed. First, load the initial control points. */ | ||
| 2800 | |||
| 2801 | control1.x = x[i] * scale; | ||
| 2802 | control1.y = y[i] * scale; | ||
| 2803 | |||
| 2804 | while (++i <= last) | ||
| 2805 | { | ||
| 2806 | /* Load this point. */ | ||
| 2807 | control2.x = x[i] * scale; | ||
| 2808 | control2.y = y[i] * scale; | ||
| 2809 | |||
| 2810 | /* If this point is on the curve, curve directly to this | ||
| 2811 | point. */ | ||
| 2812 | |||
| 2813 | if (flags[i] & 01) | ||
| 2814 | { | ||
| 2815 | curve_to (control1, control2, dcontext); | ||
| 2816 | goto continue_loop; | ||
| 2817 | } | ||
| 2818 | |||
| 2819 | /* Calculate the point between here and the previous | ||
| 2820 | point. */ | ||
| 2821 | sfnt_lerp_half (&control1, &control2, &mid); | ||
| 2822 | |||
| 2823 | /* Curve over there. */ | ||
| 2824 | curve_to (control1, mid, dcontext); | ||
| 2825 | |||
| 2826 | /* Reload the control point. */ | ||
| 2827 | control1 = control2; | ||
| 2828 | } | ||
| 2829 | |||
| 2830 | /* Close the contour by curving back to start. */ | ||
| 2831 | curve_to (control1, start, dcontext); | ||
| 2832 | |||
| 2833 | /* Don't close the contour twice. */ | ||
| 2834 | goto exit; | ||
| 2835 | |||
| 2836 | continue_loop: | ||
| 2837 | continue; | ||
| 2838 | } | ||
| 2839 | |||
| 2840 | /* Close the contour with a line back to start. */ | ||
| 2841 | line_to (start, dcontext); | ||
| 2842 | |||
| 2843 | exit: | ||
| 2844 | return 0; | ||
| 2845 | } | ||
| 2846 | |||
| 2847 | /* Decompose contour data inside X, Y and FLAGS, between the indices | ||
| 2848 | HERE and LAST. Call LINE_TO, CURVE_TO and MOVE_TO as appropriate, | ||
| 2849 | with DCONTEXT as an argument. Apply SCALE to each point; SCALE | ||
| 2850 | should be the factor necessary to turn points into 16.16 fixed | ||
| 2851 | point. | ||
| 2852 | |||
| 2853 | This is the version of sfnt_decompose_glyph_1 which takes | ||
| 2854 | sfnt_fixed (or sfnt_f26dot6) as opposed to sfnt_fword. | ||
| 2855 | |||
| 2856 | Value is 1 upon failure, else 0. */ | ||
| 2857 | |||
| 2858 | static int | ||
| 2859 | sfnt_decompose_glyph_2 (size_t here, size_t last, | ||
| 2860 | sfnt_move_to_proc move_to, | ||
| 2861 | sfnt_line_to_proc line_to, | ||
| 2862 | sfnt_curve_to_proc curve_to, | ||
| 2863 | void *dcontext, | ||
| 2864 | sfnt_fixed *x, | ||
| 2865 | sfnt_fixed *y, unsigned char *flags, | ||
| 2866 | int scale) | ||
| 2867 | { | ||
| 2868 | struct sfnt_point control1, control2, start, mid; | ||
| 2869 | size_t i; | ||
| 2870 | |||
| 2871 | /* The contour is empty. */ | ||
| 2872 | |||
| 2873 | if (here == last) | ||
| 2874 | return 1; | ||
| 2875 | |||
| 2876 | /* Move the pen to the start of the contour. Apparently some fonts | ||
| 2877 | have off the curve points as the start of a contour, so when that | ||
| 2878 | happens lerp between the first and last points. */ | ||
| 2879 | |||
| 2880 | if (flags[here] & 01) /* On Curve */ | ||
| 2881 | { | ||
| 2882 | control1.x = x[here] * scale; | ||
| 2883 | control1.y = y[here] * scale; | ||
| 2884 | start = control1; | ||
| 2885 | } | ||
| 2886 | else if (flags[last] & 01) | ||
| 2887 | { | ||
| 2888 | /* Start at the last point if it is on the curve. Here, the | ||
| 2889 | start really becomes the middle of a spline. */ | ||
| 2890 | control1.x = x[last] * scale; | ||
| 2891 | control1.y = y[last] * scale; | ||
| 2892 | start = control1; | ||
| 2893 | |||
| 2894 | /* Curve back one point early. */ | ||
| 2895 | last -= 1; | ||
| 2896 | here -= 1; | ||
| 2897 | } | ||
| 2898 | else | ||
| 2899 | { | ||
| 2900 | /* Lerp between the start and the end. */ | ||
| 2901 | control1.x = x[here] * scale; | ||
| 2902 | control1.y = y[here] * scale; | ||
| 2903 | control2.x = x[last] * scale; | ||
| 2904 | control2.y = y[last] * scale; | ||
| 2905 | sfnt_lerp_half (&control1, &control2, &start); | ||
| 2906 | |||
| 2907 | /* In either of these cases, start iterating from just here as | ||
| 2908 | opposed to here + 1, since logically the contour now starts | ||
| 2909 | from the last curve. */ | ||
| 2910 | here -= 1; | ||
| 2911 | } | ||
| 2912 | |||
| 2913 | /* Move to the start. */ | ||
| 2914 | move_to (start, dcontext); | ||
| 2915 | |||
| 2916 | /* Now handle each point between here + 1 and last. */ | ||
| 2917 | |||
| 2918 | i = here; | ||
| 2919 | while (++i <= last) | ||
| 2920 | { | ||
| 2921 | /* If the point is on the curve, then draw a line here from the | ||
| 2922 | last control point. */ | ||
| 2923 | |||
| 2924 | if (flags[i] & 01) | ||
| 2925 | { | ||
| 2926 | control1.x = x[i] * scale; | ||
| 2927 | control1.y = y[i] * scale; | ||
| 2928 | |||
| 2929 | line_to (control1, dcontext); | ||
| 2930 | |||
| 2931 | /* Move to the next point. */ | ||
| 2932 | continue; | ||
| 2933 | } | ||
| 2934 | |||
| 2935 | /* Off the curve points are more interesting. They are handled | ||
| 2936 | one by one, with points in between being interpolated, until | ||
| 2937 | either the last point is reached or an on-curve point is | ||
| 2938 | processed. First, load the initial control points. */ | ||
| 2939 | |||
| 2940 | control1.x = x[i] * scale; | ||
| 2941 | control1.y = y[i] * scale; | ||
| 2942 | |||
| 2943 | while (++i <= last) | ||
| 2944 | { | ||
| 2945 | /* Load this point. */ | ||
| 2946 | control2.x = x[i] * scale; | ||
| 2947 | control2.y = y[i] * scale; | ||
| 2948 | |||
| 2949 | /* If this point is on the curve, curve directly to this | ||
| 2950 | point. */ | ||
| 2951 | |||
| 2952 | if (flags[i] & 01) | ||
| 2953 | { | ||
| 2954 | curve_to (control1, control2, dcontext); | ||
| 2955 | goto continue_loop; | ||
| 2956 | } | ||
| 2957 | |||
| 2958 | /* Calculate the point between here and the previous | ||
| 2959 | point. */ | ||
| 2960 | sfnt_lerp_half (&control1, &control2, &mid); | ||
| 2961 | |||
| 2962 | /* Curve over there. */ | ||
| 2963 | curve_to (control1, mid, dcontext); | ||
| 2964 | |||
| 2965 | /* Reload the control point. */ | ||
| 2966 | control1 = control2; | ||
| 2967 | } | ||
| 2968 | |||
| 2969 | /* Close the contour by curving back to start. */ | ||
| 2970 | curve_to (control1, start, dcontext); | ||
| 2971 | |||
| 2972 | /* Don't close the contour twice. */ | ||
| 2973 | goto exit; | ||
| 2974 | |||
| 2975 | continue_loop: | ||
| 2976 | continue; | ||
| 2977 | } | ||
| 2978 | |||
| 2979 | /* Close the contour with a line back to start. */ | ||
| 2980 | line_to (start, dcontext); | ||
| 2981 | |||
| 2982 | exit: | ||
| 2983 | return 0; | ||
| 2984 | } | ||
| 2985 | |||
| 2711 | /* Decompose GLYPH into its individual components. Call MOVE_TO to | 2986 | /* Decompose GLYPH into its individual components. Call MOVE_TO to |
| 2712 | move to a specific location. For each line encountered, call | 2987 | move to a specific location. For each line encountered, call |
| 2713 | LINE_TO to draw a line to that location. For each spline | 2988 | LINE_TO to draw a line to that location. For each spline |
| @@ -2736,10 +3011,8 @@ sfnt_decompose_glyph (struct sfnt_glyph *glyph, | |||
| 2736 | sfnt_free_glyph_proc free_glyph, | 3011 | sfnt_free_glyph_proc free_glyph, |
| 2737 | void *dcontext) | 3012 | void *dcontext) |
| 2738 | { | 3013 | { |
| 2739 | size_t here, start, last; | 3014 | size_t here, last, n; |
| 2740 | struct sfnt_point pen, control1, control2; | ||
| 2741 | struct sfnt_compound_glyph_context context; | 3015 | struct sfnt_compound_glyph_context context; |
| 2742 | size_t n; | ||
| 2743 | 3016 | ||
| 2744 | if (glyph->simple) | 3017 | if (glyph->simple) |
| 2745 | { | 3018 | { |
| @@ -2756,113 +3029,23 @@ sfnt_decompose_glyph (struct sfnt_glyph *glyph, | |||
| 2756 | of the last point in the contour. */ | 3029 | of the last point in the contour. */ |
| 2757 | last = glyph->simple->end_pts_of_contours[n]; | 3030 | last = glyph->simple->end_pts_of_contours[n]; |
| 2758 | 3031 | ||
| 2759 | /* Move to the start. */ | 3032 | /* Make sure here and last make sense. */ |
| 2760 | pen.x = glyph->simple->x_coordinates[here] * 65536; | ||
| 2761 | pen.y = glyph->simple->y_coordinates[here] * 65536; | ||
| 2762 | move_to (pen, dcontext); | ||
| 2763 | |||
| 2764 | /* Record start so the contour can be closed. */ | ||
| 2765 | start = here; | ||
| 2766 | 3033 | ||
| 2767 | /* If there is only one point in a contour, draw a one pixel | 3034 | if (here > last || last >= glyph->simple->number_of_points) |
| 2768 | wide line. */ | ||
| 2769 | if (last == here) | ||
| 2770 | { | ||
| 2771 | line_to (pen, dcontext); | ||
| 2772 | here++; | ||
| 2773 | |||
| 2774 | continue; | ||
| 2775 | } | ||
| 2776 | |||
| 2777 | if (here > last) | ||
| 2778 | /* Indices moved backwards. */ | ||
| 2779 | return 1; | 3035 | return 1; |
| 2780 | 3036 | ||
| 2781 | /* Now start reading points. If the next point is on the | 3037 | /* Now perform the decomposition. */ |
| 2782 | curve, then it is actually a line. */ | 3038 | if (sfnt_decompose_glyph_1 (here, last, move_to, |
| 2783 | for (++here; here <= last; ++here) | 3039 | line_to, curve_to, |
| 2784 | { | 3040 | dcontext, |
| 2785 | /* Make sure here is within bounds. */ | 3041 | glyph->simple->x_coordinates, |
| 2786 | if (here >= glyph->simple->number_of_points) | 3042 | glyph->simple->y_coordinates, |
| 2787 | return 1; | 3043 | glyph->simple->flags, |
| 2788 | 3044 | 65536)) | |
| 2789 | if (glyph->simple->flags[here] & 01) /* On Curve */ | 3045 | return 1; |
| 2790 | { | ||
| 2791 | pen.x = glyph->simple->x_coordinates[here] * 65536; | ||
| 2792 | pen.y = glyph->simple->y_coordinates[here] * 65536; | ||
| 2793 | |||
| 2794 | /* See if the last point was on the curve. If it | ||
| 2795 | wasn't, then curve from there to here. */ | ||
| 2796 | if (!(glyph->simple->flags[here - 1] & 01)) | ||
| 2797 | { | ||
| 2798 | control1.x | ||
| 2799 | = glyph->simple->x_coordinates[here - 1] * 65536; | ||
| 2800 | control1.y | ||
| 2801 | = glyph->simple->y_coordinates[here - 1] * 65536; | ||
| 2802 | curve_to (control1, pen, dcontext); | ||
| 2803 | } | ||
| 2804 | else | ||
| 2805 | /* Otherwise, this is an ordinary line from there | ||
| 2806 | to here. */ | ||
| 2807 | line_to (pen, dcontext); | ||
| 2808 | |||
| 2809 | continue; | ||
| 2810 | } | ||
| 2811 | |||
| 2812 | /* If the last point was on the curve, then there's | ||
| 2813 | nothing extraordinary to do yet. */ | ||
| 2814 | if (glyph->simple->flags[here - 1] & 01) | ||
| 2815 | ; | ||
| 2816 | else | ||
| 2817 | { | ||
| 2818 | /* Otherwise, interpolate the point halfway between | ||
| 2819 | the last and current points and make that point | ||
| 2820 | the pen. */ | ||
| 2821 | control1.x = glyph->simple->x_coordinates[here - 1] * 65536; | ||
| 2822 | control1.y = glyph->simple->y_coordinates[here - 1] * 65536; | ||
| 2823 | control2.x = glyph->simple->x_coordinates[here] * 65536; | ||
| 2824 | control2.y = glyph->simple->y_coordinates[here] * 65536; | ||
| 2825 | sfnt_lerp_half (&control1, &control2, &pen); | ||
| 2826 | curve_to (control1, pen, dcontext); | ||
| 2827 | } | ||
| 2828 | } | ||
| 2829 | |||
| 2830 | /* Now close the contour if there is more than one point | ||
| 2831 | inside it. */ | ||
| 2832 | if (start != here - 1) | ||
| 2833 | { | ||
| 2834 | /* Restore here after the for loop increased it. */ | ||
| 2835 | here --; | ||
| 2836 | |||
| 2837 | /* Previously, this would check whether or not start is | ||
| 2838 | an ``on curve'' point, but that is not necessary. | ||
| 2839 | |||
| 2840 | If a contour is not closed and the edge building | ||
| 2841 | process skips the second to last vertex, then the | ||
| 2842 | outline can end up with missing edges. */ | ||
| 2843 | |||
| 2844 | pen.x = glyph->simple->x_coordinates[start] * 65536; | ||
| 2845 | pen.y = glyph->simple->y_coordinates[start] * 65536; | ||
| 2846 | |||
| 2847 | /* See if the last point (in this case, `here') was | ||
| 2848 | on the curve. If it wasn't, then curve from | ||
| 2849 | there to here. */ | ||
| 2850 | if (!(glyph->simple->flags[here] & 01)) | ||
| 2851 | { | ||
| 2852 | control1.x | ||
| 2853 | = glyph->simple->x_coordinates[here] * 65536; | ||
| 2854 | control1.y | ||
| 2855 | = glyph->simple->y_coordinates[here] * 65536; | ||
| 2856 | curve_to (control1, pen, dcontext); | ||
| 2857 | } | ||
| 2858 | else | ||
| 2859 | /* Otherwise, this is an ordinary line from there | ||
| 2860 | to here. */ | ||
| 2861 | line_to (pen, dcontext); | ||
| 2862 | 3046 | ||
| 2863 | /* Restore here to where it was earlier. */ | 3047 | /* Move forward to the start of the next contour. */ |
| 2864 | here++; | 3048 | here = last + 1; |
| 2865 | } | ||
| 2866 | } | 3049 | } |
| 2867 | 3050 | ||
| 2868 | return 0; | 3051 | return 0; |
| @@ -2898,108 +3081,22 @@ sfnt_decompose_glyph (struct sfnt_glyph *glyph, | |||
| 2898 | of the last point in the contour. */ | 3081 | of the last point in the contour. */ |
| 2899 | last = context.contour_end_points[n]; | 3082 | last = context.contour_end_points[n]; |
| 2900 | 3083 | ||
| 2901 | /* Move to the start. */ | 3084 | /* Make sure here and last make sense. */ |
| 2902 | pen.x = context.x_coordinates[here]; | ||
| 2903 | pen.y = context.y_coordinates[here]; | ||
| 2904 | move_to (pen, dcontext); | ||
| 2905 | |||
| 2906 | /* Record start so the contour can be closed. */ | ||
| 2907 | start = here; | ||
| 2908 | |||
| 2909 | /* If there is only one point in a contour, draw a one pixel | ||
| 2910 | wide line. */ | ||
| 2911 | if (last == here) | ||
| 2912 | { | ||
| 2913 | line_to (pen, dcontext); | ||
| 2914 | here++; | ||
| 2915 | |||
| 2916 | continue; | ||
| 2917 | } | ||
| 2918 | 3085 | ||
| 2919 | if (here > last) | 3086 | if (here > last || last >= context.num_points) |
| 2920 | /* Indices moved backwards. */ | ||
| 2921 | goto fail; | 3087 | goto fail; |
| 2922 | 3088 | ||
| 2923 | /* Now start reading points. If the next point is on the | 3089 | /* Now perform the decomposition. */ |
| 2924 | curve, then it is actually a line. */ | 3090 | if (sfnt_decompose_glyph_2 (here, last, move_to, |
| 2925 | for (++here; here <= last; ++here) | 3091 | line_to, curve_to, |
| 2926 | { | 3092 | dcontext, |
| 2927 | /* Make sure here is within bounds. */ | 3093 | context.x_coordinates, |
| 2928 | if (here >= context.num_points) | 3094 | context.y_coordinates, |
| 2929 | return 1; | 3095 | context.flags, 1)) |
| 2930 | 3096 | goto fail; | |
| 2931 | if (context.flags[here] & 01) /* On Curve */ | ||
| 2932 | { | ||
| 2933 | pen.x = context.x_coordinates[here]; | ||
| 2934 | pen.y = context.y_coordinates[here]; | ||
| 2935 | |||
| 2936 | /* See if the last point was on the curve. If it | ||
| 2937 | wasn't, then curve from there to here. */ | ||
| 2938 | if (!(context.flags[here - 1] & 01)) | ||
| 2939 | { | ||
| 2940 | control1.x = context.x_coordinates[here - 1]; | ||
| 2941 | control1.y = context.y_coordinates[here - 1]; | ||
| 2942 | curve_to (control1, pen, dcontext); | ||
| 2943 | } | ||
| 2944 | else | ||
| 2945 | /* Otherwise, this is an ordinary line from there | ||
| 2946 | to here. */ | ||
| 2947 | line_to (pen, dcontext); | ||
| 2948 | |||
| 2949 | continue; | ||
| 2950 | } | ||
| 2951 | |||
| 2952 | /* If the last point was on the curve, then there's | ||
| 2953 | nothing extraordinary to do yet. */ | ||
| 2954 | if (context.flags[here - 1] & 01) | ||
| 2955 | ; | ||
| 2956 | else | ||
| 2957 | { | ||
| 2958 | /* Otherwise, interpolate the point halfway between | ||
| 2959 | the last and current points and make that point | ||
| 2960 | the pen. */ | ||
| 2961 | control1.x = context.x_coordinates[here - 1]; | ||
| 2962 | control1.y = context.y_coordinates[here - 1]; | ||
| 2963 | control2.x = context.x_coordinates[here]; | ||
| 2964 | control2.y = context.y_coordinates[here]; | ||
| 2965 | sfnt_lerp_half (&control1, &control2, &pen); | ||
| 2966 | curve_to (control1, pen, dcontext); | ||
| 2967 | } | ||
| 2968 | } | ||
| 2969 | |||
| 2970 | /* Now close the contour if there is more than one point | ||
| 2971 | inside it. */ | ||
| 2972 | if (start != here - 1) | ||
| 2973 | { | ||
| 2974 | /* Restore here after the for loop increased it. */ | ||
| 2975 | here --; | ||
| 2976 | |||
| 2977 | /* Previously, this would check whether or not start is an | ||
| 2978 | ``on curve'' point, but that is not necessary. | ||
| 2979 | |||
| 2980 | If a contour is not closed and the edge building process | ||
| 2981 | skips the second to last vertex, then the outline can end | ||
| 2982 | up with missing edges. */ | ||
| 2983 | |||
| 2984 | pen.x = context.x_coordinates[start]; | ||
| 2985 | pen.y = context.y_coordinates[start]; | ||
| 2986 | |||
| 2987 | /* See if the last point (in this case, `here') was on the | ||
| 2988 | curve. If it wasn't, then curve from there to here. */ | ||
| 2989 | if (!(context.flags[here] & 01)) | ||
| 2990 | { | ||
| 2991 | control1.x = context.x_coordinates[here]; | ||
| 2992 | control1.y = context.y_coordinates[here]; | ||
| 2993 | curve_to (control1, pen, dcontext); | ||
| 2994 | } | ||
| 2995 | else | ||
| 2996 | /* Otherwise, this is an ordinary line from there | ||
| 2997 | to here. */ | ||
| 2998 | line_to (pen, dcontext); | ||
| 2999 | 3097 | ||
| 3000 | /* Restore here to where it was earlier. */ | 3098 | /* Move forward. */ |
| 3001 | here++; | 3099 | here = last + 1; |
| 3002 | } | ||
| 3003 | } | 3100 | } |
| 3004 | 3101 | ||
| 3005 | early: | 3102 | early: |
| @@ -10499,9 +10596,7 @@ sfnt_decompose_instructed_outline (struct sfnt_instructed_outline *outline, | |||
| 10499 | sfnt_curve_to_proc curve_to, | 10596 | sfnt_curve_to_proc curve_to, |
| 10500 | void *dcontext) | 10597 | void *dcontext) |
| 10501 | { | 10598 | { |
| 10502 | size_t here, start, last; | 10599 | size_t here, last, n; |
| 10503 | struct sfnt_point pen, control1, control2; | ||
| 10504 | size_t n; | ||
| 10505 | 10600 | ||
| 10506 | if (!outline->num_contours) | 10601 | if (!outline->num_contours) |
| 10507 | return 0; | 10602 | return 0; |
| @@ -10515,109 +10610,20 @@ sfnt_decompose_instructed_outline (struct sfnt_instructed_outline *outline, | |||
| 10515 | of the last point in the contour. */ | 10610 | of the last point in the contour. */ |
| 10516 | last = outline->contour_end_points[n]; | 10611 | last = outline->contour_end_points[n]; |
| 10517 | 10612 | ||
| 10518 | /* Move to the start. */ | 10613 | /* Make sure here and last make sense. */ |
| 10519 | pen.x = outline->x_points[here] * 1024; | ||
| 10520 | pen.y = outline->y_points[here] * 1024; | ||
| 10521 | move_to (pen, dcontext); | ||
| 10522 | |||
| 10523 | /* Record start so the contour can be closed. */ | ||
| 10524 | start = here; | ||
| 10525 | |||
| 10526 | /* If there is only one point in a contour, draw a one pixel | ||
| 10527 | wide line. */ | ||
| 10528 | if (last == here) | ||
| 10529 | { | ||
| 10530 | line_to (pen, dcontext); | ||
| 10531 | here++; | ||
| 10532 | |||
| 10533 | continue; | ||
| 10534 | } | ||
| 10535 | 10614 | ||
| 10536 | if (here > last) | 10615 | if (here > last || last >= outline->num_points) |
| 10537 | /* Indices moved backwards. */ | ||
| 10538 | goto fail; | 10616 | goto fail; |
| 10539 | 10617 | ||
| 10540 | /* Now start reading points. If the next point is on the | 10618 | if (sfnt_decompose_glyph_2 (here, last, move_to, |
| 10541 | curve, then it is actually a line. */ | 10619 | line_to, curve_to, dcontext, |
| 10542 | for (++here; here <= last; ++here) | 10620 | outline->x_points, |
| 10543 | { | 10621 | outline->y_points, |
| 10544 | /* Make sure here is within bounds. */ | 10622 | outline->flags, 1024)) |
| 10545 | if (here >= outline->num_points) | 10623 | goto fail; |
| 10546 | return 1; | ||
| 10547 | |||
| 10548 | if (outline->flags[here] & 01) /* On Curve */ | ||
| 10549 | { | ||
| 10550 | pen.x = outline->x_points[here] * 1024; | ||
| 10551 | pen.y = outline->y_points[here] * 1024; | ||
| 10552 | |||
| 10553 | /* See if the last point was on the curve. If it | ||
| 10554 | wasn't, then curve from there to here. */ | ||
| 10555 | if (!(outline->flags[here - 1] & 01)) | ||
| 10556 | { | ||
| 10557 | control1.x = outline->x_points[here - 1] * 1024; | ||
| 10558 | control1.y = outline->y_points[here - 1] * 1024; | ||
| 10559 | curve_to (control1, pen, dcontext); | ||
| 10560 | } | ||
| 10561 | else | ||
| 10562 | /* Otherwise, this is an ordinary line from there | ||
| 10563 | to here. */ | ||
| 10564 | line_to (pen, dcontext); | ||
| 10565 | |||
| 10566 | continue; | ||
| 10567 | } | ||
| 10568 | |||
| 10569 | /* If the last point was on the curve, then there's | ||
| 10570 | nothing extraordinary to do yet. */ | ||
| 10571 | if (outline->flags[here - 1] & 01) | ||
| 10572 | ; | ||
| 10573 | else | ||
| 10574 | { | ||
| 10575 | /* Otherwise, interpolate the point halfway between | ||
| 10576 | the last and current points and make that point | ||
| 10577 | the pen. */ | ||
| 10578 | control1.x = outline->x_points[here - 1] * 1024; | ||
| 10579 | control1.y = outline->y_points[here - 1] * 1024; | ||
| 10580 | control2.x = outline->x_points[here] * 1024; | ||
| 10581 | control2.y = outline->y_points[here] * 1024; | ||
| 10582 | sfnt_lerp_half (&control1, &control2, &pen); | ||
| 10583 | curve_to (control1, pen, dcontext); | ||
| 10584 | } | ||
| 10585 | } | ||
| 10586 | |||
| 10587 | /* Now close the contour if there is more than one point | ||
| 10588 | inside it. */ | ||
| 10589 | if (start != here - 1) | ||
| 10590 | { | ||
| 10591 | /* Restore here after the for loop increased it. */ | ||
| 10592 | here --; | ||
| 10593 | |||
| 10594 | /* Previously, this would check whether or not start is an | ||
| 10595 | ``on curve'' point, but that is not necessary. | ||
| 10596 | |||
| 10597 | If a contour is not closed and the edge building process | ||
| 10598 | skips the second to last vertex, then the outline can end | ||
| 10599 | up with missing edges. */ | ||
| 10600 | |||
| 10601 | pen.x = outline->x_points[start] * 1024; | ||
| 10602 | pen.y = outline->y_points[start] * 1024; | ||
| 10603 | |||
| 10604 | /* See if the last point (in this case, `here') was | ||
| 10605 | on the curve. If it wasn't, then curve from | ||
| 10606 | there to here. */ | ||
| 10607 | if (!(outline->flags[here] & 01)) | ||
| 10608 | { | ||
| 10609 | control1.x = outline->x_points[here] * 1024; | ||
| 10610 | control1.y = outline->y_points[here] * 1024; | ||
| 10611 | curve_to (control1, pen, dcontext); | ||
| 10612 | } | ||
| 10613 | else | ||
| 10614 | /* Otherwise, this is an ordinary line from there | ||
| 10615 | to here. */ | ||
| 10616 | line_to (pen, dcontext); | ||
| 10617 | 10624 | ||
| 10618 | /* Restore here to where it was earlier. */ | 10625 | /* Move forward to the start of the next contour. */ |
| 10619 | here++; | 10626 | here = last + 1; |
| 10620 | } | ||
| 10621 | 10627 | ||
| 10622 | /* here may be a phantom point when outlining a compound glyph, | 10628 | /* here may be a phantom point when outlining a compound glyph, |
| 10623 | as they can have phantom points mixed in with contours. | 10629 | as they can have phantom points mixed in with contours. |
| @@ -15530,6 +15536,9 @@ main (int argc, char **argv) | |||
| 15530 | return 1; | 15536 | return 1; |
| 15531 | } | 15537 | } |
| 15532 | 15538 | ||
| 15539 | fprintf (stderr, "number of subtables: %"PRIu16"\n", | ||
| 15540 | table->num_subtables); | ||
| 15541 | |||
| 15533 | for (i = 0; i < table->num_subtables; ++i) | 15542 | for (i = 0; i < table->num_subtables; ++i) |
| 15534 | { | 15543 | { |
| 15535 | fprintf (stderr, "Found cmap table %"PRIu32": %p\n", | 15544 | fprintf (stderr, "Found cmap table %"PRIu32": %p\n", |
| @@ -15540,8 +15549,8 @@ main (int argc, char **argv) | |||
| 15540 | data[i]->format); | 15549 | data[i]->format); |
| 15541 | } | 15550 | } |
| 15542 | 15551 | ||
| 15543 | #define FANCY_PPEM 12 | 15552 | #define FANCY_PPEM 40 |
| 15544 | #define EASY_PPEM 12 | 15553 | #define EASY_PPEM 40 |
| 15545 | 15554 | ||
| 15546 | interpreter = NULL; | 15555 | interpreter = NULL; |
| 15547 | head = sfnt_read_head_table (fd, font); | 15556 | head = sfnt_read_head_table (fd, font); |
diff --git a/src/sfntfont-android.c b/src/sfntfont-android.c index feea92827d9..c28a911bfba 100644 --- a/src/sfntfont-android.c +++ b/src/sfntfont-android.c | |||
| @@ -49,9 +49,11 @@ struct sfntfont_android_scanline_buffer | |||
| 49 | }; | 49 | }; |
| 50 | 50 | ||
| 51 | /* Array of directories to search for system fonts. */ | 51 | /* Array of directories to search for system fonts. */ |
| 52 | const char *system_font_directories[] = | 52 | static char *system_font_directories[] = |
| 53 | { | 53 | { |
| 54 | "/system/fonts", | 54 | "/system/fonts", |
| 55 | /* This should be filled in by init_sfntfont_android. */ | ||
| 56 | (char[PATH_MAX]) { }, | ||
| 55 | }; | 57 | }; |
| 56 | 58 | ||
| 57 | /* The font cache. */ | 59 | /* The font cache. */ |
| @@ -691,6 +693,10 @@ loaded before character sets are made available. */) | |||
| 691 | { | 693 | { |
| 692 | dir = opendir (system_font_directories[i]); | 694 | dir = opendir (system_font_directories[i]); |
| 693 | 695 | ||
| 696 | __android_log_print (ANDROID_LOG_VERBOSE, __func__, | ||
| 697 | "Loading fonts from: %s", | ||
| 698 | system_font_directories[i]); | ||
| 699 | |||
| 694 | if (!dir) | 700 | if (!dir) |
| 695 | continue; | 701 | continue; |
| 696 | 702 | ||
| @@ -752,6 +758,11 @@ init_sfntfont_android (void) | |||
| 752 | build_string ("Droid Sans Mono")), | 758 | build_string ("Droid Sans Mono")), |
| 753 | Fcons (build_string ("Sans Serif"), | 759 | Fcons (build_string ("Sans Serif"), |
| 754 | build_string ("Droid Sans"))); | 760 | build_string ("Droid Sans"))); |
| 761 | |||
| 762 | /* Set up the user fonts directory. This directory is ``fonts'' in | ||
| 763 | the Emacs files directory. */ | ||
| 764 | snprintf (system_font_directories[1], PATH_MAX, "%s/fonts", | ||
| 765 | android_get_home_directory ()); | ||
| 755 | } | 766 | } |
| 756 | 767 | ||
| 757 | void | 768 | void |
diff --git a/src/sfntfont.c b/src/sfntfont.c index a5ed54394a2..f9344067f1a 100644 --- a/src/sfntfont.c +++ b/src/sfntfont.c | |||
| @@ -87,6 +87,10 @@ struct sfnt_font_desc | |||
| 87 | 87 | ||
| 88 | /* The offset of the table directory within PATH. */ | 88 | /* The offset of the table directory within PATH. */ |
| 89 | off_t offset; | 89 | off_t offset; |
| 90 | |||
| 91 | /* The number of glyphs in this font. Used to catch invalid cmap | ||
| 92 | tables. This is actually the number of glyphs - 1. */ | ||
| 93 | int num_glyphs; | ||
| 90 | }; | 94 | }; |
| 91 | 95 | ||
| 92 | /* List of fonts. */ | 96 | /* List of fonts. */ |
| @@ -517,10 +521,11 @@ sfnt_enum_font_1 (int fd, const char *file, | |||
| 517 | struct sfnt_offset_subtable *subtables, | 521 | struct sfnt_offset_subtable *subtables, |
| 518 | off_t offset) | 522 | off_t offset) |
| 519 | { | 523 | { |
| 520 | struct sfnt_font_desc *desc; | 524 | struct sfnt_font_desc *desc, **next, *prev; |
| 521 | struct sfnt_head_table *head; | 525 | struct sfnt_head_table *head; |
| 522 | struct sfnt_name_table *name; | 526 | struct sfnt_name_table *name; |
| 523 | struct sfnt_meta_table *meta; | 527 | struct sfnt_meta_table *meta; |
| 528 | struct sfnt_maxp_table *maxp; | ||
| 524 | Lisp_Object family, style; | 529 | Lisp_Object family, style; |
| 525 | 530 | ||
| 526 | /* Create the font desc and copy in the file name. */ | 531 | /* Create the font desc and copy in the file name. */ |
| @@ -543,12 +548,16 @@ sfnt_enum_font_1 (int fd, const char *file, | |||
| 543 | if (!name) | 548 | if (!name) |
| 544 | goto bail2; | 549 | goto bail2; |
| 545 | 550 | ||
| 551 | maxp = sfnt_read_maxp_table (fd, subtables); | ||
| 552 | if (!maxp) | ||
| 553 | goto bail3; | ||
| 554 | |||
| 546 | /* meta is not required, nor present on many non-Apple fonts. */ | 555 | /* meta is not required, nor present on many non-Apple fonts. */ |
| 547 | meta = sfnt_read_meta_table (fd, subtables); | 556 | meta = sfnt_read_meta_table (fd, subtables); |
| 548 | 557 | ||
| 549 | /* Decode the family and style from the name table. */ | 558 | /* Decode the family and style from the name table. */ |
| 550 | if (sfnt_decode_family_style (name, &family, &style)) | 559 | if (sfnt_decode_family_style (name, &family, &style)) |
| 551 | goto bail3; | 560 | goto bail4; |
| 552 | 561 | ||
| 553 | /* Set the family. */ | 562 | /* Set the family. */ |
| 554 | desc->family = family; | 563 | desc->family = family; |
| @@ -556,6 +565,9 @@ sfnt_enum_font_1 (int fd, const char *file, | |||
| 556 | desc->char_cache = Qnil; | 565 | desc->char_cache = Qnil; |
| 557 | desc->subtable.platform_id = 500; | 566 | desc->subtable.platform_id = 500; |
| 558 | 567 | ||
| 568 | /* Set the largest glyph identifier. */ | ||
| 569 | desc->num_glyphs = maxp->num_glyphs; | ||
| 570 | |||
| 559 | /* Parse the style. */ | 571 | /* Parse the style. */ |
| 560 | sfnt_parse_style (style, desc); | 572 | sfnt_parse_style (style, desc); |
| 561 | 573 | ||
| @@ -584,13 +596,32 @@ sfnt_enum_font_1 (int fd, const char *file, | |||
| 584 | desc->next = system_fonts; | 596 | desc->next = system_fonts; |
| 585 | system_fonts = desc; | 597 | system_fonts = desc; |
| 586 | 598 | ||
| 599 | /* Remove any fonts which have the same style as this one. */ | ||
| 600 | |||
| 601 | next = &system_fonts->next; | ||
| 602 | prev = *next; | ||
| 603 | for (; *next; prev = *next) | ||
| 604 | { | ||
| 605 | if (!NILP (Fstring_equal (prev->style, desc->style)) | ||
| 606 | && !NILP (Fstring_equal (prev->family, desc->family))) | ||
| 607 | { | ||
| 608 | *next = prev->next; | ||
| 609 | xfree (prev); | ||
| 610 | } | ||
| 611 | else | ||
| 612 | next = &prev->next; | ||
| 613 | } | ||
| 614 | |||
| 587 | xfree (meta); | 615 | xfree (meta); |
| 616 | xfree (maxp); | ||
| 588 | xfree (name); | 617 | xfree (name); |
| 589 | xfree (head); | 618 | xfree (head); |
| 590 | return 0; | 619 | return 0; |
| 591 | 620 | ||
| 592 | bail3: | 621 | bail4: |
| 593 | xfree (meta); | 622 | xfree (meta); |
| 623 | xfree (maxp); | ||
| 624 | bail3: | ||
| 594 | xfree (name); | 625 | xfree (name); |
| 595 | bail2: | 626 | bail2: |
| 596 | xfree (head); | 627 | xfree (head); |
| @@ -602,6 +633,8 @@ sfnt_enum_font_1 (int fd, const char *file, | |||
| 602 | /* Enumerate the font FILE into the list of system fonts. Return 1 if | 633 | /* Enumerate the font FILE into the list of system fonts. Return 1 if |
| 603 | it could not be enumerated, 0 otherwise. | 634 | it could not be enumerated, 0 otherwise. |
| 604 | 635 | ||
| 636 | Remove any font whose family and style is a duplicate of this one. | ||
| 637 | |||
| 605 | FILE can either be a TrueType collection file containing TrueType | 638 | FILE can either be a TrueType collection file containing TrueType |
| 606 | fonts, or a TrueType font itself. */ | 639 | fonts, or a TrueType font itself. */ |
| 607 | 640 | ||
| @@ -960,6 +993,25 @@ sfntfont_read_cmap (struct sfnt_font_desc *desc, | |||
| 960 | emacs_close (fd); | 993 | emacs_close (fd); |
| 961 | } | 994 | } |
| 962 | 995 | ||
| 996 | /* Return whether or not CHARACTER has an associated mapping in CMAP, | ||
| 997 | and the mapping points to a valid glyph. DESC is the font | ||
| 998 | descriptor associated with the font. */ | ||
| 999 | |||
| 1000 | static bool | ||
| 1001 | sfntfont_glyph_valid (struct sfnt_font_desc *desc, | ||
| 1002 | sfnt_char font_character, | ||
| 1003 | struct sfnt_cmap_encoding_subtable_data *cmap) | ||
| 1004 | { | ||
| 1005 | sfnt_glyph glyph; | ||
| 1006 | |||
| 1007 | glyph = sfnt_lookup_glyph (font_character, cmap); | ||
| 1008 | |||
| 1009 | if (!glyph) | ||
| 1010 | return false; | ||
| 1011 | |||
| 1012 | return glyph <= desc->num_glyphs; | ||
| 1013 | } | ||
| 1014 | |||
| 963 | /* Look up a character CHARACTER in the font description DESC. Cache | 1015 | /* Look up a character CHARACTER in the font description DESC. Cache |
| 964 | the results. Return true if the character exists, false otherwise. | 1016 | the results. Return true if the character exists, false otherwise. |
| 965 | 1017 | ||
| @@ -1013,8 +1065,10 @@ sfntfont_lookup_char (struct sfnt_font_desc *desc, Lisp_Object character, | |||
| 1013 | if (font_character == CHARSET_INVALID_CODE (charset)) | 1065 | if (font_character == CHARSET_INVALID_CODE (charset)) |
| 1014 | return false; | 1066 | return false; |
| 1015 | 1067 | ||
| 1016 | /* Now return whether or not the glyph is present. */ | 1068 | /* Now return whether or not the glyph is present. Noto Sans |
| 1017 | present = sfnt_lookup_glyph (font_character, *cmap) != 0; | 1069 | Georgian comes with a corrupt format 4 cmap table that somehow |
| 1070 | tries to express glyphs greater than 65565. */ | ||
| 1071 | present = sfntfont_glyph_valid (desc, font_character, *cmap); | ||
| 1018 | 1072 | ||
| 1019 | /* Cache the result. Store Qlambda when not present, Qt | 1073 | /* Cache the result. Store Qlambda when not present, Qt |
| 1020 | otherwise. */ | 1074 | otherwise. */ |
| @@ -1133,22 +1187,23 @@ sfntfont_list_1 (struct sfnt_font_desc *desc, Lisp_Object spec) | |||
| 1133 | { | 1187 | { |
| 1134 | tem = XCDR (tem); | 1188 | tem = XCDR (tem); |
| 1135 | 1189 | ||
| 1136 | /* tem is a list of each characters, one of which must be | 1190 | /* tem is a list of each characters, all of which must be |
| 1137 | present in the font. */ | 1191 | present in the font. */ |
| 1138 | FOR_EACH_TAIL_SAFE (tem) | 1192 | FOR_EACH_TAIL_SAFE (tem) |
| 1139 | { | 1193 | { |
| 1140 | if (FIXNUMP (XCAR (tem))) | 1194 | if (FIXNUMP (XCAR (tem)) |
| 1141 | { | 1195 | && !sfntfont_lookup_char (desc, XCAR (tem), &cmap, |
| 1142 | if (!sfntfont_lookup_char (desc, XCAR (tem), &cmap, | 1196 | &subtable)) |
| 1143 | &subtable)) | 1197 | goto fail; |
| 1144 | goto fail; | ||
| 1145 | |||
| 1146 | /* One character is enough to pass a font. Don't | ||
| 1147 | look at too many. */ | ||
| 1148 | break; | ||
| 1149 | } | ||
| 1150 | } | 1198 | } |
| 1199 | |||
| 1200 | /* One or more characters are missing. */ | ||
| 1201 | if (!NILP (tem)) | ||
| 1202 | goto fail; | ||
| 1151 | } | 1203 | } |
| 1204 | /* Fail if there are no matching fonts at all. */ | ||
| 1205 | else if (NILP (tem)) | ||
| 1206 | goto fail; | ||
| 1152 | } | 1207 | } |
| 1153 | 1208 | ||
| 1154 | /* Now check that the language is supported. */ | 1209 | /* Now check that the language is supported. */ |
diff --git a/src/textconv.c b/src/textconv.c index 835d03f3037..5090b0a33b6 100644 --- a/src/textconv.c +++ b/src/textconv.c | |||
| @@ -35,6 +35,7 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */ | |||
| 35 | #include "textconv.h" | 35 | #include "textconv.h" |
| 36 | #include "buffer.h" | 36 | #include "buffer.h" |
| 37 | #include "syntax.h" | 37 | #include "syntax.h" |
| 38 | #include "blockinput.h" | ||
| 38 | 39 | ||
| 39 | 40 | ||
| 40 | 41 | ||
| @@ -47,6 +48,10 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */ | |||
| 47 | 48 | ||
| 48 | static struct textconv_interface *text_interface; | 49 | static struct textconv_interface *text_interface; |
| 49 | 50 | ||
| 51 | /* How many times text conversion has been disabled. */ | ||
| 52 | |||
| 53 | static int suppress_conversion_count; | ||
| 54 | |||
| 50 | /* Flags used to determine what must be sent after a batch edit | 55 | /* Flags used to determine what must be sent after a batch edit |
| 51 | ends. */ | 56 | ends. */ |
| 52 | 57 | ||
| @@ -391,7 +396,8 @@ textconv_query (struct frame *f, struct textconv_callback_struct *query, | |||
| 391 | static void | 396 | static void |
| 392 | sync_overlay (struct frame *f) | 397 | sync_overlay (struct frame *f) |
| 393 | { | 398 | { |
| 394 | if (MARKERP (f->conversion.compose_region_start)) | 399 | if (MARKERP (f->conversion.compose_region_start) |
| 400 | && !NILP (Vtext_conversion_face)) | ||
| 395 | { | 401 | { |
| 396 | if (NILP (f->conversion.compose_region_overlay)) | 402 | if (NILP (f->conversion.compose_region_overlay)) |
| 397 | { | 403 | { |
| @@ -400,7 +406,7 @@ sync_overlay (struct frame *f) | |||
| 400 | f->conversion.compose_region_end, Qnil, | 406 | f->conversion.compose_region_end, Qnil, |
| 401 | Qt, Qnil); | 407 | Qt, Qnil); |
| 402 | Foverlay_put (f->conversion.compose_region_overlay, | 408 | Foverlay_put (f->conversion.compose_region_overlay, |
| 403 | Qface, Qunderline); | 409 | Qface, Vtext_conversion_face); |
| 404 | } | 410 | } |
| 405 | 411 | ||
| 406 | Fmove_overlay (f->conversion.compose_region_overlay, | 412 | Fmove_overlay (f->conversion.compose_region_overlay, |
| @@ -514,6 +520,7 @@ really_commit_text (struct frame *f, EMACS_INT position, | |||
| 514 | { | 520 | { |
| 515 | specpdl_ref count; | 521 | specpdl_ref count; |
| 516 | ptrdiff_t wanted, start, end; | 522 | ptrdiff_t wanted, start, end; |
| 523 | struct window *w; | ||
| 517 | 524 | ||
| 518 | /* If F's old selected window is no longer live, fail. */ | 525 | /* If F's old selected window is no longer live, fail. */ |
| 519 | 526 | ||
| @@ -624,6 +631,10 @@ really_commit_text (struct frame *f, EMACS_INT position, | |||
| 624 | 631 | ||
| 625 | /* This should deactivate the mark. */ | 632 | /* This should deactivate the mark. */ |
| 626 | call0 (Qdeactivate_mark); | 633 | call0 (Qdeactivate_mark); |
| 634 | |||
| 635 | /* Update the ephemeral last point. */ | ||
| 636 | w = XWINDOW (selected_window); | ||
| 637 | w->ephemeral_last_point = PT; | ||
| 627 | unbind_to (count, Qnil); | 638 | unbind_to (count, Qnil); |
| 628 | } | 639 | } |
| 629 | 640 | ||
| @@ -760,6 +771,10 @@ really_set_composing_text (struct frame *f, ptrdiff_t position, | |||
| 760 | text_interface->compose_region_changed (f); | 771 | text_interface->compose_region_changed (f); |
| 761 | } | 772 | } |
| 762 | 773 | ||
| 774 | /* Update the ephemeral last point. */ | ||
| 775 | w = XWINDOW (selected_window); | ||
| 776 | w->ephemeral_last_point = PT; | ||
| 777 | |||
| 763 | unbind_to (count, Qnil); | 778 | unbind_to (count, Qnil); |
| 764 | } | 779 | } |
| 765 | 780 | ||
| @@ -771,6 +786,7 @@ really_set_composing_region (struct frame *f, ptrdiff_t start, | |||
| 771 | ptrdiff_t end) | 786 | ptrdiff_t end) |
| 772 | { | 787 | { |
| 773 | specpdl_ref count; | 788 | specpdl_ref count; |
| 789 | struct window *w; | ||
| 774 | 790 | ||
| 775 | /* If F's old selected window is no longer live, fail. */ | 791 | /* If F's old selected window is no longer live, fail. */ |
| 776 | 792 | ||
| @@ -810,6 +826,10 @@ really_set_composing_region (struct frame *f, ptrdiff_t start, | |||
| 810 | make_fixnum (end), Qnil); | 826 | make_fixnum (end), Qnil); |
| 811 | sync_overlay (f); | 827 | sync_overlay (f); |
| 812 | 828 | ||
| 829 | /* Update the ephemeral last point. */ | ||
| 830 | w = XWINDOW (selected_window); | ||
| 831 | w->ephemeral_last_point = PT; | ||
| 832 | |||
| 813 | unbind_to (count, Qnil); | 833 | unbind_to (count, Qnil); |
| 814 | } | 834 | } |
| 815 | 835 | ||
| @@ -823,6 +843,7 @@ really_delete_surrounding_text (struct frame *f, ptrdiff_t left, | |||
| 823 | { | 843 | { |
| 824 | specpdl_ref count; | 844 | specpdl_ref count; |
| 825 | ptrdiff_t start, end, a, b, a1, b1, lstart, rstart; | 845 | ptrdiff_t start, end, a, b, a1, b1, lstart, rstart; |
| 846 | struct window *w; | ||
| 826 | 847 | ||
| 827 | /* If F's old selected window is no longer live, fail. */ | 848 | /* If F's old selected window is no longer live, fail. */ |
| 828 | 849 | ||
| @@ -889,6 +910,10 @@ really_delete_surrounding_text (struct frame *f, ptrdiff_t left, | |||
| 889 | if (get_mark () == PT) | 910 | if (get_mark () == PT) |
| 890 | call0 (Qdeactivate_mark); | 911 | call0 (Qdeactivate_mark); |
| 891 | 912 | ||
| 913 | /* Update the ephemeral last point. */ | ||
| 914 | w = XWINDOW (selected_window); | ||
| 915 | w->ephemeral_last_point = PT; | ||
| 916 | |||
| 892 | unbind_to (count, Qnil); | 917 | unbind_to (count, Qnil); |
| 893 | } | 918 | } |
| 894 | 919 | ||
| @@ -904,6 +929,7 @@ really_set_point_and_mark (struct frame *f, ptrdiff_t point, | |||
| 904 | ptrdiff_t mark) | 929 | ptrdiff_t mark) |
| 905 | { | 930 | { |
| 906 | specpdl_ref count; | 931 | specpdl_ref count; |
| 932 | struct window *w; | ||
| 907 | 933 | ||
| 908 | /* If F's old selected window is no longer live, fail. */ | 934 | /* If F's old selected window is no longer live, fail. */ |
| 909 | 935 | ||
| @@ -922,7 +948,7 @@ really_set_point_and_mark (struct frame *f, ptrdiff_t point, | |||
| 922 | { | 948 | { |
| 923 | if (f->conversion.batch_edit_count > 0) | 949 | if (f->conversion.batch_edit_count > 0) |
| 924 | f->conversion.batch_edit_flags |= PENDING_POINT_CHANGE; | 950 | f->conversion.batch_edit_flags |= PENDING_POINT_CHANGE; |
| 925 | else | 951 | else if (text_interface && text_interface->point_changed) |
| 926 | text_interface->point_changed (f, | 952 | text_interface->point_changed (f, |
| 927 | XWINDOW (f->old_selected_window), | 953 | XWINDOW (f->old_selected_window), |
| 928 | current_buffer); | 954 | current_buffer); |
| @@ -936,6 +962,10 @@ really_set_point_and_mark (struct frame *f, ptrdiff_t point, | |||
| 936 | else | 962 | else |
| 937 | call1 (Qpush_mark, make_fixnum (mark)); | 963 | call1 (Qpush_mark, make_fixnum (mark)); |
| 938 | 964 | ||
| 965 | /* Update the ephemeral last point. */ | ||
| 966 | w = XWINDOW (selected_window); | ||
| 967 | w->ephemeral_last_point = PT; | ||
| 968 | |||
| 939 | unbind_to (count, Qnil); | 969 | unbind_to (count, Qnil); |
| 940 | } | 970 | } |
| 941 | 971 | ||
| @@ -949,9 +979,11 @@ complete_edit (void *token) | |||
| 949 | } | 979 | } |
| 950 | 980 | ||
| 951 | /* Process and free the text conversion ACTION. F must be the frame | 981 | /* Process and free the text conversion ACTION. F must be the frame |
| 952 | on which ACTION will be performed. */ | 982 | on which ACTION will be performed. |
| 953 | 983 | ||
| 954 | static void | 984 | Value is the window which was used, or NULL. */ |
| 985 | |||
| 986 | static struct window * | ||
| 955 | handle_pending_conversion_events_1 (struct frame *f, | 987 | handle_pending_conversion_events_1 (struct frame *f, |
| 956 | struct text_conversion_action *action) | 988 | struct text_conversion_action *action) |
| 957 | { | 989 | { |
| @@ -969,9 +1001,23 @@ handle_pending_conversion_events_1 (struct frame *f, | |||
| 969 | token = action->counter; | 1001 | token = action->counter; |
| 970 | xfree (action); | 1002 | xfree (action); |
| 971 | 1003 | ||
| 1004 | /* Text conversion events can still arrive immediately after | ||
| 1005 | `conversion_disabled_p' becomes true. In that case, process all | ||
| 1006 | events, but don't perform any associated actions. */ | ||
| 1007 | |||
| 1008 | if (conversion_disabled_p ()) | ||
| 1009 | return NULL; | ||
| 1010 | |||
| 972 | /* Make sure completion is signalled. */ | 1011 | /* Make sure completion is signalled. */ |
| 973 | count = SPECPDL_INDEX (); | 1012 | count = SPECPDL_INDEX (); |
| 974 | record_unwind_protect_ptr (complete_edit, &token); | 1013 | record_unwind_protect_ptr (complete_edit, &token); |
| 1014 | w = NULL; | ||
| 1015 | |||
| 1016 | if (WINDOW_LIVE_P (f->old_selected_window)) | ||
| 1017 | { | ||
| 1018 | w = XWINDOW (f->old_selected_window); | ||
| 1019 | buffer = XBUFFER (WINDOW_BUFFER (w)); | ||
| 1020 | } | ||
| 975 | 1021 | ||
| 976 | switch (operation) | 1022 | switch (operation) |
| 977 | { | 1023 | { |
| @@ -987,12 +1033,7 @@ handle_pending_conversion_events_1 (struct frame *f, | |||
| 987 | break; | 1033 | break; |
| 988 | 1034 | ||
| 989 | if (f->conversion.batch_edit_flags & PENDING_POINT_CHANGE) | 1035 | if (f->conversion.batch_edit_flags & PENDING_POINT_CHANGE) |
| 990 | { | 1036 | text_interface->point_changed (f, w, buffer); |
| 991 | w = XWINDOW (f->old_selected_window); | ||
| 992 | buffer = XBUFFER (WINDOW_BUFFER (w)); | ||
| 993 | |||
| 994 | text_interface->point_changed (f, w, buffer); | ||
| 995 | } | ||
| 996 | 1037 | ||
| 997 | if (f->conversion.batch_edit_flags & PENDING_COMPOSE_CHANGE) | 1038 | if (f->conversion.batch_edit_flags & PENDING_COMPOSE_CHANGE) |
| 998 | text_interface->compose_region_changed (f); | 1039 | text_interface->compose_region_changed (f); |
| @@ -1030,6 +1071,8 @@ handle_pending_conversion_events_1 (struct frame *f, | |||
| 1030 | } | 1071 | } |
| 1031 | 1072 | ||
| 1032 | unbind_to (count, Qnil); | 1073 | unbind_to (count, Qnil); |
| 1074 | |||
| 1075 | return w; | ||
| 1033 | } | 1076 | } |
| 1034 | 1077 | ||
| 1035 | /* Decrement the variable pointed to by *PTR. */ | 1078 | /* Decrement the variable pointed to by *PTR. */ |
| @@ -1055,6 +1098,8 @@ handle_pending_conversion_events (void) | |||
| 1055 | bool handled; | 1098 | bool handled; |
| 1056 | static int inside; | 1099 | static int inside; |
| 1057 | specpdl_ref count; | 1100 | specpdl_ref count; |
| 1101 | ptrdiff_t last_point; | ||
| 1102 | struct window *w; | ||
| 1058 | 1103 | ||
| 1059 | handled = false; | 1104 | handled = false; |
| 1060 | 1105 | ||
| @@ -1065,6 +1110,8 @@ handle_pending_conversion_events (void) | |||
| 1065 | Vtext_conversion_edits = Qnil; | 1110 | Vtext_conversion_edits = Qnil; |
| 1066 | 1111 | ||
| 1067 | inside++; | 1112 | inside++; |
| 1113 | last_point = -1; | ||
| 1114 | w = NULL; | ||
| 1068 | 1115 | ||
| 1069 | count = SPECPDL_INDEX (); | 1116 | count = SPECPDL_INDEX (); |
| 1070 | record_unwind_protect_ptr (decrement_inside, &inside); | 1117 | record_unwind_protect_ptr (decrement_inside, &inside); |
| @@ -1077,16 +1124,26 @@ handle_pending_conversion_events (void) | |||
| 1077 | process them in bottom to up order. */ | 1124 | process them in bottom to up order. */ |
| 1078 | while (true) | 1125 | while (true) |
| 1079 | { | 1126 | { |
| 1080 | /* Redisplay in between if there is more than one | 1127 | /* Update the input method if handled && |
| 1081 | action. | 1128 | w->ephemeral_last_point != last_point. */ |
| 1082 | 1129 | if (w && (last_point != w->ephemeral_last_point)) | |
| 1083 | This can read input. This function must be reentrant | 1130 | { |
| 1084 | here. */ | 1131 | if (handled |
| 1085 | 1132 | && last_point != -1 | |
| 1086 | if (handled) | 1133 | && text_interface |
| 1087 | redisplay (); | 1134 | && text_interface->point_changed) |
| 1135 | { | ||
| 1136 | if (f->conversion.batch_edit_count > 0) | ||
| 1137 | f->conversion.batch_edit_flags |= PENDING_POINT_CHANGE; | ||
| 1138 | else | ||
| 1139 | text_interface->point_changed (f, NULL, NULL); | ||
| 1140 | } | ||
| 1141 | |||
| 1142 | last_point = w->ephemeral_last_point; | ||
| 1143 | } | ||
| 1088 | 1144 | ||
| 1089 | /* Reload action. */ | 1145 | /* Reload action. This needs to be reentrant as buffer |
| 1146 | modification functions can call `read-char'. */ | ||
| 1090 | action = f->conversion.actions; | 1147 | action = f->conversion.actions; |
| 1091 | 1148 | ||
| 1092 | /* If there are no more actions, break. */ | 1149 | /* If there are no more actions, break. */ |
| @@ -1099,7 +1156,7 @@ handle_pending_conversion_events (void) | |||
| 1099 | f->conversion.actions = next; | 1156 | f->conversion.actions = next; |
| 1100 | 1157 | ||
| 1101 | /* Handle and free the action. */ | 1158 | /* Handle and free the action. */ |
| 1102 | handle_pending_conversion_events_1 (f, action); | 1159 | w = handle_pending_conversion_events_1 (f, action); |
| 1103 | handled = true; | 1160 | handled = true; |
| 1104 | } | 1161 | } |
| 1105 | } | 1162 | } |
| @@ -1399,6 +1456,16 @@ get_extracted_text (struct frame *f, ptrdiff_t n, | |||
| 1399 | return buffer; | 1456 | return buffer; |
| 1400 | } | 1457 | } |
| 1401 | 1458 | ||
| 1459 | /* Return whether or not text conversion is temporarily disabled. | ||
| 1460 | `reset' should always call this to determine whether or not to | ||
| 1461 | disable the input method. */ | ||
| 1462 | |||
| 1463 | bool | ||
| 1464 | conversion_disabled_p (void) | ||
| 1465 | { | ||
| 1466 | return suppress_conversion_count > 0; | ||
| 1467 | } | ||
| 1468 | |||
| 1402 | 1469 | ||
| 1403 | 1470 | ||
| 1404 | /* Window system interface. These are called from the rest of | 1471 | /* Window system interface. These are called from the rest of |
| @@ -1440,6 +1507,60 @@ report_point_change (struct frame *f, struct window *window, | |||
| 1440 | text_interface->point_changed (f, window, buffer); | 1507 | text_interface->point_changed (f, window, buffer); |
| 1441 | } | 1508 | } |
| 1442 | 1509 | ||
| 1510 | /* Temporarily disable text conversion. Must be paired with a | ||
| 1511 | corresponding call to resume_text_conversion. */ | ||
| 1512 | |||
| 1513 | void | ||
| 1514 | disable_text_conversion (void) | ||
| 1515 | { | ||
| 1516 | Lisp_Object tail, frame; | ||
| 1517 | struct frame *f; | ||
| 1518 | |||
| 1519 | suppress_conversion_count++; | ||
| 1520 | |||
| 1521 | if (!text_interface || suppress_conversion_count > 1) | ||
| 1522 | return; | ||
| 1523 | |||
| 1524 | /* Loop through and reset the input method on each window system | ||
| 1525 | frame. It should call conversion_disabled_p and then DTRT. */ | ||
| 1526 | |||
| 1527 | FOR_EACH_FRAME (tail, frame) | ||
| 1528 | { | ||
| 1529 | f = XFRAME (frame); | ||
| 1530 | reset_frame_state (f); | ||
| 1531 | |||
| 1532 | if (FRAME_WINDOW_P (f) && FRAME_VISIBLE_P (f)) | ||
| 1533 | text_interface->reset (f); | ||
| 1534 | } | ||
| 1535 | } | ||
| 1536 | |||
| 1537 | /* Undo the effect of the last call to `disable_text_conversion'. */ | ||
| 1538 | |||
| 1539 | void | ||
| 1540 | resume_text_conversion (void) | ||
| 1541 | { | ||
| 1542 | Lisp_Object tail, frame; | ||
| 1543 | struct frame *f; | ||
| 1544 | |||
| 1545 | suppress_conversion_count--; | ||
| 1546 | eassert (suppress_conversion_count >= 0); | ||
| 1547 | |||
| 1548 | if (!text_interface || suppress_conversion_count) | ||
| 1549 | return; | ||
| 1550 | |||
| 1551 | /* Loop through and reset the input method on each window system | ||
| 1552 | frame. It should call conversion_disabled_p and then DTRT. */ | ||
| 1553 | |||
| 1554 | FOR_EACH_FRAME (tail, frame) | ||
| 1555 | { | ||
| 1556 | f = XFRAME (frame); | ||
| 1557 | reset_frame_state (f); | ||
| 1558 | |||
| 1559 | if (FRAME_WINDOW_P (f) && FRAME_VISIBLE_P (f)) | ||
| 1560 | text_interface->reset (f); | ||
| 1561 | } | ||
| 1562 | } | ||
| 1563 | |||
| 1443 | /* Register INTERFACE as the text conversion interface. */ | 1564 | /* Register INTERFACE as the text conversion interface. */ |
| 1444 | 1565 | ||
| 1445 | void | 1566 | void |
| @@ -1450,6 +1571,59 @@ register_textconv_interface (struct textconv_interface *interface) | |||
| 1450 | 1571 | ||
| 1451 | 1572 | ||
| 1452 | 1573 | ||
| 1574 | /* Lisp interface. */ | ||
| 1575 | |||
| 1576 | DEFUN ("set-text-conversion-style", Fset_text_conversion_style, | ||
| 1577 | Sset_text_conversion_style, 1, 1, 0, | ||
| 1578 | doc: /* Set the text conversion style in the current buffer. | ||
| 1579 | |||
| 1580 | Set `text-conversion-mode' to VALUE, then force any input method | ||
| 1581 | editing frame displaying this buffer to stop itself. | ||
| 1582 | |||
| 1583 | This can lead to a significant amount of time being taken by the input | ||
| 1584 | method resetting itself, so you should not use this function lightly; | ||
| 1585 | instead, set `text-conversion-mode' before your buffer is displayed, | ||
| 1586 | and let redisplay manage the input method appropriately. */) | ||
| 1587 | (Lisp_Object value) | ||
| 1588 | { | ||
| 1589 | Lisp_Object tail, frame; | ||
| 1590 | struct frame *f; | ||
| 1591 | Lisp_Object buffer; | ||
| 1592 | |||
| 1593 | bset_text_conversion_style (current_buffer, value); | ||
| 1594 | |||
| 1595 | if (!text_interface) | ||
| 1596 | return Qnil; | ||
| 1597 | |||
| 1598 | /* If there are any seleted windows displaying this buffer, reset | ||
| 1599 | text conversion on their associated frames. */ | ||
| 1600 | |||
| 1601 | if (buffer_window_count (current_buffer)) | ||
| 1602 | { | ||
| 1603 | buffer = Fcurrent_buffer (); | ||
| 1604 | |||
| 1605 | FOR_EACH_FRAME (tail, frame) | ||
| 1606 | { | ||
| 1607 | f = XFRAME (frame); | ||
| 1608 | |||
| 1609 | if (WINDOW_LIVE_P (f->old_selected_window) | ||
| 1610 | && FRAME_WINDOW_P (f) | ||
| 1611 | && EQ (XWINDOW (f->old_selected_window)->contents, | ||
| 1612 | buffer)) | ||
| 1613 | { | ||
| 1614 | block_input (); | ||
| 1615 | reset_frame_state (f); | ||
| 1616 | text_interface->reset (f); | ||
| 1617 | unblock_input (); | ||
| 1618 | } | ||
| 1619 | } | ||
| 1620 | } | ||
| 1621 | |||
| 1622 | return Qnil; | ||
| 1623 | } | ||
| 1624 | |||
| 1625 | |||
| 1626 | |||
| 1453 | void | 1627 | void |
| 1454 | syms_of_textconv (void) | 1628 | syms_of_textconv (void) |
| 1455 | { | 1629 | { |
| @@ -1457,6 +1631,7 @@ syms_of_textconv (void) | |||
| 1457 | DEFSYM (Qtext_conversion, "text-conversion"); | 1631 | DEFSYM (Qtext_conversion, "text-conversion"); |
| 1458 | DEFSYM (Qpush_mark, "push-mark"); | 1632 | DEFSYM (Qpush_mark, "push-mark"); |
| 1459 | DEFSYM (Qunderline, "underline"); | 1633 | DEFSYM (Qunderline, "underline"); |
| 1634 | DEFSYM (Qoverriding_text_conversion_style, "overriding-text-conversion-style"); | ||
| 1460 | 1635 | ||
| 1461 | DEFVAR_LISP ("text-conversion-edits", Vtext_conversion_edits, | 1636 | DEFVAR_LISP ("text-conversion-edits", Vtext_conversion_edits, |
| 1462 | doc: /* List of buffers that were last edited as a result of text conversion. | 1637 | doc: /* List of buffers that were last edited as a result of text conversion. |
| @@ -1480,4 +1655,21 @@ inserted. | |||
| 1480 | If a deletion occured, then BEG and END are the same, and EPHEMERAL is | 1655 | If a deletion occured, then BEG and END are the same, and EPHEMERAL is |
| 1481 | nil. */); | 1656 | nil. */); |
| 1482 | Vtext_conversion_edits = Qnil; | 1657 | Vtext_conversion_edits = Qnil; |
| 1658 | |||
| 1659 | DEFVAR_LISP ("overriding-text-conversion-style", | ||
| 1660 | Voverriding_text_conversion_style, | ||
| 1661 | doc: /* Non-buffer local version of `text-conversion-style'. | ||
| 1662 | |||
| 1663 | If this variable is the symbol `lambda', it means to consult the | ||
| 1664 | buffer local variable `text-conversion-style' to determine whether or | ||
| 1665 | not to activate the input method. Otherwise, its value is used in | ||
| 1666 | preference to any buffer local value of `text-conversion-style'. */); | ||
| 1667 | Voverriding_text_conversion_style = Qlambda; | ||
| 1668 | |||
| 1669 | DEFVAR_LISP ("text-conversion-face", Vtext_conversion_face, | ||
| 1670 | doc: /* Face in which to display temporary edits by an input method. | ||
| 1671 | nil means to display no indication of a temporary edit. */); | ||
| 1672 | Vtext_conversion_face = Qunderline; | ||
| 1673 | |||
| 1674 | defsubr (&Sset_text_conversion_style); | ||
| 1483 | } | 1675 | } |
diff --git a/src/textconv.h b/src/textconv.h index 034c663521a..16d13deb092 100644 --- a/src/textconv.h +++ b/src/textconv.h | |||
| @@ -140,6 +140,7 @@ extern void delete_surrounding_text (struct frame *, ptrdiff_t, | |||
| 140 | ptrdiff_t, unsigned long); | 140 | ptrdiff_t, unsigned long); |
| 141 | extern char *get_extracted_text (struct frame *, ptrdiff_t, ptrdiff_t *, | 141 | extern char *get_extracted_text (struct frame *, ptrdiff_t, ptrdiff_t *, |
| 142 | ptrdiff_t *, ptrdiff_t *, ptrdiff_t *); | 142 | ptrdiff_t *, ptrdiff_t *, ptrdiff_t *); |
| 143 | extern bool conversion_disabled_p (void); | ||
| 143 | 144 | ||
| 144 | extern void register_textconv_interface (struct textconv_interface *); | 145 | extern void register_textconv_interface (struct textconv_interface *); |
| 145 | 146 | ||
diff --git a/src/window.h b/src/window.h index 463c7f89b9b..36b1bfb7283 100644 --- a/src/window.h +++ b/src/window.h | |||
| @@ -286,6 +286,21 @@ struct window | |||
| 286 | it should be positive. */ | 286 | it should be positive. */ |
| 287 | ptrdiff_t last_point; | 287 | ptrdiff_t last_point; |
| 288 | 288 | ||
| 289 | #ifdef HAVE_TEXT_CONVERSION | ||
| 290 | /* ``ephemeral'' last point position. This is used while | ||
| 291 | processing text conversion events. | ||
| 292 | |||
| 293 | `last_point' is normally used during redisplay to indicate the | ||
| 294 | position of point as seem by the input method. However, it is | ||
| 295 | not updated if consequtive conversions are processed at the | ||
| 296 | same time. | ||
| 297 | |||
| 298 | This `ephemeral_last_point' field is either the last point as | ||
| 299 | set in redisplay or the last point after a text editing | ||
| 300 | operation. */ | ||
| 301 | ptrdiff_t ephemeral_last_point; | ||
| 302 | #endif | ||
| 303 | |||
| 289 | /* Value of mark in the selected window at the time of the last | 304 | /* Value of mark in the selected window at the time of the last |
| 290 | redisplay. */ | 305 | redisplay. */ |
| 291 | ptrdiff_t last_mark; | 306 | ptrdiff_t last_mark; |
diff --git a/src/xdisp.c b/src/xdisp.c index 525eaa64b3a..a17fa97ee20 100644 --- a/src/xdisp.c +++ b/src/xdisp.c | |||
| @@ -17315,6 +17315,9 @@ mark_window_display_accurate_1 (struct window *w, bool accurate_p) | |||
| 17315 | w->last_mark = -1; | 17315 | w->last_mark = -1; |
| 17316 | 17316 | ||
| 17317 | #ifdef HAVE_TEXT_CONVERSION | 17317 | #ifdef HAVE_TEXT_CONVERSION |
| 17318 | /* See the description of this field in struct window. */ | ||
| 17319 | w->ephemeral_last_point = w->last_point; | ||
| 17320 | |||
| 17318 | /* Point motion is only propagated to the input method for use | 17321 | /* Point motion is only propagated to the input method for use |
| 17319 | in text conversion during a redisplay. While this can lead | 17322 | in text conversion during a redisplay. While this can lead |
| 17320 | to inconsistencies when point has moved but the change has | 17323 | to inconsistencies when point has moved but the change has |