summaryrefslogtreecommitdiff
path: root/src/composite.c
diff options
context:
space:
mode:
authorStefan Monnier <monnier@iro.umontreal.ca>2022-09-25 16:15:16 -0400
committerStefan Monnier <monnier@iro.umontreal.ca>2022-09-25 16:15:16 -0400
commit650c20f1ca4e07591a727e1cfcc74b3363d15985 (patch)
tree85d11f6437cde22f410c25e0e5f71a3131ebd07d /src/composite.c
parent8869332684c2302b5ba1ead4568bbc7ba1c0183e (diff)
parent4b85ae6a24380fb67a3315eaec9233f17a872473 (diff)
downloademacs-650c20f1ca4e07591a727e1cfcc74b3363d15985.tar.gz
emacs-650c20f1ca4e07591a727e1cfcc74b3363d15985.tar.bz2
emacs-650c20f1ca4e07591a727e1cfcc74b3363d15985.zip
Merge 'master' into noverlay
Diffstat (limited to 'src/composite.c')
-rw-r--r--src/composite.c633
1 files changed, 444 insertions, 189 deletions
diff --git a/src/composite.c b/src/composite.c
index c01e2e3b95c..249d7587f61 100644
--- a/src/composite.c
+++ b/src/composite.c
@@ -1,5 +1,5 @@
/* Composite sequence support.
- Copyright (C) 2001-2017 Free Software Foundation, Inc.
+ Copyright (C) 2001-2022 Free Software Foundation, Inc.
Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011
National Institute of Advanced Industrial Science and Technology (AIST)
Registration Number H14PRO021
@@ -24,6 +24,8 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
#include <config.h>
+#include <stdlib.h> /* for qsort */
+
#include "lisp.h"
#include "character.h"
#include "composite.h"
@@ -77,7 +79,7 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
composition, the elements are characters or encoded
composition rules.
- MODIFICATION-FUNC -- If non nil, it is a function to call when the
+ MODIFICATION-FUNC -- If non-nil, it is a function to call when the
composition gets invalid after a modification in a buffer. If
it is nil, a function in `composition-function-table' of the
first character in the sequence is called.
@@ -164,19 +166,17 @@ ptrdiff_t
get_composition_id (ptrdiff_t charpos, ptrdiff_t bytepos, ptrdiff_t nchars,
Lisp_Object prop, Lisp_Object string)
{
- Lisp_Object id, length, components, key, *key_contents;
+ Lisp_Object id, length, components, key, *key_contents, hash_code;
ptrdiff_t glyph_len;
struct Lisp_Hash_Table *hash_table = XHASH_TABLE (composition_hash_table);
ptrdiff_t hash_index;
- EMACS_UINT hash_code;
enum composition_method method;
struct composition *cmp;
- ptrdiff_t i;
int ch;
/* Maximum length of a string of glyphs. XftGlyphExtents limits
this to INT_MAX, and Emacs limits it further. Divide INT_MAX - 1
- by 2 because x_produce_glyphs computes glyph_len * 2 + 1. Divide
+ by 2 because gui_produce_glyphs computes glyph_len * 2 + 1. Divide
the size by MAX_MULTIBYTE_LENGTH because encode_terminal_code
multiplies glyph_len by MAX_MULTIBYTE_LENGTH. */
enum {
@@ -193,12 +193,12 @@ get_composition_id (ptrdiff_t charpos, ptrdiff_t bytepos, ptrdiff_t nchars,
goto invalid_composition;
id = XCAR (prop);
- if (INTEGERP (id))
+ if (FIXNUMP (id))
{
/* PROP should be Form-B. */
- if (XINT (id) < 0 || XINT (id) >= n_compositions)
+ if (XFIXNUM (id) < 0 || XFIXNUM (id) >= n_compositions)
goto invalid_composition;
- return XINT (id);
+ return XFIXNUM (id);
}
/* PROP should be Form-A.
@@ -206,7 +206,7 @@ get_composition_id (ptrdiff_t charpos, ptrdiff_t bytepos, ptrdiff_t nchars,
if (!CONSP (id))
goto invalid_composition;
length = XCAR (id);
- if (!INTEGERP (length) || XINT (length) != nchars)
+ if (!FIXNUMP (length) || XFIXNUM (length) != nchars)
goto invalid_composition;
components = XCDR (id);
@@ -215,8 +215,8 @@ get_composition_id (ptrdiff_t charpos, ptrdiff_t bytepos, ptrdiff_t nchars,
by consulting composition_hash_table. The key for this table is
COMPONENTS (converted to a vector COMPONENTS-VEC) or, if it is
nil, vector of characters in the composition range. */
- if (INTEGERP (components))
- key = Fmake_vector (make_number (1), components);
+ if (FIXNUMP (components))
+ key = make_vector (1, components);
else if (STRINGP (components) || CONSP (components))
key = Fvconcat (1, &components);
else if (VECTORP (components))
@@ -225,16 +225,16 @@ get_composition_id (ptrdiff_t charpos, ptrdiff_t bytepos, ptrdiff_t nchars,
{
key = make_uninit_vector (nchars);
if (STRINGP (string))
- for (i = 0; i < nchars; i++)
+ for (ptrdiff_t i = 0; i < nchars; i++)
{
- FETCH_STRING_CHAR_ADVANCE (ch, string, charpos, bytepos);
- ASET (key, i, make_number (ch));
+ ch = fetch_string_char_advance (string, &charpos, &bytepos);
+ ASET (key, i, make_fixnum (ch));
}
else
- for (i = 0; i < nchars; i++)
+ for (ptrdiff_t i = 0; i < nchars; i++)
{
- FETCH_CHAR_ADVANCE (ch, charpos, bytepos);
- ASET (key, i, make_number (ch));
+ ch = fetch_char_advance (&charpos, &bytepos);
+ ASET (key, i, make_fixnum (ch));
}
}
else
@@ -250,8 +250,8 @@ get_composition_id (ptrdiff_t charpos, ptrdiff_t bytepos, ptrdiff_t nchars,
key = HASH_KEY (hash_table, hash_index);
id = HASH_VALUE (hash_table, hash_index);
XSETCAR (prop, id);
- XSETCDR (prop, Fcons (make_number (nchars), Fcons (key, XCDR (prop))));
- return XINT (id);
+ XSETCDR (prop, Fcons (make_fixnum (nchars), Fcons (key, XCDR (prop))));
+ return XFIXNUM (id);
}
/* This composition is a new one. We must register it. */
@@ -274,7 +274,7 @@ get_composition_id (ptrdiff_t charpos, ptrdiff_t bytepos, ptrdiff_t nchars,
/* COMPONENTS is a glyph-string. */
ptrdiff_t len = ASIZE (key);
- for (i = 1; i < len; i++)
+ for (ptrdiff_t i = 1; i < len; i++)
if (! VECTORP (AREF (key, i)))
goto invalid_composition;
}
@@ -287,9 +287,9 @@ get_composition_id (ptrdiff_t charpos, ptrdiff_t bytepos, ptrdiff_t nchars,
goto invalid_composition;
/* All elements should be integers (character or encoded
composition rule). */
- for (i = 0; i < len; i++)
+ for (ptrdiff_t i = 0; i < len; i++)
{
- if (!INTEGERP (key_contents[i]))
+ if (!FIXNUMP (key_contents[i]))
goto invalid_composition;
}
}
@@ -298,14 +298,14 @@ get_composition_id (ptrdiff_t charpos, ptrdiff_t bytepos, ptrdiff_t nchars,
the cons cell of PROP because it is not shared. */
XSETFASTINT (id, n_compositions);
XSETCAR (prop, id);
- XSETCDR (prop, Fcons (make_number (nchars), Fcons (key, XCDR (prop))));
+ XSETCDR (prop, Fcons (make_fixnum (nchars), Fcons (key, XCDR (prop))));
/* Register the composition in composition_hash_table. */
hash_index = hash_put (hash_table, key, id, hash_code);
method = (NILP (components)
? COMPOSITION_RELATIVE
- : ((INTEGERP (components) || STRINGP (components))
+ : ((FIXNUMP (components) || STRINGP (components))
? COMPOSITION_WITH_ALTCHARS
: COMPOSITION_WITH_RULE_ALTCHARS));
@@ -329,10 +329,10 @@ get_composition_id (ptrdiff_t charpos, ptrdiff_t bytepos, ptrdiff_t nchars,
{
/* Relative composition. */
cmp->width = 0;
- for (i = 0; i < glyph_len; i++)
+ for (ptrdiff_t i = 0; i < glyph_len; i++)
{
int this_width;
- ch = XINT (key_contents[i]);
+ ch = XFIXNUM (key_contents[i]);
/* TAB in a composition means display glyphs with padding
space on the left or right. */
this_width = (ch == '\t' ? 1 : CHARACTER_WIDTH (ch));
@@ -345,17 +345,17 @@ get_composition_id (ptrdiff_t charpos, ptrdiff_t bytepos, ptrdiff_t nchars,
/* Rule-base composition. */
double leftmost = 0.0, rightmost;
- ch = XINT (key_contents[0]);
+ ch = XFIXNUM (key_contents[0]);
rightmost = ch != '\t' ? CHARACTER_WIDTH (ch) : 1;
- for (i = 1; i < glyph_len; i += 2)
+ for (ptrdiff_t i = 1; i < glyph_len; i += 2)
{
int rule, gref, nref;
int this_width;
double this_left;
- rule = XINT (key_contents[i]);
- ch = XINT (key_contents[i + 1]);
+ rule = XFIXNUM (key_contents[i]);
+ ch = XFIXNUM (key_contents[i + 1]);
this_width = ch != '\t' ? CHARACTER_WIDTH (ch) : 1;
/* A composition rule is specified by an integer value
@@ -431,9 +431,9 @@ find_composition (ptrdiff_t pos, ptrdiff_t limit,
if (limit > pos) /* search forward */
{
- val = Fnext_single_property_change (make_number (pos), Qcomposition,
- object, make_number (limit));
- pos = XINT (val);
+ val = Fnext_single_property_change (make_fixnum (pos), Qcomposition,
+ object, make_fixnum (limit));
+ pos = XFIXNUM (val);
if (pos == limit)
return 0;
}
@@ -442,9 +442,9 @@ find_composition (ptrdiff_t pos, ptrdiff_t limit,
if (get_property_and_range (pos - 1, Qcomposition, prop, start, end,
object))
return 1;
- val = Fprevious_single_property_change (make_number (pos), Qcomposition,
- object, make_number (limit));
- pos = XINT (val);
+ val = Fprevious_single_property_change (make_fixnum (pos), Qcomposition,
+ object, make_fixnum (limit));
+ pos = XFIXNUM (val);
if (pos == limit)
return 0;
pos--;
@@ -474,7 +474,7 @@ run_composition_function (ptrdiff_t from, ptrdiff_t to, Lisp_Object prop)
&& !composition_valid_p (start, end, prop))
to = end;
if (!NILP (Ffboundp (func)))
- call2 (func, make_number (from), make_number (to));
+ call2 (func, make_fixnum (from), make_fixnum (to));
}
/* Make invalid compositions adjacent to or inside FROM and TO valid.
@@ -519,7 +519,7 @@ update_compositions (ptrdiff_t from, ptrdiff_t to, int check_mask)
if (end > to)
max_pos = end;
if (from < end)
- Fput_text_property (make_number (from), make_number (end),
+ Fput_text_property (make_fixnum (from), make_fixnum (end),
Qcomposition,
Fcons (XCAR (prop), XCDR (prop)), Qnil);
run_composition_function (start, end, prop);
@@ -560,7 +560,7 @@ update_compositions (ptrdiff_t from, ptrdiff_t to, int check_mask)
the former to the copy of it. */
if (to < end)
{
- Fput_text_property (make_number (start), make_number (to),
+ Fput_text_property (make_fixnum (start), make_fixnum (to),
Qcomposition,
Fcons (XCAR (prop), XCDR (prop)), Qnil);
max_pos = end;
@@ -577,13 +577,13 @@ update_compositions (ptrdiff_t from, ptrdiff_t to, int check_mask)
}
if (min_pos < max_pos)
{
- ptrdiff_t count = SPECPDL_INDEX ();
+ specpdl_ref 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),
+ Fremove_list_of_text_properties (make_fixnum (min_pos),
+ make_fixnum (max_pos),
list1 (Qauto_composed), Qnil);
unbind_to (count, Qnil);
}
@@ -625,9 +625,9 @@ compose_text (ptrdiff_t start, ptrdiff_t end, Lisp_Object components,
{
Lisp_Object prop;
- prop = Fcons (Fcons (make_number (end - start), components),
+ prop = Fcons (Fcons (make_fixnum (end - start), components),
modification_func);
- Fput_text_property (make_number (start), make_number (end),
+ Fput_text_property (make_fixnum (start), make_fixnum (end),
Qcomposition, prop, string);
}
@@ -639,10 +639,8 @@ compose_text (ptrdiff_t start, ptrdiff_t end, Lisp_Object components,
static Lisp_Object gstring_hash_table;
-static Lisp_Object gstring_lookup_cache (Lisp_Object);
-
-static Lisp_Object
-gstring_lookup_cache (Lisp_Object header)
+Lisp_Object
+composition_gstring_lookup_cache (Lisp_Object header)
{
struct Lisp_Hash_Table *h = XHASH_TABLE (gstring_hash_table);
ptrdiff_t i = hash_lookup (h, header, NULL);
@@ -654,27 +652,22 @@ Lisp_Object
composition_gstring_put_cache (Lisp_Object gstring, ptrdiff_t len)
{
struct Lisp_Hash_Table *h = XHASH_TABLE (gstring_hash_table);
- EMACS_UINT hash;
- Lisp_Object header, copy;
- ptrdiff_t i;
-
- header = LGSTRING_HEADER (gstring);
- hash = h->test.hashfn (&h->test, header);
+ Lisp_Object header = LGSTRING_HEADER (gstring);
+ Lisp_Object hash = h->test.hashfn (header, h);
if (len < 0)
{
- ptrdiff_t j, glyph_len = LGSTRING_GLYPH_LEN (gstring);
- for (j = 0; j < glyph_len; j++)
- if (NILP (LGSTRING_GLYPH (gstring, j)))
+ ptrdiff_t glyph_len = LGSTRING_GLYPH_LEN (gstring);
+ for (len = 0; len < glyph_len; len++)
+ if (NILP (LGSTRING_GLYPH (gstring, len)))
break;
- len = j;
}
- copy = Fmake_vector (make_number (len + 2), Qnil);
+ Lisp_Object copy = make_nil_vector (len + 2);
LGSTRING_SET_HEADER (copy, Fcopy_sequence (header));
- for (i = 0; i < len; i++)
+ for (ptrdiff_t i = 0; i < len; i++)
LGSTRING_SET_GLYPH (copy, i, Fcopy_sequence (LGSTRING_GLYPH (gstring, i)));
- i = hash_put (h, LGSTRING_HEADER (copy), copy, hash);
- LGSTRING_SET_ID (copy, make_number (i));
+ ptrdiff_t id = hash_put (h, LGSTRING_HEADER (copy), copy, hash);
+ LGSTRING_SET_ID (copy, make_fixnum (id));
return copy;
}
@@ -686,6 +679,41 @@ composition_gstring_from_id (ptrdiff_t id)
return HASH_VALUE (h, id);
}
+/* Remove from the composition hash table every lgstring that
+ references the given FONT_OBJECT. */
+void
+composition_gstring_cache_clear_font (Lisp_Object font_object)
+{
+ struct Lisp_Hash_Table *h = XHASH_TABLE (gstring_hash_table);
+
+ for (ptrdiff_t i = 0; i < HASH_TABLE_SIZE (h); ++i)
+ {
+ Lisp_Object k = HASH_KEY (h, i);
+
+ if (!BASE_EQ (k, Qunbound))
+ {
+ Lisp_Object gstring = HASH_VALUE (h, i);
+
+ if (EQ (LGSTRING_FONT (gstring), font_object))
+ hash_remove_from_table (h, k);
+ }
+ }
+}
+
+DEFUN ("clear-composition-cache", Fclear_composition_cache,
+ Sclear_composition_cache, 0, 0, 0,
+ doc: /* Internal use only.
+Clear composition cache. */)
+ (void)
+{
+ gstring_hash_table = CALLN (Fmake_hash_table, QCtest, Qequal,
+ QCsize, make_fixnum (311));
+ /* Fixme: We call Fclear_face_cache to force complete re-building of
+ display glyphs. But, it may be better to call this function from
+ Fclear_face_cache instead. */
+ return Fclear_face_cache (Qt);
+}
+
bool
composition_gstring_p (Lisp_Object gstring)
{
@@ -702,9 +730,9 @@ composition_gstring_p (Lisp_Object gstring)
&& ! CODING_SYSTEM_P (LGSTRING_FONT (gstring))))
return 0;
for (i = 1; i < ASIZE (LGSTRING_HEADER (gstring)); i++)
- if (! NATNUMP (AREF (LGSTRING_HEADER (gstring), i)))
+ if (! FIXNATP (AREF (LGSTRING_HEADER (gstring), i)))
return 0;
- if (! NILP (LGSTRING_ID (gstring)) && ! NATNUMP (LGSTRING_ID (gstring)))
+ if (! NILP (LGSTRING_ID (gstring)) && ! FIXNATP (LGSTRING_ID (gstring)))
return 0;
for (i = 0; i < LGSTRING_GLYPH_LEN (gstring); i++)
{
@@ -777,36 +805,25 @@ static Lisp_Object gstring_work;
static Lisp_Object gstring_work_headers;
static Lisp_Object
-fill_gstring_header (Lisp_Object header, ptrdiff_t from, ptrdiff_t from_byte,
+fill_gstring_header (ptrdiff_t from, ptrdiff_t from_byte,
ptrdiff_t to, Lisp_Object font_object, Lisp_Object string)
{
- ptrdiff_t len = to - from, i;
-
+ ptrdiff_t len = to - from;
if (len == 0)
error ("Attempt to shape zero-length text");
- if (VECTORP (header))
- {
- if (ASIZE (header) != len + 1)
- args_out_of_range (header, make_number (len + 1));
- }
- else
- {
- if (len <= 8)
- header = AREF (gstring_work_headers, len - 1);
- else
- header = make_uninit_vector (len + 1);
- }
+ eassume (0 < len);
+ Lisp_Object header = (len <= 8
+ ? AREF (gstring_work_headers, len - 1)
+ : make_uninit_vector (len + 1));
ASET (header, 0, font_object);
- for (i = 0; i < len; i++)
+ for (ptrdiff_t i = 0; i < len; i++)
{
- int c;
-
- if (NILP (string))
- FETCH_CHAR_ADVANCE_NO_CHECK (c, from, from_byte);
- else
- FETCH_STRING_CHAR_ADVANCE_NO_CHECK (c, string, from, from_byte);
- ASET (header, i + 1, make_number (c));
+ int c
+ = (NILP (string)
+ ? fetch_char_advance_no_check (&from, &from_byte)
+ : fetch_string_char_advance_no_check (string, &from, &from_byte));
+ ASET (header, i + 1, make_fixnum (c));
}
return header;
}
@@ -818,11 +835,16 @@ fill_gstring_body (Lisp_Object gstring)
Lisp_Object header = AREF (gstring, 0);
ptrdiff_t len = LGSTRING_CHAR_LEN (gstring);
ptrdiff_t i;
+ struct font *font = NULL;
+ unsigned int code;
+
+ if (FONT_OBJECT_P (font_object))
+ font = XFONT_OBJECT (font_object);
for (i = 0; i < len; i++)
{
Lisp_Object g = LGSTRING_GLYPH (gstring, i);
- int c = XFASTINT (AREF (header, i + 1));
+ int c = XFIXNAT (AREF (header, i + 1));
if (NILP (g))
{
@@ -832,13 +854,18 @@ fill_gstring_body (Lisp_Object gstring)
LGLYPH_SET_FROM (g, i);
LGLYPH_SET_TO (g, i);
LGLYPH_SET_CHAR (g, c);
- if (FONT_OBJECT_P (font_object))
- {
- font_fill_lglyph_metrics (g, font_object);
- }
+
+ if (font != NULL)
+ code = font->driver->encode_char (font, LGLYPH_CHAR (g));
+ else
+ code = FONT_INVALID_CODE;
+ if (code != FONT_INVALID_CODE)
+ {
+ font_fill_lglyph_metrics (g, font, code);
+ }
else
{
- int width = XFASTINT (CHAR_TABLE_REF (Vchar_width_table, c));
+ int width = XFIXNAT (CHAR_TABLE_REF (Vchar_width_table, c));
LGLYPH_SET_CODE (g, c);
LGLYPH_SET_LBEARING (g, 0);
@@ -849,7 +876,8 @@ fill_gstring_body (Lisp_Object gstring)
}
LGLYPH_SET_ADJUSTMENT (g, Qnil);
}
- if (i < LGSTRING_GLYPH_LEN (gstring))
+ len = LGSTRING_GLYPH_LEN (gstring);
+ for (; i < len; i++)
LGSTRING_SET_GLYPH (gstring, i, Qnil);
}
@@ -857,17 +885,18 @@ fill_gstring_body (Lisp_Object gstring)
/* Try to compose the characters at CHARPOS according to composition
rule RULE ([PATTERN PREV-CHARS FUNC]). LIMIT limits the characters
to compose. STRING, if not nil, is a target string. WIN is a
- window where the characters are being displayed. If characters are
+ window where the characters are being displayed. CH is the
+ character that triggered the composition check. If characters are
successfully composed, return the composition as a glyph-string
object. Otherwise return nil. */
static Lisp_Object
autocmp_chars (Lisp_Object rule, ptrdiff_t charpos, ptrdiff_t bytepos,
ptrdiff_t limit, struct window *win, struct face *face,
- Lisp_Object string)
+ Lisp_Object string, Lisp_Object direction, int ch)
{
- ptrdiff_t count = SPECPDL_INDEX ();
- Lisp_Object pos = make_number (charpos);
+ specpdl_ref count = SPECPDL_INDEX ();
+ Lisp_Object pos = make_fixnum (charpos);
ptrdiff_t to;
ptrdiff_t pt = PT, pt_byte = PT_BYTE;
Lisp_Object re, font_object, lgstring;
@@ -895,7 +924,7 @@ autocmp_chars (Lisp_Object rule, ptrdiff_t charpos, ptrdiff_t bytepos,
struct frame *f = XFRAME (font_object);
if (FRAME_WINDOW_P (f))
{
- font_object = font_range (charpos, bytepos, &to, win, face, string);
+ font_object = font_range (charpos, bytepos, &to, win, face, string, ch);
if (! FONT_OBJECT_P (font_object)
|| (! NILP (re)
&& to < limit
@@ -903,7 +932,7 @@ autocmp_chars (Lisp_Object rule, ptrdiff_t charpos, ptrdiff_t bytepos,
return unbind_to (count, Qnil);
}
#endif
- lgstring = Fcomposition_get_gstring (pos, make_number (to), font_object,
+ lgstring = Fcomposition_get_gstring (pos, make_fixnum (to), font_object,
string);
if (NILP (LGSTRING_ID (lgstring)))
{
@@ -911,23 +940,49 @@ autocmp_chars (Lisp_Object rule, ptrdiff_t charpos, ptrdiff_t bytepos,
if (NILP (string))
record_unwind_protect (restore_point_unwind,
build_marker (current_buffer, pt, pt_byte));
- lgstring = safe_call (6, Vauto_composition_function, AREF (rule, 2),
- pos, make_number (to), font_object, string);
+ lgstring = safe_call (7, Vauto_composition_function, AREF (rule, 2),
+ pos, make_fixnum (to), font_object, string,
+ direction);
}
return unbind_to (count, lgstring);
}
/* 1 iff the character C is composable. Characters of general
- category Z? or C? are not composable except for ZWNJ and ZWJ. */
+ category Z? or C? are not composable except for ZWNJ and ZWJ,
+ and characters of category Zs. */
static bool
char_composable_p (int c)
{
Lisp_Object val;
- return (c > ' '
+ return (c >= ' '
&& (c == ZERO_WIDTH_NON_JOINER || c == ZERO_WIDTH_JOINER
- || (val = CHAR_TABLE_REF (Vunicode_category_table, c),
- (INTEGERP (val) && (XINT (val) <= UNICODE_CATEGORY_So)))));
+ /* Per Unicode TR51, these tag characters can be part of
+ Emoji sequences. */
+ || (TAG_SPACE <= c && c <= CANCEL_TAG)
+ /* unicode-category-table may not be available during
+ dumping. */
+ || (CHAR_TABLE_P (Vunicode_category_table)
+ && (val = CHAR_TABLE_REF (Vunicode_category_table, c),
+ (FIXNUMP (val)
+ && (XFIXNUM (val) <= UNICODE_CATEGORY_Zs))))));
+}
+
+static inline bool
+inhibit_auto_composition (void)
+{
+ if (NILP (Vauto_composition_mode))
+ return true;
+
+ if (STRINGP (Vauto_composition_mode))
+ {
+ char *name = tty_type_name (Qnil);
+
+ if (name && ! strcmp (SSDATA (Vauto_composition_mode), name))
+ return true;
+ }
+
+ return false;
}
/* Update cmp_it->stop_pos to the next position after CHARPOS (and
@@ -936,7 +991,9 @@ char_composable_p (int c)
less than CHARPOS, search backward to ENDPOS+1 assuming that
set_iterator_to_next works in reverse order. In this case, if a
composition closest to CHARPOS is found, set cmp_it->stop_pos to
- the last character of the composition.
+ the last character of the composition. STRING, if non-nil, is
+ the string (as opposed to a buffer) whose characters should be
+ tested for being composable.
If no composition is found, set cmp_it->ch to -2. If a static
composition is found, set cmp_it->ch to -1. Otherwise, set
@@ -944,7 +1001,9 @@ char_composable_p (int c)
composition. */
void
-composition_compute_stop_pos (struct composition_it *cmp_it, ptrdiff_t charpos, ptrdiff_t bytepos, ptrdiff_t endpos, Lisp_Object string)
+composition_compute_stop_pos (struct composition_it *cmp_it, ptrdiff_t charpos,
+ ptrdiff_t bytepos, ptrdiff_t endpos,
+ Lisp_Object string)
{
ptrdiff_t start, end;
int c;
@@ -965,7 +1024,11 @@ composition_compute_stop_pos (struct composition_it *cmp_it, ptrdiff_t charpos,
/* But we don't know where to stop the searching. */
endpos = NILP (string) ? BEGV - 1 : -1;
/* Usually we don't reach ENDPOS because we stop searching
- at an uncomposable character (NL, LRE, etc). */
+ at an uncomposable character (NL, LRE, etc). In buffers
+ with long lines, however, NL might be far away, so
+ pretend that the buffer is smaller. */
+ if (current_buffer->long_line_optimizations_p)
+ endpos = get_closer_narrowed_begv (cmp_it->parent_it->w, charpos);
}
}
cmp_it->id = -1;
@@ -983,8 +1046,10 @@ composition_compute_stop_pos (struct composition_it *cmp_it, ptrdiff_t charpos,
cmp_it->stop_pos = endpos = start;
cmp_it->ch = -1;
}
- if (NILP (BVAR (current_buffer, enable_multibyte_characters))
- || NILP (Vauto_composition_mode))
+ if ((NILP (string)
+ && NILP (BVAR (current_buffer, enable_multibyte_characters)))
+ || (STRINGP (string) && !STRING_MULTIBYTE (string))
+ || inhibit_auto_composition ())
return;
if (bytepos < 0)
{
@@ -1000,10 +1065,9 @@ composition_compute_stop_pos (struct composition_it *cmp_it, ptrdiff_t charpos,
/* Forward search. */
while (charpos < endpos)
{
- if (STRINGP (string))
- FETCH_STRING_CHAR_ADVANCE (c, string, charpos, bytepos);
- else
- FETCH_CHAR_ADVANCE (c, charpos, bytepos);
+ c = (STRINGP (string)
+ ? fetch_string_char_advance (string, &charpos, &bytepos)
+ : fetch_char_advance (&charpos, &bytepos));
if (c == '\n')
{
cmp_it->ch = -2;
@@ -1016,11 +1080,11 @@ composition_compute_stop_pos (struct composition_it *cmp_it, ptrdiff_t charpos,
{
Lisp_Object elt = XCAR (val);
if (VECTORP (elt) && ASIZE (elt) == 3
- && NATNUMP (AREF (elt, 1))
- && charpos - 1 - XFASTINT (AREF (elt, 1)) >= start)
+ && FIXNATP (AREF (elt, 1))
+ && charpos - 1 - XFIXNAT (AREF (elt, 1)) >= start)
{
cmp_it->rule_idx = ridx;
- cmp_it->lookback = XFASTINT (AREF (elt, 1));
+ cmp_it->lookback = XFIXNAT (AREF (elt, 1));
cmp_it->stop_pos = charpos - 1 - cmp_it->lookback;
cmp_it->ch = c;
return;
@@ -1058,7 +1122,7 @@ composition_compute_stop_pos (struct composition_it *cmp_it, ptrdiff_t charpos,
p = BYTE_POS_ADDR (bytepos);
else
p = SDATA (string) + bytepos;
- c = STRING_CHAR_AND_LENGTH (p, len);
+ c = string_char_and_length (p, &len);
limit = bytepos + len;
while (char_composable_p (c))
{
@@ -1067,10 +1131,10 @@ composition_compute_stop_pos (struct composition_it *cmp_it, ptrdiff_t charpos,
{
Lisp_Object elt = XCAR (val);
if (VECTORP (elt) && ASIZE (elt) == 3
- && NATNUMP (AREF (elt, 1))
- && charpos - XFASTINT (AREF (elt, 1)) > endpos)
+ && FIXNATP (AREF (elt, 1))
+ && charpos - XFIXNAT (AREF (elt, 1)) > endpos)
{
- ptrdiff_t back = XFASTINT (AREF (elt, 1));
+ ptrdiff_t back = XFIXNAT (AREF (elt, 1));
ptrdiff_t cpos = charpos - back, bpos;
if (back == 0)
@@ -1120,7 +1184,7 @@ composition_compute_stop_pos (struct composition_it *cmp_it, ptrdiff_t charpos,
}
else
{
- DEC_BOTH (charpos, bytepos);
+ dec_both (&charpos, &bytepos);
p = BYTE_POS_ADDR (bytepos);
}
c = STRING_CHAR (p);
@@ -1133,7 +1197,7 @@ composition_compute_stop_pos (struct composition_it *cmp_it, ptrdiff_t charpos,
{
while (charpos - 1 > endpos && ! char_composable_p (c))
{
- DEC_BOTH (charpos, bytepos);
+ dec_both (&charpos, &bytepos);
c = FETCH_MULTIBYTE_CHAR (bytepos);
}
}
@@ -1157,7 +1221,11 @@ composition_compute_stop_pos (struct composition_it *cmp_it, ptrdiff_t charpos,
characters to be composed. FACE, if non-NULL, is a base face of
the character. If STRING is not nil, it is a string containing the
character to check, and CHARPOS and BYTEPOS are indices in the
- string. In that case, FACE must not be NULL.
+ string. In that case, FACE must not be NULL. BIDI_LEVEL is the bidi
+ embedding level of the current paragraph, and is used to calculate the
+ direction argument to pass to the font shaper; value of -1 means the
+ caller doesn't know the embedding level (used by callers which didn't
+ invoke the display routines that perform bidi-display-reordering).
If the character is composed, setup members of CMP_IT (id, nglyphs,
from, to, reversed_p), and return true. Otherwise, update
@@ -1166,7 +1234,7 @@ composition_compute_stop_pos (struct composition_it *cmp_it, ptrdiff_t charpos,
bool
composition_reseat_it (struct composition_it *cmp_it, ptrdiff_t charpos,
ptrdiff_t bytepos, ptrdiff_t endpos, struct window *w,
- struct face *face, Lisp_Object string)
+ signed char bidi_level, struct face *face, Lisp_Object string)
{
if (cmp_it->ch == -2)
{
@@ -1196,23 +1264,29 @@ composition_reseat_it (struct composition_it *cmp_it, ptrdiff_t charpos,
else if (w)
{
Lisp_Object lgstring = Qnil;
- Lisp_Object val, elt;
+ Lisp_Object val, elt, direction = Qnil;
val = CHAR_TABLE_REF (Vcomposition_function_table, cmp_it->ch);
for (EMACS_INT i = 0; i < cmp_it->rule_idx; i++, val = XCDR (val))
continue;
if (charpos < endpos)
{
+ if (bidi_level < 0)
+ direction = Qnil;
+ else if ((bidi_level & 1) == 0)
+ direction = QL2R;
+ else
+ direction = QR2L;
for (; CONSP (val); val = XCDR (val))
{
elt = XCAR (val);
if (! VECTORP (elt) || ASIZE (elt) != 3
- || ! INTEGERP (AREF (elt, 1)))
+ || ! FIXNUMP (AREF (elt, 1)))
continue;
- if (XFASTINT (AREF (elt, 1)) != cmp_it->lookback)
+ if (XFIXNAT (AREF (elt, 1)) != cmp_it->lookback)
goto no_composition;
lgstring = autocmp_chars (elt, charpos, bytepos, endpos,
- w, face, string);
+ w, face, string, direction, cmp_it->ch);
if (composition_gstring_p (lgstring))
break;
lgstring = Qnil;
@@ -1231,13 +1305,36 @@ composition_reseat_it (struct composition_it *cmp_it, ptrdiff_t charpos,
if (cmp_it->lookback > 0)
{
cpos = charpos - cmp_it->lookback;
+ /* Reject the composition if it starts before ENDPOS,
+ which here can only happen if
+ composition-break-at-point is non-nil and point is
+ inside the composition. */
+ if (cpos < endpos)
+ {
+ eassert (composition_break_at_point);
+ eassert (endpos == PT);
+ goto no_composition;
+ }
if (STRINGP (string))
bpos = string_char_to_byte (string, cpos);
else
bpos = CHAR_TO_BYTE (cpos);
}
+ /* The bidi_level < 0 case below strictly speaking should
+ never happen, since we get here when bidi scan direction
+ is backward in the buffer, which can only happen if the
+ display routines were called to perform the bidi
+ reordering. But it doesn't harm to test for that, and
+ avoid someone raising their brows and thinking it's a
+ subtle bug... */
+ if (bidi_level < 0)
+ direction = Qnil;
+ else if ((bidi_level & 1) == 0)
+ direction = QL2R;
+ else
+ direction = QR2L;
lgstring = autocmp_chars (elt, cpos, bpos, charpos + 1, w, face,
- string);
+ string, direction, cmp_it->ch);
if (! composition_gstring_p (lgstring)
|| cpos + LGSTRING_CHAR_LEN (lgstring) - 1 != charpos)
/* Composition failed or didn't cover the current
@@ -1248,7 +1345,7 @@ composition_reseat_it (struct composition_it *cmp_it, ptrdiff_t charpos,
goto no_composition;
if (NILP (LGSTRING_ID (lgstring)))
lgstring = composition_gstring_put_cache (lgstring, -1);
- cmp_it->id = XINT (LGSTRING_ID (lgstring));
+ cmp_it->id = XFIXNUM (LGSTRING_ID (lgstring));
int i;
for (i = 0; i < LGSTRING_GLYPH_LEN (lgstring); i++)
if (NILP (LGSTRING_GLYPH (lgstring, i)))
@@ -1268,7 +1365,7 @@ composition_reseat_it (struct composition_it *cmp_it, ptrdiff_t charpos,
{
charpos++;
if (NILP (string))
- INC_POS (bytepos);
+ bytepos += next_char_len (bytepos);
else
bytepos += BYTES_BY_CHAR_HEAD (*(SDATA (string) + bytepos));
}
@@ -1377,7 +1474,7 @@ composition_update_it (struct composition_it *cmp_it, ptrdiff_t charpos, ptrdiff
cmp_it->width = 0;
for (i = cmp_it->nchars - 1; i >= 0; i--)
{
- c = XINT (LGSTRING_CHAR (gstring, from + i));
+ c = XFIXNUM (LGSTRING_CHAR (gstring, from + i));
cmp_it->nbytes += CHAR_BYTES (c);
cmp_it->width += CHARACTER_WIDTH (c);
}
@@ -1420,14 +1517,64 @@ struct position_record
(POSITION).pos--; \
} while (0)
-/* This is like find_composition, but find an automatic composition
- instead. It is assured that POS is not within a static
- composition. If found, set *GSTRING to the glyph-string
- representing the composition, and return true. Otherwise, *GSTRING to
- Qnil, and return false. */
+/* Similar to find_composition, but find an automatic composition instead.
+
+ This function looks for automatic composition at or near position
+ POS of STRING object, either a buffer or a Lisp string. If STRING
+ is nil, it defaults to the current buffer. It must be assured that
+ POS is not within a static composition. Also, the current buffer
+ must be displayed in some window, otherwise the function will
+ return FALSE.
+
+ If LIMIT is negative, and there's no composition that includes POS
+ (i.e. starts at or before POS and ends at or after POS), return
+ FALSE. In this case, the function is allowed to look from POS as
+ far back as BACKLIM, and as far forward as POS+1 plus
+ MAX_AUTO_COMPOSITION_LOOKBACK, the maximum number of look-back for
+ automatic compositions (3) -- this is a limitation imposed by
+ composition rules in composition-function-table, which see. If
+ BACKLIM is negative, it stands for the beginning of STRING object:
+ BEGV for a buffer or position zero for a string.
+
+ If LIMIT is positive, search for a composition forward (LIMIT >
+ POS) or backward (LIMIT < POS). In this case, LIMIT bounds the
+ search for the first character of a composed sequence.
+ (LIMIT == POS is the same as LIMIT < 0.) If LIMIT > POS, the
+ function can find a composition that starts after POS.
+
+ BACKLIM limits how far back is the function allowed to look in
+ STRING object while trying to find a position where it is safe to
+ start searching forward for compositions. Such a safe place is
+ generally the position after a character that can never be
+ composed.
+
+ If BACKLIM is negative, that means the first character position of
+ STRING object; this is useful when calling the function for the
+ first time for a given buffer or string, since it is possible that
+ a composition begins before POS. However, if POS is very far from
+ the beginning of STRING object, a negative value of BACKLIM could
+ make the function slow. For that reason, when STRING is a buffer
+ or nil, we restrict the search back to the first newline before
+ POS. Also, in this case the function may return START and END that
+ do not include POS, something that is not necessarily wanted, and
+ needs to be explicitly checked by the caller.
+
+ When calling the function in a loop for the same buffer/string, the
+ caller should generally set BACKLIM equal to POS, to avoid costly
+ repeated searches backward. This is because if the previous
+ positions were already checked for compositions, there should be no
+ reason to re-check them.
+
+ If BACKLIM is positive, it must be less or equal to LIMIT.
+
+ If an automatic composition satisfying the above conditions is
+ found, set *GSTRING to the Lispy glyph-string representing the
+ composition, set *START and *END to the start and end of the
+ composed sequence, and return TRUE. Otherwise, set *GSTRING to
+ nil, and return FALSE. */
-static bool
-find_automatic_composition (ptrdiff_t pos, ptrdiff_t limit,
+bool
+find_automatic_composition (ptrdiff_t pos, ptrdiff_t limit, ptrdiff_t backlim,
ptrdiff_t *start, ptrdiff_t *end,
Lisp_Object *gstring, Lisp_Object string)
{
@@ -1449,13 +1596,29 @@ find_automatic_composition (ptrdiff_t pos, ptrdiff_t limit,
cur.pos = pos;
if (NILP (string))
{
- head = BEGV, tail = ZV, stop = GPT;
+ if (backlim < 0)
+ {
+ /* This assumes a newline can never be composed. */
+ head = find_newline (pos, -1, 0, -1, -1, NULL, NULL, false);
+ }
+ else
+ head = backlim;
+ if (current_buffer->long_line_optimizations_p)
+ {
+ /* In buffers with very long lines, this function becomes very
+ slow. Pretend that the buffer is narrowed to make it fast. */
+ ptrdiff_t begv = get_closer_narrowed_begv (w, window_point (w));
+ if (pos > begv)
+ head = begv;
+ }
+ tail = ZV;
+ stop = GPT;
cur.pos_byte = CHAR_TO_BYTE (cur.pos);
cur.p = BYTE_POS_ADDR (cur.pos_byte);
}
else
{
- head = 0, tail = SCHARS (string), stop = -1;
+ head = backlim < 0 ? 0 : backlim, tail = SCHARS (string), stop = -1;
cur.pos_byte = string_char_to_byte (string, cur.pos);
cur.p = SDATA (string) + cur.pos_byte;
}
@@ -1463,6 +1626,9 @@ find_automatic_composition (ptrdiff_t pos, ptrdiff_t limit,
/* Finding a composition covering the character after POS is the
same as setting LIMIT to POS. */
limit = pos;
+
+ eassert (backlim < 0 || backlim <= limit);
+
if (limit <= pos)
fore_check_limit = min (tail, pos + 1 + MAX_AUTO_COMPOSITION_LOOKBACK);
else
@@ -1545,9 +1711,9 @@ find_automatic_composition (ptrdiff_t pos, ptrdiff_t limit,
{
Lisp_Object elt = XCAR (val);
- if (VECTORP (elt) && ASIZE (elt) == 3 && NATNUMP (AREF (elt, 1)))
+ if (VECTORP (elt) && ASIZE (elt) == 3 && FIXNATP (AREF (elt, 1)))
{
- EMACS_INT check_pos = cur.pos - XFASTINT (AREF (elt, 1));
+ EMACS_INT check_pos = cur.pos - XFIXNAT (AREF (elt, 1));
struct position_record check;
if (check_pos < head
@@ -1557,7 +1723,7 @@ find_automatic_composition (ptrdiff_t pos, ptrdiff_t limit,
for (check = cur; check_pos < check.pos; )
BACKWARD_CHAR (check, stop);
*gstring = autocmp_chars (elt, check.pos, check.pos_byte,
- tail, w, NULL, string);
+ tail, w, NULL, string, Qnil, c);
need_adjustment = 1;
if (NILP (*gstring))
{
@@ -1639,12 +1805,12 @@ composition_adjust_point (ptrdiff_t last_pt, ptrdiff_t new_pt)
}
if (NILP (BVAR (current_buffer, enable_multibyte_characters))
- || NILP (Vauto_composition_mode))
+ || inhibit_auto_composition ())
return new_pt;
/* Next check the automatic composition. */
- if (! find_automatic_composition (new_pt, (ptrdiff_t) -1, &beg, &end, &val,
- Qnil)
+ if (! find_automatic_composition (new_pt, (ptrdiff_t) -1, (ptrdiff_t) -1,
+ &beg, &end, &val, Qnil)
|| beg == new_pt)
return new_pt;
for (i = 0; i < LGSTRING_GLYPH_LEN (val); i++)
@@ -1725,27 +1891,40 @@ should be ignored. */)
if (NILP (BVAR (current_buffer, enable_multibyte_characters)))
error ("Attempt to shape unibyte text");
validate_region (&from, &to);
- frompos = XFASTINT (from);
- topos = XFASTINT (to);
+ frompos = XFIXNAT (from);
+ topos = XFIXNAT (to);
frombyte = CHAR_TO_BYTE (frompos);
}
else
{
CHECK_STRING (string);
- validate_subarray (string, from, to, SCHARS (string), &frompos, &topos);
+ ptrdiff_t chars = SCHARS (string);
+ validate_subarray (string, from, to, chars, &frompos, &topos);
if (! STRING_MULTIBYTE (string))
- error ("Attempt to shape unibyte text");
+ {
+ ptrdiff_t i;
+
+ for (i = SBYTES (string) - 1; i >= 0; i--)
+ if (!ASCII_CHAR_P (SREF (string, i)))
+ error ("Attempt to shape unibyte text");
+ /* STRING is a pure-ASCII string, so we can convert it (or,
+ rather, its copy) to multibyte and use that thereafter. */
+ /* FIXME: Not clear why we need to do that: AFAICT the rest of
+ the code should work on an ASCII-only unibyte string just
+ as well (bug#56347). */
+ string = make_multibyte_string (SSDATA (string), chars, chars);
+ }
frombyte = string_char_to_byte (string, frompos);
}
- header = fill_gstring_header (Qnil, frompos, frombyte,
+ header = fill_gstring_header (frompos, frombyte,
topos, font_object, string);
- gstring = gstring_lookup_cache (header);
+ gstring = composition_gstring_lookup_cache (header);
if (! NILP (gstring))
return gstring;
if (LGSTRING_GLYPH_LEN (gstring_work) < topos - frompos)
- gstring_work = Fmake_vector (make_number (topos - frompos + 2), Qnil);
+ gstring_work = make_nil_vector (topos - frompos + 2);
LGSTRING_SET_HEADER (gstring_work, header);
LGSTRING_SET_ID (gstring_work, Qnil);
fill_gstring_body (gstring_work);
@@ -1766,12 +1945,12 @@ for the composition. See `compose-region' for more details. */)
{
validate_region (&start, &end);
if (!NILP (components)
- && !INTEGERP (components)
+ && !FIXNUMP (components)
&& !CONSP (components)
&& !STRINGP (components))
CHECK_VECTOR (components);
- compose_text (XINT (start), XINT (end), components, modification_func, Qnil);
+ compose_text (XFIXNUM (start), XFIXNUM (end), components, modification_func, Qnil);
return Qnil;
}
@@ -1806,49 +1985,49 @@ See `find-composition' for more details. */)
ptrdiff_t start, end, from, to;
int id;
- CHECK_NUMBER_COERCE_MARKER (pos);
+ EMACS_INT fixed_pos = fix_position (pos);
if (!NILP (limit))
- {
- CHECK_NUMBER_COERCE_MARKER (limit);
- to = min (XINT (limit), ZV);
- }
+ to = clip_to_bounds (PTRDIFF_MIN, fix_position (limit), ZV);
else
to = -1;
if (!NILP (string))
{
CHECK_STRING (string);
- if (XINT (pos) < 0 || XINT (pos) > SCHARS (string))
+ if (! (0 <= fixed_pos && fixed_pos <= SCHARS (string)))
args_out_of_range (string, pos);
}
else
{
- if (XINT (pos) < BEGV || XINT (pos) > ZV)
+ if (! (BEGV <= fixed_pos && fixed_pos <= ZV))
args_out_of_range (Fcurrent_buffer (), pos);
}
- from = XINT (pos);
+ from = fixed_pos;
if (!find_composition (from, to, &start, &end, &prop, string))
{
- if (!NILP (BVAR (current_buffer, enable_multibyte_characters))
- && ! NILP (Vauto_composition_mode)
- && find_automatic_composition (from, to, &start, &end, &gstring,
- string))
- return list3 (make_number (start), make_number (end), gstring);
+ if (((NILP (string)
+ && !NILP (BVAR (current_buffer, enable_multibyte_characters)))
+ || (!NILP (string) && STRING_MULTIBYTE (string)))
+ && ! inhibit_auto_composition ()
+ && find_automatic_composition (from, to, (ptrdiff_t) -1,
+ &start, &end, &gstring, string))
+ return list3 (make_fixnum (start), make_fixnum (end), gstring);
return Qnil;
}
- if ((end <= XINT (pos) || start > XINT (pos)))
+ if (! (start <= fixed_pos && fixed_pos < end))
{
ptrdiff_t s, e;
- if (find_automatic_composition (from, to, &s, &e, &gstring, string)
- && (e <= XINT (pos) ? e > end : s < start))
- return list3 (make_number (s), make_number (e), gstring);
+ if (find_automatic_composition (from, to, (ptrdiff_t) -1,
+ &s, &e, &gstring, string)
+ && (e <= fixed_pos ? e > end : s < start))
+ return list3 (make_fixnum (s), make_fixnum (e), gstring);
}
if (!composition_valid_p (start, end, prop))
- return list3 (make_number (start), make_number (end), Qnil);
+ return list3 (make_fixnum (start), make_fixnum (end), Qnil);
if (NILP (detail_p))
- return list3 (make_number (start), make_number (end), Qt);
+ return list3 (make_fixnum (start), make_fixnum (end), Qt);
if (composition_registered_p (prop))
id = COMPOSITION_ID (prop);
@@ -1870,12 +2049,60 @@ See `find-composition' for more details. */)
relative_p = (method == COMPOSITION_WITH_RULE_ALTCHARS
? Qnil : Qt);
mod_func = COMPOSITION_MODIFICATION_FUNC (prop);
- tail = list4 (components, relative_p, mod_func, make_number (width));
+ tail = list4 (components, relative_p, mod_func, make_fixnum (width));
}
else
tail = Qnil;
- return Fcons (make_number (start), Fcons (make_number (end), tail));
+ return Fcons (make_fixnum (start), Fcons (make_fixnum (end), tail));
+}
+
+static int
+compare_composition_rules (const void *r1, const void *r2)
+{
+ Lisp_Object vec1 = *(Lisp_Object *)r1, vec2 = *(Lisp_Object *)r2;
+
+ return XFIXNAT (AREF (vec2, 1)) - XFIXNAT (AREF (vec1, 1));
+}
+
+DEFUN ("composition-sort-rules", Fcomposition_sort_rules,
+ Scomposition_sort_rules, 1, 1, 0,
+ doc: /* Sort composition RULES by their LOOKBACK parameter.
+
+If RULES include just one rule, return RULES.
+Otherwise, return a new list of rules where all the rules are
+arranged in decreasing order of the LOOKBACK parameter of the
+rules (the second element of the rule's vector). This is required
+when combining composition rules from different sources, because
+of the way buffer text is examined for matching one of the rules. */)
+ (Lisp_Object rules)
+{
+ ptrdiff_t nrules;
+ USE_SAFE_ALLOCA;
+
+ CHECK_LIST (rules);
+ nrules = list_length (rules);
+ if (nrules > 1)
+ {
+ ptrdiff_t i;
+ Lisp_Object *sortvec;
+
+ SAFE_NALLOCA (sortvec, 1, nrules);
+ for (i = 0; i < nrules; i++)
+ {
+ Lisp_Object elt = XCAR (rules);
+ if (VECTORP (elt) && ASIZE (elt) == 3 && FIXNATP (AREF (elt, 1)))
+ sortvec[i] = elt;
+ else
+ error ("Invalid composition rule in RULES argument");
+ rules = XCDR (rules);
+ }
+ qsort (sortvec, nrules, sizeof (Lisp_Object), compare_composition_rules);
+ rules = Flist (nrules, sortvec);
+ SAFE_FREE ();
+ }
+
+ return rules;
}
@@ -1892,7 +2119,7 @@ syms_of_composite (void)
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. */
- Lisp_Object args[] = {QCtest, Qequal, QCsize, make_number (311)};
+ Lisp_Object args[] = {QCtest, Qequal, QCsize, make_fixnum (311)};
composition_hash_table = CALLMANY (Fmake_hash_table, args);
staticpro (&composition_hash_table);
@@ -1901,11 +2128,11 @@ syms_of_composite (void)
staticpro (&gstring_hash_table);
staticpro (&gstring_work_headers);
- gstring_work_headers = make_uninit_vector (8);
+ gstring_work_headers = make_nil_vector (8);
for (i = 0; i < 8; i++)
- ASET (gstring_work_headers, i, Fmake_vector (make_number (i + 2), Qnil));
+ ASET (gstring_work_headers, i, make_nil_vector (i + 2));
staticpro (&gstring_work);
- gstring_work = Fmake_vector (make_number (10), Qnil);
+ gstring_work = make_nil_vector (10);
/* Text property `composition' should be nonsticky by default. */
Vtext_property_default_nonsticky
@@ -1929,20 +2156,33 @@ The default value is the function `compose-chars-after'. */);
DEFVAR_LISP ("auto-composition-mode", Vauto_composition_mode,
doc: /* Non-nil if Auto-Composition mode is enabled.
-Use the command `auto-composition-mode' to change this variable. */);
+Use the command `auto-composition-mode' to change this variable.
+
+If this variable is a string, `auto-composition-mode' will be disabled in
+buffers displayed on a terminal whose type, as reported by `tty-type',
+compares equal to that string. */);
Vauto_composition_mode = Qt;
DEFVAR_LISP ("auto-composition-function", Vauto_composition_function,
doc: /* Function to call to compose characters automatically.
-This function is called from the display routine with four arguments:
-FROM, TO, WINDOW, and STRING.
+This function is called from the display engine with 6 arguments:
+FUNC, FROM, TO, FONT-OBJECT, STRING, and DIRECTION.
+
+FUNC is the function to compose characters. On text-mode display,
+FUNC is ignored and `compose-gstring-for-terminal' is used instead.
If STRING is nil, the function must compose characters in the region
between FROM and TO in the current buffer.
Otherwise, STRING is a string, and FROM and TO are indices into the
string. In this case, the function must compose characters in the
-string. */);
+string.
+
+FONT-OBJECT is the font to use, or nil if characters are to be
+composed on a text-mode display.
+
+DIRECTION is the bidi directionality of the text to shape. It could
+be L2R or R2L, or nil if unknown. */);
Vauto_composition_function = Qnil;
DEFVAR_LISP ("composition-function-table", Vcomposition_function_table,
@@ -1952,7 +2192,9 @@ preceding and/or following characters, this char-table contains
a function to call to compose that character.
The element at index C in the table, if non-nil, is a list of
-composition rules of this form: ([PATTERN PREV-CHARS FUNC] ...)
+composition rules of the form ([PATTERN PREV-CHARS FUNC] ...);
+the rules must be specified in the descending order of PREV-CHARS
+values.
PATTERN is a regular expression which C and the surrounding
characters must match.
@@ -1978,8 +2220,21 @@ GSTRING, or modify GSTRING itself and return it.
See also the documentation of `auto-composition-mode'. */);
Vcomposition_function_table = Fmake_char_table (Qnil, Qnil);
+ DEFVAR_LISP ("auto-composition-emoji-eligible-codepoints", Vauto_composition_emoji_eligible_codepoints,
+ doc: /* List of codepoints for which auto-composition will check for an emoji font.
+
+These are codepoints which have Emoji_Presentation = No, and thus by
+default are not displayed as emoji. In certain circumstances, such as
+when followed by U+FE0F (VS-16) the emoji font should be used for
+them anyway.
+
+This list is auto-generated, you should not need to modify it. */);
+ Vauto_composition_emoji_eligible_codepoints = Qnil;
+
defsubr (&Scompose_region_internal);
defsubr (&Scompose_string_internal);
defsubr (&Sfind_composition_internal);
defsubr (&Scomposition_get_gstring);
+ defsubr (&Sclear_composition_cache);
+ defsubr (&Scomposition_sort_rules);
}