1 /* Composite sequence support.
2 Copyright (C) 2001, 2002, 2003, 2004, 2005,
3 2006, 2007 Free Software Foundation, Inc.
4 Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007
5 National Institute of Advanced Industrial Science and Technology (AIST)
6 Registration Number H14PRO021
8 This file is part of GNU Emacs.
10 GNU Emacs is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 2, or (at your option)
15 GNU Emacs is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
20 You should have received a copy of the GNU General Public License
21 along with GNU Emacs; see the file COPYING. If not, write to
22 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
23 Boston, MA 02110-1301, USA. */
29 #include "intervals.h"
31 /* Emacs uses special text property `composition' to support character
32 composition. A sequence of characters that have the same (i.e. eq)
33 `composition' property value is treated as a single composite
34 sequence (we call it just `composition' here after). Characters in
35 a composition are all composed somehow on the screen.
37 The property value has this form when the composition is made:
38 ((LENGTH . COMPONENTS) . MODIFICATION-FUNC)
39 then turns to this form:
40 (COMPOSITION-ID . (LENGTH COMPONENTS-VEC . MODIFICATION-FUNC))
41 when the composition is registered in composition_hash_table and
42 composition_table. These rather peculiar structures were designed
43 to make it easy to distinguish them quickly (we can do that by
44 checking only the first element) and to extract LENGTH (from the
45 former form) and COMPOSITION-ID (from the latter form).
47 We register a composition when it is displayed, or when the width
48 is required (for instance, to calculate columns).
50 LENGTH -- Length of the composition. This information is used to
51 check the validity of the composition.
53 COMPONENTS -- Character, string, vector, list, or nil.
55 If it is nil, characters in the text are composed relatively
56 according to their metrics in font glyphs.
58 If it is a character or a string, the character or characters
59 in the string are composed relatively.
61 If it is a vector or list of integers, the element is a
62 character or an encoded composition rule. The characters are
63 composed according to the rules. (2N)th elements are
64 characters to be composed and (2N+1)th elements are
65 composition rules to tell how to compose (2N+2)th element with
66 the previously composed 2N glyphs.
68 COMPONENTS-VEC -- Vector of integers. In relative composition, the
69 elements are characters to be composed. In rule-base
70 composition, the elements are characters or encoded
73 MODIFICATION-FUNC -- If non nil, it is a function to call when the
74 composition gets invalid after a modification in a buffer. If
75 it is nil, a function in `composition-function-table' of the
76 first character in the sequence is called.
78 COMPOSITION-ID --Identification number of the composition. It is
79 used as an index to composition_table for the composition.
81 When Emacs has to display a composition or has to know its
82 displaying width, the function get_composition_id is called. It
83 returns COMPOSITION-ID so that the caller can access the
84 information about the composition through composition_table. If a
85 COMPOSITION-ID has not yet been assigned to the composition,
86 get_composition_id checks the validity of `composition' property,
87 and, if valid, assigns a new ID, registers the information in
88 composition_hash_table and composition_table, and changes the form
89 of the property value. If the property is invalid, return -1
90 without changing the property value.
92 We use two tables to keep information about composition;
93 composition_hash_table and composition_table.
95 The former is a hash table in which keys are COMPONENTS-VECs and
96 values are the corresponding COMPOSITION-IDs. This hash table is
97 weak, but as each key (COMPONENTS-VEC) is also kept as a value of the
98 `composition' property, it won't be collected as garbage until all
99 bits of text that have the same COMPONENTS-VEC are deleted.
101 The latter is a table of pointers to `struct composition' indexed
102 by COMPOSITION-ID. This structure keeps the other information (see
105 In general, a text property holds information about individual
106 characters. But, a `composition' property holds information about
107 a sequence of characters (in this sense, it is like the `intangible'
108 property). That means that we should not share the property value
109 in adjacent compositions -- we can't distinguish them if they have the
110 same property. So, after any changes, we call
111 `update_compositions' and change a property of one of adjacent
112 compositions to a copy of it. This function also runs a proper
113 composition modification function to make a composition that gets
114 invalid by the change valid again.
116 As the value of the `composition' property holds information about a
117 specific range of text, the value gets invalid if we change the
118 text in the range. We treat the `composition' property as always
119 rear-nonsticky (currently by setting default-text-properties to
120 (rear-nonsticky (composition))) and we never make properties of
121 adjacent compositions identical. Thus, any such changes make the
122 range just shorter. So, we can check the validity of the `composition'
123 property by comparing LENGTH information with the actual length of
129 Lisp_Object Qcomposition
;
131 /* Table of pointers to the structure `composition' indexed by
132 COMPOSITION-ID. This structure is for storing information about
133 each composition except for COMPONENTS-VEC. */
134 struct composition
**composition_table
;
136 /* The current size of `composition_table'. */
137 static int composition_table_size
;
139 /* Number of compositions currently made. */
142 /* Hash table for compositions. The key is COMPONENTS-VEC of
143 `composition' property. The value is the corresponding
145 Lisp_Object composition_hash_table
;
147 /* Function to call to adjust composition. */
148 Lisp_Object Vcompose_chars_after_function
;
150 /* Char-table of patterns and functions to make a composition. */
151 Lisp_Object Vcomposition_function_table
;
152 Lisp_Object Qcomposition_function_table
;
154 /* Temporary variable used in macros COMPOSITION_XXX. */
155 Lisp_Object composition_temp
;
157 /* Return how many columns C will occupy on the screen. It always
158 returns 1 for control characters and 8-bit characters because those
159 are just ignored in a composition. */
160 #define CHAR_WIDTH(c) \
161 (SINGLE_BYTE_CHAR_P (c) ? 1 : CHARSET_WIDTH (CHAR_CHARSET (c)))
163 /* Return COMPOSITION-ID of a composition at buffer position
164 CHARPOS/BYTEPOS and length NCHARS. The `composition' property of
165 the sequence is PROP. STRING, if non-nil, is a string that
166 contains the composition instead of the current buffer.
168 If the composition is invalid, return -1. */
171 get_composition_id (charpos
, bytepos
, nchars
, prop
, string
)
172 int charpos
, bytepos
, nchars
;
173 Lisp_Object prop
, string
;
175 Lisp_Object id
, length
, components
, key
, *key_contents
;
177 struct Lisp_Hash_Table
*hash_table
= XHASH_TABLE (composition_hash_table
);
180 struct composition
*cmp
;
184 Form-A: ((LENGTH . COMPONENTS) . MODIFICATION-FUNC)
186 Form-B: (COMPOSITION-ID . (LENGTH COMPONENTS-VEC . MODIFICATION-FUNC))
188 if (nchars
== 0 || !CONSP (prop
))
189 goto invalid_composition
;
194 /* PROP should be Form-B. */
195 if (XINT (id
) < 0 || XINT (id
) >= n_compositions
)
196 goto invalid_composition
;
200 /* PROP should be Form-A.
201 Thus, ID should be (LENGTH . COMPONENTS). */
203 goto invalid_composition
;
205 if (!INTEGERP (length
) || XINT (length
) != nchars
)
206 goto invalid_composition
;
208 components
= XCDR (id
);
210 /* Check if the same composition has already been registered or not
211 by consulting composition_hash_table. The key for this table is
212 COMPONENTS (converted to a vector COMPONENTS-VEC) or, if it is
213 nil, vector of characters in the composition range. */
214 if (INTEGERP (components
))
215 key
= Fmake_vector (make_number (1), components
);
216 else if (STRINGP (components
) || CONSP (components
))
217 key
= Fvconcat (1, &components
);
218 else if (VECTORP (components
))
220 else if (NILP (components
))
222 key
= Fmake_vector (make_number (nchars
), Qnil
);
223 if (STRINGP (string
))
224 for (i
= 0; i
< nchars
; i
++)
226 FETCH_STRING_CHAR_ADVANCE (ch
, string
, charpos
, bytepos
);
227 XVECTOR (key
)->contents
[i
] = make_number (ch
);
230 for (i
= 0; i
< nchars
; i
++)
232 FETCH_CHAR_ADVANCE (ch
, charpos
, bytepos
);
233 XVECTOR (key
)->contents
[i
] = make_number (ch
);
237 goto invalid_composition
;
239 hash_index
= hash_lookup (hash_table
, key
, &hash_code
);
242 /* We have already registered the same composition. Change PROP
243 from Form-A above to Form-B while replacing COMPONENTS with
244 COMPONENTS-VEC stored in the hash table. We can directly
245 modify the cons cell of PROP because it is not shared. */
246 key
= HASH_KEY (hash_table
, hash_index
);
247 id
= HASH_VALUE (hash_table
, hash_index
);
249 XSETCDR (prop
, Fcons (make_number (nchars
), Fcons (key
, XCDR (prop
))));
253 /* This composition is a new one. We must register it. */
255 /* Check if we have sufficient memory to store this information. */
256 if (composition_table_size
== 0)
258 composition_table_size
= 256;
260 = (struct composition
**) xmalloc (sizeof (composition_table
[0])
261 * composition_table_size
);
263 else if (composition_table_size
<= n_compositions
)
265 composition_table_size
+= 256;
267 = (struct composition
**) xrealloc (composition_table
,
268 sizeof (composition_table
[0])
269 * composition_table_size
);
272 key_contents
= XVECTOR (key
)->contents
;
274 /* Check if the contents of COMPONENTS are valid if COMPONENTS is a
275 vector or a list. It should be a sequence of:
276 char1 rule1 char2 rule2 char3 ... ruleN charN+1 */
277 if (VECTORP (components
) || CONSP (components
))
279 int len
= XVECTOR (key
)->size
;
281 /* The number of elements should be odd. */
283 goto invalid_composition
;
284 /* All elements should be integers (character or encoded
285 composition rule). */
286 for (i
= 0; i
< len
; i
++)
288 if (!INTEGERP (key_contents
[i
]))
289 goto invalid_composition
;
293 /* Change PROP from Form-A above to Form-B. We can directly modify
294 the cons cell of PROP because it is not shared. */
295 XSETFASTINT (id
, n_compositions
);
297 XSETCDR (prop
, Fcons (make_number (nchars
), Fcons (key
, XCDR (prop
))));
299 /* Register the composition in composition_hash_table. */
300 hash_index
= hash_put (hash_table
, key
, id
, hash_code
);
302 /* Register the composition in composition_table. */
303 cmp
= (struct composition
*) xmalloc (sizeof (struct composition
));
305 cmp
->method
= (NILP (components
)
306 ? COMPOSITION_RELATIVE
307 : ((INTEGERP (components
) || STRINGP (components
))
308 ? COMPOSITION_WITH_ALTCHARS
309 : COMPOSITION_WITH_RULE_ALTCHARS
));
310 cmp
->hash_index
= hash_index
;
311 glyph_len
= (cmp
->method
== COMPOSITION_WITH_RULE_ALTCHARS
312 ? (XVECTOR (key
)->size
+ 1) / 2
313 : XVECTOR (key
)->size
);
314 cmp
->glyph_len
= glyph_len
;
315 cmp
->offsets
= (short *) xmalloc (sizeof (short) * glyph_len
* 2);
318 /* Calculate the width of overall glyphs of the composition. */
319 if (cmp
->method
!= COMPOSITION_WITH_RULE_ALTCHARS
)
321 /* Relative composition. */
323 for (i
= 0; i
< glyph_len
; i
++)
326 ch
= XINT (key_contents
[i
]);
327 this_width
= CHAR_WIDTH (ch
);
328 if (cmp
->width
< this_width
)
329 cmp
->width
= this_width
;
334 /* Rule-base composition. */
335 float leftmost
= 0.0, rightmost
;
337 ch
= XINT (key_contents
[0]);
338 rightmost
= CHAR_WIDTH (ch
);
340 for (i
= 1; i
< glyph_len
; i
+= 2)
342 int rule
, gref
, nref
;
346 rule
= XINT (key_contents
[i
]);
347 ch
= XINT (key_contents
[i
+ 1]);
348 this_width
= CHAR_WIDTH (ch
);
350 /* A composition rule is specified by an integer value
351 that encodes global and new reference points (GREF and
352 NREF). GREF and NREF are specified by numbers as
360 ---3---4---5--- baseline
364 COMPOSITION_DECODE_RULE (rule
, gref
, nref
);
365 this_left
= (leftmost
366 + (gref
% 3) * (rightmost
- leftmost
) / 2.0
367 - (nref
% 3) * this_width
/ 2.0);
369 if (this_left
< leftmost
)
370 leftmost
= this_left
;
371 if (this_left
+ this_width
> rightmost
)
372 rightmost
= this_left
+ this_width
;
375 cmp
->width
= rightmost
- leftmost
;
376 if (cmp
->width
< (rightmost
- leftmost
))
377 /* To get a ceiling integer value. */
381 composition_table
[n_compositions
] = cmp
;
383 return n_compositions
++;
386 /* Would it be better to remove this `composition' property? */
391 /* Find a composition at or nearest to position POS of OBJECT (buffer
394 OBJECT defaults to the current buffer. If there's a composition at
395 POS, set *START and *END to the start and end of the sequence,
396 *PROP to the `composition' property, and return 1.
398 If there's no composition at POS and LIMIT is negative, return 0.
400 Otherwise, search for a composition forward (LIMIT > POS) or
401 backward (LIMIT < POS). In this case, LIMIT bounds the search.
403 If a composition is found, set *START, *END, and *PROP as above,
404 and return 1, else return 0.
406 This doesn't check the validity of composition. */
409 find_composition (pos
, limit
, start
, end
, prop
, object
)
410 int pos
, limit
, *start
, *end
;
411 Lisp_Object
*prop
, object
;
415 if (get_property_and_range (pos
, Qcomposition
, prop
, start
, end
, object
))
418 if (limit
< 0 || limit
== pos
)
421 if (limit
> pos
) /* search forward */
423 val
= Fnext_single_property_change (make_number (pos
), Qcomposition
,
424 object
, make_number (limit
));
429 else /* search backward */
431 if (get_property_and_range (pos
- 1, Qcomposition
, prop
, start
, end
,
434 val
= Fprevious_single_property_change (make_number (pos
), Qcomposition
,
435 object
, make_number (limit
));
441 get_property_and_range (pos
, Qcomposition
, prop
, start
, end
, object
);
445 /* Run a proper function to adjust the composition sitting between
446 FROM and TO with property PROP. */
449 run_composition_function (from
, to
, prop
)
456 func
= COMPOSITION_MODIFICATION_FUNC (prop
);
457 /* If an invalid composition precedes or follows, try to make them
460 && find_composition (from
- 1, -1, &start
, &end
, &prop
, Qnil
)
461 && !COMPOSITION_VALID_P (start
, end
, prop
))
464 && find_composition (to
, -1, &start
, &end
, &prop
, Qnil
)
465 && !COMPOSITION_VALID_P (start
, end
, prop
))
467 if (!NILP (Ffboundp (func
)))
468 call2 (func
, make_number (from
), make_number (to
));
469 else if (!NILP (Ffboundp (Vcompose_chars_after_function
)))
470 call3 (Vcompose_chars_after_function
,
471 make_number (from
), make_number (to
), Qnil
);
474 /* Make invalid compositions adjacent to or inside FROM and TO valid.
475 CHECK_MASK is bitwise `or' of mask bits defined by macros
476 CHECK_XXX (see the comment in composite.h).
478 This function is called when a buffer text is changed. If the
479 change is deletion, FROM == TO. Otherwise, FROM < TO. */
482 update_compositions (from
, to
, check_mask
)
483 int from
, to
, check_mask
;
488 if (inhibit_modification_hooks
)
491 /* If FROM and TO are not in a valid range, do nothing. */
492 if (! (BEGV
<= from
&& from
<= to
&& to
<= ZV
))
495 if (check_mask
& CHECK_HEAD
)
497 /* FROM should be at composition boundary. But, insertion or
498 deletion will make two compositions adjacent and
499 indistinguishable when they have same (eq) property. To
500 avoid it, in such a case, we change the property of the
501 latter to the copy of it. */
503 && find_composition (from
- 1, -1, &start
, &end
, &prop
, Qnil
))
506 Fput_text_property (make_number (from
), make_number (end
),
508 Fcons (XCAR (prop
), XCDR (prop
)), Qnil
);
509 run_composition_function (start
, end
, prop
);
513 && find_composition (from
, -1, &start
, &from
, &prop
, Qnil
))
514 run_composition_function (start
, from
, prop
);
517 if (check_mask
& CHECK_INSIDE
)
519 /* In this case, we are sure that (check & CHECK_TAIL) is also
520 nonzero. Thus, here we should check only compositions before
523 && find_composition (from
, to
, &start
, &from
, &prop
, Qnil
)
525 run_composition_function (start
, from
, prop
);
528 if (check_mask
& CHECK_TAIL
)
531 && find_composition (to
- 1, -1, &start
, &end
, &prop
, Qnil
))
533 /* TO should be also at composition boundary. But,
534 insertion or deletion will make two compositions adjacent
535 and indistinguishable when they have same (eq) property.
536 To avoid it, in such a case, we change the property of
537 the former to the copy of it. */
539 Fput_text_property (make_number (start
), make_number (to
),
541 Fcons (XCAR (prop
), XCDR (prop
)), Qnil
);
542 run_composition_function (start
, end
, prop
);
545 && find_composition (to
, -1, &start
, &end
, &prop
, Qnil
))
546 run_composition_function (start
, end
, prop
);
551 /* Modify composition property values in LIST destructively. LIST is
552 a list as returned from text_property_list. Change values to the
553 top-level copies of them so that none of them are `eq'. */
556 make_composition_value_copy (list
)
559 Lisp_Object plist
, val
;
561 for (; CONSP (list
); list
= XCDR (list
))
563 plist
= XCAR (XCDR (XCDR (XCAR (list
))));
564 while (CONSP (plist
) && CONSP (XCDR (plist
)))
566 if (EQ (XCAR (plist
), Qcomposition
)
567 && (val
= XCAR (XCDR (plist
)), CONSP (val
)))
568 XSETCAR (XCDR (plist
), Fcons (XCAR (val
), XCDR (val
)));
569 plist
= XCDR (XCDR (plist
));
575 /* Make text in the region between START and END a composition that
576 has COMPONENTS and MODIFICATION-FUNC.
578 If STRING is non-nil, then operate on characters contained between
579 indices START and END in STRING. */
582 compose_text (start
, end
, components
, modification_func
, string
)
584 Lisp_Object components
, modification_func
, string
;
588 prop
= Fcons (Fcons (make_number (end
- start
), components
),
590 Fput_text_property (make_number (start
), make_number (end
),
591 Qcomposition
, prop
, string
);
595 /* Emacs Lisp APIs. */
597 DEFUN ("compose-region-internal", Fcompose_region_internal
,
598 Scompose_region_internal
, 2, 4, 0,
599 doc
: /* Internal use only.
601 Compose text in the region between START and END.
602 Optional 3rd and 4th arguments are COMPONENTS and MODIFICATION-FUNC
603 for the composition. See `compose-region' for more detail. */)
604 (start
, end
, components
, modification_func
)
605 Lisp_Object start
, end
, components
, modification_func
;
607 validate_region (&start
, &end
);
608 if (!NILP (components
)
609 && !INTEGERP (components
)
610 && !CONSP (components
)
611 && !STRINGP (components
))
612 CHECK_VECTOR (components
);
614 compose_text (XINT (start
), XINT (end
), components
, modification_func
, Qnil
);
618 DEFUN ("compose-string-internal", Fcompose_string_internal
,
619 Scompose_string_internal
, 3, 5, 0,
620 doc
: /* Internal use only.
622 Compose text between indices START and END of STRING.
623 Optional 4th and 5th arguments are COMPONENTS and MODIFICATION-FUNC
624 for the composition. See `compose-string' for more detail. */)
625 (string
, start
, end
, components
, modification_func
)
626 Lisp_Object string
, start
, end
, components
, modification_func
;
628 CHECK_STRING (string
);
629 CHECK_NUMBER (start
);
632 if (XINT (start
) < 0 ||
633 XINT (start
) > XINT (end
)
634 || XINT (end
) > SCHARS (string
))
635 args_out_of_range (start
, end
);
637 compose_text (XINT (start
), XINT (end
), components
, modification_func
, string
);
641 DEFUN ("find-composition-internal", Ffind_composition_internal
,
642 Sfind_composition_internal
, 4, 4, 0,
643 doc
: /* Internal use only.
645 Return information about composition at or nearest to position POS.
646 See `find-composition' for more detail. */)
647 (pos
, limit
, string
, detail_p
)
648 Lisp_Object pos
, limit
, string
, detail_p
;
650 Lisp_Object prop
, tail
;
654 CHECK_NUMBER_COERCE_MARKER (pos
);
658 CHECK_NUMBER_COERCE_MARKER (limit
);
666 CHECK_STRING (string
);
667 if (XINT (pos
) < 0 || XINT (pos
) > SCHARS (string
))
668 args_out_of_range (string
, pos
);
672 if (XINT (pos
) < BEGV
|| XINT (pos
) > ZV
)
673 args_out_of_range (Fcurrent_buffer (), pos
);
676 if (!find_composition (start
, end
, &start
, &end
, &prop
, string
))
678 if (!COMPOSITION_VALID_P (start
, end
, prop
))
679 return Fcons (make_number (start
), Fcons (make_number (end
),
680 Fcons (Qnil
, Qnil
)));
682 return Fcons (make_number (start
), Fcons (make_number (end
),
685 if (COMPOSITION_REGISTERD_P (prop
))
686 id
= COMPOSITION_ID (prop
);
689 int start_byte
= (NILP (string
)
690 ? CHAR_TO_BYTE (start
)
691 : string_char_to_byte (string
, start
));
692 id
= get_composition_id (start
, start_byte
, end
- start
, prop
, string
);
697 Lisp_Object components
, relative_p
, mod_func
;
698 enum composition_method method
= COMPOSITION_METHOD (prop
);
699 int width
= composition_table
[id
]->width
;
701 components
= Fcopy_sequence (COMPOSITION_COMPONENTS (prop
));
702 relative_p
= (method
== COMPOSITION_WITH_RULE_ALTCHARS
704 mod_func
= COMPOSITION_MODIFICATION_FUNC (prop
);
705 tail
= Fcons (components
,
708 Fcons (make_number (width
), Qnil
))));
713 return Fcons (make_number (start
), Fcons (make_number (end
), tail
));
720 Qcomposition
= intern ("composition");
721 staticpro (&Qcomposition
);
723 /* Make a hash table for composition. */
726 extern Lisp_Object QCsize
;
730 /* We used to make the hash table weak so that unreferenced
731 compostions can be garbage-collected. But, usually once
732 created compositions are repeatedly used in an Emacs session,
733 and thus it's not worth to save memory in such a way. So, we
734 make the table not weak. */
735 args
[2] = QCweakness
;
738 args
[5] = make_number (311);
739 composition_hash_table
= Fmake_hash_table (6, args
);
740 staticpro (&composition_hash_table
);
743 /* Text property `composition' should be nonsticky by default. */
744 Vtext_property_default_nonsticky
745 = Fcons (Fcons (Qcomposition
, Qt
), Vtext_property_default_nonsticky
);
747 DEFVAR_LISP ("compose-chars-after-function", &Vcompose_chars_after_function
,
748 doc
: /* Function to adjust composition of buffer text.
750 The function is called with three arguments FROM, TO, and OBJECT.
751 FROM and TO specify the range of text of which composition should be
752 adjusted. OBJECT, if non-nil, is a string that contains the text.
754 This function is called after a text with `composition' property is
755 inserted or deleted to keep `composition' property of buffer text
758 The default value is the function `compose-chars-after'. */);
759 Vcompose_chars_after_function
= intern ("compose-chars-after");
761 Qcomposition_function_table
= intern ("composition-function-table");
762 staticpro (&Qcomposition_function_table
);
764 /* Intern this now in case it isn't already done.
765 Setting this variable twice is harmless.
766 But don't staticpro it here--that is done in alloc.c. */
767 Qchar_table_extra_slots
= intern ("char-table-extra-slots");
769 Fput (Qcomposition_function_table
, Qchar_table_extra_slots
, make_number (0));
771 DEFVAR_LISP ("composition-function-table", &Vcomposition_function_table
,
772 doc
: /* Char table of patterns and functions to make a composition.
774 Each element is nil or an alist of PATTERNs vs FUNCs, where PATTERNs
775 are regular expressions and FUNCs are functions. FUNC is responsible
776 for composing text matching the corresponding PATTERN. FUNC is called
777 with three arguments FROM, TO, and PATTERN. See the function
778 `compose-chars-after' for more detail.
780 This table is looked up by the first character of a composition when
781 the composition gets invalid after a change in a buffer. */);
782 Vcomposition_function_table
783 = Fmake_char_table (Qcomposition_function_table
, Qnil
);
785 defsubr (&Scompose_region_internal
);
786 defsubr (&Scompose_string_internal
);
787 defsubr (&Sfind_composition_internal
);
790 /* arch-tag: 79cefaf8-ca48-4eed-97e5-d5afb290d272
791 (do not change this comment) */