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