X-Git-Url: https://code.delx.au/gnu-emacs/blobdiff_plain/f3fbd1553534bb85c75baf891c0ca9aaa4c3fa6f..dedb5504d3464bd50b6c591d36791c5535af68c1:/src/composite.c?ds=sidebyside diff --git a/src/composite.c b/src/composite.c index ff6d1a5ba3..17144f25cd 100644 --- a/src/composite.c +++ b/src/composite.c @@ -1,7 +1,10 @@ /* Composite sequence support. Copyright (C) 1999 Electrotechnical Laboratory, JAPAN. - Licensed to the Free Software Foundation. + Licensed to the Free Software Foundation. Copyright (C) 2001 Free Software Foundation, Inc. + Copyright (C) 2003 + National Institute of Advanced Industrial Science and Technology (AIST) + Registration Number H13PRO009 This file is part of GNU Emacs. @@ -23,7 +26,7 @@ Boston, MA 02111-1307, USA. */ #include #include "lisp.h" #include "buffer.h" -#include "charset.h" +#include "character.h" #include "intervals.h" /* Emacs uses special text property `composition' to support character @@ -92,32 +95,32 @@ Boston, MA 02111-1307, USA. */ The former is a hash table in which keys are COMPONENTS-VECs and values are the corresponding COMPOSITION-IDs. This hash table is - weak, but as each key (COMPONENTS-VEC) is also kept as a value of + weak, but as each key (COMPONENTS-VEC) is also kept as a value of the `composition' property, it won't be collected as garbage until all - text that have the same COMPONENTS-VEC are deleted. + bits of text that have the same COMPONENTS-VEC are deleted. The latter is a table of pointers to `struct composition' indexed - by COMPOSITION-ID. This structure keep the other information (see + by COMPOSITION-ID. This structure keeps the other information (see composite.h). In general, a text property holds information about individual characters. But, a `composition' property holds information about - a sequence of characters (in this sense, it is like `intangible' + a sequence of characters (in this sense, it is like the `intangible' property). That means that we should not share the property value - in adjacent compositions we can't distinguish them if they have the + in adjacent compositions -- we can't distinguish them if they have the same property. So, after any changes, we call `update_compositions' and change a property of one of adjacent compositions to a copy of it. This function also runs a proper composition modification function to make a composition that gets invalid by the change valid again. - As a value of `composition' property holds information about a + As the value of the `composition' property holds information about a specific range of text, the value gets invalid if we change the - text in the range. We treat `composition' property always + text in the range. We treat the `composition' property as always rear-nonsticky (currently by setting default-text-properties to (rear-nonsticky (composition))) and we never make properties of adjacent compositions identical. Thus, any such changes make the - range just shorter. So, we can check the validity of `composition' + range just shorter. So, we can check the validity of the `composition' property by comparing LENGTH information with the actual length of the composition. @@ -145,25 +148,15 @@ Lisp_Object composition_hash_table; /* Function to call to adjust composition. */ Lisp_Object Vcompose_chars_after_function; -/* Char-table of patterns and functions to make a composition. */ -Lisp_Object Vcomposition_function_table; -Lisp_Object Qcomposition_function_table; +Lisp_Object Qauto_composed; +Lisp_Object Vauto_composition_function; +Lisp_Object Qauto_composition_function; + +EXFUN (Fremove_list_of_text_properties, 4); /* Temporary variable used in macros COMPOSITION_XXX. */ Lisp_Object composition_temp; -/* Return how many columns C will occupy on the screen. It always - returns 1 for control characters and 8-bit characters because those - are just ignored in a composition. */ -#define CHAR_WIDTH(c) \ - (SINGLE_BYTE_CHAR_P (c) ? 1 : CHARSET_WIDTH (CHAR_CHARSET (c))) - -/* The following macros for hash table are copied from fns.c. */ -/* Value is the key part of entry IDX in hash table H. */ -#define HASH_KEY(H, IDX) AREF ((H)->key_and_value, 2 * (IDX)) -/* Value is the value part of entry IDX in hash table H. */ -#define HASH_VALUE(H, IDX) AREF ((H)->key_and_value, 2 * (IDX) + 1) - /* Return COMPOSITION-ID of a composition at buffer position CHARPOS/BYTEPOS and length NCHARS. The `composition' property of the sequence is PROP. STRING, if non-nil, is a string that @@ -255,7 +248,7 @@ get_composition_id (charpos, bytepos, nchars, prop, string) } /* This composition is a new one. We must register it. */ - + /* Check if we have sufficient memory to store this information. */ if (composition_table_size == 0) { @@ -343,7 +336,7 @@ get_composition_id (charpos, bytepos, nchars, prop, string) for (i = 1; i < glyph_len; i += 2) { - int rule, gref, nref; + int rule, gref, nref, xoff, yoff; int this_width; float this_left; @@ -365,7 +358,7 @@ get_composition_id (charpos, bytepos, nchars, prop, string) | | 6---7---8 -- descent */ - COMPOSITION_DECODE_RULE (rule, gref, nref); + COMPOSITION_DECODE_RULE (rule, gref, nref, xoff, yoff); this_left = (leftmost + (gref % 3) * (rightmost - leftmost) / 2.0 - (nref % 3) * this_width / 2.0); @@ -411,7 +404,8 @@ get_composition_id (charpos, bytepos, nchars, prop, string) int find_composition (pos, limit, start, end, prop, object) - int pos, limit, *start, *end; + int pos, limit; + EMACS_INT *start, *end; Lisp_Object *prop, object; { Lisp_Object val; @@ -455,7 +449,7 @@ run_composition_function (from, to, prop) Lisp_Object prop; { Lisp_Object func; - int start, end; + EMACS_INT start, end; func = COMPOSITION_MODIFICATION_FUNC (prop); /* If an invalid composition precedes or follows, try to make them @@ -468,30 +462,35 @@ run_composition_function (from, to, prop) && find_composition (to, -1, &start, &end, &prop, Qnil) && !COMPOSITION_VALID_P (start, end, prop)) to = end; - if (!NILP (func)) + if (!NILP (Ffboundp (func))) call2 (func, make_number (from), make_number (to)); - else if (!NILP (Ffboundp (Vcompose_chars_after_function))) - call3 (Vcompose_chars_after_function, - make_number (from), make_number (to), Qnil); } /* Make invalid compositions adjacent to or inside FROM and TO valid. CHECK_MASK is bitwise `or' of mask bits defined by macros CHECK_XXX (see the comment in composite.h). + It also resets the text-property `auto-composed' to a proper region + so that automatic character composition works correctly later while + displaying the region. + This function is called when a buffer text is changed. If the change is deletion, FROM == TO. Otherwise, FROM < TO. */ void update_compositions (from, to, check_mask) - int from, to; + EMACS_INT from, to; + int check_mask; { Lisp_Object prop; - int start, end; + EMACS_INT start, end; + /* The beginning and end of the region to set the property + `auto-composed' to nil. */ + EMACS_INT min_pos = from, max_pos = to; if (inhibit_modification_hooks) return; - + /* If FROM and TO are not in a valid range, do nothing. */ if (! (BEGV <= from && from <= to && to <= ZV)) return; @@ -506,6 +505,9 @@ update_compositions (from, to, check_mask) if (from > BEGV && find_composition (from - 1, -1, &start, &end, &prop, Qnil)) { + min_pos = start; + if (end > to) + max_pos = end; if (from < end) Fput_text_property (make_number (from), make_number (end), Qcomposition, @@ -515,7 +517,11 @@ update_compositions (from, to, check_mask) } else if (from < ZV && find_composition (from, -1, &start, &from, &prop, Qnil)) - run_composition_function (start, from, prop); + { + if (from > to) + max_pos = from; + run_composition_function (start, from, prop); + } } if (check_mask & CHECK_INSIDE) @@ -540,14 +546,32 @@ update_compositions (from, to, check_mask) To avoid it, in such a case, we change the property of the former to the copy of it. */ if (to < end) - Fput_text_property (make_number (start), make_number (to), - Qcomposition, - Fcons (XCAR (prop), XCDR (prop)), Qnil); + { + Fput_text_property (make_number (start), make_number (to), + Qcomposition, + Fcons (XCAR (prop), XCDR (prop)), Qnil); + max_pos = end; + } run_composition_function (start, end, prop); } else if (to < ZV && find_composition (to, -1, &start, &end, &prop, Qnil)) - run_composition_function (start, end, prop); + { + run_composition_function (start, end, prop); + max_pos = end; + } + } + if (min_pos < max_pos) + { + int count = SPECPDL_INDEX (); + + specbind (Qinhibit_read_only, Qt); + specbind (Qinhibit_modification_hooks, Qt); + specbind (Qinhibit_point_motion_hooks, Qt); + Fremove_list_of_text_properties (make_number (min_pos), + make_number (max_pos), + Fcons (Qauto_composed, Qnil), Qnil); + unbind_to (count, Qnil); } } @@ -594,135 +618,17 @@ compose_text (start, end, components, modification_func, string) Fput_text_property (make_number (start), make_number (end), Qcomposition, prop, string); } - -/* Compose sequences of characters in the region between START and END - by functions registered in Vcomposition_function_table. If STRING - is non-nil, operate on characters contained between indices START - and END in STRING. */ - -void -compose_chars_in_text (start, end, string) - int start, end; - Lisp_Object string; -{ - int count = 0; - struct gcpro gcpro1; - Lisp_Object tail, elt, val, to; - /* Set to nonzero if we don't have to compose ASCII characters. */ - int skip_ascii; - int i, len, stop, c; - unsigned char *ptr, *pend; - - if (! CHAR_TABLE_P (Vcomposition_function_table)) - return; - - if (STRINGP (string)) - { - count = specpdl_ptr - specpdl; - GCPRO1 (string); - stop = end; - ptr = XSTRING (string)->data + string_char_to_byte (string, start); - pend = ptr + STRING_BYTES (XSTRING (string)); - } - else - { - record_unwind_protect (save_excursion_restore, save_excursion_save ()); - TEMP_SET_PT (start); - stop = (start < GPT && GPT < end ? GPT : end); - ptr = CHAR_POS_ADDR (start); - pend = CHAR_POS_ADDR (end); - } - - /* Preserve the match data. */ - record_unwind_protect (Fset_match_data, Fmatch_data (Qnil, Qnil)); - - /* If none of ASCII characters have composition functions, we can - skip them quickly. */ - for (i = 0; i < 128; i++) - if (!NILP (CHAR_TABLE_REF (Vcomposition_function_table, i))) - break; - skip_ascii = (i == 128); - - - while (1) - { - if (skip_ascii) - while (start < stop && ASCII_BYTE_P (*ptr)) - start++, ptr++; - - if (start >= stop) - { - if (stop == end || start >= end) - break; - stop = end; - if (STRINGP (string)) - ptr = XSTRING (string)->data + string_char_to_byte (string, start); - else - ptr = CHAR_POS_ADDR (start); - } - - c = STRING_CHAR_AND_LENGTH (ptr, pend - ptr, len); - tail = CHAR_TABLE_REF (Vcomposition_function_table, c); - while (CONSP (tail)) - { - elt = XCAR (tail); - if (CONSP (elt) - && STRINGP (XCAR (elt)) - && !NILP (Ffboundp (XCDR (elt)))) - { - if (STRINGP (string)) - val = Fstring_match (XCAR (elt), string, make_number (start)); - else - { - val = Flooking_at (XCAR (elt)); - if (!NILP (val)) - val = make_number (start); - } - if (INTEGERP (val) && XFASTINT (val) == start) - { - to = Fmatch_end (make_number (0)); - val = call4 (XCDR (elt), val, to, XCAR (elt), string); - if (INTEGERP (val) && XINT (val) > 1) - { - start += XINT (val); - if (STRINGP (string)) - ptr = XSTRING (string)->data + string_char_to_byte (string, start); - else - ptr = CHAR_POS_ADDR (start); - } - else - { - start++; - ptr += len; - } - break; - } - } - tail = XCDR (tail); - } - if (!CONSP (tail)) - { - /* No composition done. Try the next character. */ - start++; - ptr += len; - } - } - - unbind_to (count, Qnil); - if (STRINGP (string)) - UNGCPRO; -} /* Emacs Lisp APIs. */ DEFUN ("compose-region-internal", Fcompose_region_internal, Scompose_region_internal, 2, 4, 0, - "Internal use only.\n\ -\n\ -Compose text in the region between START and END.\n\ -Optional 3rd and 4th arguments are COMPONENTS and MODIFICATION-FUNC\n\ -for the composition. See `compose-region' for more detial.") - (start, end, components, mod_func) + doc: /* Internal use only. + +Compose text in the region between START and END. +Optional 3rd and 4th arguments are COMPONENTS and MODIFICATION-FUNC +for the composition. See `compose-region' for more detail. */) + (start, end, components, mod_func) Lisp_Object start, end, components, mod_func; { validate_region (&start, &end); @@ -730,7 +636,7 @@ for the composition. See `compose-region' for more detial.") && !INTEGERP (components) && !CONSP (components) && !STRINGP (components)) - CHECK_VECTOR (components, 2); + CHECK_VECTOR (components); compose_text (XINT (start), XINT (end), components, mod_func, Qnil); return Qnil; @@ -738,21 +644,21 @@ for the composition. See `compose-region' for more detial.") DEFUN ("compose-string-internal", Fcompose_string_internal, Scompose_string_internal, 3, 5, 0, - "Internal use only.\n\ -\n\ -Compose text between indices START and END of STRING.\n\ -Optional 4th and 5th arguments are COMPONENTS and MODIFICATION-FUNC\n\ -for the composition. See `compose-string' for more detial.") - (string, start, end, components, mod_func) + doc: /* Internal use only. + +Compose text between indices START and END of STRING. +Optional 4th and 5th arguments are COMPONENTS and MODIFICATION-FUNC +for the composition. See `compose-string' for more detail. */) + (string, start, end, components, mod_func) Lisp_Object string, start, end, components, mod_func; { - CHECK_STRING (string, 0); - CHECK_NUMBER (start, 1); - CHECK_NUMBER (end, 2); + CHECK_STRING (string); + CHECK_NUMBER (start); + CHECK_NUMBER (end); if (XINT (start) < 0 || XINT (start) > XINT (end) - || XINT (end) > XSTRING (string)->size) + || XINT (end) > SCHARS (string)) args_out_of_range (start, end); compose_text (XINT (start), XINT (end), components, mod_func, string); @@ -760,32 +666,32 @@ for the composition. See `compose-string' for more detial.") } DEFUN ("find-composition-internal", Ffind_composition_internal, - Sfind_composition_internal, 4, 4, 0, - "Internal use only.\n\ -\n\ -Return information about composition at or nearest to position POS.\n\ -See `find-composition' for more detail.") - (pos, limit, string, detail_p) + Sfind_composition_internal, 4, 4, 0, + doc: /* Internal use only. + +Return information about composition at or nearest to position POS. +See `find-composition' for more detail. */) + (pos, limit, string, detail_p) Lisp_Object pos, limit, string, detail_p; { Lisp_Object prop, tail; - int start, end; + EMACS_INT start, end; int id; - CHECK_NUMBER_COERCE_MARKER (pos, 0); + CHECK_NUMBER_COERCE_MARKER (pos); start = XINT (pos); if (!NILP (limit)) { - CHECK_NUMBER_COERCE_MARKER (limit, 1); + CHECK_NUMBER_COERCE_MARKER (limit); end = XINT (limit); } else end = -1; - + if (!NILP (string)) { - CHECK_STRING (string, 2); - if (XINT (pos) < 0 || XINT (pos) > XSTRING (string)->size) + CHECK_STRING (string); + if (XINT (pos) < 0 || XINT (pos) > SCHARS (string)) args_out_of_range (string, pos); } else @@ -845,10 +751,15 @@ syms_of_composite () { Lisp_Object args[6]; extern Lisp_Object QCsize; - + args[0] = QCtest; args[1] = Qequal; args[2] = QCweakness; + /* We used to make the hash table weak so that unreferenced + compostions can be garbage-collected. But, usually once + created compositions are repeatedly used in an Emacs session, + and thus it's not worth to save memory in such a way. So, we + make the table not weak. */ args[3] = Qnil; args[4] = QCsize; args[5] = make_number (311); @@ -861,44 +772,42 @@ syms_of_composite () = Fcons (Fcons (Qcomposition, Qt), Vtext_property_default_nonsticky); DEFVAR_LISP ("compose-chars-after-function", &Vcompose_chars_after_function, - "Function to adjust composition of buffer text.\n\ -\n\ -The function is called with three arguments FROM, TO, and OBJECT.\n\ -FROM and TO specify the range of text of which composition should be\n\ -adjusted. OBJECT, if non-nil, is a string that contains the text.\n\ -\n\ -This function is called after a text with `composition' property is\n\ -inserted or deleted to keep `composition' property of buffer text\n\ -valid.\n\ -\n\ -The default value is the function `compose-chars-after'."); + doc: /* Function to adjust composition of buffer text. + +The function is called with three arguments FROM, TO, and OBJECT. +FROM and TO specify the range of text of which composition should be +adjusted. OBJECT, if non-nil, is a string that contains the text. + +This function is called after a text with `composition' property is +inserted or deleted to keep `composition' property of buffer text +valid. + +The default value is the function `compose-chars-after'. */); Vcompose_chars_after_function = intern ("compose-chars-after"); - Qcomposition_function_table = intern ("composition-function-table"); - staticpro (&Qcomposition_function_table); - - /* Intern this now in case it isn't already done. - Setting this variable twice is harmless. - But don't staticpro it here--that is done in alloc.c. */ - Qchar_table_extra_slots = intern ("char-table-extra-slots"); - - Fput (Qcomposition_function_table, Qchar_table_extra_slots, make_number (0)); - - DEFVAR_LISP ("composition-function-table", &Vcomposition_function_table, - "Char table of patterns and functions to make a composition.\n\ -\n\ -Each element is nil or an alist of PATTERNs vs FUNCs, where PATTERNs\n\ -are regular expressions and FUNCs are functions. FUNC is responsible\n\ -for composing text matching the corresponding PATTERN. FUNC is called\n\ -with three arguments FROM, TO, and PATTERN. See the function\n\ -`compose-chars-after' for more detail.\n\ -\n\ -This table is looked up by the first character of a composition when\n\ -the composition gets invalid after a change in a buffer."); - Vcomposition_function_table - = Fmake_char_table (Qcomposition_function_table, Qnil); + Qauto_composed = intern ("auto-composed"); + staticpro (&Qauto_composed); + + Qauto_composition_function = intern ("auto-composition-function"); + staticpro (&Qauto_composition_function); + + DEFVAR_LISP ("auto-composition-function", &Vauto_composition_function, + doc: /* Function to call to compose characters automatically. +The function is called from the display routine with two arguments, +POS and STRING. + +If STRING is nil, the function must compose characters following POS +in the current buffer. + +Otherwise, STRING is a string, and POS is an index to the string. In +this case, the function must compose characters following POS in +the string. */); + Vauto_composition_function = Qnil; defsubr (&Scompose_region_internal); defsubr (&Scompose_string_internal); defsubr (&Sfind_composition_internal); } + +/* arch-tag: 79cefaf8-ca48-4eed-97e5-d5afb290d272 + (do not change this comment) */