(update_compositions): Check the validness of
[bpt/emacs.git] / src / composite.c
CommitLineData
ca4c9455 1/* Composite sequence support.
aaef169d 2 Copyright (C) 2001, 2002, 2003, 2004, 2005,
4e6835db
GM
3 2006, 2007 Free Software Foundation, Inc.
4 Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007
ce03bf76
KH
5 National Institute of Advanced Industrial Science and Technology (AIST)
6 Registration Number H14PRO021
ca4c9455
KH
7
8This file is part of GNU Emacs.
9
10GNU Emacs is free software; you can redistribute it and/or modify
11it under the terms of the GNU General Public License as published by
12the Free Software Foundation; either version 2, or (at your option)
13any later version.
14
15GNU Emacs is distributed in the hope that it will be useful,
16but WITHOUT ANY WARRANTY; without even the implied warranty of
17MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18GNU General Public License for more details.
19
20You should have received a copy of the GNU General Public License
21along with GNU Emacs; see the file COPYING. If not, write to
4fc5845f
LK
22the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
23Boston, MA 02110-1301, USA. */
ca4c9455
KH
24
25#include <config.h>
26#include "lisp.h"
27#include "buffer.h"
28#include "charset.h"
29#include "intervals.h"
30
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.
36
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).
46
47 We register a composition when it is displayed, or when the width
48 is required (for instance, to calculate columns).
49
50 LENGTH -- Length of the composition. This information is used to
51 check the validity of the composition.
52
53 COMPONENTS -- Character, string, vector, list, or nil.
54
55 If it is nil, characters in the text are composed relatively
56 according to their metrics in font glyphs.
57
58 If it is a character or a string, the character or characters
59 in the string are composed relatively.
60
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.
67
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
71 composition rules.
72
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.
77
78 COMPOSITION-ID --Identification number of the composition. It is
79 used as an index to composition_table for the composition.
80
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.
91
92 We use two tables to keep information about composition;
93 composition_hash_table and composition_table.
94
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
4abc7470 97 weak, but as each key (COMPONENTS-VEC) is also kept as a value of the
ca4c9455 98 `composition' property, it won't be collected as garbage until all
4abc7470 99 bits of text that have the same COMPONENTS-VEC are deleted.
ca4c9455
KH
100
101 The latter is a table of pointers to `struct composition' indexed
4abc7470 102 by COMPOSITION-ID. This structure keeps the other information (see
ca4c9455
KH
103 composite.h).
104
105 In general, a text property holds information about individual
106 characters. But, a `composition' property holds information about
4abc7470 107 a sequence of characters (in this sense, it is like the `intangible'
ca4c9455 108 property). That means that we should not share the property value
4abc7470 109 in adjacent compositions -- we can't distinguish them if they have the
ca4c9455
KH
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.
115
4abc7470 116 As the value of the `composition' property holds information about a
ca4c9455 117 specific range of text, the value gets invalid if we change the
4abc7470 118 text in the range. We treat the `composition' property as always
ca4c9455
KH
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
4abc7470 122 range just shorter. So, we can check the validity of the `composition'
ca4c9455
KH
123 property by comparing LENGTH information with the actual length of
124 the composition.
125
126*/
127
128
129Lisp_Object Qcomposition;
130
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. */
134struct composition **composition_table;
135
136/* The current size of `composition_table'. */
137static int composition_table_size;
138
139/* Number of compositions currently made. */
140int n_compositions;
141
142/* Hash table for compositions. The key is COMPONENTS-VEC of
143 `composition' property. The value is the corresponding
144 COMPOSITION-ID. */
145Lisp_Object composition_hash_table;
146
147/* Function to call to adjust composition. */
148Lisp_Object Vcompose_chars_after_function;
149
40add26d
KH
150/* Char-table of patterns and functions to make a composition. */
151Lisp_Object Vcomposition_function_table;
152Lisp_Object Qcomposition_function_table;
153
ca4c9455
KH
154/* Temporary variable used in macros COMPOSITION_XXX. */
155Lisp_Object composition_temp;
156\f
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)))
162
ca4c9455
KH
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.
167
168 If the composition is invalid, return -1. */
169
170int
171get_composition_id (charpos, bytepos, nchars, prop, string)
172 int charpos, bytepos, nchars;
173 Lisp_Object prop, string;
174{
175 Lisp_Object id, length, components, key, *key_contents;
176 int glyph_len;
177 struct Lisp_Hash_Table *hash_table = XHASH_TABLE (composition_hash_table);
178 int hash_index;
179 unsigned hash_code;
180 struct composition *cmp;
181 int i, ch;
182
183 /* PROP should be
184 Form-A: ((LENGTH . COMPONENTS) . MODIFICATION-FUNC)
185 or
186 Form-B: (COMPOSITION-ID . (LENGTH COMPONENTS-VEC . MODIFICATION-FUNC))
187 */
188 if (nchars == 0 || !CONSP (prop))
189 goto invalid_composition;
190
191 id = XCAR (prop);
192 if (INTEGERP (id))
193 {
194 /* PROP should be Form-B. */
195 if (XINT (id) < 0 || XINT (id) >= n_compositions)
196 goto invalid_composition;
197 return XINT (id);
198 }
199
200 /* PROP should be Form-A.
201 Thus, ID should be (LENGTH . COMPONENTS). */
202 if (!CONSP (id))
203 goto invalid_composition;
204 length = XCAR (id);
205 if (!INTEGERP (length) || XINT (length) != nchars)
206 goto invalid_composition;
207
208 components = XCDR (id);
209
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))
219 key = components;
220 else if (NILP (components))
221 {
222 key = Fmake_vector (make_number (nchars), Qnil);
223 if (STRINGP (string))
224 for (i = 0; i < nchars; i++)
225 {
226 FETCH_STRING_CHAR_ADVANCE (ch, string, charpos, bytepos);
227 XVECTOR (key)->contents[i] = make_number (ch);
228 }
229 else
230 for (i = 0; i < nchars; i++)
231 {
232 FETCH_CHAR_ADVANCE (ch, charpos, bytepos);
233 XVECTOR (key)->contents[i] = make_number (ch);
234 }
235 }
236 else
237 goto invalid_composition;
238
239 hash_index = hash_lookup (hash_table, key, &hash_code);
240 if (hash_index >= 0)
241 {
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);
f3fbd155
KR
248 XSETCAR (prop, id);
249 XSETCDR (prop, Fcons (make_number (nchars), Fcons (key, XCDR (prop))));
ca4c9455
KH
250 return XINT (id);
251 }
252
253 /* This composition is a new one. We must register it. */
177c0ea7 254
ca4c9455
KH
255 /* Check if we have sufficient memory to store this information. */
256 if (composition_table_size == 0)
257 {
258 composition_table_size = 256;
259 composition_table
260 = (struct composition **) xmalloc (sizeof (composition_table[0])
261 * composition_table_size);
262 }
263 else if (composition_table_size <= n_compositions)
264 {
265 composition_table_size += 256;
266 composition_table
267 = (struct composition **) xrealloc (composition_table,
268 sizeof (composition_table[0])
269 * composition_table_size);
270 }
271
272 key_contents = XVECTOR (key)->contents;
273
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))
278 {
279 int len = XVECTOR (key)->size;
280
281 /* The number of elements should be odd. */
282 if ((len % 2) == 0)
283 goto invalid_composition;
284 /* All elements should be integers (character or encoded
285 composition rule). */
286 for (i = 0; i < len; i++)
287 {
288 if (!INTEGERP (key_contents[i]))
289 goto invalid_composition;
290 }
291 }
292
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);
f3fbd155
KR
296 XSETCAR (prop, id);
297 XSETCDR (prop, Fcons (make_number (nchars), Fcons (key, XCDR (prop))));
ca4c9455
KH
298
299 /* Register the composition in composition_hash_table. */
300 hash_index = hash_put (hash_table, key, id, hash_code);
301
302 /* Register the composition in composition_table. */
303 cmp = (struct composition *) xmalloc (sizeof (struct composition));
304
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);
316 cmp->font = NULL;
317
318 /* Calculate the width of overall glyphs of the composition. */
319 if (cmp->method != COMPOSITION_WITH_RULE_ALTCHARS)
320 {
321 /* Relative composition. */
322 cmp->width = 0;
323 for (i = 0; i < glyph_len; i++)
324 {
325 int this_width;
326 ch = XINT (key_contents[i]);
327 this_width = CHAR_WIDTH (ch);
328 if (cmp->width < this_width)
329 cmp->width = this_width;
330 }
331 }
332 else
333 {
334 /* Rule-base composition. */
335 float leftmost = 0.0, rightmost;
336
337 ch = XINT (key_contents[0]);
338 rightmost = CHAR_WIDTH (ch);
339
340 for (i = 1; i < glyph_len; i += 2)
341 {
342 int rule, gref, nref;
343 int this_width;
344 float this_left;
345
346 rule = XINT (key_contents[i]);
347 ch = XINT (key_contents[i + 1]);
348 this_width = CHAR_WIDTH (ch);
349
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
353 below:
354 0---1---2 -- ascent
355 | |
356 | |
357 | |
358 9--10--11 -- center
359 | |
360 ---3---4---5--- baseline
361 | |
362 6---7---8 -- descent
363 */
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);
368
369 if (this_left < leftmost)
370 leftmost = this_left;
371 if (this_left + this_width > rightmost)
372 rightmost = this_left + this_width;
373 }
374
375 cmp->width = rightmost - leftmost;
376 if (cmp->width < (rightmost - leftmost))
377 /* To get a ceiling integer value. */
378 cmp->width++;
379 }
380
381 composition_table[n_compositions] = cmp;
382
383 return n_compositions++;
384
385 invalid_composition:
386 /* Would it be better to remove this `composition' property? */
387 return -1;
388}
389
390\f
391/* Find a composition at or nearest to position POS of OBJECT (buffer
392 or string).
393
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.
397
398 If there's no composition at POS and LIMIT is negative, return 0.
399
400 Otherwise, search for a composition forward (LIMIT > POS) or
401 backward (LIMIT < POS). In this case, LIMIT bounds the search.
402
403 If a composition is found, set *START, *END, and *PROP as above,
404 and return 1, else return 0.
405
406 This doesn't check the validity of composition. */
407
408int
409find_composition (pos, limit, start, end, prop, object)
410 int pos, limit, *start, *end;
411 Lisp_Object *prop, object;
412{
413 Lisp_Object val;
414
415 if (get_property_and_range (pos, Qcomposition, prop, start, end, object))
416 return 1;
417
418 if (limit < 0 || limit == pos)
419 return 0;
420
421 if (limit > pos) /* search forward */
d279f620
KH
422 {
423 val = Fnext_single_property_change (make_number (pos), Qcomposition,
424 object, make_number (limit));
425 pos = XINT (val);
426 if (pos == limit)
427 return 0;
428 }
ca4c9455 429 else /* search backward */
d279f620
KH
430 {
431 if (get_property_and_range (pos - 1, Qcomposition, prop, start, end,
432 object))
433 return 1;
434 val = Fprevious_single_property_change (make_number (pos), Qcomposition,
435 object, make_number (limit));
436 pos = XINT (val);
437 if (pos == limit)
438 return 0;
439 pos--;
440 }
ca4c9455
KH
441 get_property_and_range (pos, Qcomposition, prop, start, end, object);
442 return 1;
443}
444
445/* Run a proper function to adjust the composition sitting between
446 FROM and TO with property PROP. */
447
448static void
449run_composition_function (from, to, prop)
450 int from, to;
451 Lisp_Object prop;
452{
7d019510 453 Lisp_Object func;
ca4c9455
KH
454 int start, end;
455
456 func = COMPOSITION_MODIFICATION_FUNC (prop);
457 /* If an invalid composition precedes or follows, try to make them
458 valid too. */
459 if (from > BEGV
460 && find_composition (from - 1, -1, &start, &end, &prop, Qnil)
461 && !COMPOSITION_VALID_P (start, end, prop))
462 from = start;
463 if (to < ZV
464 && find_composition (to, -1, &start, &end, &prop, Qnil)
465 && !COMPOSITION_VALID_P (start, end, prop))
466 to = end;
775b3d2d 467 if (!NILP (Ffboundp (func)))
ca4c9455 468 call2 (func, make_number (from), make_number (to));
09654086 469 else if (!NILP (Ffboundp (Vcompose_chars_after_function)))
40add26d
KH
470 call3 (Vcompose_chars_after_function,
471 make_number (from), make_number (to), Qnil);
ca4c9455
KH
472}
473
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).
477
478 This function is called when a buffer text is changed. If the
479 change is deletion, FROM == TO. Otherwise, FROM < TO. */
480
481void
482update_compositions (from, to, check_mask)
1e26d5ef 483 int from, to, check_mask;
ca4c9455 484{
7d019510 485 Lisp_Object prop;
ca4c9455
KH
486 int start, end;
487
6c1aa7f1
GM
488 if (inhibit_modification_hooks)
489 return;
177c0ea7 490
d3f40cbd
KH
491 /* If FROM and TO are not in a valid range, do nothing. */
492 if (! (BEGV <= from && from <= to && to <= ZV))
493 return;
494
ca4c9455
KH
495 if (check_mask & CHECK_HEAD)
496 {
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. */
502 if (from > BEGV
553d3164
KH
503 && find_composition (from - 1, -1, &start, &end, &prop, Qnil)
504 && COMPOSITION_VALID_P (start, end, prop))
ca4c9455
KH
505 {
506 if (from < end)
507 Fput_text_property (make_number (from), make_number (end),
508 Qcomposition,
509 Fcons (XCAR (prop), XCDR (prop)), Qnil);
510 run_composition_function (start, end, prop);
511 from = end;
512 }
dd33cc56 513 else if (from < ZV
553d3164
KH
514 && find_composition (from, -1, &start, &from, &prop, Qnil)
515 && COMPOSITION_VALID_P (start, end, prop))
ca4c9455
KH
516 run_composition_function (start, from, prop);
517 }
518
519 if (check_mask & CHECK_INSIDE)
520 {
521 /* In this case, we are sure that (check & CHECK_TAIL) is also
522 nonzero. Thus, here we should check only compositions before
523 (to - 1). */
524 while (from < to - 1
525 && find_composition (from, to, &start, &from, &prop, Qnil)
553d3164 526 && COMPOSITION_VALID_P (start, end, prop)
ca4c9455
KH
527 && from < to - 1)
528 run_composition_function (start, from, prop);
529 }
530
531 if (check_mask & CHECK_TAIL)
532 {
533 if (from < to
553d3164
KH
534 && find_composition (to - 1, -1, &start, &end, &prop, Qnil)
535 && COMPOSITION_VALID_P (start, end, prop))
ca4c9455
KH
536 {
537 /* TO should be also at composition boundary. But,
538 insertion or deletion will make two compositions adjacent
539 and indistinguishable when they have same (eq) property.
540 To avoid it, in such a case, we change the property of
541 the former to the copy of it. */
542 if (to < end)
543 Fput_text_property (make_number (start), make_number (to),
544 Qcomposition,
545 Fcons (XCAR (prop), XCDR (prop)), Qnil);
546 run_composition_function (start, end, prop);
547 }
548 else if (to < ZV
553d3164
KH
549 && find_composition (to, -1, &start, &end, &prop, Qnil)
550 && COMPOSITION_VALID_P (start, end, prop))
ca4c9455
KH
551 run_composition_function (start, end, prop);
552 }
553}
554
c1361885
KH
555
556/* Modify composition property values in LIST destructively. LIST is
557 a list as returned from text_property_list. Change values to the
558 top-level copies of them so that none of them are `eq'. */
559
560void
561make_composition_value_copy (list)
562 Lisp_Object list;
563{
564 Lisp_Object plist, val;
565
566 for (; CONSP (list); list = XCDR (list))
567 {
568 plist = XCAR (XCDR (XCDR (XCAR (list))));
569 while (CONSP (plist) && CONSP (XCDR (plist)))
570 {
571 if (EQ (XCAR (plist), Qcomposition)
572 && (val = XCAR (XCDR (plist)), CONSP (val)))
f3fbd155 573 XSETCAR (XCDR (plist), Fcons (XCAR (val), XCDR (val)));
c1361885
KH
574 plist = XCDR (XCDR (plist));
575 }
576 }
577}
578
579
ca4c9455
KH
580/* Make text in the region between START and END a composition that
581 has COMPONENTS and MODIFICATION-FUNC.
582
583 If STRING is non-nil, then operate on characters contained between
584 indices START and END in STRING. */
585
586void
587compose_text (start, end, components, modification_func, string)
588 int start, end;
589 Lisp_Object components, modification_func, string;
590{
591 Lisp_Object prop;
592
593 prop = Fcons (Fcons (make_number (end - start), components),
594 modification_func);
595 Fput_text_property (make_number (start), make_number (end),
596 Qcomposition, prop, string);
597}
598
599\f
600/* Emacs Lisp APIs. */
601
602DEFUN ("compose-region-internal", Fcompose_region_internal,
603 Scompose_region_internal, 2, 4, 0,
335c5470
PJ
604 doc: /* Internal use only.
605
606Compose text in the region between START and END.
607Optional 3rd and 4th arguments are COMPONENTS and MODIFICATION-FUNC
9baf7418 608for the composition. See `compose-region' for more detail. */)
d562f8ab
JB
609 (start, end, components, modification_func)
610 Lisp_Object start, end, components, modification_func;
ca4c9455
KH
611{
612 validate_region (&start, &end);
613 if (!NILP (components)
614 && !INTEGERP (components)
615 && !CONSP (components)
616 && !STRINGP (components))
b7826503 617 CHECK_VECTOR (components);
ca4c9455 618
d562f8ab 619 compose_text (XINT (start), XINT (end), components, modification_func, Qnil);
ca4c9455
KH
620 return Qnil;
621}
622
623DEFUN ("compose-string-internal", Fcompose_string_internal,
624 Scompose_string_internal, 3, 5, 0,
335c5470
PJ
625 doc: /* Internal use only.
626
627Compose text between indices START and END of STRING.
628Optional 4th and 5th arguments are COMPONENTS and MODIFICATION-FUNC
9baf7418 629for the composition. See `compose-string' for more detail. */)
d562f8ab
JB
630 (string, start, end, components, modification_func)
631 Lisp_Object string, start, end, components, modification_func;
ca4c9455 632{
b7826503
PJ
633 CHECK_STRING (string);
634 CHECK_NUMBER (start);
635 CHECK_NUMBER (end);
ca4c9455
KH
636
637 if (XINT (start) < 0 ||
638 XINT (start) > XINT (end)
d5db4077 639 || XINT (end) > SCHARS (string))
ca4c9455
KH
640 args_out_of_range (start, end);
641
d562f8ab 642 compose_text (XINT (start), XINT (end), components, modification_func, string);
ca4c9455
KH
643 return string;
644}
645
646DEFUN ("find-composition-internal", Ffind_composition_internal,
177c0ea7 647 Sfind_composition_internal, 4, 4, 0,
335c5470
PJ
648 doc: /* Internal use only.
649
650Return information about composition at or nearest to position POS.
651See `find-composition' for more detail. */)
652 (pos, limit, string, detail_p)
ca4c9455
KH
653 Lisp_Object pos, limit, string, detail_p;
654{
655 Lisp_Object prop, tail;
656 int start, end;
657 int id;
658
b7826503 659 CHECK_NUMBER_COERCE_MARKER (pos);
ca4c9455
KH
660 start = XINT (pos);
661 if (!NILP (limit))
662 {
b7826503 663 CHECK_NUMBER_COERCE_MARKER (limit);
ca4c9455
KH
664 end = XINT (limit);
665 }
666 else
667 end = -1;
177c0ea7 668
ca4c9455 669 if (!NILP (string))
e3b3e327 670 {
b7826503 671 CHECK_STRING (string);
d5db4077 672 if (XINT (pos) < 0 || XINT (pos) > SCHARS (string))
e3b3e327
GM
673 args_out_of_range (string, pos);
674 }
675 else
676 {
fa9090b8 677 if (XINT (pos) < BEGV || XINT (pos) > ZV)
e3b3e327
GM
678 args_out_of_range (Fcurrent_buffer (), pos);
679 }
ca4c9455
KH
680
681 if (!find_composition (start, end, &start, &end, &prop, string))
682 return Qnil;
683 if (!COMPOSITION_VALID_P (start, end, prop))
684 return Fcons (make_number (start), Fcons (make_number (end),
685 Fcons (Qnil, Qnil)));
686 if (NILP (detail_p))
687 return Fcons (make_number (start), Fcons (make_number (end),
688 Fcons (Qt, Qnil)));
689
690 if (COMPOSITION_REGISTERD_P (prop))
691 id = COMPOSITION_ID (prop);
692 else
693 {
694 int start_byte = (NILP (string)
695 ? CHAR_TO_BYTE (start)
696 : string_char_to_byte (string, start));
697 id = get_composition_id (start, start_byte, end - start, prop, string);
698 }
699
700 if (id >= 0)
701 {
702 Lisp_Object components, relative_p, mod_func;
703 enum composition_method method = COMPOSITION_METHOD (prop);
704 int width = composition_table[id]->width;
705
706 components = Fcopy_sequence (COMPOSITION_COMPONENTS (prop));
707 relative_p = (method == COMPOSITION_WITH_RULE_ALTCHARS
708 ? Qnil : Qt);
709 mod_func = COMPOSITION_MODIFICATION_FUNC (prop);
710 tail = Fcons (components,
711 Fcons (relative_p,
712 Fcons (mod_func,
713 Fcons (make_number (width), Qnil))));
714 }
715 else
716 tail = Qnil;
717
718 return Fcons (make_number (start), Fcons (make_number (end), tail));
719}
720
721\f
722void
723syms_of_composite ()
724{
725 Qcomposition = intern ("composition");
726 staticpro (&Qcomposition);
727
728 /* Make a hash table for composition. */
729 {
09654086 730 Lisp_Object args[6];
ca4c9455 731 extern Lisp_Object QCsize;
177c0ea7 732
ca4c9455
KH
733 args[0] = QCtest;
734 args[1] = Qequal;
c7211bc5
KH
735 /* We used to make the hash table weak so that unreferenced
736 compostions can be garbage-collected. But, usually once
737 created compositions are repeatedly used in an Emacs session,
738 and thus it's not worth to save memory in such a way. So, we
739 make the table not weak. */
ca4c9455 740 args[2] = QCweakness;
1ace9906 741 args[3] = Qnil;
ca4c9455
KH
742 args[4] = QCsize;
743 args[5] = make_number (311);
09654086 744 composition_hash_table = Fmake_hash_table (6, args);
ca4c9455
KH
745 staticpro (&composition_hash_table);
746 }
747
748 /* Text property `composition' should be nonsticky by default. */
749 Vtext_property_default_nonsticky
750 = Fcons (Fcons (Qcomposition, Qt), Vtext_property_default_nonsticky);
751
752 DEFVAR_LISP ("compose-chars-after-function", &Vcompose_chars_after_function,
335c5470
PJ
753 doc: /* Function to adjust composition of buffer text.
754
755The function is called with three arguments FROM, TO, and OBJECT.
756FROM and TO specify the range of text of which composition should be
757adjusted. OBJECT, if non-nil, is a string that contains the text.
758
759This function is called after a text with `composition' property is
760inserted or deleted to keep `composition' property of buffer text
761valid.
762
763The default value is the function `compose-chars-after'. */);
ca4c9455
KH
764 Vcompose_chars_after_function = intern ("compose-chars-after");
765
40add26d
KH
766 Qcomposition_function_table = intern ("composition-function-table");
767 staticpro (&Qcomposition_function_table);
768
769 /* Intern this now in case it isn't already done.
770 Setting this variable twice is harmless.
771 But don't staticpro it here--that is done in alloc.c. */
772 Qchar_table_extra_slots = intern ("char-table-extra-slots");
773
774 Fput (Qcomposition_function_table, Qchar_table_extra_slots, make_number (0));
775
776 DEFVAR_LISP ("composition-function-table", &Vcomposition_function_table,
335c5470
PJ
777 doc: /* Char table of patterns and functions to make a composition.
778
779Each element is nil or an alist of PATTERNs vs FUNCs, where PATTERNs
780are regular expressions and FUNCs are functions. FUNC is responsible
781for composing text matching the corresponding PATTERN. FUNC is called
782with three arguments FROM, TO, and PATTERN. See the function
783`compose-chars-after' for more detail.
784
785This table is looked up by the first character of a composition when
786the composition gets invalid after a change in a buffer. */);
40add26d
KH
787 Vcomposition_function_table
788 = Fmake_char_table (Qcomposition_function_table, Qnil);
789
ca4c9455
KH
790 defsubr (&Scompose_region_internal);
791 defsubr (&Scompose_string_internal);
792 defsubr (&Sfind_composition_internal);
793}
ab5796a9
MB
794
795/* arch-tag: 79cefaf8-ca48-4eed-97e5-d5afb290d272
796 (do not change this comment) */