(update_compositions): If FROM and TO is not in a
[bpt/emacs.git] / src / composite.c
CommitLineData
ca4c9455
KH
1/* Composite sequence support.
2 Copyright (C) 1999 Electrotechnical Laboratory, JAPAN.
3 Licensed to the Free Software Foundation.
4
5This file is part of GNU Emacs.
6
7GNU Emacs is free software; you can redistribute it and/or modify
8it under the terms of the GNU General Public License as published by
9the Free Software Foundation; either version 2, or (at your option)
10any later version.
11
12GNU Emacs is distributed in the hope that it will be useful,
13but WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15GNU General Public License for more details.
16
17You should have received a copy of the GNU General Public License
18along with GNU Emacs; see the file COPYING. If not, write to
19the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20Boston, MA 02111-1307, USA. */
21
22#include <config.h>
23#include "lisp.h"
24#include "buffer.h"
25#include "charset.h"
26#include "intervals.h"
27
28/* Emacs uses special text property `composition' to support character
29 composition. A sequence of characters that have the same (i.e. eq)
30 `composition' property value is treated as a single composite
31 sequence (we call it just `composition' here after). Characters in
32 a composition are all composed somehow on the screen.
33
34 The property value has this form when the composition is made:
35 ((LENGTH . COMPONENTS) . MODIFICATION-FUNC)
36 then turns to this form:
37 (COMPOSITION-ID . (LENGTH COMPONENTS-VEC . MODIFICATION-FUNC))
38 when the composition is registered in composition_hash_table and
39 composition_table. These rather peculiar structures were designed
40 to make it easy to distinguish them quickly (we can do that by
41 checking only the first element) and to extract LENGTH (from the
42 former form) and COMPOSITION-ID (from the latter form).
43
44 We register a composition when it is displayed, or when the width
45 is required (for instance, to calculate columns).
46
47 LENGTH -- Length of the composition. This information is used to
48 check the validity of the composition.
49
50 COMPONENTS -- Character, string, vector, list, or nil.
51
52 If it is nil, characters in the text are composed relatively
53 according to their metrics in font glyphs.
54
55 If it is a character or a string, the character or characters
56 in the string are composed relatively.
57
58 If it is a vector or list of integers, the element is a
59 character or an encoded composition rule. The characters are
60 composed according to the rules. (2N)th elements are
61 characters to be composed and (2N+1)th elements are
62 composition rules to tell how to compose (2N+2)th element with
63 the previously composed 2N glyphs.
64
65 COMPONENTS-VEC -- Vector of integers. In relative composition, the
66 elements are characters to be composed. In rule-base
67 composition, the elements are characters or encoded
68 composition rules.
69
70 MODIFICATION-FUNC -- If non nil, it is a function to call when the
71 composition gets invalid after a modification in a buffer. If
72 it is nil, a function in `composition-function-table' of the
73 first character in the sequence is called.
74
75 COMPOSITION-ID --Identification number of the composition. It is
76 used as an index to composition_table for the composition.
77
78 When Emacs has to display a composition or has to know its
79 displaying width, the function get_composition_id is called. It
80 returns COMPOSITION-ID so that the caller can access the
81 information about the composition through composition_table. If a
82 COMPOSITION-ID has not yet been assigned to the composition,
83 get_composition_id checks the validity of `composition' property,
84 and, if valid, assigns a new ID, registers the information in
85 composition_hash_table and composition_table, and changes the form
86 of the property value. If the property is invalid, return -1
87 without changing the property value.
88
89 We use two tables to keep information about composition;
90 composition_hash_table and composition_table.
91
92 The former is a hash table in which keys are COMPONENTS-VECs and
93 values are the corresponding COMPOSITION-IDs. This hash table is
94 weak, but as each key (COMPONENTS-VEC) is also kept as a value of
95 `composition' property, it won't be collected as garbage until all
96 text that have the same COMPONENTS-VEC are deleted.
97
98 The latter is a table of pointers to `struct composition' indexed
99 by COMPOSITION-ID. This structure keep the other information (see
100 composite.h).
101
102 In general, a text property holds information about individual
103 characters. But, a `composition' property holds information about
104 a sequence of characters (in this sense, it is like `intangible'
105 property). That means that we should not share the property value
106 in adjacent compositions we can't distinguish them if they have the
107 same property. So, after any changes, we call
108 `update_compositions' and change a property of one of adjacent
109 compositions to a copy of it. This function also runs a proper
110 composition modification function to make a composition that gets
111 invalid by the change valid again.
112
113 As a value of `composition' property holds information about a
114 specific range of text, the value gets invalid if we change the
115 text in the range. We treat `composition' property always
116 rear-nonsticky (currently by setting default-text-properties to
117 (rear-nonsticky (composition))) and we never make properties of
118 adjacent compositions identical. Thus, any such changes make the
119 range just shorter. So, we can check the validity of `composition'
120 property by comparing LENGTH information with the actual length of
121 the composition.
122
123*/
124
125
126Lisp_Object Qcomposition;
127
128/* Table of pointers to the structure `composition' indexed by
129 COMPOSITION-ID. This structure is for storing information about
130 each composition except for COMPONENTS-VEC. */
131struct composition **composition_table;
132
133/* The current size of `composition_table'. */
134static int composition_table_size;
135
136/* Number of compositions currently made. */
137int n_compositions;
138
139/* Hash table for compositions. The key is COMPONENTS-VEC of
140 `composition' property. The value is the corresponding
141 COMPOSITION-ID. */
142Lisp_Object composition_hash_table;
143
144/* Function to call to adjust composition. */
145Lisp_Object Vcompose_chars_after_function;
146
147/* Temporary variable used in macros COMPOSITION_XXX. */
148Lisp_Object composition_temp;
149\f
150/* Return how many columns C will occupy on the screen. It always
151 returns 1 for control characters and 8-bit characters because those
152 are just ignored in a composition. */
153#define CHAR_WIDTH(c) \
154 (SINGLE_BYTE_CHAR_P (c) ? 1 : CHARSET_WIDTH (CHAR_CHARSET (c)))
155
156/* The following macros for hash table are copied from fns.c. */
157/* Return the contents of vector V at index IDX. */
158#define AREF(V, IDX) XVECTOR (V)->contents[IDX]
159/* Value is the key part of entry IDX in hash table H. */
160#define HASH_KEY(H, IDX) AREF ((H)->key_and_value, 2 * (IDX))
161/* Value is the value part of entry IDX in hash table H. */
162#define HASH_VALUE(H, IDX) AREF ((H)->key_and_value, 2 * (IDX) + 1)
163
164/* Return COMPOSITION-ID of a composition at buffer position
165 CHARPOS/BYTEPOS and length NCHARS. The `composition' property of
166 the sequence is PROP. STRING, if non-nil, is a string that
167 contains the composition instead of the current buffer.
168
169 If the composition is invalid, return -1. */
170
171int
172get_composition_id (charpos, bytepos, nchars, prop, string)
173 int charpos, bytepos, nchars;
174 Lisp_Object prop, string;
175{
176 Lisp_Object id, length, components, key, *key_contents;
177 int glyph_len;
178 struct Lisp_Hash_Table *hash_table = XHASH_TABLE (composition_hash_table);
179 int hash_index;
180 unsigned hash_code;
181 struct composition *cmp;
182 int i, ch;
183
184 /* PROP should be
185 Form-A: ((LENGTH . COMPONENTS) . MODIFICATION-FUNC)
186 or
187 Form-B: (COMPOSITION-ID . (LENGTH COMPONENTS-VEC . MODIFICATION-FUNC))
188 */
189 if (nchars == 0 || !CONSP (prop))
190 goto invalid_composition;
191
192 id = XCAR (prop);
193 if (INTEGERP (id))
194 {
195 /* PROP should be Form-B. */
196 if (XINT (id) < 0 || XINT (id) >= n_compositions)
197 goto invalid_composition;
198 return XINT (id);
199 }
200
201 /* PROP should be Form-A.
202 Thus, ID should be (LENGTH . COMPONENTS). */
203 if (!CONSP (id))
204 goto invalid_composition;
205 length = XCAR (id);
206 if (!INTEGERP (length) || XINT (length) != nchars)
207 goto invalid_composition;
208
209 components = XCDR (id);
210
211 /* Check if the same composition has already been registered or not
212 by consulting composition_hash_table. The key for this table is
213 COMPONENTS (converted to a vector COMPONENTS-VEC) or, if it is
214 nil, vector of characters in the composition range. */
215 if (INTEGERP (components))
216 key = Fmake_vector (make_number (1), components);
217 else if (STRINGP (components) || CONSP (components))
218 key = Fvconcat (1, &components);
219 else if (VECTORP (components))
220 key = components;
221 else if (NILP (components))
222 {
223 key = Fmake_vector (make_number (nchars), Qnil);
224 if (STRINGP (string))
225 for (i = 0; i < nchars; i++)
226 {
227 FETCH_STRING_CHAR_ADVANCE (ch, string, charpos, bytepos);
228 XVECTOR (key)->contents[i] = make_number (ch);
229 }
230 else
231 for (i = 0; i < nchars; i++)
232 {
233 FETCH_CHAR_ADVANCE (ch, charpos, bytepos);
234 XVECTOR (key)->contents[i] = make_number (ch);
235 }
236 }
237 else
238 goto invalid_composition;
239
240 hash_index = hash_lookup (hash_table, key, &hash_code);
241 if (hash_index >= 0)
242 {
243 /* We have already registered the same composition. Change PROP
244 from Form-A above to Form-B while replacing COMPONENTS with
245 COMPONENTS-VEC stored in the hash table. We can directly
246 modify the cons cell of PROP because it is not shared. */
247 key = HASH_KEY (hash_table, hash_index);
248 id = HASH_VALUE (hash_table, hash_index);
249 XCAR (prop) = id;
250 XCDR (prop) = Fcons (make_number (nchars), Fcons (key, XCDR (prop)));
251 return XINT (id);
252 }
253
254 /* This composition is a new one. We must register it. */
255
256 /* Check if we have sufficient memory to store this information. */
257 if (composition_table_size == 0)
258 {
259 composition_table_size = 256;
260 composition_table
261 = (struct composition **) xmalloc (sizeof (composition_table[0])
262 * composition_table_size);
263 }
264 else if (composition_table_size <= n_compositions)
265 {
266 composition_table_size += 256;
267 composition_table
268 = (struct composition **) xrealloc (composition_table,
269 sizeof (composition_table[0])
270 * composition_table_size);
271 }
272
273 key_contents = XVECTOR (key)->contents;
274
275 /* Check if the contents of COMPONENTS are valid if COMPONENTS is a
276 vector or a list. It should be a sequence of:
277 char1 rule1 char2 rule2 char3 ... ruleN charN+1 */
278 if (VECTORP (components) || CONSP (components))
279 {
280 int len = XVECTOR (key)->size;
281
282 /* The number of elements should be odd. */
283 if ((len % 2) == 0)
284 goto invalid_composition;
285 /* All elements should be integers (character or encoded
286 composition rule). */
287 for (i = 0; i < len; i++)
288 {
289 if (!INTEGERP (key_contents[i]))
290 goto invalid_composition;
291 }
292 }
293
294 /* Change PROP from Form-A above to Form-B. We can directly modify
295 the cons cell of PROP because it is not shared. */
296 XSETFASTINT (id, n_compositions);
297 XCAR (prop) = id;
298 XCDR (prop) = Fcons (make_number (nchars), Fcons (key, XCDR (prop)));
299
300 /* Register the composition in composition_hash_table. */
301 hash_index = hash_put (hash_table, key, id, hash_code);
302
303 /* Register the composition in composition_table. */
304 cmp = (struct composition *) xmalloc (sizeof (struct composition));
305
306 cmp->method = (NILP (components)
307 ? COMPOSITION_RELATIVE
308 : ((INTEGERP (components) || STRINGP (components))
309 ? COMPOSITION_WITH_ALTCHARS
310 : COMPOSITION_WITH_RULE_ALTCHARS));
311 cmp->hash_index = hash_index;
312 glyph_len = (cmp->method == COMPOSITION_WITH_RULE_ALTCHARS
313 ? (XVECTOR (key)->size + 1) / 2
314 : XVECTOR (key)->size);
315 cmp->glyph_len = glyph_len;
316 cmp->offsets = (short *) xmalloc (sizeof (short) * glyph_len * 2);
317 cmp->font = NULL;
318
319 /* Calculate the width of overall glyphs of the composition. */
320 if (cmp->method != COMPOSITION_WITH_RULE_ALTCHARS)
321 {
322 /* Relative composition. */
323 cmp->width = 0;
324 for (i = 0; i < glyph_len; i++)
325 {
326 int this_width;
327 ch = XINT (key_contents[i]);
328 this_width = CHAR_WIDTH (ch);
329 if (cmp->width < this_width)
330 cmp->width = this_width;
331 }
332 }
333 else
334 {
335 /* Rule-base composition. */
336 float leftmost = 0.0, rightmost;
337
338 ch = XINT (key_contents[0]);
339 rightmost = CHAR_WIDTH (ch);
340
341 for (i = 1; i < glyph_len; i += 2)
342 {
343 int rule, gref, nref;
344 int this_width;
345 float this_left;
346
347 rule = XINT (key_contents[i]);
348 ch = XINT (key_contents[i + 1]);
349 this_width = CHAR_WIDTH (ch);
350
351 /* A composition rule is specified by an integer value
352 that encodes global and new reference points (GREF and
353 NREF). GREF and NREF are specified by numbers as
354 below:
355 0---1---2 -- ascent
356 | |
357 | |
358 | |
359 9--10--11 -- center
360 | |
361 ---3---4---5--- baseline
362 | |
363 6---7---8 -- descent
364 */
365 COMPOSITION_DECODE_RULE (rule, gref, nref);
366 this_left = (leftmost
367 + (gref % 3) * (rightmost - leftmost) / 2.0
368 - (nref % 3) * this_width / 2.0);
369
370 if (this_left < leftmost)
371 leftmost = this_left;
372 if (this_left + this_width > rightmost)
373 rightmost = this_left + this_width;
374 }
375
376 cmp->width = rightmost - leftmost;
377 if (cmp->width < (rightmost - leftmost))
378 /* To get a ceiling integer value. */
379 cmp->width++;
380 }
381
382 composition_table[n_compositions] = cmp;
383
384 return n_compositions++;
385
386 invalid_composition:
387 /* Would it be better to remove this `composition' property? */
388 return -1;
389}
390
391\f
392/* Find a composition at or nearest to position POS of OBJECT (buffer
393 or string).
394
395 OBJECT defaults to the current buffer. If there's a composition at
396 POS, set *START and *END to the start and end of the sequence,
397 *PROP to the `composition' property, and return 1.
398
399 If there's no composition at POS and LIMIT is negative, return 0.
400
401 Otherwise, search for a composition forward (LIMIT > POS) or
402 backward (LIMIT < POS). In this case, LIMIT bounds the search.
403
404 If a composition is found, set *START, *END, and *PROP as above,
405 and return 1, else return 0.
406
407 This doesn't check the validity of composition. */
408
409int
410find_composition (pos, limit, start, end, prop, object)
411 int pos, limit, *start, *end;
412 Lisp_Object *prop, object;
413{
414 Lisp_Object val;
415
416 if (get_property_and_range (pos, Qcomposition, prop, start, end, object))
417 return 1;
418
419 if (limit < 0 || limit == pos)
420 return 0;
421
422 if (limit > pos) /* search forward */
423 val = Fnext_single_property_change (make_number (pos), Qcomposition,
424 object, make_number (limit));
425 else /* search backward */
426 val = Fprevious_single_property_change (make_number (pos), Qcomposition,
427 object, make_number (limit));
428 pos = XINT (val);
429 if (pos == limit)
430 return 0;
431 get_property_and_range (pos, Qcomposition, prop, start, end, object);
432 return 1;
433}
434
435/* Run a proper function to adjust the composition sitting between
436 FROM and TO with property PROP. */
437
438static void
439run_composition_function (from, to, prop)
440 int from, to;
441 Lisp_Object prop;
442{
443 Lisp_Object func, val;
444 int start, end;
445
446 func = COMPOSITION_MODIFICATION_FUNC (prop);
447 /* If an invalid composition precedes or follows, try to make them
448 valid too. */
449 if (from > BEGV
450 && find_composition (from - 1, -1, &start, &end, &prop, Qnil)
451 && !COMPOSITION_VALID_P (start, end, prop))
452 from = start;
453 if (to < ZV
454 && find_composition (to, -1, &start, &end, &prop, Qnil)
455 && !COMPOSITION_VALID_P (start, end, prop))
456 to = end;
457 if (!NILP (func))
458 call2 (func, make_number (from), make_number (to));
09654086 459 else if (!NILP (Ffboundp (Vcompose_chars_after_function)))
ca4c9455
KH
460 call2 (Vcompose_chars_after_function,
461 make_number (from), make_number (to));
462}
463
464/* Make invalid compositions adjacent to or inside FROM and TO valid.
465 CHECK_MASK is bitwise `or' of mask bits defined by macros
466 CHECK_XXX (see the comment in composite.h).
467
468 This function is called when a buffer text is changed. If the
469 change is deletion, FROM == TO. Otherwise, FROM < TO. */
470
471void
472update_compositions (from, to, check_mask)
473 int from, to;
474{
475 Lisp_Object prop, hook;
476 int start, end;
477
d3f40cbd
KH
478 /* If FROM and TO are not in a valid range, do nothing. */
479 if (! (BEGV <= from && from <= to && to <= ZV))
480 return;
481
ca4c9455
KH
482 if (check_mask & CHECK_HEAD)
483 {
484 /* FROM should be at composition boundary. But, insertion or
485 deletion will make two compositions adjacent and
486 indistinguishable when they have same (eq) property. To
487 avoid it, in such a case, we change the property of the
488 latter to the copy of it. */
489 if (from > BEGV
490 && find_composition (from - 1, -1, &start, &end, &prop, Qnil))
491 {
492 if (from < end)
493 Fput_text_property (make_number (from), make_number (end),
494 Qcomposition,
495 Fcons (XCAR (prop), XCDR (prop)), Qnil);
496 run_composition_function (start, end, prop);
497 from = end;
498 }
499 else if (from < end
500 && find_composition (from, -1, &start, &from, &prop, Qnil))
501 run_composition_function (start, from, prop);
502 }
503
504 if (check_mask & CHECK_INSIDE)
505 {
506 /* In this case, we are sure that (check & CHECK_TAIL) is also
507 nonzero. Thus, here we should check only compositions before
508 (to - 1). */
509 while (from < to - 1
510 && find_composition (from, to, &start, &from, &prop, Qnil)
511 && from < to - 1)
512 run_composition_function (start, from, prop);
513 }
514
515 if (check_mask & CHECK_TAIL)
516 {
517 if (from < to
518 && find_composition (to - 1, -1, &start, &end, &prop, Qnil))
519 {
520 /* TO should be also at composition boundary. But,
521 insertion or deletion will make two compositions adjacent
522 and indistinguishable when they have same (eq) property.
523 To avoid it, in such a case, we change the property of
524 the former to the copy of it. */
525 if (to < end)
526 Fput_text_property (make_number (start), make_number (to),
527 Qcomposition,
528 Fcons (XCAR (prop), XCDR (prop)), Qnil);
529 run_composition_function (start, end, prop);
530 }
531 else if (to < ZV
532 && find_composition (to, -1, &start, &end, &prop, Qnil))
533 run_composition_function (start, end, prop);
534 }
535}
536
537/* Make text in the region between START and END a composition that
538 has COMPONENTS and MODIFICATION-FUNC.
539
540 If STRING is non-nil, then operate on characters contained between
541 indices START and END in STRING. */
542
543void
544compose_text (start, end, components, modification_func, string)
545 int start, end;
546 Lisp_Object components, modification_func, string;
547{
548 Lisp_Object prop;
549
550 prop = Fcons (Fcons (make_number (end - start), components),
551 modification_func);
552 Fput_text_property (make_number (start), make_number (end),
553 Qcomposition, prop, string);
554}
555
556\f
557/* Emacs Lisp APIs. */
558
559DEFUN ("compose-region-internal", Fcompose_region_internal,
560 Scompose_region_internal, 2, 4, 0,
561 "Internal use only.\n\
562\n\
563Compose text in the region between START and END.\n\
564Optional 3rd and 4th arguments are COMPONENTS and MODIFICATION-FUNC\n\
565for the composition. See `compose-region' for more detial.")
566 (start, end, components, mod_func)
567 Lisp_Object start, end, components, mod_func;
568{
569 validate_region (&start, &end);
570 if (!NILP (components)
571 && !INTEGERP (components)
572 && !CONSP (components)
573 && !STRINGP (components))
574 CHECK_VECTOR (components, 2);
575
576 compose_text (XINT (start), XINT (end), components, mod_func, Qnil);
577 return Qnil;
578}
579
580DEFUN ("compose-string-internal", Fcompose_string_internal,
581 Scompose_string_internal, 3, 5, 0,
582 "Internal use only.\n\
583\n\
584Compose text between indices START and END of STRING.\n\
585Optional 4th and 5th arguments are COMPONENTS and MODIFICATION-FUNC\n\
586for the composition. See `compose-string' for more detial.")
587 (string, start, end, components, mod_func)
588 Lisp_Object string, start, end, components, mod_func;
589{
590 CHECK_STRING (string, 0);
591 CHECK_NUMBER (start, 1);
592 CHECK_NUMBER (end, 2);
593
594 if (XINT (start) < 0 ||
595 XINT (start) > XINT (end)
596 || XINT (end) > XSTRING (string)->size)
597 args_out_of_range (start, end);
598
599 compose_text (XINT (start), XINT (end), components, mod_func, string);
600 return string;
601}
602
603DEFUN ("find-composition-internal", Ffind_composition_internal,
604 Sfind_composition_internal, 4, 4, 0,
605 "Internal use only.\n\
606\n\
607Return information about composition at or nearest to position POS.\n\
608See `find-composition' for more detail.")
609 (pos, limit, string, detail_p)
610 Lisp_Object pos, limit, string, detail_p;
611{
612 Lisp_Object prop, tail;
613 int start, end;
614 int id;
615
616 CHECK_NUMBER_COERCE_MARKER (pos, 0);
617 start = XINT (pos);
618 if (!NILP (limit))
619 {
620 CHECK_NUMBER_COERCE_MARKER (limit, 1);
621 end = XINT (limit);
622 }
623 else
624 end = -1;
625 if (!NILP (string))
626 CHECK_STRING (string, 2);
627
628 if (!find_composition (start, end, &start, &end, &prop, string))
629 return Qnil;
630 if (!COMPOSITION_VALID_P (start, end, prop))
631 return Fcons (make_number (start), Fcons (make_number (end),
632 Fcons (Qnil, Qnil)));
633 if (NILP (detail_p))
634 return Fcons (make_number (start), Fcons (make_number (end),
635 Fcons (Qt, Qnil)));
636
637 if (COMPOSITION_REGISTERD_P (prop))
638 id = COMPOSITION_ID (prop);
639 else
640 {
641 int start_byte = (NILP (string)
642 ? CHAR_TO_BYTE (start)
643 : string_char_to_byte (string, start));
644 id = get_composition_id (start, start_byte, end - start, prop, string);
645 }
646
647 if (id >= 0)
648 {
649 Lisp_Object components, relative_p, mod_func;
650 enum composition_method method = COMPOSITION_METHOD (prop);
651 int width = composition_table[id]->width;
652
653 components = Fcopy_sequence (COMPOSITION_COMPONENTS (prop));
654 relative_p = (method == COMPOSITION_WITH_RULE_ALTCHARS
655 ? Qnil : Qt);
656 mod_func = COMPOSITION_MODIFICATION_FUNC (prop);
657 tail = Fcons (components,
658 Fcons (relative_p,
659 Fcons (mod_func,
660 Fcons (make_number (width), Qnil))));
661 }
662 else
663 tail = Qnil;
664
665 return Fcons (make_number (start), Fcons (make_number (end), tail));
666}
667
668\f
669void
670syms_of_composite ()
671{
672 Qcomposition = intern ("composition");
673 staticpro (&Qcomposition);
674
675 /* Make a hash table for composition. */
676 {
09654086 677 Lisp_Object args[6];
ca4c9455
KH
678 extern Lisp_Object QCsize;
679
680 args[0] = QCtest;
681 args[1] = Qequal;
682 args[2] = QCweakness;
683 args[3] = Qnil;
684 args[4] = QCsize;
685 args[5] = make_number (311);
09654086 686 composition_hash_table = Fmake_hash_table (6, args);
ca4c9455
KH
687 staticpro (&composition_hash_table);
688 }
689
690 /* Text property `composition' should be nonsticky by default. */
691 Vtext_property_default_nonsticky
692 = Fcons (Fcons (Qcomposition, Qt), Vtext_property_default_nonsticky);
693
694 DEFVAR_LISP ("compose-chars-after-function", &Vcompose_chars_after_function,
695 "Function to adjust composition of buffer text.\n\
696\n\
697This function is called after a text with `composition' property is\n\
698inserted or deleted to keep `composition' property of buffer text\n\
699valid.\n\
700\n\
701The function is called with two arguments FROM and TO. They specify\n\
702the range of text of which composition should be adjusted.\n\
703\n\
704The default value is the function `compose-chars-after'.");
705 Vcompose_chars_after_function = intern ("compose-chars-after");
706
707 defsubr (&Scompose_region_internal);
708 defsubr (&Scompose_string_internal);
709 defsubr (&Sfind_composition_internal);
710}