named @code{sfnt-android} and @code{android}.
Upon startup, Emacs enumerates all the TrueType format fonts in the
-directory @file{/system/fonts}; this is where the Android system
-places fonts. Emacs assumes there will always be a font named ``Droid
-Sans Mono'', and then defaults to using this font. These fonts are
-then rendered by the @code{sfnt-android} font driver.
+directory @file{/system/fonts}, and the @file{fonts} directory inside
+the Emacs home directory. Emacs assumes there will always be a font
+named ``Droid Sans Mono'', and then defaults to using this font.
+These fonts are then displayed by the @code{sfnt-android} font driver.
When running on Android, Emacs currently lacks support for OpenType
fonts. This means that only a subset of the fonts installed on the
a request to perform the conversion from the input method. After the
conversion completes, a @code{text-conversion} event is sent.
@xref{Misc Events,,, elisp, the Emacs Reference Manual}.
+
+@vindex text-conversion-face
+ If the input method needs to work on a region of the buffer, then
+the region becomes known as the ``composing region'' (or
+``preconversion region''.) The variable @code{text-conversion-face}
+describes whether or not to display the composing region in a specific
+face.
how an input method that wishes to make edits to buffer contents will
behave.
-This variable can have one three values:
+This variable can have one of three values:
@table @code
@item nil
@item t
This, or any other value, means that the input method will be enabled
and make edits terminated by @code{text-conversion} events.
-@end itemize
+@end table
+@findex disable-text-conversion
Changes to the value of this variable will only take effect upon
the next redisplay after the buffer becomes the selected buffer
-of a frame.
+of a frame. If you need to disable text conversion in a way
+that takes immediate effect, call the function
+@code{set-text-conversion-style} instead. This can potentially
+lock up the input method for a significant amount of time, so do
+not do this lightly!
@cindex @code{delete-frame} event
@item (delete-frame (@var{frame}))
setComposingText (CharSequence text, int newCursorPosition)
{
if (EmacsService.DEBUG_IC)
- Log.d (TAG, "setComposingText: " + newCursorPosition);
+ Log.d (TAG, ("setComposingText: "
+ + text + " ## " + newCursorPosition));
EmacsNative.setComposingText (windowHandle, text.toString (),
newCursorPosition);
flags);
}
+ @Override
+ public boolean
+ setSelection (int start, int end)
+ {
+ if (EmacsService.DEBUG_IC)
+ Log.d (TAG, "setSelection: " + start + " " + end);
+
+ EmacsNative.setSelection (windowHandle, start, end);
+ return true;
+ }
+
\f
/* Override functions which are not implemented. */
import android.graphics.Rect;
import android.graphics.Paint;
+import java.lang.ref.WeakReference;
+
/* This originally extended SurfaceView. However, doing so proved to
be too slow, and Android's surface view keeps up to three of its
own back buffers, which use too much memory (up to 96 MB for a
private EmacsView view;
private Bitmap frontBuffer;
private Canvas bitmapCanvas;
- private Bitmap bitmap;
+ private WeakReference<Bitmap> bitmap;
private Paint bitmapPaint;
public
this.view = view;
this.bitmapPaint = new Paint ();
+ this.bitmap = new WeakReference<Bitmap> (null);
}
private void
- copyToFrontBuffer (Rect damageRect)
+ copyToFrontBuffer (Bitmap bitmap, Rect damageRect)
{
if (damageRect != null)
bitmapCanvas.drawBitmap (bitmap, damageRect, damageRect,
bitmapCanvas = null;
}
- this.bitmap = bitmap;
+ this.bitmap = new WeakReference<Bitmap> (bitmap);
/* Next, create the new front buffer if necessary. */
bitmapCanvas = new Canvas (frontBuffer);
/* And copy over the bitmap contents. */
- copyToFrontBuffer (null);
+ copyToFrontBuffer (bitmap, null);
}
else if (bitmap != null)
/* Just copy over the bitmap contents. */
- copyToFrontBuffer (null);
+ copyToFrontBuffer (bitmap, null);
}
public synchronized void
setBitmap (Bitmap bitmap, Rect damageRect)
{
- if (bitmap != this.bitmap)
+ if (bitmap != this.bitmap.get ())
reconfigureFrontBuffer (bitmap);
else if (bitmap != null)
- copyToFrontBuffer (damageRect);
+ copyToFrontBuffer (bitmap, damageRect);
if (bitmap != null)
{
/* Explicitly free the old bitmap's memory. */
if (oldBitmap != null)
- {
- oldBitmap.recycle ();
-
- /* Make sure to set the view's bitmap to the new bitmap, or
- ugly flicker can result. */
- surfaceView.setBitmap (bitmap, null);
- }
+ oldBitmap.recycle ();
/* Some Android versions still don't free the bitmap until the
next GC. */
(setq-local comint-last-input-start (point-min-marker))
(setq-local comint-last-input-end (point-min-marker))
(setq-local comint-last-output-start (make-marker))
+ ;; It is ok to let the input method edit prompt text, but RET must
+ ;; be processed by Emacs.
+ (setq text-conversion-style 'action)
(make-local-variable 'comint-last-prompt)
(make-local-variable 'comint-prompt-regexp) ; Don't set; default
(make-local-variable 'comint-input-ring-size) ; ...to global val.
(symbol . [#x201C #x2200 #x2500])
(braille #x2800)
(ideographic-description #x2FF0)
- (cjk-misc #x300E)
+ (cjk-misc #x300E #xff0c)
(kana #x304B)
(bopomofo #x3105)
(kanbun #x319D)
(nil . "JISX0213.2000-2")
(nil . "JISX0213.2004-1")
,(font-spec :registry "iso10646-1" :lang 'ja)
- ,(font-spec :registry "iso10646-1" :lang 'zh))
+ ,(font-spec :registry "iso10646-1" :lang 'zh)
+ ;; This is required, as otherwise many TrueType fonts with
+ ;; CJK characters but no corresponding ``design language''
+ ;; declaration can't be found.
+ ,(font-spec :registry "iso10646-1" :script 'han))
(cjk-misc (nil . "GB2312.1980-0")
(nil . "JISX0208*")
(nil . "JISX0213.2000-1")
(nil . "JISX0213.2000-2")
,(font-spec :registry "iso10646-1" :lang 'ja)
- ,(font-spec :registry "iso10646-1" :lang 'zh))
+ ,(font-spec :registry "iso10646-1" :lang 'zh)
+ ;; This is required, as otherwise many TrueType fonts
+ ;; with CJK characters but no corresponding ``design
+ ;; language'' declaration can't be found.
+ ,(font-spec :registry "iso10646-1" :script 'cjk-misc))
(hangul (nil . "KSC5601.1987-0")
,(font-spec :registry "iso10646-1" :lang 'ko))
`isearch-message-prefix' advice property to specify the prefix string
displayed in the search message.")
+(defvar isearch-text-conversion-style nil
+ "Value of `text-conversion-style' before Isearch mode
+was enabled in this buffer.")
+
;; Search ring.
(defvar search-ring nil
;; isearch-forward-regexp isearch-backward-regexp)
;; "List of commands for which isearch-mode does not recursive-edit.")
+(declare-function set-text-conversion-style "textconv.c")
+
(defun isearch-mode (forward &optional regexp op-fun recursive-edit regexp-function)
"Start Isearch minor mode.
It is called by the function `isearch-forward' and other related functions.
'keyboard)))
(frame-toggle-on-screen-keyboard (selected-frame) nil))
+ ;; Disable text conversion so that isearch can behave correctly.
+
+ (when (fboundp 'set-text-conversion-style)
+ (setq isearch-text-conversion-style
+ text-conversion-style)
+ (set-text-conversion-style nil))
+
;; isearch-mode can be made modal (in the sense of not returning to
;; the calling function until searching is completed) by entering
;; a recursive-edit and exiting it when done isearching.
(setq isearch-tool-bar-old-map nil))
(kill-local-variable 'tool-bar-map))
+ ;; Restore the previous text conversion style.
+ (when (fboundp 'set-text-conversion-style)
+ (set-text-conversion-style isearch-text-conversion-style))
+
(force-mode-line-update)
;; If we ended in the middle of some intangible text,
`minibuffer-setup-hook' and `minibuffer-exit-hook' rather than
the mode hook of this mode."
:syntax-table nil
- :interactive nil)
+ :interactive nil
+ ;; Enable text conversion, but always make sure `RET' does
+ ;; something.
+ (setq text-conversion-style 'action))
;;; Completion tables.
line breaking of the previous line when `auto-fill-mode' is
enabled.
- - Look for the insertion of a new line, and indent this new
- line if `electric-indent-mode' is enabled."
+ - Run `post-self-insert-functions' for the last character of
+ any inserted text so that modes such as `electric-pair-mode'
+ can work."
(interactive)
(dolist (edit text-conversion-edits)
;; Filter out ephemeral edits and deletions.
(when (and auto-fill-function auto-fill-p)
(progn (goto-char (nth 2 edit))
(funcall auto-fill-function)))))
- (when (and electric-indent-mode newline-p)
- (goto-char (nth 2 edit))
- (indent-according-to-mode)))))))
+ (goto-char (nth 2 edit))
+ (let ((last-command-event end))
+ (run-hooks 'post-self-insert-hook)))))))
\f
(minibuffer-message "Wrong answer")
(sit-for 2)))
+;; Defined in textconv.c.
+(defvar overriding-text-conversion-style)
+
(defun read-char-from-minibuffer (prompt &optional chars history)
"Read a character from the minibuffer, prompting for it with PROMPT.
Like `read-char', but uses the minibuffer to read and return a character.
causes it to evaluate `help-form' and display the result.
There is no need to explicitly add `help-char' to CHARS;
`help-char' is bound automatically to `help-form-show'."
- (let* ((map (if (consp chars)
+
+ ;; If text conversion is enabled in this buffer, then it will only
+ ;; be disabled the next time `force-mode-line-update' happens.
+ (when (and overriding-text-conversion-style
+ text-conversion-style)
+ (force-mode-line-update))
+
+ (let* ((overriding-text-conversion-style nil)
+ (map (if (consp chars)
(or (gethash (list help-form (cons help-char chars))
read-char-from-minibuffer-map-hash)
(let ((map (make-sparse-keymap))
;; being a command char.
(when help-form
(define-key map (vector help-char)
- (lambda ()
- (interactive)
- (let ((help-form msg)) ; lexically bound msg
- (help-form-show)))))
+ (lambda ()
+ (interactive)
+ (let ((help-form msg)) ; lexically bound msg
+ (help-form-show)))))
(dolist (char chars)
(define-key map (vector char)
- #'read-char-from-minibuffer-insert-char))
+ #'read-char-from-minibuffer-insert-char))
(define-key map [remap self-insert-command]
- #'read-char-from-minibuffer-insert-other)
+ #'read-char-from-minibuffer-insert-other)
(puthash (list help-form (cons help-char chars))
map read-char-from-minibuffer-map-hash)
map))
{
struct android_swap_info swap_info;
- /* Somehow Android frames can be swapped while garbaged. */
- if (FRAME_GARBAGED_P (f))
- return;
-
memset (&swap_info, 0, sizeof (swap_info));
swap_info.swap_window = FRAME_ANDROID_WINDOW (f);
swap_info.swap_action = ANDROID_COPIED;
/* Figure out where the point and mark are. If the mark is not
active, then point is set to equal mark. */
b = XBUFFER (w->contents);
- point = min (w->last_point, TYPE_MAXIMUM (jint));
+ point = min (w->ephemeral_last_point,
+ TYPE_MAXIMUM (jint));
mark = ((!NILP (BVAR (b, mark_active))
&& w->last_mark != -1)
? min (w->last_mark, TYPE_MAXIMUM (jint))
enum android_ic_mode mode;
struct window *w;
struct buffer *buffer;
+ Lisp_Object style;
/* Reset the input method.
w = XWINDOW (f->selected_window);
buffer = XBUFFER (WINDOW_BUFFER (w));
- if (NILP (BVAR (buffer, text_conversion_style)))
+ style = (EQ (find_symbol_value (Qoverriding_text_conversion_style),
+ Qlambda)
+ ? BVAR (buffer, text_conversion_style)
+ : find_symbol_value (Qoverriding_text_conversion_style));
+
+ if (NILP (style) || conversion_disabled_p ())
mode = ANDROID_IC_MODE_NULL;
- else if (EQ (BVAR (buffer, text_conversion_style),
- Qaction))
+ else if (EQ (style, Qaction) || EQ (f->selected_window,
+ f->minibuffer_window))
mode = ANDROID_IC_MODE_ACTION;
else
mode = ANDROID_IC_MODE_TEXT;
- android_reset_ic (FRAME_ANDROID_WINDOW (f),
- (EQ (f->selected_window,
- f->minibuffer_window)
- ? ANDROID_IC_MODE_ACTION
- : mode));
+ android_reset_ic (FRAME_ANDROID_WINDOW (f), mode);
/* Move its selection to the specified position. */
android_update_selection (f, NULL);
DEFVAR_PER_BUFFER ("text-conversion-style", &BVAR (current_buffer,
text_conversion_style),
Qnil,
- "How the on screen keyboard's input method should insert in this buffer.\n\
-When nil, the input method will be disabled and an ordinary keyboard\n\
-will be displayed in its place.\n\
-When the symbol `action', the input method will insert text directly, but\n\
-will send `return' key events instead of inserting new line characters.\n\
-Any other value means that the input method will insert text directly.\n\
-\n\
-This variable does not take immediate effect when set; rather, it takes\n\
-effect upon the next redisplay after the selected window or buffer changes.");
+ doc: /* How the on screen keyboard's input method should insert in this buffer.
+When nil, the input method will be disabled and an ordinary keyboard
+will be displayed in its place.
+When the symbol `action', the input method will insert text directly, but
+will send `return' key events instead of inserting new line characters.
+Any other value means that the input method will insert text directly.
+
+If you need to make non-buffer local changes to this variable, use
+`overriding-text-conversion-style', which see.
+
+This variable does not take immediate effect when set; rather, it
+takes effect upon the next redisplay after the selected window or
+buffer changes. */);
DEFVAR_LISP ("kill-buffer-query-functions", Vkill_buffer_query_functions,
doc: /* List of functions called with no args to query before killing a buffer.
x_handle_pending_selection_requests ();
#endif
-#ifdef HAVE_TEXT_CONVERSION
- /* Handle pending ``text conversion'' requests from an input
- method. */
-
- if (had_pending_conversion_events)
- handle_pending_conversion_events ();
-#endif
-
if (CONSP (Vunread_command_events))
{
Lisp_Object first;
return first;
}
+#ifdef HAVE_TEXT_CONVERSION
+ /* There are pending text conversion operations. Text conversion
+ events should be generated before processing any other keyboard
+ input. */
+ if (had_pending_conversion_events)
+ {
+ handle_pending_conversion_events ();
+ obj = Qtext_conversion;
+
+ /* See the comment in handle_pending_conversion_events_1.
+ Note that in addition, text conversion events are not
+ generated if no edits were actually made. */
+ if (conversion_disabled_p ()
+ || NILP (Vtext_conversion_edits))
+ obj = Qnil;
+ }
+ else
+#endif
/* At this point, we know that there is a readable event available
somewhere. If the event queue is empty, then there must be a
mouse movement enabled and available. */
#ifdef HAVE_X_WINDOWS
else if (had_pending_selection_requests)
obj = Qnil;
-#endif
-#ifdef HAVE_TEXT_CONVERSION
- /* This is an internal event used to prevent Emacs from becoming
- idle immediately after a text conversion operation. */
- else if (had_pending_conversion_events)
- obj = Qtext_conversion;
#endif
else
/* We were promised by the above while loop that there was
something for us to read! */
emacs_abort ();
-#ifdef HAVE_TEXT_CONVERSION
- /* While not implemented as keyboard commands, changes made by the
- input method still mean that Emacs is no longer idle. */
- if (had_pending_conversion_events)
- timer_stop_idle ();
-#endif
-
input_pending = readable_events (0);
Vlast_event_frame = internal_last_event_frame;
extern void report_selected_window_change (struct frame *);
extern void report_point_change (struct frame *, struct window *,
struct buffer *);
+extern void disable_text_conversion (void);
+extern void resume_text_conversion (void);
extern void syms_of_textconv (void);
#endif
if the character warrants that.
If SECONDS is a number, wait that many seconds for input, and
- return Qnil if no input arrives within that time. */
+ return Qnil if no input arrives within that time.
+
+ If text conversion is enabled and ASCII_REQUIRED && ERROR_NONASCII,
+ temporarily disable any input method which wants to perform
+ edits. */
static Lisp_Object
read_filtered_event (bool no_switch_frame, bool ascii_required,
{
Lisp_Object val, delayed_switch_frame;
struct timespec end_time;
+#ifdef HAVE_TEXT_CONVERSION
+ specpdl_ref count;
+#endif
#ifdef HAVE_WINDOW_SYSTEM
if (display_hourglass_p)
cancel_hourglass ();
#endif
+#ifdef HAVE_TEXT_CONVERSION
+ count = SPECPDL_INDEX ();
+
+ /* Don't use text conversion when trying to just read a
+ character. */
+
+ if (ascii_required && error_nonascii)
+ {
+ disable_text_conversion ();
+ record_unwind_protect_void (resume_text_conversion);
+ }
+#endif
+
delayed_switch_frame = Qnil;
/* Compute timeout. */
#endif
+#ifdef HAVE_TEXT_CONVERSION
+ return unbind_to (count, val);
+#else
return val;
+#endif
}
DEFUN ("read-char", Fread_char, Sread_char, 0, 3, 0,
result->y = control1->y + ((control2->y - control1->y) >> 1);
}
+/* Decompose contour data inside X, Y and FLAGS, between the indices
+ HERE and LAST. Call LINE_TO, CURVE_TO and MOVE_TO as appropriate,
+ with DCONTEXT as an argument. Apply SCALE to each point; SCALE
+ should be the factor necessary to turn points into 16.16 fixed
+ point.
+
+ Value is 1 upon failure, else 0. */
+
+static int
+sfnt_decompose_glyph_1 (size_t here, size_t last,
+ sfnt_move_to_proc move_to,
+ sfnt_line_to_proc line_to,
+ sfnt_curve_to_proc curve_to,
+ void *dcontext,
+ sfnt_fword *x,
+ sfnt_fword *y, unsigned char *flags,
+ int scale)
+{
+ struct sfnt_point control1, control2, start, mid;
+ size_t i;
+
+ /* The contour is empty. */
+
+ if (here == last)
+ return 1;
+
+ /* Move the pen to the start of the contour. Apparently some fonts
+ have off the curve points as the start of a contour, so when that
+ happens lerp between the first and last points. */
+
+ if (flags[here] & 01) /* On Curve */
+ {
+ control1.x = x[here] * scale;
+ control1.y = y[here] * scale;
+ start = control1;
+ }
+ else if (flags[last] & 01)
+ {
+ /* Start at the last point if it is on the curve. Here, the
+ start really becomes the middle of a spline. */
+ control1.x = x[last] * scale;
+ control1.y = y[last] * scale;
+ start = control1;
+
+ /* Curve back one point early. */
+ last -= 1;
+ here -= 1;
+ }
+ else
+ {
+ /* Lerp between the start and the end. */
+ control1.x = x[here] * scale;
+ control1.y = y[here] * scale;
+ control2.x = x[last] * scale;
+ control2.y = y[last] * scale;
+ sfnt_lerp_half (&control1, &control2, &start);
+
+ /* In either of these cases, start iterating from just here as
+ opposed to here + 1, since logically the contour now starts
+ from the last curve. */
+ here -= 1;
+ }
+
+ /* Move to the start. */
+ move_to (start, dcontext);
+
+ /* Now handle each point between here + 1 and last. */
+
+ i = here;
+ while (++i <= last)
+ {
+ /* If the point is on the curve, then draw a line here from the
+ last control point. */
+
+ if (flags[i] & 01)
+ {
+ control1.x = x[i] * scale;
+ control1.y = y[i] * scale;
+
+ line_to (control1, dcontext);
+
+ /* Move to the next point. */
+ continue;
+ }
+
+ /* Off the curve points are more interesting. They are handled
+ one by one, with points in between being interpolated, until
+ either the last point is reached or an on-curve point is
+ processed. First, load the initial control points. */
+
+ control1.x = x[i] * scale;
+ control1.y = y[i] * scale;
+
+ while (++i <= last)
+ {
+ /* Load this point. */
+ control2.x = x[i] * scale;
+ control2.y = y[i] * scale;
+
+ /* If this point is on the curve, curve directly to this
+ point. */
+
+ if (flags[i] & 01)
+ {
+ curve_to (control1, control2, dcontext);
+ goto continue_loop;
+ }
+
+ /* Calculate the point between here and the previous
+ point. */
+ sfnt_lerp_half (&control1, &control2, &mid);
+
+ /* Curve over there. */
+ curve_to (control1, mid, dcontext);
+
+ /* Reload the control point. */
+ control1 = control2;
+ }
+
+ /* Close the contour by curving back to start. */
+ curve_to (control1, start, dcontext);
+
+ /* Don't close the contour twice. */
+ goto exit;
+
+ continue_loop:
+ continue;
+ }
+
+ /* Close the contour with a line back to start. */
+ line_to (start, dcontext);
+
+ exit:
+ return 0;
+}
+
+/* Decompose contour data inside X, Y and FLAGS, between the indices
+ HERE and LAST. Call LINE_TO, CURVE_TO and MOVE_TO as appropriate,
+ with DCONTEXT as an argument. Apply SCALE to each point; SCALE
+ should be the factor necessary to turn points into 16.16 fixed
+ point.
+
+ This is the version of sfnt_decompose_glyph_1 which takes
+ sfnt_fixed (or sfnt_f26dot6) as opposed to sfnt_fword.
+
+ Value is 1 upon failure, else 0. */
+
+static int
+sfnt_decompose_glyph_2 (size_t here, size_t last,
+ sfnt_move_to_proc move_to,
+ sfnt_line_to_proc line_to,
+ sfnt_curve_to_proc curve_to,
+ void *dcontext,
+ sfnt_fixed *x,
+ sfnt_fixed *y, unsigned char *flags,
+ int scale)
+{
+ struct sfnt_point control1, control2, start, mid;
+ size_t i;
+
+ /* The contour is empty. */
+
+ if (here == last)
+ return 1;
+
+ /* Move the pen to the start of the contour. Apparently some fonts
+ have off the curve points as the start of a contour, so when that
+ happens lerp between the first and last points. */
+
+ if (flags[here] & 01) /* On Curve */
+ {
+ control1.x = x[here] * scale;
+ control1.y = y[here] * scale;
+ start = control1;
+ }
+ else if (flags[last] & 01)
+ {
+ /* Start at the last point if it is on the curve. Here, the
+ start really becomes the middle of a spline. */
+ control1.x = x[last] * scale;
+ control1.y = y[last] * scale;
+ start = control1;
+
+ /* Curve back one point early. */
+ last -= 1;
+ here -= 1;
+ }
+ else
+ {
+ /* Lerp between the start and the end. */
+ control1.x = x[here] * scale;
+ control1.y = y[here] * scale;
+ control2.x = x[last] * scale;
+ control2.y = y[last] * scale;
+ sfnt_lerp_half (&control1, &control2, &start);
+
+ /* In either of these cases, start iterating from just here as
+ opposed to here + 1, since logically the contour now starts
+ from the last curve. */
+ here -= 1;
+ }
+
+ /* Move to the start. */
+ move_to (start, dcontext);
+
+ /* Now handle each point between here + 1 and last. */
+
+ i = here;
+ while (++i <= last)
+ {
+ /* If the point is on the curve, then draw a line here from the
+ last control point. */
+
+ if (flags[i] & 01)
+ {
+ control1.x = x[i] * scale;
+ control1.y = y[i] * scale;
+
+ line_to (control1, dcontext);
+
+ /* Move to the next point. */
+ continue;
+ }
+
+ /* Off the curve points are more interesting. They are handled
+ one by one, with points in between being interpolated, until
+ either the last point is reached or an on-curve point is
+ processed. First, load the initial control points. */
+
+ control1.x = x[i] * scale;
+ control1.y = y[i] * scale;
+
+ while (++i <= last)
+ {
+ /* Load this point. */
+ control2.x = x[i] * scale;
+ control2.y = y[i] * scale;
+
+ /* If this point is on the curve, curve directly to this
+ point. */
+
+ if (flags[i] & 01)
+ {
+ curve_to (control1, control2, dcontext);
+ goto continue_loop;
+ }
+
+ /* Calculate the point between here and the previous
+ point. */
+ sfnt_lerp_half (&control1, &control2, &mid);
+
+ /* Curve over there. */
+ curve_to (control1, mid, dcontext);
+
+ /* Reload the control point. */
+ control1 = control2;
+ }
+
+ /* Close the contour by curving back to start. */
+ curve_to (control1, start, dcontext);
+
+ /* Don't close the contour twice. */
+ goto exit;
+
+ continue_loop:
+ continue;
+ }
+
+ /* Close the contour with a line back to start. */
+ line_to (start, dcontext);
+
+ exit:
+ return 0;
+}
+
/* Decompose GLYPH into its individual components. Call MOVE_TO to
move to a specific location. For each line encountered, call
LINE_TO to draw a line to that location. For each spline
sfnt_free_glyph_proc free_glyph,
void *dcontext)
{
- size_t here, start, last;
- struct sfnt_point pen, control1, control2;
+ size_t here, last, n;
struct sfnt_compound_glyph_context context;
- size_t n;
if (glyph->simple)
{
of the last point in the contour. */
last = glyph->simple->end_pts_of_contours[n];
- /* Move to the start. */
- pen.x = glyph->simple->x_coordinates[here] * 65536;
- pen.y = glyph->simple->y_coordinates[here] * 65536;
- move_to (pen, dcontext);
-
- /* Record start so the contour can be closed. */
- start = here;
+ /* Make sure here and last make sense. */
- /* If there is only one point in a contour, draw a one pixel
- wide line. */
- if (last == here)
- {
- line_to (pen, dcontext);
- here++;
-
- continue;
- }
-
- if (here > last)
- /* Indices moved backwards. */
+ if (here > last || last >= glyph->simple->number_of_points)
return 1;
- /* Now start reading points. If the next point is on the
- curve, then it is actually a line. */
- for (++here; here <= last; ++here)
- {
- /* Make sure here is within bounds. */
- if (here >= glyph->simple->number_of_points)
- return 1;
-
- if (glyph->simple->flags[here] & 01) /* On Curve */
- {
- pen.x = glyph->simple->x_coordinates[here] * 65536;
- pen.y = glyph->simple->y_coordinates[here] * 65536;
-
- /* See if the last point was on the curve. If it
- wasn't, then curve from there to here. */
- if (!(glyph->simple->flags[here - 1] & 01))
- {
- control1.x
- = glyph->simple->x_coordinates[here - 1] * 65536;
- control1.y
- = glyph->simple->y_coordinates[here - 1] * 65536;
- curve_to (control1, pen, dcontext);
- }
- else
- /* Otherwise, this is an ordinary line from there
- to here. */
- line_to (pen, dcontext);
-
- continue;
- }
-
- /* If the last point was on the curve, then there's
- nothing extraordinary to do yet. */
- if (glyph->simple->flags[here - 1] & 01)
- ;
- else
- {
- /* Otherwise, interpolate the point halfway between
- the last and current points and make that point
- the pen. */
- control1.x = glyph->simple->x_coordinates[here - 1] * 65536;
- control1.y = glyph->simple->y_coordinates[here - 1] * 65536;
- control2.x = glyph->simple->x_coordinates[here] * 65536;
- control2.y = glyph->simple->y_coordinates[here] * 65536;
- sfnt_lerp_half (&control1, &control2, &pen);
- curve_to (control1, pen, dcontext);
- }
- }
-
- /* Now close the contour if there is more than one point
- inside it. */
- if (start != here - 1)
- {
- /* Restore here after the for loop increased it. */
- here --;
-
- /* Previously, this would check whether or not start is
- an ``on curve'' point, but that is not necessary.
-
- If a contour is not closed and the edge building
- process skips the second to last vertex, then the
- outline can end up with missing edges. */
-
- pen.x = glyph->simple->x_coordinates[start] * 65536;
- pen.y = glyph->simple->y_coordinates[start] * 65536;
-
- /* See if the last point (in this case, `here') was
- on the curve. If it wasn't, then curve from
- there to here. */
- if (!(glyph->simple->flags[here] & 01))
- {
- control1.x
- = glyph->simple->x_coordinates[here] * 65536;
- control1.y
- = glyph->simple->y_coordinates[here] * 65536;
- curve_to (control1, pen, dcontext);
- }
- else
- /* Otherwise, this is an ordinary line from there
- to here. */
- line_to (pen, dcontext);
+ /* Now perform the decomposition. */
+ if (sfnt_decompose_glyph_1 (here, last, move_to,
+ line_to, curve_to,
+ dcontext,
+ glyph->simple->x_coordinates,
+ glyph->simple->y_coordinates,
+ glyph->simple->flags,
+ 65536))
+ return 1;
- /* Restore here to where it was earlier. */
- here++;
- }
+ /* Move forward to the start of the next contour. */
+ here = last + 1;
}
return 0;
of the last point in the contour. */
last = context.contour_end_points[n];
- /* Move to the start. */
- pen.x = context.x_coordinates[here];
- pen.y = context.y_coordinates[here];
- move_to (pen, dcontext);
-
- /* Record start so the contour can be closed. */
- start = here;
-
- /* If there is only one point in a contour, draw a one pixel
- wide line. */
- if (last == here)
- {
- line_to (pen, dcontext);
- here++;
-
- continue;
- }
+ /* Make sure here and last make sense. */
- if (here > last)
- /* Indices moved backwards. */
+ if (here > last || last >= context.num_points)
goto fail;
- /* Now start reading points. If the next point is on the
- curve, then it is actually a line. */
- for (++here; here <= last; ++here)
- {
- /* Make sure here is within bounds. */
- if (here >= context.num_points)
- return 1;
-
- if (context.flags[here] & 01) /* On Curve */
- {
- pen.x = context.x_coordinates[here];
- pen.y = context.y_coordinates[here];
-
- /* See if the last point was on the curve. If it
- wasn't, then curve from there to here. */
- if (!(context.flags[here - 1] & 01))
- {
- control1.x = context.x_coordinates[here - 1];
- control1.y = context.y_coordinates[here - 1];
- curve_to (control1, pen, dcontext);
- }
- else
- /* Otherwise, this is an ordinary line from there
- to here. */
- line_to (pen, dcontext);
-
- continue;
- }
-
- /* If the last point was on the curve, then there's
- nothing extraordinary to do yet. */
- if (context.flags[here - 1] & 01)
- ;
- else
- {
- /* Otherwise, interpolate the point halfway between
- the last and current points and make that point
- the pen. */
- control1.x = context.x_coordinates[here - 1];
- control1.y = context.y_coordinates[here - 1];
- control2.x = context.x_coordinates[here];
- control2.y = context.y_coordinates[here];
- sfnt_lerp_half (&control1, &control2, &pen);
- curve_to (control1, pen, dcontext);
- }
- }
-
- /* Now close the contour if there is more than one point
- inside it. */
- if (start != here - 1)
- {
- /* Restore here after the for loop increased it. */
- here --;
-
- /* Previously, this would check whether or not start is an
- ``on curve'' point, but that is not necessary.
-
- If a contour is not closed and the edge building process
- skips the second to last vertex, then the outline can end
- up with missing edges. */
-
- pen.x = context.x_coordinates[start];
- pen.y = context.y_coordinates[start];
-
- /* See if the last point (in this case, `here') was on the
- curve. If it wasn't, then curve from there to here. */
- if (!(context.flags[here] & 01))
- {
- control1.x = context.x_coordinates[here];
- control1.y = context.y_coordinates[here];
- curve_to (control1, pen, dcontext);
- }
- else
- /* Otherwise, this is an ordinary line from there
- to here. */
- line_to (pen, dcontext);
+ /* Now perform the decomposition. */
+ if (sfnt_decompose_glyph_2 (here, last, move_to,
+ line_to, curve_to,
+ dcontext,
+ context.x_coordinates,
+ context.y_coordinates,
+ context.flags, 1))
+ goto fail;
- /* Restore here to where it was earlier. */
- here++;
- }
+ /* Move forward. */
+ here = last + 1;
}
early:
sfnt_curve_to_proc curve_to,
void *dcontext)
{
- size_t here, start, last;
- struct sfnt_point pen, control1, control2;
- size_t n;
+ size_t here, last, n;
if (!outline->num_contours)
return 0;
of the last point in the contour. */
last = outline->contour_end_points[n];
- /* Move to the start. */
- pen.x = outline->x_points[here] * 1024;
- pen.y = outline->y_points[here] * 1024;
- move_to (pen, dcontext);
-
- /* Record start so the contour can be closed. */
- start = here;
-
- /* If there is only one point in a contour, draw a one pixel
- wide line. */
- if (last == here)
- {
- line_to (pen, dcontext);
- here++;
-
- continue;
- }
+ /* Make sure here and last make sense. */
- if (here > last)
- /* Indices moved backwards. */
+ if (here > last || last >= outline->num_points)
goto fail;
- /* Now start reading points. If the next point is on the
- curve, then it is actually a line. */
- for (++here; here <= last; ++here)
- {
- /* Make sure here is within bounds. */
- if (here >= outline->num_points)
- return 1;
-
- if (outline->flags[here] & 01) /* On Curve */
- {
- pen.x = outline->x_points[here] * 1024;
- pen.y = outline->y_points[here] * 1024;
-
- /* See if the last point was on the curve. If it
- wasn't, then curve from there to here. */
- if (!(outline->flags[here - 1] & 01))
- {
- control1.x = outline->x_points[here - 1] * 1024;
- control1.y = outline->y_points[here - 1] * 1024;
- curve_to (control1, pen, dcontext);
- }
- else
- /* Otherwise, this is an ordinary line from there
- to here. */
- line_to (pen, dcontext);
-
- continue;
- }
-
- /* If the last point was on the curve, then there's
- nothing extraordinary to do yet. */
- if (outline->flags[here - 1] & 01)
- ;
- else
- {
- /* Otherwise, interpolate the point halfway between
- the last and current points and make that point
- the pen. */
- control1.x = outline->x_points[here - 1] * 1024;
- control1.y = outline->y_points[here - 1] * 1024;
- control2.x = outline->x_points[here] * 1024;
- control2.y = outline->y_points[here] * 1024;
- sfnt_lerp_half (&control1, &control2, &pen);
- curve_to (control1, pen, dcontext);
- }
- }
-
- /* Now close the contour if there is more than one point
- inside it. */
- if (start != here - 1)
- {
- /* Restore here after the for loop increased it. */
- here --;
-
- /* Previously, this would check whether or not start is an
- ``on curve'' point, but that is not necessary.
-
- If a contour is not closed and the edge building process
- skips the second to last vertex, then the outline can end
- up with missing edges. */
-
- pen.x = outline->x_points[start] * 1024;
- pen.y = outline->y_points[start] * 1024;
-
- /* See if the last point (in this case, `here') was
- on the curve. If it wasn't, then curve from
- there to here. */
- if (!(outline->flags[here] & 01))
- {
- control1.x = outline->x_points[here] * 1024;
- control1.y = outline->y_points[here] * 1024;
- curve_to (control1, pen, dcontext);
- }
- else
- /* Otherwise, this is an ordinary line from there
- to here. */
- line_to (pen, dcontext);
+ if (sfnt_decompose_glyph_2 (here, last, move_to,
+ line_to, curve_to, dcontext,
+ outline->x_points,
+ outline->y_points,
+ outline->flags, 1024))
+ goto fail;
- /* Restore here to where it was earlier. */
- here++;
- }
+ /* Move forward to the start of the next contour. */
+ here = last + 1;
/* here may be a phantom point when outlining a compound glyph,
as they can have phantom points mixed in with contours.
return 1;
}
+ fprintf (stderr, "number of subtables: %"PRIu16"\n",
+ table->num_subtables);
+
for (i = 0; i < table->num_subtables; ++i)
{
fprintf (stderr, "Found cmap table %"PRIu32": %p\n",
data[i]->format);
}
-#define FANCY_PPEM 12
-#define EASY_PPEM 12
+#define FANCY_PPEM 40
+#define EASY_PPEM 40
interpreter = NULL;
head = sfnt_read_head_table (fd, font);
};
/* Array of directories to search for system fonts. */
-const char *system_font_directories[] =
+static char *system_font_directories[] =
{
"/system/fonts",
+ /* This should be filled in by init_sfntfont_android. */
+ (char[PATH_MAX]) { },
};
/* The font cache. */
{
dir = opendir (system_font_directories[i]);
+ __android_log_print (ANDROID_LOG_VERBOSE, __func__,
+ "Loading fonts from: %s",
+ system_font_directories[i]);
+
if (!dir)
continue;
build_string ("Droid Sans Mono")),
Fcons (build_string ("Sans Serif"),
build_string ("Droid Sans")));
+
+ /* Set up the user fonts directory. This directory is ``fonts'' in
+ the Emacs files directory. */
+ snprintf (system_font_directories[1], PATH_MAX, "%s/fonts",
+ android_get_home_directory ());
}
void
/* The offset of the table directory within PATH. */
off_t offset;
+
+ /* The number of glyphs in this font. Used to catch invalid cmap
+ tables. This is actually the number of glyphs - 1. */
+ int num_glyphs;
};
/* List of fonts. */
struct sfnt_offset_subtable *subtables,
off_t offset)
{
- struct sfnt_font_desc *desc;
+ struct sfnt_font_desc *desc, **next, *prev;
struct sfnt_head_table *head;
struct sfnt_name_table *name;
struct sfnt_meta_table *meta;
+ struct sfnt_maxp_table *maxp;
Lisp_Object family, style;
/* Create the font desc and copy in the file name. */
if (!name)
goto bail2;
+ maxp = sfnt_read_maxp_table (fd, subtables);
+ if (!maxp)
+ goto bail3;
+
/* meta is not required, nor present on many non-Apple fonts. */
meta = sfnt_read_meta_table (fd, subtables);
/* Decode the family and style from the name table. */
if (sfnt_decode_family_style (name, &family, &style))
- goto bail3;
+ goto bail4;
/* Set the family. */
desc->family = family;
desc->char_cache = Qnil;
desc->subtable.platform_id = 500;
+ /* Set the largest glyph identifier. */
+ desc->num_glyphs = maxp->num_glyphs;
+
/* Parse the style. */
sfnt_parse_style (style, desc);
desc->next = system_fonts;
system_fonts = desc;
+ /* Remove any fonts which have the same style as this one. */
+
+ next = &system_fonts->next;
+ prev = *next;
+ for (; *next; prev = *next)
+ {
+ if (!NILP (Fstring_equal (prev->style, desc->style))
+ && !NILP (Fstring_equal (prev->family, desc->family)))
+ {
+ *next = prev->next;
+ xfree (prev);
+ }
+ else
+ next = &prev->next;
+ }
+
xfree (meta);
+ xfree (maxp);
xfree (name);
xfree (head);
return 0;
- bail3:
+ bail4:
xfree (meta);
+ xfree (maxp);
+ bail3:
xfree (name);
bail2:
xfree (head);
/* Enumerate the font FILE into the list of system fonts. Return 1 if
it could not be enumerated, 0 otherwise.
+ Remove any font whose family and style is a duplicate of this one.
+
FILE can either be a TrueType collection file containing TrueType
fonts, or a TrueType font itself. */
emacs_close (fd);
}
+/* Return whether or not CHARACTER has an associated mapping in CMAP,
+ and the mapping points to a valid glyph. DESC is the font
+ descriptor associated with the font. */
+
+static bool
+sfntfont_glyph_valid (struct sfnt_font_desc *desc,
+ sfnt_char font_character,
+ struct sfnt_cmap_encoding_subtable_data *cmap)
+{
+ sfnt_glyph glyph;
+
+ glyph = sfnt_lookup_glyph (font_character, cmap);
+
+ if (!glyph)
+ return false;
+
+ return glyph <= desc->num_glyphs;
+}
+
/* Look up a character CHARACTER in the font description DESC. Cache
the results. Return true if the character exists, false otherwise.
if (font_character == CHARSET_INVALID_CODE (charset))
return false;
- /* Now return whether or not the glyph is present. */
- present = sfnt_lookup_glyph (font_character, *cmap) != 0;
+ /* Now return whether or not the glyph is present. Noto Sans
+ Georgian comes with a corrupt format 4 cmap table that somehow
+ tries to express glyphs greater than 65565. */
+ present = sfntfont_glyph_valid (desc, font_character, *cmap);
/* Cache the result. Store Qlambda when not present, Qt
otherwise. */
{
tem = XCDR (tem);
- /* tem is a list of each characters, one of which must be
+ /* tem is a list of each characters, all of which must be
present in the font. */
FOR_EACH_TAIL_SAFE (tem)
{
- if (FIXNUMP (XCAR (tem)))
- {
- if (!sfntfont_lookup_char (desc, XCAR (tem), &cmap,
- &subtable))
- goto fail;
-
- /* One character is enough to pass a font. Don't
- look at too many. */
- break;
- }
+ if (FIXNUMP (XCAR (tem))
+ && !sfntfont_lookup_char (desc, XCAR (tem), &cmap,
+ &subtable))
+ goto fail;
}
+
+ /* One or more characters are missing. */
+ if (!NILP (tem))
+ goto fail;
}
+ /* Fail if there are no matching fonts at all. */
+ else if (NILP (tem))
+ goto fail;
}
/* Now check that the language is supported. */
#include "textconv.h"
#include "buffer.h"
#include "syntax.h"
+#include "blockinput.h"
\f
static struct textconv_interface *text_interface;
+/* How many times text conversion has been disabled. */
+
+static int suppress_conversion_count;
+
/* Flags used to determine what must be sent after a batch edit
ends. */
static void
sync_overlay (struct frame *f)
{
- if (MARKERP (f->conversion.compose_region_start))
+ if (MARKERP (f->conversion.compose_region_start)
+ && !NILP (Vtext_conversion_face))
{
if (NILP (f->conversion.compose_region_overlay))
{
f->conversion.compose_region_end, Qnil,
Qt, Qnil);
Foverlay_put (f->conversion.compose_region_overlay,
- Qface, Qunderline);
+ Qface, Vtext_conversion_face);
}
Fmove_overlay (f->conversion.compose_region_overlay,
{
specpdl_ref count;
ptrdiff_t wanted, start, end;
+ struct window *w;
/* If F's old selected window is no longer live, fail. */
/* This should deactivate the mark. */
call0 (Qdeactivate_mark);
+
+ /* Update the ephemeral last point. */
+ w = XWINDOW (selected_window);
+ w->ephemeral_last_point = PT;
unbind_to (count, Qnil);
}
text_interface->compose_region_changed (f);
}
+ /* Update the ephemeral last point. */
+ w = XWINDOW (selected_window);
+ w->ephemeral_last_point = PT;
+
unbind_to (count, Qnil);
}
ptrdiff_t end)
{
specpdl_ref count;
+ struct window *w;
/* If F's old selected window is no longer live, fail. */
make_fixnum (end), Qnil);
sync_overlay (f);
+ /* Update the ephemeral last point. */
+ w = XWINDOW (selected_window);
+ w->ephemeral_last_point = PT;
+
unbind_to (count, Qnil);
}
{
specpdl_ref count;
ptrdiff_t start, end, a, b, a1, b1, lstart, rstart;
+ struct window *w;
/* If F's old selected window is no longer live, fail. */
if (get_mark () == PT)
call0 (Qdeactivate_mark);
+ /* Update the ephemeral last point. */
+ w = XWINDOW (selected_window);
+ w->ephemeral_last_point = PT;
+
unbind_to (count, Qnil);
}
ptrdiff_t mark)
{
specpdl_ref count;
+ struct window *w;
/* If F's old selected window is no longer live, fail. */
{
if (f->conversion.batch_edit_count > 0)
f->conversion.batch_edit_flags |= PENDING_POINT_CHANGE;
- else
+ else if (text_interface && text_interface->point_changed)
text_interface->point_changed (f,
XWINDOW (f->old_selected_window),
current_buffer);
else
call1 (Qpush_mark, make_fixnum (mark));
+ /* Update the ephemeral last point. */
+ w = XWINDOW (selected_window);
+ w->ephemeral_last_point = PT;
+
unbind_to (count, Qnil);
}
}
/* Process and free the text conversion ACTION. F must be the frame
- on which ACTION will be performed. */
+ on which ACTION will be performed.
-static void
+ Value is the window which was used, or NULL. */
+
+static struct window *
handle_pending_conversion_events_1 (struct frame *f,
struct text_conversion_action *action)
{
token = action->counter;
xfree (action);
+ /* Text conversion events can still arrive immediately after
+ `conversion_disabled_p' becomes true. In that case, process all
+ events, but don't perform any associated actions. */
+
+ if (conversion_disabled_p ())
+ return NULL;
+
/* Make sure completion is signalled. */
count = SPECPDL_INDEX ();
record_unwind_protect_ptr (complete_edit, &token);
+ w = NULL;
+
+ if (WINDOW_LIVE_P (f->old_selected_window))
+ {
+ w = XWINDOW (f->old_selected_window);
+ buffer = XBUFFER (WINDOW_BUFFER (w));
+ }
switch (operation)
{
break;
if (f->conversion.batch_edit_flags & PENDING_POINT_CHANGE)
- {
- w = XWINDOW (f->old_selected_window);
- buffer = XBUFFER (WINDOW_BUFFER (w));
-
- text_interface->point_changed (f, w, buffer);
- }
+ text_interface->point_changed (f, w, buffer);
if (f->conversion.batch_edit_flags & PENDING_COMPOSE_CHANGE)
text_interface->compose_region_changed (f);
}
unbind_to (count, Qnil);
+
+ return w;
}
/* Decrement the variable pointed to by *PTR. */
bool handled;
static int inside;
specpdl_ref count;
+ ptrdiff_t last_point;
+ struct window *w;
handled = false;
Vtext_conversion_edits = Qnil;
inside++;
+ last_point = -1;
+ w = NULL;
count = SPECPDL_INDEX ();
record_unwind_protect_ptr (decrement_inside, &inside);
process them in bottom to up order. */
while (true)
{
- /* Redisplay in between if there is more than one
- action.
-
- This can read input. This function must be reentrant
- here. */
-
- if (handled)
- redisplay ();
+ /* Update the input method if handled &&
+ w->ephemeral_last_point != last_point. */
+ if (w && (last_point != w->ephemeral_last_point))
+ {
+ if (handled
+ && last_point != -1
+ && text_interface
+ && text_interface->point_changed)
+ {
+ if (f->conversion.batch_edit_count > 0)
+ f->conversion.batch_edit_flags |= PENDING_POINT_CHANGE;
+ else
+ text_interface->point_changed (f, NULL, NULL);
+ }
+
+ last_point = w->ephemeral_last_point;
+ }
- /* Reload action. */
+ /* Reload action. This needs to be reentrant as buffer
+ modification functions can call `read-char'. */
action = f->conversion.actions;
/* If there are no more actions, break. */
f->conversion.actions = next;
/* Handle and free the action. */
- handle_pending_conversion_events_1 (f, action);
+ w = handle_pending_conversion_events_1 (f, action);
handled = true;
}
}
return buffer;
}
+/* Return whether or not text conversion is temporarily disabled.
+ `reset' should always call this to determine whether or not to
+ disable the input method. */
+
+bool
+conversion_disabled_p (void)
+{
+ return suppress_conversion_count > 0;
+}
+
\f
/* Window system interface. These are called from the rest of
text_interface->point_changed (f, window, buffer);
}
+/* Temporarily disable text conversion. Must be paired with a
+ corresponding call to resume_text_conversion. */
+
+void
+disable_text_conversion (void)
+{
+ Lisp_Object tail, frame;
+ struct frame *f;
+
+ suppress_conversion_count++;
+
+ if (!text_interface || suppress_conversion_count > 1)
+ return;
+
+ /* Loop through and reset the input method on each window system
+ frame. It should call conversion_disabled_p and then DTRT. */
+
+ FOR_EACH_FRAME (tail, frame)
+ {
+ f = XFRAME (frame);
+ reset_frame_state (f);
+
+ if (FRAME_WINDOW_P (f) && FRAME_VISIBLE_P (f))
+ text_interface->reset (f);
+ }
+}
+
+/* Undo the effect of the last call to `disable_text_conversion'. */
+
+void
+resume_text_conversion (void)
+{
+ Lisp_Object tail, frame;
+ struct frame *f;
+
+ suppress_conversion_count--;
+ eassert (suppress_conversion_count >= 0);
+
+ if (!text_interface || suppress_conversion_count)
+ return;
+
+ /* Loop through and reset the input method on each window system
+ frame. It should call conversion_disabled_p and then DTRT. */
+
+ FOR_EACH_FRAME (tail, frame)
+ {
+ f = XFRAME (frame);
+ reset_frame_state (f);
+
+ if (FRAME_WINDOW_P (f) && FRAME_VISIBLE_P (f))
+ text_interface->reset (f);
+ }
+}
+
/* Register INTERFACE as the text conversion interface. */
void
\f
+/* Lisp interface. */
+
+DEFUN ("set-text-conversion-style", Fset_text_conversion_style,
+ Sset_text_conversion_style, 1, 1, 0,
+ doc: /* Set the text conversion style in the current buffer.
+
+Set `text-conversion-mode' to VALUE, then force any input method
+editing frame displaying this buffer to stop itself.
+
+This can lead to a significant amount of time being taken by the input
+method resetting itself, so you should not use this function lightly;
+instead, set `text-conversion-mode' before your buffer is displayed,
+and let redisplay manage the input method appropriately. */)
+ (Lisp_Object value)
+{
+ Lisp_Object tail, frame;
+ struct frame *f;
+ Lisp_Object buffer;
+
+ bset_text_conversion_style (current_buffer, value);
+
+ if (!text_interface)
+ return Qnil;
+
+ /* If there are any seleted windows displaying this buffer, reset
+ text conversion on their associated frames. */
+
+ if (buffer_window_count (current_buffer))
+ {
+ buffer = Fcurrent_buffer ();
+
+ FOR_EACH_FRAME (tail, frame)
+ {
+ f = XFRAME (frame);
+
+ if (WINDOW_LIVE_P (f->old_selected_window)
+ && FRAME_WINDOW_P (f)
+ && EQ (XWINDOW (f->old_selected_window)->contents,
+ buffer))
+ {
+ block_input ();
+ reset_frame_state (f);
+ text_interface->reset (f);
+ unblock_input ();
+ }
+ }
+ }
+
+ return Qnil;
+}
+
+\f
+
void
syms_of_textconv (void)
{
DEFSYM (Qtext_conversion, "text-conversion");
DEFSYM (Qpush_mark, "push-mark");
DEFSYM (Qunderline, "underline");
+ DEFSYM (Qoverriding_text_conversion_style, "overriding-text-conversion-style");
DEFVAR_LISP ("text-conversion-edits", Vtext_conversion_edits,
doc: /* List of buffers that were last edited as a result of text conversion.
If a deletion occured, then BEG and END are the same, and EPHEMERAL is
nil. */);
Vtext_conversion_edits = Qnil;
+
+ DEFVAR_LISP ("overriding-text-conversion-style",
+ Voverriding_text_conversion_style,
+ doc: /* Non-buffer local version of `text-conversion-style'.
+
+If this variable is the symbol `lambda', it means to consult the
+buffer local variable `text-conversion-style' to determine whether or
+not to activate the input method. Otherwise, its value is used in
+preference to any buffer local value of `text-conversion-style'. */);
+ Voverriding_text_conversion_style = Qlambda;
+
+ DEFVAR_LISP ("text-conversion-face", Vtext_conversion_face,
+ doc: /* Face in which to display temporary edits by an input method.
+nil means to display no indication of a temporary edit. */);
+ Vtext_conversion_face = Qunderline;
+
+ defsubr (&Sset_text_conversion_style);
}
ptrdiff_t, unsigned long);
extern char *get_extracted_text (struct frame *, ptrdiff_t, ptrdiff_t *,
ptrdiff_t *, ptrdiff_t *, ptrdiff_t *);
+extern bool conversion_disabled_p (void);
extern void register_textconv_interface (struct textconv_interface *);
it should be positive. */
ptrdiff_t last_point;
+#ifdef HAVE_TEXT_CONVERSION
+ /* ``ephemeral'' last point position. This is used while
+ processing text conversion events.
+
+ `last_point' is normally used during redisplay to indicate the
+ position of point as seem by the input method. However, it is
+ not updated if consequtive conversions are processed at the
+ same time.
+
+ This `ephemeral_last_point' field is either the last point as
+ set in redisplay or the last point after a text editing
+ operation. */
+ ptrdiff_t ephemeral_last_point;
+#endif
+
/* Value of mark in the selected window at the time of the last
redisplay. */
ptrdiff_t last_mark;
w->last_mark = -1;
#ifdef HAVE_TEXT_CONVERSION
+ /* See the description of this field in struct window. */
+ w->ephemeral_last_point = w->last_point;
+
/* Point motion is only propagated to the input method for use
in text conversion during a redisplay. While this can lead
to inconsistencies when point has moved but the change has